<commit_before>var SourceMapConsumer = require('source-map').SourceMapConsumer;
var path = require('path');
var fs = require('fs');

exports.mapSourcePosition = mapSourcePosition = function(cache, position) {
  var sourceMap = cache[position.source];
  if (!sourceMap && fs.existsSync(position.source)) {
    // Get the URL of the source map
    var fileData = fs.readFileSync(position.source, 'utf8');
    var match = /\/\/[#@]\s*sourceMappingURL=(.*)\s*$/m.exec(fileData);
    if (!match) return position;
    var sourceMappingURL = match[1];

    // Read the contents of the source map
    var sourceMapData;
    var dataUrlPrefix = "data:application/json;base64,";
    if (sourceMappingURL.slice(0, dataUrlPrefix.length).toLowerCase() == dataUrlPrefix) {
      // Support source map URL as a data url
      sourceMapData = new Buffer(sourceMappingURL.slice(dataUrlPrefix.length), "base64").toString();
    }
    else {
      // Support source map URLs relative to the source URL
      var dir = path.dirname(position.source);
      sourceMappingURL = path.resolve(dir, sourceMappingURL);

      if (fs.existsSync(sourceMappingURL)) {
        sourceMapData = fs.readFileSync(sourceMappingURL, 'utf8');
      }
    }

    if (sourceMapData) {
      sourceMap = {
        url: sourceMappingURL,
        map: new SourceMapConsumer(sourceMapData)
      };
      cache[position.source] = sourceMap;
    }
  }

  // Resolve the source URL relative to the URL of the source map
  if (sourceMap) {
    var originalPosition = sourceMap.map.originalPositionFor(position);

    // Only return the original position if a matching line was found. If no
    // matching line is found then we return position instead, which will cause
    // the stack trace to print the path and line for the compiled file. It is
    // better to give a precise location in the compiled file than a vague
    // location in the original file.
    if (originalPosition.source !== null) {
      originalPosition.source = path.resolve(path.dirname(sourceMap.url), originalPosition.source);
      return originalPosition;
    }
  }

  return position;
}

// Parses code generated by FormatEvalOrigin(), a function inside V8:
// https://code.google.com/p/v8/source/browse/trunk/src/messages.js
function mapEvalOrigin(cache, origin) {
  // Most eval() calls are in this format
  var match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
  if (match) {
    var position = mapSourcePosition(cache, {
      source: match[2],
      line: match[3],
      column: match[4]
    });
    return 'eval at ' + match[1] + ' (' + position.source + ':' +
      position.line + ':' + position.column + ')';
  }

  // Parse nested eval() calls using recursion
  match = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
  if (match) {
    return 'eval at ' + match[1] + ' (' + mapEvalOrigin(cache, match[2]) + ')';
  }

  // Make sure we still return useful information if we didn't find anything
  return origin;
}

function wrapCallSite(cache, frame) {
  // Most call sites will return the source file from getFileName(), but code
  // passed to eval() ending in "//# sourceURL=..." will return the source file
  // from getScriptNameOrSourceURL() instead
  var source = frame.getFileName() || frame.getScriptNameOrSourceURL();
  if (source) {
    var position = mapSourcePosition(cache, {
      source: source,
      line: frame.getLineNumber(),
      column: frame.getColumnNumber()
    });
    return {
      __proto__: frame,
      getFileName: function() { return position.source; },
      getLineNumber: function() { return position.line; },
      getColumnNumber: function() { return position.column; },
      getScriptNameOrSourceURL: function() { return position.source; }
    };
  }

  // Code called using eval() needs special handling
  var origin = frame.isEval() && frame.getEvalOrigin();
  if (origin) {
    origin = mapEvalOrigin(cache, origin);
    return {
      __proto__: frame,
      getEvalOrigin: function() { return origin; }
    };
  }

  // If we get here then we were unable to change the source position
  return frame;
}

// This function is part of the V8 stack trace API, for more info see:
// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
function prepareStackTrace(error, stack) {
  // Store source maps in a cache so we don't load them more than once when
  // formatting a single stack trace (don't cache them forever though in case
  // the files change on disk and the user wants to see the updated mapping)
  var cache = {};
  return error + stack.map(function(frame) {
    return '\n    at ' + wrapCallSite(cache, frame);
  }).join('');
}

// Mimic node's stack trace printing when an exception escapes the process
function handleUncaughtExceptions(error) {
  if (!error || !error.stack) {
    console.log('Uncaught exception:', error);
    process.exit();
  }
  var match = /\n    at [^(]+ \((.*):(\d+):(\d+)\)/.exec(error.stack);
  if (match) {
    var cache = {};
    var position = mapSourcePosition(cache, {
      source: match[1],
      line: match[2],
      column: match[3]
    });
    if (fs.existsSync(position.source)) {
      var contents = fs.readFileSync(position.source, 'utf8');
      var line = contents.split(/(?:\r\n|\r|\n)/)[position.line - 1];
      if (line) {
        console.log('\n' + position.source + ':' + position.line);
        console.log(line);
        console.log(new Array(+position.column).join(' ') + '^');
      }
    }
  }
  console.log(error.stack);
  process.exit();
}

exports.install = function(options) {
  Error.prepareStackTrace = prepareStackTrace;

  // Configure options
  options = options || {};
  var installHandler = 'handleUncaughtExceptions' in options ?
    options.handleUncaughtExceptions : true;

  // Provide the option to not install the uncaught exception handler. This is
  // to support other uncaught exception handlers (in test frameworks, for
  // example). If this handler is not installed and there are no other uncaught
  // exception handlers, uncaught exceptions will be caught by node's built-in
  // exception handler and the process will still be terminated. However, the
  // generated JavaScript code will be shown above the stack trace instead of
  // the original source code.
  if (installHandler) {
    process.on('uncaughtException', handleUncaughtExceptions);
  }
};
<commit_msg>Allow overriding the mapping from source file to source map.<commit_after>var SourceMapConsumer = require('source-map').SourceMapConsumer;
var path = require('path');
var fs = require('fs');

// Can be overridden by the retrieveSourceMap option to install. Takes a
// generated source filename; returns a {map, optional url} object, or null if
// there is no source map.  The map field may be either a string or the parsed
// JSON object (ie, it must be a valid argument to the SourceMapConsumer
// constructor).
var retrieveSourceMap = function (source) {
  if (!fs.existsSync(source))
    return null;

  // Get the URL of the source map
  var fileData = fs.readFileSync(source, 'utf8');
  var match = /\/\/[#@]\s*sourceMappingURL=(.*)\s*$/m.exec(fileData);
  if (!match) return null;
  var sourceMappingURL = match[1];

  // Read the contents of the source map
  var sourceMapData;
  var dataUrlPrefix = "data:application/json;base64,";
  if (sourceMappingURL.slice(0, dataUrlPrefix.length).toLowerCase() == dataUrlPrefix) {
    // Support source map URL as a data url
    sourceMapData = new Buffer(sourceMappingURL.slice(dataUrlPrefix.length), "base64").toString();
  }
  else {
    // Support source map URLs relative to the source URL
    var dir = path.dirname(source);
    sourceMappingURL = path.resolve(dir, sourceMappingURL);

    if (fs.existsSync(sourceMappingURL)) {
      sourceMapData = fs.readFileSync(sourceMappingURL, 'utf8');
    }
  }

  if (!sourceMapData) {
    return null;
  }

  return {
    url: sourceMappingURL,
    map: sourceMapData
  };
};

var mapSourcePosition = exports.mapSourcePosition = function(cache, position) {
  var sourceMap = cache[position.source];
  if (!sourceMap) {
    // Call the (overrideable) retrieveSourceMap function to get the source map.
    var urlAndMap = retrieveSourceMap(position.source);
    if (urlAndMap) {
      sourceMap = cache[position.source] = {
        url: urlAndMap.url,
        map: new SourceMapConsumer(urlAndMap.map)
      };
    }
  }

  // Resolve the source URL relative to the URL of the source map
  if (sourceMap) {
    var originalPosition = sourceMap.map.originalPositionFor(position);

    // Only return the original position if a matching line was found. If no
    // matching line is found then we return position instead, which will cause
    // the stack trace to print the path and line for the compiled file. It is
    // better to give a precise location in the compiled file than a vague
    // location in the original file.
    if (originalPosition.source !== null) {
      if (sourceMap.url) {
        originalPosition.source = path.resolve(path.dirname(sourceMap.url), originalPosition.source);
      }
      return originalPosition;
    }
  }

  return position;
};

// Parses code generated by FormatEvalOrigin(), a function inside V8:
// https://code.google.com/p/v8/source/browse/trunk/src/messages.js
function mapEvalOrigin(cache, origin) {
  // Most eval() calls are in this format
  var match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
  if (match) {
    var position = mapSourcePosition(cache, {
      source: match[2],
      line: match[3],
      column: match[4]
    });
    return 'eval at ' + match[1] + ' (' + position.source + ':' +
      position.line + ':' + position.column + ')';
  }

  // Parse nested eval() calls using recursion
  match = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
  if (match) {
    return 'eval at ' + match[1] + ' (' + mapEvalOrigin(cache, match[2]) + ')';
  }

  // Make sure we still return useful information if we didn't find anything
  return origin;
}

function wrapCallSite(cache, frame) {
  // Most call sites will return the source file from getFileName(), but code
  // passed to eval() ending in "//# sourceURL=..." will return the source file
  // from getScriptNameOrSourceURL() instead
  var source = frame.getFileName() || frame.getScriptNameOrSourceURL();
  if (source) {
    var position = mapSourcePosition(cache, {
      source: source,
      line: frame.getLineNumber(),
      column: frame.getColumnNumber()
    });
    return {
      __proto__: frame,
      getFileName: function() { return position.source; },
      getLineNumber: function() { return position.line; },
      getColumnNumber: function() { return position.column; },
      getScriptNameOrSourceURL: function() { return position.source; }
    };
  }

  // Code called using eval() needs special handling
  var origin = frame.isEval() && frame.getEvalOrigin();
  if (origin) {
    origin = mapEvalOrigin(cache, origin);
    return {
      __proto__: frame,
      getEvalOrigin: function() { return origin; }
    };
  }

  // If we get here then we were unable to change the source position
  return frame;
}

// This function is part of the V8 stack trace API, for more info see:
// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
function prepareStackTrace(error, stack) {
  // Store source maps in a cache so we don't load them more than once when
  // formatting a single stack trace (don't cache them forever though in case
  // the files change on disk and the user wants to see the updated mapping)
  var cache = {};
  return error + stack.map(function(frame) {
    return '\n    at ' + wrapCallSite(cache, frame);
  }).join('');
}

// Mimic node's stack trace printing when an exception escapes the process
function handleUncaughtExceptions(error) {
  if (!error || !error.stack) {
    console.log('Uncaught exception:', error);
    process.exit();
  }
  var match = /\n    at [^(]+ \((.*):(\d+):(\d+)\)/.exec(error.stack);
  if (match) {
    var cache = {};
    var position = mapSourcePosition(cache, {
      source: match[1],
      line: match[2],
      column: match[3]
    });
    if (fs.existsSync(position.source)) {
      var contents = fs.readFileSync(position.source, 'utf8');
      var line = contents.split(/(?:\r\n|\r|\n)/)[position.line - 1];
      if (line) {
        console.log('\n' + position.source + ':' + position.line);
        console.log(line);
        console.log(new Array(+position.column).join(' ') + '^');
      }
    }
  }
  console.log(error.stack);
  process.exit();
}

exports.install = function(options) {
  Error.prepareStackTrace = prepareStackTrace;

  // Configure options
  options = options || {};
  var installHandler = 'handleUncaughtExceptions' in options ?
    options.handleUncaughtExceptions : true;

  // Allow source maps to be found by methods other than reading the files
  // directly from disk.
  if (options.retrieveSourceMap)
    retrieveSourceMap = options.retrieveSourceMap;

  // Provide the option to not install the uncaught exception handler. This is
  // to support other uncaught exception handlers (in test frameworks, for
  // example). If this handler is not installed and there are no other uncaught
  // exception handlers, uncaught exceptions will be caught by node's built-in
  // exception handler and the process will still be terminated. However, the
  // generated JavaScript code will be shown above the stack trace instead of
  // the original source code.
  if (installHandler) {
    process.on('uncaughtException', handleUncaughtExceptions);
  }
};
<|endoftext|>


<commit_before>import React from "react";
import injectSheet from "react-jss";
import { Col } from "react-bootstrap/lib";
import { Link } from "react-router-dom";

import { Byline, Dateline } from "../";

const styles = {
  RightColumn: {
    borderLeft: "solid 1px #ddd",
    paddingLeft: "14px !important",
    paddingRight: 0,
    "& > div": {
      paddingBottom: "14px",
    },
  },
  issuuEmbed: {
    borderBottom: "1px solid #ddd",
    marginBottom: "10px",
    paddingBottom: "10px !important",
    textAlign: "center",
  },
  virtualArchivesLabel: {
    color: "#000",
    display: "block",
    fontFamily: "Minion Pro",
    fontWeight: "bold",
    fontSize: "24px",
    lineHeight: 1.22,
    marginTop: "15px",
    marginBottom: "1px",
    "&:hover, &:active, &:focus": {
      color: "#000",
    },
  },
  figure: {
    margin: "0 0 12px 0",
    width: "100%",
    "& img": {
      width: "100%",
    },
  },
  sectionLabel: {
    color: "#000",
    display: "block",
    fontFamily: "Circular Std",
    fontWeight: 300,
    fontSize: "12px",
    marginBottom: "4px",
    textTransform: "uppercase",
    "&:hover, &:active, &:focus": {
      color: "#000",
    },
  },
  primaryArticle: {
    borderBottom: "1px solid #ddd",
    marginBottom: "14px",
  },
  preview: {
    color: "#000",
    fontFamily: "Minion Pro",
    fontSize: "14px",
    lineHeight: 1.29,
    marginBottom: "10px",
  },
  articleTitle: {
    color: "#000",
    display: "block",
    fontFamily: "Minion Pro",
    fontWeight: "bold",
    fontSize: "18px",
    lineHeight: 1.22,
    marginBottom: "1px",
    "&:hover, &:active, &:focus": {
      color: "#000",
    },
  },
  label: {
    borderTop: "1px solid #000",
    borderBottom: "1px solid #ddd",
    color: "#000",
    display: "block",
    fontFamily: "Circular Std",
    fontSize: "13px",
    fontWeight: 300,
    margin: "0 0 12px 0",
    padding: "4px 0",
    "&:hover": {
      color: "#000",
    },
    "&:focus": {
      color: "#000",
    },
  },
  spotifyEmbed: {
    border: 0,
    height: 340,
    width: "100%",
  },
  "@media (max-width: 767px)": {
    RightColumn: {
      borderLeft: "none",
      paddingLeft: "0 !important",
    },
  },
};

const RightColumn = ({ classes, articles }) => {
  if (articles.length !== 2) {
    // TODO: Better way to handle this
    return (
      <Col xsHidden sm={3} md={3} lg={3} className={classes.RightColumn} />
    );
  }
  const [primaryArticle] = articles;
  const primarySection = primaryArticle.section;

  return (
    <Col xsHidden sm={3} md={3} lg={3} className={classes.RightColumn}>
      {/* Column xsHidden because the mobile UI would repeat too many articles */}

          <img
            src={`${process.env.PUBLIC_URL}/img/virtualArchiveLabel.png`}
            href="https://issuu.com/stuyspectator"
            height={384}
            width={248}
            alt=""
          />

            Virtual Archives

      {primaryArticle && (

          {primaryArticle.media.length > 0 && (

              <Link to={`${primarySection.permalink}/${primaryArticle.slug}`}>

              </Link>

          )}
          <Link to={primarySection.permalink} className={classes.sectionLabel}>
            {primarySection.name}
          </Link>
          <Link
            to={`${primarySection.permalink}/${primaryArticle.slug}`}
            className={classes.articleTitle}
          >
            {primaryArticle.title}
          </Link>

{primaryArticle.preview}

          <Byline contributors={primaryArticle.contributors} />
          <Dateline timestamp={primaryArticle.created_at} />

      )}
    </Col>
  );
};

export default injectSheet(styles)(RightColumn);
<commit_msg>revert<commit_after>import React from "react";
import injectSheet from "react-jss";
import { Col } from "react-bootstrap/lib";
import { Link } from "react-router-dom";

import { Byline, Dateline } from "../";

const styles = {
  RightColumn: {
    borderLeft: "solid 1px #ddd",
    paddingLeft: "14px !important",
    paddingRight: 0,
    "& > div": {
      paddingBottom: "14px",
    },
  },
  issuuEmbed: {
    borderBottom: "1px solid #ddd",
    marginBottom: "10px",
    paddingBottom: "10px !important",
    textAlign: "center",
  },
  virtualArchivesLabel: {
    color: "#000",
    display: "block",
    fontFamily: "Minion Pro",
    fontWeight: "bold",
    fontSize: "24px",
    lineHeight: 1.22,
    marginTop: "15px",
    marginBottom: "1px",
    "&:hover, &:active, &:focus": {
      color: "#000",
    },
  },
  figure: {
    margin: "0 0 12px 0",
    width: "100%",
    "& img": {
      width: "100%",
    },
  },
  sectionLabel: {
    color: "#000",
    display: "block",
    fontFamily: "Circular Std",
    fontWeight: 300,
    fontSize: "12px",
    marginBottom: "4px",
    textTransform: "uppercase",
    "&:hover, &:active, &:focus": {
      color: "#000",
    },
  },
  primaryArticle: {
    borderBottom: "1px solid #ddd",
    marginBottom: "14px",
  },
  preview: {
    color: "#000",
    fontFamily: "Minion Pro",
    fontSize: "14px",
    lineHeight: 1.29,
    marginBottom: "10px",
  },
  articleTitle: {
    color: "#000",
    display: "block",
    fontFamily: "Minion Pro",
    fontWeight: "bold",
    fontSize: "18px",
    lineHeight: 1.22,
    marginBottom: "1px",
    "&:hover, &:active, &:focus": {
      color: "#000",
    },
  },
  label: {
    borderTop: "1px solid #000",
    borderBottom: "1px solid #ddd",
    color: "#000",
    display: "block",
    fontFamily: "Circular Std",
    fontSize: "13px",
    fontWeight: 300,
    margin: "0 0 12px 0",
    padding: "4px 0",
    "&:hover": {
      color: "#000",
    },
    "&:focus": {
      color: "#000",
    },
  },
  spotifyEmbed: {
    border: 0,
    height: 340,
    width: "100%",
  },
  "@media (max-width: 767px)": {
    RightColumn: {
      borderLeft: "none",
      paddingLeft: "0 !important",
    },
  },
};

const RightColumn = ({ classes, articles }) => {
  if (articles.length !== 2) {
    // TODO: Better way to handle this
    return (
      <Col xsHidden sm={3} md={3} lg={3} className={classes.RightColumn} />
    );
  }
  const [primaryArticle, secondaryArticle] = articles;
  const primarySection = primaryArticle.section;
  const secondarySection = secondaryArticle.section;

  return (
    <Col xsHidden sm={3} md={3} lg={3} className={classes.RightColumn}>
      {/* Column xsHidden because the mobile UI would repeat too many articles */}

          <img
            src={`${process.env.PUBLIC_URL}/img/virtualArchiveLabel.png`}
            href="https://issuu.com/stuyspectator"
            height={384}
            width={248}
            alt=""
          />

            Virtual Archives

      {primaryArticle && (

          {primaryArticle.media.length > 0 && (

              <Link to={`${primarySection.permalink}/${primaryArticle.slug}`}>

              </Link>

          )}
          <Link to={primarySection.permalink} className={classes.sectionLabel}>
            {primarySection.name}
          </Link>
          <Link
            to={`${primarySection.permalink}/${primaryArticle.slug}`}
            className={classes.articleTitle}
          >
            {primaryArticle.title}
          </Link>

{primaryArticle.preview}

          <Byline contributors={primaryArticle.contributors} />
          <Dateline timestamp={primaryArticle.created_at} />

      )}

      {secondaryArticle && (

          {secondaryArticle.media.length > 0 && (

              <Link
                to={`${secondarySection.permalink}/${secondaryArticle.slug}`}
              >

              </Link>

          )}
          <Link
            to={secondarySection.permalink}
            className={classes.sectionLabel}
          >
            {secondarySection.name}
          </Link>
          <Link
            to={`${secondarySection.permalink}/${secondaryArticle.slug}`}
            className={classes.articleTitle}
          >
            {secondaryArticle.title}
          </Link>

{secondaryArticle.preview}

          <Byline contributors={secondaryArticle.contributors} />
          <Dateline timestamp={secondaryArticle.created_at} />

      )}
    </Col>
  );
};

export default injectSheet(styles)(RightColumn);
<|endoftext|>


<commit_before>/* Copyright 2009-2011 Hewlett-Packard Development Company, L.P. All rights reserved. */

enyo.kind({
	name: "EditorPanel",
	kind: enyo.HFlexBox,
	components: [
		{name: "slidingPane", kind: "HSlidingPane", flex: 1, multiViewMinHeight:1, components: [
			{name: "top",flex: 1, kind:"HSlidingView",
				components: [
					{kind: "Header", components: [
						{kind:"Image", "src":"images/icon.png"},
						{content: "Typewriter", "style": "padding-left: 10px;"},
						{kind: "Spacer", flex: 11},
						{kind: "ToolButtonGroup", components: [
							{caption: "Save File", onclick: "saveFile"},
							{caption: "Open File...", onclick: "openFile"}
						]},
						{kind: "Spacer"}
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, pack: "center", components: [
							{className: "desk-left", flex: 1, overflow: "hidden" },
							{kind: "BasicScroller",
								name:"editorScroller",
								width: "760px",
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "BasicRichText",
										name: "editor",
										richContent: false,
										className: "editor-input",
										onblur: "generateMarkdown",
										onfocus: "showKeyboard"
									}
								]
							},
							{className: "desk-right", flex: 1, overflow: "hidden" }
						]}
					]}
			]},
			{name: "bottom", kind:"HSlidingView", height: "62px", flex:0, //peekHeight: 54,
				onResize: "barMoved",
				components: [
					{kind: "Header", className: "enyo-toolbar fake-toolbar", components: [
						{kind: "GrabButton", className: "HGrabButton"},
						{kind: "Spacer", flex: 18},
						/*{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Headline", name:"markupheadline", className: "markuphelper", onclick:"markupHeadline" },
							{caption: "List", name:"markuplist", className: "markuphelper", onclick:"markupList" },
							{caption: "Link", name:"markuplink", className: "markuphelper", onclick:"markupLink" },
							{caption: "Quote", name:"markupquote", className: "markuphelper", onclick:"markupQuote" },
							{caption: "Code", name:"markupcode", className: "markuphelper", onclick:"markupCode" },
							{caption: "Image", name:"markupimage", className: "markuphelper", onclick:"markupImage" },
						]},
						{kind: "Spacer", flex: 10},
						*/
						{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Syntax", name:"helpmarkdown", onclick: "helpMarkdown"},
							{caption: "Typewriter", name:"helptypewriter", onclick: "helpTypewriter"},
							{caption: "Print", name:"print", onclick: "printDocument"}
						]},
						{kind: "Spacer"},
						{kind: "GrabButton", className: "HGrabButton Right"},
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, pack: "center", components: [
							{className: "desk-left", flex: 1, overflow: "hidden" },
							{kind: "BasicScroller",
								name:"previewScroller",
								width: "760px",
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "HtmlContent",
										name: "preview",
										className: "output-preview",
										onLinkClick: "htmlContentLinkClick"
									}
								]
							},
							{className: "desk-right", flex: 1, overflow: "hidden" }
						]}
					]}
			]}
		]},
		{name:'filePicker', kind: "FilePicker", fileType:["image"], allowMultiSelect:false, onPickFile: "handleFile"},
		{kind: "PrintDialog",
			duplexOption: true,
			frameToPrint: {name:"preview", landscape:false},
			appName: "Typewriter"
		},
		{name: "markdownHelper", kind:"markdownHelper"},
		{name: "typewriterHelper", kind:"typewriterHelper"},
		{name:"Demotext", kind:"Demotext" }
	],

	/* PREVIEW HANDLING */

	barMoved: function(event) {
		if(event.slidePosition == 0) { // down position
			this.position = "down";
			this.$.editorScroller.setScrollTop(this.$.previewScroller.scrollTop/this.$.previewScroller.getBoundaries().bottom*this.$.editorScroller.getBoundaries().bottom);
			//this.$.editor.forceFocus(); // buggy with on screen keyboard
			this.$.print.addClass("enyo-button-disabled");
			this.$.print.disabled = true;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.removeClass("enyo-button-disabled");
			//	item.disabled = false;
			//});

			/*
			this.$.markupheadline.removeClass("enyo-button-disabled");
			this.$.markuplist.removeClass("enyo-button-disabled");
			this.$.markuplink.removeClass("enyo-button-disabled");
			this.$.markupquote.removeClass("enyo-button-disabled");
			this.$.markupcode.removeClass("enyo-button-disabled");
			this.$.markupimage.removeClass("enyo-button-disabled");
			this.$.markupheadline.disabled = false;
			this.$.markuplist.disabled = false;
			this.$.markuplink.disabled = false;
			this.$.markupquote.disabled = false;
			this.$.markupcode.disabled = false;
			this.$.markupimage.disabled = false;
			*/
		}
		else {  // up position
			this.position = "up";
			this.$.previewScroller.setScrollTop(this.$.editorScroller.scrollTop/this.$.editorScroller.getBoundaries().bottom*this.$.previewScroller.getBoundaries().bottom);
			this.$.print.removeClass("enyo-button-disabled");
			this.$.print.disabled = false;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.addClass("enyo-button-disabled");
			//	item.disabled = true;
			//});

			/*
			this.$.markupheadline.addClass("enyo-button-disabled");
			this.$.markuplist.addClass("enyo-button-disabled");
			this.$.markuplink.addClass("enyo-button-disabled");
			this.$.markupquote.addClass("enyo-button-disabled");
			this.$.markupcode.addClass("enyo-button-disabled");
			this.$.markupimage.addClass("enyo-button-disabled");
			this.$.markupheadline.disabled = true;
			this.$.markuplist.disabled = true;
			this.$.markuplink.disabled = true;
			this.$.markupquote.disabled = true;
			this.$.markupcode.disabled = true;
			this.$.markupimage.disabled = true;
			*/
		}

		//this.generateMarkdown();
	},
	generateMarkdown: function() {
		var converter = new Showdown.converter();

		var value = this.$.editor.getValue();
		this.$.preview.setContent(converter.makeHtml(value));
		//this.$.htmlContent.setContent(converter.makeHtml(example));
	},
	htmlContentLinkClick: function(sender, url) {
		var splits = url.split(/#/).slice(-1).pop();
		switch(splits) {
			case "clear":
				this.$.editor.setValue("");
			case "editor":
				this.$.slidingPane.selectView(this.$.top);
				return false;
				break;
			case "preview":
				this.$.slidingPane.selectView(this.$.bottom);
				return false;
				break;
			default:
				var r = new enyo.PalmService();
				r.service = "palm://com.palm.applicationManager/";
				r.method = "open";
				r.call({target: url});
		}
	},

	/* PRINT HANDLING */

	printDocument: function() {
		if(this.position == "down") {
			alert("Preview first!");
		}
		else {
			this.$.printDialog.openAtCenter();
		}
	},

	/* FILE HANDLING */

	openFile: function() {
		this.$.filePicker.pickFile();
	},
	handleFile: function(inSender, msg) {
		this.$.editor.setValue(enyo.json.stringify(msg));
	},

	/* MARKUP CALLBACKS */

	markupHeadline: function() {
	},
	markupList: function() {
	},
	markupLink: function() {
	},
	markupQuote: function() {
	},
	markupCode: function() {
	},
	markupImage: function() {
	},

	helpMarkdown: function() {
		this.$.markdownHelper.openAtControl(this.$.helpmarkdown, {left: 170});
	},
	helpTypewriter: function() {
		this.$.typewriterHelper.openAtControl(this.$.helptypewriter, {left: 220});
	},
	showKeyboard: function() {
		enyo.keyboard.show();
	},

	/* CONSTRUCTOR */

	ready: function() {
		enyo.keyboard.setManualMode(true);
		enyo.keyboard.show();
		this.$.editor.setValue(this.$.Demotext.text);
		this.generateMarkdown();
		this.$.editor.forceFocus();
	}
});
<commit_msg>Syntaxhelper ins Appmenu<commit_after>/* Copyright 2009-2011 Hewlett-Packard Development Company, L.P. All rights reserved. */

