<commit_before>/* global $ */
/* global fabric */
/* global Office */
/* global sendHeadersRequest */
/* global Diagnostics */
/* global Errors */
/* global appInsights */
/* exported ParentFrame */

// Controller for Settings screen which controls what is being displayed
// and which UI to use.

var ParentFrame = (function () {
    var iFrame = null;
    var currentChoice = {};
    var deferredErrors = [];
    var deferredStatus = [];
    var headers = "";

    function choice(label, url, checked) {
        return { label: label, url: url, checked: checked };
    }

    var choices = [
        choice("classic", "classicDesktopFrame.html", false),
        choice("new", "newDesktopFrame.html", true),
        choice("new-mobile", "newMobilePaneIosFrame.html", false)
    ];

    function setDefault() {
        var uiDefault = getQueryVariable("default");
        if (uiDefault === null) {
            uiDefault = "new";
        }

        for (var iChoice = 0; iChoice < choices.length; iChoice++) {
            if (uiDefault === choices[iChoice].label) {
                choices[iChoice].checked = true;
            } else {
                choices[iChoice].checked = false;
            }
        }
    }

    function getQueryVariable(variable) {
        var vars = window.location.search.substring(1).split("&");
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair[0] === variable) {
                return pair[1];
            }
        }
        return null;
    }

    function site() { return window.location.protocol + "//" + window.location.host; }

    function postMessageToFrame(eventName, data) {
        if (iFrame) {
            iFrame.postMessage({ eventName: eventName, data: data }, site());
        }
    }

    function eventListener(event) {
        if (!event || event.origin !== site()) return;

        if (event.data) {
            switch (event.data.eventName) {
                case "frameActive":
                    setFrame(event.source);
                    break;
                case "LogError":
                    Errors.log(JSON.parse(event.data.data.error), event.data.data.message);
                    break;
            }
        }
    }

    function initUI() {
        setDefault();
        addChoices();
        initFabric();

        try {
            var choice = Office.context.roamingSettings.get(getSettingsKey());
            var input = $("#uiToggle" + choice.label);
            input.prop("checked", true);
            go(choice);
        } catch (e) {
            goDefaultChoice();
        }

        registerItemChangedEvent();

        window.addEventListener("message", eventListener, false);
        loadNewItem();
    }

    function registerItemChangedEvent() {
        try {
            if (Office.context.mailbox.addHandlerAsync !== undefined) {
                Office.context.mailbox.addHandlerAsync(Office.EventType.ItemChanged,
                    function () {
                        Errors.clear();
                        Diagnostics.clear();
                        loadNewItem();
                    });
            }
        } catch (e) {
            Errors.log(e, "Could not register item changed event");
        }
    }

    function loadNewItem() {
        if (Office.context.mailbox.item) {
            sendHeadersRequest(function (_headers, apiUsed) {
                headers = _headers;
                Diagnostics.set("API used", apiUsed);
                renderItem(headers);
            });
        }
    }

    function setFrame(frame) {
        iFrame = frame;

        if (iFrame) {
            // If we have any deferred status, signal them
            for (var iStatus = 0; iStatus < deferredStatus.length; iStatus++) {
                postMessageToFrame("updateStatus", deferredStatus[iStatus]);
            }

            // Clear out the now displayed status
            deferredStatus = [];

            // If we have any deferred errors, signal them
            for (var iError = 0; iError < deferredErrors.length; iError++) {
                postMessageToFrame("showError",
                    {
                        error: JSON.stringify(deferredErrors[iError][0]),
                        message: deferredErrors[iError][1]
                    });
            }

            // Clear out the now displayed errors
            deferredErrors = [];

            renderItem(headers);
        }
    }

    function renderItem(headers) {
        if (appInsights && headers) appInsights.trackEvent("analyzeHeaders: ");
        postMessageToFrame("renderItem", headers);
    }

    // Tells the UI to show an error.
    function showError(error, message, suppressTracking) {
        Errors.log(error, message, suppressTracking);

        if (iFrame) {
            postMessageToFrame("showError", { error: JSON.stringify(error), message: message });
        } else {
            // We don't have an iFrame, so defer the message
            deferredErrors.push([error, message]);
        }
    }

    // Tells the UI to show an error.
    function updateStatus(statusText) {
        if (iFrame) {
            postMessageToFrame("updateStatus", statusText);
        } else {
            // We don't have an iFrame, so defer the status
            deferredStatus.push(statusText);
        }
    }

    function getSettingsKey() {
        try {
            return "frame" + Office.context.mailbox.diagnostics.hostName;
        } catch (e) {
            return "frame";
        }
    }

    // Display primary UI
    function go(choice) {
        iFrame = null;
        currentChoice = choice;
        document.getElementById("uiFrame").src = choice.url;
        if (Office.context) {
            Office.context.roamingSettings.set(getSettingsKey(), choice);
            Office.context.roamingSettings.saveAsync();
        }
    }

    function goDefaultChoice() {
        for (var iChoice = 0; iChoice < choices.length; iChoice++) {
            var choice = choices[iChoice];
            if (choice.checked) {
                go(choice);
                return;
            }
        }
    }

    function create(parentElement, newType, newClass) {
        var newElement = $(document.createElement(newType));
        if (newClass) {
            newElement.addClass(newClass);
        }

        if (parentElement) {
            parentElement.append(newElement);
        }

        return newElement;
    }

    // Create list of choices to display for the UI types
    function addChoices() {
        var list = $("#uiChoice-list");
        list.empty();

        for (var iChoice = 0; iChoice < choices.length; iChoice++) {
            var choice = choices[iChoice];

            // Create html:

            var listItem = create(list, "li", "ms-RadioButton");

            // Create html: <input tabindex="-1" type="radio" class="ms-RadioButton-input" value="classic">
            var input = create(listItem, "input", "ms-RadioButton-input");

            input.attr("tabindex", "-1");
            input.attr("type", "radio");
            input.attr("value", iChoice);

            //  Create html:
            var label = create(listItem, "label", "ms-RadioButton-field");
            label.attr("role", "radio");
            label.attr("tabindex", "0");
            label.attr("name", "uiChoice");
            label.attr("value", choice.label);

            // Create html: classic
            var inputSpan = create(label, "span", "ms-Label");
            inputSpan.text(choice.label);
        }
    }

    // Hook the UI together for display
    function initFabric() {
        var i;
        var header = document.querySelector(".header-row");

        var dialogSettings = header.querySelector("#dialog-Settings");
        // Wire up the dialog
        var dialogSettingsComponent = new fabric["Dialog"](dialogSettings);

        var dialogDiagnostics = header.querySelector("#dialog-Diagnostics");
        // Wire up the dialog
        var dialogDiagnosticsComponent = new fabric["Dialog"](dialogDiagnostics);

        var actionButtonElements = header.querySelectorAll(".ms-Dialog-action");
        // Wire up the buttons
        for (i = 0; i < actionButtonElements.length; i++) {
            new fabric["Button"](actionButtonElements[i], actionHandler);
        }

        var choiceGroup = dialogSettings.querySelectorAll(".ms-ChoiceFieldGroup");
        new fabric["ChoiceFieldGroup"](choiceGroup[0]);

        var choiceFieldGroupElements = dialogSettings.querySelectorAll(".ms-ChoiceFieldGroup");
        for (i = 0; i < choiceFieldGroupElements.length; i++) {
            new fabric["ChoiceFieldGroup"](choiceFieldGroupElements[i]);
        }

        var button = header.querySelector(".dialog-button");
        // When clicking the button, open the dialog
        button.onclick = function () {
            // Set the current choice in the UI.
            $("#uiChoice input").attr("checked", false);
            var labels = $("#uiChoice label");
            labels.removeClass("is-checked");
            labels.attr("aria-checked", "false");
            var currentSelected = $("#uiChoice label[value=" + currentChoice.label + "]");
            currentSelected.addClass("is-checked");
            currentSelected.attr("aria-checked", "true");
            var input = currentSelected.prevAll("input:first");
            input.prop("checked", "true");
            dialogSettingsComponent.open();
        };

        function actionHandler() {
            var action = this.id;

            switch (action) {
                case "actionsSettings-OK":
                    // How did the user say to display it (UI to display)

                    var iChoice = $("#uiChoice input:checked")[0].value;
                    var choice = choices[iChoice];
                    if (choice.label !== currentChoice.label) {
                        go(choice);
                    }
                    break;
                case "actionsSettings-diag":
                    var diagnostics = getDiagnostics();
                    $("#diagnostics").text(diagnostics);
                    dialogDiagnosticsComponent.open();
                    break;
            }
        }

        function getDiagnostics() {
            var diagnostics = "";
            try {
                var diagnosticMap = Diagnostics.get();
                for (var diag in diagnosticMap) {
                    if (diagnosticMap.hasOwnProperty(diag)) {
                        diagnostics += diag + " = " + diagnosticMap[diag] + "\n";
                    }
                }
            } catch (e) {
                diagnostics += "ERROR: Failed to get diagnostics\n";
            }

            var errors = Errors.get();
            for (var iError = 0; iError < errors.length; iError++) {
                if (errors[iError]) {
                    diagnostics += "ERROR: " + errors[iError] + "\n";
                }
            }

            return diagnostics;
        }
    }

    function getChoice() { return currentChoice; }

    return {
        initUI: initUI,
        updateStatus: updateStatus,
        showError: showError,
        getChoice: getChoice
    }
})();

