<commit_before>'use strict';
/**
 * This code is mostly from the old Etherpad. Please help us to comment this code.
 * This helps other people to understand this code better and helps them to improve it.
 * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
 */

/**
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// requires: top
// requires: undefined

const KERNEL_SOURCE = '../static/js/require-kernel.js';

const hooks = require('./pluginfw/hooks');
const pluginUtils = require('./pluginfw/shared');

const scriptTag =
    (source) => `<script type="text/javascript">\n${source.replace(/<\//g, '<\\/')}</script>`;

const Ace2Editor = function () {
  const ace2 = Ace2Editor;

  let info = {
    editor: this,
    id: (ace2.registry.nextId++),
  };
  let loaded = false;

  let actionsPendingInit = [];

  const pendingInit = (func) => function (...args) {
    const action = () => func.apply(this, args);
    if (loaded) return action();
    actionsPendingInit.push(action);
  };

  const doActionsPendingInit = () => {
    for (const fn of actionsPendingInit) fn();
    actionsPendingInit = [];
  };

  ace2.registry[info.id] = info;

  // The following functions (prefixed by 'ace_')  are exposed by editor, but
  // execution is delayed until init is complete
  const aceFunctionsPendingInit = [
    'importText',
    'importAText',
    'focus',
    'setEditable',
    'getFormattedCode',
    'setOnKeyPress',
    'setOnKeyDown',
    'setNotifyDirty',
    'setProperty',
    'setBaseText',
    'setBaseAttributedText',
    'applyChangesToBase',
    'applyPreparedChangesetToBase',
    'setUserChangeNotificationCallback',
    'setAuthorInfo',
    'setAuthorSelectionRange',
    'callWithAce',
    'execCommand',
    'replaceRange',
  ];

  for (const fnName of aceFunctionsPendingInit) {
    // Note: info[`ace_${fnName}`] does not exist yet, so it can't be passed directly to
    // pendingInit(). A simple wrapper is used to defer the info[`ace_${fnName}`] lookup until
    // method invocation.
    this[fnName] = pendingInit(function (...args) {
      info[`ace_${fnName}`].apply(this, args);
    });
  }

  this.exportText = () => loaded ? info.ace_exportText() : '(awaiting init)\n';

  this.getFrame = () => info.frame || null;

  this.getDebugProperty = (prop) => info.ace_getDebugProperty(prop);

  this.getInInternationalComposition =
      () => loaded ? info.ace_getInInternationalComposition() : false;

  // prepareUserChangeset:
  // Returns null if no new changes or ACE not ready.  Otherwise, bundles up all user changes
  // to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
  // If this method returns a truthy value, then applyPreparedChangesetToBase can be called at some
  // later point to consider these changes part of the base, after which prepareUserChangeset must
  // be called again before applyPreparedChangesetToBase. Multiple consecutive calls to
  // prepareUserChangeset will return an updated changeset that takes into account the latest user
  // changes, and modify the changeset to be applied by applyPreparedChangesetToBase accordingly.
  this.prepareUserChangeset = () => loaded ? info.ace_prepareUserChangeset() : null;

  // returns array of {error: <browser Error object>, time: +new Date()}
  this.getUnhandledErrors = () => loaded ? info.ace_getUnhandledErrors() : [];

  const sortFilesByEmbeded = (files) => {
    const embededFiles = [];
    let remoteFiles = [];

    if (Ace2Editor.EMBEDED) {
      for (let i = 0, ii = files.length; i < ii; i++) {
        const file = files[i];
        if (Object.prototype.hasOwnProperty.call(Ace2Editor.EMBEDED, file)) {
          embededFiles.push(file);
        } else {
          remoteFiles.push(file);
        }
      }
    } else {
      remoteFiles = files;
    }

    return {embeded: embededFiles, remote: remoteFiles};
  };

  const pushStyleTagsFor = (buffer, files) => {
    const sorted = sortFilesByEmbeded(files);
    const embededFiles = sorted.embeded;
    const remoteFiles = sorted.remote;

    if (embededFiles.length > 0) {
      buffer.push('');
    }
    for (const file of remoteFiles) {
      buffer.push(`<link rel="stylesheet" type="text/css" href="${encodeURI(file)}"/>`);
    }
  };

  this.destroy = pendingInit(() => {
    info.ace_dispose();
    info.frame.parentNode.removeChild(info.frame);
    delete ace2.registry[info.id];
    info = null; // prevent IE 6 closure memory leaks
  });

  this.init = function (containerId, initialCode, doneFunc) {
    this.importText(initialCode);

    info.onEditorReady = () => {
      loaded = true;
      doActionsPendingInit();
      doneFunc();
    };

    (() => {
      const doctype = '<!doctype html>';

      const iframeHTML = [];

      iframeHTML.push(doctype);
      iframeHTML.push(`<html class='inner-editor ${clientVars.skinVariants}'><head>`);

      // calls to these functions ($$INCLUDE_...)  are replaced when this file is processed
      // and compressed, putting the compressed code from the named file directly into the
      // source here.
      // these lines must conform to a specific format because they are passed by the build script:
      let includedCSS = [];
      let $$INCLUDE_CSS = (filename) => { includedCSS.push(filename); };
      $$INCLUDE_CSS('../static/css/iframe_editor.css');

      // disableCustomScriptsAndStyles can be used to disable loading of custom scripts
      if (!clientVars.disableCustomScriptsAndStyles) {
        $$INCLUDE_CSS(`../static/css/pad.css?v=${clientVars.randomVersionString}`);
      }

      let additionalCSS = hooks.callAll('aceEditorCSS').map((path) => {
        if (path.match(/\/\//)) { // Allow urls to external CSS - http(s):// and //some/path.css
          return path;
        }
        return `../static/plugins/${path}`;
      });
      includedCSS = includedCSS.concat(additionalCSS);
      $$INCLUDE_CSS(
          `../static/skins/${clientVars.skinName}/pad.css?v=${clientVars.randomVersionString}`);

      pushStyleTagsFor(iframeHTML, includedCSS);

      if (!Ace2Editor.EMBEDED && Ace2Editor.EMBEDED[KERNEL_SOURCE]) {
        // Remotely src'd script tag will not work in IE; it must be embedded, so
        // throw an error if it is not.
        throw new Error('Require kernel could not be found.');
      }

      iframeHTML.push(scriptTag(
          `${Ace2Editor.EMBEDED[KERNEL_SOURCE]}\n\
require.setRootURI("../javascripts/src");\n\
require.setLibraryURI("../javascripts/lib");\n\
require.setGlobalKeyPath("require");\n\
\n\
var plugins = require("ep_etherpad-lite/static/js/pluginfw/client_plugins");\n\
plugins.adoptPluginsFromAncestorsOf(window);\n\
\n\
$ = jQuery = require("ep_etherpad-lite/static/js/rjquery").jQuery; // Expose jQuery #HACK\n\
var Ace2Inner = require("ep_etherpad-lite/static/js/ace2_inner");\n\
\n\
plugins.ensure(function () {\n\
  Ace2Inner.init();\n\
});\n\
`));

      iframeHTML.push('');

      hooks.callAll('aceInitInnerdocbodyHead', {
        iframeHTML,
      });

      iframeHTML.push(' ');

      // eslint-disable-next-line node/no-unsupported-features/es-builtins
      const gt = typeof globalThis === 'object' ? globalThis : window;
      gt.ChildAccessibleAce2Editor = Ace2Editor;

      const outerScript = `\
editorId = ${JSON.stringify(info.id)};\n\
editorInfo = parent.ChildAccessibleAce2Editor.registry[editorId];\n\
window.onload = function () {\n\
  window.onload = null;\n\
  setTimeout(function () {\n\
    var iframe = document.createElement("IFRAME");\n\
    iframe.name = "ace_inner";\n\
    iframe.title = "pad";\n\
    iframe.scrolling = "no";\n\
    var outerdocbody = document.getElementById("outerdocbody");\n\
    iframe.frameBorder = 0;\n\
    iframe.allowTransparency = true; // for IE\n\
    outerdocbody.insertBefore(iframe, outerdocbody.firstChild);\n\
    iframe.ace_outerWin = window;\n\
    readyFunc = function () {\n\
      editorInfo.onEditorReady();\n\
      readyFunc = null;\n\
      editorInfo = null;\n\
    };\n\
    var doc = iframe.contentWindow.document;\n\
    doc.open();\n\
    var text = (${JSON.stringify(iframeHTML.join('\n'))});\n\
    doc.write(text);\n\
    doc.close();\n\
  }, 0);\n\
}`;

      const outerHTML =
          [doctype, `<html class="inner-editor outerdoc ${clientVars.skinVariants}"><head>`];

      includedCSS = [];
      $$INCLUDE_CSS = (filename) => { includedCSS.push(filename); };
      $$INCLUDE_CSS('../static/css/iframe_editor.css');
      $$INCLUDE_CSS(`../static/css/pad.css?v=${clientVars.randomVersionString}`);

      additionalCSS = hooks.callAll('aceEditorCSS').map((path) => {
        if (path.match(/\/\//)) { // Allow urls to external CSS - http(s):// and //some/path.css
          return path;
        }
        return `../static/plugins/${path}`;
      });
      includedCSS = includedCSS.concat(additionalCSS);
      $$INCLUDE_CSS(
          `../static/skins/${clientVars.skinName}/pad.css?v=${clientVars.randomVersionString}`);

      pushStyleTagsFor(outerHTML, includedCSS);

      // bizarrely, in FF2, a file with no "external" dependencies won't finish loading properly
      // (throbs busy while typing)
      const pluginNames = pluginUtils.clientPluginNames();
      outerHTML.push(
          '',
          '<link rel="stylesheet" type="text/css" href="data:text/css,"/>',
          scriptTag(outerScript),
          '',
          '',
          '

',
          '
x
',
          '');

      const outerFrame = document.createElement('IFRAME');
      outerFrame.name = 'ace_outer';
      outerFrame.frameBorder = 0; // for IE
      outerFrame.title = 'Ether';
      info.frame = outerFrame;
      document.getElementById(containerId).appendChild(outerFrame);

      const editorDocument = outerFrame.contentWindow.document;

      editorDocument.open();
      editorDocument.write(outerHTML.join(''));
      editorDocument.close();
    })();
  };
};

Ace2Editor.registry = {
  nextId: 1,
};

exports.Ace2Editor = Ace2Editor;
<commit_msg>ace: Fix EMBEDDED check<commit_after>'use strict';
/**
 * This code is mostly from the old Etherpad. Please help us to comment this code.
 * This helps other people to understand this code better and helps them to improve it.
 * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
 */

