<commit_before>/**
 * marketo_form_cdialog.js
 *
 * Mail bug reports and suggestion to : Yukio Y <unknot304 AT gmail.com>
 * MIT License, Copyright 2015 Yukio Y.
 *
 * Requires: jquery.min.js, jquery-ui.js
 */
$(function(){
	var confirmDialog;
	var dialogContents;
	var xform;

	// Option Handling for Null Fill Fields　(this only supports text type fields)
	var null_fields = $('meta[name="mktoForm2CDialog:NULL_Fill_Field_API_Names"]').attr("content");
	var null_vals = {};
	// Option handling for email confirmation fields
	var mail_confirm = $('meta[name="mktoForm2CDialog:Mail_Confirm"]').attr("content");

	dialogContents = '\

\

\

\

\

\

';

	MktoForms2.whenReady(function (form) {
		// Mail confirm field will be dded if name="mktoForm2CDialog:Mail_Confirm" meta tag has "true"
		if (mail_confirm == "true") {
			// The following section (line from 38 to 78), "Mail confirmation fields code" is written by Sandord Whiteman.
			// https://nation.marketo.com/message/91696#91696
			// http://jsfiddle.net/sanford/9bo4rq8v/
			// MIT License

		    //  tag all outer wrapper DIVs with their inner inputs' names to make them more findable
		    for ( var formEl = form.getFormElem()[0], formRows = formEl.querySelectorAll('.mktoFormRow'), i = 0, imax = formRows.length, wrappedField; i < imax; i++ ) {
		        if ( (wrappedField = formRows[i].querySelector('INPUT,SELECT,TEXTAREA')) && wrappedField.name) {
		            formRows[i].setAttribute('data-wrapper-for',wrappedField.name);
		        }
		    }

		    // clone the Email field wrapper
		    var emailWrapper = formEl.querySelector('.mktoFormRow[data-wrapper-for="Email"]');
		    var emailConfirmWrapper = emailWrapper.cloneNode(true);

		    // set some strings
		    var emailConfirmFieldName = 'emailConfirm';
		    var emailConfirmFieldSelector = '#'+emailConfirmFieldName;
		    var emailConfirmFieldLabel = 'メールアドレス確認';
		    var	emailConfirmValidationError = 'メールアドレスとその確認は一致する必要があります';

		    // change some attributes before injecting
		    emailConfirmWrapper.setAttribute('data-wrapper-for',emailConfirmFieldName);
		    emailConfirmWrapper.querySelector('INPUT').name = emailConfirmWrapper.querySelector('INPUT').id = emailConfirmFieldName;
		    emailConfirmWrapper.querySelector('.mktoFormCol').className = 'mktoFormCol'; // fixes bug when cloning mandatory field
		    emailConfirmWrapper.querySelector('LABEL').innerHTML = emailConfirmFieldLabel;

		    // add to form
		    formEl.insertBefore(emailConfirmWrapper,emailWrapper.nextSibling);

		    // compare Email and emailConfirm before submitting
		    form.onValidate(function(valid) {
		        if ( form.vals().Email == emailConfirmWrapper.querySelector(emailConfirmFieldSelector).value ) {
		            form.submittable(true);
		        } else {
		            form.submittable(false);
		            form.showErrorMessage(emailConfirmValidationError,
		            form.getFormElem().find(emailConfirmFieldSelector));
		        }
		    });
		}

		// Creating Confirmation Dialogs
	    // Callback for Submit
		xform = form;
	    xform.onSubmit(function(){

	    	// creates dialog without open
	    	$("body").append(dialogContents);
	    	confirmDialog = $("#mktoConfirmDialog").dialog({
	    		autoOpen: false,
	    		modal: true,
	    		closeOnEscape: false,
	    		width: "auto",
	    		hight: "auto",
	    		buttons: {
	    			"送信": function(){
	    				if (Object.keys(null_vals).length != 0) {
	    					xform.vals(null_vals); // if NULL filled fields are specified.
	    				}
	    				xform.submitable(true);
	    				xform.submit();
	    				$(this).dialog("close");
	    			},
	    			"戻る": function(){
	    				null_vals = {};
	    				$(this).dialog("close")
	    			}
	    		},
	    		open: function(){
	    			xform.submitable(false);
	    			$('.ui-dialog-titlebar-close').hide();
	    			$("#mktoConfirmDialog").append('
上記内容をご確認いただき、送信ください。
');
	    		},
	    		close: function(event){
	    			// remove table all contents
	    			// $("#confirmationContents").find("tr:gt(-1)").remove();
	    			$(this).dialog("destroy");
	    			$(event.target).remove();
	    			xform.submitable(true);
	    		}
	    	});

	    	// get form columns and displaying selected items.
			var lastLabelforCheckBox = ""; // This is used for radio/checkbox field to remove the same label (offsetLabel).
			var $inputs = xform.getFormElem().find(':input');
			$inputs.each(function() {
				var displayLabel;
				var itemLabels;
				var offsetLabel;
				var displayValue;
				var fieldName = this.name;
				var fieldType = this.type;
				var fieldLabels = $(this).parent();
				var fieldValue = $(this).val();

				// append Label and Value according to types
				switch(fieldType) {
				case 'email':
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.text();
					displayValue = fieldValue;
					break;
				case 'checkbox':
				case 'radio':
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.text();
					//contains concatinated item labels (i.e. ABCD)
					itemLabels = fieldLabels.offsetParent().text();

					// if the checkbox has only one item, we displayed YES or No.
					if ("" == displayLabel) {
						displayLabel = fieldLabels.parent().text();
						if ($(this).prop('checked')) {
							displayValue = 'はい';
						} else {
							displayValue = 'いいえ';
						}
					} else {
						// if the checkbox has multiple items, we displayed checked one only with item's label.
						if ($(this).prop('checked')) {
							displayValue = $(this).next().text();
							displayLabel = itemLabels.replace(new RegExp(displayLabel,"g"),'');
							// check if this is the same label or not, if the label is the same, display empty strings to avoid duplication.
							// skip the same label to display
							if (lastLabelforCheckBox == displayLabel) {
								displayLabel = "";
							} else {
								lastLabelforCheckBox = displayLabel;
							}
						} else {
							return true;
						}
					}
					break;
				case 'select-one':
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.children().eq(0).text();
					displayValue = $('option:selected', this).text();
					break;
				case 'range':
					// 50
					displayLabel = fieldLabels.text();
					// Label50
					itemLabels = fieldLabels.offsetParent().text();
					// Label
					displayLabel = itemLabels.replace(new RegExp(displayLabel,"g"),'');
					displayValue = fieldValue;
					break;
				case 'hidden':
				case 'submit':
					return true;
					break;
				// The following types are processed as text field, it can be default case.
				// case 'text':
				// case 'date':
				// case 'textarea':
				// case 'url':
				// case 'tel':
				// case 'number':
				default:
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.text();
					displayValue = fieldValue;
					break;
				}

				// remove '*'
				if (displayLabel) {
					displayLabel = displayLabel.replace(/\*/g,'');
				}

				// if displayValue is not specified, we print value as 'not specified'.
				if (!displayValue) {
					displayValue = '未指定';

					// NULL fill: if null_fields is specified in meta tag, we fill-out it with NULL.
					if (fieldName && -1 != null_fields.search(new RegExp(fieldName))) {
						null_vals[fieldName] = 'NULL';
					}

				} else {
					// textarea might have new line.
					displayValue = displayValue.replace(/[\n\r]/g,'
');
				}

				$("#confirmationContents").append('
'+displayLabel+'	'+displayValue+'
');
			});
	    	confirmDialog.dialog("open");
	    	confirmDialog.dialog("moveToTop");
	    });
	});
});
<commit_msg>Revise comments<commit_after>/**
 * marketo_form_cdialog.js
 *
 * Mail bug reports and suggestion to : Yukio Y <unknot304 AT gmail.com>
 * MIT License, Copyright 2015 Yukio Y.
 *
 * Requires: jquery.min.js, jquery-ui.js
 */
$(function(){
	var confirmDialog;
	var dialogContents;
	var xform;

	// Option Handling for Null Fill Fields　(this only supports text type fields)
	var null_fields = $('meta[name="mktoForm2CDialog:NULL_Fill_Field_API_Names"]').attr("content");
	var null_vals = {};
	// Option handling for email confirmation fields
	var mail_confirm = $('meta[name="mktoForm2CDialog:Mail_Confirm"]').attr("content");

	dialogContents = '\

\

\

\

\

\

';

	MktoForms2.whenReady(function (form) {
		// Mail confirm field will be dded if name="mktoForm2CDialog:Mail_Confirm" meta tag has "true"
		if (mail_confirm == "true") {
			// The following section (line from 37 to 71), "Mail confirmation fields code" is written by Sandord Whiteman.
			// https://nation.marketo.com/message/91696#91696
			// http://jsfiddle.net/sanford/9bo4rq8v/
			// MIT License

		    //  tag all outer wrapper DIVs with their inner inputs' names to make them more findable
		    for ( var formEl = form.getFormElem()[0], formRows = formEl.querySelectorAll('.mktoFormRow'), i = 0, imax = formRows.length, wrappedField; i < imax; i++ ) {
		        if ( (wrappedField = formRows[i].querySelector('INPUT,SELECT,TEXTAREA')) && wrappedField.name) {
		            formRows[i].setAttribute('data-wrapper-for',wrappedField.name);
		        }
		    }

		    // clone the Email field wrapper
		    var emailWrapper = formEl.querySelector('.mktoFormRow[data-wrapper-for="Email"]');
		    var emailConfirmWrapper = emailWrapper.cloneNode(true);

		    // set some strings
		    var emailConfirmFieldName = 'emailConfirm';
		    var emailConfirmFieldSelector = '#'+emailConfirmFieldName;
		    var emailConfirmFieldLabel = 'メールアドレス確認';
		    var	emailConfirmValidationError = 'メールアドレスとその確認は一致する必要があります';

		    // change some attributes before injecting
		    emailConfirmWrapper.setAttribute('data-wrapper-for',emailConfirmFieldName);
		    emailConfirmWrapper.querySelector('INPUT').name = emailConfirmWrapper.querySelector('INPUT').id = emailConfirmFieldName;
		    emailConfirmWrapper.querySelector('.mktoFormCol').className = 'mktoFormCol'; // fixes bug when cloning mandatory field
		    emailConfirmWrapper.querySelector('LABEL').innerHTML = emailConfirmFieldLabel;

		    // add to form
		    formEl.insertBefore(emailConfirmWrapper,emailWrapper.nextSibling);

		    // compare Email and emailConfirm before submitting
		    form.onValidate(function(valid) {
		        if ( form.vals().Email == emailConfirmWrapper.querySelector(emailConfirmFieldSelector).value ) {
		            form.submittable(true);
		        } else {
		            form.submittable(false);
		            form.showErrorMessage(emailConfirmValidationError,
		            form.getFormElem().find(emailConfirmFieldSelector));
		        }
		    });
		}

		// Creating Confirmation Dialogs
	    // Callback for Submit
		xform = form;
	    xform.onSubmit(function(){

	    	// creates dialog without open
	    	$("body").append(dialogContents);
	    	confirmDialog = $("#mktoConfirmDialog").dialog({
	    		autoOpen: false,
	    		modal: true,
	    		closeOnEscape: false,
	    		width: "auto",
	    		hight: "auto",
	    		buttons: {
	    			"送信": function(){
	    				if (Object.keys(null_vals).length != 0) {
	    					xform.vals(null_vals); // if NULL filled fields are specified.
	    				}
	    				xform.submitable(true);
	    				xform.submit();
	    				$(this).dialog("close");
	    			},
	    			"戻る": function(){
	    				null_vals = {};
	    				$(this).dialog("close")
	    			}
	    		},
	    		open: function(){
	    			xform.submitable(false);
	    			$('.ui-dialog-titlebar-close').hide();
	    			$("#mktoConfirmDialog").append('
上記内容をご確認いただき、送信ください。
');
	    		},
	    		close: function(event){
	    			// remove table all contents
	    			// $("#confirmationContents").find("tr:gt(-1)").remove();
	    			$(this).dialog("destroy");
	    			$(event.target).remove();
	    			xform.submitable(true);
	    		}
	    	});

	    	// get form columns and displaying selected items.
			var lastLabelforCheckBox = ""; // This is used for radio/checkbox field to remove the same label (offsetLabel).
			var $inputs = xform.getFormElem().find(':input');
			$inputs.each(function() {
				var displayLabel;
				var itemLabels;
				var offsetLabel;
				var displayValue;
				var fieldName = this.name;
				var fieldType = this.type;
				var fieldLabels = $(this).parent();
				var fieldValue = $(this).val();

				// append Label and Value according to types
				switch(fieldType) {
				case 'email':
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.text();
					displayValue = fieldValue;
					break;
				case 'checkbox':
				case 'radio':
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.text();
					//contains concatinated item labels (i.e. ABCD)
					itemLabels = fieldLabels.offsetParent().text();

					// if the checkbox has only one item, we displayed YES or No.
					if ("" == displayLabel) {
						displayLabel = fieldLabels.parent().text();
						if ($(this).prop('checked')) {
							displayValue = 'はい';
						} else {
							displayValue = 'いいえ';
						}
					} else {
						// if the checkbox has multiple items, we displayed checked one only with item's label.
						if ($(this).prop('checked')) {
							displayValue = $(this).next().text();
							displayLabel = itemLabels.replace(new RegExp(displayLabel,"g"),'');
							// check if this is the same label or not, if the label is the same, display empty strings to avoid duplication.
							// skip the same label to display
							if (lastLabelforCheckBox == displayLabel) {
								displayLabel = "";
							} else {
								lastLabelforCheckBox = displayLabel;
							}
						} else {
							return true;
						}
					}
					break;
				case 'select-one':
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.children().eq(0).text();
					displayValue = $('option:selected', this).text();
					break;
				case 'range':
					// 50
					displayLabel = fieldLabels.text();
					// Label50
					itemLabels = fieldLabels.offsetParent().text();
					// Label
					displayLabel = itemLabels.replace(new RegExp(displayLabel,"g"),'');
					displayValue = fieldValue;
					break;
				case 'hidden':
				case 'submit':
					return true;
					break;
				// The following types are processed as text field, it can be default case.
				// case 'text':
				// case 'date':
				// case 'textarea':
				// case 'url':
				// case 'tel':
				// case 'number':
				default:
					// displayLabel = fieldLabels[0].textContent;
					displayLabel = fieldLabels.text();
					displayValue = fieldValue;
					break;
				}

				// remove '*'
				if (displayLabel) {
					displayLabel = displayLabel.replace(/\*/g,'');
				}

				// if displayValue is not specified, we print value as 'not specified'.
				if (!displayValue) {
					displayValue = '未指定';

					// NULL fill: if null_fields is specified in meta tag, we fill-out it with NULL.
					if (fieldName && -1 != null_fields.search(new RegExp(fieldName))) {
						null_vals[fieldName] = 'NULL';
					}

				} else {
					// textarea might have new line.
					displayValue = displayValue.replace(/[\n\r]/g,'
');
				}

				$("#confirmationContents").append('
'+displayLabel+'	'+displayValue+'
');
			});
	    	confirmDialog.dialog("open");
	    	confirmDialog.dialog("moveToTop");
	    });
	});
});
<|endoftext|>


<commit_before>var fs = require("fs"),
	slave = require("./slave-driver");
require("colors");

var module = process.argv[2] || "test";
var s = slave.run(module);

console.log("Running with NodeJS: " + process.version);
var out = "", err = "";

s.on("out", function(data) {
	out += data;
	console.log("[test.js:out]:\n".green + data);
});

s.on("err", function(err, data) {
	err += data;
	console.log("[test.js:err]:\n".red + err, data);
});

s.on("complete", function(code, sig) {
	fs.writeFile("./logs/" + module + ".out.log", out);
	fs.writeFile("./logs/" + module + ".err.log", err);
	console.log("test completed with code:", code, 'sig:', sig);
});
<commit_msg>slave: run-test.js uses new async slave-driver API<commit_after>var fs = require("fs"),
	slave = require("./slave-driver");
require("colors");

var module = process.argv[2] || "test";

slave.ready(function(run) {
	var s = run(module);

	console.log("Running with NodeJS: " + process.version);
	var out = "", err = "";

	s.on("out", function(data) {
		out += data;
		console.log("[test.js:out]:\n".green + data);
	});

	s.on("err", function(err, data) {
		err += data;
		console.log("[test.js:err]:\n".red + err, data);
	});

	s.on("complete", function(code, sig) {
		fs.writeFile("./logs/" + module + ".out.log", out);
		fs.writeFile("./logs/" + module + ".err.log", err);
		console.log("test completed with code:", code, 'sig:', sig);
	});
});
<|endoftext|>


<commit_before>window.lispz_modules={}<commit_msg>lispz release code<commit_after>window.lispz_modules={}function (){var _h_callbacks=[];//#core:72

var _h_pledge=(new Promise((function(ok,fail){_h_callbacks={'ok':ok,'fail':fail};})));//#core:73

var resolve_promise=(function(){_h_callbacks.ok.apply(null,[].slice.call(arguments,0))});//#core:74

var reject_promise=(function(err){_h_callbacks.fail(err)});//#core:75

lispz.globals.promise.all(names.map(load_riot)).then((function(){return resolve_promise(source)
//#dev:47
}))//#dev:48

return _h_pledge
//#core:78
}<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { propType } from 'graphql-anywhere';
import { graphql } from 'react-apollo';

import mapErrors from 'react/util/mapErrors';
import compactObject from 'react/util/compactObject';

import manageBlockFragment from 'react/components/ManageBlock/fragments/manageBlock';
import updateBlockMutation from 'react/components/ManageBlock/mutations/updateBlock';

import Box from 'react/components/UI/Box';
import ErrorAlert from 'react/components/UI/ErrorAlert';
import TitledDialog from 'react/components/UI/TitledDialog';
import { Input, Textarea, Label, LabelledInput } from 'react/components/UI/Inputs';

class ManageBlock extends PureComponent {
  static propTypes = {
    block: propType(manageBlockFragment).isRequired,
    updateBlock: PropTypes.func.isRequired,
    onDone: PropTypes.func.isRequired,
    autoFocus: PropTypes.oneOf(['title', 'description', 'body']),
  }

  static defaultProps = {
    autoFocus: 'title',
  }

  state = {
    mode: 'resting',
    title: null,
    description: null,
    content: null,
    errorMessage: null,
  }

  componentDidMount() {
    const { autoFocus } = this.props;

    setTimeout(() => {
      const element = {
        title: this.titleRef,
        description: this.descriptionRef,
        body: this.bodyRef,
      }[autoFocus];

      element.current.focus();
    }, 0);
  }

  titleRef = React.createRef()
  descriptionRef = React.createRef()
  bodyRef = React.createRef()

  handleErrors = (err) => {
    this.setState({
      mode: 'error',
      ...mapErrors(err),
    });
  }

  updateBlock = (e) => {
    e.preventDefault();

    const { block, updateBlock, onDone } = this.props;
    const { title, description, content } = this.state;

    const variables = compactObject({
      id: block.id,
      title,
      description,
      content,
    });

    this.setState({ mode: 'updating' });

    return updateBlock({ variables })
      .then(() => onDone())
      .catch(this.handleErrors);
  }

  handleInput = fieldName => ({ target: { value: fieldValue } }) => {
    this.setState({ [fieldName]: fieldValue });
  }

  handleTitle = this.handleInput('title')
  handleDescription = this.handleInput('description')
  handleContent = this.handleInput('content')

  render() {
    const { mode, errorMessage } = this.state;
    const { block } = this.props;

    return (
      <TitledDialog
        title="Update block"
        onDone={this.updateBlock}
        disabled={mode === 'updating'}
        label={{
          resting: 'Save',
          updating: 'Updating...',
          error: 'Error',
        }[mode]}
      >
        <Box>
          {mode === 'error' &&
            <ErrorAlert my={6} isReloadable={false}>
              {errorMessage}
            </ErrorAlert>
          }

          <LabelledInput>
            Title

            <Input
              placeholder="Title your block here"
              defaultValue={block.editable_title}
              onChange={this.handleTitle}
              ref={this.titleRef}
            />
          </LabelledInput>

          <LabelledInput>
            Info

            <Textarea
              placeholder="Describe your block here"
              defaultValue={block.editable_description}
              onChange={this.handleDescription}
              rows={block.__typename !== 'Text' ? 12 : 4}
              f={3}
              ref={this.descriptionRef}
            />
          </LabelledInput>

          {block.__typename === 'Text' &&
            <LabelledInput>
              Text

              <Textarea
                required
                placeholder="Required"
                defaultValue={block.editable_content}
                rows={12}
                onChange={this.handleContent}
                font="mono"
                f={3}
                lineHeight={2}
                ref={this.bodyRef}
              />
            </LabelledInput>
          }
        </Box>
      </TitledDialog>
    );
  }
}

export default graphql(updateBlockMutation, {
  name: 'updateBlock',
})(ManageBlock);
<commit_msg>Adds a callback to denote whether there are changes pending<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { propType } from 'graphql-anywhere';
import { graphql } from 'react-apollo';

import mapErrors from 'react/util/mapErrors';
import compactObject from 'react/util/compactObject';

import manageBlockFragment from 'react/components/ManageBlock/fragments/manageBlock';
import updateBlockMutation from 'react/components/ManageBlock/mutations/updateBlock';

import Box from 'react/components/UI/Box';
import ErrorAlert from 'react/components/UI/ErrorAlert';
import TitledDialog from 'react/components/UI/TitledDialog';
import { Input, Textarea, Label, LabelledInput } from 'react/components/UI/Inputs';

class ManageBlock extends PureComponent {
  static propTypes = {
    block: propType(manageBlockFragment).isRequired,
    updateBlock: PropTypes.func.isRequired,
    onDone: PropTypes.func.isRequired,
    onChangePending: PropTypes.func,
    autoFocus: PropTypes.oneOf(['title', 'description', 'body']),
  }

  static defaultProps = {
    onChangePending: () => {},
    autoFocus: 'title',
  }

  state = {
    mode: 'resting',
    title: null,
    description: null,
    content: null,
    errorMessage: null,
  }

  componentDidMount() {
    const { autoFocus } = this.props;

    setTimeout(() => {
      const element = {
        title: this.titleRef,
        description: this.descriptionRef,
        body: this.bodyRef,
      }[autoFocus];

      element.current.focus();
    }, 0);
  }

  titleRef = React.createRef()
  descriptionRef = React.createRef()
  bodyRef = React.createRef()

  handleErrors = (err) => {
    this.setState({
      mode: 'error',
      ...mapErrors(err),
    });
  }

  updateBlock = (e) => {
    e.preventDefault();

    const {
      block, updateBlock, onDone, onChangePending,
    } = this.props;
    const { title, description, content } = this.state;

    const variables = compactObject({
      id: block.id,
      title,
      description,
      content,
    });

    this.setState({ mode: 'updating' });

    return updateBlock({ variables })
      .then(() => {
        onChangePending(false);
        return onDone();
      })
      .catch(this.handleErrors);
  }

  handleInput = fieldName => ({ target: { value: fieldValue } }) => {
    const { onChangePending } = this.props;

    onChangePending(true);

    this.setState({ [fieldName]: fieldValue });
  }

  handleTitle = this.handleInput('title')
  handleDescription = this.handleInput('description')
  handleContent = this.handleInput('content')

  render() {
    const { mode, errorMessage } = this.state;
    const { block } = this.props;

    return (
      <TitledDialog
        title="Update block"
        onDone={this.updateBlock}
        disabled={mode === 'updating'}
        label={{
          resting: 'Save',
          updating: 'Updating...',
          error: 'Error',
        }[mode]}
      >
        <Box>
          {mode === 'error' &&
            <ErrorAlert my={6} isReloadable={false}>
              {errorMessage}
            </ErrorAlert>
          }

          <LabelledInput>
            Title

            <Input
              placeholder="Title your block here"
              defaultValue={block.editable_title}
              onChange={this.handleTitle}
              ref={this.titleRef}
            />
          </LabelledInput>

          <LabelledInput>
            Info

            <Textarea
              placeholder="Describe your block here"
              defaultValue={block.editable_description}
              onChange={this.handleDescription}
              rows={block.__typename !== 'Text' ? 12 : 4}
              f={3}
              ref={this.descriptionRef}
            />
          </LabelledInput>

          {block.__typename === 'Text' &&
            <LabelledInput>
              Text

              <Textarea
                required
                placeholder="Required"
                defaultValue={block.editable_content}
                rows={12}
                onChange={this.handleContent}
                font="mono"
                f={3}
                lineHeight={2}
                ref={this.bodyRef}
              />
            </LabelledInput>
          }
        </Box>
      </TitledDialog>
    );
  }
}

export default graphql(updateBlockMutation, {
  name: 'updateBlock',
})(ManageBlock);
<|endoftext|>


<commit_before>jq(document).ready(function(){

  $('pre').each(function(i, e) {hljs.highlightBlock(e)});

});<commit_msg>need to change jQ invocation from  to jq() for Plone compatability<commit_after>jq(document).ready(function(){

  jq('pre').each(function(i, e) {hljs.highlightBlock(e)});

});<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Marco Barisione <marco@barisione.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

const Main = imports.ui.main;
const St = imports.gi.St;

let label;

function MessageLabel() {
    this._init();
}

MessageLabel.prototype = {
    _init: function() {
        this.countLabel = new St.Label();

        this.actor = new St.Button({name: 'messageButton'});
        this.actor.set_child(this.countLabel);

        this._updateText();
    },

    _updateText: function() {
        this.countLabel.set_text('0');
    }
};

function init() {
    label = new MessageLabel();
}

function enable() {
    Main.panel._rightBox.insert_actor(label.actor, 0);
}

function disable() {
    Main.panel._rightBox.remove_actor(label);
}
<commit_msg>Hook into the shell to get notified when the message count changes<commit_after>/*
 * Copyright (C) 2011 Marco Barisione <marco@barisione.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

const Lang = imports.lang;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const St = imports.gi.St;

let label;

function MessageLabel() {
    this._init();
}

MessageLabel.prototype = {
    _init: function() {
        this.countLabel = new St.Label();

        this.actor = new St.Button({name: 'messageButton'});
        this.actor.set_child(this.countLabel);

        this.updateCount();
    },

    updateCount: function() {
        this.countLabel.set_text('0');
    }
};

function customSetCount(count, visible) {
    let fallbackSetCount = Lang.bind(this, originalSetCount);
    fallbackSetCount(count, visible);

    label.updateCount();
}

let originalSetCount;

function init() {
    originalSetCount = MessageTray.Source.prototype._setCount;

    label = new MessageLabel();
}

function enable() {
    MessageTray.Source.prototype._setCount = customSetCount;

    Main.panel._rightBox.insert_actor(label.actor, 0);
}

function disable() {
    MessageTray.Source.prototype._setCount = originalSetCount;

    Main.panel._rightBox.remove_actor(label);
}
<|endoftext|>


<commit_before>const path = require('path');
const vscode = require('vscode');

function stripWorkspaceFolder(currentFilename, workspaceFolder) {
    if (workspaceFolder && currentFilename.indexOf(workspaceFolder) === 0) {
        return currentFilename.slice(workspaceFolder.length);
    } else {
        return currentFilename;
    }
}

function stripExcessDirectoryLevels(currentFilename, separator, directoryLevelsToPreserve) {
    const filenameParts = currentFilename.split(separator);
    const startingIndex = filenameParts.length - 1 - directoryLevelsToPreserve;
    const boundedStartingIndex = Math.min(Math.max(startingIndex, 1), filenameParts.length - 1);
    return filenameParts.slice(boundedStartingIndex).join(separator);
}

function stripExtension(basename) {
    let extension;

    while (extension = path.extname(basename)) {
        basename = path.basename(basename, extension);
    }

    return basename;
}

function stripPatterns(currentFilename, separator, patterns) {
    if (patterns) {
        patterns.forEach((pattern) => {
            if (pattern === '{EXTENSION}') {
                const filenameParts = currentFilename.split(separator);
                filenameParts[filenameParts.length - 1] = stripExtension(filenameParts[filenameParts.length - 1]);
                currentFilename = filenameParts.join(separator);
            }
        });
    }

    return currentFilename;
}

function buildPrefix(currentFilename, workspaceFolder, separator, config) {
    currentFilename = stripWorkspaceFolder(currentFilename, workspaceFolder);
    currentFilename = stripExcessDirectoryLevels(currentFilename, separator, config.directoryLevelsToPreserve);
    currentFilename = stripPatterns(currentFilename, separator, config.patternsToStrip);

    return currentFilename;
}

function showRelatedFiles() {
    const { document } = vscode.window.activeTextEditor;

    const currentFilename = document.fileName;
    const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri).uri.path;
    const separator = path.sep;
    const config = vscode.workspace.getConfiguration('quickPickRelatedFiles');

    const prefix = buildPrefix(currentFilename, workspaceFolder, separator, config);
    vscode.commands.executeCommand('workbench.action.quickOpen', prefix);
}

function activate(context) {
    context.subscriptions.push(vscode.commands.registerCommand('quickPickRelatedFiles.show', showRelatedFiles));
}

module.exports.buildPrefix = buildPrefix;
module.exports.activate = activate;
<commit_msg>Refactor stripExtension<commit_after>const path = require('path');
const vscode = require('vscode');

function stripWorkspaceFolder(currentFilename, workspaceFolder) {
    if (workspaceFolder && currentFilename.indexOf(workspaceFolder) === 0) {
        return currentFilename.slice(workspaceFolder.length);
    } else {
        return currentFilename;
    }
}

function stripExcessDirectoryLevels(currentFilename, separator, directoryLevelsToPreserve) {
    const filenameParts = currentFilename.split(separator);
    const startingIndex = filenameParts.length - 1 - directoryLevelsToPreserve;
    const boundedStartingIndex = Math.min(Math.max(startingIndex, 1), filenameParts.length - 1);
    return filenameParts.slice(boundedStartingIndex).join(separator);
}

function stripExtension(currentFilename, separator) {
    const filenameParts = currentFilename.split(separator);

    let basename = filenameParts[filenameParts.length - 1];
    let extension;
    while (extension = path.extname(basename)) {
        basename = path.basename(basename, extension);
    }

    filenameParts[filenameParts.length - 1] = basename;
    return filenameParts.join(separator);
}

function stripPatterns(currentFilename, separator, patterns) {
    if (patterns) {
        patterns.forEach(function(pattern) {
            if (pattern === '{EXTENSION}') {
                currentFilename = stripExtension(currentFilename, separator);
            }
        });
    }

    return currentFilename;
}

function buildPrefix(currentFilename, workspaceFolder, separator, config) {
    currentFilename = stripWorkspaceFolder(currentFilename, workspaceFolder);
    currentFilename = stripExcessDirectoryLevels(currentFilename, separator, config.directoryLevelsToPreserve);
    currentFilename = stripPatterns(currentFilename, separator, config.patternsToStrip);

    return currentFilename;
}

function showRelatedFiles() {
    const { document } = vscode.window.activeTextEditor;

    const currentFilename = document.fileName;
    const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri).uri.path;
    const separator = path.sep;
    const config = vscode.workspace.getConfiguration('quickPickRelatedFiles');

    const prefix = buildPrefix(currentFilename, workspaceFolder, separator, config);
    vscode.commands.executeCommand('workbench.action.quickOpen', prefix);
}

function activate(context) {
    context.subscriptions.push(vscode.commands.registerCommand('quickPickRelatedFiles.show', showRelatedFiles));
}

module.exports.buildPrefix = buildPrefix;
module.exports.activate = activate;
<|endoftext|>


<commit_before>import Path from 'path-parser';
import { getSearch, getPath, omit, withoutBrackets, parse, toObject } from 'search-params';

const noop = () => {};

export default class RouteNode {
    constructor(name = '', path = '', childRoutes = [], cb) {
        this.name     = name;
        this.path     = path;
        this.parser   = path ? new Path(path) : null;
        this.children = [];

        this.add(childRoutes, cb);

        return this;
    }

    setPath(path = '') {
        this.path = path;
        this.parser = path ? new Path(path) : null;
    }

    add(route, cb = noop) {
        let originalRoute;
        if (route === undefined || route === null) return;

        if (route instanceof Array) {
            route.forEach(r => this.add(r, cb));
            return;
        }

        if (!(route instanceof RouteNode) && !(route instanceof Object)) {
            throw new Error('RouteNode.add() expects routes to be an Object or an instance of RouteNode.');
        }
        if (route instanceof Object) {
            if (!route.name || !route.path) {
                throw new Error('RouteNode.add() expects routes to have a name and a path defined.');
            }
            originalRoute = route;
            route = new RouteNode(route.name, route.path, route.children);
        }

        let names = route.name.split('.');

        if (names.length === 1) {
            // Check duplicated routes
            if (this.children.map(child => child.name).indexOf(route.name) !== -1) {
                throw new Error(`Alias "${route.name}" is already defined in route node`);
            }

            // Check duplicated paths
            if (this.children.map(child => child.path).indexOf(route.path) !== -1) {
                throw new Error(`Path "${route.path}" is already defined in route node`);
            }

            this.children.push(route);
            // Push greedy spats to the bottom of the pile
            this.children.sort((left, right) => {
                const leftPath = left.path.split('?')[0].replace(/(.+)\/$/, '$1');
                const rightPath = right.path.split('?')[0].replace(/(.+)\/$/, '$1');
                // '/' last
                if (leftPath === '/') return 1;
                if (rightPath === '/') return -1;
                // Spat params last
                if (left.parser.hasSpatParam) return 1;
                if (right.parser.hasSpatParam) return -1;
                // No spat, number of segments (less segments last)
                const leftSegments = (leftPath.match(/\//g) || []).length;
                const rightSegments = (rightPath.match(/\//g) || []).length;
                if (leftSegments < rightSegments) return 1;
                if (leftSegments > rightSegments) return -1;
                // Same number of segments, number of URL params ascending
                const leftParamsCount = left.parser.urlParams.length;
                const rightParamsCount = right.parser.urlParams.length;
                if (leftParamsCount < rightParamsCount) return -1;
                if (leftParamsCount > rightParamsCount) return 1;
                // Same number of segments and params, last segment length descending
                const leftParamLength = (leftPath.split('/').slice(-1)[0] || '').length;
                const rightParamLength = (rightPath.split('/').slice(-1)[0] || '').length;
                if (leftParamLength < rightParamLength) return 1;
                if (leftParamLength > rightParamLength) return -1;
                // Same last segment length, preserve definition order
                return 0;
            });
            console.log(this.children.map(c => c.path));
        } else {
            // Locate parent node
            let segments = this.getSegmentsByName(names.slice(0, -1).join('.'));
            if (segments) {
                segments[segments.length - 1].add(new RouteNode(names[names.length - 1], route.path, route.children));
            } else {
                throw new Error(`Could not add route named '${route.name}', parent is missing.`);
            }
        }

        if (originalRoute) cb(originalRoute);

        return this;
    }

    addNode(name, params) {
        this.add(new RouteNode(name, params));
        return this;
    }

    getSegmentsByName(routeName) {
        let findSegmentByName = (name, routes) => {
            let filteredRoutes = routes.filter(r => r.name === name);
            return filteredRoutes.length ? filteredRoutes[0] : undefined;
        };
        let segments = [];
        let routes = this.parser ? [ this ] : this.children;
        let names = ( this.parser ? [''] : [] ).concat(routeName.split('.'));

        let matched = names.every(name => {
            let segment = findSegmentByName(name, routes);
            if (segment) {
                routes = segment.children;
                segments.push(segment);
                return true;
            }
            return false;
        });

        return matched ? segments : null;
    }

    getSegmentsMatchingPath(path, options) {
        const { trailingSlash, strictQueryParams } = options;
        let matchChildren = (nodes, pathSegment, segments) => {
            // for (child of node.children) {
            for (let i in nodes) {
                let child = nodes[i];
                // Partially match path
                let match = child.parser.partialMatch(pathSegment);
                let remainingPath;

                if (!match && trailingSlash) {
                    // Try with optional trailing slash
                    match = child.parser.match(pathSegment, true);
                    remainingPath = '';
                } else if (match) {
                    // Remove consumed segment from path
                    const consumedPath = child.parser.build(match, {ignoreSearch: true});
                    remainingPath = pathSegment.replace(consumedPath, '');
                    const search = omit(
                        getSearch(pathSegment.replace(consumedPath, '')),
                        child.parser.queryParams.concat(child.parser.queryParamsBr)
                    );
                    remainingPath = getPath(remainingPath) + (search ? `?${search}` : '');

                    if (trailingSlash && remainingPath === '/' && !/\/$/.test(consumedPath)) {
                        remainingPath = '';
                    }
                }

                if (match) {
                    segments.push(child);
                    Object.keys(match).forEach(param => segments.params[param] = match[param]);

                    if (!remainingPath.length || // fully matched
                        !strictQueryParams && remainingPath.indexOf('?') === 0 // unmatched queryParams in non strict mode
                    ) {
                      return segments;
                    }
                    // If no children to match against but unmatched path left
                    if (!child.children.length) {
                        return null;
                    }
                    // Else: remaining path and children
                    return matchChildren(child.children, remainingPath, segments);
                }
            }
            return null;
        };

        let startingNodes = this.parser ? [this] : this.children;
        let segments = [];
        segments.params = {};

        const matched = matchChildren(startingNodes, path, segments);
        if (matched && matched.length === 1 && matched[0].name === '') return null;
        return matched;
    }

    getPathFromSegments(segments) {
        return segments ? segments.map(segment => segment.path).join('') : null;
    }

    getPath(routeName) {
        return this.getPathFromSegments(this.getSegmentsByName(routeName));
    }

    buildPathFromSegments(segments, params = {}) {
        if (!segments) return null;

        const searchParams = segments
            .filter(s => s.parser.hasQueryParams)
            .reduce(
                (params, s) => params
                    .concat(s.parser.queryParams)
                    .concat(s.parser.queryParamsBr.map(p => p + '[]')),
                []
            );

        const searchPart = !searchParams.length ? null : searchParams
            .filter(p => Object.keys(params).indexOf(withoutBrackets(p)) !== -1)
            .map(p => Path.serialise(p, params[withoutBrackets(p)]))
            .join('&');

        return segments
            .map(segment => segment.parser.build(params, {ignoreSearch: true}))
            .join('') + (searchPart ? '?' + searchPart : '');
    }

    getMetaFromSegments(segments) {
        let accName = '';

        return segments.reduce((meta, segment) => {
            const urlParams = segment.parser.urlParams.reduce((params, p) => {
                params[p] = 'url';
                return params;
            }, {});

            const allParams = segment.parser.queryParams.reduce((params, p) => {
                params[p] = 'query';
                return params;
            }, urlParams);

            if (segment.name !== undefined) {
                accName = accName ? accName + '.' + segment.name : segment.name;
                meta[accName] = allParams;
            }
            return meta;
        }, {});
    }

    buildPath(routeName, params = {}) {
        return this.buildPathFromSegments(this.getSegmentsByName(routeName), params);
    }

    buildStateFromSegments(segments) {
        if (!segments || !segments.length) return null;

        const name = segments
            .map(segment => segment.name)
            .filter(name => name)
            .join('.');
        const params = segments.params;

        return {
            name,
            params,
            _meta: this.getMetaFromSegments(segments)
        };
    }

    buildState(name, params = {}) {
        const segments = this.getSegmentsByName(name);
        if (!segments || !segments.length) return null;

        return {
            name,
            params,
            _meta: this.getMetaFromSegments(segments)
        };
    }

    matchPath(path, options) {
        const defaultOptions = { trailingSlash: false, strictQueryParams: true };
        options = { ...defaultOptions, ...options };
        return this.buildStateFromSegments(this.getSegmentsMatchingPath(path, options));
    }
}
<commit_msg>style: fix linting issue<commit_after>import Path from 'path-parser';
import { getSearch, getPath, omit, withoutBrackets } from 'search-params';

const noop = () => {};

export default class RouteNode {
    constructor(name = '', path = '', childRoutes = [], cb) {
        this.name     = name;
        this.path     = path;
        this.parser   = path ? new Path(path) : null;
        this.children = [];

        this.add(childRoutes, cb);

        return this;
    }

    setPath(path = '') {
        this.path = path;
        this.parser = path ? new Path(path) : null;
    }

    add(route, cb = noop) {
        let originalRoute;
        if (route === undefined || route === null) return;

        if (route instanceof Array) {
            route.forEach(r => this.add(r, cb));
            return;
        }

        if (!(route instanceof RouteNode) && !(route instanceof Object)) {
            throw new Error('RouteNode.add() expects routes to be an Object or an instance of RouteNode.');
        }
        if (route instanceof Object) {
            if (!route.name || !route.path) {
                throw new Error('RouteNode.add() expects routes to have a name and a path defined.');
            }
            originalRoute = route;
            route = new RouteNode(route.name, route.path, route.children);
        }

        let names = route.name.split('.');

        if (names.length === 1) {
            // Check duplicated routes
            if (this.children.map(child => child.name).indexOf(route.name) !== -1) {
                throw new Error(`Alias "${route.name}" is already defined in route node`);
            }

            // Check duplicated paths
            if (this.children.map(child => child.path).indexOf(route.path) !== -1) {
                throw new Error(`Path "${route.path}" is already defined in route node`);
            }

            this.children.push(route);
            // Push greedy spats to the bottom of the pile
            this.children.sort((left, right) => {
                const leftPath = left.path.split('?')[0].replace(/(.+)\/$/, '$1');
                const rightPath = right.path.split('?')[0].replace(/(.+)\/$/, '$1');
                // '/' last
                if (leftPath === '/') return 1;
                if (rightPath === '/') return -1;
                // Spat params last
                if (left.parser.hasSpatParam) return 1;
                if (right.parser.hasSpatParam) return -1;
                // No spat, number of segments (less segments last)
                const leftSegments = (leftPath.match(/\//g) || []).length;
                const rightSegments = (rightPath.match(/\//g) || []).length;
                if (leftSegments < rightSegments) return 1;
                if (leftSegments > rightSegments) return -1;
                // Same number of segments, number of URL params ascending
                const leftParamsCount = left.parser.urlParams.length;
                const rightParamsCount = right.parser.urlParams.length;
                if (leftParamsCount < rightParamsCount) return -1;
                if (leftParamsCount > rightParamsCount) return 1;
                // Same number of segments and params, last segment length descending
                const leftParamLength = (leftPath.split('/').slice(-1)[0] || '').length;
                const rightParamLength = (rightPath.split('/').slice(-1)[0] || '').length;
                if (leftParamLength < rightParamLength) return 1;
                if (leftParamLength > rightParamLength) return -1;
                // Same last segment length, preserve definition order
                return 0;
            });
            console.log(this.children.map(c => c.path));
        } else {
            // Locate parent node
            let segments = this.getSegmentsByName(names.slice(0, -1).join('.'));
            if (segments) {
                segments[segments.length - 1].add(new RouteNode(names[names.length - 1], route.path, route.children));
            } else {
                throw new Error(`Could not add route named '${route.name}', parent is missing.`);
            }
        }

        if (originalRoute) cb(originalRoute);

        return this;
    }

    addNode(name, params) {
        this.add(new RouteNode(name, params));
        return this;
    }

    getSegmentsByName(routeName) {
        let findSegmentByName = (name, routes) => {
            let filteredRoutes = routes.filter(r => r.name === name);
            return filteredRoutes.length ? filteredRoutes[0] : undefined;
        };
        let segments = [];
        let routes = this.parser ? [ this ] : this.children;
        let names = ( this.parser ? [''] : [] ).concat(routeName.split('.'));

        let matched = names.every(name => {
            let segment = findSegmentByName(name, routes);
            if (segment) {
                routes = segment.children;
                segments.push(segment);
                return true;
            }
            return false;
        });

        return matched ? segments : null;
    }

    getSegmentsMatchingPath(path, options) {
        const { trailingSlash, strictQueryParams } = options;
        let matchChildren = (nodes, pathSegment, segments) => {
            // for (child of node.children) {
            for (let i in nodes) {
                let child = nodes[i];
                // Partially match path
                let match = child.parser.partialMatch(pathSegment);
                let remainingPath;

                if (!match && trailingSlash) {
                    // Try with optional trailing slash
                    match = child.parser.match(pathSegment, true);
                    remainingPath = '';
                } else if (match) {
                    // Remove consumed segment from path
                    const consumedPath = child.parser.build(match, {ignoreSearch: true});
                    remainingPath = pathSegment.replace(consumedPath, '');
                    const search = omit(
                        getSearch(pathSegment.replace(consumedPath, '')),
                        child.parser.queryParams.concat(child.parser.queryParamsBr)
                    );
                    remainingPath = getPath(remainingPath) + (search ? `?${search}` : '');

                    if (trailingSlash && remainingPath === '/' && !/\/$/.test(consumedPath)) {
                        remainingPath = '';
                    }
                }

                if (match) {
                    segments.push(child);
                    Object.keys(match).forEach(param => segments.params[param] = match[param]);

                    if (!remainingPath.length || // fully matched
                        !strictQueryParams && remainingPath.indexOf('?') === 0 // unmatched queryParams in non strict mode
                    ) {
                      return segments;
                    }
                    // If no children to match against but unmatched path left
                    if (!child.children.length) {
                        return null;
                    }
                    // Else: remaining path and children
                    return matchChildren(child.children, remainingPath, segments);
                }
            }
            return null;
        };

        let startingNodes = this.parser ? [this] : this.children;
        let segments = [];
        segments.params = {};

        const matched = matchChildren(startingNodes, path, segments);
        if (matched && matched.length === 1 && matched[0].name === '') return null;
        return matched;
    }

    getPathFromSegments(segments) {
        return segments ? segments.map(segment => segment.path).join('') : null;
    }

    getPath(routeName) {
        return this.getPathFromSegments(this.getSegmentsByName(routeName));
    }

    buildPathFromSegments(segments, params = {}) {
        if (!segments) return null;

        const searchParams = segments
            .filter(s => s.parser.hasQueryParams)
            .reduce(
                (params, s) => params
                    .concat(s.parser.queryParams)
                    .concat(s.parser.queryParamsBr.map(p => p + '[]')),
                []
            );

        const searchPart = !searchParams.length ? null : searchParams
            .filter(p => Object.keys(params).indexOf(withoutBrackets(p)) !== -1)
            .map(p => Path.serialise(p, params[withoutBrackets(p)]))
            .join('&');

        return segments
            .map(segment => segment.parser.build(params, {ignoreSearch: true}))
            .join('') + (searchPart ? '?' + searchPart : '');
    }

    getMetaFromSegments(segments) {
        let accName = '';

        return segments.reduce((meta, segment) => {
            const urlParams = segment.parser.urlParams.reduce((params, p) => {
                params[p] = 'url';
                return params;
            }, {});

            const allParams = segment.parser.queryParams.reduce((params, p) => {
                params[p] = 'query';
                return params;
            }, urlParams);

            if (segment.name !== undefined) {
                accName = accName ? accName + '.' + segment.name : segment.name;
                meta[accName] = allParams;
            }
            return meta;
        }, {});
    }

    buildPath(routeName, params = {}) {
        return this.buildPathFromSegments(this.getSegmentsByName(routeName), params);
    }

    buildStateFromSegments(segments) {
        if (!segments || !segments.length) return null;

        const name = segments
            .map(segment => segment.name)
            .filter(name => name)
            .join('.');
        const params = segments.params;

        return {
            name,
            params,
            _meta: this.getMetaFromSegments(segments)
        };
    }

    buildState(name, params = {}) {
        const segments = this.getSegmentsByName(name);
        if (!segments || !segments.length) return null;

        return {
            name,
            params,
            _meta: this.getMetaFromSegments(segments)
        };
    }

    matchPath(path, options) {
        const defaultOptions = { trailingSlash: false, strictQueryParams: true };
        options = { ...defaultOptions, ...options };
        return this.buildStateFromSegments(this.getSegmentsMatchingPath(path, options));
    }
}
<|endoftext|>


<commit_before>/**
	_moon.Tooltip_ is a popup that works in conjunction with
	[moon.TooltipDecorator](#moon.TooltipDecorator). It automatically displays a
	tooltip when the user hovers over the decorator for a given period of time.
	The tooltip is positioned around the decorator where there is available window
	space.

		{kind: "moon.TooltipDecorator", components: [
			{kind: "moon.Button", content: "Tooltip"},
			{kind: "moon.Tooltip", content: "I'm a tooltip for a button."}
		]}

	You may force the tooltip to appear by calling its _show()_ method.
*/

enyo.kind({
	name: "moon.Tooltip",
	kind: "enyo.Popup",
	//* @protected
	classes: "moon-tooltip below left-arrow",
	//* @public
	published: {
		//* This property is added to override the default value of autoDismiss
		//* from enyo.Popup. If true,the tooltip will hide when the user taps outside it or
		//* presses ESC.  Set to false to prevent this behavior.
		//* This property works only when Tooltip used independently,
		//* not works when Tooltip used with the TooltipDecorator.
		autoDismiss: false,
		//* Hovering over the decorator for this length of time (in milliseconds)
		//* causes the tooltip to appear.
		showDelay: 500,
		//* Whether to position the tooltip above or below the activator.  Valid values are
		//* "above", "below", or "auto".
		position: "auto",
		//* Default _margin-left_ value
		defaultLeft: 10
	},
	//* @protected
	handlers: {
		onRequestShowTooltip: "requestShow",
		onRequestHideTooltip: "requestHide"
	},
	tools: [
		{name: "client", classes: "moon-tooltip-label moon-header-font"}
	],
	initComponents: function() {
		this.createChrome(this.tools);
		this.inherited(arguments);
	},
	create: function() {
		this.inherited(arguments);
		this.contentChanged();
	},
	contentChanged: function() {
		this.$.client.setContent(this.content);
	},
	requestShow: function() {
		this.startJob("showJob", "show", this.showDelay);
		return true;
	},
	cancelShow: function() {
		this.stopJob("showJob");
	},
	requestHide: function() {
		this.cancelShow();
		return this.inherited(arguments);
	},
	showingChanged: function() {
		this.cancelShow();
		this.inherited(arguments);
		this.adjustPosition(true);
	},
	applyPosition: function(inRect) {
		var s = "";
		for (var n in inRect) {
			s += (n + ":" + inRect[n] + (isNaN(inRect[n]) ? "; " : "px; "));
		}
		this.addStyles(s);
	},
	adjustPosition: function(belowActivator) {
		if (this.showing && this.hasNode()) {

			var b = this.node.getBoundingClientRect();
			var moonDefaultPadding = 20;

			//when the tooltip bottom goes below the window height move it above the decorator
			if ((b.top + b.height > window.innerHeight - moonDefaultPadding) || (this.position == "above")) {
				this.removeClass("below");
				this.addClass("above");
				this.applyStyle("top", -b.height + "px");
			}
			if ((b.top  < 0) || (this.position == "below")) {
				this.removeClass("above");
				this.addClass("below");
				this.applyStyle("top", "100%");
			}

			// FIXME: Leaving the following commented until verification from UX
			//when the tooltip top goes above the window height move it below the decorator
			/*
			if (b.top < 0) {
				this.addRemoveClass("below", true);
				this.addRemoveClass("above", false);
			} else {
				this.addRemoveClass("above", true);
				this.addRemoveClass("below", false);
			}
			*/

			//when the tooltip's right edge is out of the window, align its right edge with the decorator left edge (approx)
			if (b.left + b.width > window.innerWidth - moonDefaultPadding){
				//use the right-arrow
				this.applyPosition({'margin-left': -b.width});
				this.removeClass("left-arrow");
				this.addClass("right-arrow");
				this.$.client.addClass("right-arrow");
			}
		}
	},
	resizeHandler: function() {
		//reset the tooltip to align its left edge with the decorator
		this.applyPosition({"margin-left": this.defaultLeft, "bottom": "auto"});
		this.addRemoveClass("left-arrow", true);
		this.addRemoveClass("right-arrow", false);
		this.applyStyle("top", "100%");
		this.$.client.addRemoveClass("right-arrow", false);
		this.adjustPosition(true);
		this.inherited(arguments);
	}
});
<commit_msg>Edits for GF-53023<commit_after>/**
	_moon.Tooltip_ is a popup that works in conjunction with
	[moon.TooltipDecorator](#moon.TooltipDecorator). It automatically displays a
	tooltip when the user hovers over the decorator for a given period of time.
	The tooltip is positioned around the decorator where there is available window
	space.

		{kind: "moon.TooltipDecorator", components: [
			{kind: "moon.Button", content: "Tooltip"},
			{kind: "moon.Tooltip", content: "I'm a tooltip for a button."}
		]}

	You may force the tooltip to appear by calling its _show()_ method.
*/

enyo.kind({
	name: "moon.Tooltip",
	kind: "enyo.Popup",
	//* @protected
	classes: "moon-tooltip below left-arrow",
	//* @public
	published: {
		/**
			This value overrides the default value of _autoDismiss_ inherited from
			_enyo.Popup_. If true, the Tooltip will hide when the user taps outside of
			it or presses ESC.  Note that this property only affects behavior when the
			Tooltip is used independently--not when it is used with TooltipDecorator.
		*/
		autoDismiss: false,
		//* Hovering over the decorator for this length of time (in milliseconds)
		//* causes the tooltip to appear.
		showDelay: 500,
		//* Whether to position the tooltip above or below the activator.  Valid values are
		//* "above", "below", or "auto".
		position: "auto",
		//* Default _margin-left_ value
		defaultLeft: 10
	},
	//* @protected
	handlers: {
		onRequestShowTooltip: "requestShow",
		onRequestHideTooltip: "requestHide"
	},
	tools: [
		{name: "client", classes: "moon-tooltip-label moon-header-font"}
	],
	initComponents: function() {
		this.createChrome(this.tools);
		this.inherited(arguments);
	},
	create: function() {
		this.inherited(arguments);
		this.contentChanged();
	},
	contentChanged: function() {
		this.$.client.setContent(this.content);
	},
	requestShow: function() {
		this.startJob("showJob", "show", this.showDelay);
		return true;
	},
	cancelShow: function() {
		this.stopJob("showJob");
	},
	requestHide: function() {
		this.cancelShow();
		return this.inherited(arguments);
	},
	showingChanged: function() {
		this.cancelShow();
		this.inherited(arguments);
		this.adjustPosition(true);
	},
	applyPosition: function(inRect) {
		var s = "";
		for (var n in inRect) {
			s += (n + ":" + inRect[n] + (isNaN(inRect[n]) ? "; " : "px; "));
		}
		this.addStyles(s);
	},
	adjustPosition: function(belowActivator) {
		if (this.showing && this.hasNode()) {

			var b = this.node.getBoundingClientRect();
			var moonDefaultPadding = 20;

			//when the tooltip bottom goes below the window height move it above the decorator
			if ((b.top + b.height > window.innerHeight - moonDefaultPadding) || (this.position == "above")) {
				this.removeClass("below");
				this.addClass("above");
				this.applyStyle("top", -b.height + "px");
			}
			if ((b.top  < 0) || (this.position == "below")) {
				this.removeClass("above");
				this.addClass("below");
				this.applyStyle("top", "100%");
			}

			// FIXME: Leaving the following commented until verification from UX
			//when the tooltip top goes above the window height move it below the decorator
			/*
			if (b.top < 0) {
				this.addRemoveClass("below", true);
				this.addRemoveClass("above", false);
			} else {
				this.addRemoveClass("above", true);
				this.addRemoveClass("below", false);
			}
			*/

			//when the tooltip's right edge is out of the window, align its right edge with the decorator left edge (approx)
			if (b.left + b.width > window.innerWidth - moonDefaultPadding){
				//use the right-arrow
				this.applyPosition({'margin-left': -b.width});
				this.removeClass("left-arrow");
				this.addClass("right-arrow");
				this.$.client.addClass("right-arrow");
			}
		}
	},
	resizeHandler: function() {
		//reset the tooltip to align its left edge with the decorator
		this.applyPosition({"margin-left": this.defaultLeft, "bottom": "auto"});
		this.addRemoveClass("left-arrow", true);
		this.addRemoveClass("right-arrow", false);
		this.applyStyle("top", "100%");
		this.$.client.addRemoveClass("right-arrow", false);
		this.adjustPosition(true);
		this.inherited(arguments);
	}
});
<|endoftext|>


<commit_before>var BTCE = require('btce');
var btce = new BTCE();

module.exports.commands = {
  "btc": function(remainder, parts, reply, command, from, to, text, raw) {
    btce.ticker({pair: "btc_usd"}, function(err, data) {
      if(err || !data || !data.ticker) return reply("Error occured getting BTC prices");
      data = data.ticker;
      if(data[remainder.toLowerCase()]) {
        reply(remainder + ":", data[remainder.toLowerCase()]);
      } else {
        reply("Last:", data.last, "| Avg:", data.avg);
      }
    });
  },
  "ltc": function(remainder, parts, reply, command, from, to, text, raw) {
    btce.ticker({pair: "ltc_usd"}, function(err, data) {
      if(err || !data || !data.ticker) return reply("Error occured getting BTC prices");
      data = data.ticker;
      if(data[remainder.toLowerCase()]) {
        reply(remainder + ":", data[remainder.toLowerCase()]);
      } else {
        reply("Last:", data.last, "| Avg:", data.avg);
      }
    });
  },
};
<commit_msg>Cleanup btc/ltc command<commit_after>var BTCE = require('btce');
var btce = new BTCE();

function capitalize(str) {
  if(str === '') return '';
  return str[0].toUpperCase() + str.slice(1);
}

function getTickerData(coin, metric, callback) {
  btce.ticker({pair: coin+"_usd"}, function(err, data) {
    if(err || !data || !data.ticker) return callback("Error occured getting BTC prices");
    data = data.ticker;
    if(data[metric.toLowerCase()]) {
      callback(capitalize(metric) + ": $" + data[metric.toLowerCase()]);
    } else {
      callback("Last: $" + data.last + " | Avg: $" + data.avg);
    }
  });
}

module.exports.commands = ['btc', 'ltc'];
module.exports.run = function(remainder, parts, reply, command, from, to, text, raw) {
  getTickerData(command, remainder, reply);
};
<|endoftext|>


<commit_before>app.controller('HomeCtrl', function($scope, $rootScope, $compile, uiGridConstants, HomeFact, HttpFact, dataset, $route) {
  console.log('Home control instantiated')

  // Initialize grid and chart options
  $scope.grid = {
    columnDefs: [],
    data: [],
    enableHorizontalScrollbar: 2, // will be enabled when needed
    enableFiltering: true,

    onRegisterApi: function(gridApi){
      $scope.gridApi = gridApi;
    },
  }

  $scope.chartSource = {
    chart: {
      exportEnabled: 1
    },
    data: []
  }

  $scope.chartType; $scope.chartTypeShow // The graph to show when user clicks plot
  $scope.title

  if(dataset) {
    console.log('Here is the dataset: ', dataset)
    preloadData(dataset)
    $scope.title = dataset.name
  }
  else {
    $scope.title = 'Workspace'
    console.log('No dataset')
  }

  // Read file on file input event
  $('#file-input').change(importData)

  function preloadData(dataset) {
    console.log('preloading data')
    $scope.grid.data = dataset.data
    $scope.grid.columnDefs = HomeFact.generateColumnDefs(dataset.data[0])
  }

  // Read CSV file, convert to array of objects and attach to scope
  // Attach column names to columnDefs
  // If first var is blank, replace with var name "row"
  // Scope refresh and ui grid refresh
  function importData(evt) {
    console.log('upload')
    let file = evt.target.files[0]
    let reader = new FileReader()
    reader.readAsText(file)
    reader.onload = function(event) {
      let csvData = event.target.result
      if(csvData.slice(0, 3) === `"",`) {
        csvData = `"id",` + csvData.slice(3)
      }
      const parsedData = $.csv.toObjects(csvData)
      let convertedData = HomeFact.convertData(parsedData)
      convertedData = HomeFact.renameColumnsWithPeriods(convertedData)
      $scope.grid.data = convertedData
      $scope.grid.columnDefs = HomeFact.generateColumnDefs(convertedData[0])
      $scope.$apply()
    } // end onLoad
    reader.onerror = function() {
      console.log('error reading file')
    }
  }

  $scope.updateChart = function(chartType) {
    $scope.chartType = chartType
  }

  $scope.createPlot = function() {
    console.log('create plot')

    let chartType = $scope.chartType,
        xVar = $scope.xVar.field,
        yVar = $scope.yVar.field

    if (!chartType) return alert('Please select chart type')
    if (!xVar) return alert('Please select X (labels) variable')
    if (!yVar) return alert('Please select Y (values) variable')

    if(chartType === "scatter") return createScatterplot(chartType, xVar, yVar)
    else if(chartType === "boxandwhisker2d") return createBoxAndWhiskerPlot(chartType, xVar, yVar)
    else return createLabelValueChart(chartType, xVar, yVar)
  }

  function createLabelValueChart(chartType, xVar, yVar) {
    resetChart()
    $scope.gridApi.core.getVisibleRows().forEach(rowInfo => {
      row = rowInfo.entity
      let datum = {}
      datum.label = row[xVar]
      datum.value = row[yVar]
      $scope.chartSource.data.push(datum)
    })
    $scope.chartSource.chart.xAxisName = xVar
    $scope.chartSource.chart.yAxisName = yVar

    $scope.chartTypeShow = $scope.chartType
  }

  function createScatterplot(chartType, xVar, yVar) {
    resetChart()
    $scope.chartSource.dataset = [{showRegressionLine: 1, data: []}]
    $scope.chartSource.chart.xAxisName = xVar
    $scope.chartSource.chart.yAxisName = yVar
    $scope.gridApi.core.getVisibleRows().forEach(rowInfo => {
      row = rowInfo.entity
      let datum = {}
      datum.x = row[xVar]
      datum.y = row[yVar]
      $scope.chartSource.dataset[0].data.push(datum)
    })

    $scope.chartTypeShow = $scope.chartType
  }

  function createBoxAndWhiskerPlot(chartType, xVar, yVar) {
    resetChart()
    $scope.chartSource.categories = [{category: []}]
    $scope.chartSource.dataset = [{data: []}]
    let data = $scope.gridApi.core.getVisibleRows()
    let arrayOfUniqueXVars = []
    data.forEach(rowInfo => {
      let row = rowInfo.entity
      if(!arrayOfUniqueXVars.includes(row[xVar])) arrayOfUniqueXVars.push(row[xVar])
    })
    // Create category labels
    arrayOfUniqueXVars.forEach(uniqueVar => {
      $scope.chartSource.categories[0].category.push({
        label: uniqueVar
      })
    })
    // Create strings of values and push to "data" array
    arrayOfUniqueXVars.forEach((uniqueVar, i) => {
      values = ""
      data.forEach((rowInfo, j) => {
        let row = rowInfo.entity
        if(row[xVar] === uniqueVar) values += (String(row[yVar]) + ',')
      })
      $scope.chartSource.dataset[0].data.push({value: values.slice(0, -1)})
    })
    console.log($scope.chartSource)
    $scope.chartTypeShow = chartType
  }

  // reset chartSource data, dataset, and chart properties
  function resetChart() {
    $scope.chartSource = {
      chart: {
        exportEnabled: 1
      },
      data: []
    }
  }

  $scope.triggerSaveModal = function() {
    if($scope.grid.data.length === 0) return alert('No data to save')
    $('#add-dataset-modal').modal()
  }

  $scope.saveDataset = function() {
    $('#add-dataset-modal').modal('hide')

    const name = $('#save-dataset-name').val(); $('#save-dataset-name').val('')
    const description = $('#save-dataset-description').val(); $('#save-dataset-description').val('')

    let postBody = {
      name: name,
      description: description,
      user_id: 1,
      data: angular.toJson($scope.grid.data)
    }

    HttpFact.addDataset(postBody)
      .then(response => console.log(response.data.id))
      .catch(response => {
        if(response.status === 413) return alert('Sorry, that file is too big')
        else if(response.status !== 200) return alert('There was an error processing your request.  Please try again later')
        else return alert('Successfully saved')
      })
  }
})

<commit_msg>x and y variables on axes<commit_after>app.controller('HomeCtrl', function($scope, $rootScope, $compile, uiGridConstants, HomeFact, HttpFact, dataset, $route) {
  console.log('Home control instantiated')

  // Initialize grid and chart options
  $scope.grid = {
    columnDefs: [],
    data: [],
    enableHorizontalScrollbar: 2, // will be enabled when needed
    enableFiltering: true,

    onRegisterApi: function(gridApi){
      $scope.gridApi = gridApi;
    },
  }

  $scope.chartSource = {
    chart: {
      exportEnabled: 1
    },
    data: []
  }

  $scope.chartType; $scope.chartTypeShow // The graph to show when user clicks plot
  $scope.title

  if(dataset) {
    console.log('Here is the dataset: ', dataset)
    preloadData(dataset)
    $scope.title = dataset.name
  }
  else {
    $scope.title = 'Workspace'
    console.log('No dataset')
  }

  // Read file on file input event
  $('#file-input').change(importData)

  function preloadData(dataset) {
    console.log('preloading data')
    $scope.grid.data = dataset.data
    $scope.grid.columnDefs = HomeFact.generateColumnDefs(dataset.data[0])
  }

  // Read CSV file, convert to array of objects and attach to scope
  // Attach column names to columnDefs
  // If first var is blank, replace with var name "row"
  // Scope refresh and ui grid refresh
  function importData(evt) {
    console.log('upload')
    let file = evt.target.files[0]
    let reader = new FileReader()
    reader.readAsText(file)
    reader.onload = function(event) {
      let csvData = event.target.result
      if(csvData.slice(0, 3) === `"",`) {
        csvData = `"id",` + csvData.slice(3)
      }
      const parsedData = $.csv.toObjects(csvData)
      let convertedData = HomeFact.convertData(parsedData)
      convertedData = HomeFact.renameColumnsWithPeriods(convertedData)
      $scope.grid.data = convertedData
      $scope.grid.columnDefs = HomeFact.generateColumnDefs(convertedData[0])
      $scope.$apply()
    } // end onLoad
    reader.onerror = function() {
      console.log('error reading file')
    }
  }

  $scope.updateChart = function(chartType) {
    $scope.chartType = chartType
  }

  $scope.createPlot = function() {
    console.log('create plot')

    let chartType = $scope.chartType,
        xVar = $scope.xVar.field,
        yVar = $scope.yVar.field

    if (!chartType) return alert('Please select chart type')
    if (!xVar) return alert('Please select X (labels) variable')
    if (!yVar) return alert('Please select Y (values) variable')

    if(chartType === "scatter") return createScatterplot(chartType, xVar, yVar)
    else if(chartType === "boxandwhisker2d") return createBoxAndWhiskerPlot(chartType, xVar, yVar)
    else return createLabelValueChart(chartType, xVar, yVar)
  }

  function createLabelValueChart(chartType, xVar, yVar) {
    resetChart()
    $scope.gridApi.core.getVisibleRows().forEach(rowInfo => {
      row = rowInfo.entity
      let datum = {}
      datum.label = row[xVar]
      datum.value = row[yVar]
      $scope.chartSource.data.push(datum)
    })
    $scope.chartSource.chart.xAxisName = xVar
    $scope.chartSource.chart.yAxisName = yVar

    $scope.chartTypeShow = $scope.chartType
  }

  function createScatterplot(chartType, xVar, yVar) {
    resetChart()
    $scope.chartSource.dataset = [{showRegressionLine: 1, data: []}]
    $scope.chartSource.chart.xAxisName = xVar
    $scope.chartSource.chart.yAxisName = yVar
    $scope.gridApi.core.getVisibleRows().forEach(rowInfo => {
      row = rowInfo.entity
      let datum = {}
      datum.x = row[xVar]
      datum.y = row[yVar]
      $scope.chartSource.dataset[0].data.push(datum)
    })

    $scope.chartTypeShow = $scope.chartType
  }

  function createBoxAndWhiskerPlot(chartType, xVar, yVar) {
    resetChart()
    $scope.chartSource.categories = [{category: []}]
    $scope.chartSource.dataset = [{data: []}]
    $scope.chartSource.chart.xAxisName = String(xVar)
    $scope.chartSource.chart.yAxisName = String(yVar)
    let data = $scope.gridApi.core.getVisibleRows()
    let arrayOfUniqueXVars = []
    data.forEach(rowInfo => {
      let row = rowInfo.entity
      if(!arrayOfUniqueXVars.includes(row[xVar])) arrayOfUniqueXVars.push(row[xVar])
    })
    // Create category labels
    arrayOfUniqueXVars.forEach(uniqueVar => {
      $scope.chartSource.categories[0].category.push({
        label: String(uniqueVar)
      })
    })
    // Create strings of values and push to "data" array
    arrayOfUniqueXVars.forEach((uniqueVar, i) => {
      values = ""
      data.forEach((rowInfo, j) => {
        let row = rowInfo.entity
        if(isNaN(row[yVar])) return
        if(row[xVar] === uniqueVar) values += (String(row[yVar]) + ',')
      })
      $scope.chartSource.dataset[0].data.push({value: values.slice(0, -1)})
    })
    console.log($scope.chartSource)
    $scope.chartTypeShow = chartType
  }

  // reset chartSource data, dataset, and chart properties
  function resetChart() {
    $scope.chartSource = {
      chart: {
        exportEnabled: 1
      },
      data: []
    }
  }

  $scope.triggerSaveModal = function() {
    if($scope.grid.data.length === 0) return alert('No data to save')
    $('#add-dataset-modal').modal()
  }

  $scope.saveDataset = function() {
    $('#add-dataset-modal').modal('hide')

    const name = $('#save-dataset-name').val(); $('#save-dataset-name').val('')
    const description = $('#save-dataset-description').val(); $('#save-dataset-description').val('')

    let postBody = {
      name: name,
      description: description,
      user_id: 1,
      data: angular.toJson($scope.grid.data)
    }

    HttpFact.addDataset(postBody)
      .then(response => console.log(response.data.id))
      .catch(response => {
        if(response.status === 413) return alert('Sorry, that file is too big')
        else if(response.status !== 200) return alert('There was an error processing your request.  Please try again later')
        else return alert('Successfully saved')
      })
  }
})

<|endoftext|>


<commit_before>const EventEmitter = require('events').EventEmitter;
const _ = require('lodash');
const debug = require('debug')('scope:app-store');
const Immutable = require('immutable');

const AppDispatcher = require('../dispatcher/app-dispatcher');
const ActionTypes = require('../constants/action-types');
const Naming = require('../constants/naming');

const makeOrderedMap = Immutable.OrderedMap;
const makeSet = Immutable.Set;

// Helpers

function findCurrentTopology(subTree, topologyId) {
  let foundTopology;

  _.each(subTree, function(topology) {
    if (_.endsWith(topology.url, topologyId)) {
      foundTopology = topology;
    }
    if (!foundTopology) {
      foundTopology = findCurrentTopology(topology.sub_topologies, topologyId);
    }
    if (foundTopology) {
      return false;
    }
  });

  return foundTopology;
}

function makeNode(node) {
  return {
    id: node.id,
    label_major: node.label_major,
    label_minor: node.label_minor,
    rank: node.rank,
    pseudo: node.pseudo,
    adjacency: node.adjacency
  };
}

// Initial values

let topologyOptions = makeOrderedMap();
let adjacentNodes = makeSet();
let controlError = null;
let controlPending = false;
let currentTopology = null;
let currentTopologyId = 'containers';
let errorUrl = null;
let version = '';
let mouseOverEdgeId = null;
let mouseOverNodeId = null;
let nodes = makeOrderedMap();
let nodeDetails = null;
let selectedNodeId = null;
let topologies = [];
let topologiesLoaded = false;
let routeSet = false;
let websocketClosed = true;

function processTopologies(topologyList) {
  // adds ID field to topology, based on last part of URL path
  _.each(topologyList, function(topology) {
    topology.id = topology.url.split('/').pop();
    processTopologies(topology.sub_topologies);
  });
  return topologyList;
}

function setTopology(topologyId) {
  currentTopologyId = topologyId;
  currentTopology = findCurrentTopology(topologies, topologyId);
}

function setDefaultTopologyOptions(topologyList) {
  _.each(topologyList, function(topology) {
    let defaultOptions = makeOrderedMap();
    _.each(topology.options, function(items, option) {
      _.each(items, function(item) {
        if (item.default === true) {
          defaultOptions = defaultOptions.set(option, item.value);
        }
      });
    });

    if (defaultOptions.size) {
      topologyOptions = topologyOptions.set(
        topology.id,
        defaultOptions
      );
    }

    setDefaultTopologyOptions(topology.sub_topologies);
  });
}

function deSelectNode() {
  selectedNodeId = null;
  nodeDetails = null;
}

// Store API

const AppStore = Object.assign({}, EventEmitter.prototype, {

  CHANGE_EVENT: 'change',

  // keep at the top
  getAppState: function() {
    return {
      topologyId: currentTopologyId,
      selectedNodeId: this.getSelectedNodeId(),
      topologyOptions: topologyOptions.toJS() // all options
    };
  },

  getActiveTopologyOptions: function() {
    // options for current topology
    return topologyOptions.get(currentTopologyId);
  },

  getAdjacentNodes: function(nodeId) {
    adjacentNodes = adjacentNodes.clear();

    if (nodes.has(nodeId)) {
      adjacentNodes = makeSet(nodes.get(nodeId).get('adjacency'));
      // fill up set with reverse edges
      nodes.forEach(function(node, id) {
        if (node.get('adjacency') && node.get('adjacency').includes(nodeId)) {
          adjacentNodes = adjacentNodes.add(id);
        }
      });
    }

    return adjacentNodes;
  },

  getControlError: function() {
    return controlError;
  },

  getCurrentTopology: function() {
    if (!currentTopology) {
      currentTopology = setTopology(currentTopologyId);
    }
    return currentTopology;
  },

  getCurrentTopologyId: function() {
    return currentTopologyId;
  },

  getCurrentTopologyOptions: function() {
    return currentTopology && currentTopology.options;
  },

  getCurrentTopologyUrl: function() {
    return currentTopology && currentTopology.url;
  },

  getErrorUrl: function() {
    return errorUrl;
  },

  getHighlightedEdgeIds: function() {
    if (mouseOverNodeId && nodes.has(mouseOverNodeId)) {
      // all neighbour combinations because we dont know which direction exists
      const adjacency = nodes.get(mouseOverNodeId).get('adjacency');
      if (adjacency) {
        return _.flatten(
          adjacency.forEach(function(nodeId) {
            return [
              [nodeId, mouseOverNodeId].join(Naming.EDGE_ID_SEPARATOR),
              [mouseOverNodeId, nodeId].join(Naming.EDGE_ID_SEPARATOR)
            ];
          })
        );
      }
    }
    if (mouseOverEdgeId) {
      return mouseOverEdgeId;
    }
    return null;
  },

  getHighlightedNodeIds: function() {
    if (mouseOverNodeId) {
      const adjacency = this.getAdjacentNodes(mouseOverNodeId);
      if (adjacency.size) {
        return _.union(adjacency.toJS(), [mouseOverNodeId]);
      }
    }
    if (mouseOverEdgeId) {
      return mouseOverEdgeId.split(Naming.EDGE_ID_SEPARATOR);
    }
    return null;
  },

  getNodeDetails: function() {
    return nodeDetails;
  },

  getNodes: function() {
    return nodes;
  },

  getSelectedNodeId: function() {
    return selectedNodeId;
  },

  getTopologies: function() {
    return topologies;
  },

  getVersion: function() {
    return version;
  },

  isControlPending: function() {
    return controlPending;
  },

  isRouteSet: function() {
    return routeSet;
  },

  isTopologiesLoaded: function() {
    return topologiesLoaded;
  },

  isTopologyEmpty: function() {
    return currentTopology && currentTopology.stats && currentTopology.stats.node_count === 0 && nodes.size === 0;
  },

  isWebsocketClosed: function() {
    return websocketClosed;
  }

});

// Store Dispatch Hooks

AppStore.registeredCallback = function(payload) {
  switch (payload.type) {

  case ActionTypes.CHANGE_TOPOLOGY_OPTION:
    if (topologyOptions.getIn([payload.topologyId, payload.option])
      !== payload.value) {
      nodes = nodes.clear();
    }
    topologyOptions = topologyOptions.setIn(
      [payload.topologyId, payload.option],
      payload.value
    );
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLEAR_CONTROL_ERROR:
    controlError = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLICK_CLOSE_DETAILS:
    deSelectNode();
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLICK_NODE:
    if (payload.nodeId === selectedNodeId) {
      // clicking same node twice unsets the selection
      deSelectNode();
    } else {
      selectedNodeId = payload.nodeId;
    }
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLICK_TOPOLOGY:
    deSelectNode();
    if (payload.topologyId !== currentTopologyId) {
      setTopology(payload.topologyId);
      nodes = nodes.clear();
    }
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLOSE_WEBSOCKET:
    websocketClosed = true;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.DO_CONTROL:
    controlPending = true;
    controlError = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.ENTER_EDGE:
    mouseOverEdgeId = payload.edgeId;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.ENTER_NODE:
    mouseOverNodeId = payload.nodeId;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.HIT_ESC_KEY:
    deSelectNode();
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.LEAVE_EDGE:
    mouseOverEdgeId = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.LEAVE_NODE:
    mouseOverNodeId = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.OPEN_WEBSOCKET:
    // flush nodes cache after re-connect
    nodes = nodes.clear();
    websocketClosed = false;

    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.DO_CONTROL_ERROR:
    controlPending = false;
    controlError = payload.error;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.DO_CONTROL_SUCCESS:
    controlPending = false;
    controlError = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_ERROR:
    errorUrl = payload.errorUrl;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_NODE_DETAILS:
    errorUrl = null;
    nodeDetails = payload.details;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_NODES_DELTA:
    const emptyMessage = !payload.delta.add && !payload.delta.remove
      && payload.delta.update;

    if (!emptyMessage) {
      debug('RECEIVE_NODES_DELTA',
        'remove', _.size(payload.delta.remove),
        'update', _.size(payload.delta.update),
        'add', _.size(payload.delta.add));
    }

    errorUrl = null;

    // nodes that no longer exist
    _.each(payload.delta.remove, function(nodeId) {
      // in case node disappears before mouseleave event
      if (mouseOverNodeId === nodeId) {
        mouseOverNodeId = null;
      }
      if (nodes.has(nodeId) && _.contains(mouseOverEdgeId, nodeId)) {
        mouseOverEdgeId = null;
      }
      nodes = nodes.delete(nodeId);
    });

    // update existing nodes
    _.each(payload.delta.update, function(node) {
      nodes = nodes.set(node.id, nodes.get(node.id).merge(makeNode(node)));
    });

    // add new nodes
    _.each(payload.delta.add, function(node) {
      nodes = nodes.set(node.id, Immutable.fromJS(makeNode(node)));
    });

    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_TOPOLOGIES:
    errorUrl = null;
    topologies = processTopologies(payload.topologies);
    setTopology(currentTopologyId);
    // only set on first load, if options are not already set via route
    if (!topologiesLoaded && topologyOptions.size === 0) {
      setDefaultTopologyOptions(topologies);
    }
    topologiesLoaded = true;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_API_DETAILS:
    errorUrl = null;
    version = payload.version;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.ROUTE_TOPOLOGY:
    routeSet = true;
    if (currentTopologyId !== payload.state.topologyId) {
      nodes = nodes.clear();
    }
    setTopology(payload.state.topologyId);
    setDefaultTopologyOptions(topologies);
    selectedNodeId = payload.state.selectedNodeId;
    topologyOptions = Immutable.fromJS(payload.state.topologyOptions)
      || topologyOptions;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  default:
    break;

  }
};

AppStore.dispatchToken = AppDispatcher.register(AppStore.registeredCallback);

module.exports = AppStore;
<commit_msg>Click on node unsets loaded node details<commit_after>const EventEmitter = require('events').EventEmitter;
const _ = require('lodash');
const debug = require('debug')('scope:app-store');
const Immutable = require('immutable');

const AppDispatcher = require('../dispatcher/app-dispatcher');
const ActionTypes = require('../constants/action-types');
const Naming = require('../constants/naming');

const makeOrderedMap = Immutable.OrderedMap;
const makeSet = Immutable.Set;

// Helpers

function findCurrentTopology(subTree, topologyId) {
  let foundTopology;

  _.each(subTree, function(topology) {
    if (_.endsWith(topology.url, topologyId)) {
      foundTopology = topology;
    }
    if (!foundTopology) {
      foundTopology = findCurrentTopology(topology.sub_topologies, topologyId);
    }
    if (foundTopology) {
      return false;
    }
  });

  return foundTopology;
}

function makeNode(node) {
  return {
    id: node.id,
    label_major: node.label_major,
    label_minor: node.label_minor,
    rank: node.rank,
    pseudo: node.pseudo,
    adjacency: node.adjacency
  };
}

// Initial values

let topologyOptions = makeOrderedMap();
let adjacentNodes = makeSet();
let controlError = null;
let controlPending = false;
let currentTopology = null;
let currentTopologyId = 'containers';
let errorUrl = null;
let version = '';
let mouseOverEdgeId = null;
let mouseOverNodeId = null;
let nodes = makeOrderedMap();
let nodeDetails = null;
let selectedNodeId = null;
let topologies = [];
let topologiesLoaded = false;
let routeSet = false;
let websocketClosed = true;

function processTopologies(topologyList) {
  // adds ID field to topology, based on last part of URL path
  _.each(topologyList, function(topology) {
    topology.id = topology.url.split('/').pop();
    processTopologies(topology.sub_topologies);
  });
  return topologyList;
}

function setTopology(topologyId) {
  currentTopologyId = topologyId;
  currentTopology = findCurrentTopology(topologies, topologyId);
}

function setDefaultTopologyOptions(topologyList) {
  _.each(topologyList, function(topology) {
    let defaultOptions = makeOrderedMap();
    _.each(topology.options, function(items, option) {
      _.each(items, function(item) {
        if (item.default === true) {
          defaultOptions = defaultOptions.set(option, item.value);
        }
      });
    });

    if (defaultOptions.size) {
      topologyOptions = topologyOptions.set(
        topology.id,
        defaultOptions
      );
    }

    setDefaultTopologyOptions(topology.sub_topologies);
  });
}

function deSelectNode() {
  selectedNodeId = null;
  nodeDetails = null;
}

// Store API

const AppStore = Object.assign({}, EventEmitter.prototype, {

  CHANGE_EVENT: 'change',

  // keep at the top
  getAppState: function() {
    return {
      topologyId: currentTopologyId,
      selectedNodeId: this.getSelectedNodeId(),
      topologyOptions: topologyOptions.toJS() // all options
    };
  },

  getActiveTopologyOptions: function() {
    // options for current topology
    return topologyOptions.get(currentTopologyId);
  },

  getAdjacentNodes: function(nodeId) {
    adjacentNodes = adjacentNodes.clear();

    if (nodes.has(nodeId)) {
      adjacentNodes = makeSet(nodes.get(nodeId).get('adjacency'));
      // fill up set with reverse edges
      nodes.forEach(function(node, id) {
        if (node.get('adjacency') && node.get('adjacency').includes(nodeId)) {
          adjacentNodes = adjacentNodes.add(id);
        }
      });
    }

    return adjacentNodes;
  },

  getControlError: function() {
    return controlError;
  },

  getCurrentTopology: function() {
    if (!currentTopology) {
      currentTopology = setTopology(currentTopologyId);
    }
    return currentTopology;
  },

  getCurrentTopologyId: function() {
    return currentTopologyId;
  },

  getCurrentTopologyOptions: function() {
    return currentTopology && currentTopology.options;
  },

  getCurrentTopologyUrl: function() {
    return currentTopology && currentTopology.url;
  },

  getErrorUrl: function() {
    return errorUrl;
  },

  getHighlightedEdgeIds: function() {
    if (mouseOverNodeId && nodes.has(mouseOverNodeId)) {
      // all neighbour combinations because we dont know which direction exists
      const adjacency = nodes.get(mouseOverNodeId).get('adjacency');
      if (adjacency) {
        return _.flatten(
          adjacency.forEach(function(nodeId) {
            return [
              [nodeId, mouseOverNodeId].join(Naming.EDGE_ID_SEPARATOR),
              [mouseOverNodeId, nodeId].join(Naming.EDGE_ID_SEPARATOR)
            ];
          })
        );
      }
    }
    if (mouseOverEdgeId) {
      return mouseOverEdgeId;
    }
    return null;
  },

  getHighlightedNodeIds: function() {
    if (mouseOverNodeId) {
      const adjacency = this.getAdjacentNodes(mouseOverNodeId);
      if (adjacency.size) {
        return _.union(adjacency.toJS(), [mouseOverNodeId]);
      }
    }
    if (mouseOverEdgeId) {
      return mouseOverEdgeId.split(Naming.EDGE_ID_SEPARATOR);
    }
    return null;
  },

  getNodeDetails: function() {
    return nodeDetails;
  },

  getNodes: function() {
    return nodes;
  },

  getSelectedNodeId: function() {
    return selectedNodeId;
  },

  getTopologies: function() {
    return topologies;
  },

  getVersion: function() {
    return version;
  },

  isControlPending: function() {
    return controlPending;
  },

  isRouteSet: function() {
    return routeSet;
  },

  isTopologiesLoaded: function() {
    return topologiesLoaded;
  },

  isTopologyEmpty: function() {
    return currentTopology && currentTopology.stats && currentTopology.stats.node_count === 0 && nodes.size === 0;
  },

  isWebsocketClosed: function() {
    return websocketClosed;
  }

});

// Store Dispatch Hooks

AppStore.registeredCallback = function(payload) {
  switch (payload.type) {

  case ActionTypes.CHANGE_TOPOLOGY_OPTION:
    if (topologyOptions.getIn([payload.topologyId, payload.option])
      !== payload.value) {
      nodes = nodes.clear();
    }
    topologyOptions = topologyOptions.setIn(
      [payload.topologyId, payload.option],
      payload.value
    );
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLEAR_CONTROL_ERROR:
    controlError = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLICK_CLOSE_DETAILS:
    deSelectNode();
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLICK_NODE:
    deSelectNode();
    if (payload.nodeId !== selectedNodeId) {
      // select new node if it's not the same (in that case just delesect)
      selectedNodeId = payload.nodeId;
    }
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLICK_TOPOLOGY:
    deSelectNode();
    if (payload.topologyId !== currentTopologyId) {
      setTopology(payload.topologyId);
      nodes = nodes.clear();
    }
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.CLOSE_WEBSOCKET:
    websocketClosed = true;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.DO_CONTROL:
    controlPending = true;
    controlError = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.ENTER_EDGE:
    mouseOverEdgeId = payload.edgeId;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.ENTER_NODE:
    mouseOverNodeId = payload.nodeId;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.HIT_ESC_KEY:
    deSelectNode();
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.LEAVE_EDGE:
    mouseOverEdgeId = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.LEAVE_NODE:
    mouseOverNodeId = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.OPEN_WEBSOCKET:
    // flush nodes cache after re-connect
    nodes = nodes.clear();
    websocketClosed = false;

    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.DO_CONTROL_ERROR:
    controlPending = false;
    controlError = payload.error;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.DO_CONTROL_SUCCESS:
    controlPending = false;
    controlError = null;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_ERROR:
    errorUrl = payload.errorUrl;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_NODE_DETAILS:
    errorUrl = null;
    nodeDetails = payload.details;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_NODES_DELTA:
    const emptyMessage = !payload.delta.add && !payload.delta.remove
      && payload.delta.update;

    if (!emptyMessage) {
      debug('RECEIVE_NODES_DELTA',
        'remove', _.size(payload.delta.remove),
        'update', _.size(payload.delta.update),
        'add', _.size(payload.delta.add));
    }

    errorUrl = null;

    // nodes that no longer exist
    _.each(payload.delta.remove, function(nodeId) {
      // in case node disappears before mouseleave event
      if (mouseOverNodeId === nodeId) {
        mouseOverNodeId = null;
      }
      if (nodes.has(nodeId) && _.contains(mouseOverEdgeId, nodeId)) {
        mouseOverEdgeId = null;
      }
      nodes = nodes.delete(nodeId);
    });

    // update existing nodes
    _.each(payload.delta.update, function(node) {
      nodes = nodes.set(node.id, nodes.get(node.id).merge(makeNode(node)));
    });

    // add new nodes
    _.each(payload.delta.add, function(node) {
      nodes = nodes.set(node.id, Immutable.fromJS(makeNode(node)));
    });

    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_TOPOLOGIES:
    errorUrl = null;
    topologies = processTopologies(payload.topologies);
    setTopology(currentTopologyId);
    // only set on first load, if options are not already set via route
    if (!topologiesLoaded && topologyOptions.size === 0) {
      setDefaultTopologyOptions(topologies);
    }
    topologiesLoaded = true;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.RECEIVE_API_DETAILS:
    errorUrl = null;
    version = payload.version;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  case ActionTypes.ROUTE_TOPOLOGY:
    routeSet = true;
    if (currentTopologyId !== payload.state.topologyId) {
      nodes = nodes.clear();
    }
    setTopology(payload.state.topologyId);
    setDefaultTopologyOptions(topologies);
    selectedNodeId = payload.state.selectedNodeId;
    topologyOptions = Immutable.fromJS(payload.state.topologyOptions)
      || topologyOptions;
    AppStore.emit(AppStore.CHANGE_EVENT);
    break;

  default:
    break;

  }
};

AppStore.dispatchToken = AppDispatcher.register(AppStore.registeredCallback);

module.exports = AppStore;
<|endoftext|>