Office.initialize = function () {
    $(document).ready(function () {
        ParentFrame.initUI();
    });
};<commit_msg>fiurther cleanup<commit_after>/* global $ */
/* global fabric */
/* global Office */
/* global sendHeadersRequest */
/* global Diagnostics */
/* global Errors */
/* global appInsights */
/* exported ParentFrame */

// Controller for Settings screen which controls what is being displayed
// and which UI to use.

var ParentFrame = (function () {
    var iFrame = null;
    var currentChoice = {};
    var deferredErrors = [];
    var deferredStatus = [];
    var headers = "";

    function choice(label, url, checked) {
        return { label: label, url: url, checked: checked };
    }

    var choices = [
        choice("classic", "classicDesktopFrame.html", false),
        choice("new", "newDesktopFrame.html", true),
        choice("new-mobile", "newMobilePaneIosFrame.html", false)
    ];

    function setDefault() {
        var uiDefault = getQueryVariable("default");
        if (uiDefault === null) {
            uiDefault = "new";
        }

        for (var iChoice = 0; iChoice < choices.length; iChoice++) {
            if (uiDefault === choices[iChoice].label) {
                choices[iChoice].checked = true;
            } else {
                choices[iChoice].checked = false;
            }
        }
    }

    function getQueryVariable(variable) {
        var vars = window.location.search.substring(1).split("&");
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair[0] === variable) {
                return pair[1];
            }
        }
        return null;
    }

    function site() { return window.location.protocol + "//" + window.location.host; }

    function postMessageToFrame(eventName, data) {
        if (iFrame) {
            iFrame.postMessage({ eventName: eventName, data: data }, site());
        }
    }

    function eventListener(event) {
        if (!event || event.origin !== site()) return;

        if (event.data) {
            switch (event.data.eventName) {
                case "frameActive":
                    setFrame(event.source);
                    break;
                case "LogError":
                    Errors.log(JSON.parse(event.data.data.error), event.data.data.message);
                    break;
            }
        }
    }

    function initUI() {
        setDefault();
        addChoices();
        initFabric();

        try {
            var choice = Office.context.roamingSettings.get(getSettingsKey());
            var input = $("#uiToggle" + choice.label);
            input.prop("checked", true);
            go(choice);
        } catch (e) {
            goDefaultChoice();
        }

        registerItemChangedEvent();

        window.addEventListener("message", eventListener, false);
        loadNewItem();
    }

    function registerItemChangedEvent() {
        try {
            if (Office.context.mailbox.addHandlerAsync !== undefined) {
                Office.context.mailbox.addHandlerAsync(Office.EventType.ItemChanged,
                    function () {
                        Errors.clear();
                        Diagnostics.clear();
                        loadNewItem();
                    });
            }
        } catch (e) {
            Errors.log(e, "Could not register item changed event");
        }
    }

    function loadNewItem() {
        if (Office.context.mailbox.item) {
            sendHeadersRequest(function (_headers, apiUsed) {
                headers = _headers;
                Diagnostics.set("API used", apiUsed);
                renderItem(headers);
            });
        }
    }

    function setFrame(frame) {
        iFrame = frame;

        if (iFrame) {
            // If we have any deferred status, signal them
            for (var iStatus = 0; iStatus < deferredStatus.length; iStatus++) {
                postMessageToFrame("updateStatus", deferredStatus[iStatus]);
            }

            // Clear out the now displayed status
            deferredStatus = [];

            // If we have any deferred errors, signal them
            for (var iError = 0; iError < deferredErrors.length; iError++) {
                postMessageToFrame("showError",
                    {
                        error: JSON.stringify(deferredErrors[iError][0]),
                        message: deferredErrors[iError][1]
                    });
            }

            // Clear out the now displayed errors
            deferredErrors = [];

            renderItem(headers);
        }
    }

    function renderItem(headers) {
        if (appInsights && headers) appInsights.trackEvent("analyzeHeaders");
        postMessageToFrame("renderItem", headers);
    }

    // Tells the UI to show an error.
    function showError(error, message, suppressTracking) {
        Errors.log(error, message, suppressTracking);

        if (iFrame) {
            postMessageToFrame("showError", { error: JSON.stringify(error), message: message });
        } else {
            // We don't have an iFrame, so defer the message
            deferredErrors.push([error, message]);
        }
    }

    // Tells the UI to show an error.
    function updateStatus(statusText) {
        if (iFrame) {
            postMessageToFrame("updateStatus", statusText);
        } else {
            // We don't have an iFrame, so defer the status
            deferredStatus.push(statusText);
        }
    }

    function getSettingsKey() {
        try {
            return "frame" + Office.context.mailbox.diagnostics.hostName;
        } catch (e) {
            return "frame";
        }
    }

    // Display primary UI
    function go(choice) {
        iFrame = null;
        currentChoice = choice;
        document.getElementById("uiFrame").src = choice.url;
        if (Office.context) {
            Office.context.roamingSettings.set(getSettingsKey(), choice);
            Office.context.roamingSettings.saveAsync();
        }
    }

    function goDefaultChoice() {
        for (var iChoice = 0; iChoice < choices.length; iChoice++) {
            var choice = choices[iChoice];
            if (choice.checked) {
                go(choice);
                return;
            }
        }
    }

    function create(parentElement, newType, newClass) {
        var newElement = $(document.createElement(newType));
        if (newClass) {
            newElement.addClass(newClass);
        }

        if (parentElement) {
            parentElement.append(newElement);
        }

        return newElement;
    }

    // Create list of choices to display for the UI types
    function addChoices() {
        var list = $("#uiChoice-list");
        list.empty();

        for (var iChoice = 0; iChoice < choices.length; iChoice++) {
            var choice = choices[iChoice];

            // Create html:

            var listItem = create(list, "li", "ms-RadioButton");

            // Create html: <input tabindex="-1" type="radio" class="ms-RadioButton-input" value="classic">
            var input = create(listItem, "input", "ms-RadioButton-input");

            input.attr("tabindex", "-1");
            input.attr("type", "radio");
            input.attr("value", iChoice);

            //  Create html:
            var label = create(listItem, "label", "ms-RadioButton-field");
            label.attr("role", "radio");
            label.attr("tabindex", "0");
            label.attr("name", "uiChoice");
            label.attr("value", choice.label);

            // Create html: classic
            var inputSpan = create(label, "span", "ms-Label");
            inputSpan.text(choice.label);
        }
    }

    // Hook the UI together for display
    function initFabric() {
        var i;
        var header = document.querySelector(".header-row");

        var dialogSettings = header.querySelector("#dialog-Settings");
        // Wire up the dialog
        var dialogSettingsComponent = new fabric["Dialog"](dialogSettings);

        var dialogDiagnostics = header.querySelector("#dialog-Diagnostics");
        // Wire up the dialog
        var dialogDiagnosticsComponent = new fabric["Dialog"](dialogDiagnostics);

        var actionButtonElements = header.querySelectorAll(".ms-Dialog-action");
        // Wire up the buttons
        for (i = 0; i < actionButtonElements.length; i++) {
            new fabric["Button"](actionButtonElements[i], actionHandler);
        }

        var choiceGroup = dialogSettings.querySelectorAll(".ms-ChoiceFieldGroup");
        new fabric["ChoiceFieldGroup"](choiceGroup[0]);

        var choiceFieldGroupElements = dialogSettings.querySelectorAll(".ms-ChoiceFieldGroup");
        for (i = 0; i < choiceFieldGroupElements.length; i++) {
            new fabric["ChoiceFieldGroup"](choiceFieldGroupElements[i]);
        }

        var button = header.querySelector(".dialog-button");
        // When clicking the button, open the dialog
        button.onclick = function () {
            // Set the current choice in the UI.
            $("#uiChoice input").attr("checked", false);
            var labels = $("#uiChoice label");
            labels.removeClass("is-checked");
            labels.attr("aria-checked", "false");
            var currentSelected = $("#uiChoice label[value=" + currentChoice.label + "]");
            currentSelected.addClass("is-checked");
            currentSelected.attr("aria-checked", "true");
            var input = currentSelected.prevAll("input:first");
            input.prop("checked", "true");
            dialogSettingsComponent.open();
        };

        function actionHandler() {
            var action = this.id;

            switch (action) {
                case "actionsSettings-OK":
                    // How did the user say to display it (UI to display)

                    var iChoice = $("#uiChoice input:checked")[0].value;
                    var choice = choices[iChoice];
                    if (choice.label !== currentChoice.label) {
                        go(choice);
                    }
                    break;
                case "actionsSettings-diag":
                    var diagnostics = getDiagnostics();
                    $("#diagnostics").text(diagnostics);
                    dialogDiagnosticsComponent.open();
                    break;
            }
        }

        function getDiagnostics() {
            var diagnostics = "";
            try {
                var diagnosticMap = Diagnostics.get();
                for (var diag in diagnosticMap) {
                    if (diagnosticMap.hasOwnProperty(diag)) {
                        diagnostics += diag + " = " + diagnosticMap[diag] + "\n";
                    }
                }
            } catch (e) {
                diagnostics += "ERROR: Failed to get diagnostics\n";
            }

            var errors = Errors.get();
            for (var iError = 0; iError < errors.length; iError++) {
                if (errors[iError]) {
                    diagnostics += "ERROR: " + errors[iError] + "\n";
                }
            }

            return diagnostics;
        }
    }

    function getChoice() { return currentChoice; }

    return {
        initUI: initUI,
        updateStatus: updateStatus,
        showError: showError,
        getChoice: getChoice
    }
})();

