<commit_before>/* eslint-disable no-underscore-dangle */

/**
 * Registers an event listener for the given events
 *
 * @param {HTMLElement|HTMLElement[]} element
 * @param {string|string[]} type
 * @param {function(*):*} handler
 */
export function on (element, type, handler)
{
    const list = Array.isArray(element) ? element : [element];
    const types = Array.isArray(type) ? type : [type];

    for (let i = 0; i < list.length; i++)
    {
        for (let j = 0; j < types.length; j++)
        {
            const node = list[i];
            const eventType = types[j];

            node.addEventListener(eventType, handler);

            if (typeof node._listeners === "undefined")
            {
                node._listeners = {};
            }

            if (typeof node._listeners[eventType] === "undefined")
            {
                node._listeners[eventType] = [];
            }

            node._listeners[eventType].push(handler);
        }
    }
}

/**
 * Removes an event listener for the given events
 *
 * @param {HTMLElement|HTMLElement[]} element
 * @param {string|string[]} type
 * @param {function(*):*} handler
 */
export function off (element, type, handler)
{
    const list = Array.isArray(element) ? element : [element];
    const types = Array.isArray(type) ? type : [type];

    for (let i = 0; i < list.length; i++)
    {
        for (let j = 0; j < types.length; j++)
        {
            const node = list[i];
            const eventType = types[j];

            node.removeEventListener(eventType, handler);

            if (typeof node._listeners !== "undefined" && typeof node._listeners[eventType] !== "undefined")
            {
                const index = node._listeners[eventType].indexOf(handler);

                if (-1 !== index)
                {
                    node._listeners[eventType].splice(index, 1);
                }
            }
        }
    }
}

/**
 * Registers an event listener, that it automatically is removed after it was executed once.
 *
 * Returns the intermediate function, so that the event listener can be removed:
 *
 *      const intermediate = once(element, event, handler);
 *      off(element, event, intermediate);
 *
 * @param {HTMLElement} element
 * @param {string} type
 * @param {function(*):*} handler
 * @return {function():*}
 */
export function once (element, type, handler)
{
    const intermediate = (...args) => {
        handler(...args);
        off(element, type, intermediate);
    };
    on(element, type, intermediate);

    return intermediate;
}
<commit_msg>Add support for space separated events<commit_after>/* eslint-disable no-underscore-dangle */

/**
 * Registers an event listener for the given events
 *
 * @param {HTMLElement|HTMLElement[]} element
 * @param {string|string[]} type
 * @param {function(*):*} handler
 */
export function on (element, type, handler)
{
    const list = Array.isArray(element) ? element : [element];
    const types = Array.isArray(type) ? type : type.trim().split(/ +/);

    for (let i = 0; i < list.length; i++)
    {
        for (let j = 0; j < types.length; j++)
        {
            const node = list[i];
            const eventType = types[j];

            node.addEventListener(eventType, handler);

            if (typeof node._listeners === "undefined")
            {
                node._listeners = {};
            }

            if (typeof node._listeners[eventType] === "undefined")
            {
                node._listeners[eventType] = [];
            }

            node._listeners[eventType].push(handler);
        }
    }
}

/**
 * Removes an event listener for the given events
 *
 * @param {HTMLElement|HTMLElement[]} element
 * @param {string|string[]} type
 * @param {function(*):*} handler
 */
export function off (element, type, handler)
{
    const list = Array.isArray(element) ? element : [element];
    const types = Array.isArray(type) ? type : type.trim().split(/ +/);

    for (let i = 0; i < list.length; i++)
    {
        for (let j = 0; j < types.length; j++)
        {
            const node = list[i];
            const eventType = types[j];

            node.removeEventListener(eventType, handler);

            if (typeof node._listeners !== "undefined" && typeof node._listeners[eventType] !== "undefined")
            {
                const index = node._listeners[eventType].indexOf(handler);

                if (-1 !== index)
                {
                    node._listeners[eventType].splice(index, 1);
                }
            }
        }
    }
}

/**
 * Registers an event listener, that it automatically is removed after it was executed once.
 *
 * Returns the intermediate function, so that the event listener can be removed:
 *
 *      const intermediate = once(element, event, handler);
 *      off(element, event, intermediate);
 *
 * @param {HTMLElement} element
 * @param {string} type
 * @param {function(*):*} handler
 * @return {function():*}
 */
export function once (element, type, handler)
{
    const intermediate = (...args) => {
        handler(...args);
        off(element, type, intermediate);
    };
    on(element, type, intermediate);

    return intermediate;
}
<|endoftext|>


<commit_before>'use strict'

var express = require('express')
var requireDir = require('require-dir')

var apiModules = requireDir('../api')
var search = require('../api/search/search')
var scrapeAndAddPage = require('../api/scrape/scrapeAndAddPage')
var appSettings = require('../../db/appSettings')
var requestDataValidation = require('../requestDataValidation')

var router = express.Router()

router.get('/', (req, res) => {
  res.render('searchPage',
      {
        title: 'MarkSearch',
        csrfToken: req.csrfToken(),
        markSearchSettings: JSON.stringify(
            {
              prebrowsing: appSettings.settings.prebrowsing,
              alwaysDisableTooltips: appSettings.settings.alwaysDisableTooltips
            }
        )
      }
  )
})

router.get('/about', (req, res) => {
  res.render('aboutPage',
      {
        title: 'MarkSearch About'
      }
  )
})

router.get('/help', (req, res) => {
  res.render('helpPage',
      {
        title: 'MarkSearch Help'
      }
  )
})

router.get('/settings', (req, res) => {
  res.render('settingsPage',
      {
        title: 'MarkSearch Settings',
        csrfToken: req.csrfToken(),
        markSearchSettings: JSON.stringify(
            {
              prebrowsing: appSettings.settings.prebrowsing,
              pagesDBFilePath: appSettings.settings.pagesDBFilePath,
              alwaysDisableTooltips: appSettings.settings.alwaysDisableTooltips,
              bookmarkExpiryEnabled: appSettings.settings.bookmarkExpiryEnabled,
              bookmarkExpiryEmail: appSettings.settings.bookmarkExpiryEmail,
              bookmarkExpiryMonths: appSettings.settings.bookmarkExpiryMonths,
              trayIconColor: appSettings.settings.trayIconColor
            }
        )
      }
  )
})

/****
 * We don't load the bookmarklet code directly on load as it includes the token.
 * The bookmarklet page js loads the boookmarklet code and token via the frontend api so
 * there is some security there (the csrf token).
 */
router.get('/bookmarklet', (req, res) => {
  res.render('bookmarkletPage',
      {
        title: 'MarkSearch Bookmarklet',
        csrfToken: req.csrfToken()
      }
  )
})

router.get('/removeOldBookmarks', (req, res) => {
  res.render('removeOldBookmarksPage',
    {
      title: 'MarkSearch - Remove Old Bookmarks',
      csrfToken: req.csrfToken()
    }
  )
})

/****
 * Doing it this way so dont have to bother with auth sessions to call the api from the frontend
 * (the api routes are protected by the JWT) and also so need csrf token to be able to call
 * the api from the frontend. (OWASP seems to recommend making them into POST so I guess do that)
 */
router.post('/frontendapi/getall/', requestDataValidation, apiModules.getAllPages)
router.post('/frontendapi/search/:searchTerms', requestDataValidation, search)
router.post('/frontendapi/scrapeAndAdd/:pageUrl', requestDataValidation, scrapeAndAddPage)
router.delete('/frontendapi/remove/:pageUrl', requestDataValidation, apiModules.deletePage)
router.post('/frontendapi/openUrlInBrowser/:urlToOpen', requestDataValidation, apiModules.openUrlInBrowser)
router.post('/frontendapi/getMostRecentlyExpiredBookmarks/', requestDataValidation, apiModules.getMostRecentlyExpiredBookmarks)
router.post('/frontendapi/settings/update/', requestDataValidation, apiModules.updateMarkSearchSettings)
router.post('/frontendapi/settings/changePagesDBlocation/', requestDataValidation, apiModules.changePagesDBlocation)
router.post('/frontendapi/settings/generateExtToken/', requestDataValidation, apiModules.generateExtToken)
router.post('/frontendapi/settings/emailBookmarklet/', requestDataValidation, apiModules.emailBookmarklet)
router.post('/frontendapi/settings/checkIfFileIsBinary/:filePath', requestDataValidation, apiModules.checkIfFileIsBinary)
router.post('/frontendapi/settings/revokeExtTokens/', requestDataValidation, apiModules.resetJWTsecret)

module.exports = router
<commit_msg>Comments index.js<commit_after>'use strict'

var express = require('express')
var requireDir = require('require-dir')

var apiModules = requireDir('../api')
var search = require('../api/search/search')
var scrapeAndAddPage = require('../api/scrape/scrapeAndAddPage')
var appSettings = require('../../db/appSettings')
var requestDataValidation = require('../requestDataValidation')

var router = express.Router()

router.get('/', (req, res) => {
  res.render('searchPage',
      {
        title: 'MarkSearch',
        csrfToken: req.csrfToken(),
        markSearchSettings: JSON.stringify(
            {
              prebrowsing: appSettings.settings.prebrowsing,
              alwaysDisableTooltips: appSettings.settings.alwaysDisableTooltips
            }
        )
      }
  )
})

router.get('/about', (req, res) => {
  res.render('aboutPage',
      {
        title: 'MarkSearch About'
      }
  )
})

router.get('/help', (req, res) => {
  res.render('helpPage',
      {
        title: 'MarkSearch Help'
      }
  )
})

router.get('/settings', (req, res) => {
  res.render('settingsPage',
      {
        title: 'MarkSearch Settings',
        csrfToken: req.csrfToken(),
        markSearchSettings: JSON.stringify(
            {
              prebrowsing: appSettings.settings.prebrowsing,
              pagesDBFilePath: appSettings.settings.pagesDBFilePath,
              alwaysDisableTooltips: appSettings.settings.alwaysDisableTooltips,
              bookmarkExpiryEnabled: appSettings.settings.bookmarkExpiryEnabled,
              bookmarkExpiryEmail: appSettings.settings.bookmarkExpiryEmail,
              bookmarkExpiryMonths: appSettings.settings.bookmarkExpiryMonths,
              trayIconColor: appSettings.settings.trayIconColor
            }
        )
      }
  )
})

/****
 * We don't load the bookmarklet code directly on load as it includes an api token.
 * The bookmarklet page js loads the boookmarklet code and token via the frontend api so
 * there is some security there (the csrf token).
 */