/**
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// requires: top
// requires: undefined

const KERNEL_SOURCE = '../static/js/require-kernel.js';

const hooks = require('./pluginfw/hooks');
const pluginUtils = require('./pluginfw/shared');

const scriptTag =
    (source) => `<script type="text/javascript">\n${source.replace(/<\//g, '<\\/')}</script>`;

const Ace2Editor = function () {
  const ace2 = Ace2Editor;

  let info = {
    editor: this,
    id: (ace2.registry.nextId++),
  };
  let loaded = false;

  let actionsPendingInit = [];

  const pendingInit = (func) => function (...args) {
    const action = () => func.apply(this, args);
    if (loaded) return action();
    actionsPendingInit.push(action);
  };

  const doActionsPendingInit = () => {
    for (const fn of actionsPendingInit) fn();
    actionsPendingInit = [];
  };

  ace2.registry[info.id] = info;

  // The following functions (prefixed by 'ace_')  are exposed by editor, but
  // execution is delayed until init is complete
  const aceFunctionsPendingInit = [
    'importText',
    'importAText',
    'focus',
    'setEditable',
    'getFormattedCode',
    'setOnKeyPress',
    'setOnKeyDown',
    'setNotifyDirty',
    'setProperty',
    'setBaseText',
    'setBaseAttributedText',
    'applyChangesToBase',
    'applyPreparedChangesetToBase',
    'setUserChangeNotificationCallback',
    'setAuthorInfo',
    'setAuthorSelectionRange',
    'callWithAce',
    'execCommand',
    'replaceRange',
  ];

  for (const fnName of aceFunctionsPendingInit) {
    // Note: info[`ace_${fnName}`] does not exist yet, so it can't be passed directly to
    // pendingInit(). A simple wrapper is used to defer the info[`ace_${fnName}`] lookup until
    // method invocation.
    this[fnName] = pendingInit(function (...args) {
      info[`ace_${fnName}`].apply(this, args);
    });
  }

  this.exportText = () => loaded ? info.ace_exportText() : '(awaiting init)\n';

  this.getFrame = () => info.frame || null;

  this.getDebugProperty = (prop) => info.ace_getDebugProperty(prop);

  this.getInInternationalComposition =
      () => loaded ? info.ace_getInInternationalComposition() : false;

  // prepareUserChangeset:
  // Returns null if no new changes or ACE not ready.  Otherwise, bundles up all user changes
  // to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
  // If this method returns a truthy value, then applyPreparedChangesetToBase can be called at some
  // later point to consider these changes part of the base, after which prepareUserChangeset must
  // be called again before applyPreparedChangesetToBase. Multiple consecutive calls to
  // prepareUserChangeset will return an updated changeset that takes into account the latest user
  // changes, and modify the changeset to be applied by applyPreparedChangesetToBase accordingly.
  this.prepareUserChangeset = () => loaded ? info.ace_prepareUserChangeset() : null;

  // returns array of {error: <browser Error object>, time: +new Date()}
  this.getUnhandledErrors = () => loaded ? info.ace_getUnhandledErrors() : [];

  const sortFilesByEmbeded = (files) => {
    const embededFiles = [];
    let remoteFiles = [];

    if (Ace2Editor.EMBEDED) {
      for (let i = 0, ii = files.length; i < ii; i++) {
        const file = files[i];
        if (Object.prototype.hasOwnProperty.call(Ace2Editor.EMBEDED, file)) {
          embededFiles.push(file);
        } else {
          remoteFiles.push(file);
        }
      }
    } else {
      remoteFiles = files;
    }

    return {embeded: embededFiles, remote: remoteFiles};
  };

  const pushStyleTagsFor = (buffer, files) => {
    const sorted = sortFilesByEmbeded(files);
    const embededFiles = sorted.embeded;
    const remoteFiles = sorted.remote;

    if (embededFiles.length > 0) {
      buffer.push('');
    }
    for (const file of remoteFiles) {
      buffer.push(`<link rel="stylesheet" type="text/css" href="${encodeURI(file)}"/>`);
    }
  };

  this.destroy = pendingInit(() => {
    info.ace_dispose();
    info.frame.parentNode.removeChild(info.frame);
    delete ace2.registry[info.id];
    info = null; // prevent IE 6 closure memory leaks
  });

  this.init = function (containerId, initialCode, doneFunc) {
    this.importText(initialCode);

    info.onEditorReady = () => {
      loaded = true;
      doActionsPendingInit();
      doneFunc();
    };

    (() => {
      const doctype = '<!doctype html>';

      const iframeHTML = [];

      iframeHTML.push(doctype);
      iframeHTML.push(`<html class='inner-editor ${clientVars.skinVariants}'><head>`);

      // calls to these functions ($$INCLUDE_...)  are replaced when this file is processed
      // and compressed, putting the compressed code from the named file directly into the
      // source here.
      // these lines must conform to a specific format because they are passed by the build script:
      let includedCSS = [];
      let $$INCLUDE_CSS = (filename) => { includedCSS.push(filename); };
      $$INCLUDE_CSS('../static/css/iframe_editor.css');

      // disableCustomScriptsAndStyles can be used to disable loading of custom scripts
      if (!clientVars.disableCustomScriptsAndStyles) {
        $$INCLUDE_CSS(`../static/css/pad.css?v=${clientVars.randomVersionString}`);
      }

      let additionalCSS = hooks.callAll('aceEditorCSS').map((path) => {
        if (path.match(/\/\//)) { // Allow urls to external CSS - http(s):// and //some/path.css
          return path;
        }
        return `../static/plugins/${path}`;
      });
      includedCSS = includedCSS.concat(additionalCSS);
      $$INCLUDE_CSS(
          `../static/skins/${clientVars.skinName}/pad.css?v=${clientVars.randomVersionString}`);

      pushStyleTagsFor(iframeHTML, includedCSS);

      if (!Ace2Editor.EMBEDED || !Ace2Editor.EMBEDED[KERNEL_SOURCE]) {
        // Remotely src'd script tag will not work in IE; it must be embedded, so
        // throw an error if it is not.
        throw new Error('Require kernel could not be found.');
      }

      iframeHTML.push(scriptTag(
          `${Ace2Editor.EMBEDED[KERNEL_SOURCE]}\n\
require.setRootURI("../javascripts/src");\n\
require.setLibraryURI("../javascripts/lib");\n\
require.setGlobalKeyPath("require");\n\
\n\
var plugins = require("ep_etherpad-lite/static/js/pluginfw/client_plugins");\n\
plugins.adoptPluginsFromAncestorsOf(window);\n\
\n\
$ = jQuery = require("ep_etherpad-lite/static/js/rjquery").jQuery; // Expose jQuery #HACK\n\
var Ace2Inner = require("ep_etherpad-lite/static/js/ace2_inner");\n\
\n\
plugins.ensure(function () {\n\
  Ace2Inner.init();\n\
});\n\
`));

      iframeHTML.push('');

      hooks.callAll('aceInitInnerdocbodyHead', {
        iframeHTML,
      });

      iframeHTML.push(' ');

      // eslint-disable-next-line node/no-unsupported-features/es-builtins
      const gt = typeof globalThis === 'object' ? globalThis : window;
      gt.ChildAccessibleAce2Editor = Ace2Editor;

      const outerScript = `\
editorId = ${JSON.stringify(info.id)};\n\
editorInfo = parent.ChildAccessibleAce2Editor.registry[editorId];\n\
window.onload = function () {\n\
  window.onload = null;\n\
  setTimeout(function () {\n\
    var iframe = document.createElement("IFRAME");\n\
    iframe.name = "ace_inner";\n\
    iframe.title = "pad";\n\
    iframe.scrolling = "no";\n\
    var outerdocbody = document.getElementById("outerdocbody");\n\
    iframe.frameBorder = 0;\n\
    iframe.allowTransparency = true; // for IE\n\
    outerdocbody.insertBefore(iframe, outerdocbody.firstChild);\n\
    iframe.ace_outerWin = window;\n\
    readyFunc = function () {\n\
      editorInfo.onEditorReady();\n\
      readyFunc = null;\n\
      editorInfo = null;\n\
    };\n\
    var doc = iframe.contentWindow.document;\n\
    doc.open();\n\
    var text = (${JSON.stringify(iframeHTML.join('\n'))});\n\
    doc.write(text);\n\
    doc.close();\n\
  }, 0);\n\
}`;

      const outerHTML =
          [doctype, `<html class="inner-editor outerdoc ${clientVars.skinVariants}"><head>`];

      includedCSS = [];
      $$INCLUDE_CSS = (filename) => { includedCSS.push(filename); };
      $$INCLUDE_CSS('../static/css/iframe_editor.css');
      $$INCLUDE_CSS(`../static/css/pad.css?v=${clientVars.randomVersionString}`);

      additionalCSS = hooks.callAll('aceEditorCSS').map((path) => {
        if (path.match(/\/\//)) { // Allow urls to external CSS - http(s):// and //some/path.css
          return path;
        }
        return `../static/plugins/${path}`;
      });
      includedCSS = includedCSS.concat(additionalCSS);
      $$INCLUDE_CSS(
          `../static/skins/${clientVars.skinName}/pad.css?v=${clientVars.randomVersionString}`);

      pushStyleTagsFor(outerHTML, includedCSS);

      // bizarrely, in FF2, a file with no "external" dependencies won't finish loading properly
      // (throbs busy while typing)
      const pluginNames = pluginUtils.clientPluginNames();
      outerHTML.push(
          '',
          '<link rel="stylesheet" type="text/css" href="data:text/css,"/>',
          scriptTag(outerScript),
          '',
          '',
          '

',
          '
x
',
          '');

      const outerFrame = document.createElement('IFRAME');
      outerFrame.name = 'ace_outer';
      outerFrame.frameBorder = 0; // for IE
      outerFrame.title = 'Ether';
      info.frame = outerFrame;
      document.getElementById(containerId).appendChild(outerFrame);

      const editorDocument = outerFrame.contentWindow.document;

      editorDocument.open();
      editorDocument.write(outerHTML.join(''));
      editorDocument.close();
    })();
  };
};

Ace2Editor.registry = {
  nextId: 1,
};

exports.Ace2Editor = Ace2Editor;
<|endoftext|>


<commit_before>/**
 * Created by Mike on 1/29/2016.
 */

//A pattern document contains sections
//There are different kinds of sections.
//  Text
//  Materials
//  Guage
//  Instructions
//  Pattern

/**
 *
 * @type {PatternDocument}
 */
var pdoc = new PatternDocument();

/**
 *
 * @constructor
 */
function PatternDocument() {
  /**
   *
   * @type {string}
   * @private
   */
  var _id = "PatternDocument";
  Object.defineProperty(this,"id",{
    get: function() { return _id }
  });

  var _sections = [];
  Object.defineProperty(this, "sections", {
    get: function() {
      return _sections
    }
  });

  this.addTextSection = function () {
    var newSection = new TextSection();
    newSection.headerText = "A new text section (" + this.sections.length + ")";
    newSection.text = "some text goes here.";
    newSection.index = _sections.push(newSection) - 1;
    //$("#PatternDocument").append(newSection.html);
    newSection.render();
  };

  this.addPatternSection = function () {
    var newSection = new PatternSection();
    newSection.headerText = "A new pattern section (" + this.sections.length + ")";
    newSection.text = "some instructions go here.";
    newSection.index = _sections.push(newSection) - 1;
    newSection.render();
  };

  this.render = function() {
    var markup = markupGenerator();
    $("body").append(markup);
    $("#btnCreateSection").on("click", btnCreateSection_click);
  };

  function btnCreateSection_click() {
    var $sectionSelector = $("#selSectionType")[0];
    var input = $sectionSelector.options[$sectionSelector.selectedIndex].value;
    //alert(input);
    if(input === "Text Section") {
      pdoc.addTextSection();
    }else if (input === "Pattern Section") {
      pdoc.addPatternSection();
    }
    else {
      alert("Invalid Section Type.");
    }

    return false;
  }

  this.render();
}

/** TextSection
 *
 * @constructor
 */
function TextSection() {
  var thisSection = this;

  Object.defineProperty(this, "id", {
    get: function(){
      return "TextSection_" + this.index;
    }
  });

  var _document = pdoc;
  Object.defineProperty(this,"patternDocument", {
    get: function() {
      return _document;
    },
    set: function(val) {
      if(val instanceof PatternDocument) {
        _document = val;
      }
      else {
        throw new InvalidArgumentException("PatternSection.patternDocument","(object)PatternDocument","value",val);
      }
    }
  });

  var _index = null;
  Object.defineProperty(this,"index", {
    get: function() { return _index },
    set: function(val) { _index = val; }
  });

  var _headerText = "Section Header";
  Object.defineProperty(this, "headerText", {
    get:  function () {
            return _headerText;
          },
    set:  function (val) {
            if((val !== null) && (val !== undefined)) {
              _headerText = val;
            }
          }
  });

  var _text = "Additional Text";
  Object.defineProperty(this, "text", {
    get: function() {
      return _text;
    },
    set: function(val) {
      _text = val;
    }
  });

  var _html = null;
  Object.defineProperty(this, "html", {
    get: function() {
      if(_html === null) {
        _html = '
' +
        '
 ' +
        '       ' + this.headerText + '' +
        '       <button id="copy"></button><button id="min"></button><button id="close"></button>' +
        '
' +
        '
' + this.text + '
' +
        '
';
      }
      return _html
    }
    ,set: function(val) {
      if(checkHTML(val)) {
        _html = _val;
      }
      else {
        throw new InvalidArgumentException("TextSection.html (set)","(string)HTML","value", val);
      }
    }
  });

  this.render = function() {
    //$("#" + thisSection.patternDocument.id).append(thisSection.html);
    var markup = markupGenerator(thisSection);
    $("#PatternDocument").append(markup);
    $("#" + thisSection.id).accordion({animate:200, collapsible:true, heightStyle:"content"});
  }
}