Office.initialize = function () {
    $(document).ready(function () {
        ParentFrame.initUI();
    });
};<|endoftext|>


<commit_before>/*eslint dot-notation:0*/
import {
  Parser,
  ObserverLocator,
  EventManager,
  ListenerExpression,
  BindingExpression,
  CallExpression,
  bindingMode,
  delegationStrategy
} from 'aurelia-binding';

import {BehaviorInstruction} from 'aurelia-templating';
import * as LogManager from 'aurelia-logging';
import {AttributeMap} from './attribute-map';

export class SyntaxInterpreter {
  static inject = [Parser, ObserverLocator, EventManager, AttributeMap];

  constructor(parser, observerLocator, eventManager, attributeMap) {
    this.parser = parser;
    this.observerLocator = observerLocator;
    this.eventManager = eventManager;
    this.attributeMap = attributeMap;
  }

  interpret(resources, element, info, existingInstruction, context) {
    if (info.command in this) {
      return this[info.command](resources, element, info, existingInstruction, context);
    }

    return this.handleUnknownCommand(resources, element, info, existingInstruction, context);
  }

  handleUnknownCommand(resources, element, info, existingInstruction, context) {
    LogManager.getLogger('templating-binding').warn('Unknown binding command.', info);
    return existingInstruction;
  }

  determineDefaultBindingMode(element, attrName, context) {
    let tagName = element.tagName.toLowerCase();

    if (tagName === 'input' && (attrName === 'value' || attrName === 'files') && element.type !== 'checkbox' && element.type !== 'radio'
      || tagName === 'input' && attrName === 'checked' && (element.type === 'checkbox' || element.type === 'radio')
      || (tagName === 'textarea' || tagName === 'select') && attrName === 'value'
      || (attrName === 'textcontent' || attrName === 'innerhtml') && element.contentEditable === 'true'
      || attrName === 'scrolltop'
      || attrName === 'scrollleft') {
      return bindingMode.twoWay;
    }

    if (context
      && attrName in context.attributes
      && context.attributes[attrName]
      && context.attributes[attrName].defaultBindingMode >= bindingMode.oneTime) {
      return context.attributes[attrName].defaultBindingMode;
    }

    return bindingMode.oneWay;
  }

  bind(resources, element, info, existingInstruction, context) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      info.defaultBindingMode === undefined || info.defaultBindingMode === null
        ? this.determineDefaultBindingMode(element, info.attrName, context)
        : info.defaultBindingMode,
      resources.lookupFunctions
    );

    return instruction;
  }

  trigger(resources, element, info) {
    return new ListenerExpression(
      this.eventManager,
      info.attrName,
      this.parser.parse(info.attrValue),
      delegationStrategy.none,
      true,
      resources.lookupFunctions
    );
  }

  capture(resources, element, info) {
    return new ListenerExpression(
      this.eventManager,
      info.attrName,
      this.parser.parse(info.attrValue),
      delegationStrategy.capturing,
      true,
      resources.lookupFunctions
    );
  }

  delegate(resources, element, info) {
    return new ListenerExpression(
      this.eventManager,
      info.attrName,
      this.parser.parse(info.attrValue),
      delegationStrategy.bubbling,
      true,
      resources.lookupFunctions
    );
  }

  call(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new CallExpression(
      this.observerLocator,
      info.attrName,
      this.parser.parse(info.attrValue),
      resources.lookupFunctions
    );

    return instruction;
  }

  options(resources, element, info, existingInstruction, context) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);
    let attrValue = info.attrValue;
    let language = this.language;
    let name = null;
    let target = '';
    let current;
    let i;
    let ii;
    let inString = false;
    let inEscape = false;
    let foundName = false;

    for (i = 0, ii = attrValue.length; i < ii; ++i) {
      current = attrValue[i];

      if (current === ';' && !inString) {
        if (!foundName) {
          name = this._getPrimaryPropertyName(resources, context);
        }
        info = language.inspectAttribute(resources, '?', name, target.trim());
        language.createAttributeInstruction(resources, element, info, instruction, context);

        if (!instruction.attributes[info.attrName]) {
          instruction.attributes[info.attrName] = info.attrValue;
        }

        target = '';
        name = null;
      } else if (current === ':' && name === null) {
        foundName = true;
        name = target.trim();
        target = '';
      } else if (current === '\\') {
        target += current;
        inEscape = true;
        continue;
      } else {
        target += current;

        if (name !== null && inEscape === false && current === '\'') {
          inString = !inString;
        }
      }

      inEscape = false;
    }

    // check for the case where we have a single value with no name
    // and there is a default property that we can use to obtain
    // the name of the property with which the value should be associated.
    if (!foundName) {
      name = this._getPrimaryPropertyName(resources, context);
    }

    if (name !== null) {
      info = language.inspectAttribute(resources, '?', name, target.trim());
      language.createAttributeInstruction(resources, element, info, instruction, context);

      if (!instruction.attributes[info.attrName]) {
        instruction.attributes[info.attrName] = info.attrValue;
      }
    }

    return instruction;
  }

  _getPrimaryPropertyName(resources, context) {
    let type = resources.getAttribute(context.attributeName);
    if (type && type.primaryProperty) {
      return type.primaryProperty.name;
    }
    return null;
  }

  'for'(resources, element, info, existingInstruction) {
    let parts;
    let keyValue;
    let instruction;
    let attrValue;
    let isDestructuring;

    attrValue = info.attrValue;
    isDestructuring = attrValue.match(/^ *[[].+[\]]/);
    parts = isDestructuring ? attrValue.split('of ') : attrValue.split(' of ');

    if (parts.length !== 2) {
      throw new Error('Incorrect syntax for "for". The form is: "$local of $items" or "[$key, $value] of $items".');
    }

    instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    if (isDestructuring) {
      keyValue = parts[0].replace(/[[\]]/g, '').replace(/,/g, ' ').replace(/\s+/g, ' ').trim().split(' ');
      instruction.attributes.key = keyValue[0];
      instruction.attributes.value = keyValue[1];
    } else {
      instruction.attributes.local = parts[0];
    }

    instruction.attributes.items = new BindingExpression(
      this.observerLocator,
      'items',
      this.parser.parse(parts[1]),
      bindingMode.oneWay,
      resources.lookupFunctions
    );

    return instruction;
  }

  'two-way'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
        this.observerLocator,
        this.attributeMap.map(element.tagName, info.attrName),
        this.parser.parse(info.attrValue),
        bindingMode.twoWay,
        resources.lookupFunctions
      );

    return instruction;
  }

  'to-view'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      bindingMode.toView,
      resources.lookupFunctions
    );

    return instruction;
  }

  'from-view'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      bindingMode.fromView,
      resources.lookupFunctions
    );

    return instruction;
  }

  'one-time'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      bindingMode.oneTime,
      resources.lookupFunctions
    );

    return instruction;
  }
}

SyntaxInterpreter.prototype['one-way'] = SyntaxInterpreter.prototype['to-view'];
<commit_msg>chore(all): fix lint issues<commit_after>/*eslint dot-notation:0*/
import {
  Parser,
  ObserverLocator,
  EventManager,
  ListenerExpression,
  BindingExpression,
  CallExpression,
  bindingMode,
  delegationStrategy
} from 'aurelia-binding';