router.get('/bookmarklet', (req, res) => {
  res.render('bookmarkletPage',
      {
        title: 'MarkSearch Bookmarklet',
        csrfToken: req.csrfToken()
      }
  )
})

router.get('/removeOldBookmarks', (req, res) => {
  res.render('removeOldBookmarksPage',
    {
      title: 'MarkSearch - Remove Old Bookmarks',
      csrfToken: req.csrfToken()
    }
  )
})

/****
 * Doing it this way so dont have to bother with auth sessions to call the api from the frontend
 * (the api routes are protected by the JWT) and also so need csrf token to be able to call
 * the api from the frontend. (OWASP seems to recommend making them into POST so I guess do that)
 */
router.post('/frontendapi/getall/', requestDataValidation, apiModules.getAllPages)
router.post('/frontendapi/search/:searchTerms', requestDataValidation, search)
router.post('/frontendapi/scrapeAndAdd/:pageUrl', requestDataValidation, scrapeAndAddPage)
router.delete('/frontendapi/remove/:pageUrl', requestDataValidation, apiModules.deletePage)
router.post('/frontendapi/openUrlInBrowser/:urlToOpen', requestDataValidation, apiModules.openUrlInBrowser)
router.post('/frontendapi/getMostRecentlyExpiredBookmarks/', requestDataValidation, apiModules.getMostRecentlyExpiredBookmarks)
router.post('/frontendapi/settings/update/', requestDataValidation, apiModules.updateMarkSearchSettings)
router.post('/frontendapi/settings/changePagesDBlocation/', requestDataValidation, apiModules.changePagesDBlocation)
router.post('/frontendapi/settings/generateExtToken/', requestDataValidation, apiModules.generateExtToken)
router.post('/frontendapi/settings/emailBookmarklet/', requestDataValidation, apiModules.emailBookmarklet)
router.post('/frontendapi/settings/checkIfFileIsBinary/:filePath', requestDataValidation, apiModules.checkIfFileIsBinary)
router.post('/frontendapi/settings/revokeExtTokens/', requestDataValidation, apiModules.resetJWTsecret)

module.exports = router
<|endoftext|>


<commit_before>var React = require('react'),
    AppStore = require('../../stores/AppStore'),
    ObservationStore = require('../../stores/ObservationStore'),
    ObservationActions = require('../../actions/ObservationActions');

var ObservationCreate = React.createClass({
  getInitialState: function() {
    // Initially sets the text field of the observation form to blank
    // will be filed in the form
    return {
      userId: AppStore.getCurrentUser().id,
      username: AppStore.getCurrentUser().username,
      content: '',
      image: undefined
    };
  },

  componentDidMount: function() {
    // Clears default values after observation is created
    ObservationStore.addEventListener('create', this._onCreate);
  },

  componentWillUnmount: function() {
    // Clears eventlistener when dom node is deleted
    ObservationStore.removeEventListener('create', this._onCreate);
  },

  // asks for users inputs if they want to create an observation
  render: function() {
    return (

        <form className="observationCreateForm" onSubmit={this._save}>
          <input className="inputBox" type="text" name="content" placeholder="Your Observation" value={this.state.content} onChange={this._onChange} />

            <button><input type="file" id="take-picture" accept="image/*" ref="camera" onChange={this.handleFiles}/></button>

          <input className="inputBox" type="submit" value="Submit" />
        </form>

    );
  },

  handleFiles: function(e){
    var files = e.target.files,
        file;
    if (files && files.length > 0) {
        file = files[0];
    }
    var imgUrl = window.URL.createObjectURL(file);
    this.convert(file, imgUrl);
  },

  convert: function (blob, url) {
    var reader = new FileReader();

    reader.onloadend = function () {
      this.setState({
        image: reader.result,
        rawImage: reader.result
      })
    }.bind(this);

    reader.readAsDataURL(blob);
  },

  // Add new observation to the database
  // .target references the dom node of e
  _save: function(e) {
    e.preventDefault();
    var newObservation = {
      userId: this.state.userId,
      eventId: this.props.eventId,
      content: this.state.content,
      rawImage: this.state.rawImage
    };
    ObservationActions.create(newObservation);
  },

  // Update the current state with the new values in the input fields
  // every time the user types a letter
  // this updates the state values that were defined in getInitialState
  _onChange: function(e) {
    var obj = {};
    obj[e.target.name] = e.target.value;
    this.setState(obj);
  },

  // Event handler for 'create' observations coming from the ObservationStore
  // Clears the input field on the observation form
  _onCreate: function() {
    this.setState({
      content: '',
      image: undefined,
      rawImage: undefined
    });
  }
});

module.exports = ObservationCreate;
<commit_msg>input fields are cleared upon submission<commit_after>var React = require('react'),
    AppStore = require('../../stores/AppStore'),
    ObservationStore = require('../../stores/ObservationStore'),
    ObservationActions = require('../../actions/ObservationActions');

var ObservationCreate = React.createClass({
  getInitialState: function() {
    // Initially sets the text field of the observation form to blank
    // will be filed in the form
    return {
      userId: AppStore.getCurrentUser().id,
      username: AppStore.getCurrentUser().username,
      content: '',
      image: undefined
    };
  },

  componentDidMount: function() {
    // Clears default values after observation is created
    ObservationStore.addEventListener('create', this._onCreate);
  },

  componentWillUnmount: function() {
    // Clears eventlistener when dom node is deleted
    ObservationStore.removeEventListener('create', this._onCreate);
  },

  // asks for users inputs if they want to create an observation
  render: function() {
    return (

        <form className="observationCreateForm" onSubmit={this._save}>
          <input className="inputBox" type="text" name="content" placeholder="Your Observation" value={this.state.content} onChange={this._onChange} />

            <button><input type="file" id="take-picture" accept="image/*" ref="camera" onChange={this.handleFiles}/></button>

          <input className="inputBox" type="submit" value="Submit" />
        </form>

    );
  },

  handleFiles: function(e){
    var files = e.target.files,
        file;
    if (files && files.length > 0) {
        file = files[0];
    }
    var imgUrl = window.URL.createObjectURL(file);
    this.convert(file, imgUrl);
  },

  convert: function (blob, url) {
    var reader = new FileReader();

    reader.onloadend = function () {
      this.setState({
        image: reader.result,
        rawImage: reader.result
      })
    }.bind(this);

    reader.readAsDataURL(blob);
  },

  // Add new observation to the database
  // .target references the dom node of e
  _save: function(e) {
    e.preventDefault();
    var newObservation = {
      userId: this.state.userId,
      eventId: this.props.eventId,
      content: this.state.content,
      rawImage: this.state.rawImage
    };
    ObservationActions.create(newObservation);
    this._onCreate();
  },

  // Update the current state with the new values in the input fields
  // every time the user types a letter
  // this updates the state values that were defined in getInitialState
  _onChange: function(e) {
    var obj = {};
    obj[e.target.name] = e.target.value;
    this.setState(obj);
  },

  // Event handler for 'create' observations coming from the ObservationStore
  // Clears the input field on the observation form
  _onCreate: function() {
    this.setState({
      content: '',
      image: undefined,
      rawImage: undefined
    });
  }
});

module.exports = ObservationCreate;
<|endoftext|>


<commit_before>import Ember from 'ember';
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';
import App from '../../app';

const { RSVP } = Ember;
const SEPARATORS = /\/|\\/;

moduleForAcceptance('Acceptance | lazy routable engine', {
  beforeEach() {
    // Remove the ember-blog to fake it having "not loaded".
    this._engineModule = window.requirejs.entries['ember-blog/engine'];
    delete window.requirejs.entries['ember-blog/engine'];

    // We stub out the loader methods so that we can verify what they're doing.
    const module = this;
    this.loadEvents = [];
    this.application.instanceInitializer({
      name: 'stub-loader-methods',
      initialize(instance) {
        var loader = instance.lookup('service:asset-loader');

        loader.defineLoader('js', function(uri) {
          module.loadEvents.push(uri);

          // "Load" the engine module.
          if (uri.indexOf('engine.js') !== -1) {
            window.requirejs.entries['ember-blog/engine'] = module._engineModule;
          }

          return RSVP.resolve();
        });

        loader.defineLoader('css', function(uri) {
          module.loadEvents.push(uri);
          return RSVP.resolve();
        });
      }
    });
  },

  afterEach() {
    // Reset this initializer so subsequent tests don't blow up.
    delete App.instanceInitializers['stub-loader-methods'];

    window.requirejs.entries['ember-blog/engine'] = this._engineModule;
  }
});

function verifyInitialBlogRoute(assert, loadEvents, application) {
  assert.equal(loadEvents.length, 3, 'loaded 3 assets');
  assert.deepEqual(loadEvents[0].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine-vendor.css' ], 'loaded engine vendor css');
  assert.deepEqual(loadEvents[1].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine-vendor.js' ], 'loaded engine vendor js');
  assert.deepEqual(loadEvents[2].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine.js' ], 'loaded engine js');

  assert.equal(currentURL(), '/routable-engine-demo/blog/new');

  assert.equal(application.$('.routable-hello-world').text().trim(), 'Hello, world!');
  assert.equal(application.$('.hello-name').text().trim(), 'Hello, Jerry!', 'Re-rendered hello-name component correctly');
}

test('it should pause to load JS and CSS assets on deep link into a lazy Engine', function(assert) {
  assert.expect(7);

  visit('/routable-engine-demo/blog/new');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));
});

test('it should pause to load JS and CSS assets on an initial transition into a lazy Engine', function(assert) {
  assert.expect(7);

  visit('/routable-engine-demo');
  click('.blog-new:last');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));
});

test('it should not pause to load assets on subsequent transitions into a lazy Engine', function(assert) {
  assert.expect(10);

  visit('/routable-engine-demo/blog/new');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));

  click('.routeable-engine:last');
  andThen(() => {
    assert.equal(currentURL(), '/routable-engine-demo');
  });

  click('.blog-new');
  andThen(() => {
    assert.equal(this.loadEvents.length, 3, 'did not load additional assets');
    assert.equal(currentURL(), '/routable-engine-demo/blog/new');
  });
});

test('it should not pause to load assets on transition to a loaded, but not initialized instance of a lazy Engine (e.g., Engine mounted more than once)', function(assert) {
  assert.expect(10);

  visit('/routable-engine-demo/blog/new');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));

  click('.routeable-engine:last');
  andThen(() => {
    assert.equal(currentURL(), '/routable-engine-demo');
  });

  click('.ember-blog-new:last');
  andThen(() => {
    assert.equal(this.loadEvents.length, 3, 'did not load additional assets');
    assert.equal(currentURL(), '/routable-engine-demo/ember-blog/new');
  });
});