enyo.kind({
	name: "EditorPanel",
	kind: enyo.HFlexBox,
	components: [
		{name: "slidingPane", kind: "HSlidingPane", flex: 1, multiViewMinHeight:1, components: [
			{name: "top",flex: 1, kind:"HSlidingView",
				components: [
					{kind: "Header", components: [
						{kind:"Image", "src":"images/icon.png"},
						{content: "Typewriter", "style": "padding-left: 10px;"},
						{kind: "Spacer", flex: 11},
						{kind: "ToolButtonGroup", components: [
							{caption: "Save File", onclick: "saveFile"},
							{caption: "Open File...", onclick: "openFile"}
						]},
						{kind: "Spacer"}
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, pack: "center", components: [
							{className: "desk-left", flex: 1, overflow: "hidden" },
							{kind: "BasicScroller",
								name:"editorScroller",
								width: "760px",
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "BasicRichText",
										name: "editor",
										richContent: false,
										className: "editor-input",
										onblur: "generateMarkdown",
										onfocus: "showKeyboard"
									}
								]
							},
							{className: "desk-right", flex: 1, overflow: "hidden" }
						]}
					]}
			]},
			{name: "bottom", kind:"HSlidingView", height: "62px", flex:0, //peekHeight: 54,
				onResize: "barMoved",
				components: [
					{kind: "Header", className: "enyo-toolbar fake-toolbar", components: [
						{kind: "GrabButton", className: "HGrabButton"},
						{kind: "Spacer", flex: 18},
						/*{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Headline", name:"markupheadline", className: "markuphelper", onclick:"markupHeadline" },
							{caption: "List", name:"markuplist", className: "markuphelper", onclick:"markupList" },
							{caption: "Link", name:"markuplink", className: "markuphelper", onclick:"markupLink" },
							{caption: "Quote", name:"markupquote", className: "markuphelper", onclick:"markupQuote" },
							{caption: "Code", name:"markupcode", className: "markuphelper", onclick:"markupCode" },
							{caption: "Image", name:"markupimage", className: "markuphelper", onclick:"markupImage" },
						]},
						{kind: "Spacer", flex: 10},
						*/
						{kind: "ToolButtonGroup", className: "enyo-toolbutton-dark", components: [
							{caption: "Print", name:"print", onclick: "printDocument"}
						]},
						{kind: "Spacer"},
						{kind: "GrabButton", className: "HGrabButton Right"},
					]},
					{kind: "VFlexBox", flex: 1, components: [
						{kind: "HFlexBox", flex: 1, pack: "center", components: [
							{className: "desk-left", flex: 1, overflow: "hidden" },
							{kind: "BasicScroller",
								name:"previewScroller",
								width: "760px",
								autoHorizontal: false,
								horizontal: false,
								className: "output-scroller",
								components: [
									{kind: "HtmlContent",
										name: "preview",
										className: "output-preview",
										onLinkClick: "htmlContentLinkClick"
									}
								]
							},
							{className: "desk-right", flex: 1, overflow: "hidden" }
						]}
					]}
			]}
		]},
		{name:'filePicker', kind: "FilePicker", fileType:["image"], allowMultiSelect:false, onPickFile: "handleFile"},
		{kind: "PrintDialog",
			duplexOption: true,
			frameToPrint: {name:"preview", landscape:false},
			appName: "Typewriter"
		},
		{name: "markdownHelper", kind:"markdownHelper"},
		{name: "typewriterHelper", kind:"typewriterHelper"},
		{name:"Demotext", kind:"Demotext" },
		{kind: "AppMenu", components: [
			{caption: "Markdown Syntax Help", onclick: "helpMarkdown"},
			{caption: "Typewriter Syntax Help", onclick: "helpTypewriter"},
		]}
	],

	/* PREVIEW HANDLING */

	barMoved: function(event) {
		if(event.slidePosition == 0) { // down position
			this.position = "down";
			this.$.editorScroller.setScrollTop(this.$.previewScroller.scrollTop/this.$.previewScroller.getBoundaries().bottom*this.$.editorScroller.getBoundaries().bottom);
			//this.$.editor.forceFocus(); // buggy with on screen keyboard
			this.$.print.addClass("enyo-button-disabled");
			this.$.print.disabled = true;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.removeClass("enyo-button-disabled");
			//	item.disabled = false;
			//});

			/*
			this.$.markupheadline.removeClass("enyo-button-disabled");
			this.$.markuplist.removeClass("enyo-button-disabled");
			this.$.markuplink.removeClass("enyo-button-disabled");
			this.$.markupquote.removeClass("enyo-button-disabled");
			this.$.markupcode.removeClass("enyo-button-disabled");
			this.$.markupimage.removeClass("enyo-button-disabled");
			this.$.markupheadline.disabled = false;
			this.$.markuplist.disabled = false;
			this.$.markuplink.disabled = false;
			this.$.markupquote.disabled = false;
			this.$.markupcode.disabled = false;
			this.$.markupimage.disabled = false;
			*/
		}
		else {  // up position
			this.position = "up";
			this.$.previewScroller.setScrollTop(this.$.editorScroller.scrollTop/this.$.editorScroller.getBoundaries().bottom*this.$.previewScroller.getBoundaries().bottom);
			this.$.print.removeClass("enyo-button-disabled");
			this.$.print.disabled = false;

			//this.$$.select(".markuphelper").each(function(item) {
			//	item.addClass("enyo-button-disabled");
			//	item.disabled = true;
			//});

			/*
			this.$.markupheadline.addClass("enyo-button-disabled");
			this.$.markuplist.addClass("enyo-button-disabled");
			this.$.markuplink.addClass("enyo-button-disabled");
			this.$.markupquote.addClass("enyo-button-disabled");
			this.$.markupcode.addClass("enyo-button-disabled");
			this.$.markupimage.addClass("enyo-button-disabled");
			this.$.markupheadline.disabled = true;
			this.$.markuplist.disabled = true;
			this.$.markuplink.disabled = true;
			this.$.markupquote.disabled = true;
			this.$.markupcode.disabled = true;
			this.$.markupimage.disabled = true;
			*/
		}

		//this.generateMarkdown();
	},
	generateMarkdown: function() {
		var converter = new Showdown.converter();

		var value = this.$.editor.getValue();
		this.$.preview.setContent(converter.makeHtml(value));
		//this.$.htmlContent.setContent(converter.makeHtml(example));
	},
	htmlContentLinkClick: function(sender, url) {
		var splits = url.split(/#/).slice(-1).pop();
		switch(splits) {
			case "clear":
				this.$.editor.setValue("");
			case "editor":
				this.$.slidingPane.selectView(this.$.top);
				return false;
				break;
			case "preview":
				this.$.slidingPane.selectView(this.$.bottom);
				return false;
				break;
			default:
				var r = new enyo.PalmService();
				r.service = "palm://com.palm.applicationManager/";
				r.method = "open";
				r.call({target: url});
		}
	},

	/* PRINT HANDLING */

	printDocument: function() {
		if(this.position == "down") {
			alert("Preview first!");
		}
		else {
			this.$.printDialog.openAtCenter();
		}
	},

	/* FILE HANDLING */

	openFile: function() {
		this.$.filePicker.pickFile();
	},
	handleFile: function(inSender, msg) {
		this.$.editor.setValue(enyo.json.stringify(msg));
	},

	/* MARKUP CALLBACKS */

	markupHeadline: function() {
	},
	markupList: function() {
	},
	markupLink: function() {
	},
	markupQuote: function() {
	},
	markupCode: function() {
	},
	markupImage: function() {
	},

	helpMarkdown: function() {
		this.$.markdownHelper.openAtCenter(this.$.helpmarkdown);
	},
	helpTypewriter: function() {
		this.$.typewriterHelper.openAtCenter(this.$.helptypewriter);
	},
	showKeyboard: function() {
		enyo.keyboard.show();
	},

	/* CONSTRUCTOR */

	ready: function() {
		enyo.keyboard.setManualMode(true);
		enyo.keyboard.show();
		this.$.editor.setValue(this.$.Demotext.text);
		this.generateMarkdown();
		this.$.editor.forceFocus();
	}
});
<|endoftext|>