import {BehaviorInstruction} from 'aurelia-templating';
import * as LogManager from 'aurelia-logging';
import {AttributeMap} from './attribute-map';

export class SyntaxInterpreter {
  static inject = [Parser, ObserverLocator, EventManager, AttributeMap];

  constructor(parser, observerLocator, eventManager, attributeMap) {
    this.parser = parser;
    this.observerLocator = observerLocator;
    this.eventManager = eventManager;
    this.attributeMap = attributeMap;
  }

  interpret(resources, element, info, existingInstruction, context) {
    if (info.command in this) {
      return this[info.command](resources, element, info, existingInstruction, context);
    }

    return this.handleUnknownCommand(resources, element, info, existingInstruction, context);
  }

  handleUnknownCommand(resources, element, info, existingInstruction, context) {
    LogManager.getLogger('templating-binding').warn('Unknown binding command.', info);
    return existingInstruction;
  }

  determineDefaultBindingMode(element, attrName, context) {
    let tagName = element.tagName.toLowerCase();

    if (tagName === 'input' && (attrName === 'value' || attrName === 'files') && element.type !== 'checkbox' && element.type !== 'radio'
      || tagName === 'input' && attrName === 'checked' && (element.type === 'checkbox' || element.type === 'radio')
      || (tagName === 'textarea' || tagName === 'select') && attrName === 'value'
      || (attrName === 'textcontent' || attrName === 'innerhtml') && element.contentEditable === 'true'
      || attrName === 'scrolltop'
      || attrName === 'scrollleft') {
      return bindingMode.twoWay;
    }

    if (context
      && attrName in context.attributes
      && context.attributes[attrName]
      && context.attributes[attrName].defaultBindingMode >= bindingMode.oneTime) {
      return context.attributes[attrName].defaultBindingMode;
    }

    return bindingMode.oneWay;
  }

  bind(resources, element, info, existingInstruction, context) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      info.defaultBindingMode === undefined || info.defaultBindingMode === null
        ? this.determineDefaultBindingMode(element, info.attrName, context)
        : info.defaultBindingMode,
      resources.lookupFunctions
    );

    return instruction;
  }

  trigger(resources, element, info) {
    return new ListenerExpression(
      this.eventManager,
      info.attrName,
      this.parser.parse(info.attrValue),
      delegationStrategy.none,
      true,
      resources.lookupFunctions
    );
  }

  capture(resources, element, info) {
    return new ListenerExpression(
      this.eventManager,
      info.attrName,
      this.parser.parse(info.attrValue),
      delegationStrategy.capturing,
      true,
      resources.lookupFunctions
    );
  }

  delegate(resources, element, info) {
    return new ListenerExpression(
      this.eventManager,
      info.attrName,
      this.parser.parse(info.attrValue),
      delegationStrategy.bubbling,
      true,
      resources.lookupFunctions
    );
  }

  call(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new CallExpression(
      this.observerLocator,
      info.attrName,
      this.parser.parse(info.attrValue),
      resources.lookupFunctions
    );

    return instruction;
  }

  options(resources, element, info, existingInstruction, context) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);
    let attrValue = info.attrValue;
    let language = this.language;
    let name = null;
    let target = '';
    let current;
    let i;
    let ii;
    let inString = false;
    let inEscape = false;
    let foundName = false;

    for (i = 0, ii = attrValue.length; i < ii; ++i) {
      current = attrValue[i];

      if (current === ';' && !inString) {
        if (!foundName) {
          name = this._getPrimaryPropertyName(resources, context);
        }
        info = language.inspectAttribute(resources, '?', name, target.trim());
        language.createAttributeInstruction(resources, element, info, instruction, context);

        if (!instruction.attributes[info.attrName]) {
          instruction.attributes[info.attrName] = info.attrValue;
        }

        target = '';
        name = null;
      } else if (current === ':' && name === null) {
        foundName = true;
        name = target.trim();
        target = '';
      } else if (current === '\\') {
        target += current;
        inEscape = true;
        continue;
      } else {
        target += current;

        if (name !== null && inEscape === false && current === '\'') {
          inString = !inString;
        }
      }

      inEscape = false;
    }

    // check for the case where we have a single value with no name
    // and there is a default property that we can use to obtain
    // the name of the property with which the value should be associated.
    if (!foundName) {
      name = this._getPrimaryPropertyName(resources, context);
    }

    if (name !== null) {
      info = language.inspectAttribute(resources, '?', name, target.trim());
      language.createAttributeInstruction(resources, element, info, instruction, context);

      if (!instruction.attributes[info.attrName]) {
        instruction.attributes[info.attrName] = info.attrValue;
      }
    }

    return instruction;
  }

  _getPrimaryPropertyName(resources, context) {
    let type = resources.getAttribute(context.attributeName);
    if (type && type.primaryProperty) {
      return type.primaryProperty.name;
    }
    return null;
  }

  'for'(resources, element, info, existingInstruction) {
    let parts;
    let keyValue;
    let instruction;
    let attrValue;
    let isDestructuring;

    attrValue = info.attrValue;
    isDestructuring = attrValue.match(/^ *[[].+[\]]/);
    parts = isDestructuring ? attrValue.split('of ') : attrValue.split(' of ');

    if (parts.length !== 2) {
      throw new Error('Incorrect syntax for "for". The form is: "$local of $items" or "[$key, $value] of $items".');
    }

    instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    if (isDestructuring) {
      keyValue = parts[0].replace(/[[\]]/g, '').replace(/,/g, ' ').replace(/\s+/g, ' ').trim().split(' ');
      instruction.attributes.key = keyValue[0];
      instruction.attributes.value = keyValue[1];
    } else {
      instruction.attributes.local = parts[0];
    }

    instruction.attributes.items = new BindingExpression(
      this.observerLocator,
      'items',
      this.parser.parse(parts[1]),
      bindingMode.oneWay,
      resources.lookupFunctions
    );

    return instruction;
  }

  'two-way'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
        this.observerLocator,
        this.attributeMap.map(element.tagName, info.attrName),
        this.parser.parse(info.attrValue),
        bindingMode.twoWay,
        resources.lookupFunctions
      );

    return instruction;
  }

  'to-view'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      bindingMode.toView,
      resources.lookupFunctions
    );

    return instruction;
  }

  'from-view'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      bindingMode.fromView,
      resources.lookupFunctions
    );

    return instruction;
  }

  'one-time'(resources, element, info, existingInstruction) {
    let instruction = existingInstruction || BehaviorInstruction.attribute(info.attrName);

    instruction.attributes[info.attrName] = new BindingExpression(
      this.observerLocator,
      this.attributeMap.map(element.tagName, info.attrName),
      this.parser.parse(info.attrValue),
      bindingMode.oneTime,
      resources.lookupFunctions
    );

    return instruction;
  }
}

SyntaxInterpreter.prototype['one-way'] = SyntaxInterpreter.prototype['to-view'];
<|endoftext|>