/**
 *
 * @constructor
 */
function PatternSection () {
  var thisSection = this;

  Object.defineProperty(this, "id",{
    get: function() {
      return "Pattern_" + this.index;
    }
  });

  var _counterBoxFactory = new CounterBoxFactory();
  _counterBoxFactory.container = thisSection;
  Object.defineProperty(this, "buttonFactory", {
    get: function() { return _counterBoxFactory }
  });

  function btnBoxCount_Click(event){
    var $inputQuantity = $("#" + event.target.parentElement.id + " > #inputBoxCount")[0];
    var quantity = parseInt($inputQuantity.value);
    thisSection.buttonFactory.createButtons(quantity,event);
    return false;
  }

  this.render = function() {
    var markup = markupGenerator(thisSection);
    $("#PatternDocument").append(markup);
    $("#" + thisSection.id).accordion({animate:200, collapsible:true, heightStyle:"content"});
    $("#" + thisSection.id + " #btnBoxCount").on("click", btnBoxCount_Click);
  };
}
PatternSection.prototype = new TextSection();

/**
 *
 * @constructor
 */
function CounterBoxFactory() {
  var thisFactory = this;

  Object.defineProperty(this,"id",{
    get: function() {
      return this.container.id + "_factory";
    }
  });

  var _container = null;
  Object.defineProperty(this, "container", {
    get: function(){
      return _container;
    },
    set: function(val) {
      if(val instanceof TextSection){
        _container = val;
      }
      else {
        throw new InvalidArgumentException("CounterBoxFactory.container","(object) instanceOf a section","value", val);
      }
    }
  });

  var _buttons = [];
  Object.defineProperty(this,"buttons",{
    get: function() {
      return _buttons;
    }
  });

  var _pb = null;
  Object.defineProperty(this,"progressBar", {
    get: function() {
      return _pb;
    },
    set: function(val) {
      _pb = val;
    }
  });

  this.createButtons = function (quantity,event) {
    console.log(this);
    //empty the collection of buttons.
    _buttons = [];
    var parentElementId = event.target.parentElement.id;
    var $buttonContainer = $("#" + parentElementId + " #counterBoxes");
    $buttonContainer.empty();
    var $pbContainer  = $("#" + parentElementId + " #pb");
    $pbContainer.empty();
    _pb = new ProgressBar.Line("#" + parentElementId + " #pb",{color:'#f00', strokeWidth: 1});

    //create a new collection of buttons === boxcount param.
    for(var i = 1; i<=quantity; i++){
      _buttons[i] = new CounterBox(i);
      _buttons[i].index = i;
      _buttons[i].factory = thisFactory;
    }

    //add each button to the document.
    _buttons.forEach(function(counterbox) {
      $buttonContainer.append(counterbox.html);
      var selector = "#" + event.target.parentElement.id + " > #counterBoxes > #" + counterbox.id;
      $(selector).on("click", counterbox, counterbox.click);
    });
  }
}

/**
 *
 * @param labelText
 * @param forecolor
 * @param backcolor
 * @constructor
 */
function CounterBox(labelText,forecolor,backcolor) {
  var thisCounterBox = this;

  Object.defineProperty(this,"id", {
       get: function() {
       return "box_" + thisCounterBox.index;
    }
  });

  var _labelText = labelText;
  Object.defineProperty(this, "labelText", {
    get: function () {
      return _labelText;
    },
    set: function (val) {
      _labelText = val;
    }
  });

  var _fcolor = forecolor || "black";
  Object.defineProperty(this, "foreColor", {
    get: function () {
      return _fcolor
    },
    /**
     * A named color
     * @param val
     */
    set: function (val) {
      if (Colors.isColorValid(val)) {
        _fcolor = val;
      }
      else {
        throw new InvalidArgumentException("CounterBox.foreColor", "(string)a Named Color", "val", val);
      }
    }
  });

  var _bcolor = backcolor || "white";
  Object.defineProperty(this, "backColor", {
    get: function () {
      return _bcolor;
    },
    /**
     * A named color
     * @param val
     */
    set: function (val) {
      if (Colors.isColorValid(val)) {
        _bcolor = val;
      }
      else {
        throw new InvalidArgumentException("CounterBox.backColor", "(string)a Named Color", "val", val);
      }
    }
  });

  Object.defineProperty(this, "html", {
    get: function () {
      var _labelDivStyle = "style='position:relative; width:100%; height:100%; text-align: center'";
      var _imageDivStyle = "style='position:relative; top:-30px; left:0; z-index:1; display:none;'";
      var _imageStyle = "style='height:25px; width:30px; margin: auto;'";
      var _boxStyle = "style='float:left; color:" + thisCounterBox.foreColor + "; background-color: " + thisCounterBox.backColor + "; height: 25px; width: 30px; margin-top:2px; margin-left:2px; border: solid black 1px; padding-top:5px;'";
      var _imageMarkup = "";
      var _labeldiv = "
" + _labelText + "
";
      var _imagediv = "
" + _imageMarkup + "
";
      var _counterBoxMarkup = "
" + _labeldiv + _imagediv + "
";
      return _counterBoxMarkup;
    }
  });

  Object.defineProperty(this, "index", {
    get: function() {
      return thisCounterBox.factory.buttons.indexOf(this)
    }
  });

  this.factory = null;

  this.getLabelId = function() {
    return thisCounterBox.id + "_label" + thisCounterBox.labelText
  };

  this.getImageId = function() {
    return thisCounterBox.id + "_image"
  };

  //this.getImageDivId = function() {
  //  return thisCounterBox.id + "_imageDiv"
  //};

  this.click = function (event) {
    //todo: if later I want to update the objects, make sure to do it in counterbox.click.
    var currentSectionId = $(this).parent().parent().parent()[0].id;
    var sectionIndex = currentSectionId.split("_")[1];
    var $thisButton = $("#" + currentSectionId + " #" + $(this)[0].id);
    var $imageDiv = $("#" + currentSectionId + " #" + $(this)[0].id + " #imageDiv");
    var css = $imageDiv.css("display");
    //var action = null;
    if (css === "none") {
      $imageDiv.css({display: "block"});
      //action = "clicked"
    }
    else {
      $imageDiv.css({display: "none"});
      //action = "unclicked";
    }

    var clickedIndex = parseInt($thisButton[0].id.split("_")[1]);
    var sibIndex = null, $sibImageDiv = null, sibCss = null;
    var $siblingButtons = $thisButton.parent().children().not("[id='" + $thisButton[0].id + "']");
    $siblingButtons.each(function(index,element){
      sibIndex = parseInt(element.id.split("_")[1]);
      $sibImageDiv = $(element).children().last();
      sibCss = $sibImageDiv.css("display");
      if(clickedIndex > sibIndex) {
        $sibImageDiv.css("display","block");
      }
      else if(sibIndex > clickedIndex) {
        $sibImageDiv.css("display","none");
      }
    });

    var section = pdoc.sections[sectionIndex];
    section.buttonFactory.progressBar.animate((event.data.index -1) / thisCounterBox.factory.buttons.length);

    return false;
  }
}

/**
 *
 * @constructor
 */
function markupGenerator(section) {
  var markup;

  var outerHTML = '
' +
    '
Pattern Title
' +
    '   <select id="selSectionType">' +
    '     <option>Text Section</option>' +
    '     <option>Pattern Section</option>'+
    '   </select>' +
    ' <button id="btnCreateSection">Create New Section</button>' +
    '
';

  if(section === undefined) {
    markup = outerHTML;
    return markup;
  }

  var textHTML = '
' +
    '
 ' +
    '   ' + section.headerText + '' +
    '   <button id="copy"></button><button id="min"></button><button id="close"></button>' +
    '
' +
    '
' +
    '
' + section.text + '
';

  var patternHTML = ' <input id="inputBoxCount" type="number" min="0" step="1">' +
    ' <button id="btnBoxCount" type="button">Create</button>' +
    '

' +
    '

';

  var closingTag ="

";

  if(section instanceof PatternSection) {
    markup = textHTML + patternHTML + closingTag;
  }
  else if (section instanceof TextSection) {
    markup = textHTML + closingTag;
  }
  else {
    markup = outerHTML;
  }

  return markup;

}

//function GuageSection() {
//
//}
//GuageSection.prototype = new TextSection();
//
//function TextSection() {
//  var _bodytext = "";
//  Object.defineProperty(this, "bodyText", {
//    get:  function() {
//      return _bodytext;
//    },
//    set:  function(val) {
//      if((val !== null) && (val !== undefined)) {
//        _bodytext = val;
//      }
//    }
//  })
//}
//TextSection.prototype = new TextSection();
//
//function MaterialsSection() {
//
//}
//MaterialsSection.prototype = new TextSection();
//
//function InstructionSection () {
//
//}
//InstructionSection.prototype = new TextSection();

<commit_msg>Added a small notebox under each counterbox. Also changed counterbox numbering to reflect total row count instead of just per section numbering.<commit_after>/**
 * Created by Mike on 1/29/2016.
 */

//A pattern document contains sections
//There are different kinds of sections.
//  Text
//  Materials
//  Guage
//  Instructions
//  Pattern

/**
 *
 * @type {PatternDocument}
 */
var pdoc = new PatternDocument();

/**
 *
 * @constructor
 */
function PatternDocument() {
  /**
   *
   * @type {string}
   * @private
   */
  var _id = "PatternDocument";
  Object.defineProperty(this,"id",{
    get: function() { return _id }
  });

  var _sections = [];
  Object.defineProperty(this, "sections", {
    get: function() {
      return _sections
    }
  });

  var _buttons = [];
  Object.defineProperty(this, "buttons", {
    get: function() {
      return _buttons;
    }
  });

  this.addTextSection = function () {
    var newSection = new TextSection();
    newSection.headerText = "A new text section (" + this.sections.length + ")";
    newSection.text = "some text goes here.";
    newSection.index = _sections.push(newSection) - 1;
    //$("#PatternDocument").append(newSection.html);
    newSection.render();
  };

  this.addPatternSection = function () {
    var newSection = new PatternSection();
    newSection.headerText = "A new pattern section (" + this.sections.length + ")";
    newSection.text = "some instructions go here.";
    newSection.index = _sections.push(newSection) - 1;
    newSection.render();
  };

  this.render = function() {
    var markup = markupGenerator();
    $("body").append(markup);
    $("#btnCreateSection").on("click", btnCreateSection_click);
  };

  function btnCreateSection_click() {
    var $sectionSelector = $("#selSectionType")[0];
    var input = $sectionSelector.options[$sectionSelector.selectedIndex].value;
    //alert(input);
    if(input === "Text Section") {
      pdoc.addTextSection();
    }else if (input === "Pattern Section") {
      pdoc.addPatternSection();
    }
    else {
      alert("Invalid Section Type.");
    }

    return false;
  }

  this.render();
}

/** TextSection
 *
 * @constructor
 */