<commit_before>describe('eventRender', function() {
	var options;

	beforeEach(function() {
		options = {
			defaultDate: '2014-11-12',
			scrollTime: '00:00:00'
		};
		affix('#cal');
	});

	$.each({
		'month': '.fc-day-grid',
		'agendaWeek': '.fc-time-grid'
	}, function(viewName, gridSelector) {
		describe('when in ' + viewName + ' view', function() {
			beforeEach(function() {
				options.defaultView = viewName;
			});
			describe('with foreground event', function() {
				it('receives correct args AND can modify the element', function(done) {
					options.events = [ {
						title: 'my event',
						start: '2014-11-12T09:00:00'
					} ];
					options.eventRender = function(event, element, view) {
						expect(typeof event).toBe('object');
						expect(event.rendering).toBeUndefined();
						expect(event.start).toBeDefined();
						expect(typeof element).toBe('object');
						expect(element.length).toBe(1);
						expect(typeof view).toBe('object');
						element.css('font-size', '20px');
					};
					options.eventAfterAllRender = function() {
						expect($(gridSelector).find('.fc-event').css('font-size')).toBe('20px');
						expect(options.eventRender).toHaveBeenCalled();
						done();
					};
					spyOn(options, 'eventRender').and.callThrough();
					$('#cal').fullCalendar(options);
				});
			});
		});
	});

	describe('when in month view', function() {
		beforeEach(function() {
			options.defaultView = 'month';
		});

		describe('with a foreground event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12'
				} ];
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-event').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with an all-day background event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12',
					rendering: 'background'
				} ];
			});
			it('receives correct args AND can modify the element', function(done) {
				options.eventRender = function(event, element, view) {
					expect(typeof event).toBe('object');
					expect(event.rendering).toBe('background');
					expect(event.start).toBeDefined();
					expect(typeof element).toBe('object');
					expect(element.length).toBe(1);
					expect(typeof view).toBe('object');
					element.css('font-size', '20px');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').css('font-size')).toBe('20px');
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('sup g	');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('won\'t rendering when returning a new element of the wrong type', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .sup').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with a timed background event', function() { // not exactly related to eventRender!
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12T01:00:00',
					rendering: 'background'
				} ];
			});
			it('won\'t render or call eventRender', function(done) {
				options.eventRender = function(event, element, view) { };
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).not.toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});
	});

	describe('when in agendaWeek view', function() {
		beforeEach(function() {
			options.defaultView = 'agendaWeek';
		});

		describe('with a foreground event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12T01:00:00'
				} ];
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .fc-event').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with a timed background event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12T01:00:00',
					rendering: 'background'
				} ];
			});
			it('receives correct args AND can modify the element', function(done) {
				options.eventRender = function(event, element, view) {
					expect(typeof event).toBe('object');
					expect(event.rendering).toBe('background');
					expect(event.start).toBeDefined();
					expect(typeof element).toBe('object');
					expect(element.length).toBe(1);
					expect(typeof view).toBe('object');
					element.css('font-size', '20px');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .fc-bgevent').css('font-size')).toBe('20px');
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('won\'t rendering when returning a new element of the wrong type', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .sup').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with an all-day background event', function() { // not exactly related to eventRender!
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12',
					rendering: 'background'
				} ];
			});
			it('will render in the all-day slot', function(done) {
				options.eventRender = function(event, element, view) { };
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').length).toBe(1);
					expect($('.fc-time-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});
	});
});<commit_msg>make some unrelated tests pass style check<commit_after>describe('eventRender', function() {
	var options;

	beforeEach(function() {
		options = {
			defaultDate: '2014-11-12',
			scrollTime: '00:00:00'
		};
		affix('#cal');
	});

	$.each({
		month: '.fc-day-grid',
		agendaWeek: '.fc-time-grid'
	}, function(viewName, gridSelector) {
		describe('when in ' + viewName + ' view', function() {
			beforeEach(function() {
				options.defaultView = viewName;
			});
			describe('with foreground event', function() {
				it('receives correct args AND can modify the element', function(done) {
					options.events = [ {
						title: 'my event',
						start: '2014-11-12T09:00:00'
					} ];
					options.eventRender = function(event, element, view) {
						expect(typeof event).toBe('object');
						expect(event.rendering).toBeUndefined();
						expect(event.start).toBeDefined();
						expect(typeof element).toBe('object');
						expect(element.length).toBe(1);
						expect(typeof view).toBe('object');
						element.css('font-size', '20px');
					};
					options.eventAfterAllRender = function() {
						expect($(gridSelector).find('.fc-event').css('font-size')).toBe('20px');
						expect(options.eventRender).toHaveBeenCalled();
						done();
					};
					spyOn(options, 'eventRender').and.callThrough();
					$('#cal').fullCalendar(options);
				});
			});
		});
	});

	describe('when in month view', function() {
		beforeEach(function() {
			options.defaultView = 'month';
		});

		describe('with a foreground event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12'
				} ];
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-event').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with an all-day background event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12',
					rendering: 'background'
				} ];
			});
			it('receives correct args AND can modify the element', function(done) {
				options.eventRender = function(event, element, view) {
					expect(typeof event).toBe('object');
					expect(event.rendering).toBe('background');
					expect(event.start).toBeDefined();
					expect(typeof element).toBe('object');
					expect(element.length).toBe(1);
					expect(typeof view).toBe('object');
					element.css('font-size', '20px');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').css('font-size')).toBe('20px');
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('sup g	');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('won\'t rendering when returning a new element of the wrong type', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .sup').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with a timed background event', function() { // not exactly related to eventRender!
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12T01:00:00',
					rendering: 'background'
				} ];
			});
			it('won\'t render or call eventRender', function(done) {
				options.eventRender = function(event, element, view) { };
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).not.toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});
	});

	describe('when in agendaWeek view', function() {
		beforeEach(function() {
			options.defaultView = 'agendaWeek';
		});

		describe('with a foreground event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12T01:00:00'
				} ];
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .fc-event').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with a timed background event', function() {
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12T01:00:00',
					rendering: 'background'
				} ];
			});
			it('receives correct args AND can modify the element', function(done) {
				options.eventRender = function(event, element, view) {
					expect(typeof event).toBe('object');
					expect(event.rendering).toBe('background');
					expect(event.start).toBeDefined();
					expect(typeof element).toBe('object');
					expect(element.length).toBe(1);
					expect(typeof view).toBe('object');
					element.css('font-size', '20px');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .fc-bgevent').css('font-size')).toBe('20px');
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return a new element', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .sup').length).toBe(1);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('won\'t rendering when returning a new element of the wrong type', function(done) {
				options.eventRender = function(event, element, view) {
					return $('
sup g
');
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .sup').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
			it('can return false and cancel rendering', function(done) {
				options.eventRender = function(event, element, view) {
					return false;
				};
				options.eventAfterAllRender = function() {
					expect($('.fc-time-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});

		describe('with an all-day background event', function() { // not exactly related to eventRender!
			beforeEach(function() {
				options.events = [ {
					title: 'my event',
					start: '2014-11-12',
					rendering: 'background'
				} ];
			});
			it('will render in the all-day slot', function(done) {
				options.eventRender = function(event, element, view) { };
				options.eventAfterAllRender = function() {
					expect($('.fc-day-grid .fc-bgevent').length).toBe(1);
					expect($('.fc-time-grid .fc-bgevent').length).toBe(0);
					expect(options.eventRender).toHaveBeenCalled();
					done();
				};
				spyOn(options, 'eventRender').and.callThrough();
				$('#cal').fullCalendar(options);
			});
		});
	});
});<|endoftext|>


<commit_before>var folder_name = "KPJSFL";
var code_list = ["GlobalLibs.jsfl", "CreateScript.jsfl"];
var current_dir = fl.scriptURI.substr(0, fl.scriptURI.lastIndexOf("/") + 1);
for each(var code_name in code_list) {
	var source = current_dir + code_name;
	if (!FLfile.exists(source)) {
		alert("无法找到" + source);
	}
	var folder_path = fl.configURI + folder_name + "/";
	FLfile.createFolder(folder_path);
	var target = folder_path + code_name;
	if (FLfile.exists(target)) {
		FLfile.remove(target);
	}
	FLfile.copy(source, target);
}
alert("安装完成!");<commit_msg>source change<commit_after>/**
*@author:fangtao
*@date:2014-12-08
*@support:525398535@qq.com
*/

var folder_name = "KPJSFL";
var code_list = ["GlobalLibs.jsfl", "CreateScript.jsfl"];
var current_dir = fl.scriptURI.substr(0, fl.scriptURI.lastIndexOf("/") + 1);
for each(var code_name in code_list) {
	var source = current_dir + code_name;
	if (!FLfile.exists(source)) {
		alert("无法找到" + source);
	}
	var folder_path = fl.configURI + folder_name + "/";
	FLfile.createFolder(folder_path);
	var target = folder_path + code_name;
	if (FLfile.exists(target)) {
		FLfile.remove(target);
	}
	FLfile.copy(source, target);
}
alert("安装完成!");<|endoftext|>


<commit_before>/**
	_moon.ListActions_ is a control used in conjunction with a list of items.  It
	combines an activating control with a drawer containing a menu of selectable
	options.  When a menu item is selected, an action--such as filtering, sorting,
	moving, or deleting--is performed on the items in the associated list.
*/
enyo.kind({
	name: "moon.ListActions",
	//* @protected
	classes: "moon-list-actions",
	kind: "enyo.GroupItem",
	//* @public
	published: {
		//* If true, the drawer is expanded, showing this item's contents
		open: false,
		/**
			If true, the drawer will automatically close when the user
			selects a menu item
		*/
		autoCollapse: false,
		/**
			A block of components (typically, lists of items) to be displayed inside
			of a _moon.Scroller_; by default, it is a scroller without any components.
			When instantiating _moon.ListActions_, declare
			_listActions: <your components>_ to populate the scroller.
		*/
		listActions: null,
		/**
			Source URL for icon image
		*/
		iconSrc: "",
		/**
			By default, list action menus are 300px wide.  To have the menus be proportionally
			sized within the available space, set to true.  Note, a minimum width of 300px is still
			respected; if all menus don't fit horizontally, they will be stacked vertically.
		*/
		proportionalWidth: false
	},

	//* @protected
	events: {
		/**
			Used internally for ListActions to request Header to add fitting components to itself.
			Not intended for use by end-developer.
		*/
		onRequestCreateListActions: ""
	},
	components:[
		{name:"activator", kind: "moon.IconButton", classes: "moon-list-actions-activator", ontap: "expandContract"}
	],
	drawerComponents: [
		{name: "drawer", kind: "moon.ListActionsDrawer", classes: "list-actions-drawer", onComplete: "drawerAnimationEnd", open: false, spotlight: "container", spotlightModal:true, components: [
			{name: "closeButton", kind: "moon.IconButton", icon: "closex", classes: "moon-popup-close moon-list-actions-close moon-neutral", ontap: "expandContract", defaultSpotlightDown:"listActions"},
			{name: "listActionsClientContainer", classes: "enyo-fit moon-list-actions-client-container moon-neutral", components: [
				{name: "listActions", kind: "moon.Scroller", classes: "enyo-fit moon-list-actions-scroller", horizontal:"hidden", vertical:"hidden", onActivate: "optionSelected", defaultSpotlightUp:"closeButton"}
			]}
		]}
	],
	bindings: [
		{from: ".open", to: ".$.drawer.open"},
		{from: ".iconSrc", to: ".$.activator.src"}
	],
	create: function() {
		this.inherited(arguments);
		this.doRequestCreateListActions({components: this.drawerComponents});
		if (!this.$.drawer) {
			throw "moon.ListActions must be created as a child of moon.Header";
		}
		this.listActionsChanged();
		this.drawerNeedsResize = true;
	},
	listActionsChanged: function() {
		var owner = this.hasOwnProperty("listActions") ? this.getInstanceOwner() : this;
		this.listActions = this.listActions || [];
		this.renderListActionComponents(owner);
	},
	renderListActionComponents: function(inOwner) {
		this.noAutoCollapse = true;
		this.createListActionComponents(inOwner);
		this.noAutoCollapse = false;
	},
	createListActionComponents: function(inOwner) {
		var listAction, i;

		this.listActionComponents = [];
		for (i = 0; (listAction = this.listActions[i]); i++) {
			this.listActionComponents.push(this.createListActionComponent(listAction, inOwner));
		}

		// Increase width to 100% if there is only one list action
		if (this.proportionalWidth) {
			this.$.drawer.addClass("proportional-width");
			var w = 100 / this.listActionComponents.length;
			for (i=0; i<this.listActionComponents.length; i++) {
				this.listActionComponents[i].applyStyle("width", w + "%");
			}
		}

		if (this.hasNode()) {
			this.$.listActions.render();
		}
	},
	//* Creates a new list action component based on _inListAction_.
	createListActionComponent: function(inListAction, inOwner) {
		var listActionComponent;

		inListAction.mixins = this.addListActionMixin(inListAction);
		listActionComponent = this.$.listActions.createComponent(inListAction, {owner: inOwner, layoutKind:"FittableRowsLayout"});
		listActionComponent.addClass("moon-list-actions-menu");

		return listActionComponent;
	},
	/**
		Adds a mixin to each list action menu that decorates _activate_ events
		with the menu's _action_ property.
	*/
	addListActionMixin: function(inListAction) {
		var mixins = inListAction.mixins || [];
		if (mixins.indexOf("moon.ListActionActivationSupport") === -1) {
			mixins.push("moon.ListActionActivationSupport");
		}
		return mixins;
	},
	//* Toggles value of _this.open_.
	expandContract: function(inSender, inEvent) {
		if (this.disabled) {
			return true;
		}
		this.setActive(!this.getOpen());
		this.setOpen(!this.getOpen());
	},
	openChanged: function(){
		//If opened, show drawer and resize it if needed
		if(this.open){
			this.$.drawer.show();
			if (this.drawerNeedsResize) {
				this.resizeDrawer();
				this.drawerNeedsResize = false;
			}
		}
	},
	drawerAnimationEnd: function() {
		//on closed, hide drawer and spot _this.$.activator_
		if (!this.getOpen()) {
			this.$.drawer.hide();
			enyo.Spotlight.spot(this.$.activator);
			this.bubble("onRequestUnmuteTooltip");
		}
		//on open, move top and spot _this.$.closeButton_
		else {
			if (this.resetScroller) {
				this.$.listActions.scrollTo(0, 0);
				this.resetScroller = false;
			}
			enyo.Spotlight.spot(this.$.closeButton);
			this.bubble("onRequestMuteTooltip");
		}
	},
	updateStacking: function() {
		if (this.$.drawer.hasNode()) {
			this.set("stacked", this.shouldStack());
		}
	},
	shouldStack: function() {
		// Assumption: min-width of all listActionsComponents set to 300px in CSS
		return this.$.listActions.getBounds().width < (300 * this.listActionComponents.length);
	},
	stackedChanged: function() {
		if (this.stacked) {
			this.$.drawer.addClass("stacked");
			this.stackMeUp();
			this.$.listActions.setVertical("auto");
		}
		else {
			this.$.drawer.removeClass("stacked");
			this.unStackMeUp();
			this.$.listActions.setVertical("hidden");
		}
		this.resetScroller = true;
		this.$.listActions.resized();
	},
	stackMeUp: function() {
		var optionGroup, i;

		for (i = 0; (optionGroup = this.listActionComponents[i]); i++) {
			optionGroup.applyStyle("display", "block");
			optionGroup.applyStyle("height", "none");
		}
	},
	unStackMeUp: function() {
		var containerHeight = this.getContainerBounds().height,
			optionGroup,
			i;

		for (i = 0; (optionGroup = this.listActionComponents[i]); i++) {
			optionGroup.applyStyle("display", "inline-block");
			optionGroup.applyStyle("height", containerHeight + "px");
		}
	},
	resizeHandler: function() {
		this.resetCachedValues();

		// If drawer is collapsed, resize it the next time it is opened
		if (this.getOpen()) {
			this.resizeDrawer();
		} else {
			this.drawerNeedsResize = true;
		}
	},
	resizeDrawer: function() {
		this.updateStacking();
	},
	optionSelected: function(inSender, inEvent) {
		if (this.getOpen() && this.autoCollapse && !this.noAutoCollapse) {
			this.startJob("expandContract", "expandContract", 300);
		}
	},
	getContainerBounds: function() {
		this.containerBounds = this.containerBounds || this.$.listActions.getBounds();
		return this.containerBounds;
	},
	resetCachedValues: function() {
		this.headerBounds = null;
		this.clientBounds = null;
		this.containerBounds = null;
	}
});

/**
	_moon.ListActionsDrawer_ is a control used by
	[moon.ListActions](#moon.ListActions) to house a menu of selectable options.
*/
enyo.kind({
	name: "moon.ListActionsDrawer",
	//* @public
	published: {
		open: false
	},
	//* @protected
	classes: "moon-list-actions-drawer",
	components: [
		{name: "client", classes: "moon-list-actions-drawer-client moon-neutral"},
		{name: "animator", kind: "enyo.StyleAnimator", onStep: "step"}
	],
	rendered: function() {
		this.inherited(arguments);
		// On webOS TV, 2D matrix transforms seem to perform as well as 3D
		// for this use case, and avoid a strange "layer ghosting" issue
		// the first time a drawer is opened.
		this.accel = enyo.dom.canAccelerate() && enyo.platform.webos !== 4;
		this.resetClientPosition();
		this.setShowing(false);
	},
	// We override getBubbleTarget here so that events emanating from a ListActionsDrawer
	// instance will bubble to the owner of the associated ListActions instance, as expected.
	// This is necessary because events normally bubble to a control's DOM parent, but
	// we have sneakily arranged for the DOM parent of a ListActionsDrawer instance to be
	// not the ListActions instance but the containing Header instance.
	getBubbleTarget: function() {
		return this.owner;
	},
	openChanged: function() {
		if (this.open) {
			this.playOpenAnimation();
		} else {
			this.playCloseAnimation();
		}
	},
	resetClientPosition: function() {
		var matrix = this.generateMatrix(this.getBounds().height);
		this.$.client.applyStyle("-webkit-transform", matrix);
	},
	playOpenAnimation: function() {
		var openAnimation = this.createOpenAnimation();
		this.$.animator.play(openAnimation.name);
	},
	createOpenAnimation: function() {
		// For unknown reasons, a null transform works reliably in Chrome,
		// whereas a matrix transform setting Y translation to 0 causes a
		// a strange "layer ghosting" issue the first time a drawer is
		// opened -- the same issue we see on webOS TV with 3D matrices.
		var matrix = enyo.platform.chrome ? null : this.generateMatrix(0);
		return this.$.animator.newAnimation({
			name: "open",
			duration: 225,
			timingFunction: "linear",
			keyframes: {
				0: [{
					control: this.$.client,
					properties: {
						"-webkit-transform"  : "current"
					}
				}],
				100: [{
					control: this.$.client,
					properties: {
						"-webkit-transform" : matrix
					}
				}]
			}
		});
	},
	playCloseAnimation: function() {
		var closeAnimation = this.createCloseAnimation(this.getBounds().height);
		this.$.animator.play(closeAnimation.name);
	},
	createCloseAnimation: function(inHeight) {
		var matrix = this.generateMatrix(inHeight);
		return this.$.animator.newAnimation({
			name: "close",
			duration: 225,
			timingFunction: "linear",
			keyframes: {
				0: [{
					control: this.$.client,
					properties: {
						"-webkit-transform"  : "current"
					}
				}],
				100: [{
					control: this.$.client,
					properties: {
						"-webkit-transform" : matrix
					}
				}]
			}
		});
	},
	generateMatrix: function(inYPosition) {
		return (this.accel) ? this.assemble3dMatrix(0, inYPosition, 1, 1) : this.assemle2dMatrix(0, inYPosition, 1, 1);
	},
	assemle2dMatrix: function(inX, inY, inWidth, inHeight) {
		return "matrix(" + inWidth + ", 0, 0, " + inHeight + ", " + inX + ", " + inY + ")";
	},
	assemble3dMatrix: function(inX, inY, inWidth, inHeight) {
		return "matrix3d(" + inWidth + ", 0, 0, 0, 0, " + inHeight + ", 0, 0, 0, 0, 1, 0, " + inX + ", " + inY + ", 1, 1)";
	}
});

moon.ListActionActivationSupport = {
	name: "ListActionActivationSupport",
	handlers: {
		onActivate: "activate"
	},
	activate: function(inSender, inEvent) {
		inEvent.action = this.action;
	}
};
<commit_msg>GF-55905: Capture onSpotlightFocus events happening outside drawer inside header, and redirect them into the drawer when open. DCO-1.1-Signed-Off-By: Kevin Schaaf <kevin.schaaf@lge.com><commit_after>/**
	_moon.ListActions_ is a control used in conjunction with a list of items.  It
	combines an activating control with a drawer containing a menu of selectable
	options.  When a menu item is selected, an action--such as filtering, sorting,
	moving, or deleting--is performed on the items in the associated list.
*/
enyo.kind({
	name: "moon.ListActions",
	//* @protected
	classes: "moon-list-actions",
	kind: "enyo.GroupItem",
	//* @public
	published: {
		//* If true, the drawer is expanded, showing this item's contents
		open: false,
		/**
			If true, the drawer will automatically close when the user
			selects a menu item
		*/
		autoCollapse: false,
		/**
			A block of components (typically, lists of items) to be displayed inside
			of a _moon.Scroller_; by default, it is a scroller without any components.
			When instantiating _moon.ListActions_, declare
			_listActions: <your components>_ to populate the scroller.
		*/
		listActions: null,
		/**
			Source URL for icon image
		*/
		iconSrc: "",
		/**
			By default, list action menus are 300px wide.  To have the menus be proportionally
			sized within the available space, set to true.  Note, a minimum width of 300px is still
			respected; if all menus don't fit horizontally, they will be stacked vertically.
		*/
		proportionalWidth: false
	},

	//* @protected
	events: {
		/**
			Used internally for ListActions to request Header to add fitting components to itself.
			Not intended for use by end-developer.
		*/
		onRequestCreateListActions: ""
	},
	components:[
		{name:"activator", kind: "moon.IconButton", classes: "moon-list-actions-activator", ontap: "expandContract"}
	],
	drawerComponents: [
		{name: "drawer", kind: "moon.ListActionsDrawer", classes: "list-actions-drawer", onComplete: "drawerAnimationEnd", open: false, spotlight: "container", spotlightModal:true, components: [
			{name: "closeButton", kind: "moon.IconButton", icon: "closex", classes: "moon-popup-close moon-list-actions-close moon-neutral", ontap: "expandContract", defaultSpotlightDown:"listActions"},
			{name: "listActionsClientContainer", classes: "enyo-fit moon-list-actions-client-container moon-neutral", components: [
				{name: "listActions", kind: "moon.Scroller", classes: "enyo-fit moon-list-actions-scroller", horizontal:"hidden", vertical:"hidden", onActivate: "optionSelected", defaultSpotlightUp:"closeButton"}
			]}
		]}
	],
	bindings: [
		{from: ".open", to: ".$.drawer.open"},
		{from: ".iconSrc", to: ".$.activator.src"}
	],
	create: function() {
		this.inherited(arguments);
		this.doRequestCreateListActions({components: this.drawerComponents});
		if (!this.$.drawer) {
			throw "moon.ListActions must be created as a child of moon.Header";
		}
		this.listActionsChanged();
		this.drawerNeedsResize = true;
	},
	listActionsChanged: function() {
		var owner = this.hasOwnProperty("listActions") ? this.getInstanceOwner() : this;
		this.listActions = this.listActions || [];
		this.renderListActionComponents(owner);
	},
	renderListActionComponents: function(inOwner) {
		this.noAutoCollapse = true;
		this.createListActionComponents(inOwner);
		this.noAutoCollapse = false;
	},
	createListActionComponents: function(inOwner) {
		var listAction, i;

		this.listActionComponents = [];
		for (i = 0; (listAction = this.listActions[i]); i++) {
			this.listActionComponents.push(this.createListActionComponent(listAction, inOwner));
		}

		// Increase width to 100% if there is only one list action
		if (this.proportionalWidth) {
			this.$.drawer.addClass("proportional-width");
			var w = 100 / this.listActionComponents.length;
			for (i=0; i<this.listActionComponents.length; i++) {
				this.listActionComponents[i].applyStyle("width", w + "%");
			}
		}

		if (this.hasNode()) {
			this.$.listActions.render();
		}
	},
	//* Creates a new list action component based on _inListAction_.
	createListActionComponent: function(inListAction, inOwner) {
		var listActionComponent;

		inListAction.mixins = this.addListActionMixin(inListAction);
		listActionComponent = this.$.listActions.createComponent(inListAction, {owner: inOwner, layoutKind:"FittableRowsLayout"});
		listActionComponent.addClass("moon-list-actions-menu");

		return listActionComponent;
	},
	/**
		Adds a mixin to each list action menu that decorates _activate_ events
		with the menu's _action_ property.
	*/
	addListActionMixin: function(inListAction) {
		var mixins = inListAction.mixins || [];
		if (mixins.indexOf("moon.ListActionActivationSupport") === -1) {
			mixins.push("moon.ListActionActivationSupport");
		}
		return mixins;
	},
	//* Toggles value of _this.open_.
	expandContract: function(inSender, inEvent) {
		if (this.disabled) {
			return true;
		}
		this.setActive(!this.getOpen());
		this.setOpen(!this.getOpen());

		// Capture onSpotlightFocus happening outside the drawer, so that we can prevent focus
		// from landing in the header beneath the drawer
		if (this.open) {
			enyo.dispatcher.capture(this.$.drawer, {onSpotlightFocus: "capturedSpotlightFocus"}, this);
		} else {
			enyo.dispatcher.release(this.$.drawer);
		}
	},
	openChanged: function(){
		//If opened, show drawer and resize it if needed
		if(this.open){
			this.$.drawer.show();
			if (this.drawerNeedsResize) {
				this.resizeDrawer();
				this.drawerNeedsResize = false;
			}
		}
	},
	drawerAnimationEnd: function() {
		//on closed, hide drawer and spot _this.$.activator_
		if (!this.getOpen()) {
			this.$.drawer.hide();
			enyo.Spotlight.spot(this.$.activator);
			this.bubble("onRequestUnmuteTooltip");
		}
		//on open, move top and spot _this.$.closeButton_
		else {
			if (this.resetScroller) {
				this.$.listActions.scrollTo(0, 0);
				this.resetScroller = false;
			}
			enyo.Spotlight.spot(this.$.closeButton);
			this.bubble("onRequestMuteTooltip");
		}
	},
	updateStacking: function() {
		if (this.$.drawer.hasNode()) {
			this.set("stacked", this.shouldStack());
		}
	},
	shouldStack: function() {
		// Assumption: min-width of all listActionsComponents set to 300px in CSS
		return this.$.listActions.getBounds().width < (300 * this.listActionComponents.length);
	},
	stackedChanged: function() {
		if (this.stacked) {
			this.$.drawer.addClass("stacked");
			this.stackMeUp();
			this.$.listActions.setVertical("auto");
		}
		else {
			this.$.drawer.removeClass("stacked");
			this.unStackMeUp();
			this.$.listActions.setVertical("hidden");
		}
		this.resetScroller = true;
		this.$.listActions.resized();
	},
	stackMeUp: function() {
		var optionGroup, i;

		for (i = 0; (optionGroup = this.listActionComponents[i]); i++) {
			optionGroup.applyStyle("display", "block");
			optionGroup.applyStyle("height", "none");
		}
	},
	unStackMeUp: function() {
		var containerHeight = this.getContainerBounds().height,
			optionGroup,
			i;

		for (i = 0; (optionGroup = this.listActionComponents[i]); i++) {
			optionGroup.applyStyle("display", "inline-block");
			optionGroup.applyStyle("height", containerHeight + "px");
		}
	},
	resizeHandler: function() {
		this.resetCachedValues();

		// If drawer is collapsed, resize it the next time it is opened
		if (this.getOpen()) {
			this.resizeDrawer();
		} else {
			this.drawerNeedsResize = true;
		}
	},
	resizeDrawer: function() {
		this.updateStacking();
	},
	optionSelected: function(inSender, inEvent) {
		if (this.getOpen() && this.autoCollapse && !this.noAutoCollapse) {
			this.startJob("expandContract", "expandContract", 300);
		}
	},
	getContainerBounds: function() {
		this.containerBounds = this.containerBounds || this.$.listActions.getBounds();
		return this.containerBounds;
	},
	resetCachedValues: function() {
		this.headerBounds = null;
		this.clientBounds = null;
		this.containerBounds = null;
	},
	capturedSpotlightFocus: function(inSender, inEvent) {
		// We need to prevent header children below the drawer from being focused
		if (inEvent.originator.isDescendantOf(this.$.drawer.parent) &&
			!inEvent.originator.isDescendantOf(this.$.drawer)) {
			enyo.Spotlight.spot(this.$.drawer);
			return true;
		}
	}
});

/**
	_moon.ListActionsDrawer_ is a control used by
	[moon.ListActions](#moon.ListActions) to house a menu of selectable options.
*/
enyo.kind({
	name: "moon.ListActionsDrawer",
	//* @public
	published: {
		open: false
	},
	//* @protected
	classes: "moon-list-actions-drawer",
	components: [
		{name: "client", classes: "moon-list-actions-drawer-client moon-neutral"},
		{name: "animator", kind: "enyo.StyleAnimator", onStep: "step"}
	],
	rendered: function() {
		this.inherited(arguments);
		// On webOS TV, 2D matrix transforms seem to perform as well as 3D
		// for this use case, and avoid a strange "layer ghosting" issue
		// the first time a drawer is opened.
		this.accel = enyo.dom.canAccelerate() && enyo.platform.webos !== 4;
		this.resetClientPosition();
		this.setShowing(false);
	},
	// We override getBubbleTarget here so that events emanating from a ListActionsDrawer
	// instance will bubble to the owner of the associated ListActions instance, as expected.
	// This is necessary because events normally bubble to a control's DOM parent, but
	// we have sneakily arranged for the DOM parent of a ListActionsDrawer instance to be
	// not the ListActions instance but the containing Header instance.
	getBubbleTarget: function() {
		return this.owner;
	},
	openChanged: function() {
		if (this.open) {
			this.playOpenAnimation();
		} else {
			this.playCloseAnimation();
		}
	},
	resetClientPosition: function() {
		var matrix = this.generateMatrix(this.getBounds().height);
		this.$.client.applyStyle("-webkit-transform", matrix);
	},
	playOpenAnimation: function() {
		var openAnimation = this.createOpenAnimation();
		this.$.animator.play(openAnimation.name);
	},
	createOpenAnimation: function() {
		// For unknown reasons, a null transform works reliably in Chrome,
		// whereas a matrix transform setting Y translation to 0 causes a
		// a strange "layer ghosting" issue the first time a drawer is
		// opened -- the same issue we see on webOS TV with 3D matrices.
		var matrix = enyo.platform.chrome ? null : this.generateMatrix(0);
		return this.$.animator.newAnimation({
			name: "open",
			duration: 225,
			timingFunction: "linear",
			keyframes: {
				0: [{
					control: this.$.client,
					properties: {
						"-webkit-transform"  : "current"
					}
				}],
				100: [{
					control: this.$.client,
					properties: {
						"-webkit-transform" : matrix
					}
				}]
			}
		});
	},
	playCloseAnimation: function() {
		var closeAnimation = this.createCloseAnimation(this.getBounds().height);
		this.$.animator.play(closeAnimation.name);
	},
	createCloseAnimation: function(inHeight) {
		var matrix = this.generateMatrix(inHeight);
		return this.$.animator.newAnimation({
			name: "close",
			duration: 225,
			timingFunction: "linear",
			keyframes: {
				0: [{
					control: this.$.client,
					properties: {
						"-webkit-transform"  : "current"
					}
				}],
				100: [{
					control: this.$.client,
					properties: {
						"-webkit-transform" : matrix
					}
				}]
			}
		});
	},
	generateMatrix: function(inYPosition) {
		return (this.accel) ? this.assemble3dMatrix(0, inYPosition, 1, 1) : this.assemle2dMatrix(0, inYPosition, 1, 1);
	},
	assemle2dMatrix: function(inX, inY, inWidth, inHeight) {
		return "matrix(" + inWidth + ", 0, 0, " + inHeight + ", " + inX + ", " + inY + ")";
	},
	assemble3dMatrix: function(inX, inY, inWidth, inHeight) {
		return "matrix3d(" + inWidth + ", 0, 0, 0, 0, " + inHeight + ", 0, 0, 0, 0, 1, 0, " + inX + ", " + inY + ", 1, 1)";
	}
});

moon.ListActionActivationSupport = {
	name: "ListActionActivationSupport",
	handlers: {
		onActivate: "activate"
	},
	activate: function(inSender, inEvent) {
		inEvent.action = this.action;
	}
};
<|endoftext|>


<commit_before>'use strict';
/*jshint bitwise: false*/

import Promise from 'es6-promises';

const CRC8_TABLE = [
  0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
  0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
  0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
  0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
  0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
  0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
  0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
  0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
  0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
  0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
  0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
  0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
  0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
  0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
  0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
  0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
  0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
  0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
  0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
  0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
  0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
  0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
  0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
  0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
  0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
  0x76, 0x71, 0x78, 0x7f, 0x6A, 0x6d, 0x64, 0x63,
  0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
  0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
  0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
  0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83,
  0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
  0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
];

const LONG_DATA_ID_IDX = [
  [3, 0], [4, 0], [4, 4], [6, 0]
];

const TELEGRAM_TYPES = {
  0x00: ['RPS', 0xf6],
  0x01: ['1BS', 0xd5],
  0x02: ['4BS', 0xa5],
  0x03: ['Smart Acknowledge Signal', 0xd0],
  0x04: ['VDL', 0xd2],
  0x05: ['Universal Teach-In EEP', 0xd4],
  0x06: ['MSC', 0xd1],
  0x07: ['SEC', 0x30],
  0x08: ['SEC_ENCAPS', 0x31],
  0x09: ['Secure Teach-In telegram for switch', 0x35],
  0x0a: ['Generic Profiles selective data', 0xb3],
  0x0b: ['reserved'],
  0x0c: ['reserved'],
  0x0d: ['reserved'],
  0x0e: ['reserved'],
  0x0f: ['Extended Telegram type available']
};

if (!Uint8Array.prototype.slice) {
  Uint8Array.prototype.slice = Array.prototype.slice;
}

class Utils {
  static pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
  }

  static crc8(crc8, u8data) {
    return CRC8_TABLE[crc8 ^ u8data];
  }
}

// EnOcean Radio Protocol 2 SPECIFICATION V1.0 September 26, 2013
export class ERP2Parser {

  parse(payload) {
    let len, dataPl, p, c;
    if (typeof(payload) === 'object' && payload.payload && ERP2Parser.isArray(payload.payload)) {
      dataPl = payload.payload;
      c = payload;
    } else if (typeof(payload) === 'string') {
      dataPl = new Uint8Array(new Buffer(payload, 'hex'));
    } else if (ERP2Parser.isArray(payload)) {
      dataPl = payload;
    } else if (payload instanceof Buffer) {
      dataPl = new Uint8Array(payload);
    } else {
      throw new Error('Unsupported ERP2 payload data type!');
    }
    len = dataPl.length;

    if (len <= 6) {
      p = this._doParseShort(len, dataPl, c);
    } else {
      p = this._doParseLong(len, dataPl, c);
    }
    return p;
  }

  static isArray(val) {
    return (val instanceof Array) || (val instanceof Uint8Array);
  }

  _doParseShort(len, dataPl, c) {
    return new Promise((resolve, reject) => {
      try {
        let i, ctx = { len: len, payload: dataPl, originatorId: '' }, idLen = len - 1, dlLen = 1;
        if (len === 1) {
          ctx.originatorId = Utils.pad(dataPl[0].toString(16), 2);
          dlLen = 0;
        } else if (len >= 6) {
          idLen = 4;
          dlLen = 2;
        }
        for (i = 0; i < idLen; i++) {
          ctx.originatorId += Utils.pad(dataPl[i].toString(16), 2);
        }
        ctx.originatorIdInt = parseInt(ctx.originatorId, 16);
        for (i = 0; i < dlLen; i++) {
          ctx.dataDl += Utils.pad(dataPl[i + idLen].toString(16), 2);
        }
        if (c) {
          ctx.container = c;
        }
        resolve(ctx);
      } catch (e) {
        reject(e);
      }
    });
  }

  _doParseLong(len, dataPl, c) {
    return new Promise((resolve, reject) => {
      try {
        // Bit 5...7 Address Control
        let addressControl = dataPl[0] >> 5;
        if (!LONG_DATA_ID_IDX[addressControl]) {
          throw new Error('Reserved address is unsupported');
        }
        let i, ctx = { len: len, payload: dataPl, originatorId: '', destinationId: '' };
        let idLen = LONG_DATA_ID_IDX[addressControl][0];
        let destLen = LONG_DATA_ID_IDX[addressControl][1];
        for (i = 0; i < idLen; i++) {
          ctx.originatorId += Utils.pad(dataPl[i + 1].toString(16), 2);
        }
        for (i = 0; i < destLen; i++) {
          ctx.destinationId += Utils.pad(dataPl[i + idLen + 1].toString(16), 2);
        }
        ctx.originatorIdInt = parseInt(ctx.originatorId, 16);

        // Bit4 Extended header available
        let extendedHeader = (dataPl[0] & 0x10) >> 4;
        if (extendedHeader > 0) {
          throw new Error('Extended header is unsuported');
        }

        // Bit 0...3 Telegram type (R-ORG)
        let telegramType = dataPl[0] & 0x0f;
        if (telegramType === 0x0f) {
          throw new Error('Extended Telegram type is unsuported');
        }

        ctx.telegramType = TELEGRAM_TYPES[telegramType][0];
        ctx.rorg = TELEGRAM_TYPES[telegramType][1];
        ctx.dataDl = dataPl.slice(idLen + destLen + 1, dataPl.length - 1);

        // Compute CRC8 with DATA_PL except CRC
        let crc8 = 0;
        for (i = 0; i < dataPl.length - 1; i++) {
          crc8 = Utils.crc8(crc8, dataPl[i]);
        }
        if (crc8 !== dataPl[dataPl.length - 1]) {
          throw new Error('CRC8 checksum failure');
        }

        if (c) {
          ctx.container = c;
        }

        resolve(ctx);
      } catch (e) {
        reject(e);
      }
    });
  }
}

// EnOcean Serial Protocol 3 (ESP3) V1.27 / July 30, 2014
export class ESP3RadioERP2Parser {
  parse(payload) {
    let len, esp3;
    if (typeof(payload) === 'string') {
      esp3 = new Uint8Array(new Buffer(payload, 'hex'));
    } else if (payload instanceof Array) {
      esp3 = payload;
    } else if (payload instanceof Buffer) {
      esp3 = new Uint8Array(payload);
    } else {
      throw new Error('Unsupported ESP3 payload data type!');
    }
    len = esp3.length;
    return new Promise((resolve, reject) => {
      try {
        if (esp3[0] !== 0x55) {
          throw new Error('Unknown Synchronization-word');
        }
        if (esp3[4] !== 0x0a) {
          throw new Error('Invalid packet type, RADIO_ERP2(0x0a) is expected');
        }
        if (esp3[3] !== 0x02) {
          throw new Error('Invalid optinal size');
        }
        let crc8 = 0, i, header = esp3.slice(1, 5);
        for (i = 0; i < header.length; i++) {
          crc8 = Utils.crc8(crc8, header[i]);
        }
        if (crc8 !== esp3[5]) {
          throw new Error('CRC8 for header value checksum failure');
        }

        let ctx = { len: len };
        let dataLen = esp3[1] * 256 + esp3[2];
        ctx.payload = esp3.slice(6, 6 + dataLen);
        ctx.subTelNum = esp3[6 + dataLen];
        ctx.dBm = esp3[7 + dataLen];

        crc8 = 0;
        for (i = 0; i < (dataLen + 2); i++) {
          crc8 = Utils.crc8(crc8, esp3[i + 6]);
        }
        if (crc8 !== esp3[esp3.length - 1]) {
          throw new Error('CRC8 for data value checksum failure');
        }
        resolve(ctx);
      } catch (e) {
        reject(e);
      }
    });
  }
}
<commit_msg>Add a flag to enable/disable ESP3 dump to stdout<commit_after>'use strict';
/*jshint bitwise: false*/

import Promise from 'es6-promises';

const CRC8_TABLE = [
  0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
  0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
  0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
  0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
  0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
  0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
  0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
  0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
  0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
  0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
  0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
  0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
  0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
  0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
  0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
  0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
  0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
  0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
  0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
  0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
  0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
  0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
  0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
  0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
  0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
  0x76, 0x71, 0x78, 0x7f, 0x6A, 0x6d, 0x64, 0x63,
  0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
  0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
  0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
  0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8D, 0x84, 0x83,
  0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
  0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
];

const LONG_DATA_ID_IDX = [
  [3, 0], [4, 0], [4, 4], [6, 0]
];

const TELEGRAM_TYPES = {
  0x00: ['RPS', 0xf6],
  0x01: ['1BS', 0xd5],
  0x02: ['4BS', 0xa5],
  0x03: ['Smart Acknowledge Signal', 0xd0],
  0x04: ['VDL', 0xd2],
  0x05: ['Universal Teach-In EEP', 0xd4],
  0x06: ['MSC', 0xd1],
  0x07: ['SEC', 0x30],
  0x08: ['SEC_ENCAPS', 0x31],
  0x09: ['Secure Teach-In telegram for switch', 0x35],
  0x0a: ['Generic Profiles selective data', 0xb3],
  0x0b: ['reserved'],
  0x0c: ['reserved'],
  0x0d: ['reserved'],
  0x0e: ['reserved'],
  0x0f: ['Extended Telegram type available']
};

const ESP3_DUMP = process.env.ESP3_DUMP || false;

if (!Uint8Array.prototype.slice) {
  Uint8Array.prototype.slice = Array.prototype.slice;
}

class Utils {
  static pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
  }

  static crc8(crc8, u8data) {
    return CRC8_TABLE[crc8 ^ u8data];
  }
}

// EnOcean Radio Protocol 2 SPECIFICATION V1.0 September 26, 2013
export class ERP2Parser {

  parse(payload) {
    let len, dataPl, p, c;
    if (typeof(payload) === 'object' && payload.payload && ERP2Parser.isArray(payload.payload)) {
      dataPl = payload.payload;
      c = payload;
    } else if (typeof(payload) === 'string') {
      dataPl = new Uint8Array(new Buffer(payload, 'hex'));
    } else if (ERP2Parser.isArray(payload)) {
      dataPl = payload;
    } else if (payload instanceof Buffer) {
      dataPl = new Uint8Array(payload);
    } else {
      throw new Error('Unsupported ERP2 payload data type!');
    }
    len = dataPl.length;

    if (len <= 6) {
      p = this._doParseShort(len, dataPl, c);
    } else {
      p = this._doParseLong(len, dataPl, c);
    }
    return p;
  }

  static isArray(val) {
    return (val instanceof Array) || (val instanceof Uint8Array);
  }

  _doParseShort(len, dataPl, c) {
    return new Promise((resolve, reject) => {
      try {
        let i, ctx = { len: len, payload: dataPl, originatorId: '' }, idLen = len - 1, dlLen = 1;
        if (len === 1) {
          ctx.originatorId = Utils.pad(dataPl[0].toString(16), 2);
          dlLen = 0;
        } else if (len >= 6) {
          idLen = 4;
          dlLen = 2;
        }
        for (i = 0; i < idLen; i++) {
          ctx.originatorId += Utils.pad(dataPl[i].toString(16), 2);
        }
        ctx.originatorIdInt = parseInt(ctx.originatorId, 16);
        for (i = 0; i < dlLen; i++) {
          ctx.dataDl += Utils.pad(dataPl[i + idLen].toString(16), 2);
        }
        if (c) {
          ctx.container = c;
        }
        resolve(ctx);
      } catch (e) {
        reject(e);
      }
    });
  }

  _doParseLong(len, dataPl, c) {
    return new Promise((resolve, reject) => {
      try {
        // Bit 5...7 Address Control
        let addressControl = dataPl[0] >> 5;
        if (!LONG_DATA_ID_IDX[addressControl]) {
          throw new Error('Reserved address is unsupported');
        }
        let i, ctx = { len: len, payload: dataPl, originatorId: '', destinationId: '' };
        let idLen = LONG_DATA_ID_IDX[addressControl][0];
        let destLen = LONG_DATA_ID_IDX[addressControl][1];
        for (i = 0; i < idLen; i++) {
          ctx.originatorId += Utils.pad(dataPl[i + 1].toString(16), 2);
        }
        for (i = 0; i < destLen; i++) {
          ctx.destinationId += Utils.pad(dataPl[i + idLen + 1].toString(16), 2);
        }
        ctx.originatorIdInt = parseInt(ctx.originatorId, 16);

        // Bit4 Extended header available
        let extendedHeader = (dataPl[0] & 0x10) >> 4;
        if (extendedHeader > 0) {
          throw new Error('Extended header is unsuported');
        }

        // Bit 0...3 Telegram type (R-ORG)
        let telegramType = dataPl[0] & 0x0f;
        if (telegramType === 0x0f) {
          throw new Error('Extended Telegram type is unsuported');
        }

        ctx.telegramType = TELEGRAM_TYPES[telegramType][0];
        ctx.rorg = TELEGRAM_TYPES[telegramType][1];
        ctx.dataDl = dataPl.slice(idLen + destLen + 1, dataPl.length - 1);

        // Compute CRC8 with DATA_PL except CRC
        let crc8 = 0;
        for (i = 0; i < dataPl.length - 1; i++) {
          crc8 = Utils.crc8(crc8, dataPl[i]);
        }
        if (crc8 !== dataPl[dataPl.length - 1]) {
          throw new Error('CRC8 checksum failure');
        }

        if (c) {
          ctx.container = c;
        }

        resolve(ctx);
      } catch (e) {
        reject(e);
      }
    });
  }
}

// EnOcean Serial Protocol 3 (ESP3) V1.27 / July 30, 2014
export class ESP3RadioERP2Parser {
  parse(payload) {
    let len, esp3;
    if (typeof(payload) === 'string') {
      esp3 = new Uint8Array(new Buffer(payload, 'hex'));
    } else if (payload instanceof Array) {
      esp3 = payload;
    } else if (payload instanceof Buffer) {
      esp3 = new Uint8Array(payload);
    } else {
      throw new Error('Unsupported ESP3 payload data type!');
    }
    len = esp3.length;
    if (ESP3_DUMP) {
      console.log(`ENOCEAN LEN[${len}] RAW[${new Buffer(esp3).toString('hex')}]`);
    }
    return new Promise((resolve, reject) => {
      try {
        if (esp3[0] !== 0x55) {
          throw new Error('Unknown Synchronization-word');
        }
        if (esp3[4] !== 0x0a) {
          throw new Error('Invalid packet type, RADIO_ERP2(0x0a) is expected');
        }
        if (esp3[3] !== 0x02) {
          throw new Error('Invalid optinal size');
        }
        let crc8 = 0, i, header = esp3.slice(1, 5);
        for (i = 0; i < header.length; i++) {
          crc8 = Utils.crc8(crc8, header[i]);
        }
        if (crc8 !== esp3[5]) {
          throw new Error('CRC8 for header value checksum failure');
        }

        let ctx = { len: len };
        let dataLen = esp3[1] * 256 + esp3[2];
        ctx.payload = esp3.slice(6, 6 + dataLen);
        ctx.subTelNum = esp3[6 + dataLen];
        ctx.dBm = esp3[7 + dataLen];

        crc8 = 0;
        for (i = 0; i < (dataLen + 2); i++) {
          crc8 = Utils.crc8(crc8, esp3[i + 6]);
        }
        if (crc8 !== esp3[esp3.length - 1]) {
          throw new Error('CRC8 for data value checksum failure');
        }
        resolve(ctx);
      } catch (e) {
        reject(e);
      }
    });
  }
}
<|endoftext|>