<commit_before>dc.canvasScatterPlot = function(parent, chartGroup) {
  var _chart = dc.coordinateGridMixin({});
  _chart._mandatoryAttributes(['dimension', 'x', 'xAccessor', 'yAccessor']);

  var _canvas;
  var _context;
  var _xAccessor;
  var _xTickFormator;
  var _y;
  var _yAccessor;
  var _yTickFormator;

  var tick_length = 8;
  var font_size = 10;
  var label_padding = 3;
  var num_ticks = 6;

  _chart._doRender = function() {
    return _chart._doRedraw();
  }

  _chart._doRedraw = function () {
    var selected = _chart.dimension().top(Infinity);
    var xDomain = d3.extent(selected, function(d) {
      return _xAccessor(d);
    });
    var yDomain = d3.extent(selected, function(d) {
      return _yAccessor(d);
    });

    _chart.resetCanvas();
    renderXAxis(xDomain);
    renderYAxis(yDomain);

    selected.forEach(function(d, i) {
      _context.beginPath();
      _context.rect(
        _chart.margins().left + _chart.x()(_xAccessor(d)),
        _chart.height() - _chart.margins().bottom - _y(_yAccessor(d)),
        4, 4);
      _context.fillStyle = _chart.getColor(d, i);
      _context.fill();
      _context.closePath();
    });

    return _chart;
  }

  _chart.resetCanvas = function() {
    _chart.select('canvas').remove();
    return generateCanvas();
  }
  function generateCanvas() {
    _canvas = _chart.root().append('canvas')
      .attr('width', _chart.width())
      .attr('height', _chart.height());
    _context = _canvas.node().getContext('2d');
    return _canvas;
  }

  _chart.xAccessor = function(_) {
    if(!arguments.length) {
      return _xAccessor;
    }
    _xAccessor = _;
    return _chart;
  }
  _chart.xTickFormator = function(_) {
    if(!arguments.length) {
      return _xTickFormator;
    }
    _xTickFormator = _;
    return _chart;
  }
  function renderXAxis(domain) {
    if ("ordinal" === getScaleType(_chart.x())) {
      _chart.x().rangeRoundBands([_chart.margins().left, _chart.effectiveWidth()]);
      //ticks function is used to iterate through axis ticks
      //define ticks function to returns domain array
      _chart.x().ticks = function() { return _chart.x().domain(); }
      _xTickFormator = function(value) { return value; }
    } else {
      _chart.x().domain(domain);
      _chart.x().range([_chart.margins().left, _chart.effectiveWidth()]);
    }

    //draw x-axis baseline
    _context.beginPath();
    _context.rect(
      _chart.margins().left,
      _chart.height() - _chart.margins().bottom,
      _chart.effectiveWidth(),
      1);
    _context.fillStyle = 'black';
    _context.fill();
    _context.closePath();

    var formator = _xTickFormator ? _xTickFormator : _chart.x().tickFormat(num_ticks);
    _chart.x().ticks(num_ticks).forEach(function(tick) {
      var x = _chart.margins().left + _chart.x()(tick);
      var y = _chart.height() - _chart.margins().bottom;
      _context.beginPath();
      _context.rect(x, y, 1, tick_length);
      _context.fillStyle = 'black';
      _context.fill();
      _context.closePath();

      var label = formator(tick);
      var dx = (label.length / 2) * -5; //shift text left to center
      var dy = font_size + tick_length + label_padding; //shift text below tick lines
      _context.font = font_size + 'pt';
      _context.fillText(label, x + dx, y + dy);
    });
  }

  _chart.y = function(_) {
    if(!arguments.length) {
      return _y;
    }
    _y = _;
    return _chart;
  }
  _chart.yAccessor = function(_) {
    if(!arguments.length) {
      return _yAccessor;
    }
    _yAccessor = _;
    return _chart;
  }
  _chart.yTickFormator = function(_) {
    if(!arguments.length) {
      return _yTickFormator;
    }
    _yTickFormator = _;
    return _chart;
  }
  function renderYAxis(domain) {
    if (_y === undefined) {
      _y = d3.scale.linear();
    }
    if ("ordinal" === getScaleType(_y)) {
      _y.rangeRoundBands([_chart.margins().top, _chart.effectiveHeight()]);
      //ticks function is used to iterate through axis ticks
      //define ticks function to returns domain array
      _y.ticks = function() { return _y.domain(); }
      _yTickFormator = function(value) { return value; }
    } else {
      _y.domain(domain);
      _y.range([_chart.margins().top, _chart.effectiveHeight()]);
    }

    //draw y-axis baseline
    _context.beginPath();
    _context.rect(
      _chart.margins().left,
      _chart.margins().top,
      1,
      _chart.effectiveHeight());
    _context.fillStyle = 'black';
    _context.fill();
    _context.closePath();

    var formator = _yTickFormator ? _yTickFormator : _y.tickFormat(num_ticks);
    _y.ticks(num_ticks).forEach(function(tick) {
      var x = _chart.margins().left - tick_length;
      var y = _chart.height() - _chart.margins().bottom - _y(tick);
      _context.beginPath();
      _context.rect(x, y, tick_length, 1);
      _context.fillStyle = 'black';
      _context.fill();
      _context.closePath();

      var label = formator(tick);
      var dx = (label.length * -5) - label_padding; //shift text left to of ticks
      var dy = font_size/3; //center text
      _context.font = font_size + 'pt';
      _context.fillText(label, x + dx, y + dy);
    });
  }

  function getScaleType(scale) {
    var type = "quantitative";
    if (scale.hasOwnProperty("rangePoints")) {
      type = "ordinal";
    }
    return type;
  }

  return _chart.anchor(parent, chartGroup);
}<commit_msg>replace _y member with value from coordinateGridMixin base class<commit_after>dc.canvasScatterPlot = function(parent, chartGroup) {
  var _chart = dc.coordinateGridMixin({});
  _chart._mandatoryAttributes(['dimension', 'x', 'xAccessor', 'yAccessor']);

  var _canvas;
  var _context;
  var _xAccessor;
  var _xTickFormator;
  var _yAccessor;
  var _yTickFormator;

  var tick_length = 8;
  var font_size = 10;
  var label_padding = 3;
  var num_ticks = 6;

  _chart._doRender = function() {
    return _chart._doRedraw();
  }

  _chart._doRedraw = function () {
    var selected = _chart.dimension().top(Infinity);
    var xDomain = d3.extent(selected, function(d) {
      return _xAccessor(d);
    });
    var yDomain = d3.extent(selected, function(d) {
      return _yAccessor(d);
    });

    _chart.resetCanvas();
    renderXAxis(xDomain);
    renderYAxis(yDomain);

    selected.forEach(function(d, i) {
      _context.beginPath();
      _context.rect(
        _chart.margins().left + _chart.x()(_xAccessor(d)),
        _chart.height() - _chart.margins().bottom - _chart.y()(_yAccessor(d)),
        4, 4);
      _context.fillStyle = _chart.getColor(d, i);
      _context.fill();
      _context.closePath();
    });

    return _chart;
  }

  _chart.resetCanvas = function() {
    _chart.select('canvas').remove();
    return generateCanvas();
  }
  function generateCanvas() {
    _canvas = _chart.root().append('canvas')
      .attr('width', _chart.width())
      .attr('height', _chart.height());
    _context = _canvas.node().getContext('2d');
    return _canvas;
  }

  _chart.xAccessor = function(_) {
    if(!arguments.length) {
      return _xAccessor;
    }
    _xAccessor = _;
    return _chart;
  }
  _chart.xTickFormator = function(_) {
    if(!arguments.length) {
      return _xTickFormator;
    }
    _xTickFormator = _;
    return _chart;
  }
  function renderXAxis(domain) {
    if ("ordinal" === getScaleType(_chart.x())) {
      _chart.x().rangeRoundBands([_chart.margins().left, _chart.effectiveWidth()]);
      //ticks function is used to iterate through axis ticks
      //define ticks function to returns domain array
      _chart.x().ticks = function() { return _chart.x().domain(); }
      _xTickFormator = function(value) { return value; }
    } else {
      _chart.x().domain(domain);
      _chart.x().range([_chart.margins().left, _chart.effectiveWidth()]);
    }

    //draw x-axis baseline
    _context.beginPath();
    _context.rect(
      _chart.margins().left,
      _chart.height() - _chart.margins().bottom,
      _chart.effectiveWidth(),
      1);
    _context.fillStyle = 'black';
    _context.fill();
    _context.closePath();

    var formator = _xTickFormator ? _xTickFormator : _chart.x().tickFormat(num_ticks);
    _chart.x().ticks(num_ticks).forEach(function(tick) {
      var x = _chart.margins().left + _chart.x()(tick);
      var y = _chart.height() - _chart.margins().bottom;
      _context.beginPath();
      _context.rect(x, y, 1, tick_length);
      _context.fillStyle = 'black';
      _context.fill();
      _context.closePath();

      var label = formator(tick);
      var dx = (label.length / 2) * -5; //shift text left to center
      var dy = font_size + tick_length + label_padding; //shift text below tick lines
      _context.font = font_size + 'pt';
      _context.fillText(label, x + dx, y + dy);
    });
  }

  _chart.yAccessor = function(_) {
    if(!arguments.length) {
      return _yAccessor;
    }
    _yAccessor = _;
    return _chart;
  }
  _chart.yTickFormator = function(_) {
    if(!arguments.length) {
      return _yTickFormator;
    }
    _yTickFormator = _;
    return _chart;
  }
  function renderYAxis(domain) {
    if (_chart.y() === undefined) {
      _chart.y(d3.scale.linear());
    }
    if ("ordinal" === getScaleType(_chart.y())) {
      _chart.y().rangeRoundBands([_chart.margins().top, _chart.effectiveHeight()]);
      //ticks function is used to iterate through axis ticks
      //define ticks function to returns domain array
      _chart.y().ticks = function() { return _chart.y().domain(); }
      _yTickFormator = function(value) { return value; }
    } else {
      _chart.y().domain(domain);
      _chart.y().range([_chart.margins().top, _chart.effectiveHeight()]);
    }

    //draw y-axis baseline
    _context.beginPath();
    _context.rect(
      _chart.margins().left,
      _chart.margins().top,
      1,
      _chart.effectiveHeight());
    _context.fillStyle = 'black';
    _context.fill();
    _context.closePath();

    var formator = _yTickFormator ? _yTickFormator : _chart.y().tickFormat(num_ticks);
    _chart.y().ticks(num_ticks).forEach(function(tick) {
      var x = _chart.margins().left - tick_length;
      var y = _chart.height() - _chart.margins().bottom - _chart.y()(tick);
      _context.beginPath();
      _context.rect(x, y, tick_length, 1);
      _context.fillStyle = 'black';
      _context.fill();
      _context.closePath();

      var label = formator(tick);
      var dx = (label.length * -5) - label_padding; //shift text left to of ticks
      var dy = font_size/3; //center text
      _context.font = font_size + 'pt';
      _context.fillText(label, x + dx, y + dy);
    });
  }

  function getScaleType(scale) {
    var type = "quantitative";
    if (scale.hasOwnProperty("rangePoints")) {
      type = "ordinal";
    }
    return type;
  }

  return _chart.anchor(parent, chartGroup);
}<|endoftext|>