function TextSection() {
  var thisSection = this;

  Object.defineProperty(this, "id", {
    get: function(){
      return "TextSection_" + this.index;
    }
  });

  var _document = pdoc;
  Object.defineProperty(this,"patternDocument", {
    get: function() {
      return _document;
    },
    set: function(val) {
      if(val instanceof PatternDocument) {
        _document = val;
      }
      else {
        throw new InvalidArgumentException("PatternSection.patternDocument","(object)PatternDocument","value",val);
      }
    }
  });

  var _index = null;
  Object.defineProperty(this,"index", {
    get: function() { return _index },
    set: function(val) { _index = val; }
  });

  var _headerText = "Section Header";
  Object.defineProperty(this, "headerText", {
    get:  function () {
            return _headerText;
          },
    set:  function (val) {
            if((val !== null) && (val !== undefined)) {
              _headerText = val;
            }
          }
  });

  var _text = "Additional Text";
  Object.defineProperty(this, "text", {
    get: function() {
      return _text;
    },
    set: function(val) {
      _text = val;
    }
  });

  var _html = null;
  Object.defineProperty(this, "html", {
    get: function() {
      if(_html === null) {
        _html = '
' +
        '
 ' +
        '       ' + this.headerText + '' +
        '       <button id="copy"></button><button id="min"></button><button id="close"></button>' +
        '
' +
        '
' + this.text + '
' +
        '
';
      }
      return _html
    }
    ,set: function(val) {
      if(checkHTML(val)) {
        _html = _val;
      }
      else {
        throw new InvalidArgumentException("TextSection.html (set)","(string)HTML","value", val);
      }
    }
  });

  this.render = function() {
    //$("#" + thisSection.patternDocument.id).append(thisSection.html);
    var markup = markupGenerator(thisSection);
    $("#PatternDocument").append(markup);
    $("#" + thisSection.id).accordion({animate:200, collapsible:true, heightStyle:"content"});
  }
}

/**
 *
 * @constructor
 */
function PatternSection () {
  var thisSection = this;

  Object.defineProperty(this, "id",{
    get: function() {
      return "Pattern_" + this.index;
    }
  });

  var _counterBoxFactory = new CounterBoxFactory();
  _counterBoxFactory.container = thisSection;
  Object.defineProperty(this, "buttonFactory", {
    get: function() { return _counterBoxFactory }
  });

  function btnBoxCount_Click(event){
    var $inputQuantity = $("#" + event.target.parentElement.id + " > #inputBoxCount")[0];
    var quantity = parseInt($inputQuantity.value);
    thisSection.buttonFactory.createButtons(quantity,event);
    return false;
  }

  this.render = function() {
    var markup = markupGenerator(thisSection);
    $("#PatternDocument").append(markup);
    $("#" + thisSection.id).accordion({animate:200, collapsible:true, heightStyle:"content"});
    $("#" + thisSection.id + " #btnBoxCount").on("click", btnBoxCount_Click);
  };
}
PatternSection.prototype = new TextSection();

/**
 *
 * @constructor
 */
function CounterBoxFactory() {
  var thisFactory = this;

  Object.defineProperty(this,"id",{
    get: function() {
      return this.container.id + "_factory";
    }
  });

  var _container = null;
  Object.defineProperty(this, "container", {
    get: function(){
      return _container;
    },
    set: function(val) {
      if(val instanceof TextSection){
        _container = val;
      }
      else {
        throw new InvalidArgumentException("CounterBoxFactory.container","(object) instanceOf a section","value", val);
      }
    }
  });

  var _buttons = [];
  Object.defineProperty(this,"buttons",{
    get: function() {
      return _buttons;
    }
  });

  var _pb = null;
  Object.defineProperty(this,"progressBar", {
    get: function() {
      return _pb;
    },
    set: function(val) {
      _pb = val;
    }
  });

  this.createButtons = function (quantity,event) {
    console.log(this);
    //empty the collection of buttons.
    _buttons = [];
    var parentElementId = event.target.parentElement.id;
    var $buttonContainer = $("#" + parentElementId + " #counterBoxes");
    $buttonContainer.empty();
    var $pbContainer  = $("#" + parentElementId + " #pb");
    $pbContainer.empty();
    _pb = new ProgressBar.Line("#" + parentElementId + " #pb",{color:'#f00', strokeWidth: 1});

    //create a new collection of buttons === boxcount param.
    for(var i = 1; i<=quantity; i++){
      _buttons[i] = new CounterBox(i);
      _buttons[i].index = i;
      _buttons[i].factory = thisFactory;
      var bindex = pdoc.buttons.push(_buttons[i]);
      _buttons[i].text = bindex;
    }

    //add each button to the document.
    _buttons.forEach(function(counterbox) {
      $buttonContainer.append(counterbox.html);
      var selector = "#" + event.target.parentElement.id + " > #counterBoxes > #" + counterbox.id;
      $(selector).on("click", counterbox, counterbox.click);
    });
  }
}

/**
 *
 * @param labelText
 * @param forecolor
 * @param backcolor
 * @constructor
 */
function CounterBox(text,forecolor,backcolor) {
  var thisCounterBox = this;

  Object.defineProperty(this,"id", {
       get: function() {
       return "box_" + thisCounterBox.index;
    }
  });

  var _text = text;
  Object.defineProperty(this, "text", {
    get: function () {
      return _text;
    },
    set: function (val) {
      _text = val;
    }
  });

  var _fcolor = forecolor || "black";
  Object.defineProperty(this, "foreColor", {
    get: function () {
      return _fcolor
    },
    /**
     * A named color
     * @param val
     */
    set: function (val) {
      if (Colors.isColorValid(val)) {
        _fcolor = val;
      }
      else {
        throw new InvalidArgumentException("CounterBox.foreColor", "(string)a Named Color", "val", val);
      }
    }
  });

  var _bcolor = backcolor || "white";
  Object.defineProperty(this, "backColor", {
    get: function () {
      return _bcolor;
    },
    /**
     * A named color
     * @param val
     */
    set: function (val) {
      if (Colors.isColorValid(val)) {
        _bcolor = val;
      }
      else {
        throw new InvalidArgumentException("CounterBox.backColor", "(string)a Named Color", "val", val);
      }
    }
  });

  Object.defineProperty(this, "html", {
    get: function () {
      var _labelDivStyle = "style='position:relative; width:100%; height:100%; text-align: center'";
      var _imageDivStyle = "style='position:relative; top:-30px; left:0; z-index:1; display:none;'";
      var _imageStyle = "style='height:25px; width:30px; margin: auto;'";
      //var _boxStyle = "style='float:left; color:" + thisCounterBox.foreColor + "; background-color: " + thisCounterBox.backColor + "; height: 25px; width: 30px; margin-top:2px; margin-left:2px; border: solid black 1px; padding-top:5px;'";
      var _boxStyle = "style='color:" + thisCounterBox.foreColor + "; background-color: " + thisCounterBox.backColor + "; height: 25px; width: 30px; margin-top:2px; margin-left:2px; border: solid black 1px; padding-top:5px;'";
      var _imageMarkup = "";
      var _labeldiv = "
" + _text + "
";
      var _imagediv = "
" + _imageMarkup + "
";
      var _inputA = "
";
      var _inputB = "<input type='text' style='margin-left: 3px; width:26px;font-size:.5em'>
";
      var _counterBoxMarkup = _inputA + "
" + _labeldiv + _imagediv + "
" + _inputB;
      //var _counterBoxMarkup = "
" + _labeldiv + _imagediv + "
";
      return _counterBoxMarkup;
    }
  });

  Object.defineProperty(this, "index", {
    get: function() {
      return thisCounterBox.factory.buttons.indexOf(this)
    }
  });

  this.factory = null;

  this.getLabelId = function() {
    return thisCounterBox.id + "_label" + thisCounterBox.labelText
  };

  this.getImageId = function() {
    return thisCounterBox.id + "_image"
  };

  //this.getImageDivId = function() {
  //  return thisCounterBox.id + "_imageDiv"
  //};

  this.click = function (event) {
    //todo: if later I want to update the objects, make sure to do it in counterbox.click.
    var currentSectionId = $(this).parent().parent().parent()[0].id;
    var sectionIndex = currentSectionId.split("_")[1];
    var $thisButton = $("#" + currentSectionId + " #" + $(this)[0].id);
    var $imageDiv = $("#" + currentSectionId + " #" + $(this)[0].id + " #imageDiv");
    var css = $imageDiv.css("display");
    //var action = null;
    if (css === "none") {
      $imageDiv.css({display: "block"});
      //action = "clicked"
    }
    else {
      $imageDiv.css({display: "none"});
      //action = "unclicked";
    }

    var clickedIndex = parseInt($thisButton[0].id.split("_")[1]);
    var sibIndex = null, $sibImageDiv = null, sibCss = null;
    var $siblingButtons = $thisButton.parent().children().not("[id='" + $thisButton[0].id + "']");
    $siblingButtons.each(function(index,element){
      sibIndex = parseInt(element.id.split("_")[1]);
      $sibImageDiv = $(element).children().last();
      sibCss = $sibImageDiv.css("display");
      if(clickedIndex > sibIndex) {
        $sibImageDiv.css("display","block");
      }
      else if(sibIndex > clickedIndex) {
        $sibImageDiv.css("display","none");
      }
    });

    var section = pdoc.sections[sectionIndex];
    section.buttonFactory.progressBar.animate((event.data.index -1) / thisCounterBox.factory.buttons.length);

    return false;
  }
}

/**
 *
 * @constructor
 */
function markupGenerator(section) {
  var markup;

  var outerHTML = '
' +
    '
Pattern Title
' +
    '   <select id="selSectionType">' +
    '     <option>Text Section</option>' +
    '     <option>Pattern Section</option>'+
    '   </select>' +
    ' <button id="btnCreateSection">Create New Section</button>' +
    '
';

  if(section === undefined) {
    markup = outerHTML;
    return markup;
  }

  var textHTML = '
' +
    '
 ' +
    '   ' + section.headerText + '' +
    '   <button id="copy"></button><button id="min"></button><button id="close"></button>' +
    '
' +
    '
' +
    '
' + section.text + '
';

  var patternHTML = ' <input id="inputBoxCount" type="number" min="0" step="1">' +
    ' <button id="btnBoxCount" type="button">Create</button>' +
    '

' +
    '

';

  var closingTag ="

";

  if(section instanceof PatternSection) {
    markup = textHTML + patternHTML + closingTag;
  }
  else if (section instanceof TextSection) {
    markup = textHTML + closingTag;
  }
  else {
    markup = outerHTML;
  }

  return markup;

}

//function GuageSection() {
//
//}
//GuageSection.prototype = new TextSection();
//
//function TextSection() {
//  var _bodytext = "";
//  Object.defineProperty(this, "bodyText", {
//    get:  function() {
//      return _bodytext;
//    },
//    set:  function(val) {
//      if((val !== null) && (val !== undefined)) {
//        _bodytext = val;
//      }
//    }
//  })
//}
//TextSection.prototype = new TextSection();
//
//function MaterialsSection() {
//
//}
//MaterialsSection.prototype = new TextSection();
//
//function InstructionSection () {
//
//}
//InstructionSection.prototype = new TextSection();
<|endoftext|>


<commit_before>/*eslint-env browser*/
/*eslint max-len: 0*/
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import TitleBar from "../components/framework/title-bar";
import Title from "../components/framework/title";
import { headerFont, materialButtonOutline } from "../globalStyles";
import Flex from "../components/framework/flex";
import { analyticsNewPage, triggerOutboundEvent } from "../util/googleAnalytics";
import { generateLogos } from "./helpers/logos";

const styles = {
  cardMainText: {
    fontFamily: headerFont,
    fontWeight: 500,
    fontSize: 28,
    position: "absolute",
    paddingTop: 10,
    paddingBottom: 10,
    paddingLeft: 20,
    paddingRight: 20,
    top: "40px",
    left: "20px",
    color: "white",
    background: "rgba(0, 0, 0, 0.7)"
  },
  cardSubText: {
    color: "white",
    fontStyle: "italic",
    fontSize: 16,
    fontWeight: 400,
    lineHeight: 0.3,
    textAlign: "right"
  },
  cardOuterDiv: {
    backgroundColor: "#FFFFFF",
    // marginLeft: 10,
    // marginRight: 10,
    // marginTop: 5,
    // marginBottom: 5,
    padding: 0,
    overflow: "hidden",
    position: "relative"
    // boxSizing: "content-box"
  },
  cardInnerDiv: {
    boxShadow: "3px 3px 4px 1px rgba(215,215,215,0.85)",
    borderRadius: 2,
    marginLeft: 10,
    marginRight: 10,
    marginTop: 5,
    marginBottom: 5
    // display: "flex",
    // justifyContent: "center",
    // alignItems: "center",
    // overflow: "hidden"
  },
  cardImg: {
    objectFit: "cover",
    width: "100%"
  }
};