test('it should not pause to load assets on deep link into an eager Engine', function(assert) {
  assert.expect(2);

  visit('/routable-engine-demo/eager-blog');
  andThen(() => {
    assert.equal(this.loadEvents.length, 0, 'no load events occured');
    assert.equal(currentURL(), '/routable-engine-demo/eager-blog');
  });
});

test('it should not pause to load assets on transition into an eager Engine', function(assert) {
  assert.expect(2);

  visit('/routable-engine-demo');
  click('.eager-blog:last');
  andThen(() => {
    assert.equal(this.loadEvents.length, 0, 'no load events occured');
    assert.equal(currentURL(), '/routable-engine-demo/eager-blog');
  });
});
<commit_msg>Fix tests now that CSS assets are properly built.<commit_after>import Ember from 'ember';
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';
import App from '../../app';

const { RSVP } = Ember;
const SEPARATORS = /\/|\\/;

moduleForAcceptance('Acceptance | lazy routable engine', {
  beforeEach() {
    // Remove the ember-blog to fake it having "not loaded".
    this._engineModule = window.requirejs.entries['ember-blog/engine'];
    delete window.requirejs.entries['ember-blog/engine'];

    // We stub out the loader methods so that we can verify what they're doing.
    const module = this;
    this.loadEvents = [];
    this.application.instanceInitializer({
      name: 'stub-loader-methods',
      initialize(instance) {
        var loader = instance.lookup('service:asset-loader');

        loader.defineLoader('js', function(uri) {
          module.loadEvents.push(uri);

          // "Load" the engine module.
          if (uri.indexOf('engine.js') !== -1) {
            window.requirejs.entries['ember-blog/engine'] = module._engineModule;
          }

          return RSVP.resolve();
        });

        loader.defineLoader('css', function(uri) {
          module.loadEvents.push(uri);
          return RSVP.resolve();
        });
      }
    });
  },

  afterEach() {
    // Reset this initializer so subsequent tests don't blow up.
    delete App.instanceInitializers['stub-loader-methods'];

    window.requirejs.entries['ember-blog/engine'] = this._engineModule;
  }
});

function verifyInitialBlogRoute(assert, loadEvents, application) {
  assert.equal(loadEvents.length, 4, 'loaded 4 assets');
  assert.deepEqual(loadEvents[0].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine-vendor.css' ], 'loaded engine vendor css');
  assert.deepEqual(loadEvents[1].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine-vendor.js' ], 'loaded engine vendor js');
  assert.deepEqual(loadEvents[2].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine.css' ], 'loaded engine css');
  assert.deepEqual(loadEvents[3].split(SEPARATORS), [ '', 'engines-dist', 'ember-blog', 'assets', 'engine.js' ], 'loaded engine js');

  assert.equal(currentURL(), '/routable-engine-demo/blog/new');

  assert.equal(application.$('.routable-hello-world').text().trim(), 'Hello, world!');
  assert.equal(application.$('.hello-name').text().trim(), 'Hello, Jerry!', 'Re-rendered hello-name component correctly');
}

test('it should pause to load JS and CSS assets on deep link into a lazy Engine', function(assert) {
  assert.expect(8);

  visit('/routable-engine-demo/blog/new');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));
});

test('it should pause to load JS and CSS assets on an initial transition into a lazy Engine', function(assert) {
  assert.expect(8);

  visit('/routable-engine-demo');
  click('.blog-new:last');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));
});

test('it should not pause to load assets on subsequent transitions into a lazy Engine', function(assert) {
  assert.expect(11);

  visit('/routable-engine-demo/blog/new');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));

  click('.routeable-engine:last');
  andThen(() => {
    assert.equal(currentURL(), '/routable-engine-demo');
  });

  click('.blog-new');
  andThen(() => {
    assert.equal(this.loadEvents.length, 4, 'did not load additional assets');
    assert.equal(currentURL(), '/routable-engine-demo/blog/new');
  });
});

test('it should not pause to load assets on transition to a loaded, but not initialized instance of a lazy Engine (e.g., Engine mounted more than once)', function(assert) {
  assert.expect(11);

  visit('/routable-engine-demo/blog/new');
  andThen(() => verifyInitialBlogRoute(assert, this.loadEvents, this.application));

  click('.routeable-engine:last');
  andThen(() => {
    assert.equal(currentURL(), '/routable-engine-demo');
  });

  click('.ember-blog-new:last');
  andThen(() => {
    assert.equal(this.loadEvents.length, 4, 'did not load additional assets');
    assert.equal(currentURL(), '/routable-engine-demo/ember-blog/new');
  });
});

test('it should not pause to load assets on deep link into an eager Engine', function(assert) {
  assert.expect(2);

  visit('/routable-engine-demo/eager-blog');
  andThen(() => {
    assert.equal(this.loadEvents.length, 0, 'no load events occured');
    assert.equal(currentURL(), '/routable-engine-demo/eager-blog');
  });
});

test('it should not pause to load assets on transition into an eager Engine', function(assert) {
  assert.expect(2);

  visit('/routable-engine-demo');
  click('.eager-blog:last');
  andThen(() => {
    assert.equal(this.loadEvents.length, 0, 'no load events occured');
    assert.equal(currentURL(), '/routable-engine-demo/eager-blog');
  });
});
<|endoftext|>


<commit_before>// Copyright 2015-present 650 Industries. All rights reserved.

'use strict';

import { getManifestAsync, saveUrlToPathAsync, spawnAsyncThrowError, spawnAsync } from './tools-utils';
import {
  configureStandaloneIOSInfoPlistAsync,
  configureStandaloneIOSShellPlistAsync,
} from './ios-shell-app';

const EXPONENT_SRC_URL = 'https://github.com/exponentjs/exponent.git';
const EXPONENT_ARCHIVE_URL = 'https://api.github.com/repos/exponentjs/exponent/tarball/master';

function validateArgs(args) {
  if (!args.outputDirectory) {
    throw new Error(`Must specify --outputDirectory <path to create detached project>`);
  }
  if (!args.sdkVersion) {
    // TODO: maybe just default to newest?
    // we will need to figure out newest SDK version anyway to configure the kernel properly.
    throw new Error(`Must specify --sdkVersion <sdk version of project to detach>`);
  }
  if (!args.url) {
    throw new Error(`Must specify --url <url of project to detach>`);
  }
  return args;
}

function validateManifest(manifest) {
  if (!manifest.name) {
    throw new Error('Manifest is missing `name`');
  }
  return manifest;
}

/**
 *  Create a detached Exponent iOS app pointing at the given project.
 *  @param args.url url of the Exponent project.
 *  @param args.outputDirectory directory to create the detached project.
 */
export async function detachIOSAsync(args) {
  args = validateArgs(args);

  console.log('Validating output directory...');
  await spawnAsyncThrowError('/bin/mkdir', ['-p', args.outputDirectory]);

  console.log('Downloading and validating project manifest...');
  let manifest = await getManifestAsync(args.url, {
    'Exponent-SDK-Version': args.sdkVersion,
    'Exponent-Platform': 'ios',
  });
  manifest = validateManifest(manifest);

  console.log('Downloading Exponent kernel...');
  let tmpExponentDirectory = `${args.outputDirectory}/exponent-src-tmp`;
  // TODO: Make this method work
  // await spawnAsync(`/usr/bin/curl -L ${EXPONENT_ARCHIVE_URL} | tar xzf -`, null, { shell: true });
  await spawnAsyncThrowError('/usr/bin/git', ['clone', EXPONENT_SRC_URL, tmpExponentDirectory]);

  console.log('Moving project files...');
  let exponentDirectory = `${args.outputDirectory}/exponent`;
  let iosProjectDirectory = `${args.outputDirectory}/ios`;
  await spawnAsyncThrowError('/bin/mkdir', ['-p', exponentDirectory]);
  await spawnAsync('/bin/cp', ['-r', `${tmpExponentDirectory}/ios`, `${exponentDirectory}/ios`]);
  await spawnAsync('/bin/cp', ['-r', `${tmpExponentDirectory}/cpp`, `${exponentDirectory}/cpp`]);
  await spawnAsync('/bin/cp', [`${tmpExponentDirectory}/ExponentView.podspec`, `${exponentDirectory}/.`]);
  await spawnAsync('/bin/cp', ['-r', `${tmpExponentDirectory}/exponent-view-template/ios`, iosProjectDirectory]);

  console.log('Naming project...');
  let projectName = manifest.name;
  await spawnAsyncThrowError('sed', [
    '-i', `''`, '--',
    `s/exponent-view-template/${projectName}/g`,
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/project.pbxproj`,
  ]);
  await spawnAsyncThrowError('sed', [
    '-i', `''`,
    `s/exponent-view-template/${projectName}/g`,
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/xcshareddata/xcschemes/exponent-view-template.xcscheme`,
  ]);
  await spawnAsync('/bin/mv', [`${iosProjectDirectory}/exponent-view-template`, `${iosProjectDirectory}/${projectName}`]);
  await spawnAsync('/bin/mv', [
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/xcshareddata/xcschemes/exponent-view-template.xcscheme`,
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/xcshareddata/xcschemes/${projectName}.xcscheme`,
  ]);
  await spawnAsync('/bin/mv', [`${iosProjectDirectory}/exponent-view-template.xcodeproj`, `${iosProjectDirectory}/${projectName}.xcodeproj`]);
  await spawnAsync('/bin/mv', [`${iosProjectDirectory}/exponent-view-template.xcworkspace`, `${iosProjectDirectory}/${projectName}.xcworkspace`]);

  console.log('Configuring project...');
  let infoPlistPath = `${iosProjectDirectory}/${projectName}/Supporting`;
  await configureStandaloneIOSInfoPlistAsync(infoPlistPath, manifest);
  await configureStandaloneIOSShellPlistAsync(infoPlistPath, manifest, args.url);

  console.log('Cleaning up...');
  await spawnAsync('/bin/rm', ['-rf', tmpExponentDirectory]);

  /*
  TODO:
  - generate myproj/ios/Podfile
  --- ExponentView local pod
  --- ExponentCPP local pod
  --- React remote pod, on correct sdk branch or tag
  ----- postinstall
  --- versioned React local pod, if needed
  ----- postinstall
  - modify copied project template
  --- generate EXSDKVersions.plist
   */
  return;
}
<commit_msg>Generate detached EXSDKVersions.plist for exponent view projects<commit_after>// Copyright 2015-present 650 Industries. All rights reserved.

'use strict';