<commit_before>// Your code goes here.
<commit_msg>Introduction to JS Completed All tests passed.<commit_after>// Your code goes here.

// Exercise Number 1

var name = "Thomas Birai";

var age = 25;

var major = "Computer Information Systems";

var classStanding = ["Freshman", "Sophomore", "Junior", "Senior" , "Alumnus"];

var message = "Hello! My name is "+name+". I'm "+age+" years old, and I am a "+classStanding[3]+" "+major+" major at Union College.";

console.log(message);<|endoftext|>


<commit_before>function(objectID)
{
	var weave = objectID ? document.getElementById(objectID) : document;

	/**
	 * Creates a WeavePath object.
	 * Accepts an optional Array or list of names to serve as the base path.
	 */
	weave.path = function(names/*, ...rest*/)
	{
		// if there are multiple arguments passed to the function, create an Array
		if (arguments.length != 1 || names.constructor != Array)
			names = A(arguments);

		return new WeavePath(names);
	};

	// Used by callbackToString(), maps an integer id to an object with two properties: callback and name
	weave._WeavePathCallbacks = [];

	// converts an arguments object to an Array
	function A(argumentsObject)
	{
		var array = [];
		var i = argumentsObject.length;
		while (i--)
			array[i] = argumentsObject[i];
		return array;
	}

	// constructor, accepts a single parameter - the base path Array
	function WeavePath(path)
	{
		if (!path)
			path = [];

		// private variables
		var stack = []; // stack of argument counts from push() calls, used with pop()
		var vars = {}; // used with exec() and getVar()
		var libs = []; // used with exec()

		// public variables and non-chainable methods

		/**
		 * A pointer to the Weave instance.
		 */
		this.weave = weave;
		/**
		 * Makes a copy of the current path Array.
		 */
		this.getPath = function()
		{
			return this.path.concat();
		};
		/**
		 * Gets the session state of an object at the current path or relative to the current path.
		 * Accepts an optional list of names relative to the current path.
		 */
		this.getState = function(/*...names*/)
		{
			return weave.getSessionState(path.concat(A(arguments)));
		};
		/**
		 * Gets the object type at the current path.
		 */
		this.getType = function()
		{
			return weave.getObjectType(path);
		};
		/**
		 * Gets an Array of child names under the current path.
		 */
		this.getNames = function()
		{
			return weave.getChildNames(path);
		};
		/**
		 * Gets a variable that was previously specified in WeavePath.vars() or saved with WeavePath.exec().
		 * The first parameter is the variable name.
		 */
		this.getVar = function(name)
		{
			return vars[name];
		};

		// public chainable methods

		/**
		 * Specify any number of names to push on to the end of the path.
		 * Accepts an optional list of names relative to the current path.
		 */
		this.push = function(/*...names*/)
		{
			if (assertParams('push', arguments))
			{
				// append names to path
				for (var i = 0; i < arguments.length; i++)
					path.push(arguments[i]);
				// remember the number of names we appended
				stack.push(arguments.length);
			}
			return this;
		};
		/**
		 * Pops off all names from previous call to push().  No arguments.
		 */
		this.pop = function()
		{
			if (stack.length)
				path.length -= stack.pop();
			else
				failMessage('pop', 'stack is empty');
			return this;
		};
		/**
		 * Request a new object without modifying the current path.
		 * Accepts an optional list of names relative to the current path.
		 * The final parameter should be the object type passed to weave.requestObject().
		 */
		this.request = function(/*...names, objectType*/)
		{
			if (assertParams('request', arguments))
			{
				var pathcopy = path.concat(A(arguments));
				var type = pathcopy.pop();
				weave.requestObject(pathcopy, type)
					|| failPath('request', pathcopy);
			}
			return this;
		};
		/**
		 * Remove a dynamically created object without modifying the current path.
		 * Accepts an optional list of names relative to the current path.
		 */
		this.remove = function(/*...names*/)
		{
			var pathcopy = path.concat(A(arguments));
			weave.removeObject(pathcopy)
				|| failPath('remove', pathcopy);
			return this;
		};
		/**
		 * Calls weave.setChildNameOrder() for the current path.
		 * Accepts a list of ordered child names.
		 */
		this.reorder = function(/*...orderedNames*/)
		{
			if (assertParams('reorder', arguments))
			{
				weave.setChildNameOrder(path, A(arguments))
					|| failMessage('reorder', 'path does not refer to an ILinkableHashMap: ' + path);
			}
			return this;
		};
		/**
		 * Sets the session state without modifying the current path, removing any
		 * dynamically created objects that do not appear in the new state.
		 * Accepts an optional list of names relative to the current path.
		 * The final parameter should be the session state diff.
		 */
		this.state = function(/*...names, state*/)
		{
			if (assertParams('state', arguments))
			{
				var pathcopy = path.concat(A(arguments));
				var state = pathcopy.pop();
				weave.setSessionState(pathcopy, state, true)
					|| failObject('state', pathcopy);
			}
			return this;
		};
		/**
		 * Applies a session state as a diff, keeping any dynamically created objects that do not appear in the new state.
		 * Accepts an optional list of names relative to the current path.
		 * The final parameter should be the session state diff.
		 */
		this.diff = function(/*...names, diff*/)
		{
			if (assertParams('diff', arguments))
			{
				var pathcopy = path.concat(A(arguments));
				var diff = pathcopy.pop();
				weave.setSessionState(pathcopy, diff, false)
					|| failObject('diff', pathcopy);
			}
			return this;
		};
		/**
		 * Specifies additional variables to be used in subsequent calls to exec().
		 * The parameter should be an object mapping variable names to their values.
		 */
		this.vars = function(newVars)
		{
			for (var key in newVars)
				vars[key] = newVars[key];
			return this;
		};
		/**
		 * Specifies additional libraries to be included in subsequent calls to exec().
		 */
		this.libs = function(/*...libraries*/)
		{
			if (assertParams('libs', arguments))
				A(arguments).forEach(function(lib){ if (libs.indexOf(lib) < 0) libs.push(lib); });
			return this;
		};
		/**
		 * Calls weave.evaluateExpression() using the current path, vars, and libs.
		 * First parameter is the script to be evaluated by Weave at the current path.
		 * Second parameter is an optional callback or variable name.
		 * - If given a callback function, the function will be passed the result of
		 *   evaluating the expression, setting the 'this' pointer to this WeavePath object.
		 * - If the second parameter is a variable name, the result will be stored as a variable
		 *   as if it was passed as an object property to WeavePath.vars().  It may then be used
		 *   in future calls to WeavePath.exec() or retrieved with WeavePath.getVar().
		 */
		this.exec = function(script, callback_or_variableName)
		{
			var result = weave.evaluateExpression(path, script, vars, libs);
			if (typeof callback_or_variableName == 'function')
				callback_or_variableName.apply(this, [result]);
			else
				vars[callback_or_variableName] = result;
			return this;
		};
		/**
		 * Adds a grouped callback to the object at the current path.
		 * First parameter is the callback function.
		 * Second parameter is a Boolean, when set to true will trigger the callback now.
		 * Since this adds a grouped callback, the callback will not run immediately when addCallback() is called.
		 */
		this.addCallback = function(callback, triggerCallbackNow)
		{
			if (assertParams('addCallback', arguments))
			{
				weave.addCallback(path, callbackToString(callback), triggerCallbackNow)
					|| failObject('addCallback');
			}
			return this;
		};
		/**
		 * Removes a callback from the object at the current path.
		 */
		this.removeCallback = function(callback)
		{
			if (assertParams('removeCallback', arguments))
			{
				weave.removeCallback(path, callbackToString(callback))
					|| failObject('removeCallback');
			}
			return this;
		};
		/**
		 * Applies a function with optional parameters, setting 'this' pointer to the WeavePath object
		 */
		this.call = function(func/*[, ...args]*/)
		{
			if (assertParams('call', arguments))
			{
				var a = A(arguments);
				a.shift().apply(this, a);
			}
			return this;
		};
		/**
		 * Applies a function to each item in an Array or an Object.
		 * If items is an Array, this has the same effect as WeavePath.call(function(){ itemsArray.forEach(visitorFunction, this); }).
		 * If items is an Object, it will behave like WeavePath.call(function(){ for(var key in items) visitorFunction.call(this, items[key], key, items); }).
		 */
		this.forEach = function(items, visitorFunction)
		{
			if (assertParams('forEach', arguments, 2))
			{
				if (items.constructor == Array)
					items.forEach(visitorFunction, this);
				else
					for (var key in items) visitorFunction.call(this, items[key], key, items);
			}
			return this;
		};

		// private functions
		function callbackToString(callback)
		{
			var list = weave._WeavePathCallbacks;
			for (var i in list)
				if (list[i].callback == callback)
					return list[i].name;

			var idStr;
			try
			{
				idStr = JSON.stringify(objectID);
			}
			catch (e)
			{
				idStr = '"' + objectId + '"';
			}

			var name = 'function(){' +
				'  var weave = document.getElementById('+idStr+');' +
				'  weave._WeavePathCallbacks['+list.length+'].callback.call(weave);' +
				'}';

			list.push({ 'callback': callback, 'name': name });

			return name;
		}
		function assertParams(methodName, args, minLength)
		{
			if (!minLength)
				minLength = 1;
			if (args.length < minLength)
			{
				var msg = 'requires at least ' + ((minLength == 1) ? 'one parameter' : (minLength + ' parameters'));
				failMessage(methodName, msg);
				return false;
			}
			return true;
		}
		function failPath(methodName, path)
		{
			var msg = 'command failed (path: ' + (path || this.path) + ')';
			failMessage(methodName, msg);
		}
		function failObject(methodName, path)
		{
			var msg = 'object does not exist (path: ' + (path || this.path) + ')';
			failMessage(methodName, msg);
		}
		function failMessage(methodName, message)
		{
			var str = 'WeavePath.' + methodName + '(): ' + message;

			//TODO - mode where error is logged instead of thrown
			//console.log(str);

			throw new Error(str);
		}
	}
}
<commit_msg>added support for an Array as a parameter to reorder().<commit_after>function(objectID)
{
	var weave = objectID ? document.getElementById(objectID) : document;

	/**
	 * Creates a WeavePath object.
	 * Accepts an optional Array or list of names to serve as the base path.
	 */
	weave.path = function(names/*, ...rest*/)
	{
		// if there are multiple arguments passed to the function, create an Array
		if (arguments.length != 1 || names.constructor != Array)
			names = A(arguments);

		return new WeavePath(names);
	};

	// Used by callbackToString(), maps an integer id to an object with two properties: callback and name
	weave._WeavePathCallbacks = [];

	// converts an arguments object to an Array
	function A(argumentsObject)
	{
		var array = [];
		var i = argumentsObject.length;
		while (i--)
			array[i] = argumentsObject[i];
		return array;
	}

	// constructor, accepts a single parameter - the base path Array
	function WeavePath(path)
	{
		if (!path)
			path = [];

		// private variables
		var stack = []; // stack of argument counts from push() calls, used with pop()
		var vars = {}; // used with exec() and getVar()
		var libs = []; // used with exec()

		// public variables and non-chainable methods

		/**
		 * A pointer to the Weave instance.
		 */
		this.weave = weave;
		/**
		 * Makes a copy of the current path Array.
		 */
		this.getPath = function()
		{
			return this.path.concat();
		};
		/**
		 * Gets the session state of an object at the current path or relative to the current path.
		 * Accepts an optional list of names relative to the current path.
		 */
		this.getState = function(/*...names*/)
		{
			return weave.getSessionState(path.concat(A(arguments)));
		};
		/**
		 * Gets the object type at the current path.
		 */
		this.getType = function()
		{
			return weave.getObjectType(path);
		};
		/**
		 * Gets an Array of child names under the current path.
		 */
		this.getNames = function()
		{
			return weave.getChildNames(path);
		};
		/**
		 * Gets a variable that was previously specified in WeavePath.vars() or saved with WeavePath.exec().
		 * The first parameter is the variable name.
		 */
		this.getVar = function(name)
		{
			return vars[name];
		};

		// public chainable methods

		/**
		 * Specify any number of names to push on to the end of the path.
		 * Accepts an optional list of names relative to the current path.
		 */
		this.push = function(/*...names*/)
		{
			if (assertParams('push', arguments))
			{
				// append names to path
				for (var i = 0; i < arguments.length; i++)
					path.push(arguments[i]);
				// remember the number of names we appended
				stack.push(arguments.length);
			}
			return this;
		};
		/**
		 * Pops off all names from previous call to push().  No arguments.
		 */
		this.pop = function()
		{
			if (stack.length)
				path.length -= stack.pop();
			else
				failMessage('pop', 'stack is empty');
			return this;
		};
		/**
		 * Request a new object without modifying the current path.
		 * Accepts an optional list of names relative to the current path.
		 * The final parameter should be the object type passed to weave.requestObject().
		 */
		this.request = function(/*...names, objectType*/)
		{
			if (assertParams('request', arguments))
			{
				var pathcopy = path.concat(A(arguments));
				var type = pathcopy.pop();
				weave.requestObject(pathcopy, type)
					|| failPath('request', pathcopy);
			}
			return this;
		};
		/**
		 * Remove a dynamically created object without modifying the current path.
		 * Accepts an optional list of names relative to the current path.
		 */
		this.remove = function(/*...names*/)
		{
			var pathcopy = path.concat(A(arguments));
			weave.removeObject(pathcopy)
				|| failPath('remove', pathcopy);
			return this;
		};
		/**
		 * Calls weave.setChildNameOrder() for the current path.
		 * Accepts an Array or a list of ordered child names.
		 */
		this.reorder = function(orderedNames/*, ...rest*/)
		{
			if (assertParams('reorder', arguments))
			{
				if (arguments.length > 1)
					orderedNames = A(arguments);
				weave.setChildNameOrder(path, orderedNames)
					|| failMessage('reorder', 'path does not refer to an ILinkableHashMap: ' + path);
			}
			return this;
		};
		/**
		 * Sets the session state without modifying the current path, removing any
		 * dynamically created objects that do not appear in the new state.
		 * Accepts an optional list of names relative to the current path.
		 * The final parameter should be the session state diff.
		 */
		this.state = function(/*...names, state*/)
		{
			if (assertParams('state', arguments))
			{
				var pathcopy = path.concat(A(arguments));
				var state = pathcopy.pop();
				weave.setSessionState(pathcopy, state, true)
					|| failObject('state', pathcopy);
			}
			return this;
		};
		/**
		 * Applies a session state as a diff, keeping any dynamically created objects that do not appear in the new state.
		 * Accepts an optional list of names relative to the current path.
		 * The final parameter should be the session state diff.
		 */
		this.diff = function(/*...names, diff*/)
		{
			if (assertParams('diff', arguments))
			{
				var pathcopy = path.concat(A(arguments));
				var diff = pathcopy.pop();
				weave.setSessionState(pathcopy, diff, false)
					|| failObject('diff', pathcopy);
			}
			return this;
		};
		/**
		 * Specifies additional variables to be used in subsequent calls to exec().
		 * The parameter should be an object mapping variable names to their values.
		 */
		this.vars = function(newVars)
		{
			for (var key in newVars)
				vars[key] = newVars[key];
			return this;
		};
		/**
		 * Specifies additional libraries to be included in subsequent calls to exec().
		 */
		this.libs = function(/*...libraries*/)
		{
			if (assertParams('libs', arguments))
				A(arguments).forEach(function(lib){ if (libs.indexOf(lib) < 0) libs.push(lib); });
			return this;
		};
		/**
		 * Calls weave.evaluateExpression() using the current path, vars, and libs.
		 * First parameter is the script to be evaluated by Weave at the current path.
		 * Second parameter is an optional callback or variable name.
		 * - If given a callback function, the function will be passed the result of
		 *   evaluating the expression, setting the 'this' pointer to this WeavePath object.
		 * - If the second parameter is a variable name, the result will be stored as a variable
		 *   as if it was passed as an object property to WeavePath.vars().  It may then be used
		 *   in future calls to WeavePath.exec() or retrieved with WeavePath.getVar().
		 */
		this.exec = function(script, callback_or_variableName)
		{
			var result = weave.evaluateExpression(path, script, vars, libs);
			if (typeof callback_or_variableName == 'function')
				callback_or_variableName.apply(this, [result]);
			else
				vars[callback_or_variableName] = result;
			return this;
		};
		/**
		 * Adds a grouped callback to the object at the current path.
		 * First parameter is the callback function.
		 * Second parameter is a Boolean, when set to true will trigger the callback now.
		 * Since this adds a grouped callback, the callback will not run immediately when addCallback() is called.
		 */
		this.addCallback = function(callback, triggerCallbackNow)
		{
			if (assertParams('addCallback', arguments))
			{
				weave.addCallback(path, callbackToString(callback), triggerCallbackNow)
					|| failObject('addCallback');
			}
			return this;
		};
		/**
		 * Removes a callback from the object at the current path.
		 */
		this.removeCallback = function(callback)
		{
			if (assertParams('removeCallback', arguments))
			{
				weave.removeCallback(path, callbackToString(callback))
					|| failObject('removeCallback');
			}
			return this;
		};
		/**
		 * Applies a function with optional parameters, setting 'this' pointer to the WeavePath object
		 */
		this.call = function(func/*[, ...args]*/)
		{
			if (assertParams('call', arguments))
			{
				var a = A(arguments);
				a.shift().apply(this, a);
			}
			return this;
		};
		/**
		 * Applies a function to each item in an Array or an Object.
		 * If items is an Array, this has the same effect as WeavePath.call(function(){ itemsArray.forEach(visitorFunction, this); }).
		 * If items is an Object, it will behave like WeavePath.call(function(){ for(var key in items) visitorFunction.call(this, items[key], key, items); }).
		 */
		this.forEach = function(items, visitorFunction)
		{
			if (assertParams('forEach', arguments, 2))
			{
				if (items.constructor == Array)
					items.forEach(visitorFunction, this);
				else
					for (var key in items) visitorFunction.call(this, items[key], key, items);
			}
			return this;
		};

		// private functions
		function callbackToString(callback)
		{
			var list = weave._WeavePathCallbacks;
			for (var i in list)
				if (list[i].callback == callback)
					return list[i].name;

			var idStr;
			try
			{
				idStr = JSON.stringify(objectID);
			}
			catch (e)
			{
				idStr = '"' + objectId + '"';
			}

			var name = 'function(){' +
				'  var weave = document.getElementById('+idStr+');' +
				'  weave._WeavePathCallbacks['+list.length+'].callback.call(weave);' +
				'}';

			list.push({ 'callback': callback, 'name': name });

			return name;
		}
		function assertParams(methodName, args, minLength)
		{
			if (!minLength)
				minLength = 1;
			if (args.length < minLength)
			{
				var msg = 'requires at least ' + ((minLength == 1) ? 'one parameter' : (minLength + ' parameters'));
				failMessage(methodName, msg);
				return false;
			}
			return true;
		}
		function failPath(methodName, path)
		{
			var msg = 'command failed (path: ' + (path || this.path) + ')';
			failMessage(methodName, msg);
		}
		function failObject(methodName, path)
		{
			var msg = 'object does not exist (path: ' + (path || this.path) + ')';
			failMessage(methodName, msg);
		}
		function failMessage(methodName, message)
		{
			var str = 'WeavePath.' + methodName + '(): ' + message;

			//TODO - mode where error is logged instead of thrown
			//console.log(str);

			throw new Error(str);
		}
	}
}
<|endoftext|>