const generateCard = (title, imgRequired, to, outboundLink) => {
  function imgAndText() {
    return (
      <g>

          {title[0]}
          {title.length === 2 ?
{title[1]}
 : null}

      </g>
    );
  }
  if (outboundLink) { // use  and trigger google analytics
    return (

           triggerOutboundEvent(to)}>
            {imgAndText()}

    );
  } else { // use <Link> and let React Router sort it out
    return (

          <Link to={to}>
            {imgAndText()}
          </Link>

    );
  }
};

class Splash extends React.Component {
  componentWillMount() {
    analyticsNewPage();
    const script = document.createElement("script");
    script.src = "https://platform.twitter.com/widgets.js";
    script.async = true;
    document.body.appendChild(script);
  }
  render() {
    return(

        <TitleBar logoHidden={true} titleHidden={true}/>

          <Flex justifyContent="center">
            <Title/>
          </Flex>

 Real-time tracking of virus evolution

            Nextstrain is an open-source project to harness the scientific and public health potential of pathogen genome data. We provide a continually-updated view of publicly available data with powerful analytics and visualizations showing pathogen evolution and epidemic spread. Our goal is to aid epidemiological understanding and improve outbreak response.

          <Flex justifyContent="center">
            <Link to="/about">
              <button style={materialButtonOutline}>
                Read More
              </button>
            </Link>
          </Flex>

          {/* THE CLICKABLE CARDS - see about page for sources & attribution */}

Explore viruses

                  {generateCard(["Ebola"], require("../images/ebola.png"), "/ebola?c=division&r=division", false)}

                  {generateCard(["Zika"], require("../images/zika.png"), "/zika", false)}

                  {generateCard(["Influenza", "(uses nextflu.org)"], require("../images/influenza.png"), "http://nextflu.org", true)}

          {/* SOCIAL MEDIA AKA TWITTER */}

From the community

          <Flex wrap="wrap" direction="row" alignItems="flex-start">

Here's NextStrain from @richardneher @trvrb used in Sierra Leone for realtime Ebola transmission. A powerful tool ! pic.twitter.com/fN5sjzUWkL
— Matthew Cotten (@mlcotten13) May 12, 2016

Vote for best open data project: https://t.co/XjHfFWiWLl My favorite: https://t.co/Iana59QyqN from @richardneher @trvrb pic.twitter.com/XTj4bqdsVK
— Matthew Cotten (@mlcotten13) December 3, 2016

https://t.co/RCFZfgStHs shows the 2016 Nzerekore flare-up, sparked by a a survivor in which the virus remained evolutionarily static. pic.twitter.com/RXeniJ3gtu
— Trevor Bedford (@trvrb) October 5, 2016

lovely real time analysis of Ebola virus evolution, great example of timely live data sharing http://t.co/ZZbhehvo44 pic.twitter.com/vqb3EbOeg1
— ben goldacre (@bengoldacre) August 7, 2015

See https://t.co/3K19DNrxgy used to construct lineages, visualize analysis of Ebola virus evolution, context and course of epidemic #AGBT16
— Orli Bahcall (@obahcall) February 13, 2016

Benchmark in data visualisation to help understand, track and manage outbreaks is http://t.co/A1SWuZ5DbM #mHealthMeetup
— Ctrl Group (@ctrl_group) September 1, 2015

Nextstrain uses phylogenetics to track epidemics real-time and understand spread of disease #openscienceprize #BD2KOpenSci
— Lisa Federer (@lisafederer) December 1, 2016

Well said @trvrb ! http://t.co/CqXuO43x7p http://t.co/uoq0CO4anX pic.twitter.com/zSVEJVVLMI
— Nick Loman (@pathogenomenick) June 20, 2015

          </Flex>

          {/* FOOTER / LOGOS */}

              <Flex wrap="wrap" style={{marginTop: 20, justifyContent: "space-around"}}>
                {generateLogos}
              </Flex>

    );
  }
}

export default Splash;

//

http://t.co/zTlTC5bEJP Ebola virus evolution and nanopore sequencing at @unibirmingham Biosciences open day today pic.twitter.com/Bnmw5qREuA
— Nick Loman (@pathogenomenick) October 17, 2015

//

Vote for best Taylor Swift project: https://t.co/LFLPqF9k0x My favorite: https://t.co/pIvv9jAY6z from @richardneher… https://t.co/GrCLAURNJ5
— OpenDataTaylorSwift (@t_s_institute) December 3, 2016

<commit_msg>fix react / twitter warning<commit_after>/*eslint-env browser*/
/*eslint max-len: 0*/
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import TitleBar from "../components/framework/title-bar";
import Title from "../components/framework/title";
import { headerFont, materialButtonOutline } from "../globalStyles";
import Flex from "../components/framework/flex";
import { analyticsNewPage, triggerOutboundEvent } from "../util/googleAnalytics";
import { generateLogos } from "./helpers/logos";

const styles = {
  cardMainText: {
    fontFamily: headerFont,
    fontWeight: 500,
    fontSize: 28,
    position: "absolute",
    paddingTop: 10,
    paddingBottom: 10,
    paddingLeft: 20,
    paddingRight: 20,
    top: "40px",
    left: "20px",
    color: "white",
    background: "rgba(0, 0, 0, 0.7)"
  },
  cardSubText: {
    color: "white",
    fontStyle: "italic",
    fontSize: 16,
    fontWeight: 400,
    lineHeight: 0.3,
    textAlign: "right"
  },
  cardOuterDiv: {
    backgroundColor: "#FFFFFF",
    // marginLeft: 10,
    // marginRight: 10,
    // marginTop: 5,
    // marginBottom: 5,
    padding: 0,
    overflow: "hidden",
    position: "relative"
    // boxSizing: "content-box"
  },
  cardInnerDiv: {
    boxShadow: "3px 3px 4px 1px rgba(215,215,215,0.85)",
    borderRadius: 2,
    marginLeft: 10,
    marginRight: 10,
    marginTop: 5,
    marginBottom: 5
    // display: "flex",
    // justifyContent: "center",
    // alignItems: "center",
    // overflow: "hidden"
  },
  cardImg: {
    objectFit: "cover",
    width: "100%"
  }
};

const generateCard = (title, imgRequired, to, outboundLink) => {
  function imgAndText() {
    return (
      <g>

          {title[0]}
          {title.length === 2 ?
{title[1]}
 : null}

      </g>
    );
  }
  if (outboundLink) { // use  and trigger google analytics
    return (

           triggerOutboundEvent(to)}>
            {imgAndText()}

    );
  } else { // use <Link> and let React Router sort it out
    return (

          <Link to={to}>
            {imgAndText()}
          </Link>

    );
  }
};

class Splash extends React.Component {
  componentWillMount() {
    analyticsNewPage();
    const script = document.createElement("script");
    script.src = "https://platform.twitter.com/widgets.js";
    script.async = true;
    document.body.appendChild(script);
  }
  render() {
    return(

        <TitleBar logoHidden={true} titleHidden={true}/>

          <Flex justifyContent="center">
            <Title/>
          </Flex>

 Real-time tracking of virus evolution

            Nextstrain is an open-source project to harness the scientific and public health potential of pathogen genome data. We provide a continually-updated view of publicly available data with powerful analytics and visualizations showing pathogen evolution and epidemic spread. Our goal is to aid epidemiological understanding and improve outbreak response.

          <Flex justifyContent="center">
            <Link to="/about">
              <button style={materialButtonOutline}>
                Read More
              </button>
            </Link>
          </Flex>

          {/* THE CLICKABLE CARDS - see about page for sources & attribution */}

Explore viruses

                  {generateCard(["Ebola"], require("../images/ebola.png"), "/ebola?c=division&r=division", false)}

                  {generateCard(["Zika"], require("../images/zika.png"), "/zika", false)}

                  {generateCard(["Influenza", "(uses nextflu.org)"], require("../images/influenza.png"), "http://nextflu.org", true)}

          {/* SOCIAL MEDIA AKA TWITTER */}

From the community

          <Flex wrap="wrap" direction="row" alignItems="flex-start">

Here's NextStrain from @richardneher @trvrb used in Sierra Leone for realtime Ebola transmission. A powerful tool ! pic.twitter.com/fN5sjzUWkL
— Matthew Cotten (@mlcotten13) May 12, 2016

Vote for best open data project: https://t.co/XjHfFWiWLl My favorite: https://t.co/Iana59QyqN from @richardneher @trvrb pic.twitter.com/XTj4bqdsVK
— Matthew Cotten (@mlcotten13) December 3, 2016

https://t.co/RCFZfgStHs shows the 2016 Nzerekore flare-up, sparked by a a survivor in which the virus remained evolutionarily static. pic.twitter.com/RXeniJ3gtu
— Trevor Bedford (@trvrb) October 5, 2016

lovely real time analysis of Ebola virus evolution, great example of timely live data sharing http://t.co/ZZbhehvo44 pic.twitter.com/vqb3EbOeg1
— ben goldacre (@bengoldacre) August 7, 2015

See https://t.co/3K19DNrxgy used to construct lineages, visualize analysis of Ebola virus evolution, context and course of epidemic #AGBT16
— Orli Bahcall (@obahcall) February 13, 2016

Benchmark in data visualisation to help understand, track and manage outbreaks is http://t.co/A1SWuZ5DbM #mHealthMeetup
— Ctrl Group (@ctrl_group) September 1, 2015

Nextstrain uses phylogenetics to track epidemics real-time and understand spread of disease #openscienceprize #BD2KOpenSci
— Lisa Federer (@lisafederer) December 1, 2016

Well said @trvrb ! http://t.co/CqXuO43x7p http://t.co/uoq0CO4anX pic.twitter.com/zSVEJVVLMI
— Nick Loman (@pathogenomenick) June 20, 2015

          </Flex>

          {/* FOOTER / LOGOS */}

              <Flex wrap="wrap" style={{marginTop: 20, justifyContent: "space-around"}}>
                {generateLogos}
              </Flex>

    );
  }
}

export default Splash;

//

http://t.co/zTlTC5bEJP Ebola virus evolution and nanopore sequencing at @unibirmingham Biosciences open day today pic.twitter.com/Bnmw5qREuA
— Nick Loman (@pathogenomenick) October 17, 2015

//

Vote for best Taylor Swift project: https://t.co/LFLPqF9k0x My favorite: https://t.co/pIvv9jAY6z from @richardneher… https://t.co/GrCLAURNJ5
— OpenDataTaylorSwift (@t_s_institute) December 3, 2016

<|endoftext|>


<commit_before>import superagent from 'superagent'

const REQUEST_FETCH_BLOCKS = 'REQUEST_FETCH_BLOCKS'
const SUCCESS_FETCH_BLOCKS = 'SUCCESS_FETCH_BLOCKS'
const FAILURE_FETCH_BLOCKS = 'FAILURE_FETCH_BLOCKS'
const EDIT_BLOCK = 'EDIT_BLOCK'
const REMOVE_BLOCK = 'REMOVE_BLOCK'
const MOVE_BLOCK_UP = 'MOVE_BLOCK_UP'
const MOVE_BLOCK_DOWN = 'MOVE_BLOCK_DOWN'

const initialState = {
  loaded: false,
  data: []
}