import {
  getManifestAsync,
  spawnAsyncThrowError,
  spawnAsync,
  modifyIOSPropertyListAsync,
  cleanIOSPropertyListBackupAsync,
} from './tools-utils';
import {
  configureStandaloneIOSInfoPlistAsync,
  configureStandaloneIOSShellPlistAsync,
} from './ios-shell-app';

const EXPONENT_SRC_URL = 'https://github.com/exponentjs/exponent.git';
const EXPONENT_ARCHIVE_URL = 'https://api.github.com/repos/exponentjs/exponent/tarball/master';

function validateArgs(args) {
  if (!args.outputDirectory) {
    throw new Error(`Must specify --outputDirectory <path to create detached project>`);
  }
  if (!args.sdkVersion) {
    // TODO: maybe just default to newest?
    // we will need to figure out newest SDK version anyway to configure the kernel properly.
    throw new Error(`Must specify --sdkVersion <sdk version of project to detach>`);
  }
  if (!args.url) {
    throw new Error(`Must specify --url <url of project to detach>`);
  }
  return args;
}

function validateManifest(manifest) {
  if (!manifest.name) {
    throw new Error('Manifest is missing `name`');
  }
  return manifest;
}

async function configureDetachedVersionsPlistAsync(configFilePath, detachedSDKVersion, kernelSDKVersion) {
  await modifyIOSPropertyListAsync(configFilePath, 'EXSDKVersions', (versionConfig) => {
    versionConfig.sdkVersions = [detachedSDKVersion];
    versionConfig.detachedNativeVersions = {
      shell: detachedSDKVersion,
      kernel: kernelSDKVersion,
    };
    return versionConfig;
  });
}

async function cleanPropertyListBackupsAsync(configFilePath) {
  console.log('Cleaning up...');
  await cleanIOSPropertyListBackupAsync(configFilePath, 'EXShell', false);
  await cleanIOSPropertyListBackupAsync(configFilePath, 'Info', false);
  await cleanIOSPropertyListBackupAsync(configFilePath, 'EXSDKVersions', false);
}

/**
 *  Create a detached Exponent iOS app pointing at the given project.
 *  @param args.url url of the Exponent project.
 *  @param args.outputDirectory directory to create the detached project.
 */