<commit_before>/**
 * @file MaterialTreeSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import TreeSelect from '../TreeSelect';
import MaterialProvider from '../MaterialProvider';

import Theme from '../Theme';
import SelectMode from '../_statics/SelectMode';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import ComponentUtil from '../_vendors/ComponentUtil';

class MaterialTreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.treeSelect = createRef();
        this.treeSelectInstance = null;

        this.state = {
            value: props.value
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.treeSelectInstance && this.treeSelectInstance.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.treeSelectInstance && this.treeSelectInstance.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.treeSelectInstance && this.treeSelectInstance.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.treeSelectInstance && this.treeSelectInstance.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.treeSelectInstance && this.treeSelectInstance.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.treeSelectInstance && this.treeSelectInstance.closePopup();
    };

    handleTriggerChange = value => {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    };

    componentDidMount() {
        this.treeSelectInstance = this.treeSelect && this.treeSelect.current;
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate, disabled, required,
                ...restProps
            } = this.props,
            {value} = this.state;

        return (
            <MaterialProvider className={classNames('material-tree-select', {
                [className]: className
            })}
                              style={style}
                              theme={theme}
                              label={label}
                              isLabelAnimate={isLabelAnimate}
                              hasValue={value && value.length > 0}
                              disabled={disabled}
                              required={required}>
                <TreeSelect {...restProps}
                            ref={this.treeSelect}
                            value={value}
                            disabled={disabled}
                            onChange={this.handleTriggerChange}/>
            </MaterialProvider>
        );

    }
}

MaterialTreeSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * The name of the MaterialTreeSelect.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.any,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The value of the MaterialTreeSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the MaterialTreeSelect.
     */
    placeholder: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),
    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    /**
     * The options data.
     */
    data: PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the tree node.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the tree node.
         */
        style: PropTypes.object,

        /**
         * The theme of the tree button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The text value of the tree button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The tree node's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the tree node. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the tree node will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        title: PropTypes.string,

        children: PropTypes.array,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        itemRenderer: PropTypes.func,

        /**
         * Callback function fired when a tree node touch-tapped.
         */
        onClick: PropTypes.func

    }), PropTypes.array]),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    required: PropTypes.bool,

    /**
     * The select mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the MaterialTreeSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    useFilter: PropTypes.bool,
    filterIconCls: PropTypes.string,
    noMatchedMsg: PropTypes.string,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsed: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    resetPopPositionWait: PropTypes.number,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.func,

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onItemClick: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    onWheel: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

MaterialTreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    isLabelAnimate: true,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    data: [],
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,
    tipPosition: Position.BOTTOM,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',

    isSelectRecursive: false,
    allowCollapse: true,
    collapsed: false,

    required: false,

    resetPopPositionWait: 250

};

export default MaterialTreeSelect;
<commit_msg>update MaterialTreeSelect<commit_after>/**
 * @file MaterialTreeSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import TreeSelect from '../TreeSelect';
import MaterialProvider from '../MaterialProvider';

import Theme from '../Theme';
import SelectMode from '../_statics/SelectMode';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import ComponentUtil from '../_vendors/ComponentUtil';

class MaterialTreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.treeSelect = createRef();
        this.treeSelectInstance = null;

        this.state = {
            value: props.value
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.treeSelectInstance && this.treeSelectInstance.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.treeSelectInstance && this.treeSelectInstance.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.treeSelectInstance && this.treeSelectInstance.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.treeSelectInstance && this.treeSelectInstance.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.treeSelectInstance && this.treeSelectInstance.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.treeSelectInstance && this.treeSelectInstance.closePopup();
    };

    handleTriggerChange = value => {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    };

    componentDidMount() {
        this.treeSelectInstance = this.treeSelect && this.treeSelect.current;
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate, disabled, required,
                ...restProps
            } = this.props,
            {value} = this.state;

        return (
            <MaterialProvider className={classNames('material-tree-select', {
                [className]: className
            })}
                              style={style}
                              theme={theme}
                              label={label}
                              isLabelAnimate={isLabelAnimate}
                              hasValue={value && value.length > 0}
                              disabled={disabled}
                              required={required}>
                <TreeSelect {...restProps}
                            ref={this.treeSelect}
                            value={value}
                            disabled={disabled}
                            onChange={this.handleTriggerChange}/>
            </MaterialProvider>
        );

    }
}

MaterialTreeSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * The name of the MaterialTreeSelect.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.any,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The value of the MaterialTreeSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the MaterialTreeSelect.
     */
    placeholder: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),
    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    /**
     * The options data.
     */
    data: PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the tree node.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the tree node.
         */
        style: PropTypes.object,

        /**
         * The theme of the tree button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The text value of the tree button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The tree node's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the tree node. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the tree node will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        title: PropTypes.string,

        children: PropTypes.array,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        itemRenderer: PropTypes.func,

        /**
         * Callback function fired when a tree node touch-tapped.
         */
        onClick: PropTypes.func

    }), PropTypes.array]),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    required: PropTypes.bool,

    /**
     * The select mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the MaterialTreeSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    useFilter: PropTypes.bool,
    filterIconCls: PropTypes.string,
    noMatchedMsg: PropTypes.string,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsed: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    resetPopPositionWait: PropTypes.number,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.func,

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onItemClick: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    isNodeCollapsed: PropTypes.func,
    onWheel: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

MaterialTreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    isLabelAnimate: true,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    data: [],
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,
    tipPosition: Position.BOTTOM,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',

    isSelectRecursive: false,
    allowCollapse: true,
    collapsed: false,

    required: false,

    resetPopPositionWait: 250

};

export default MaterialTreeSelect;
<|endoftext|>