export default function blocks(state = initialState, action) {
  switch (action.type) {
    case REQUEST_FETCH_BLOCKS:
      return {...state, loaded: false}
    case SUCCESS_FETCH_BLOCKS:
      return {...state, loaded: true, data: action.result }
    case FAILURE_FETCH_BLOCKS:
      return {...state, loaded: true}
    case EDIT_BLOCK:
      return state.map(block =>
        block.id === action.block.id ? action.block : block
      )
    case MOVE_BLOCK_UP:
      return state.map((block, index) => {
        if (index + 1 < state.length && state[index + 1].id === action.block.id) {
          return action.block
        } else if (block.id === action.block.id) {
          return state[index - 1]
        }
        return block
      })
    case MOVE_BLOCK_DOWN:
      return state.map((block, index) => {
        if (index > 0 && state[index - 1].id === action.block.id) {
          return action.block
        } else if (block.id === action.block.id) {
          return state[index + 1]
        }
        return block
      })
    case REMOVE_BLOCK:
      return state.filter(block =>
        action.block.id !== block.id
      )
    default:
      return state
  }
}

export function isBlocksLoaded(globalState) {
  return globalState.blocks.loaded
}

export function fetchBlocks(options) {
  return {
    types: [REQUEST_FETCH_BLOCKS, SUCCESS_FETCH_BLOCKS, FAILURE_FETCH_BLOCKS],
    promise: function() {
      return new Promise(function(resolve, reject) {
        superagent.get(`${process.env.API_URL}/mobilizations/${options.mobilization_id}/blocks`).end((err, res) => {
          if (err) {
            reject(res.body || err)
          } else {
            resolve(res.body)
          }
        })
      })
    }
  }
}
<commit_msg>Add support to add blocks in blocks reducer<commit_after>import superagent from 'superagent'

const REQUEST_FETCH_BLOCKS = 'REQUEST_FETCH_BLOCKS'
const SUCCESS_FETCH_BLOCKS = 'SUCCESS_FETCH_BLOCKS'
const FAILURE_FETCH_BLOCKS = 'FAILURE_FETCH_BLOCKS'

const REQUEST_ADD_BLOCK = 'REQUEST_ADD_BLOCK'
const SUCCESS_ADD_BLOCK = 'SUCCESS_ADD_BLOCK'
const FAILURE_ADD_BLOCK = 'FAILURE_ADD_BLOCK'

const EDIT_BLOCK = 'EDIT_BLOCK'
const REMOVE_BLOCK = 'REMOVE_BLOCK'
const MOVE_BLOCK_UP = 'MOVE_BLOCK_UP'
const MOVE_BLOCK_DOWN = 'MOVE_BLOCK_DOWN'

const initialState = {
  loaded: false,
  data: []
}

export default function blocks(state = initialState, action) {
  switch (action.type) {
    case REQUEST_FETCH_BLOCKS:
      return {...state, loaded: false}
    case SUCCESS_FETCH_BLOCKS:
      return {...state, loaded: true, data: action.result }
    case FAILURE_FETCH_BLOCKS:
      return {...state, loaded: true}
    case EDIT_BLOCK:
      return {...state,
        data: state.data.map(
          block => block.id === action.block.id ? action.block : block
        )
      }
    case REQUEST_ADD_BLOCK:
      return {...state, loaded: false}
    case SUCCESS_ADD_BLOCK:
      return {...state, loaded: true, data: state.data.concat([action.result])}
    case FAILURE_ADD_BLOCK:
      return {...state, loaded: true}
    case MOVE_BLOCK_UP:
      return {...state,
        data: state.map((block, index) => {
          if (index + 1 < state.length && state[index + 1].id === action.block.id) {
            return action.block
          } else if (block.id === action.block.id) {
            return state[index - 1]
          }
          return block
        })
      }
    case MOVE_BLOCK_DOWN:
      return {...state,
        data: state.map((block, index) => {
          if (index > 0 && state[index - 1].id === action.block.id) {
            return action.block
          } else if (block.id === action.block.id) {
            return state[index + 1]
          }
          return block
        })
      }
    case REMOVE_BLOCK:
      return {...state,
        data: state.data.filter(block => action.block.id !== block.id)
      }
    default:
      return state
  }
}

export function isBlocksLoaded(globalState) {
  return globalState.blocks.loaded
}

export function fetchBlocks(options) {
  return {
    types: [REQUEST_FETCH_BLOCKS, SUCCESS_FETCH_BLOCKS, FAILURE_FETCH_BLOCKS],
    promise: function() {
      return new Promise(function(resolve, reject) {
        superagent.get(`${process.env.API_URL}/mobilizations/${options.mobilization_id}/blocks`).end((err, res) => {
          if (err) {
            reject(res.body || err)
          } else {
            resolve(res.body)
          }
        })
      })
    }
  }
}

export function addBlock(params) {
  return {
    types: [REQUEST_ADD_BLOCK, SUCCESS_ADD_BLOCK, FAILURE_ADD_BLOCK],
    promise: function() {
      return new Promise(function(resolve, reject) {
        superagent
        .post(`${process.env.API_URL}/mobilizations/${params.mobilization_id}/blocks`)
        .set(params.credentials)
        .send(params.block)
        .end((err, res) => {
          if (err) {
            reject(res.body || err)
          } else {
            resolve(res.body)
          }
        })
      })
    }
  }
}
<|endoftext|>


<commit_before>/* global services:true */

'use strict';

services.service('KodiPlayer', ['KodiWS', '$q',
  function(KodiWS, $q) {

    /**
     * Format time into a string
     *
     * @param array time : Array with hours, minutes and seconds.
     * @return string Time formatted as '00:00:00'
     */
    function timeFormat(time) {
      var string = '';
      if (time.hours > 0) {
        string += time.hours + ':';
      }
      if (time.minutes < 10) {
        string += '0';
      }
      string += time.minutes + ':';
      if (time.seconds < 10) {
        string += '0';
      }
      string += time.seconds;
      return string;
    }

    var speeds = [-32, -16, -8, -4, -2, -1, 1, 2, 4, 8, 16, 32];

    var hash = {

      /**
       * Get active players from Kodi (if a video or music is being played)
       *
       * @return deferred callback with an active player or a null object.
       */
      active: function() {
        var deferred = $q.defer();
        KodiWS.send('Player.GetActivePlayers', {}).then(function(data) {
          var result = null;
          for (var i = 0; i < data.length ; i++)
          {
            if (data[i].type !== 'picture')
            {
              result = data[i];
            }
          }
          deferred.resolve(result);
        });
        return deferred.promise;
      },

      /**
       * Get the song being played.
       *
       * @param integer playerId : the ID of the active player.
       * @return a deferred callback with the song information.
       */
      get: function(playerId) {
        var deferred = $q.defer();
        KodiWS.send('Player.getItem', { playerid: playerId, properties: ['title', 'artist', 'artistid', 'albumid'] }).then(function(data) {
          if (data === null || data === undefined) {
            deferred.resolve(null);
          }
          var item = {
            label: data.item.label,
            time: null,
            totalTime: null,
            percentage: null,
            paused: false,
            speed: 0,
          };
          if (data.item.type === 'song') {
            item.label = data.item.title + ' - ' + data.item.artist[0];
            item.artistid = data.item.artistid[0];
            item.albumid = data.item.albumid;
          }
          KodiWS.send('Player.getProperties', { playerid: playerId, properties: ['time', 'totaltime', 'percentage', 'speed'] }).then(function(data) {
            if (data === undefined) {
              deferred.resolve(null);
            }
            item.speed = data.speed;
            item.percentage = Math.ceil(data.percentage);
            item.totalTime = timeFormat(data.totaltime);
            item.time = timeFormat(data.time);
            deferred.resolve(item);
          });
        });
        return deferred.promise;
      },

      /**
       * Play or Pause a player.
       *
       * @param integer playerId : the ID of the player to pause
       * @return void
       */
      playPause: function(playerId) {
        KodiWS.send('Player.PlayPause', { playerid: playerId });
      },

      /**
       * Stop a player.
       *
       * @param integer playerId : the ID of the player to stop
       * @return void
       */
      stop: function(playerId) {
        KodiWS.send('Player.Stop', { playerid: playerId });
      },

      /**
       * Go to previous or next song.
       *
       * @param integer playerId : the ID of the player
       * @param string state : 'previous' or 'next'
       * @return void
       */
      changeItem: function(playerId, state) {
        KodiWS.send('Player.GoTo', { playerid: playerId, to: state });
      },

      /**
       * Go backward or forward with a specified speed
       *
       * @param integer playerId : the ID of the player
       * @param integer speed : the current speed
       * @param boolean forward
       * @return void
       */
      changeSpeed: function(playerId, speed, forward) {
        if (speed === 0) {
          speed = 1;
        }
        var i = speeds.indexOf(speed);
        if (i > 0 && !forward) {
          KodiWS.send('Player.SetSpeed', { playerid: playerId, speed: speeds[i - 1] });
        }
        else if (i + 1 < speeds.length && forward) {
          KodiWS.send('Player.SetSpeed', { playerid: playerId, speed: speeds[i + 1] });
        }
      }
    };

    return hash;
  }
]);
<commit_msg>Handle error<commit_after>/* global services:true */

'use strict';

services.service('KodiPlayer', ['KodiWS', '$q',
  function(KodiWS, $q) {

    /**
     * Format time into a string
     *
     * @param array time : Array with hours, minutes and seconds.
     * @return string Time formatted as '00:00:00'
     */
    function timeFormat(time) {
      var string = '';
      if (time.hours > 0) {
        string += time.hours + ':';
      }
      if (time.minutes < 10) {
        string += '0';
      }
      string += time.minutes + ':';
      if (time.seconds < 10) {
        string += '0';
      }
      string += time.seconds;
      return string;
    }

    var speeds = [-32, -16, -8, -4, -2, -1, 1, 2, 4, 8, 16, 32];

    var hash = {

      /**
       * Get active players from Kodi (if a video or music is being played)
       *
       * @return deferred callback with an active player or a null object.
       */
      active: function() {
        var deferred = $q.defer();
        KodiWS.send('Player.GetActivePlayers', {}).then(function(data) {
          var result = null;
          for (var i = 0; i < data.length ; i++)
          {
            if (data[i].type !== 'picture')
            {
              result = data[i];
            }
          }
          deferred.resolve(result);
        });
        return deferred.promise;
      },

      /**
       * Get the song being played.
       *
       * @param integer playerId : the ID of the active player.
       * @return a deferred callback with the song information.
       */
      get: function(playerId) {
        var deferred = $q.defer();
        KodiWS.send('Player.getItem', { playerid: playerId, properties: ['title', 'artist', 'artistid', 'albumid'] }).then(function(data) {
          if (data === null || data === undefined || data.item === undefined) {
            deferred.resolve(null);
          }
          var item = {
            label: data.item.label,
            time: null,
            totalTime: null,
            percentage: null,
            paused: false,
            speed: 0,
          };
          if (data.item.type === 'song') {
            item.label = data.item.title + ' - ' + data.item.artist[0];
            item.artistid = data.item.artistid[0];
            item.albumid = data.item.albumid;
          }
          KodiWS.send('Player.getProperties', { playerid: playerId, properties: ['time', 'totaltime', 'percentage', 'speed'] }).then(function(data) {
            if (data === undefined) {
              deferred.resolve(null);
            }
            item.speed = data.speed;
            item.percentage = Math.ceil(data.percentage);
            item.totalTime = timeFormat(data.totaltime);
            item.time = timeFormat(data.time);
            deferred.resolve(item);
          });
        });
        return deferred.promise;
      },

      /**
       * Play or Pause a player.
       *
       * @param integer playerId : the ID of the player to pause
       * @return void
       */
      playPause: function(playerId) {
        KodiWS.send('Player.PlayPause', { playerid: playerId });
      },

      /**
       * Stop a player.
       *
       * @param integer playerId : the ID of the player to stop
       * @return void
       */
      stop: function(playerId) {
        KodiWS.send('Player.Stop', { playerid: playerId });
      },

      /**
       * Go to previous or next song.
       *
       * @param integer playerId : the ID of the player
       * @param string state : 'previous' or 'next'
       * @return void
       */
      changeItem: function(playerId, state) {
        KodiWS.send('Player.GoTo', { playerid: playerId, to: state });
      },

      /**
       * Go backward or forward with a specified speed
       *
       * @param integer playerId : the ID of the player
       * @param integer speed : the current speed
       * @param boolean forward
       * @return void
       */
      changeSpeed: function(playerId, speed, forward) {
        if (speed === 0) {
          speed = 1;
        }
        var i = speeds.indexOf(speed);
        if (i > 0 && !forward) {
          KodiWS.send('Player.SetSpeed', { playerid: playerId, speed: speeds[i - 1] });
        }
        else if (i + 1 < speeds.length && forward) {
          KodiWS.send('Player.SetSpeed', { playerid: playerId, speed: speeds[i + 1] });
        }
      }
    };

    return hash;
  }
]);
<|endoftext|>


