<commit_before>import Ember from "ember";
import PreventGhostClicks from "../utils/prevent-ghost-clicks";
import capitalizeWord from "../utils/capitalize-word";
import isCustomProtocol from "../utils/is-custom-protocol";
import isGesture from "../utils/is-gesture";
import defaultConfiguration from "../default-config";
import hammerEvents from "../utils/hammer-events";
import RecognizerInterface from "../recognizers";
import removeEventsPatch from "../utils/determine-remove-events-patch";

var IS_MOBILE = !!("ontouchstart" in window);

export default Ember.EventDispatcher.reopen({

  /**!
   * Used to store the Hammer.js Manager instance
   */
  _hammerInstance: null,

  /**!
   * Gets set during initialization with the user's
   * custom configuration
   */
  _mobileTouchCustomizations : null,

  /**!
   * Stores the result of merging the user's customizations
   * with the default configuration.
   */
  _mobileTouchConfig : null,

  /**!
   *
   * Sets up the manager instance
   *
   * @private
   */
  _initializeHammer: function (rootElement) {

    var element = Ember.$(rootElement)[0];
    Ember.assert('Application has no rootElement', element);

    //setup the Manager instance
    var config = this.get('_mobileTouchConfig');
    this.set('_hammerInstance', new Hammer.Manager(element, config.options));

    //add recognizers
    this._initializeRecognizers();

    /*
      We have to click bust clicks that trigger undesirable behaviors,
      but still allow clicks that do.
     */
    document.body.addEventListener('click', function (e) {

      e = e || window.event;
      var $element = Ember.$(e.target);

      // cancel the click only if there is an ember action defined on the input or button of type submit
      // or if the click is on a link and no href attribute is present
      var cancelIf =

        //allow overriding click busting by adding the `allow-click` class
        !$element.hasClass('allow-click') &&
        (
          //bust clicks on links that don't have a custom protocol such as `mailto:` or `tel:`
          ($element.is('a[href]') && !isCustomProtocol($element.attr('href'))) ||

          //bust clicks on buttons and input buttons that aren't 'submit' buttons
          $element.is('button[type!="submit"], input[type="button"]') ||

          //bust clicks on inputs/buttons of type submit when they have a defined action handler
          ($element.is('input[type="submit"], button[type="submit"]') && $element.attr('data-ember-action'))
        );

      /*
        recast the click as a "submit" action if we're on mobile
        this allows mobile keyboard submit button to work
       */
      if (IS_MOBILE && $element.is('input[type="submit"], button[type="submit"]')) {
        $element.trigger('submit');
      }

      //bust the click
      if (cancelIf) {
        e.preventDefault();
        e.stopPropagation();
        return false;
      }

    });

    /*
        Implements a fast focus mechanism on mobile web/Cordova
     */
    if (IS_MOBILE) {

      document.body.addEventListener('tap press', function (e) {
        e = e || window.event;
        var $element = Ember.$(e.target);

        /*
         If the click was on an input element that needs to be able to focus, recast
         the click as a "focus" event.

         This fixes tap events on mobile where keyboardShrinksView or similar is true.
         Such devices depend on the ghost click to trigger focus, but the ghost click
         will never reach the element.
         */
        var notFocusableTypes = ['submit', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox'];
        if ($element.is('input') && notFocusableTypes.indexOf($element.attr('type')) === -1) {
          $element.focus();
        }

      });

    }

    /*
      Mobile devices trigger a click after a delay

      Mobile Browsers try to pretend that they are normal browsers, so they fire a "click" event
      a short delay after a "touchEnd". This is great for sites that haven't optimized for mobile,
      but for sites that do use touchEnd to determine taps/clicks, the extra click event needs to
      be captured and discarded, otherwise both the touchEnd and the click event will trigger a tap.
     */
    PreventGhostClicks.add(element);

  },

  _customRecognizers : null,

  /**!
   * Initializes any custom recognizers added in app/recognizers.js
   */
  _initializeRecognizers : function () {

    var config = this.get('_mobileTouchConfig');
    var EventManager = this;
    var Interface = new RecognizerInterface(this, this.get('_hammerInstance'));

    //add initial recognizers (recognizers defined in app/recognizers.js are added later)
    config.use.forEach(function (name) {
      Interface.Recognizers[capitalizeWord(name)] = EventManager._addRecognizer(name, config.tune[name]);
    });

    //if swipe and pan are present, recognize together
    if (Interface.Recognizers.Swipe && Interface.Recognizers.Pan) {
      Interface.Recognizers.Swipe.recognizeWith(Interface.Recognizers.Pan);
    }

    //add custom recognizers
    var CustomRecognizers = this.get('_customRecognizers');
    if (CustomRecognizers) { CustomRecognizers.call(Interface); }

  },

  /**!
   * Adds a recognizer to the Hammer instance
   */
  _addRecognizer: function(type, options) {
    var Manager = this.get('_hammerInstance');
    var recognizer = new Hammer[capitalizeWord(type)](options);
    Manager.add(recognizer);
    return recognizer;
  },

  /**!
   *
   * Setup the mobileTouch configuration
   *
   * @param addedEvents
   * @param rootElement
   */
  setup: function (addedEvents, rootElement) {

    //merge the default configuration with the user's alterations
    var customConfig = this.get('_mobileTouchCustomizations');
    var config = Ember.merge(Ember.copy(defaultConfiguration, true), customConfig);

    //assert necessary configurations
    Ember.assert('ENV.mobileTouch.options.domEvents MUST be true!', config.options.domEvents);
    Ember.assert('ENV.mobileTouch.use MUST contain a minimum of `tap`!', (config.use.indexOf('tap') !== -1));

    //save configuration
    this.set('_mobileTouchConfig', config);

    //remove undesirable events from Ember's Eventing
    var events = this.get('events');
    var eventsToRemove = removeEventsPatch(config.events, events);
    eventsToRemove.forEach(function (name) {
      delete events[name];
    });

    //change click to internalClick
    events.click = 'internalClick';

    //add gesture events
    config.use.forEach(function (category) {
      Ember.merge(events, hammerEvents[category]);
    });

    //allow `alwaysTapOnPress` configuration
    if (config.use.indexOf('press') !== -1 && config.alwaysTapOnPress) {
      events.press = 'tap';
      delete events.pressUp;
    }

    //probably unnecessary? events should be a reference already
    this.set('events', events);

    //setup hammer
    this._initializeHammer(rootElement);

    //setup rootElement and  event listeners
    this._super(addedEvents, rootElement);

  },

  /**!
   *
   * If a view or component had defined gestureAllow or gestureExclude,
   * filter gesture events.
   *
   * @param eventName
   * @param event
   * @param view
   * @param context
   * @returns {*}
   * @private
   */
  __executeGestureWithFilters: function (eventName, event, view, context) {

    var shouldFilter = isGesture(eventName) ? (view.get('gestureAllow') || view.get('gestureExclude')) : false,
      element, result;

    if (context) {

      element = shouldFilter ? view._filterTouchableElements.call(view, event.target) : false;
      result = (shouldFilter && !element) ? false : Ember.run(context, context[eventName], event, view);

    } else {

      element = shouldFilter ? view._filterTouchableElements.call(view, event.target) : false;
      result = (shouldFilter && !element) ? false : Ember.run.join(view, view.handleEvent, eventName, event);

    }

    //only stop propagation if result is explicitly false, not null or undefined
    if (result === false) {
      //hammer events have different semantics than normal events, so we must check before invoking
      if (event.stopPropagation) { event.stopPropagation(); }
      if (event.preventDefault) { event.preventDefault(); }
      if (event.preventDefaults) { event.preventDefaults(); }
    }

    return result;

  },

  /**
   *
   * Alters the normal _dispatchEvent to allow gesture filtering
   *
   * @param object
   * @param event
   * @param eventName
   * @param view
   * @returns {boolean}
   * @private
   */
  _dispatchEvent: function (object, event, eventName, view) {
    var result = true;

    var handler = object[eventName];
    if (Ember.typeOf(handler) === 'function') {
      result = this.__executeGestureWithFilters(eventName, event, view, object);
      // Do not preventDefault in eventManagers.
      event.stopPropagation();
    }
    else if (view) {
      result = this._bubbleEvent(view, event, eventName);
    }

    return result;
  },

  /**
   *
   * Alters the normal _bubbleEvent to allow gesture filtering
   *
   * @param view
   * @param event
   * @param eventName
   * @returns {*}
   * @private
   */
  _bubbleEvent: function (view, event, eventName) {
    return this.__executeGestureWithFilters(eventName, event, view);
  },

  /**!
   * Extend the normal destroy method to teardown the hammer manager
   * instance and remove the click buster.
   */
  destroy: function () {

    var hammer = this.get('_hammerInstance'),
      element = Ember.$(this.get('rootElement'))[0];

    //teardown Hammer
    if (hammer) { hammer.destroy(); }
    this.set('_hammerInstance', null);

    //teardown clickbuster
    PreventGhostClicks.remove(element);

    //run normal destroy
    this._super();
  }

});
<commit_msg>trigger clicks immediately on tap/press (fastclick)<commit_after>import Ember from "ember";
import PreventGhostClicks from "../utils/prevent-ghost-clicks";
import capitalizeWord from "../utils/capitalize-word";
import isCustomProtocol from "../utils/is-custom-protocol";
import isGesture from "../utils/is-gesture";
import defaultConfiguration from "../default-config";
import hammerEvents from "../utils/hammer-events";
import RecognizerInterface from "../recognizers";
import removeEventsPatch from "../utils/determine-remove-events-patch";

var IS_MOBILE = !!("ontouchstart" in window);

export default Ember.EventDispatcher.reopen({

  /**!
   * Used to store the Hammer.js Manager instance
   */
  _hammerInstance: null,

  /**!
   * Gets set during initialization with the user's
   * custom configuration
   */
  _mobileTouchCustomizations : null,

  /**!
   * Stores the result of merging the user's customizations
   * with the default configuration.
   */
  _mobileTouchConfig : null,

  /**!
   *
   * Sets up the manager instance
   *
   * @private
   */
  _initializeHammer: function (rootElement) {

    var element = Ember.$(rootElement)[0];
    Ember.assert('Application has no rootElement', element);

    //setup the Manager instance
    var config = this.get('_mobileTouchConfig');
    this.set('_hammerInstance', new Hammer.Manager(element, config.options));

    //add recognizers
    this._initializeRecognizers();

    /*
      We have to click bust clicks that trigger undesirable behaviors,
      but still allow clicks that do.
     */
    document.body.addEventListener('click', function (e) {

      e = e || window.event;
      var $element = Ember.$(e.target);

      // cancel the click only if there is an ember action defined on the input or button of type submit
      // or if the click is on a link and no href attribute is present
      var cancelIf =

        //allow overriding click busting by adding the `allow-click` class
        !$element.hasClass('allow-click') &&
        (
          //bust clicks on links that don't have a custom protocol such as `mailto:` or `tel:`
          ($element.is('a[href]') && !isCustomProtocol($element.attr('href'))) ||

          //bust clicks on buttons and input buttons that aren't 'submit' buttons
          $element.is('button[type!="submit"], input[type="button"]') ||

          //bust clicks on inputs/buttons of type submit when they have a defined action handler
          ($element.is('input[type="submit"], button[type="submit"]') && $element.attr('data-ember-action'))
        );

      /*
        recast the click as a "submit" action if we're on mobile
        this allows mobile keyboard submit button to work
       */
      if (IS_MOBILE && $element.is('input[type="submit"], button[type="submit"]')) {
        $element.trigger('submit');
      }

      //bust the click
      if (cancelIf) {
        e.preventDefault();
        e.stopPropagation();
        return false;
      }

    });

    /*
        Implements fastclick and fastfocus mechanisms on mobile web/Cordova
     */
    if (IS_MOBILE) {

      document.body.addEventListener('tap press', function (e) {
        e = e || window.event;
        var $element = Ember.$(e.target);

        /*
         If the click was on an input element that needs to be able to focus, recast
         the click as a "focus" event.

         This fixes tap events on mobile where keyboardShrinksView or similar is true.
         Such devices depend on the ghost click to trigger focus, but the ghost click
         will never reach the element.
         */
        var notFocusableTypes = ['submit', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox'];
        if ($element.is('input') && notFocusableTypes.indexOf($element.attr('type')) === -1) {
          $element.focus();
        } else {

          //set the fastclick flag so that we can filter this from
          // Ember's eventing later
          var click = Ember.$.Event('click');
          click.fastclick = true;
          $element.trigger(click);
        }

      });

    }

    /*
      Mobile devices trigger a click after a delay

      Mobile Browsers try to pretend that they are normal browsers, so they fire a "click" event
      a short delay after a "touchEnd". This is great for sites that haven't optimized for mobile,
      but for sites that do use touchEnd to determine taps/clicks, the extra click event needs to
      be captured and discarded, otherwise both the touchEnd and the click event will trigger a tap.
     */
    PreventGhostClicks.add(element);

  },

  _customRecognizers : null,

  /**!
   * Initializes any custom recognizers added in app/recognizers.js
   */
  _initializeRecognizers : function () {

    var config = this.get('_mobileTouchConfig');
    var EventManager = this;
    var Interface = new RecognizerInterface(this, this.get('_hammerInstance'));

    //add initial recognizers (recognizers defined in app/recognizers.js are added later)
    config.use.forEach(function (name) {
      Interface.Recognizers[capitalizeWord(name)] = EventManager._addRecognizer(name, config.tune[name]);
    });

    //if swipe and pan are present, recognize together
    if (Interface.Recognizers.Swipe && Interface.Recognizers.Pan) {
      Interface.Recognizers.Swipe.recognizeWith(Interface.Recognizers.Pan);
    }

    //add custom recognizers
    var CustomRecognizers = this.get('_customRecognizers');
    if (CustomRecognizers) { CustomRecognizers.call(Interface); }

  },

  /**!
   * Adds a recognizer to the Hammer instance
   */
  _addRecognizer: function(type, options) {
    var Manager = this.get('_hammerInstance');
    var recognizer = new Hammer[capitalizeWord(type)](options);
    Manager.add(recognizer);
    return recognizer;
  },

  /**!
   *
   * Setup the mobileTouch configuration
   *
   * @param addedEvents
   * @param rootElement
   */
  setup: function (addedEvents, rootElement) {

    //merge the default configuration with the user's alterations
    var customConfig = this.get('_mobileTouchCustomizations');
    var config = Ember.merge(Ember.copy(defaultConfiguration, true), customConfig);

    //assert necessary configurations
    Ember.assert('ENV.mobileTouch.options.domEvents MUST be true!', config.options.domEvents);
    Ember.assert('ENV.mobileTouch.use MUST contain a minimum of `tap`!', (config.use.indexOf('tap') !== -1));

    //save configuration
    this.set('_mobileTouchConfig', config);

    //remove undesirable events from Ember's Eventing
    var events = this.get('events');
    var eventsToRemove = removeEventsPatch(config.events, events);
    eventsToRemove.forEach(function (name) {
      delete events[name];
    });

    //change click to internalClick
    events.click = 'internalClick';

    //add gesture events
    config.use.forEach(function (category) {
      Ember.merge(events, hammerEvents[category]);
    });

    //allow `alwaysTapOnPress` configuration
    if (config.use.indexOf('press') !== -1 && config.alwaysTapOnPress) {
      events.press = 'tap';
      delete events.pressUp;
    }

    //probably unnecessary? events should be a reference already
    this.set('events', events);

    //setup hammer
    this._initializeHammer(rootElement);

    //setup rootElement and  event listeners
    this._super(addedEvents, rootElement);

  },

  /**!
   *
   * If a view or component had defined gestureAllow or gestureExclude,
   * filter gesture events.
   *
   * @param eventName
   * @param event
   * @param view
   * @param context
   * @returns {*}
   * @private
   */
  __executeGestureWithFilters: function (eventName, event, view, context) {

    var shouldFilter = isGesture(eventName) ? (view.get('gestureAllow') || view.get('gestureExclude')) : false,
      element, result;

    if (context) {

      element = shouldFilter ? view._filterTouchableElements.call(view, event.target) : false;
      result = (shouldFilter && !element) ? false : Ember.run(context, context[eventName], event, view);

    } else {

      element = shouldFilter ? view._filterTouchableElements.call(view, event.target) : false;
      result = (shouldFilter && !element) ? false : Ember.run.join(view, view.handleEvent, eventName, event);

    }

    //only stop propagation if result is explicitly false, not null or undefined
    if (result === false) {
      //hammer events have different semantics than normal events, so we must check before invoking
      if (event.stopPropagation) { event.stopPropagation(); }
      if (event.preventDefault) { event.preventDefault(); }
      if (event.preventDefaults) { event.preventDefaults(); }
    }

    return result;

  },

  /**
   *
   * Alters the normal _dispatchEvent to allow gesture filtering
   *
   * @param object
   * @param event
   * @param eventName
   * @param view
   * @returns {boolean}
   * @private
   */
  _dispatchEvent: function (object, event, eventName, view) {
    var result = true;

    var handler = object[eventName];
    if (Ember.typeOf(handler) === 'function') {
      result = this.__executeGestureWithFilters(eventName, event, view, object);
      // Do not preventDefault in eventManagers.
      event.stopPropagation();
    }
    else if (view) {
      result = this._bubbleEvent(view, event, eventName);
    }

    return result;
  },

  /**
   *
   * Alters the normal _bubbleEvent to allow gesture filtering
   *
   * @param view
   * @param event
   * @param eventName
   * @returns {*}
   * @private
   */
  _bubbleEvent: function (view, event, eventName) {
    return this.__executeGestureWithFilters(eventName, event, view);
  },

  /**!
   * Extend the normal destroy method to teardown the hammer manager
   * instance and remove the click buster.
   */
  destroy: function () {

    var hammer = this.get('_hammerInstance'),
      element = Ember.$(this.get('rootElement'))[0];

    //teardown Hammer
    if (hammer) { hammer.destroy(); }
    this.set('_hammerInstance', null);

    //teardown clickbuster
    PreventGhostClicks.remove(element);

    //run normal destroy
    this._super();
  }

});
<|endoftext|>


<commit_before>'use strict';

const Code = require('code');
const Lab = require('lab');
const EventEmitter = require('events').EventEmitter;
const testHelper = require('../helpers/testHelpers');

const lab = exports.lab = Lab.script();
const expect = Code.expect;
const Bpmn = require('../..');

lab.experiment('EndEvent', () => {

  lab.test('should have inbound sequence flows and flagged as end', (done) => {
    const processXml = `
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <process id="theProcess" isExecutable="true">
    <startEvent id="start" />
    <endEvent id="end" />
    <sequenceFlow id="flow1" sourceRef="start" targetRef="end" />
  </process>
</definitions>`;

    const engine = new Bpmn.Engine({
      source: processXml
    });
    engine.execute((err, definition) => {
      if (err) return done(err);
      const event = definition.getChildActivityById('end');
      expect(event).to.include('inbound');
      expect(event.inbound).to.have.length(1);
      expect(event.inbound).to.have.length(1);
      expect(event.isEnd).to.be.true();
      done();
    });
  });

  lab.experiment('terminateEventDefinition', () => {
    const processXml = `
<?xml version="1.0" encoding="UTF-8"?>
  <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <process id="theProcess" isExecutable="true">
    <startEvent id="theStart" />
    <endEvent id="fatal">
      <terminateEventDefinition />
    </endEvent>
    <endEvent id="theEnd1" />
    <endEvent id="theEnd2" />
    <endEvent id="theEnd3" />
    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fatal" />
    <sequenceFlow id="flow2" sourceRef="theStart" targetRef="theEnd1" />
    <sequenceFlow id="flow3" sourceRef="theStart" targetRef="theEnd2" />
    <sequenceFlow id="flow4" sourceRef="theStart" targetRef="theEnd3" />
  </process>
</definitions>`;

    let definition;
    lab.before((done) => {
      const engine = new Bpmn.Engine({
        source: processXml
      });
      engine.getDefinition((err, def) => {
        if (err) return done(err);
        definition = def;
        done();
      });
    });

    lab.test('should have inbound sequence flows', (done) => {
      const element = definition.getChildActivityById('fatal');
      expect(element).to.include('inbound');
      expect(element.inbound).to.have.length(1);
      done();
    });

    lab.test('and have property isTermation flag true', (done) => {
      const element = definition.getChildActivityById('fatal');
      expect(element.terminate).to.be.true();
      done();
    });

    lab.test('should terminate process', (done) => {
      const engine = new Bpmn.Engine({
        source: processXml
      });
      const listener = new EventEmitter();
      listener.once('end-theEnd1', (c) => {
        Code.fail(new Error(`${c.id} should have been terminated`));
      });

      engine.execute({
        listener: listener
      }, (err, instance) => {
        if (err) return done(err);

        instance.once('end', () => {
          expect(instance.isEnded).to.equal(true);
          expect(instance.getChildActivityById('fatal').taken, 'fatal').to.be.true();
          testHelper.expectNoLingeringListenersOnDefinition(instance);
          done();
        });
      });
    });
  });
});
<commit_msg>Make sure end event support io<commit_after>'use strict';

const Code = require('code');
const Lab = require('lab');
const EventEmitter = require('events').EventEmitter;
const testHelpers = require('../helpers/testHelpers');

const lab = exports.lab = Lab.script();
const expect = Code.expect;
const Bpmn = require('../..');

lab.experiment('EndEvent', () => {
  lab.describe('behaviour', () => {
    const processXml = `
<?xml version="1.0" encoding="UTF-8"?>
  <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:camunda="http://camunda.org/schema/1.0/bpmn">
  <process id="theProcess" isExecutable="true">
    <startEvent id="start" />
    <endEvent id="end">
      <extensionElements>
        <camunda:InputOutput>
          <camunda:inputParameter name="data">\${variables.statusCode}</camunda:inputParameter>
        </camunda:InputOutput>
      </extensionElements>
    </endEvent>
    <sequenceFlow id="flow1" sourceRef="start" targetRef="end" />
  </process>
</definitions>`;

    let context;
    lab.beforeEach((done) => {
      testHelpers.getContext(processXml, {
        camunda: require('camunda-bpmn-moddle/resources/camunda')
      }, (err, c) => {
        if (err) return done(err);
        context = c;
        done();
      });
    });

    lab.test('has pending inbound and marked as end', (done) => {
      const event = context.getChildActivityById('end');
      expect(event.inbound).to.have.length(1);
      expect(event.isEnd).to.be.true();
      done();
    });

    lab.test('supports io', (done) => {
      const event = context.getChildActivityById('end');
      expect(event.io).to.exist();
      done();
    });

    lab.test('getInput() returns io input', (done) => {
      const event = context.getChildActivityById('end');
      context.variables.statusCode = 200;
      expect(event.getInput()).to.equal({
        data: 200
      });

      done();
    });
  });

  lab.describe('engine behaviour', () => {
    lab.experiment('terminateEventDefinition', () => {
      const processXml = `
<?xml version="1.0" encoding="UTF-8"?>
  <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <process id="theProcess" isExecutable="true">
    <startEvent id="theStart" />
    <endEvent id="fatal">
      <terminateEventDefinition />
    </endEvent>
    <endEvent id="theEnd1" />
    <endEvent id="theEnd2" />
    <endEvent id="theEnd3" />
    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fatal" />
    <sequenceFlow id="flow2" sourceRef="theStart" targetRef="theEnd1" />
    <sequenceFlow id="flow3" sourceRef="theStart" targetRef="theEnd2" />
    <sequenceFlow id="flow4" sourceRef="theStart" targetRef="theEnd3" />
  </process>
</definitions>`;

      let definition;
      lab.before((done) => {
        const engine = new Bpmn.Engine({
          source: processXml
        });
        engine.getDefinition((err, def) => {
          if (err) return done(err);
          definition = def;
          done();
        });
      });

      lab.test('should have inbound sequence flows', (done) => {
        const element = definition.getChildActivityById('fatal');
        expect(element).to.include('inbound');
        expect(element.inbound).to.have.length(1);
        done();
      });

      lab.test('and have property isTermation flag true', (done) => {
        const element = definition.getChildActivityById('fatal');
        expect(element.terminate).to.be.true();
        done();
      });

      lab.test('should terminate process', (done) => {
        const engine = new Bpmn.Engine({
          source: processXml
        });
        const listener = new EventEmitter();
        listener.once('end-theEnd1', (c) => {
          Code.fail(new Error(`${c.id} should have been terminated`));
        });

        engine.execute({
          listener: listener
        }, (err, instance) => {
          if (err) return done(err);

          instance.once('end', () => {
            expect(instance.isEnded).to.equal(true);
            expect(instance.getChildActivityById('fatal').taken, 'fatal').to.be.true();
            testHelpers.expectNoLingeringListenersOnDefinition(instance);
            done();
          });
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/*eslint-env mocha*/
"use strict";
var eslint = require("eslint");

function verifyAndAssertMessages(code, rules, expectedMessages) {
  var messages = eslint.linter.verify(
    code,
    {
      parser: require.resolve(".."),
      rules: rules,
      env: {
        node: true
      }
    }
  );

  if (messages.length !== expectedMessages.length) {
    throw new Error("Expected " + expectedMessages.length + " message(s), got " + messages.length);
  }

  messages.forEach(function (message, i) {
    var formatedMessage = message.line + ":" + message.column + " " + message.message + (message.ruleId ? " " + message.ruleId : "");
    if (formatedMessage !== expectedMessages[i]) {
      throw new Error("Message " + i + " does not match:\nExpected: " + expectedMessages[i] + "\nActual:   " + formatedMessage);
    }
  });
}

describe("verify", function () {
  it("arrow function support (issue #1)", function () {
    verifyAndAssertMessages(
      "describe('stuff', () => {});",
      {},
      []
    );
  });

  it("EOL validation (issue #2)", function () {
    verifyAndAssertMessages(
      "module.exports = \"something\";",
      { "eol-last": 1, "semi": 1 },
      [ "1:1 Newline required at end of file but not found. eol-last" ]
    );
  });

  it("Readable error messages (issue #3)", function () {
    verifyAndAssertMessages(
      "{ , res }",
      {},
      [ "1:2 Unexpected token" ]
    );
  });

  it("Unused vars in JSX (issue #5)", function () {
    verifyAndAssertMessages(
      "var App = require('./App');\n" +
      "module.exports = <App />;",
      { "no-unused-vars": 1 },
      []
    );
  });

  it("Modules support (issue #5)", function () {
    verifyAndAssertMessages(
      "import Foo from 'foo';\n" +
      "export default Foo;",
      { },
      []
    );
  });

  it("Rest parameters (issue #7)", function () {
    verifyAndAssertMessages(
      "function foo(...args) { return args; }",
      { "no-undef": 1 },
      []
    );
  });

  it("Exported classes should be used (issue #8)", function () {
    verifyAndAssertMessages(
      "class Foo {} module.exports = Foo;",
      { "no-unused-vars": 1 },
      []
    );
  });

  it("super keyword in class (issue #10)", function () {
    verifyAndAssertMessages(
      "class Foo { constructor() { super() } }",
      { "no-undef": 1 },
      []
    );
  });

  it("Rest parameter in destructuring assignment (issue #11)", function () {
    verifyAndAssertMessages(
      "const [a, ...rest] = ['1', '2', '3']; module.exports = rest;",
      { "no-undef": 1 },
      []
    );
  });

  it("JSX attribute names marked as variables (issue #12)", function () {
    verifyAndAssertMessages(
      "module.exports =
",
      { "no-undef": 1 },
      []
    );
  });

  it("Variables in JSX should be used (issues #15, #17, #21, #29)", function () {
    verifyAndAssertMessages(
      "import App from './App'; export default (<App />);",
      { "no-unused-vars": 1, "no-undef": 1 },
      []
    );
  });

  it("Multiple destructured assignment with compound properties (issue #16)", function () {
    verifyAndAssertMessages(
      "module.exports = { ...a.a, ...a.b };",
      { "no-dupe-keys": 1 },
      []
    );
  });

  it("Arrow function with non-block bodies (issue #20)", function () {
    verifyAndAssertMessages(
      "\"use strict\"; () => 1",
      { "strict": 1 },
      []
    );
  });

  it("await keyword (issue #22)", function () {
    verifyAndAssertMessages(
      "async function foo() { await bar(); }",
      { "no-unused-expressions": 1 },
      []
    );
  });
});
<commit_msg>add messages to non regression test output<commit_after>/*eslint-env mocha*/
"use strict";
var eslint = require("eslint");

function verifyAndAssertMessages(code, rules, expectedMessages) {
  var messages = eslint.linter.verify(
    code,
    {
      parser: require.resolve(".."),
      rules: rules,
      env: {
        node: true
      }
    }
  );

  if (messages.length !== expectedMessages.length) {
    throw new Error("Expected " + expectedMessages.length + " message(s), got " + messages.length + " " + JSON.stringify(messages));
  }

  messages.forEach(function (message, i) {
    var formatedMessage = message.line + ":" + message.column + " " + message.message + (message.ruleId ? " " + message.ruleId : "");
    if (formatedMessage !== expectedMessages[i]) {
      throw new Error("Message " + i + " does not match:\nExpected: " + expectedMessages[i] + "\nActual:   " + formatedMessage);
    }
  });
}

describe("verify", function () {
  it("arrow function support (issue #1)", function () {
    verifyAndAssertMessages(
      "describe('stuff', () => {});",
      {},
      []
    );
  });

  it("EOL validation (issue #2)", function () {
    verifyAndAssertMessages(
      "module.exports = \"something\";",
      { "eol-last": 1, "semi": 1 },
      [ "1:1 Newline required at end of file but not found. eol-last" ]
    );
  });

  it("Readable error messages (issue #3)", function () {
    verifyAndAssertMessages(
      "{ , res }",
      {},
      [ "1:2 Unexpected token" ]
    );
  });

  it("Unused vars in JSX (issue #5)", function () {
    verifyAndAssertMessages(
      "var App = require('./App');\n" +
      "module.exports = <App />;",
      { "no-unused-vars": 1 },
      []
    );
  });

  it("Modules support (issue #5)", function () {
    verifyAndAssertMessages(
      "import Foo from 'foo';\n" +
      "export default Foo;",
      { },
      []
    );
  });

  it("Rest parameters (issue #7)", function () {
    verifyAndAssertMessages(
      "function foo(...args) { return args; }",
      { "no-undef": 1 },
      []
    );
  });

  it("Exported classes should be used (issue #8)", function () {
    verifyAndAssertMessages(
      "class Foo {} module.exports = Foo;",
      { "no-unused-vars": 1 },
      []
    );
  });

  it("super keyword in class (issue #10)", function () {
    verifyAndAssertMessages(
      "class Foo { constructor() { super() } }",
      { "no-undef": 1 },
      []
    );
  });

  it("Rest parameter in destructuring assignment (issue #11)", function () {
    verifyAndAssertMessages(
      "const [a, ...rest] = ['1', '2', '3']; module.exports = rest;",
      { "no-undef": 1 },
      []
    );
  });

  it("JSX attribute names marked as variables (issue #12)", function () {
    verifyAndAssertMessages(
      "module.exports =
",
      { "no-undef": 1 },
      []
    );
  });

  it("Variables in JSX should be used (issues #15, #17, #21, #29)", function () {
    verifyAndAssertMessages(
      "import App from './App'; export default (<App />);",
      { "no-unused-vars": 1, "no-undef": 1 },
      []
    );
  });

  it("Multiple destructured assignment with compound properties (issue #16)", function () {
    verifyAndAssertMessages(
      "module.exports = { ...a.a, ...a.b };",
      { "no-dupe-keys": 1 },
      []
    );
  });

  it("Arrow function with non-block bodies (issue #20)", function () {
    verifyAndAssertMessages(
      "\"use strict\"; () => 1",
      { "strict": 1 },
      []
    );
  });

  it("await keyword (issue #22)", function () {
    verifyAndAssertMessages(
      "async function foo() { await bar(); }",
      { "no-unused-expressions": 1 },
      []
    );
  });
});
<|endoftext|>


<commit_before>//This sets the variable for the spacebar.
var spaceKey;
var speed;

//This sets the score to start at -1.
var score = -1;

//This is the object which runs the game.
var mainState = {

	preload: function(){

		//These foure things sets the assets for the game. If you want to add music or images, there is where you would preload it.
		game.load.image('background', 'assets/background.png');
		game.load.image('Goblin', 'assets/Goblin1.png');
		game.load.image('ground', 'assets/wallHorizontal.png');
		game.load.image('obstacle', 'assets/wallVertical.png');
		//If you'd like to load music files, the format would look like this. game.load.audio('[name of music]', ['[location for music file]']);

	},

	create: function(){

		//This sets the game physics to Arcade style.
		game.physics.startSystem(Phaser.Physics.ARCADE);

		//This sets the background color to #3498db on the hex system.
		game.stage.backgroundColor = '#3498db';

		//This gives us sharp corners for all of our images.
		game.renderer.renderSession.roundPixels = true;

		//This would be a good place to start the general background music for the game.

		//This sets up a group call platforms. For future functionality we can set all horizontal surfaces to this group.
		platforms = game.add.group();
		platforms.enableBody = true;

		//This creates the ground, and makes it solid object the player will not pass through.
		this.ground = platforms.create(0, game.world.height, 'ground');
		this.ground.anchor.setTo(0,1);
		this.ground.scale.setTo(4, 1);
		game.physics.arcade.enable(this.ground);
		this.ground.body.immovable = true;

		//This creates the player character at the bottom left side of the screen.
		this.player = game.add.sprite(game.width/5, game.world.height*(2/7), 'Goblin');
		game.physics.arcade.enable(this.player);
		this.player.scale.setTo(0.15,0.15);
		this.player.anchor.setTo(0,0);

		//This sets the spacebar key as the input for this game.
		this.spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

		//This sets the physics on the player in terms of the gravity and the bounce.
		this.player.body.bounce.y = 0;
		this.player.body.gravity.y = 600;

		//This creates the first obstacle on the right side of the screen.
		this.obstacle = game.add.sprite(700,game.world.height, 'obstacle');
		this.obstacle.scale.setTo(1,0.2);
		this.obstacle.anchor.setTo(0,1);
		game.physics.arcade.enable(this.obstacle);
		this.obstacle.body.immovable = true;

		//This adds the scoreboard on the top left side of the screen.
		scoreText = game.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
	},

	update: function(){

		//This is where the game engine recognizes collision betwen the player and the ground or the obstacle.
		game.physics.arcade.collide(this.player, this.ground);
		game.physics.arcade.collide(this.player, this.obstacle);

		//This will set the horizontal movement to zero.
		this.player.body.velocity.x = 0;

		//This will create a new wall if the old wall goes off the screen.
		if (this.obstacle.x < 0) {
			this.obstacle.kill();
			speed = Math.floor(Math.random()* 0.3);
			console.log(speed);
			this.obstacle = game.add.sprite(900,game.world.height, 'obstacle');
			this.obstacle.scale.setTo(1,0.2);
			this.obstacle.anchor.setTo(0,1);
			game.physics.arcade.enable(this.obstacle);
			this.obstacle.body.immovable = true;
		};

		//This creates a place to add sound when the obstacle reaches the player.
		if (this.obstacle.x < 20 && this.obstacle.x > 15) {
			console.log("sound!");
			//This is where you'd add a sound que when the obstacle reaches the player.
		}

		//This will move the obstacle to the left if it is on the right side of the screen.
		if (this.obstacle.x > 100) {
			this.obstacle.x -= speed;

		};

		//This allows the player to jump only if you press the space key and the player is touching the something at the bottom.
		if (this.spaceKey.isDown && this.player.body.touching.down){
			this.player.body.velocity.y = -300;
			//This is a good place to add the sound for when the player jumps.
		};

		//This will update the score if the player has not been pushed off the screen, and the wall has gone off the left side.
		if (this.obstacle.x < 5 && this.player.x > 5){
			score++;
			scoreText.text = 'score: ' + score;
		};

		//This will tell you "You Lose!" if the player is pushed off the left side of the screen.
		if (this.player.x < 0){
			scoreText = game.add.text(350,200, 'Get Rekt!', {fill: '#ff0000'});
			this.obstacle.kill();
			this.player.kill();
		};
	}
};

//This sets the size of the game screen and sets it to the div "gameDiv".
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'gameDiv');

//This starts the game, by running the object "mainState".
game.state.add('main', mainState);
game.state.start('main');<commit_msg>change<commit_after>//This sets the variable for the spacebar.
var spaceKey;
var speed;

//This sets the score to start at -1.
var score = -1;

//This is the object which runs the game.
var mainState = {

	preload: function(){

		//These foure things sets the assets for the game. If you want to add music or images, there is where you would preload it.
		game.load.image('background', 'assets/background.png');
		game.load.image('Goblin', 'assets/Goblin1.png');
		game.load.image('ground', 'assets/wallHorizontal.png');
		game.load.image('obstacle', 'assets/wallVertical.png');
		//If you'd like to load music files, the format would look like this. game.load.audio('[name of music]', ['[location for music file]']);

	},

	create: function(){

		//This sets the game physics to Arcade style.
		game.physics.startSystem(Phaser.Physics.ARCADE);

		//This sets the background color to #3498db on the hex system.
		game.stage.backgroundColor = '#3498db';

		//This gives us sharp corners for all of our images.
		game.renderer.renderSession.roundPixels = true;

		//This would be a good place to start the general background music for the game.

		//This sets up a group call platforms. For future functionality we can set all horizontal surfaces to this group.
		platforms = game.add.group();
		platforms.enableBody = true;

		//This creates the ground, and makes it solid object the player will not pass through.
		this.ground = platforms.create(0, game.world.height, 'ground');
		this.ground.anchor.setTo(0,1);
		this.ground.scale.setTo(4, 1);
		game.physics.arcade.enable(this.ground);
		this.ground.body.immovable = true;

		//This creates the player character at the bottom left side of the screen.
		this.player = game.add.sprite(game.width/5, game.world.height*(2/7), 'Goblin');
		game.physics.arcade.enable(this.player);
		this.player.scale.setTo(0.15,0.15);
		this.player.anchor.setTo(0,0);

		//This sets the spacebar key as the input for this game.
		this.spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

		//This sets the physics on the player in terms of the gravity and the bounce.
		this.player.body.bounce.y = 0;
		this.player.body.gravity.y = 2000;

		//This creates the first obstacle on the right side of the screen.
		this.obstacle = game.add.sprite(700,game.world.height, 'obstacle');
		this.obstacle.scale.setTo(1,0.2);
		this.obstacle.anchor.setTo(0,1);
		game.physics.arcade.enable(this.obstacle);
		this.obstacle.body.immovable = true;

		//This adds the scoreboard on the top left side of the screen.
		scoreText = game.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
	},

	update: function(){

		//This is where the game engine recognizes collision betwen the player and the ground or the obstacle.
		game.physics.arcade.collide(this.player, this.ground);
		game.physics.arcade.collide(this.player, this.obstacle);

		//This will set the horizontal movement to zero.
		this.player.body.velocity.x = 0;

		//This will create a new wall if the old wall goes off the screen.
		if (this.obstacle.x < 0) {
			this.obstacle.kill();
			speed = Math.floor(Math.random()* 0.3);
			console.log(speed);
			this.obstacle = game.add.sprite(900,game.world.height, 'obstacle');
			this.obstacle.scale.setTo(1,0.2);
			this.obstacle.anchor.setTo(0,1);
			game.physics.arcade.enable(this.obstacle);
			this.obstacle.body.immovable = true;
		};

		//This creates a place to add sound when the obstacle reaches the player.
		if (this.obstacle.x < 20 && this.obstacle.x > 15) {
			console.log("sound!");
			//This is where you'd add a sound que when the obstacle reaches the player.
		}

		//This will move the obstacle to the left if it is on the right side of the screen.
		if (this.obstacle.x > 100) {
			this.obstacle.x -= speed;

		};

		//This allows the player to jump only if you press the space key and the player is touching the something at the bottom.
		if (this.spaceKey.isDown){
			this.player.body.velocity.y = -300;
			//This is a good place to add the sound for when the player jumps.
		};

		//This will update the score if the player has not been pushed off the screen, and the wall has gone off the left side.
		if (this.obstacle.x < 5 && this.player.x > 5){
			score++;
			scoreText.text = 'score: ' + score;
		};

		//This will tell you "You Lose!" if the player is pushed off the left side of the screen.
		if (this.player.x < 0){
			scoreText = game.add.text(350,200, 'Get Rekt!', {fill: '#ff0000'});
			this.obstacle.kill();
			this.player.kill();
		};
	}
};

//This sets the size of the game screen and sets it to the div "gameDiv".
var game = new Phaser.Game(800, 600, Phaser.AUTO, 'gameDiv');

//This starts the game, by running the object "mainState".
game.state.add('main', mainState);
game.state.start('main');<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides control sap.ui.core.HTML.
sap.ui.define(['jquery.sap.global', './Control', './RenderManager'],
	function(jQuery, Control, RenderManager) {
	"use strict";

	// local shortcut
	var RenderPrefixes = RenderManager.RenderPrefixes;

	/**
	 * Constructor for a new HTML.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Embeds standard HTML in a SAPUI5 control tree.
	 *
	 * Security Hint: By default, the HTML content (property 'content') is not sanitized and therefore
	 * open to XSS attacks. Applications that want to show user defined input in an HTML control, should
	 * either sanitize the content on their own or activate automatic sanitizing through the
	 * {@link #setSanitizeContent sanitizeContent} property.
	 *
	 * Although this control inherits the tooltip aggregation/property and the
	 * hasStyleClass, addStyleClass, removeStyleClass and
	 * toggleStyleClass methods from its base class, it doesn't support them.
	 * Instead, the defined HTML content can contain a tooltip (title attribute) or custom CSS classes.
	 *
	 * For further hints about usage restrictions for this control, see also the documentation of the
	 * content property.
	 *
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.core.HTML
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var HTML = Control.extend("sap.ui.core.HTML", /** @lends sap.ui.core.HTML.prototype */ { metadata : {

		library : "sap.ui.core",
		properties : {

			/**
			 * HTML content to be displayed, defined as a string.
			 *
			 * The content is converted to DOM nodes with a call to new jQuery(content), so any
			 * restrictions for the jQuery constructor apply to the content of the HTML control as well.
			 *
			 * Some of these restrictions (there might be others!) are:
			 *

			 *
the content must be enclosed in tags, pure text is not supported.

			 *
if the content contains script tags, they will be executed but they will not appear in the
			 *     resulting DOM tree. When the contained code tries to find the corresponding script tag,
			 *     it will fail.

			 *

			 *
			 * Please consider to consult the jQuery documentation as well.
			 *
			 * The HTML control currently doesn't prevent the usage of multiple root nodes in its DOM content
			 * (e.g. setContent("<div/><div/>")), but this is not a guaranteed feature.
			 * The accepted content might be restricted to single root nodes in future versions.
			 * To notify applications about this fact, a warning is written in the log when multiple root nodes are used.
			 *
			 * @SecSink {,XSS} The content of the 'content' property is rendered 1:1 to allow the full
			 * flexibility of HTML in UI5 applications. Applications therefore must ensure, that they don't
			 * set malicious content (e.g. derived from user input). UI5 does not provide an HTML validation
			 * function. jQuery.sap.encodeHTML will encode any HTML relevant character, but this is in
			 * nearly all cases not what applications want here.
			 */
			content : {type : "string", group : "Misc", defaultValue : null},

			/**
			 * Whether existing DOM content is preferred over the given content string.
			 *
			 * There are two scenarios where this flag is relevant (when set to true):
			 *

			 *
for the initial rendering: when an HTML control is added to an UIArea for the first time
			 *     and if the root node of that UIArea contained DOM content with the same id as the HTML
			 *     control, then that content will be used for rendering instead of any specified string
			 *     content

			 *
any follow-up rendering: when an HTML control is rendered for the second or any later
			 *     time and the preferDOM flag is set, then the DOM from the first rendering is preserved
			 *     and not replaced by the string content

			 *

			 *
			 * As preserving the existing DOM is the most common use case of the HTML control, the default value is true.
			 */
			preferDOM : {type : "boolean", group : "Misc", defaultValue : true},

			/**
			 * Whether to run the HTML sanitizer once the content (HTML markup) is applied or not.
			 *
			 * To configure allowed URLs please use the whitelist API via jQuery.sap.addUrlWhitelist.
			 */
			sanitizeContent : {type : "boolean", group : "Misc", defaultValue : false},

			/**
			 * Specifies whether the control is visible. Invisible controls are not rendered.
			 */
			visible : {type : "boolean", group : "Appearance", defaultValue : true}
		},
		events : {

			/**
			 * Fired after the HTML control has been rendered. Allows to manipulate the resulting DOM.
			 *
			 * When the control doesn't have string content and no preserved DOM existed for this control,
			 * then this event will fire, but there won't be a DOM node for this control.
			 */
			afterRendering : {
				parameters : {

					/**
					 * Whether the current DOM of the control has been preserved (true) or not (e.g.
					 * rendered from content property or it is an empty HTML control).
					 */
					isPreservedDOM : {type : "boolean"}
				}
			}
		}
	}});

	/**
	 * @param {string} [sSuffix=''] Suffix of the Element to be retrieved or empty
	 * @return {Element} The element's DOM reference or null
	 * @public
	 */
	HTML.prototype.getDomRef = function(sSuffix) {
		var sId = sSuffix ? this.getId() + "-" + sSuffix : this.getId();
		return jQuery.sap.domById(RenderPrefixes.Dummy + sId) || jQuery.sap.domById(sId);
	};

	HTML.prototype.setContent = function(sContent) {

		function parseHTML(s) {
			if ( jQuery.parseHTML ) {
				var a = jQuery.parseHTML(s);
				if ( a ) {
					var start = 0, end = a.length;
					while ( start < end && a[start].nodeType != 1 ) {
						start++;
					}
					while ( start < end && a[end - 1].nodeType != 1 ) {
						end--;
					}
					if ( start > 0 || end < a.length ) {
						a = a.slice(start, end);
					}
					return jQuery(a);
				}
			}
			return jQuery(s);
		}

		if ( this.getSanitizeContent() ) {
			jQuery.sap.log.trace("sanitizing HTML content for " + this);
			sContent = jQuery.sap._sanitizeHTML(sContent);
		}

		this.setProperty("content", sContent, true);
		if ( /* sContent && */ this.getDomRef() ) {
			var $newContent = parseHTML(this.getContent()); // TODO what if content is not HTML (e.g. #something)?
			jQuery(this.getDomRef()).replaceWith($newContent);
			this._postprocessNewContent($newContent);
		} else {
			this.invalidate();
		}
		return this;
	};

	HTML.prototype.setSanitizeContent = function(bSanitizeContent) {
		this.setProperty("sanitizeContent", bSanitizeContent, true);
		// if sanitizeContent has been enabled, set the content again to enable sanitizing on current content
		if (bSanitizeContent) {
			this.setContent(this.getContent());
		}
		return this;
	};

	HTML.prototype.onBeforeRendering = function() {
		if (this.getPreferDOM() && this.getDomRef() && !RenderManager.isPreservedContent(this.getDomRef())) {
			RenderManager.preserveContent(this.getDomRef(), /* bPreserveRoot */ true, /* bPreserveNodesWithId */ false);
		}
	};

	/**
	 * If the HTML doesn't contain own content, it tries to reproduce existing content
	 */
	HTML.prototype.onAfterRendering = function() {
		if (!this.getVisible()) {
			// Just leave the placeholder there
			return;
		}

		var $placeholder = jQuery(jQuery.sap.domById(RenderPrefixes.Dummy + this.getId()));
		var $oldContent = RenderManager.findPreservedContent(this.getId());
		var $newContent;
		var isPreservedDOM = false;
		if ( /*this.getContent() && */ (!this.getPreferDOM() || $oldContent.size() == 0) ) {
			// remove old, preserved content
			$oldContent.remove();
			// replace placeholder with content string
			$newContent = new jQuery(this.getContent()); // TODO what if content is not HTML (e.g. #something)?
			$placeholder.replaceWith($newContent);
		} else if ( $oldContent.size() > 0 ) {
			// replace dummy with old content
			$placeholder.replaceWith($oldContent);
			$newContent = $oldContent;
			isPreservedDOM = true;
		} else {
			$placeholder.remove();
		}

		this._postprocessNewContent($newContent);

		this.fireAfterRendering({isPreservedDOM : isPreservedDOM});

	};

	HTML.prototype._postprocessNewContent = function($newContent) {
		if ( $newContent && $newContent.size() > 0 ) {
			if ( $newContent.length > 1 ) {
				jQuery.sap.log.warning("[Unsupported Feature]: " + this + " has rendered " + $newContent.length + " root nodes!");
			} else {
				var sContentId = $newContent.attr("id");
				if (sContentId && sContentId != this.getId()) {
					jQuery.sap.log.warning("[Unsupported Feature]: Id of HTML Control '" + this.getId() + "' does not match with content id '" + sContentId + "'!");
				}
			}

			// set a marker that identifies all root nodes in $newContent as 'to-be-preserved'
			RenderManager.markPreservableContent($newContent, this.getId());
			// and if no node has the control id, search the first without an id and set it
			if ( $newContent.find("#" + this.getId().replace(/(:|\.)/g,'\\$1')).length === 0 ) {
				$newContent.filter(":not([id])").first().attr("id", this.getId());
			}
		} else {
			jQuery.sap.log.debug("" + this + " is empty after rendering, setting bOutput to false");
			this.bOutput = false; // clean up internal rendering bookkeeping
		}
	};

	/**
	 * Sets some new DOM content for this HTML control. The content will replace the existing content
	 * after the next rendering. Properties are not modified, but preferDOM should be set to true.
	 *
	 * @param {Element} oDom the new DOM content
	 * @return {sap.ui.core.HTML} this to facilitate method chaining
	 * @public
	 */
	HTML.prototype.setDOMContent = function(oDom) {
		var $newContent = jQuery(oDom);
		if ( this.getDomRef() ) {
			jQuery(this.getDomRef()).replaceWith($newContent);
			this._postprocessNewContent($newContent);
		} else {
			$newContent.appendTo(RenderManager.getPreserveAreaRef());
			if ( this.getUIArea() ) {
				this.getUIArea().invalidate();
			} // TODO fix issue with Control.rerender()
			this._postprocessNewContent($newContent); // CHECK is it okay to set bOutput to false for empty content?
		}

		return this;
	};

	HTML.prototype.setTooltip = function() {
		jQuery.sap.log.warning("The sap.ui.core.HTML control doesn't support tooltips. Add the tooltip to the HTML content instead.");
		return Control.prototype.setTooltip.apply(this, arguments);
	};

	jQuery.each("hasStyleClass addStyleClass removeStyleClass toggleStyleClass".split(" "), function(method) {
		HTML.prototype[method] = function() {
			jQuery.sap.log.warning("The sap.ui.core.HTML control doesn't support custom style classes. Manage custom CSS classes in the HTML content instead.");
			return Control.prototype[method].apply(this, arguments);
		};
	});

	return HTML;

});
<commit_msg>[INTERNAL] core/HTML: document content restriction<commit_after>/*!
 * ${copyright}
 */

// Provides control sap.ui.core.HTML.
sap.ui.define(['jquery.sap.global', './Control', './RenderManager'],
	function(jQuery, Control, RenderManager) {
	"use strict";

	// local shortcut
	var RenderPrefixes = RenderManager.RenderPrefixes;

	/**
	 * Constructor for a new HTML.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Embeds standard HTML in a SAPUI5 control tree.
	 *
	 * Security Hint: By default, the HTML content (property 'content') is not sanitized and therefore
	 * open to XSS attacks. Applications that want to show user defined input in an HTML control, should
	 * either sanitize the content on their own or activate automatic sanitizing through the
	 * {@link #setSanitizeContent sanitizeContent} property.
	 *
	 * Although this control inherits the tooltip aggregation/property and the
	 * hasStyleClass, addStyleClass, removeStyleClass and
	 * toggleStyleClass methods from its base class, it doesn't support them.
	 * Instead, the defined HTML content can contain a tooltip (title attribute) or custom CSS classes.
	 *
	 * For further hints about usage restrictions for this control, see also the documentation of the
	 * content property.
	 *
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.core.HTML
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var HTML = Control.extend("sap.ui.core.HTML", /** @lends sap.ui.core.HTML.prototype */ { metadata : {

		library : "sap.ui.core",
		properties : {

			/**
			 * HTML content to be displayed, defined as a string.
			 *
			 * The content is converted to DOM nodes with a call to new jQuery(content), so any
			 * restrictions for the jQuery constructor apply to the content of the HTML control as well.
			 *
			 * Some of these restrictions (there might be others!) are:
			 *

			 *
the content must be enclosed in tags, pure text is not supported.

			 *
if the content contains script tags, they will be executed but they will not appear in the
			 *     resulting DOM tree. When the contained code tries to find the corresponding script tag,
			 *     it will fail.

			 *

			 *
			 * Please consider to consult the jQuery documentation as well.
			 *
			 * The HTML control currently doesn't prevent the usage of multiple root nodes in its DOM content
			 * (e.g. setContent("<div/><div/>")), but this is not a guaranteed feature.
			 * The accepted content might be restricted to single root nodes in future versions.
			 * To notify applications about this fact, a warning is written in the log when multiple root nodes are used.
			 *
			 * When changing the content dynamically, ensure that the ID of the root node remains the same as the HTML
			 * control´s ID. Otherwise it cannot be guaranteed that certain lifecycle events take place.
			 *
			 * @SecSink {,XSS} The content of the 'content' property is rendered 1:1 to allow the full
			 * flexibility of HTML in UI5 applications. Applications therefore must ensure, that they don't
			 * set malicious content (e.g. derived from user input). UI5 does not provide an HTML validation
			 * function. jQuery.sap.encodeHTML will encode any HTML relevant character, but this is in
			 * nearly all cases not what applications want here.
			 */
			content : {type : "string", group : "Misc", defaultValue : null},

			/**
			 * Whether existing DOM content is preferred over the given content string.
			 *
			 * There are two scenarios where this flag is relevant (when set to true):
			 *

			 *
for the initial rendering: when an HTML control is added to an UIArea for the first time
			 *     and if the root node of that UIArea contained DOM content with the same id as the HTML
			 *     control, then that content will be used for rendering instead of any specified string
			 *     content

			 *
any follow-up rendering: when an HTML control is rendered for the second or any later
			 *     time and the preferDOM flag is set, then the DOM from the first rendering is preserved
			 *     and not replaced by the string content

			 *

			 *
			 * As preserving the existing DOM is the most common use case of the HTML control, the default value is true.
			 */
			preferDOM : {type : "boolean", group : "Misc", defaultValue : true},

			/**
			 * Whether to run the HTML sanitizer once the content (HTML markup) is applied or not.
			 *
			 * To configure allowed URLs please use the whitelist API via jQuery.sap.addUrlWhitelist.
			 */
			sanitizeContent : {type : "boolean", group : "Misc", defaultValue : false},

			/**
			 * Specifies whether the control is visible. Invisible controls are not rendered.
			 */
			visible : {type : "boolean", group : "Appearance", defaultValue : true}
		},
		events : {

			/**
			 * Fired after the HTML control has been rendered. Allows to manipulate the resulting DOM.
			 *
			 * When the control doesn't have string content and no preserved DOM existed for this control,
			 * then this event will fire, but there won't be a DOM node for this control.
			 */
			afterRendering : {
				parameters : {

					/**
					 * Whether the current DOM of the control has been preserved (true) or not (e.g.
					 * rendered from content property or it is an empty HTML control).
					 */
					isPreservedDOM : {type : "boolean"}
				}
			}
		}
	}});

	/**
	 * @param {string} [sSuffix=''] Suffix of the Element to be retrieved or empty
	 * @return {Element} The element's DOM reference or null
	 * @public
	 */
	HTML.prototype.getDomRef = function(sSuffix) {
		var sId = sSuffix ? this.getId() + "-" + sSuffix : this.getId();
		return jQuery.sap.domById(RenderPrefixes.Dummy + sId) || jQuery.sap.domById(sId);
	};

	HTML.prototype.setContent = function(sContent) {

		function parseHTML(s) {
			if ( jQuery.parseHTML ) {
				var a = jQuery.parseHTML(s);
				if ( a ) {
					var start = 0, end = a.length;
					while ( start < end && a[start].nodeType != 1 ) {
						start++;
					}
					while ( start < end && a[end - 1].nodeType != 1 ) {
						end--;
					}
					if ( start > 0 || end < a.length ) {
						a = a.slice(start, end);
					}
					return jQuery(a);
				}
			}
			return jQuery(s);
		}

		if ( this.getSanitizeContent() ) {
			jQuery.sap.log.trace("sanitizing HTML content for " + this);
			sContent = jQuery.sap._sanitizeHTML(sContent);
		}

		this.setProperty("content", sContent, true);
		if ( /* sContent && */ this.getDomRef() ) {
			var $newContent = parseHTML(this.getContent()); // TODO what if content is not HTML (e.g. #something)?
			jQuery(this.getDomRef()).replaceWith($newContent);
			this._postprocessNewContent($newContent);
		} else {
			this.invalidate();
		}
		return this;
	};

	HTML.prototype.setSanitizeContent = function(bSanitizeContent) {
		this.setProperty("sanitizeContent", bSanitizeContent, true);
		// if sanitizeContent has been enabled, set the content again to enable sanitizing on current content
		if (bSanitizeContent) {
			this.setContent(this.getContent());
		}
		return this;
	};

	HTML.prototype.onBeforeRendering = function() {
		if (this.getPreferDOM() && this.getDomRef() && !RenderManager.isPreservedContent(this.getDomRef())) {
			RenderManager.preserveContent(this.getDomRef(), /* bPreserveRoot */ true, /* bPreserveNodesWithId */ false);
		}
	};

	/**
	 * If the HTML doesn't contain own content, it tries to reproduce existing content
	 */
	HTML.prototype.onAfterRendering = function() {
		if (!this.getVisible()) {
			// Just leave the placeholder there
			return;
		}

		var $placeholder = jQuery(jQuery.sap.domById(RenderPrefixes.Dummy + this.getId()));
		var $oldContent = RenderManager.findPreservedContent(this.getId());
		var $newContent;
		var isPreservedDOM = false;
		if ( /*this.getContent() && */ (!this.getPreferDOM() || $oldContent.size() == 0) ) {
			// remove old, preserved content
			$oldContent.remove();
			// replace placeholder with content string
			$newContent = new jQuery(this.getContent()); // TODO what if content is not HTML (e.g. #something)?
			$placeholder.replaceWith($newContent);
		} else if ( $oldContent.size() > 0 ) {
			// replace dummy with old content
			$placeholder.replaceWith($oldContent);
			$newContent = $oldContent;
			isPreservedDOM = true;
		} else {
			$placeholder.remove();
		}

		this._postprocessNewContent($newContent);

		this.fireAfterRendering({isPreservedDOM : isPreservedDOM});

	};

	HTML.prototype._postprocessNewContent = function($newContent) {
		if ( $newContent && $newContent.size() > 0 ) {
			if ( $newContent.length > 1 ) {
				jQuery.sap.log.warning("[Unsupported Feature]: " + this + " has rendered " + $newContent.length + " root nodes!");
			} else {
				var sContentId = $newContent.attr("id");
				if (sContentId && sContentId != this.getId()) {
					jQuery.sap.log.warning("[Unsupported Feature]: Id of HTML Control '" + this.getId() + "' does not match with content id '" + sContentId + "'!");
				}
			}

			// set a marker that identifies all root nodes in $newContent as 'to-be-preserved'
			RenderManager.markPreservableContent($newContent, this.getId());
			// and if no node has the control id, search the first without an id and set it
			if ( $newContent.find("#" + this.getId().replace(/(:|\.)/g,'\\$1')).length === 0 ) {
				$newContent.filter(":not([id])").first().attr("id", this.getId());
			}
		} else {
			jQuery.sap.log.debug("" + this + " is empty after rendering, setting bOutput to false");
			this.bOutput = false; // clean up internal rendering bookkeeping
		}
	};

	/**
	 * Sets some new DOM content for this HTML control. The content will replace the existing content
	 * after the next rendering. Properties are not modified, but preferDOM should be set to true.
	 *
	 * @param {Element} oDom the new DOM content
	 * @return {sap.ui.core.HTML} this to facilitate method chaining
	 * @public
	 */
	HTML.prototype.setDOMContent = function(oDom) {
		var $newContent = jQuery(oDom);
		if ( this.getDomRef() ) {
			jQuery(this.getDomRef()).replaceWith($newContent);
			this._postprocessNewContent($newContent);
		} else {
			$newContent.appendTo(RenderManager.getPreserveAreaRef());
			if ( this.getUIArea() ) {
				this.getUIArea().invalidate();
			} // TODO fix issue with Control.rerender()
			this._postprocessNewContent($newContent); // CHECK is it okay to set bOutput to false for empty content?
		}

		return this;
	};

	HTML.prototype.setTooltip = function() {
		jQuery.sap.log.warning("The sap.ui.core.HTML control doesn't support tooltips. Add the tooltip to the HTML content instead.");
		return Control.prototype.setTooltip.apply(this, arguments);
	};

	jQuery.each("hasStyleClass addStyleClass removeStyleClass toggleStyleClass".split(" "), function(method) {
		HTML.prototype[method] = function() {
			jQuery.sap.log.warning("The sap.ui.core.HTML control doesn't support custom style classes. Manage custom CSS classes in the HTML content instead.");
			return Control.prototype[method].apply(this, arguments);
		};
	});

	return HTML;

});
<|endoftext|>


<commit_before>//Maximum frames of the video stream per second. The less frames the less network traffic.
//(the current server side webcam stream delivers 30 frames, so I limit the frames to 30)
var maximumVideoFramesPerSecond = 30;

var xhttpRequestTimeout = 2000;
var videoFrameTimeout = 1000.0 / maximumVideoFramesPerSecond;
var lastVideoFrameTime = new Date();

function GetVideoFrame() {

    lastVideoFrameTime = new Date();

    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://minwinpc/VideoFrame" + new Date().getTime().toString() + ".html", true);
    xhr.responseType = "blob";

    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status === 200) {
                var urlCreator = window.URL || window.webkitURL;
                var imageUrl = urlCreator.createObjectURL(xhr.response);
                document.querySelector("#videoFrame").src = imageUrl;
            }
        }
    }

    xhr.timeout = xhttpRequestTimeout;
    xhr.ontimeout = function () {
        GetVideoFrameAfterTimeout();
    }

    xhr.onerror = function () {
        GetVideoFrameAfterTimeout();
    }

    xhr.onload = function () {
        GetVideoFrameAfterTimeout();
    }

    xhr.send();
}

function GetVideoFrameAfterTimeout() {
    var lastVideoFrameTimeToLast = new Date() - lastVideoFrameTime;

    if (lastVideoFrameTimeToLast >= videoFrameTimeout) {
        setTimeout(function () { GetVideoFrame(); }, 0);

    } else {
        var nextVideoFrameTimeout = videoFrameTimeout - lastVideoFrameTimeToLast;
        setTimeout(function () { GetVideoFrame(); }, nextVideoFrameTimeout);
    }
}

GetVideoFrame();<commit_msg>Rename<commit_after>//Maximum frames of the video stream per second. The less frames the less network traffic.
//(the current server side webcam stream delivers 30 frames, so I limit the frames to 30)
var maximumVideoFramesPerSecond = 30;

var maximumVideoFramesPerSecondTimeout = 1000.0 / maximumVideoFramesPerSecond;
var getVideoFrameTimeout = 2000;
var lastVideoFrameTime = new Date();

function GetVideoFrame() {

    lastVideoFrameTime = new Date();

    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://minwinpc/VideoFrame" + new Date().getTime().toString() + ".html", true);
    xhr.responseType = "blob";

    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status === 200) {
                var urlCreator = window.URL || window.webkitURL;
                var imageUrl = urlCreator.createObjectURL(xhr.response);
                document.querySelector("#videoFrame").src = imageUrl;
            }
        }
    }

    xhr.timeout = getVideoFrameTimeout;
    xhr.ontimeout = function () {
        GetVideoFrameAfterTimeout();
    }

    xhr.onerror = function () {
        GetVideoFrameAfterTimeout();
    }

    xhr.onload = function () {
        GetVideoFrameAfterTimeout();
    }

    xhr.send();
}

function GetVideoFrameAfterTimeout() {
    var videoFrameTimeToLastFrame = new Date() - lastVideoFrameTime;

    if (videoFrameTimeToLastFrame >= maximumVideoFramesPerSecondTimeout) {
        setTimeout(function () { GetVideoFrame(); }, 0);

    } else {
        var nextVideoFrameTimeout = maximumVideoFramesPerSecondTimeout - videoFrameTimeToLastFrame;
        setTimeout(function () { GetVideoFrame(); }, nextVideoFrameTimeout);
    }
}

GetVideoFrame();<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

Menubar.File = function ( editor ) {

	var container = new UI.Panel();
	container.setClass( 'menu' );

	var title = new UI.Panel();
	title.setClass( 'title' );
	title.setTextContent( 'File' );
	container.add( title );

	var options = new UI.Panel();
	options.setClass( 'options' );
	container.add( options );

	// New

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'New' );
	option.onClick( function () {

		if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {

			editor.clear();

		}

	} );
	options.add( option );

	//

	options.add( new UI.HorizontalRule() );

	// Import

	var fileInput = document.createElement( 'input' );
	fileInput.type = 'file';
	fileInput.addEventListener( 'change', function ( event ) {

		editor.loader.loadFile( fileInput.files[ 0 ] );

	} );

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Import' );
	option.onClick( function () {

		fileInput.click();

	} );
	options.add( option );

	//

	options.add( new UI.HorizontalRule() );

	// Export Geometry

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export Geometry' );
	option.onClick( function () {

		var object = editor.selected;

		if ( object === null ) {

			alert( 'No object selected.' );
			return;

		}

		var geometry = object.geometry;

		if ( geometry === undefined ) {

			alert( 'The selected object doesn\'t have geometry.' );
			return;

		}

		var output = geometry.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		exportString( output );

	} );
	options.add( option );

	// Export Object

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export Object' );
	option.onClick( function () {

		var object = editor.selected;

		if ( object === null ) {

			alert( 'No object selected' );
			return;

		}

		var output = object.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		exportString( output );

	} );
	options.add( option );

	// Export Scene

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export Scene' );
	option.onClick( function () {

		var output = editor.scene.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		exportString( output );

	} );
	options.add( option );

	// Export OBJ

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export OBJ' );
	option.onClick( function () {

		var object = editor.selected;

		if ( object === null ) {

			alert( 'No object selected.' );
			return;

		}

		var exporter = new THREE.OBJExporter();

		exportString( exporter.parse( object ) );

	} );
	options.add( option );

	// Export STL

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export STL' );
	option.onClick( function () {

		var exporter = new THREE.STLExporter();

		exportString( exporter.parse( editor.scene ) );

	} );
	options.add( option );

	//

	options.add( new UI.HorizontalRule() );

	// Publish

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Publish' );
	option.onClick( function () {

		var camera = editor.camera;

		var zip = new JSZip();

		zip.file( 'index.html', [

			'<!DOCTYPE html>',
			'',
			'	',
			'		<title>three.js</title>',
			'		<meta charset="utf-8">',
			'		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">',
			'		',
			'	',
			'	',
			'		',
			'		',
			'		',
			'	',
			''

		].join( '\n' ) );

		//

		var output = editor.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		zip.file( 'app.json', output );

		//

		var manager = new THREE.LoadingManager( function () {

			location.href = 'data:application/zip;base64,' + zip.generate();

		} );

		var loader = new THREE.XHRLoader( manager );
		loader.load( 'js/libs/app.js', function ( content ) {

			zip.file( 'js/app.js', content );

		} );
		loader.load( '../build/three.min.js', function ( content ) {

			zip.file( 'js/three.min.js', content );

		} );

	} );
	options.add( option );

	/*
	// Test

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Test' );
	option.onClick( function () {

		var text = new UI.Text( 'blah' );
		editor.showDialog( text );

	} );
	options.add( option );
	*/

	//

	var exportString = function ( output ) {

		var blob = new Blob( [ output ], { type: 'text/plain' } );
		var objectURL = URL.createObjectURL( blob );

		window.open( objectURL, '_blank' );
		window.focus();

	};

	return container;

};
<commit_msg>User friendly file saving<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

Menubar.File = function ( editor ) {

	var container = new UI.Panel();
	container.setClass( 'menu' );

	var title = new UI.Panel();
	title.setClass( 'title' );
	title.setTextContent( 'File' );
	container.add( title );

	var options = new UI.Panel();
	options.setClass( 'options' );
	container.add( options );

	// New

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'New' );
	option.onClick( function () {

		if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {

			editor.clear();

		}

	} );
	options.add( option );

	//

	options.add( new UI.HorizontalRule() );

	// Import

	var fileInput = document.createElement( 'input' );
	fileInput.type = 'file';
	fileInput.addEventListener( 'change', function ( event ) {

		editor.loader.loadFile( fileInput.files[ 0 ] );

	} );

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Import' );
	option.onClick( function () {

		fileInput.click();

	} );
	options.add( option );

	//

	options.add( new UI.HorizontalRule() );

	// Export Geometry

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export Geometry' );
	option.onClick( function () {

		var object = editor.selected;

		if ( object === null ) {

			alert( 'No object selected.' );
			return;

		}

		var geometry = object.geometry;

		if ( geometry === undefined ) {

			alert( 'The selected object doesn\'t have geometry.' );
			return;

		}

		var output = geometry.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		exportString( output, "geometry.json" );

	} );
	options.add( option );

	// Export Object

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export Object' );
	option.onClick( function () {

		var object = editor.selected;

		if ( object === null ) {

			alert( 'No object selected' );
			return;

		}

		var output = object.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		exportString( output, "model.json" );

	} );
	options.add( option );

	// Export Scene

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export Scene' );
	option.onClick( function () {

		var output = editor.scene.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		exportString( output, "scene.json" );

	} );
	options.add( option );

	// Export OBJ

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export OBJ' );
	option.onClick( function () {

		var object = editor.selected;

		if ( object === null ) {

			alert( 'No object selected.' );
			return;

		}

		var exporter = new THREE.OBJExporter();

		exportString( exporter.parse( object ), "model.obj" );

	} );
	options.add( option );

	// Export STL

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Export STL' );
	option.onClick( function () {

		var exporter = new THREE.STLExporter();

		exportString( exporter.parse( editor.scene ), "model.stl" );

	} );
	options.add( option );

	//

	options.add( new UI.HorizontalRule() );

	// Publish

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Publish' );
	option.onClick( function () {

		var camera = editor.camera;

		var zip = new JSZip();

		zip.file( 'index.html', [

			'<!DOCTYPE html>',
			'',
			'	',
			'		<title>three.js</title>',
			'		<meta charset="utf-8">',
			'		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">',
			'		',
			'	',
			'	',
			'		',
			'		',
			'		',
			'	',
			''

		].join( '\n' ) );

		//

		var output = editor.toJSON();
		output = JSON.stringify( output, null, '\t' );
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

		zip.file( 'app.json', output );

		//

		var manager = new THREE.LoadingManager( function () {

			location.href = 'data:application/zip;base64,' + zip.generate();

		} );

		var loader = new THREE.XHRLoader( manager );
		loader.load( 'js/libs/app.js', function ( content ) {

			zip.file( 'js/app.js', content );

		} );
		loader.load( '../build/three.min.js', function ( content ) {

			zip.file( 'js/three.min.js', content );

		} );

	} );
	options.add( option );

	/*
	// Test

	var option = new UI.Panel();
	option.setClass( 'option' );
	option.setTextContent( 'Test' );
	option.onClick( function () {

		var text = new UI.Text( 'blah' );
		editor.showDialog( text );

	} );
	options.add( option );
	*/

	//

	var exportString = function ( output, filename ) {

		var blob = new Blob( [ output ], { type: 'text/plain' } );
		var objectURL = URL.createObjectURL( blob );

		var link = document.createElement('a');
		link.href = objectURL;
		link.download = filename || "data.json";
		link.target = "_blank";
		link.click();

	};

	return container;

};
<|endoftext|>


<commit_before>var utils = require('../utils')

module.exports = function ($provide, traceBuffer) {
  // Template Request Instrumentation
  $provide.decorator('$templateRequest', ['$delegate', '$injector', function ($delegate, $injector) {
    return utils.instrumentModule($delegate, $injector, {
      type: 'template.angular.request',
      prefix: '$templateRequest',
      signatureFormatter: function (key, args) {
        var text = ['$templateRequest', args[0]]
        return text.join(' ')
      }
    })
  }])
}
<commit_msg>Make instrumentation of templateRequest optional to gain Angular 1.2 support<commit_after>var utils = require('../utils')

module.exports = function ($provide, traceBuffer) {
  try {
    // Template Request Instrumentation
    $provide.decorator('$templateRequest', ['$delegate', '$injector', function ($delegate, $injector) {
      return utils.instrumentModule($delegate, $injector, {
        type: 'template.angular.request',
        prefix: '$templateRequest',
        signatureFormatter: function (key, args) {
          var text = ['$templateRequest', args[0]]
          return text.join(' ')
        }
      })
    }])
  } catch (e) {
  }
}
<|endoftext|>