export async function detachIOSAsync(args) {
  args = validateArgs(args);

  console.log('Validating output directory...');
  await spawnAsyncThrowError('/bin/mkdir', ['-p', args.outputDirectory]);

  console.log('Downloading and validating project manifest...');
  let manifest = await getManifestAsync(args.url, {
    'Exponent-SDK-Version': args.sdkVersion,
    'Exponent-Platform': 'ios',
  });
  manifest = validateManifest(manifest);

  console.log('Downloading Exponent kernel...');
  let tmpExponentDirectory = `${args.outputDirectory}/exponent-src-tmp`;
  // TODO: Make this method work
  // await spawnAsync(`/usr/bin/curl -L ${EXPONENT_ARCHIVE_URL} | tar xzf -`, null, { shell: true });
  await spawnAsyncThrowError('/usr/bin/git', ['clone', EXPONENT_SRC_URL, tmpExponentDirectory]);

  console.log('Moving project files...');
  let exponentDirectory = `${args.outputDirectory}/exponent`;
  let iosProjectDirectory = `${args.outputDirectory}/ios`;
  await spawnAsyncThrowError('/bin/mkdir', ['-p', exponentDirectory]);
  await spawnAsync('/bin/cp', ['-r', `${tmpExponentDirectory}/ios`, `${exponentDirectory}/ios`]);
  await spawnAsync('/bin/cp', ['-r', `${tmpExponentDirectory}/cpp`, `${exponentDirectory}/cpp`]);
  await spawnAsync('/bin/cp', [`${tmpExponentDirectory}/ExponentView.podspec`, `${exponentDirectory}/.`]);
  await spawnAsync('/bin/cp', ['-r', `${tmpExponentDirectory}/exponent-view-template/ios`, iosProjectDirectory]);

  console.log('Naming project...');
  let projectName = manifest.name;
  await spawnAsyncThrowError('sed', [
    '-i', `''`, '--',
    `s/exponent-view-template/${projectName}/g`,
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/project.pbxproj`,
  ]);
  await spawnAsyncThrowError('sed', [
    '-i', `''`,
    `s/exponent-view-template/${projectName}/g`,
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/xcshareddata/xcschemes/exponent-view-template.xcscheme`,
  ]);
  await spawnAsync('/bin/mv', [`${iosProjectDirectory}/exponent-view-template`, `${iosProjectDirectory}/${projectName}`]);
  await spawnAsync('/bin/mv', [
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/xcshareddata/xcschemes/exponent-view-template.xcscheme`,
    `${iosProjectDirectory}/exponent-view-template.xcodeproj/xcshareddata/xcschemes/${projectName}.xcscheme`,
  ]);
  await spawnAsync('/bin/mv', [`${iosProjectDirectory}/exponent-view-template.xcodeproj`, `${iosProjectDirectory}/${projectName}.xcodeproj`]);
  await spawnAsync('/bin/mv', [`${iosProjectDirectory}/exponent-view-template.xcworkspace`, `${iosProjectDirectory}/${projectName}.xcworkspace`]);

  console.log('Configuring project...');
  let infoPlistPath = `${iosProjectDirectory}/${projectName}/Supporting`;
  await configureStandaloneIOSInfoPlistAsync(infoPlistPath, manifest);
  await configureStandaloneIOSShellPlistAsync(infoPlistPath, manifest, args.url);
  // TODO: logic for when kernel sdk version is different from detached sdk version
  await configureDetachedVersionsPlistAsync(infoPlistPath, args.sdkVersion, args.sdkVersion);

  console.log('Cleaning up...');
  await cleanPropertyListBackupsAsync(infoPlistPath);
  await spawnAsync('/bin/rm', ['-rf', tmpExponentDirectory]);

  /*
  TODO:
  - generate myproj/ios/Podfile
  --- ExponentView local pod
  --- ExponentCPP local pod
  --- React remote pod, on correct sdk branch or tag
  ----- postinstall
  --- versioned React local pod, if needed
  ----- postinstall
  - modify copied project template
  --- icons etc. same stuff as shell app
   */
  return;
}
<|endoftext|>


<commit_before>define(
	[
		"./meta",
		"./type",
		"./extends",
		"./method",
		"./overload"
	],
	function (meta, type) {

		meta({
			"entity": "module",
			"export": "Class",
			"description": "System for building classes"
		});

		meta({
			"entity": "function",
			"name": "Class",
			"description": "Creates a new class",
			"arguments": [{
				"name": "init",
				"type": "function",
				"description": "This function is called from within the constructor. Use it to initialize new instances. The value of this within init will be the new instance.",
				"required": false
			}],
			"return": {
				"type": "function",
				"description": "Class constructor. Use this constructor other class setup tasks such as creating methods and setting up inheritance. Instance are created when is function is invoked with or without the new operator."
			}
		});

		meta({
			"arguments": [{
				"name": "options",
				"type": "object",
				"description": "Class options.",
				"required": false
			}],
			"return": {
				"type": "function",
				"description": "Class constructor. Use this constructor other class setup tasks such as creating methods and setting up inheritance. Instance are created when is function is invoked with or without the new operator."
			}
		});

		function Class (options) {
			var forcingNew = false,
				name = options.name || options.init.name;

			if (name) {
				Constructor = Constructor.toString().replace(/Constructor/g, name);
				eval("Constructor = "+ Constructor +";");
			}

			if (options.extends) {
				Constructor.extends(options.extends);
			}

			function Constructor () {
				var instance = this;

				if (notAnInstance(instance)) {
					forcingNew = true;
					instance = new Constructor();
					forcingNew = false;
				}

				if (shouldInvokeInit()) {
					options.init.apply(instance, arguments);
				}

				function notAnInstance(instance) {
					return (instance instanceof Constructor) === false;
				}

				return instance;
			}

			function shouldInvokeInit () {
				return !forcingNew && type.is("function", options.init);
			}

			return Constructor;
		}

		Class = Class.overload("function?", ClassNoOptions);

		function ClassNoOptions (init) {
			return Class({
				init: init
			});
		}

		return Class;
	}
);
<commit_msg>changing signature of Class to (object, function) or (function). init can't be part of options because meta must be valid json and can't include functions.<commit_after>define(
	[
		"./meta",
		"./type",
		"./extends",
		"./method",
		"./overload"
	],
	function (meta, type) {

		meta({
			"entity": "module",
			"export": "Class",
			"description": "System for building classes"
		});

		meta({
			"entity": "function",
			"name": "Class",
			"description": "Creates a new class",
			"arguments": [{
				"name": "init",
				"type": "function",
				"description": "This function is called from within the constructor. Use it to initialize new instances. The value of this within init will be the new instance.",
				"required": false
			}],
			"return": {
				"type": "function",
				"description": "Class constructor. Use this constructor other class setup tasks such as creating methods and setting up inheritance. Instance are created when is function is invoked with or without the new operator."
			}
		});

		meta({
			"arguments": [{
				"name": "options",
				"type": "object",
				"description": "Class options.",
				"required": false
			}],
			"return": {
				"type": "function",
				"description": "Class constructor. Use this constructor other class setup tasks such as creating methods and setting up inheritance. Instance are created when is function is invoked with or without the new operator."
			}
		});

		function Class (options, init) {
			var forcingNew = false,
				name = options.name || init.name;

			if (name) {
				Constructor = Constructor.toString().replace(/Constructor/g, name);
				eval("Constructor = "+ Constructor +";");
			}

			if (options.extends) {
				Constructor.extends(options.extends);
			}

			function Constructor () {
				var instance = this;

				if (notAnInstance(instance)) {
					forcingNew = true;
					instance = new Constructor();
					forcingNew = false;
				}

				if (shouldInvokeInit()) {
					init.apply(instance, arguments);
				}

				function notAnInstance(instance) {
					return (instance instanceof Constructor) === false;
				}

				return instance;
			}

			function shouldInvokeInit () {
				return !forcingNew && type.is("function", init);
			}

			return Constructor;
		}

		Class = Class.overload("function?", ClassNoOptions);

		function ClassNoOptions (init) {
			return Class({}, init);
		}

		return Class;
	}
);
<|endoftext|>


<commit_before>jQuery.entwine("workflow", function($) {
	$(".workflow-field").entwine({
		Loading: null,
		Dialog:  null,
		onmatch: function() {
			var self = this;

			this.setLoading(this.find(".workflow-field-loading"));
			this.setDialog(this.find(".workflow-field-dialog"));

			this.getDialog().data("workflow-field", this).dialog({
				autoOpen: false,
				width:    800,
				height:   600,
				modal:    true
			});

			this.getDialog().on("click", "button", function() {
				$(this).addClass("loading ui-state-disabled");
			});

			this.getDialog().on("submit", "form", function() {
				$(this).ajaxSubmit(function(response) {
					if($(response).is(".workflow-field")) {
						self.getDialog().empty().dialog("close");
						self.replaceWith(response);
					} else {
						self.getDialog().html(response);
					}
				});

				return false;
			});
		},
		showDialog: function(url) {
			var dlg = this.getDialog();

			dlg.empty().dialog("open");
			dlg.parent().addClass("loading");

			$.get(url).done(function(body) {
				dlg.html(body).parent().removeClass("loading");
			});
		},
		loading: function(toggle) {
			this.getLoading().toggle(typeof(toggle) == "undefined" || toggle);
		}
	});

	function helper() {
		return $("
").addClass("ui-state-highlight").appendTo("body");
	}

	$(".workflow-field .workflow-field-actions").entwine({
		onmatch: function() {
			$(".workflow-field .workflow-field-action-disabled").on('click',function() {
				return false;
			});
			this.sortable({
				axis:        "y",
				containment: this,
				placeholder: "ui-state-highlight workflow-placeholder",
				handle:      ".workflow-field-action-drag",
				tolerance:   "pointer",
				update: function() {
					var actions = $(this).find(".workflow-field-action");
					var field   = $(this).closest(".workflow-field");
					var link    = field.data("sort-link");
					var ids     = actions.map(function() { return $(this).data("id"); });

					var data = {
						"id[]":  ids.get(),
						"class": "WorkflowAction",
						"SecurityID": field.data("securityid")
					};

					field.loading();
					$.post(link, data).done(function() { field.loading(false); });
				}
			});
		}
	});

	$(".workflow-field .workflow-field-action-transitions").entwine({
		onmatch: function() {
			this.sortable({
				axis:        "y",
				containment: this,
				handle:      ".workflow-field-action-drag",
				tolerance:   "pointer",
				update: function() {
					var trans = $(this).find("li");
					var field = $(this).closest(".workflow-field");
					var link  = field.data("sort-link");
					var ids   = trans.map(function() { return $(this).data("id"); });

					var data = {
						"id[]":   ids.get(),
						"class":  "WorkflowTransition",
						"parent": $(this).closest(".workflow-field-action").data("id"),
						"SecurityID": field.data("securityid")
					};

					field.loading();
					$.post(link, data).done(function() { field.loading(false); });
				}
			});
		}
	});

	$(".workflow-field .workflow-field-create-class").entwine({
		onmatch: function() {
			this.chosen().addClass("has-chnz");
		},
		onchange: function() {
			this.siblings(".workflow-field-do-create").toggleClass("ui-state-disabled", !this.val());
		}
	});

	$(".workflow-field .workflow-field-do-create").entwine({
		onclick: function() {
			var sel   = this.siblings(".workflow-field-create-class");
			var field = this.closest(".workflow-field");

			if(sel.val()) {
				field.showDialog(sel.val());
			}

			return false;
		}
	});

	$(".workflow-field .workflow-field-open-dialog").entwine({
		onclick: function() {
			this.closest(".workflow-field").showDialog(this.prop("href"));
			return false;
		}
	});

	$(".workflow-field .workflow-field-delete").entwine({
		onclick: function() {
			if(confirm(ss.i18n._t('Workflow.DeleteQuestion'))) {
				var data = {
					"SecurityID" : this.data("securityid")
				};
				$.post(this.prop('href'), data).done(function(body) {
					$(".workflow-field").replaceWith(body);
				});
			}

			return false;
		}
	});

	/*
	 * Simple implementation of the jQuery-UI timepicker widget
	 * @see: http://trentrichardson.com/examples/timepicker/ for more config options
	 *
	 * This will need some more work when it comes to implementing i18n functionality. Fortunately, the library handles these as option-settings quite well.
	 */
	$("#Root_PublishingSchedule").entwine({
		onclick: function() {
			if(typeof $.fn.timepicker() !== 'object' || !$('input.hasTimePicker').length >0) {
				return false;
			}
			var field = $('input.hasTimePicker');
			var defaultTime = function() {
				var date = new Date();
				return date.getHours()+':'+date.getMinutes();
			}
			var pickerOpts = {
				useLocalTimezone: true,
				defaultValue: defaultTime,
				controlType: 'select',
				timeFormat: 'HH:mm'
			};
			field.timepicker(pickerOpts);
			return false;
		},
		onmatch: function(){
			var self = this,
				publishDate = this.find('#PublishOnDate input.date'),
				publishTime = this.find('#PublishOnDate input.time'),
				parent = this.find('#PublishOnDate');

			if(!$('#Form_EditForm_action_publish').attr('disabled')){
				self.checkEmbargo($(publishDate).val(), $(publishTime).val(), parent);

				publishDate.change(function(){
					self.checkEmbargo($(publishDate).val(),$(publishTime).val(), parent);
				});

				publishTime.change(function(){
					self.checkEmbargo($(publishDate).val(), $(publishTime).val(), parent);
				});
			}

			this._super();
		},
		/*
		 * Helper function opens publishing schedule tab when link clicked
		 */
		linkScheduled: function(parent){
			$('#workflow-schedule').click(function(){
				var tabID = parent.closest('.ui-tabs-panel.tab').attr('id');
				$('#tab-'+tabID).trigger('click');
				return false;
			});
		},
		/*
		 * Checks whether an embargo is present.
		 * If an embargo is present, display an altered actions panel,
		 * with a message notifying the user
		 */
		checkEmbargo: function(publishDate, publishTime, parent){

			// Something has changed, remove any existing embargo message
			$('.Actions #embargo-message').remove();

			/*
			 * Fuzzy checking:
			 * There may not be $(#PublishOnXXX input.date) DOM objects = undefined.
			 * There may be $(#PublishOnXXX input.date) DOM objects = val() method may return zero-length.
			 */
			var noPublishDate = (publishDate === undefined || publishDate.length == 0);
			var noPublishTime = (publishTime === undefined || publishTime.length == 0);

			if(noPublishDate && noPublishTime){
				//No Embargo, remove customizations
				$('#Form_EditForm_action_publish').removeClass('embargo');
				$('#Form_EditForm_action_publish').prev('button').removeClass('ui-corner-right');
			} else {

				var link,
					message;

				$('#Form_EditForm_action_publish').addClass('embargo');
				$('#Form_EditForm_action_publish').prev('button').addClass('ui-corner-right');

				if(publishDate === ''){
					//Has time, not date
					message = ss.i18n.sprintf(
						ss.i18n._t('Workflow.EMBARGOMESSAGETIME'),
						publishTime
					);

				}else if(publishTime === ''){
					//has date no time
					message = ss.i18n.sprintf(
						ss.i18n._t('Workflow.EMBARGOMESSAGEDATE'),
						publishDate
					);
				}else{
					//has date and time
					message = ss.i18n.sprintf(
						ss.i18n._t('Workflow.EMBARGOMESSAGEDATETIME'),
						publishDate,
						publishTime
					);
				}

				message = message.replace('','');

				//Append message with link
				$('.Actions #ActionMenus').after('
' + message + '
');

				//Active link
				this.linkScheduled(parent);
			}

			return false;
		}
	});
});

jQuery.entwine("ss", function($) {

	// Hide the uneccesary "Show Specification..." link included on ImportForms by default
	$('.importSpec').entwine({
		onmatch: function() {
			this.hide();
		}
	});

	// Remove the somehat hard-coded 'CSV' string from error message
	$('#Form_ImportForm_error').entwine({
		onmatch: function() {
			var ele = this;
			ele.html(ele.html().replace('CSV', ''));
		}
	});

	/**
	 * Prevents actions from causing an ajax reload of the field.
	 *
	 * This is specific to workflow export logic, where we don't want an AJAX request
	 * interfering with browser download headers.
	 */
	$('.ss-gridfield .action.no-ajax.export-link').entwine({
		onclick: function(e){

			window.location.href = $.path.makeUrlAbsolute(
				$(this).attr('href')
			);

			return false;
		}
	});

});<commit_msg>Remove editor dialog on unmatch to prevent multiple dialogs<commit_after>jQuery.entwine("workflow", function($) {
	$(".workflow-field").entwine({
		Loading: null,
		Dialog:  null,
		onmatch: function() {
			var self = this;

			this.setLoading(this.find(".workflow-field-loading"));
			this.setDialog(this.find(".workflow-field-dialog"));

			this.getDialog().data("workflow-field", this).dialog({
				autoOpen: false,
				width:    800,
				height:   600,
				modal:    true,
				dialogClass: 'workflow-field-editor-dialog'
			});

			this.getDialog().on("click", "button", function() {
				$(this).addClass("loading ui-state-disabled");
			});

			this.getDialog().on("submit", "form", function() {
				$(this).ajaxSubmit(function(response) {
					if($(response).is(".workflow-field")) {
						self.getDialog().empty().dialog("close");
						self.replaceWith(response);
					} else {
						self.getDialog().html(response);
					}
				});

				return false;
			});
		},
		onunmatch: function () {
			$('.workflow-field-editor-dialog').remove();
		},
		showDialog: function(url) {
			var dlg = this.getDialog();

			dlg.empty().dialog("open");
			dlg.parent().addClass("loading");

			$.get(url).done(function(body) {
				dlg.html(body).parent().removeClass("loading");
			});
		},
		loading: function(toggle) {
			this.getLoading().toggle(typeof(toggle) == "undefined" || toggle);
		}
	});

	function helper() {
		return $("
").addClass("ui-state-highlight").appendTo("body");
	}

	$(".workflow-field .workflow-field-actions").entwine({
		onmatch: function() {
			$(".workflow-field .workflow-field-action-disabled").on('click',function() {
				return false;
			});
			this.sortable({
				axis:        "y",
				containment: this,
				placeholder: "ui-state-highlight workflow-placeholder",
				handle:      ".workflow-field-action-drag",
				tolerance:   "pointer",
				update: function() {
					var actions = $(this).find(".workflow-field-action");
					var field   = $(this).closest(".workflow-field");
					var link    = field.data("sort-link");
					var ids     = actions.map(function() { return $(this).data("id"); });

					var data = {
						"id[]":  ids.get(),
						"class": "WorkflowAction",
						"SecurityID": field.data("securityid")
					};

					field.loading();
					$.post(link, data).done(function() { field.loading(false); });
				}
			});
		}
	});

	$(".workflow-field .workflow-field-action-transitions").entwine({
		onmatch: function() {
			this.sortable({
				axis:        "y",
				containment: this,
				handle:      ".workflow-field-action-drag",
				tolerance:   "pointer",
				update: function() {
					var trans = $(this).find("li");
					var field = $(this).closest(".workflow-field");
					var link  = field.data("sort-link");
					var ids   = trans.map(function() { return $(this).data("id"); });

					var data = {
						"id[]":   ids.get(),
						"class":  "WorkflowTransition",
						"parent": $(this).closest(".workflow-field-action").data("id"),
						"SecurityID": field.data("securityid")
					};

					field.loading();
					$.post(link, data).done(function() { field.loading(false); });
				}
			});
		}
	});

	$(".workflow-field .workflow-field-create-class").entwine({
		onmatch: function() {
			this.chosen().addClass("has-chnz");
		},
		onchange: function() {
			this.siblings(".workflow-field-do-create").toggleClass("ui-state-disabled", !this.val());
		}
	});

	$(".workflow-field .workflow-field-do-create").entwine({
		onclick: function() {
			var sel   = this.siblings(".workflow-field-create-class");
			var field = this.closest(".workflow-field");

			if(sel.val()) {
				field.showDialog(sel.val());
			}

			return false;
		}
	});

	$(".workflow-field .workflow-field-open-dialog").entwine({
		onclick: function() {
			this.closest(".workflow-field").showDialog(this.prop("href"));
			return false;
		}
	});

	$(".workflow-field .workflow-field-delete").entwine({
		onclick: function() {
			if(confirm(ss.i18n._t('Workflow.DeleteQuestion'))) {
				var data = {
					"SecurityID" : this.data("securityid")
				};
				$.post(this.prop('href'), data).done(function(body) {
					$(".workflow-field").replaceWith(body);
				});
			}

			return false;
		}
	});

	/*
	 * Simple implementation of the jQuery-UI timepicker widget
	 * @see: http://trentrichardson.com/examples/timepicker/ for more config options
	 *
	 * This will need some more work when it comes to implementing i18n functionality. Fortunately, the library handles these as option-settings quite well.
	 */
	$("#Root_PublishingSchedule").entwine({
		onclick: function() {
			if(typeof $.fn.timepicker() !== 'object' || !$('input.hasTimePicker').length >0) {
				return false;
			}
			var field = $('input.hasTimePicker');
			var defaultTime = function() {
				var date = new Date();
				return date.getHours()+':'+date.getMinutes();
			}
			var pickerOpts = {
				useLocalTimezone: true,
				defaultValue: defaultTime,
				controlType: 'select',
				timeFormat: 'HH:mm'
			};
			field.timepicker(pickerOpts);
			return false;
		},
		onmatch: function(){
			var self = this,
				publishDate = this.find('#PublishOnDate input.date'),
				publishTime = this.find('#PublishOnDate input.time'),
				parent = this.find('#PublishOnDate');

			if(!$('#Form_EditForm_action_publish').attr('disabled')){
				self.checkEmbargo($(publishDate).val(), $(publishTime).val(), parent);

				publishDate.change(function(){
					self.checkEmbargo($(publishDate).val(),$(publishTime).val(), parent);
				});

				publishTime.change(function(){
					self.checkEmbargo($(publishDate).val(), $(publishTime).val(), parent);
				});
			}

			this._super();
		},
		/*
		 * Helper function opens publishing schedule tab when link clicked
		 */
		linkScheduled: function(parent){
			$('#workflow-schedule').click(function(){
				var tabID = parent.closest('.ui-tabs-panel.tab').attr('id');
				$('#tab-'+tabID).trigger('click');
				return false;
			});
		},
		/*
		 * Checks whether an embargo is present.
		 * If an embargo is present, display an altered actions panel,
		 * with a message notifying the user
		 */
		checkEmbargo: function(publishDate, publishTime, parent){

			// Something has changed, remove any existing embargo message
			$('.Actions #embargo-message').remove();

			/*
			 * Fuzzy checking:
			 * There may not be $(#PublishOnXXX input.date) DOM objects = undefined.
			 * There may be $(#PublishOnXXX input.date) DOM objects = val() method may return zero-length.
			 */
			var noPublishDate = (publishDate === undefined || publishDate.length == 0);
			var noPublishTime = (publishTime === undefined || publishTime.length == 0);

			if(noPublishDate && noPublishTime){
				//No Embargo, remove customizations
				$('#Form_EditForm_action_publish').removeClass('embargo');
				$('#Form_EditForm_action_publish').prev('button').removeClass('ui-corner-right');
			} else {

				var link,
					message;

				$('#Form_EditForm_action_publish').addClass('embargo');
				$('#Form_EditForm_action_publish').prev('button').addClass('ui-corner-right');

				if(publishDate === ''){
					//Has time, not date
					message = ss.i18n.sprintf(
						ss.i18n._t('Workflow.EMBARGOMESSAGETIME'),
						publishTime
					);

				}else if(publishTime === ''){
					//has date no time
					message = ss.i18n.sprintf(
						ss.i18n._t('Workflow.EMBARGOMESSAGEDATE'),
						publishDate
					);
				}else{
					//has date and time
					message = ss.i18n.sprintf(
						ss.i18n._t('Workflow.EMBARGOMESSAGEDATETIME'),
						publishDate,
						publishTime
					);
				}

				message = message.replace('','');

				//Append message with link
				$('.Actions #ActionMenus').after('
' + message + '
');

				//Active link
				this.linkScheduled(parent);
			}

			return false;
		}
	});
});

jQuery.entwine("ss", function($) {

	// Hide the uneccesary "Show Specification..." link included on ImportForms by default
	$('.importSpec').entwine({
		onmatch: function() {
			this.hide();
		}
	});

	// Remove the somehat hard-coded 'CSV' string from error message
	$('#Form_ImportForm_error').entwine({
		onmatch: function() {
			var ele = this;
			ele.html(ele.html().replace('CSV', ''));
		}
	});

	/**
	 * Prevents actions from causing an ajax reload of the field.
	 *
	 * This is specific to workflow export logic, where we don't want an AJAX request
	 * interfering with browser download headers.
	 */
	$('.ss-gridfield .action.no-ajax.export-link').entwine({
		onclick: function(e){

			window.location.href = $.path.makeUrlAbsolute(
				$(this).attr('href')
			);

			return false;
		}
	});

});<|endoftext|>


<commit_before>var assert = require('assert');
var sinon = require('sinon');
var chai = require("chai");
var sinonChai = require("sinon-chai");
var Promise = require('bluebird');

chai.should();
chai.use(sinonChai);

var createRootDispatcher = require('../createRootDispatcher.js');
var rootDispatcher;
var eventModel;
describe('RootDispatcher', function() {
  beforeEach(function(){
    // dispatch = sinon.spy();
    rootDispatcher = createRootDispatcher(function(model) {
      eventModel = model;
    });
  });

  describe('dispatch', function () {
    it('should concatinate scopes with _', function (done) {
      var scope1 = "scope1";
      var scope2 = "scope2";
      var eventName = "event";

      rootDispatcher.createScoped(scope1).createScoped(scope2).dispatch(eventName)
      .then(function(){
        eventModel.Scope.should.be.equal(scope1 + "_" + scope2);
        done();
      });
    });

    it('should run all filters', function (done) {
      var firstFilter = function(model){
        return Promise.resolve()
        .then(function(){
          model.ExtraData["key1"] = "value1";
        });
      };
      var lastFilter = function(model){
        return Promise.resolve()
        .then(function(){
          model.ExtraData["key2"] = "value2";
        });
      };
      rootDispatcher.withFilter(firstFilter).withFilter(lastFilter).dispatch()
      .then(function(){
        eventModel.ExtraData["key1"].should.be.equal("value1");
        eventModel.ExtraData["key2"].should.be.equal("value2");
        done();
      });
    });

    it('should run filters sequentially', function (done) {
      var firstFilter = function(model){
        return Promise.delay(10)
        .then(function(){

          model.ExtraData["key"] = "firstFilter";

        });
      };
      var lastFilter = function(model){
        return Promise.resolve()
        .then(function(){
          model.ExtraData["key"] = "lastFilter";

        });
      };
      rootDispatcher.withFilter(firstFilter).withFilter(lastFilter).dispatch()
      .then(function(){
        eventModel.ExtraData["key"].should.be.equal("lastFilter");
        done();
      });
    });
  });
});
<commit_msg>Add Identities test to RootDispatcherSpec<commit_after>var assert = require('assert');
var sinon = require('sinon');
var chai = require("chai");
var sinonChai = require("sinon-chai");
var Promise = require('bluebird');

chai.should();
chai.use(sinonChai);

var createRootDispatcher = require('../createRootDispatcher.js');
var rootDispatcher;
var eventModel;
describe('RootDispatcher', function() {
  beforeEach(function(){
    // dispatch = sinon.spy();
    rootDispatcher = createRootDispatcher(function(model) {
      eventModel = model;
    });
  });

  describe('dispatch', function () {
    it('should concatinate scopes with _', function (done) {
      var scope1 = "scope1";
      var scope2 = "scope2";
      var eventName = "event";

      rootDispatcher.createScoped(scope1).createScoped(scope2).dispatch(eventName)
      .then(function(){
        eventModel.Scope.should.be.equal(scope1 + "_" + scope2);
        done();
      });
    });

    it('should copy identities', function (done) {
      var id = '12345';
      rootDispatcher.withIdentity('id',id).dispatch('event')
      .then(function(){
        eventModel.Identities['id'].should.be.equal(id);
        done();
      });
    });

    it('should run all filters', function (done) {
      var firstFilter = function(model){
        return Promise.resolve()
        .then(function(){
          model.ExtraData["key1"] = "value1";
        });
      };
      var lastFilter = function(model){
        return Promise.resolve()
        .then(function(){
          model.ExtraData["key2"] = "value2";
        });
      };
      rootDispatcher.withFilter(firstFilter).withFilter(lastFilter).dispatch()
      .then(function(){
        eventModel.ExtraData["key1"].should.be.equal("value1");
        eventModel.ExtraData["key2"].should.be.equal("value2");
        done();
      });
    });

    it('should run filters sequentially', function (done) {
      var firstFilter = function(model){
        return Promise.delay(10)
        .then(function(){

          model.ExtraData["key"] = "firstFilter";

        });
      };
      var lastFilter = function(model){
        return Promise.resolve()
        .then(function(){
          model.ExtraData["key"] = "lastFilter";

        });
      };
      rootDispatcher.withFilter(firstFilter).withFilter(lastFilter).dispatch()
      .then(function(){
        eventModel.ExtraData["key"].should.be.equal("lastFilter");
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * This file provided by Facebook is for non-commercial testing and evaluation
 * purposes only. Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var fs = require('fs');
var path = require('path');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var router = express.Router();

if(process.argv[2]!==undefined){
	app.set('port',  process.argv[2]);
}
else{
	app.set('port',  3000);
}

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.use(express.static('../Frontend'))

/*
// Additional middleware which will set headers that we need on each request.
app.use(function(req, res, next) {
    // Set permissive CORS header - this allows this server to be used only as
    // an API server in conjunction with something like webpack-dev-server.
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Disable caching so we'll always get the latest comments.
    res.setHeader('Cache-Control', 'no-cache');
    next();
});
*/

var aSong={id:1232141,name:'supersong',artistName:'Joe Cool',albumName:'blablabla'};
app.get('/current', function (req, res) {
	console.log('allsongs called');
	res.send(aSong);
})

var dummySongList=[
	{id:1232141,name:'supersong',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232143,name:'supersong1',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232144,name:'supersong2',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232145,name:'supersong3',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922046/256x256'},
	{id:1232146,name:'supersong4',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232147,name:'supersong5',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232148,name:'supersong6',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232149,name:'supersong7',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232150,name:'supersong8',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922646/256x256'}
];
app.get('/playlist', function (req, res) {
	console.log('allsongs called');
	res.send(dummySongList);
})

app.listen(app.get('port'), function() {
  console.log('Server started: http://localhost:' + app.get('port') + '/');
});
<commit_msg>automatic redirect for test server<commit_after>/**
 * This file provided by Facebook is for non-commercial testing and evaluation
 * purposes only. Facebook reserves all rights not expressly granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var fs = require('fs');
var path = require('path');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var router = express.Router();

if(process.argv[2]!==undefined){
	app.set('port',  process.argv[2]);
}
else{
	app.set('port',  3000);
}

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.use(express.static('../Frontend'))

app.get("/", function(req, res) {
	res.redirect(301, "index.html");
});

/*
// Additional middleware which will set headers that we need on each request.
app.use(function(req, res, next) {
    // Set permissive CORS header - this allows this server to be used only as
    // an API server in conjunction with something like webpack-dev-server.
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Disable caching so we'll always get the latest comments.
    res.setHeader('Cache-Control', 'no-cache');
    next();
});
*/

var aSong={id:1232141,name:'supersong',artistName:'Joe Cool',albumName:'blablabla'};
app.get('/current', function (req, res) {
	res.send(aSong);
})

var dummySongList=[
	{id:1232141,name:'supersong',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232143,name:'supersong1',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232144,name:'supersong2',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232145,name:'supersong3',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922046/256x256'},
	{id:1232146,name:'supersong4',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232147,name:'supersong5',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232148,name:'supersong6',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232149,name:'supersong7',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922746/256x256'},
	{id:1232150,name:'supersong8',artistName:'Joe Cool',albumName:'blablabla',imageUrl:'https://artwork.cdn.247e.com/covers/3922646/256x256'}
];
app.get('/playlist', function (req, res) {
	console.log('allsongs called');
	res.send(dummySongList);
})

app.listen(app.get('port'), function() {
  console.log('Server started: http://localhost:' + app.get('port') + '/');
});
<|endoftext|>


<commit_before>if (typeof NCI === 'undefined')
   NCI = {};

NCI.start_time; // no data exists on the server before
NCI.time_adjustment = 0; //difference between client and server time in milliseconds
NCI.numOfPoints = 200;
//NCI.Connection = new WebSocket("ws://epamove.herokuapp.com");
NCI.connectionURL = "ws://" + location.host + "/clientsock.yaws";
NCI.connectionURL = "ws://10.48.2.81:28080/clientsock.yaws";

NCI.Connection = [];

NCI.lastUpdateTimeVal = new Date();
NCI.lastRedrawTimeVal = new Date();

NCI.Connection.onmessage  = function (e) {
	var data = eval("tmp = " + e.data );

	if (data.start_time){
		// to show utc time
		// NCI.time_adjustment = new Date() - new Date(data.current_time) - new Date().getTimezoneOffset()*1000*60;
		var curTime = new Date(data.current_time);
		NCI.time_adjustment = new Date() - curTime;
		if (!NCI.chart){
			NCI.start_time = new Date(data.start_time);
			NCI.zoomLinks.setTimePeriod(curTime - NCI.start_time);
			NCI.initChart(curTime - NCI.time_adjustment);

			NCI.curChartPeriod = (NCI.chartPeriods.twoyears - (curTime - NCI.start_time) < 0) ? NCI.chartPeriods.twoyears : (curTime - NCI.start_time);
			NCI.Connection.moreData(new Date() - NCI.curChartPeriod, new Date(), NCI.numOfPoints);
		};
		return;
	} else if (data.action == "collectors") {
		//data.Time
		 NCI.collectorsTable.fillData(data.Collectors);
	} else if (data.action == "QPS") {
			NCI.setQpsLatestValue(NCI.parceNumberForView(data.QPS, 1), NCI.parceDateForLastUpdate(data.Time));
	} else if (data.action == "NEP") {
			NCI.setNepLatestValue(NCI.parceNumberForView(data.NEP), NCI.parceDateForLastUpdate(data.Time));
	} else if (data.action == "Collectors")	{
		    NCI.setCollectorsLatestValue(NCI.parceNumberForView(data.COLLECTORS), NCI.parceDateForLastUpdate(data.Time));
	} else if (data.action == "NCI"){
		var dateVal = new Date(data.Time);
		if (data.NCI){
			NCI.lastUpdateTimeVal = dateVal;
			NCI.nciUpdateDateServer = data.Time;
			NCI.setNciLatestValue(data.NCI, NCI.parceDateForLastUpdate(data.Time), data.activities);
			if (!NCI.chart){
				 NCI.initChart(new Date(data.Time) - NCI.time_adjustment);
			} else {
				//update chart not faster then once in 3 seconds and only for case when we are in 2 years mode
				if (new Date() - NCI.lastRedrawTimeVal < 3000  && NCI.curChartPeriod <= NCI.chartPeriods.twoyears )
					return;

				NCI.chartData.push([new Date(dateVal - NCI.time_adjustment).getTime(), data.NCI]);
				NCI.lastRedrawTimeVal = new Date();
				//next cycle checks if there are values in chart data set,
				//that are older then current chart time period
				var len = NCI.chartData.length - 2;
				for (var ind = 0; ind < len; ind++ ){
					if (new Date(data.Time).getTime() - NCI.chartData[ind + 1][0] > NCI.curChartPeriod){
						NCI.chartData.shift();
					} else {
						break;
					}
				}

				//check if chart selected area right border is in the beginning of chart ,
				//then automaticaly move selection area to the beginning (error ~ one minute)
				if (parseInt(NCI.chart.xAxisExtremes()[1] - NCI.chart.xAxisRange()[1]) < NCI.chartPeriods.minute && NCI.chart &&  NCI.chart.dateWindow_){
					var diff = NCI.chart.dateWindow_[1] - NCI.chart.dateWindow_[0];
					NCI.chart.updateOptions({
						file: NCI.chartData,
						dateWindow: [new Date(dateVal - diff  - NCI.time_adjustment).getTime(),
							new Date(dateVal  - NCI.time_adjustment).getTime()]
					});
				} else {
					NCI.chart.updateOptions({
						file: NCI.chartData
					});
				}
			};
		} ;
	} else if (data.action == "NCIDetails"){
		NCI.setupCommunities(data)
		$('#nciDetailsTabs').find("a").first().click();
	    NCI.socialGraph.show(false, false, false, false);
	} else {
		//we recieve such format:
		// {"Time":"2013-10-27T13:01:09Z","NCI":99,
		// "Time":"2013-10-27T13:11:39Z","NCI":8,
		// "Time":"2013-10-27T13:22:15Z","NCI":18,
		// "Time":"2013-10-27T13:33:01Z","NCI":87}
		var newData = [];
		var recievedDataArray = e.data.substring(1, e.data.length - 1).split(',');
		for (var i = 0; i < recievedDataArray.length/2; i++){
			var curIndex = 2 * i;
			var timeValue = recievedDataArray[curIndex].substring(7);
			timeValue = timeValue.substring(1, timeValue.length - 1);
			var nciValue = recievedDataArray[curIndex + 1];
			nciValue = parseInt(nciValue.split(":")[1]);
			newData.push([new Date(new Date(timeValue) - NCI.time_adjustment).getTime() , nciValue]);
		};

		NCI.setBottomChartDates(new Date(new Date() - NCI.time_adjustment).getTime() - newData[0][0]);

		NCI.detailedChartPeriod = NCI.detailedChartPeriod ? NCI.detailedChartPeriod : NCI.curChartPeriod/10;
		if (NCI.detailedChartPeriod > (new Date().getTime() - newData[0][0])){
			NCI.detailedChartPeriod = new Date().getTime() - newData[0][0];
		};

		var ranges = NCI.DetectRangesForPeiod( NCI.detailedChartPeriod, newData);
		//var endRangeDate = newData[newData.length - 1][0];
		// var firstDate = newData[0][0];
		// if (endRangeDate - NCI.detailedChartPeriod < firstDate){
		// 	var startRangeDate = firstDate;
		// 	if (startRangeDate +  NCI.detailedChartPeriod < new Date().getTime()){
		// 		endRangeDate = startRangeDate +  NCI.detailedChartPeriod;
		// 	} else {
		// 		endRangeDate = new Date().getTime();
		// 	};
		// } else {
		// 	var startRangeDate = endRangeDate - NCI.detailedChartPeriod;
		// };
		//
		newData.push([new Date(new Date() - NCI.time_adjustment).getTime() , null]);
		NCI.chartData = newData;

	 	NCI.chart.updateOptions({
			dateWindow: [ranges[0] - NCI.time_adjustment, ranges[1] - NCI.time_adjustment],
			connectSeparatedPoints: true,
			file: NCI.chartData
	 	});
	};

};

NCI.DetectRangesForPeiod = function(detailedChartPeriod, chartData){
	if (chartData.length < 2)
		return [0,0];
	var endRangeDate = chartData[chartData.length - 1][0];
	if (!chartData[chartData.length - 1][1])
		endRangeDate = chartData[chartData.length - 2][0];
	var firstDate = chartData[0][0];
	if (endRangeDate - detailedChartPeriod < firstDate){
		var startRangeDate = firstDate;
		if (startRangeDate +  detailedChartPeriod < new Date().getTime()){
			endRangeDate = startRangeDate +  detailedChartPeriod;
		} else {
			endRangeDate = new Date().getTime();
		};
	} else {
		var startRangeDate = endRangeDate - detailedChartPeriod;
	};
	return [startRangeDate, new Date().getTime()];
};

NCI.Connection.NCIDetails = function(time){
    NCI.Socket.send('{"action":"NCIDetails","Time": "' + time + '"}');
};

NCI.Connection.CollectorsDetails = function(time){
	 NCI.Socket.send('{"action":"collectors","Time": "' + time + '"}');
}

NCI.Connection.startData = function() {
	NCI.Socket.send('START_DATA');
};

NCI.Connection.moreData = function(startTime, endTime, pointsNum) {
	startTime = NCI.convertDateForServer(startTime);
	endTime = NCI.convertDateForServer(endTime);
    NCI.Socket.send('{"request":"more_data","start": "' +
		startTime + '",' +  '"end": "' + endTime + '","max_items": "' + pointsNum + '"}');
};

NCI.initSocket = function(){
	NCI.Socket = new WebSocket(NCI.connectionURL);
	NCI.Socket.onerror = function (e) {
		//$(".disconected").show();
	};
	NCI.Socket.onclose = function (e) {
		$(".disconected").show();
	};
	NCI.Socket.onopen = function () {
		$(".disconected").hide();
		NCI.Connection.startData();
	};
	NCI.Socket.onmessage  = function (e) {
		NCI.Connection.onmessage(e);
	};
};

NCI.initSocket();

$(".disconected img").on('click', function(){
	$(".disconected").hide();
	NCI.initSocket();
});
<commit_msg>Comment freezen url<commit_after>if (typeof NCI === 'undefined')
   NCI = {};

NCI.start_time; // no data exists on the server before
NCI.time_adjustment = 0; //difference between client and server time in milliseconds
NCI.numOfPoints = 200;
//NCI.Connection = new WebSocket("ws://epamove.herokuapp.com");
NCI.connectionURL = "ws://" + location.host + "/clientsock.yaws";
//NCI.connectionURL = "ws://10.48.2.81:28080/clientsock.yaws";

NCI.Connection = [];

NCI.lastUpdateTimeVal = new Date();
NCI.lastRedrawTimeVal = new Date();

NCI.Connection.onmessage  = function (e) {
	var data = eval("tmp = " + e.data );

	if (data.start_time){
		// to show utc time
		// NCI.time_adjustment = new Date() - new Date(data.current_time) - new Date().getTimezoneOffset()*1000*60;
		var curTime = new Date(data.current_time);
		NCI.time_adjustment = new Date() - curTime;
		if (!NCI.chart){
			NCI.start_time = new Date(data.start_time);
			NCI.zoomLinks.setTimePeriod(curTime - NCI.start_time);
			NCI.initChart(curTime - NCI.time_adjustment);

			NCI.curChartPeriod = (NCI.chartPeriods.twoyears - (curTime - NCI.start_time) < 0) ? NCI.chartPeriods.twoyears : (curTime - NCI.start_time);
			NCI.Connection.moreData(new Date() - NCI.curChartPeriod, new Date(), NCI.numOfPoints);
		};
		return;
	} else if (data.action == "collectors") {
		//data.Time
		 NCI.collectorsTable.fillData(data.Collectors);
	} else if (data.action == "QPS") {
			NCI.setQpsLatestValue(NCI.parceNumberForView(data.QPS, 1), NCI.parceDateForLastUpdate(data.Time));
	} else if (data.action == "NEP") {
			NCI.setNepLatestValue(NCI.parceNumberForView(data.NEP), NCI.parceDateForLastUpdate(data.Time));
	} else if (data.action == "Collectors")	{
		    NCI.setCollectorsLatestValue(NCI.parceNumberForView(data.COLLECTORS), NCI.parceDateForLastUpdate(data.Time));
	} else if (data.action == "NCI"){
		var dateVal = new Date(data.Time);
		if (data.NCI){
			NCI.lastUpdateTimeVal = dateVal;
			NCI.nciUpdateDateServer = data.Time;
			NCI.setNciLatestValue(data.NCI, NCI.parceDateForLastUpdate(data.Time), data.activities);
			if (!NCI.chart){
				 NCI.initChart(new Date(data.Time) - NCI.time_adjustment);
			} else {
				//update chart not faster then once in 3 seconds and only for case when we are in 2 years mode
				if (new Date() - NCI.lastRedrawTimeVal < 3000  && NCI.curChartPeriod <= NCI.chartPeriods.twoyears )
					return;

				NCI.chartData.push([new Date(dateVal - NCI.time_adjustment).getTime(), data.NCI]);
				NCI.lastRedrawTimeVal = new Date();
				//next cycle checks if there are values in chart data set,
				//that are older then current chart time period
				var len = NCI.chartData.length - 2;
				for (var ind = 0; ind < len; ind++ ){
					if (new Date(data.Time).getTime() - NCI.chartData[ind + 1][0] > NCI.curChartPeriod){
						NCI.chartData.shift();
					} else {
						break;
					}
				}

				//check if chart selected area right border is in the beginning of chart ,
				//then automaticaly move selection area to the beginning (error ~ one minute)
				if (parseInt(NCI.chart.xAxisExtremes()[1] - NCI.chart.xAxisRange()[1]) < NCI.chartPeriods.minute && NCI.chart &&  NCI.chart.dateWindow_){
					var diff = NCI.chart.dateWindow_[1] - NCI.chart.dateWindow_[0];
					NCI.chart.updateOptions({
						file: NCI.chartData,
						dateWindow: [new Date(dateVal - diff  - NCI.time_adjustment).getTime(),
							new Date(dateVal  - NCI.time_adjustment).getTime()]
					});
				} else {
					NCI.chart.updateOptions({
						file: NCI.chartData
					});
				}
			};
		} ;
	} else if (data.action == "NCIDetails"){
		NCI.setupCommunities(data)
		$('#nciDetailsTabs').find("a").first().click();
	    NCI.socialGraph.show(false, false, false, false);
	} else {
		//we recieve such format:
		// {"Time":"2013-10-27T13:01:09Z","NCI":99,
		// "Time":"2013-10-27T13:11:39Z","NCI":8,
		// "Time":"2013-10-27T13:22:15Z","NCI":18,
		// "Time":"2013-10-27T13:33:01Z","NCI":87}
		var newData = [];
		var recievedDataArray = e.data.substring(1, e.data.length - 1).split(',');
		for (var i = 0; i < recievedDataArray.length/2; i++){
			var curIndex = 2 * i;
			var timeValue = recievedDataArray[curIndex].substring(7);
			timeValue = timeValue.substring(1, timeValue.length - 1);
			var nciValue = recievedDataArray[curIndex + 1];
			nciValue = parseInt(nciValue.split(":")[1]);
			newData.push([new Date(new Date(timeValue) - NCI.time_adjustment).getTime() , nciValue]);
		};

		NCI.setBottomChartDates(new Date(new Date() - NCI.time_adjustment).getTime() - newData[0][0]);

		NCI.detailedChartPeriod = NCI.detailedChartPeriod ? NCI.detailedChartPeriod : NCI.curChartPeriod/10;
		if (NCI.detailedChartPeriod > (new Date().getTime() - newData[0][0])){
			NCI.detailedChartPeriod = new Date().getTime() - newData[0][0];
		};

		var ranges = NCI.DetectRangesForPeiod( NCI.detailedChartPeriod, newData);
		//var endRangeDate = newData[newData.length - 1][0];
		// var firstDate = newData[0][0];
		// if (endRangeDate - NCI.detailedChartPeriod < firstDate){
		// 	var startRangeDate = firstDate;
		// 	if (startRangeDate +  NCI.detailedChartPeriod < new Date().getTime()){
		// 		endRangeDate = startRangeDate +  NCI.detailedChartPeriod;
		// 	} else {
		// 		endRangeDate = new Date().getTime();
		// 	};
		// } else {
		// 	var startRangeDate = endRangeDate - NCI.detailedChartPeriod;
		// };
		//
		newData.push([new Date(new Date() - NCI.time_adjustment).getTime() , null]);
		NCI.chartData = newData;

	 	NCI.chart.updateOptions({
			dateWindow: [ranges[0] - NCI.time_adjustment, ranges[1] - NCI.time_adjustment],
			connectSeparatedPoints: true,
			file: NCI.chartData
	 	});
	};

};

NCI.DetectRangesForPeiod = function(detailedChartPeriod, chartData){
	if (chartData.length < 2)
		return [0,0];
	var endRangeDate = chartData[chartData.length - 1][0];
	if (!chartData[chartData.length - 1][1])
		endRangeDate = chartData[chartData.length - 2][0];
	var firstDate = chartData[0][0];
	if (endRangeDate - detailedChartPeriod < firstDate){
		var startRangeDate = firstDate;
		if (startRangeDate +  detailedChartPeriod < new Date().getTime()){
			endRangeDate = startRangeDate +  detailedChartPeriod;
		} else {
			endRangeDate = new Date().getTime();
		};
	} else {
		var startRangeDate = endRangeDate - detailedChartPeriod;
	};
	return [startRangeDate, new Date().getTime()];
};

NCI.Connection.NCIDetails = function(time){
    NCI.Socket.send('{"action":"NCIDetails","Time": "' + time + '"}');
};

NCI.Connection.CollectorsDetails = function(time){
	 NCI.Socket.send('{"action":"collectors","Time": "' + time + '"}');
}

NCI.Connection.startData = function() {
	NCI.Socket.send('START_DATA');
};

NCI.Connection.moreData = function(startTime, endTime, pointsNum) {
	startTime = NCI.convertDateForServer(startTime);
	endTime = NCI.convertDateForServer(endTime);
    NCI.Socket.send('{"request":"more_data","start": "' +
		startTime + '",' +  '"end": "' + endTime + '","max_items": "' + pointsNum + '"}');
};

NCI.initSocket = function(){
	NCI.Socket = new WebSocket(NCI.connectionURL);
	NCI.Socket.onerror = function (e) {
		//NCI.chartData = [];
		//$(".disconected").show();
	};
	NCI.Socket.onclose = function (e) {
		$(".disconected").show();
	};
	NCI.Socket.onopen = function () {
		$(".disconected").hide();
		NCI.Connection.startData();
	};
	NCI.Socket.onmessage  = function (e) {
		NCI.Connection.onmessage(e);
	};
};

NCI.initSocket();

$(".disconected img").on('click', function(){
	$(".disconected").hide();
	NCI.initSocket();
});
<|endoftext|>