<commit_before>// getters are functions
import * as utils from '../utils'

export const areas = state => {
  return state.areas
}
export const dragAreas = state => {
  return state.dragAreas
}
export const rows = state => {
  return state.rows
}
export const columns = state => {
  return state.columns
}
export const colGap = state => {
  return state.colGap
}
export const rowGap = state => {
  return state.rowGap
}
export const justify = state => {
  return state.justify
}
export const align = state => {
  return state.align
}

export const gridSize = state => {
  return { w: state.columns.length, h: state.rows.length }
}

export const gridTemplateAreas = state => {
  return state.rows
    .map((row, rIndex) => {
      return (
        '    "' +
        state.columns
          .map((col, cIndex) => {
            let areas = state.dragAreas || state.areas
            let area = utils.areaAt(areas, { x: cIndex, y: rIndex, w: 1, h: 1 })
            return area ? area.label : '.'
          })
          .join(' ') +
        '"'
      )
    })
    .join('\n')
}

export const gridStyle = state => {
  return {
    display: 'grid',
    gridTemplateRows: state.rows.reduce(
      (acc, val) =>
        acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
      ''
    ),
    gridTemplateColumns: state.columns.reduce(
      (acc, val) =>
        acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
      ''
    ),
    gridColumnGap:
      state.colGap.size && state.colGap.units
        ? state.colGap.size + state.colGap.units
        : undefined,
    gridRowGap:
      state.rowGap.size && state.rowGap.units
        ? state.rowGap.size + state.rowGap.units
        : undefined,
    justifyItems: state.justify.value ? state.justify.value : undefined,
    alignItems: state.align.value ? state.align.value : undefined,
    gridTemplateAreas: gridTemplateAreas(state),
  }
}

export const itemStyle = state => item => {
  if (item.id === 'placeholder') {
    return {
      backgroundColor: 'rgba(0,0,0,0.5)',
      position: 'absolute',
      top: 0,
      left: 0,
      height: item.h,
      width: item.w,
      transform: 'translate(' + item.x + 'px,' + item.y + 'px)',
    }
  }
  return {
    backgroundColor: utils.stringToRGBA(item.label),
    gridArea: item.label,
  }
}

export const css = state => {
  return `
@supports (grid-area: auto) {
  .grid-container{
    display: grid;
    grid-template-columns: ${state.columns
      .reduce(
        (acc, val) =>
          acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
        ''
      )
      .trim()};
    grid-template-rows: ${state.rows
      .reduce(
        (acc, val) =>
          acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
        ''
      )
      .trim()};
    ${state.colGap.size && state.colGap.units
      ? 'grid-column-gap: ' + state.colGap.size + state.colGap.units + ';'
      : ''}
    ${state.rowGap.size && state.rowGap.units
      ? 'grid-row-gap: ' + state.rowGap.size + state.rowGap.units + ';'
      : ''}
    ${state.justify.value ? 'justify-items: ' + state.justify.value + ';' : ''}
    ${state.align.value ? 'align-items: ' + state.align.value + ';' : ''}
    grid-temlate-areas:
${gridTemplateAreas(state)};
  }

${state.areas
    .sort((a, b) => a.label > b.label)
    .map(a => '  .' + a.label + ' {\n    grid-area: ' + a.label + ';\n  }')
    .join('\n')}

}`.replace(/ {4}\n/g, '')
}
<commit_msg>Fix typo in generated css<commit_after>// getters are functions
import * as utils from '../utils'

export const areas = state => {
  return state.areas
}
export const dragAreas = state => {
  return state.dragAreas
}
export const rows = state => {
  return state.rows
}
export const columns = state => {
  return state.columns
}
export const colGap = state => {
  return state.colGap
}
export const rowGap = state => {
  return state.rowGap
}
export const justify = state => {
  return state.justify
}
export const align = state => {
  return state.align
}

export const gridSize = state => {
  return { w: state.columns.length, h: state.rows.length }
}

export const gridTemplateAreas = state => {
  return state.rows
    .map((row, rIndex) => {
      return (
        '    "' +
        state.columns
          .map((col, cIndex) => {
            let areas = state.dragAreas || state.areas
            let area = utils.areaAt(areas, { x: cIndex, y: rIndex, w: 1, h: 1 })
            return area ? area.label : '.'
          })
          .join(' ') +
        '"'
      )
    })
    .join('\n')
}

export const gridStyle = state => {
  return {
    display: 'grid',
    gridTemplateRows: state.rows.reduce(
      (acc, val) =>
        acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
      ''
    ),
    gridTemplateColumns: state.columns.reduce(
      (acc, val) =>
        acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
      ''
    ),
    gridColumnGap:
      state.colGap.size && state.colGap.units
        ? state.colGap.size + state.colGap.units
        : undefined,
    gridRowGap:
      state.rowGap.size && state.rowGap.units
        ? state.rowGap.size + state.rowGap.units
        : undefined,
    justifyItems: state.justify.value ? state.justify.value : undefined,
    alignItems: state.align.value ? state.align.value : undefined,
    gridTemplateAreas: gridTemplateAreas(state),
  }
}

export const itemStyle = state => item => {
  if (item.id === 'placeholder') {
    return {
      backgroundColor: 'rgba(0,0,0,0.5)',
      position: 'absolute',
      top: 0,
      left: 0,
      height: item.h,
      width: item.w,
      transform: 'translate(' + item.x + 'px,' + item.y + 'px)',
    }
  }
  return {
    backgroundColor: utils.stringToRGBA(item.label),
    gridArea: item.label,
  }
}

export const css = state => {
  return `
@supports (grid-area: auto) {
  .grid-container{
    display: grid;
    grid-template-columns: ${state.columns
      .reduce(
        (acc, val) =>
          acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
        ''
      )
      .trim()};
    grid-template-rows: ${state.rows
      .reduce(
        (acc, val) =>
          acc + (val.units === 'auto' ? '' : val.size) + val.units + ' ',
        ''
      )
      .trim()};
    ${state.colGap.size && state.colGap.units
      ? 'grid-column-gap: ' + state.colGap.size + state.colGap.units + ';'
      : ''}
    ${state.rowGap.size && state.rowGap.units
      ? 'grid-row-gap: ' + state.rowGap.size + state.rowGap.units + ';'
      : ''}
    ${state.justify.value ? 'justify-items: ' + state.justify.value + ';' : ''}
    ${state.align.value ? 'align-items: ' + state.align.value + ';' : ''}
    grid-template-areas:
${gridTemplateAreas(state)};
  }

${state.areas
    .sort((a, b) => a.label > b.label)
    .map(a => '  .' + a.label + ' {\n    grid-area: ' + a.label + ';\n  }')
    .join('\n')}

}`.replace(/ {4}\n/g, '')
}
<|endoftext|>


<commit_before>'use strict';

var exports = module.exports = {};

var _ = require('underscore');
var bookshelf = require('../../db').bookshelf;

// Properties of a todo that can be updated via the API
var editableProps = [
  'Summary',
  'Details'
];

// POST /todos
module.exports.create = function(req, res, next) {

  var ID = req.params.ID;
  var props = _.pick(req.params, editableProps);

  var todoModel = bookshelf.model('Todo');
  var todo = todoModel.forge(props);

  if (!props.Summary) {
    throw new Error('A summary must be provided');
  }

  return todo
    .save()
    .then(function(todo) {
      res.send(200, todo.toJSON());
      return next();
    });

};

// GET /todos
module.exports.getMultiple = function(req, res, next) {

  var todoCollection = bookshelf.collection('Todos');
  var todos = todoCollection.forge();

  var dbQuery = {
    orderByRaw: 'Created ASC'
  };

  return todos
    .query(dbQuery)
    .fetch()
    .then(function() {
      res.send(200, todos.toJSON());
      return next();
    });

};

// GET /todos/:ID
module.exports.getSingle = function(req, res, next) {

  var ID = req.params.ID;

  return fetchTodo(ID)
    .then(function(todo) {
      res.send(200, todo.toJSON());
      return next();
    });

};

// PATCH /todos/:ID
module.exports.patch = function(req, res, next) {

  var ID = req.params.ID;
  var props = _.pick(req.params, editableProps);

  return fetchTodo(ID)
    .then(function(todo) {
      return todo.patch(props);
    })
    .then(function(todo) {
      res.send(200, todo.toJSON());
      return next();
    });

};

// DELETE /todos/:ID
module.exports.delete = function(req, res, next) {

  var ID = req.params.ID;

  return fetchTodo(ID)
    .then(function(todo) {
      return todo.del();
    })
    .then(function() {
      res.send(204, '');
      return next();
    });

};

// Get a todo by ID
function fetchTodo(ID) {

  var todoModel = bookshelf.model('Todo');
  var todo = todoModel.forge({ID: ID});

  return todo
    .fetch()
    .then(function(todo) {

      var todoExists = !!todo && !todo.get('Deleted');

      if (!todoExists) {
        throw new Error('Todo #' + ID + ' does not exist');
      }

      return todo;

    });

}<commit_msg>Fix for Todo API controller returning deleted models in getMultiple()<commit_after>'use strict';

var exports = module.exports = {};

var _ = require('underscore');
var bookshelf = require('../../db').bookshelf;

// Properties of a todo that can be updated via the API
var editableProps = [
  'Summary',
  'Details'
];

// POST /todos
module.exports.create = function(req, res, next) {

  var ID = req.params.ID;
  var props = _.pick(req.params, editableProps);

  var todoModel = bookshelf.model('Todo');
  var todo = todoModel.forge(props);

  if (!props.Summary) {
    throw new Error('A summary must be provided');
  }

  return todo
    .save()
    .then(function(todo) {
      res.send(200, todo.toJSON());
      return next();
    });

};

// GET /todos
module.exports.getMultiple = function(req, res, next) {

  var todoCollection = bookshelf.collection('Todos');
  var todos = todoCollection.forge();

  var dbQuery = {
    whereNull: [
      'Deleted'
    ],
    orderByRaw: 'Created ASC'
  };

  return todos
    .query(dbQuery)
    .fetch()
    .then(function() {
      res.send(200, todos.toJSON());
      return next();
    });

};

// GET /todos/:ID
module.exports.getSingle = function(req, res, next) {

  var ID = req.params.ID;

  return fetchTodo(ID)
    .then(function(todo) {
      res.send(200, todo.toJSON());
      return next();
    });

};

// PATCH /todos/:ID
module.exports.patch = function(req, res, next) {

  var ID = req.params.ID;
  var props = _.pick(req.params, editableProps);

  return fetchTodo(ID)
    .then(function(todo) {
      return todo.patch(props);
    })
    .then(function(todo) {
      res.send(200, todo.toJSON());
      return next();
    });

};

// DELETE /todos/:ID
module.exports.delete = function(req, res, next) {

  var ID = req.params.ID;

  return fetchTodo(ID)
    .then(function(todo) {
      return todo.del();
    })
    .then(function() {
      res.send(204, '');
      return next();
    });

};

// Get a todo by ID
function fetchTodo(ID) {

  var todoModel = bookshelf.model('Todo');
  var todo = todoModel.forge({ID: ID});

  return todo
    .fetch()
    .then(function(todo) {

      var todoExists = !!todo && !todo.get('Deleted');

      if (!todoExists) {
        throw new Error('Todo #' + ID + ' does not exist');
      }

      return todo;

    });

}<|endoftext|>


<commit_before>/* global DS */
import Ember from 'ember';
var {
  $,
  Service
} = Ember;

export default Service.extend({
  container: null,
  init() {
    this.global = this.global || window;
    this.console = this.console || window.console;
    if (typeof DS === 'object') {
      this.store = this.container.lookup('service:store') ||
          this.container.lookup('store:main'); // for ember-data < 2
      this.typeMaps = this.store.typeMaps;
    }
  },
  consoleLog() {
    this.console.log.apply(this.console, arguments);
  },
  app(name) {
    name = name || 'main';
    return this.container.lookup('application:' + name);
  },
  route(name) {
    name = name || this.currentRouteName();
    return this.container.lookup('route:' + name);
  },
  controller(name) {
    name = name || this.currentRouteName();
    return this.container.lookup('controller:' + name);
  },
  model(name) {
    var controller = this.controller(name);
    return controller && controller.get('model');
  },
  service(name) {
    return this.lookup('service:' + name);
  },
  router(name) {
    name = name || 'main';
    return this.container.lookup('router:' + name).get('router');
  },
  routes() {
    return Object.keys(this.router().recognizer.names);
  },
  //component(idDomElementOrSelector) {
  //  if (typeof idDomElementOrSelector === 'object') {
  //    idDomElementOrSelector = idDomElementOrSelector.id;
  //  }
  //  return Ember.Component.views[idDomElementOrSelector] || this.components(idDomElementOrSelector)[0];
  //},
  //components(selectorOrName) {
  //  var views = Ember.Component.views;
  //  var componentClass =  this.lookupFactory('component:' + selectorOrName);
  //
  //  if (componentClass) {
  //    return Object.keys(views).map(id => views[id])
  //      .filter(component => component instanceof componentClass);
  //  }
  //  else {
  //    return $(selectorOrName).map((ix, element) => views[element.id]);
  //  }
  //},
  currentRouteName() {
    return this.controller('application').get('currentRouteName');
  },
  currentPath() {
    return this.controller('application').get('currentPath');
  },
  log(promise, property, getEach) {
    var self = this;
    return promise.then(function(value) {
      self.global.$E = value;
      if (property) {
        value = value[getEach ? 'getEach' : 'get'].call(value, property);
      }
      self.consoleLog(value);
    }, function(err) {
      self.console.error(err);
    });
  },
  lookup(name) {
    return this.container.lookup(name);
  },
  lookupFactory(name) {
    return this.container.lookupFactory(name);
  },
  containerNameFor(object) {
    var cache = this.container.cache || this.container._defaultContainer.cache;
    var keys = Object.keys(cache);
    for (var i = 0; i < keys.length; i++) {
      if (cache[keys[i]] === object) return keys[i];
    }
  },
  inspect: Ember.inspect,
  logResolver(bool) {
    bool = typeof bool === 'undefined' ? true : bool;
    Ember.ENV.LOG_MODULE_RESOLVER = bool;
  },
  logAll(bool) {
    bool = typeof bool === 'undefined' ? true : bool;
    var app = this.app();
    app.LOG_ACTIVE_GENERATION = bool;
    app.LOG_VIEW_LOOKUPS = bool;
    app.LOG_TRANSITIONS = bool;
    app.LOG_TRANSITIONS_INTERNAL = bool;
    this.logResolver(bool);
  },
  globalize() {
    var self = this;
    var props = ['app', 'container', 'store', 'typeMaps',
        'route', 'controller', 'model', 'service', 'routes', 'view', 'currentRouteName',
        'currentPath', 'log', 'lookup', 'lookupFactory', 'containerNameFor',
        'inspect', 'logResolver', 'logAll'];
    // don't stomp on pre-existing global vars
    var skipGlobalize = this.constructor.skipGlobalize;
    if (skipGlobalize === null) {
      skipGlobalize = this.constructor.skipGlobalize = props.filter(function(prop) {
        return !Ember.isNone(self.global[prop]);
      });
    }
    props.map(function(name) {
      if (skipGlobalize.indexOf(name) !== -1) return;
      var prop = self[name];
      if (typeof prop === 'function') {
        prop = function() {
          return self[name].apply(self, arguments);
        };
      }
      self.global[name] = prop;
    });
  }
}).reopenClass({
  skipGlobalize: null
});
<commit_msg>Log render duration<commit_after>/* global DS */
import Ember from 'ember';
var {
  $,
  Service
} = Ember;

export default Service.extend({
  container: null,
  init() {
    this.global = this.global || window;
    this.console = this.console || window.console;
    if (typeof DS === 'object') {
      this.store = this.container.lookup('service:store') ||
          this.container.lookup('store:main'); // for ember-data < 2
      this.typeMaps = this.store.typeMaps;
    }
  },
  consoleLog() {
    this.console.log.apply(this.console, arguments);
  },
  app(name) {
    name = name || 'main';
    return this.container.lookup('application:' + name);
  },
  route(name) {
    name = name || this.currentRouteName();
    return this.container.lookup('route:' + name);
  },
  controller(name) {
    name = name || this.currentRouteName();
    return this.container.lookup('controller:' + name);
  },
  model(name) {
    var controller = this.controller(name);
    return controller && controller.get('model');
  },
  service(name) {
    return this.lookup('service:' + name);
  },
  router(name) {
    name = name || 'main';
    return this.container.lookup('router:' + name).get('router');
  },
  routes() {
    return Object.keys(this.router().recognizer.names);
  },
  //component(idDomElementOrSelector) {
  //  if (typeof idDomElementOrSelector === 'object') {
  //    idDomElementOrSelector = idDomElementOrSelector.id;
  //  }
  //  return Ember.Component.views[idDomElementOrSelector] || this.components(idDomElementOrSelector)[0];
  //},
  //components(selectorOrName) {
  //  var views = Ember.Component.views;
  //  var componentClass =  this.lookupFactory('component:' + selectorOrName);
  //
  //  if (componentClass) {
  //    return Object.keys(views).map(id => views[id])
  //      .filter(component => component instanceof componentClass);
  //  }
  //  else {
  //    return $(selectorOrName).map((ix, element) => views[element.id]);
  //  }
  //},
  currentRouteName() {
    return this.controller('application').get('currentRouteName');
  },
  currentPath() {
    return this.controller('application').get('currentPath');
  },
  log(promise, property, getEach) {
    var self = this;
    return promise.then(function(value) {
      self.global.$E = value;
      if (property) {
        value = value[getEach ? 'getEach' : 'get'].call(value, property);
      }
      self.consoleLog(value);
    }, function(err) {
      self.console.error(err);
    });
  },
  lookup(name) {
    return this.container.lookup(name);
  },
  lookupFactory(name) {
    return this.container.lookupFactory(name);
  },
  containerNameFor(object) {
    var cache = this.container.cache || this.container._defaultContainer.cache;
    var keys = Object.keys(cache);
    for (var i = 0; i < keys.length; i++) {
      if (cache[keys[i]] === object) return keys[i];
    }
  },
  inspect: Ember.inspect,
  logResolver(bool) {
    bool = typeof bool === 'undefined' ? true : bool;
    Ember.ENV.LOG_MODULE_RESOLVER = bool;
  },
  logAll(bool) {
    bool = typeof bool === 'undefined' ? true : bool;
    var app = this.app();
    app.LOG_ACTIVE_GENERATION = bool;
    app.LOG_VIEW_LOOKUPS = bool;
    app.LOG_TRANSITIONS = bool;
    app.LOG_TRANSITIONS_INTERNAL = bool;
    this.logResolver(bool);
  },
  logRenders() {
    var colorForRender = this.colorForRender;

    Ember.subscribe('render', {
      before(name, start, payload) {
        return start;
      },
      after(name, end, payload, start) {
        var id = payload.containerKey;
        if (!id) return;

        var duration = Math.round(end - start);
        var color = colorForRender(duration);

        console.log('%c rendered ' + id + ' in ' + duration + 'ms', 'color: ' + color);
      }
    });
  },
  colorForRender(duration) {
    var ok = '#000000';
    var warning = '#F1B178';
    var serious = '#E86868';

    if (duration < 300) return ok;
    if (duration < 600) return warning;

    return serious;
  },
  globalize() {
    var self = this;
    var props = ['app', 'container', 'store', 'typeMaps',
        'route', 'controller', 'model', 'service', 'routes', 'view', 'currentRouteName',
        'currentPath', 'log', 'lookup', 'lookupFactory', 'containerNameFor',
        'inspect', 'logResolver', 'logAll'];
    // don't stomp on pre-existing global vars
    var skipGlobalize = this.constructor.skipGlobalize;
    if (skipGlobalize === null) {
      skipGlobalize = this.constructor.skipGlobalize = props.filter(function(prop) {
        return !Ember.isNone(self.global[prop]);
      });
    }
    props.map(function(name) {
      if (skipGlobalize.indexOf(name) !== -1) return;
      var prop = self[name];
      if (typeof prop === 'function') {
        prop = function() {
          return self[name].apply(self, arguments);
        };
      }
      self.global[name] = prop;
    });
  }
}).reopenClass({
  skipGlobalize: null
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import RSVP from 'rsvp';
import ENV from 'canvas-web/config/environment';
import Phoenix from 'canvas-web/lib/phoenix';
import { task } from 'ember-concurrency';

const { computed, inject, observer, run } = Ember;

export default Ember.Service.extend({
  currentAccount: inject.service(),
  store: inject.service(),

  liveURL: computed(_ => {
    const host = ENV.apiURL.replace(/^.+?\/\//, '').replace(/\/v1\/$/, '');
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    return `${protocol}//${host}/socket`;
  }),

  /**
   * @member {Ember.Object} An object containing socket params that will be
   *   read anew each time the socket attempts to connect or reconnect
   */
  socketParams: Ember.computed(_ => Ember.Object.create()),

  socket: computed('currentAccount.loggedIn', function() {
    if (!this.get('currentAccount.loggedIn')) return RSVP.Promise.resolve(null);

    return this.get('setSocketToken').perform().then(_ => {
      const socket = new Phoenix.Socket(this.get('liveURL'), {
        heartbeatIntervalMs: 15000,
        params: this.get('socketParams')
      });

      socket.connect();

      socket.onClose(run.bind(this, function() {
        this.get('setSocketToken').perform();
      }));

      this._socket = socket;
      return socket;
    });
  }),

  /**
   * Create an access token and set it as a property on the socket params.
   *
   * @method
   */
  setSocketToken: task(function *() {
    const token = yield this.get('store').createRecord('token', {}).save();
    this.set('socketParams.token', token.get('token'));
  })
});
<commit_msg>Fix ESLint error<commit_after>import Ember from 'ember';
import RSVP from 'rsvp';
import ENV from 'canvas-web/config/environment';
import Phoenix from 'canvas-web/lib/phoenix';
import { task } from 'ember-concurrency';

const { computed, inject, run } = Ember;

export default Ember.Service.extend({
  currentAccount: inject.service(),
  store: inject.service(),

  liveURL: computed(_ => {
    const host = ENV.apiURL.replace(/^.+?\/\//, '').replace(/\/v1\/$/, '');
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    return `${protocol}//${host}/socket`;
  }),

  /**
   * @member {Ember.Object} An object containing socket params that will be
   *   read anew each time the socket attempts to connect or reconnect
   */
  socketParams: Ember.computed(_ => Ember.Object.create()),

  socket: computed('currentAccount.loggedIn', function() {
    if (!this.get('currentAccount.loggedIn')) return RSVP.Promise.resolve(null);

    return this.get('setSocketToken').perform().then(_ => {
      const socket = new Phoenix.Socket(this.get('liveURL'), {
        heartbeatIntervalMs: 15000,
        params: this.get('socketParams')
      });

      socket.connect();

      socket.onClose(run.bind(this, function() {
        this.get('setSocketToken').perform();
      }));

      this._socket = socket;
      return socket;
    });
  }),

  /**
   * Create an access token and set it as a property on the socket params.
   *
   * @method
   */
  setSocketToken: task(function *() {
    const token = yield this.get('store').createRecord('token', {}).save();
    this.set('socketParams.token', token.get('token'));
  })
});
<|endoftext|>