<commit_before>
var path = require('path');

var browserify = require('browserify');
var titaniumResolve = require('titanium-resolve');
var when = require('when');
var nodefn = require('when/node/function');

var fs = require('./util/fs');

var BUILTINS = require('./builtins');
var GLOBAL_VARS = require('./globals');
var PRELUDE_PATH = path.resolve(__dirname, 'util', '_prelude.js');
var PRELUDE_SRC = require('fs').readFileSync(PRELUDE_PATH, 'utf8');

module.exports = pack;

function getPackage(entryfile) {
  return fs.isFile(entryfile).then(function (isFile) {
    if (isFile) return entryfile;
    else return path.resolve(entryfile, 'package.json');
  })
  .then(function (entry) {
    return fs
    .readFile(entry, 'utf8')
    .then(JSON.parse)
    .then(function (pkg) {
      return {
        path: entry,
        pkg: pkg
      };
    });
  });
}

function addDeps(to, deps) {
  if (Array.isArray(deps)) {
    deps.forEach(function (dep) {
      to.push(dep);
    });
  }
  else if (typeof deps === 'string') {
    to.push(deps);
  }
  else if (deps) {
    addDeps(to, Object.keys(deps));
  }
}

// cfg = {
//   noDependencies // do not pack dependencies with it
//   useTitaniumPlatformResolve // TODO
//   debug // build source maps
// }

function pack(entry, cfg, callback) {
  var promise = getPackage(entry).then(function (data) {

    var entry = path.dirname(data.path);
    var pkg = data.pkg;
    var titaniumManifest = pkg.titaniumManifest || {};

    var moduleid = titaniumManifest.moduleid || pkg.name;

    var opts = pkg.titaniumifier || pkg.npmifier || pkg.browserify || {};

    opts.extensions || (opts.extensions = [ '.js', '.json' ]);
    opts.transforms || (opts.transforms = []);
    opts.ignores || (opts.ignores = []);
    opts.externals || (opts.externals = []);

    var addExternals = addDeps.bind(null, opts.externals);

    addExternals(pkg.peerDependencies);
    addExternals(pkg.nativeDependencies);

    if (cfg.noDependencies) {
      addExternals(pkg.dependencies);
      addExternals(pkg.devDependencies);
      addExternals(pkg.optionalDependencies);
    }

    opts.ignoreMissing = !!opts.ignoreMissing;

    opts.transforms = opts.transforms.map(function (tr) {
      return require(tr);
    });

    var b = browserify({
      builtins: BUILTINS,
      debug: cfg.debug,
      extensions: opts.extensions,
      insertGlobalVars: GLOBAL_VARS,
      ignoreMissing: true,
      standalone: moduleid,
      prelude: PRELUDE_SRC,
      preludePath: PRELUDE_PATH
    });

    b.plugin(fixResolver, {
      resolve: titaniumResolve
    });

    opts.transforms.forEach(function (transform) {
      b.transform(transform);
    });

    opts.ignores.forEach(function (ignore) {
      b.ignore(ignore);
    });

    opts.externals.forEach(function (external) {
      b.exclude(external);
    });

    if (cfg.useTitaniumPlatformResolve) {
      TODO;
      /*b.transform(titaniumPlatformResolve.createTransform({
        platforms: [ build.platformName ],
        extensions: opts.extensions
      }));*/
    }

    var entrypoint = path.resolve(entry, pkg.main || 'index.js');

    return when.promise(function (resolve, reject) {
      titaniumResolve(entrypoint, {
        paths: b._mdeps.paths,
        modules: b._mdeps.options.modules,
        filename: path.resolve(entry, 'package.json'),
        extensions: opts.extensions
      }, function (err, result) {
        if (err) return reject(err);

        b.add(result);

        b.bundle(function (err, result) {
          if (err) return reject(err);
          resolve(result);
        });
      });
    });
  });

  if (callback) {
    promise.done(callback.bind(null, null), callback.bind(null));
  }

  return promise;
}

function fixResolver(b, opts) {
  b._mdeps.resolver = (opts.resolve || b._mdeps.resolver);
}
<commit_msg>Throw on missing packages, use `nativeDependencies`<commit_after>
var path = require('path');

var browserify = require('browserify');
var titaniumResolve = require('titanium-resolve');
var when = require('when');
var nodefn = require('when/node/function');

var fs = require('./util/fs');

var BUILTINS = require('./builtins');
var GLOBAL_VARS = require('./globals');
var PRELUDE_PATH = path.resolve(__dirname, 'util', '_prelude.js');
var PRELUDE_SRC = require('fs').readFileSync(PRELUDE_PATH, 'utf8');

module.exports = pack;

function getPackage(entryfile) {
  return fs.isFile(entryfile).then(function (isFile) {
    if (isFile) return entryfile;
    else return path.resolve(entryfile, 'package.json');
  })
  .then(function (entry) {
    return fs
    .readFile(entry, 'utf8')
    .then(JSON.parse)
    .then(function (pkg) {
      return {
        path: entry,
        pkg: pkg
      };
    });
  });
}

function addDeps(to, deps) {
  if (Array.isArray(deps)) {
    deps.forEach(function (dep) {
      to.push(dep);
    });
  }
  else if (typeof deps === 'string') {
    to.push(deps);
  }
  else if (deps) {
    addDeps(to, Object.keys(deps));
  }
}

// cfg = {
//   noDependencies // do not pack dependencies with it
//   useTitaniumPlatformResolve // TODO
//   debug // build source maps
// }

function pack(entry, cfg, callback) {
  var promise = getPackage(entry).then(function (data) {

    var entry = path.dirname(data.path);
    var pkg = data.pkg;
    var titaniumManifest = pkg.titaniumManifest || {};

    var moduleid = titaniumManifest.moduleid || pkg.name;

    var opts = pkg.titaniumifier || pkg.npmifier || pkg.browserify || {};

    opts.extensions || (opts.extensions = [ '.js', '.json' ]);
    opts.transforms || (opts.transforms = []);
    opts.ignores || (opts.ignores = []);
    opts.externals || (opts.externals = []);

    var addExternals = addDeps.bind(null, opts.externals);

    addExternals(pkg.peerDependencies);
    addExternals(pkg.nativeDependencies);

    if (cfg.noDependencies) {
      addExternals(pkg.dependencies);
      addExternals(pkg.devDependencies);
      addExternals(pkg.optionalDependencies);
    }

    opts.ignoreMissing = !!opts.ignoreMissing;

    opts.transforms = opts.transforms.map(function (tr) {
      return require(tr);
    });

    var b = browserify({
      builtins: BUILTINS,
      debug: cfg.debug,
      extensions: opts.extensions,
      insertGlobalVars: GLOBAL_VARS,
      ignoreMissing: false,
      standalone: moduleid,
      prelude: PRELUDE_SRC,
      preludePath: PRELUDE_PATH
    });

    b.plugin(fixResolver, {
      resolve: titaniumResolve
    });

    opts.transforms.forEach(function (transform) {
      b.transform(transform);
    });

    opts.ignores.forEach(function (ignore) {
      b.ignore(ignore);
    });

    opts.externals.forEach(function (external) {
      b.exclude(external);
    });

    if (cfg.useTitaniumPlatformResolve) {
      TODO;
      /*b.transform(titaniumPlatformResolve.createTransform({
        platforms: [ build.platformName ],
        extensions: opts.extensions
      }));*/
    }

    var entrypoint = path.resolve(entry, pkg.main || 'index.js');

    return when.promise(function (resolve, reject) {
      titaniumResolve(entrypoint, {
        paths: b._mdeps.paths,
        modules: b._mdeps.options.modules,
        filename: path.resolve(entry, 'package.json'),
        extensions: opts.extensions
      }, function (err, result) {
        if (err) return reject(err);

        b.add(result);

        b.bundle(function (err, result) {
          if (err) return reject(err);
          resolve(result);
        });
      });
    });
  });

  if (callback) {
    promise.done(callback.bind(null, null), callback.bind(null));
  }

  return promise;
}

function fixResolver(b, opts) {
  b._mdeps.resolver = (opts.resolve || b._mdeps.resolver);
}
<|endoftext|>


<commit_before>/*global describe,before,it,cy,Cypress */

describe('Journey', function () {

  before(function () {
    cy.clearIndexDb()
    cy.unregisterServiceWorkers()
  })

  it('should all work fine', function () {
    cy.visit('/')
    cy.location('pathname').should('include', 'tracking')

    cy.locate('add-tray-url').type(Cypress.env('TRAY_URL'))
    if(Cypress.env('TRAY_USERNAME') && Cypress.env('TRAY_PASSWORD')) {
      cy.locate('add-tray-username').type(Cypress.env('TRAY_USERNAME'))
      cy.locate('add-tray-password').type(Cypress.env('TRAY_PASSWORD'))
    }
    cy.locate('add-tray').click()

    cy.locate('tray')
      .locate('container-sub-title').should('have.text', Cypress.env('TRAY_URL'))
      .locate('exclude-all').click()
      .locate('include-all').click()
      .locate('tab-settings').click()
      .locate('generate-random').click()
      .locate('tray-name').clear().type('renamed tray').blur()
      .locate('container-title').should('have.text', 'renamed tray')
      .locate('tab-projects').click()
      .locate('available-projects-list').contains('failure building project')
      .locate('available-projects-list').contains('failure sleeping project')
      .locate('available-projects-list').contains('success building project')
      .locate('available-projects-list').contains('success sleeping project')

    cy.locate('menu-success').click()
    cy.location('pathname').should('include', 'success')
    cy.locate('message').type('some message')
    cy.locate('add-message').click()
    cy.locate('success-message').contains('=(^.^)=')
    cy.locate('success-message').contains('some message')

    cy.locate('message')
      .type('https://raw.githubusercontent.com/build-canaries/nevergreen/master/doc/screenshot.png')
    cy.locate('add-message').click()
    cy.locate('success-image').should('be.visible')

    // settings
    cy.locate('menu-settings').click()
    cy.location('pathname').should('include', 'settings')

    cy.locate('play-sounds').click()
    cy.locate('refresh-time').select('60')
    cy.locate('click-to-show-menu').click()

    cy.locate('show-tray-names').check()
    cy.locate('show-build-times').check()
    cy.locate('show-broken-build-times').check()
    cy.locate('show-build-labels').check()
    cy.locate('max-projects-to-show').select('6')
    cy.locate('build-label').should('exist')
    cy.locate('tray-name').should('exist')
    cy.locate('duration').should('exist') // todo: building vs broken time

    cy.locate('show-tray-names').uncheck()
    cy.locate('show-build-times').uncheck()
    cy.locate('show-broken-build-times').uncheck()
    cy.locate('show-build-labels').uncheck()
    cy.locate('max-projects-to-show').select('30')
    cy.locate('build-label').should('not.exist')
    cy.locate('tray-name').should('not.exist')
    cy.locate('duration').should('not.exist')
  })
})
<commit_msg>[#162] split cypress test up<commit_after>/*global describe,before,it,cy,Cypress */

describe('Journey', function () {

  before(function () {
    cy.clearIndexDb()
    cy.unregisterServiceWorkers()
  })

  it('should all work fine', function () {
    cy.visit('/')

    shouldBeAbleToAddTrays(Cypress.env('TRAY_URL'), Cypress.env('TRAY_USERNAME'), Cypress.env('TRAY_PASSWORD'))
    shouldBeAbleToChangeMessages()
    shouldBeAbleToChangeSettings()
  })

  function shouldBeAbleToAddTrays(trayUrl, username, password) {
    cy.location('pathname').should('include', 'tracking')

    cy.locate('add-tray-url').type(trayUrl)
    if (username && password) {
      cy.locate('add-tray-username').type(username)
      cy.locate('add-tray-password').type(password)
    }
    cy.locate('add-tray').click()

    cy.locate('tray').should('exist')
    cy.locate('container-sub-title').should('have.text', trayUrl)
    cy.locate('exclude-all').click()
    cy.locate('include-all').click()
    cy.locate('tab-settings').click()
    cy.locate('generate-random').click()
    cy.locate('tray-name').clear().type('renamed tray').blur()
    cy.locate('container-title').should('have.text', 'renamed tray')
    cy.locate('tab-projects').click()
    cy.locate('available-projects-list').contains('failure building project')
    cy.locate('available-projects-list').contains('failure sleeping project')
    cy.locate('available-projects-list').contains('success building project')
    cy.locate('available-projects-list').contains('success sleeping project')
  }

  function shouldBeAbleToChangeMessages() {
    cy.locate('menu-success').click()
    cy.location('pathname').should('include', 'success')
    cy.locate('message').type('some message')
    cy.locate('add-message').click()
    cy.locate('success-message').contains('=(^.^)=')
    cy.locate('success-message').contains('some message')

    cy.locate('message')
      .type('https://raw.githubusercontent.com/build-canaries/nevergreen/master/doc/screenshot.png')
    cy.locate('add-message').click()
    cy.locate('success-image').should('be.visible')
  }

  function shouldBeAbleToChangeSettings() {
    cy.locate('menu-settings').click()
    cy.location('pathname').should('include', 'settings')

    cy.locate('play-sounds').click()
    cy.locate('refresh-time').select('60')
    cy.locate('click-to-show-menu').click()

    cy.locate('show-tray-names').check()
    cy.locate('show-build-times').check()
    cy.locate('show-broken-build-times').check()
    cy.locate('show-build-labels').check()
    cy.locate('max-projects-to-show').select('6')
    cy.locate('build-label').should('exist')
    cy.locate('tray-name').should('exist')
    cy.locate('duration').should('exist') // TODO: building vs broken time

    cy.locate('show-tray-names').uncheck()
    cy.locate('show-build-times').uncheck()
    cy.locate('show-broken-build-times').uncheck()
    cy.locate('show-build-labels').uncheck()
    cy.locate('max-projects-to-show').select('30')
    cy.locate('build-label').should('not.exist')
    cy.locate('tray-name').should('not.exist')
    cy.locate('duration').should('not.exist')
  }
})
<|endoftext|>


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

var invokerUtil = function () {

    var module = {};

    var END_POINT = window.location.origin+"/devicemgt/api/invoker/execute/";

    module.get = function (url, successCallback, errorCallback, contentType, acceptType) {
        var payload = null;
        execute("GET", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    module.post = function (url, payload, successCallback, errorCallback, contentType, acceptType) {
        execute("POST", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    module.put = function (url, payload, successCallback, errorCallback, contentType, acceptType) {
        execute("PUT", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    module.delete = function (url, successCallback, errorCallback, contentType, acceptType) {
        var payload = null;
        execute("DELETE", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    function execute (methoad, url, payload, successCallback, errorCallback, contentType, acceptType) {
        if(contentType == undefined){
            contentType = "application/json";
        }
        if(acceptType == undefined){
            acceptType = "application/json";
        }
        var data = {
            url: END_POINT,
            type: "POST",
            contentType: contentType,
            accept: acceptType,
            success: successCallback
        };
        console.log(data);
        var paramValue = {};
        paramValue.actionMethod = methoad;
        paramValue.actionUrl = url;
        paramValue.actionPayload = payload;
        if(acceptType == "application/json"){
            paramValue.actionPayload = JSON.stringify(payload);
        }
        data.data = JSON.stringify(paramValue);
        $.ajax(data).fail(function (jqXHR) {
            if (jqXHR.status == "401") {
                console.log("Unauthorized access attempt!");
                $(modalPopupContent).html($('#error-msg').html());
                showPopup();
            } else {
                errorCallback(jqXHR);
            }
        });
    };
    return module;
}();
<commit_msg>adding JSON strigify on payload if contentType is json<commit_after>/*
 * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var invokerUtil = function () {

    var module = {};

    var END_POINT = window.location.origin+"/devicemgt/api/invoker/execute/";

    module.get = function (url, successCallback, errorCallback, contentType, acceptType) {
        var payload = null;
        execute("GET", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    module.post = function (url, payload, successCallback, errorCallback, contentType, acceptType) {
        execute("POST", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    module.put = function (url, payload, successCallback, errorCallback, contentType, acceptType) {
        execute("PUT", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    module.delete = function (url, successCallback, errorCallback, contentType, acceptType) {
        var payload = null;
        execute("DELETE", url, payload, successCallback, errorCallback, contentType, acceptType);
    };
    function execute (methoad, url, payload, successCallback, errorCallback, contentType, acceptType) {
        if(contentType == undefined){
            contentType = "application/json";
        }
        if(acceptType == undefined){
            acceptType = "application/json";
        }
        var data = {
            url: END_POINT,
            type: "POST",
            contentType: contentType,
            accept: acceptType,
            success: successCallback
        };
        console.log(data);
        var paramValue = {};
        paramValue.actionMethod = methoad;
        paramValue.actionUrl = url;
        paramValue.actionPayload = payload;
        if(contentType == "application/json"){
            paramValue.actionPayload = JSON.stringify(payload);
        }
        data.data = JSON.stringify(paramValue);
        $.ajax(data).fail(function (jqXHR) {
            if (jqXHR.status == "401") {
                console.log("Unauthorized access attempt!");
                $(modalPopupContent).html($('#error-msg').html());
                showPopup();
            } else {
                errorCallback(jqXHR);
            }
        });
    };
    return module;
}();
<|endoftext|>


<commit_before>/* @flow */

import { CompositeDisposable } from 'atom'
import Delegate from './delegate'
import PanelDock from './dock'
import type { LinterMessage } from '../types'

class Panel {
  panel: PanelDock | null
  element: HTMLElement
  delegate: Delegate
  messages: Array<LinterMessage>
  deactivating: boolean
  subscriptions: CompositeDisposable
  showPanelConfig: boolean
  hidePanelWhenEmpty: boolean
  showPanelStateMessages: boolean
  activationTimer: number
  constructor() {
    this.panel = null
    this.element = document.createElement('div')
    this.delegate = new Delegate()
    this.messages = []
    this.deactivating = false
    this.subscriptions = new CompositeDisposable()
    this.showPanelStateMessages = false

    this.subscriptions.add(this.delegate)
    this.subscriptions.add(
      atom.config.observe('linter-ui-default.hidePanelWhenEmpty', hidePanelWhenEmpty => {
        this.hidePanelWhenEmpty = hidePanelWhenEmpty
        this.refresh()
      }),
    )
    this.subscriptions.add(
      atom.workspace.onDidDestroyPaneItem(({ item: paneItem }) => {
        if (paneItem instanceof PanelDock && !this.deactivating) {
          this.panel = null
          atom.config.set('linter-ui-default.showPanel', false)
        }
      }),
    )
    this.subscriptions.add(
      atom.config.observe('linter-ui-default.showPanel', showPanel => {
        this.showPanelConfig = showPanel
        this.refresh()
      }),
    )
    this.subscriptions.add(
      atom.workspace.getCenter().observeActivePaneItem(() => {
        this.showPanelStateMessages = !!this.delegate.filteredMessages.length
        this.refresh()
      }),
    )
    this.activationTimer = window.requestIdleCallback(() => {
      this.activate()
    })
  }
  async activate() {
    if (this.panel) {
      return
    }
    this.panel = new PanelDock(this.delegate)
    await atom.workspace.open(this.panel, {
      activatePane: false,
      activateItem: false,
      searchAllPanes: true,
    })
    this.update()
    this.refresh()
  }
  update(newMessages: ?Array<LinterMessage> = null): void {
    if (newMessages) {
      this.messages = newMessages
    }
    this.delegate.update(this.messages)
    this.showPanelStateMessages = !!this.delegate.filteredMessages.length
    this.refresh()
  }
  async refresh() {
    const panel = this.panel
    if (panel === null) {
      if (this.showPanelConfig) {
        await this.activate()
      }
      return
    }
    const paneContainer = atom.workspace.paneContainerForItem(panel)
    if (!paneContainer || paneContainer.location !== 'bottom' || paneContainer.getActivePaneItem() !== panel) {
      return
    }
    if (this.showPanelConfig && (!this.hidePanelWhenEmpty || this.showPanelStateMessages)) {
      paneContainer.show()
    } else {
      paneContainer.hide()
    }
    panel.doPanelResize()
  }
  dispose() {
    this.deactivating = true
    if (this.panel) {
      this.panel.dispose()
    }
    this.subscriptions.dispose()
    window.cancelIdleCallback(this.activationTimer)
  }
}

module.exports = Panel
<commit_msg>:bug: Do not show panel again if user hid it<commit_after>/* @flow */

import { CompositeDisposable } from 'atom'
import Delegate from './delegate'
import PanelDock from './dock'
import type { LinterMessage } from '../types'

class Panel {
  panel: PanelDock | null
  element: HTMLElement
  delegate: Delegate
  messages: Array<LinterMessage>
  deactivating: boolean
  subscriptions: CompositeDisposable
  showPanelConfig: boolean
  hidePanelWhenEmpty: boolean
  showPanelStateMessages: boolean
  lastSetDockVisibility: boolean
  activationTimer: number
  constructor() {
    this.panel = null
    this.element = document.createElement('div')
    this.delegate = new Delegate()
    this.messages = []
    this.deactivating = false
    this.subscriptions = new CompositeDisposable()
    this.showPanelStateMessages = false
    this.lastSetDockVisibility = false

    this.subscriptions.add(this.delegate)
    this.subscriptions.add(
      atom.config.observe('linter-ui-default.hidePanelWhenEmpty', hidePanelWhenEmpty => {
        this.hidePanelWhenEmpty = hidePanelWhenEmpty
        this.refresh()
      }),
    )
    this.subscriptions.add(
      atom.workspace.onDidDestroyPaneItem(({ item: paneItem }) => {
        if (paneItem instanceof PanelDock && !this.deactivating) {
          this.panel = null
          atom.config.set('linter-ui-default.showPanel', false)
        }
      }),
    )
    this.subscriptions.add(
      atom.config.observe('linter-ui-default.showPanel', showPanel => {
        this.showPanelConfig = showPanel
        this.refresh()
      }),
    )
    this.subscriptions.add(
      atom.workspace.getCenter().observeActivePaneItem(() => {
        this.showPanelStateMessages = !!this.delegate.filteredMessages.length
        this.refresh()
      }),
    )
    this.activationTimer = window.requestIdleCallback(() => {
      this.activate()
    })
  }
  async activate() {
    if (this.panel) {
      return
    }
    this.panel = new PanelDock(this.delegate)
    await atom.workspace.open(this.panel, {
      activatePane: false,
      activateItem: false,
      searchAllPanes: true,
    })
    this.update()
    this.refresh()
  }
  update(newMessages: ?Array<LinterMessage> = null): void {
    if (newMessages) {
      this.messages = newMessages
    }
    this.delegate.update(this.messages)
    this.showPanelStateMessages = !!this.delegate.filteredMessages.length
    this.refresh()
  }
  async refresh() {
    const panel = this.panel
    if (panel === null) {
      if (this.showPanelConfig) {
        await this.activate()
      }
      return
    }
    const paneContainer = atom.workspace.paneContainerForItem(panel)
    if (!paneContainer || paneContainer.location !== 'bottom' || paneContainer.getActivePaneItem() !== panel) {
      return
    }
    if (this.showPanelConfig && (!this.hidePanelWhenEmpty || this.showPanelStateMessages)) {
      // NOTE: Don't show when user hide it on purpose
      if (this.lastSetDockVisibility === paneContainer.state.visible || paneContainer.state.visible) {
        paneContainer.show()
        this.lastSetDockVisibility = true
      }
    } else {
      paneContainer.hide()
      this.lastSetDockVisibility = true
    }
    panel.doPanelResize()
  }
  dispose() {
    this.deactivating = true
    if (this.panel) {
      this.panel.dispose()
    }
    this.subscriptions.dispose()
    window.cancelIdleCallback(this.activationTimer)
  }
}

module.exports = Panel
<|endoftext|>


<commit_before>/* jshint node:true */
'use strict';

/**
 * Module dependencies.
 */
var os = require('os');
var _ = require('underscore');
var Transform = require('stream').Transform;
var joinRows = require('../core/join-rows');

class Parser {
  constructor(options) {
    this._options = this._parseOptions(options) || {};
    this._headers = this._options.headers || [];
    this._escape = require('../core/escape-delimiters')(
      this._options.textDelimiter,
      this._options.rowDelimiter
    );
  }

  /**
   * Generates a CSV file with optional headers based on the passed JSON,
   * with can be an Object or Array.
   *
   * @param {Object|Array} json
   * @param {Function} done(err,csv) - Callback function
   *      if error, returning error in call back.
   *      if csv is created successfully, returning csv output to callback.
   */
  parse(json, done, stream) {
    if (_.isArray(json)) return done(null, this._parseArray(json, stream));
    else if (_.isObject(json)) return done(null, this._parseObject(json));
    return done(new Error('Unable to parse the JSON object, its not an Array or Object.'));
  }

  get headers() {
    let headers = this._headers;
    if(this._options.rename && this._options.rename.length > 0)
      headers = headers.map((header) => this._options.rename[this._options.headers.indexOf(header)] || header)
    return headers.join(this._options.rowDelimiter);
  }

  _parseArray(json, stream) {
    let self = this;
    this._headers = this._headers || [];
    let fileRows = [];
    let outputFile;
    let fillRows;

    let getHeaderIndex = function(header) {
      let index = self._headers.indexOf(header);
      if (index === -1) {
        self._headers.push(header);
        index = self._headers.indexOf(header);
      }
      return index;
    };

    //Generate the csv headers based on prop usage over the elements
    //var headers = generateHeaders(parseResult, options.orderHeaders);
    //Generate the csv output
    fillRows = function(result) {
      //Initialize the array with empty strings to handle 'unpopular' headers
      let rows = [Array(self._headers.length).join(".").split(".")];
      for(let element of result){
        let elementHeaderIndex = getHeaderIndex(element.item);
        let placed = false;
        for(let row of rows){
          if (!placed && row[elementHeaderIndex] === '' || row[elementHeaderIndex] === undefined) {
            row[elementHeaderIndex] = self._escape(element.value);
            placed = true;
            break;
          }
        }
        if (!placed) {
          let newRow = Array(self._headers.length).join(".").split(".");
          newRow[elementHeaderIndex] = self._escape(element.value);
          rows.push(newRow);
        }
      }
      let lastRow = null;
      for(let row of rows){
        let missing = self._headers.length - row.length;
        if(missing > 0) row = row.concat(Array(missing).join(".").split("."));
        if(lastRow && self._options.fillGaps) row = row.map((col, index) => col === '' || col === undefined ? lastRow[index] : col);
        fileRows.push(row.join(self._options.rowDelimiter));
        lastRow = row;
      }
    };
    for(let item of json){
      //Call checkType to list all items inside this object
      //Items are returned as a object {item: 'Prop Value, Item Name',

      //                                value: 'Prop Data Value'}
      let itemResult = self._checkType(item, self._options.mainPathItem);
      fillRows(itemResult);
    }

    if (!stream && self._options.includeHeaders) {
      //Add the headers to the first line
      fileRows.unshift(this.headers);
    }

    return joinRows(fileRows, self._options.endOfLine);
  }

  _parseObject(json) {
    let self = this;
    let fileRows = [];
    let parseResult = [];
    let outputFile;
    let fillRows;
    let horizontalRows = [
      [],
      []
    ];

    fillRows = function(result) {
      var value = result.value ? result.value.toString() : self._options.undefinedString;
      value = self._escape(value);

      //Type header;value
      if (self._options.verticalOutput) {
        var row = [result.item, value];
        fileRows.push(row.join(self._options.rowDelimiter));
      } else {
        horizontalRows[0].push(result.item);
        horizontalRows[1].push(value);
      }
    };
    for (var prop in json) {
      var prefix = "";
      if (this._options.mainPathItem)
        prefix = this._options.mainPathItem + this._options.headerPathString;
      parseResult = this._checkType(json[prop], prefix + prop);

      parseResult.forEach(fillRows);
    }
    if (!this._options.verticalOutput) {
      fileRows.push(horizontalRows[0].join(this._options.rowDelimiter));
      fileRows.push(horizontalRows[1].join(this._options.rowDelimiter));
    }
    return joinRows(fileRows, this._options.endOfLine);
  }

  _setHeaders(result, item) {
    let self = this;
    if (!item) return result;
    return result.map(function(element) {
      element.item = element.item ? item + self._options.headerPathString + element.item : item;
      return element;
    });
  }

  /**
   * Check the element type of the element call the correct handle function
   *
   * @param element Element that will be checked
   * @param item Used to make the headers/path breadcrumb
   */
  _checkType(element, item) {
    let result;
    //Check if element is a String
    if (_.isString(element)) {
      result = [{
        item: item,
        value: this._options.handleString(element, item),
      }];
    }
    //Check if element is a Number
    else if (_.isNumber(element)) {
      result = [{
        item: item,
        value: this._options.handleNumber(element, item),
      }];
    }
    //Check if element is a Boolean
    else if (_.isBoolean(element)) {
      result = [{
        item: item,
        value: this._options.handleBoolean(element, item),
      }];
    }
    //Check if element is a Date
    else if (_.isDate(element)) {
      result = [{
        item: item,
        value: this._options.handleDate(element, item),
      }];
    }
    //Check if element is an Array
    else if (_.isArray(element)) {
      var resultArray = this._handleArray(element, item);
      result = this._setHeaders(resultArray, item);
    }
    //Check if element is a Object
    else if (_.isObject(element)) {
      var resultObject = this._handleObject(element, item);
      result = this._setHeaders(resultObject, item);
    } else {
      result = [{
        item: item,
        value: '',
      }];
    }
    return result;
  }

  /**
   * Handle all Objects
   *
   * @param {Object} obj
   * @returns {Array} result
   */
  _handleObject(obj) {
    var result = [];
    //Look every object props
    for (var prop in obj) {
      var propData = obj[prop];
      //Check the propData type
      var resultCheckType = this._checkType(propData, prop);
      //Append to results
      result = result.concat(resultCheckType);
    }
    return result;
  }
  /**
   * Handle all Arrays, merges arrays with primitive types in a single value
   *
   * @param {Array} array
   * @returns {Array} result
   */
  _handleArray(array) {
    let self = this;
    let result = [];
    for(let element of array){
      //Check the propData type
      var resultCheckType = self._checkType(element);

      //Append to results
      result = result.concat(resultCheckType);
    }
    //Check for results without itens, merge all itens with the first occurrence
    var firstElementWithoutItem;
    result = result.filter(function(resultElement, resultIndex) {
      //Check if there is a firstElement and if the current element dont have a item
      if (!resultElement.item && firstElementWithoutItem !== undefined) {
        //Append the value to the firstElementWithoutItem.
        result[firstElementWithoutItem].value += self._options.arrayPathString + resultElement.value;
        //Remove the item
        return false;
      }
      //Set the firstElement if its not set
      if (!firstElementWithoutItem && !resultElement.item)
        firstElementWithoutItem = resultIndex;
      //Keep the item in the array
      return true;
    });
    return result;
  }
  /**
   * Handle all Boolean variables, can be replaced with options.handleBoolean
   *
   * @param {Boolean} boolean
   * @returns {String} result
   */
  _handleBoolean(boolean) {
    var result;
    //Check for booolean options
    if (boolean) {
      result = this.booleanTrueString || 'true';
    } else {
      result = this.booleanFalseString || 'false';
    }
    return result;
  }
  /**
   * Handle all String variables, can be replaced with options.handleString
   *
   * @param {String} string
   * @returns {String} string
   */
  _handleString(string) {
    return string;
  }
  /**
   * Handle all Number variables, can be replaced with options.handleNumber
   *
   * @param {Number} number
   * @returns {Number} number
   */
  _handleNumber(number) {
    return number;
  }
  /**
   * Handle all Date variables, can be replaced with options.handleDate
   *
   * @param {Date} number
   * @returns {string} result
   */
  _handleDate(date) {
    return date.toLocaleDateString();
  }

  /**
   * Replaces the default options with the custom user options
   *
   * @param {Options} userOptions
   */
  _parseOptions(userOptions) {

    /**
     * Default options
     */
    let defaultOptions = {
      headers: [],//                  Array
      rename: [],//                   Array
      headerPathString: '.', //       String
      rowDelimiter: ',', //           String
      textDelimiter: '"', //          String
      arrayPathString: ';', //        String
      undefinedString: '', //         String
      endOfLine: os.EOL || '\n', //   String
      mainPathItem: null, //          String
      booleanTrueString: null, //     String
      booleanFalseString: null, //    String
      includeHeaders: true, //        Boolean
      fillGaps: false, //             Boolean
      verticalOutput: true, //        Boolean
      //Handlers
      handleString: this._handleString, //          Function
      handleNumber: this._handleNumber, //          Function
      handleBoolean: this._handleBoolean, //        Function
      handleDate: this._handleDate, //              Function
    };
    return _.extend(defaultOptions, userOptions);
  }
}

module.exports = Parser;
<commit_msg>_handleArray performace update<commit_after>/* jshint node:true */
'use strict';

/**
 * Module dependencies.
 */
var os = require('os');
var _ = require('underscore');
var Transform = require('stream').Transform;
var joinRows = require('../core/join-rows');

class Parser {
  constructor(options) {
    this._options = this._parseOptions(options) || {};
    this._headers = this._options.headers || [];
    this._escape = require('../core/escape-delimiters')(
      this._options.textDelimiter,
      this._options.rowDelimiter
    );
  }

  /**
   * Generates a CSV file with optional headers based on the passed JSON,
   * with can be an Object or Array.
   *
   * @param {Object|Array} json
   * @param {Function} done(err,csv) - Callback function
   *      if error, returning error in call back.
   *      if csv is created successfully, returning csv output to callback.
   */
  parse(json, done, stream) {
    if (_.isArray(json)) return done(null, this._parseArray(json, stream));
    else if (_.isObject(json)) return done(null, this._parseObject(json));
    return done(new Error('Unable to parse the JSON object, its not an Array or Object.'));
  }

  get headers() {
    let headers = this._headers;
    if (this._options.rename && this._options.rename.length > 0)
      headers = headers.map((header) => this._options.rename[this._options.headers.indexOf(header)] || header)
    return headers.join(this._options.rowDelimiter);
  }

  _parseArray(json, stream) {
    let self = this;
    this._headers = this._headers || [];
    let fileRows = [];
    let outputFile;
    let fillRows;

    let getHeaderIndex = function(header) {
      var index = self._headers.indexOf(header);
      if (index === -1) {
        self._headers.push(header);
        index = self._headers.indexOf(header);
      }
      return index;
    };

    //Generate the csv headers based on prop usage over the elements
    //var headers = generateHeaders(parseResult, options.orderHeaders);
    //Generate the csv output
    fillRows = function(result) {
      //Initialize the array with empty strings to handle 'unpopular' headers
      let rows = [Array(self._headers.length).join(".").split(".")];
      for (let element of result) {
        let elementHeaderIndex = getHeaderIndex(element.item);
        let placed = false;
        for (let row of rows) {
          if (!placed && row[elementHeaderIndex] === '' || row[elementHeaderIndex] === undefined) {
            row[elementHeaderIndex] = self._escape(element.value);
            placed = true;
            break;
          }
        }
        if (!placed) {
          let newRow = Array(self._headers.length).join(".").split(".");
          newRow[elementHeaderIndex] = self._escape(element.value);
          rows.push(newRow);
        }
      }
      let lastRow = null;
      for (let row of rows) {
        let missing = self._headers.length - row.length;
        if (missing > 0) row = row.concat(Array(missing).join(".").split("."));
        if (lastRow && self._options.fillGaps) row = row.map((col, index) => col === '' || col === undefined ? lastRow[index] : col);
        fileRows.push(row.join(self._options.rowDelimiter));
        lastRow = row;
      }
    };
    for (let item of json) {
      //Call checkType to list all items inside this object
      //Items are returned as a object {item: 'Prop Value, Item Name',

      //                                value: 'Prop Data Value'}
      let itemResult = self._checkType(item, self._options.mainPathItem);
      fillRows(itemResult);
    }

    if (!stream && self._options.includeHeaders) {
      //Add the headers to the first line
      fileRows.unshift(this.headers);
    }

    return joinRows(fileRows, self._options.endOfLine);
  }

  _parseObject(json) {
    let self = this;
    let fileRows = [];
    let parseResult = [];
    let outputFile;
    let fillRows;
    let horizontalRows = [
      [],
      []
    ];

    fillRows = function(result) {
      var value = result.value ? result.value.toString() : self._options.undefinedString;
      value = self._escape(value);

      //Type header;value
      if (self._options.verticalOutput) {
        var row = [result.item, value];
        fileRows.push(row.join(self._options.rowDelimiter));
      } else {
        horizontalRows[0].push(result.item);
        horizontalRows[1].push(value);
      }
    };
    for (var prop in json) {
      var prefix = "";
      if (this._options.mainPathItem)
        prefix = this._options.mainPathItem + this._options.headerPathString;
      parseResult = this._checkType(json[prop], prefix + prop);

      parseResult.forEach(fillRows);
    }
    if (!this._options.verticalOutput) {
      fileRows.push(horizontalRows[0].join(this._options.rowDelimiter));
      fileRows.push(horizontalRows[1].join(this._options.rowDelimiter));
    }
    return joinRows(fileRows, this._options.endOfLine);
  }

  _setHeaders(result, item) {
    let self = this;
    if (!item) return result;
    return result.map(function(element) {
      element.item = element.item ? item + self._options.headerPathString + element.item : item;
      return element;
    });
  }

  /**
   * Check the element type of the element call the correct handle function
   *
   * @param element Element that will be checked
   * @param item Used to make the headers/path breadcrumb
   */
  _checkType(element, item) {
    let result;
    //Check if element is a String
    if (_.isString(element)) {
      result = [{
        item: item,
        value: this._options.handleString(element, item),
      }];
    }
    //Check if element is a Number
    else if (_.isNumber(element)) {
      result = [{
        item: item,
        value: this._options.handleNumber(element, item),
      }];
    }
    //Check if element is a Boolean
    else if (_.isBoolean(element)) {
      result = [{
        item: item,
        value: this._options.handleBoolean(element, item),
      }];
    }
    //Check if element is a Date
    else if (_.isDate(element)) {
      result = [{
        item: item,
        value: this._options.handleDate(element, item),
      }];
    }
    //Check if element is an Array
    else if (_.isArray(element)) {
      var resultArray = this._handleArray(element, item);
      result = this._setHeaders(resultArray, item);
    }
    //Check if element is a Object
    else if (_.isObject(element)) {
      var resultObject = this._handleObject(element, item);
      result = this._setHeaders(resultObject, item);
    } else {
      result = [{
        item: item,
        value: '',
      }];
    }
    return result;
  }

  /**
   * Handle all Objects
   *
   * @param {Object} obj
   * @returns {Array} result
   */
  _handleObject(obj) {
    var result = [];
    //Look every object props
    for (var prop in obj) {
      var propData = obj[prop];
      //Check the propData type
      var resultCheckType = this._checkType(propData, prop);
      //Append to results
      result = result.concat(resultCheckType);
    }
    return result;
  }
  /**
   * Handle all Arrays, merges arrays with primitive types in a single value
   *
   * @param {Array} array
   * @returns {Array} result
   */
  _handleArray(array) {
    let self = this;
    let result = [];
    var firstElementWithoutItem;
    for (let element of array) {
      //Check the propData type
      var resultCheckType = self._checkType(element);
      //Check for results without itens, merge all itens with the first occurrence
      if(resultCheckType.length === 0) continue;
      var firstResult = resultCheckType[0];
      if (!firstResult.item && firstElementWithoutItem !== undefined) {
        firstElementWithoutItem.value += self._options.arrayPathString + firstResult.value;
        continue;
      } else if (resultCheckType.length > 0 && !firstResult.item && firstElementWithoutItem === undefined) {
        firstElementWithoutItem = firstResult;
      }
      //Append to results
      result = result.concat(resultCheckType);
    }
    return result;
  }
  /**
   * Handle all Boolean variables, can be replaced with options.handleBoolean
   *
   * @param {Boolean} boolean
   * @returns {String} result
   */
  _handleBoolean(boolean) {
    var result;
    //Check for booolean options
    if (boolean) {
      result = this.booleanTrueString || 'true';
    } else {
      result = this.booleanFalseString || 'false';
    }
    return result;
  }
  /**
   * Handle all String variables, can be replaced with options.handleString
   *
   * @param {String} string
   * @returns {String} string
   */
  _handleString(string) {
    return string;
  }
  /**
   * Handle all Number variables, can be replaced with options.handleNumber
   *
   * @param {Number} number
   * @returns {Number} number
   */
  _handleNumber(number) {
    return number;
  }
  /**
   * Handle all Date variables, can be replaced with options.handleDate
   *
   * @param {Date} number
   * @returns {string} result
   */
  _handleDate(date) {
    return date.toLocaleDateString();
  }

  /**
   * Replaces the default options with the custom user options
   *
   * @param {Options} userOptions
   */
  _parseOptions(userOptions) {

    /**
     * Default options
     */
    let defaultOptions = {
      headers: [], //                  Array
      rename: [], //                   Array
      headerPathString: '.', //       String
      rowDelimiter: ',', //           String
      textDelimiter: '"', //          String
      arrayPathString: ';', //        String
      undefinedString: '', //         String
      endOfLine: os.EOL || '\n', //   String
      mainPathItem: null, //          String
      booleanTrueString: null, //     String
      booleanFalseString: null, //    String
      includeHeaders: true, //        Boolean
      fillGaps: false, //             Boolean
      verticalOutput: true, //        Boolean
      //Handlers
      handleString: this._handleString, //          Function
      handleNumber: this._handleNumber, //          Function
      handleBoolean: this._handleBoolean, //        Function
      handleDate: this._handleDate, //              Function
    };
    return _.extend(defaultOptions, userOptions);
  }
}

module.exports = Parser;
<|endoftext|>


<commit_before>function initTask(subTask) {

    subTask.gridInfos = {
        hideSaveOrLoad: false,
        actionDelay: 200,
        buttonScaleDrawing: false,

        includeBlocks: {
            groupByCategory: true,
            generatedBlocks: {
                database: [
                    'loadTable',
                    'loadTableFromCsv',
                    'joinTables',
                    'displayTable',
                    'unionTables',
                    'displayRecord',
                    'getColumn',
                    'displayTableOnMap',
                    'getRecords',
                    'selectByColumn',
                    'selectByFunction',
                    'sortByColumn',
                    'sortByFunction',
                    'selectColumns',
                    'updateWhere',
                    'insertRecord'
                ]
            },
            standardBlocks: {
                includeAll: true
            }
        },
        maxInstructions: 100,
        checkEndEveryTurn: false,
        checkEndCondition: function(context, lastTurn) {
            // subTask.data.easy.tables
            if(context.expectTable('valid_table')) {
                context.success = true;
                throw(strings.complete);
            }
        },
        databaseOptions: {
            render_row_height: '20px',
            render_max_rows: 10,
        },
        example: {
           blockly: '<xml xmlns="http://www.w3.org/1999/xhtml"><block type="robot_start" id="cwD?Km9#D6D_9NH{A6z." deletable="false" movable="false" editable="false" x="0" y="0"><next><block type="variables_set" id="a]yR,?2V:Y{m[l@LB21d"><field name="VAR">testTable</field><value name="VALUE"><block type="loadTable" id="fk_p6Sad,f:)m!aga1=/"><value name="PARAM_0"><shadow type="text" id="kzOpIV1e?gT;WG;vkW(0"><field name="TEXT">test_table</field></shadow></value></block></value><next><block type="displayTable" id=",`vFND|DG-thvpo?[!*h"><value name="PARAM_0"><block type="variables_get" id="eX}C#H;I@ep@`krGs._m"><field name="VAR">testTable</field></block></value><value name="PARAM_1"><block type="lists_create_with" id="eJck9xqe(BAu+[+YwNzR"><mutation items="4"></mutation><value name="ADD0"><block type="text" id="~(IMsSdX=oJfbw:F;prx"><field name="TEXT">id</field></block></value><value name="ADD1"><block type="text" id="!vX`z7e]|Vwz)sj*~)dN"><field name="TEXT">image</field></block></value><value name="ADD2"><block type="text" id="s6GeqLT,t)Znb::/f=r;"><field name="TEXT">name</field></block></value><value name="ADD3"><block type="text" id="h!`nE@pJO#)gvd@HEc7U"><field name="TEXT">date</field></block></value></block></value></block></next></block></next></block></xml>'
        }
    }

    var test_table = {
        columnNames: [
            'id', 'image', 'name', 'date'
        ],
        columnTypes: [
            'number', 'image', 'string', 'date'
        ],
        records: [
            [ 1, 'img/apple.jpg', 'apple', '2018-01-01' ],
            [ 2, 'img/banana.jpg', 'banana', '2019-01-01' ],
            [ 3, 'img/kiwi.jpg', 'kiwi', '2020-01-01' ],
            [ 4, null, 'null_image_here_null_image_here_null_image_here_null_image_here', '2021-01-01' ],
        ]
    }

    var valid_table = {
        columnNames: [
            'id', 'image', 'name', 'date'
        ],
        columnTypes: [
            'number', 'image', 'string', 'date'
        ],
        records: [
            [ 1, 'img/apple.jpg', 'apple', '2018-01-01' ],
            [ 2, 'img/banana.jpg', 'banana', '2019-01-01' ],
            [ 3, 'img/kiwi.jpg', 'kiwi', '2020-01-01' ]
        ]
    }

    subTask.data = {
        easy: [{
            tables: {
                test_table: test_table,
                valid_table: valid_table
            }
        }]
    }
    initBlocklySubTask(subTask)
}
initWrapper(initTask, null, null)<commit_msg>remove limit on number of instructions, hide validate button<commit_after>function initTask(subTask) {

    subTask.gridInfos = {
        hideSaveOrLoad: false,
        actionDelay: 200,
        buttonScaleDrawing: false,
        hideValidate: true,

        includeBlocks: {
            groupByCategory: true,
            generatedBlocks: {
                database: [
                    'loadTable',
                    'loadTableFromCsv',
                    'joinTables',
                    'displayTable',
                    'unionTables',
                    'displayRecord',
                    'getColumn',
                    'displayTableOnMap',
                    'getRecords',
                    'selectByColumn',
                    'selectByFunction',
                    'sortByColumn',
                    'sortByFunction',
                    'selectColumns',
                    'updateWhere',
                    'insertRecord'
                ]
            },
            standardBlocks: {
                includeAll: true
            }
        },
        maxInstructions: 0,
        checkEndEveryTurn: false,
        checkEndCondition: function(context, lastTurn) {
            // subTask.data.easy.tables
            if(context.expectTable('valid_table')) {
                context.success = true;
                throw(strings.complete);
            }
        },
        databaseOptions: {
            render_row_height: '20px',
            render_max_rows: 10,
        },
        example: {
           blockly: '<xml xmlns="http://www.w3.org/1999/xhtml"><block type="robot_start" id="cwD?Km9#D6D_9NH{A6z." deletable="false" movable="false" editable="false" x="0" y="0"><next><block type="variables_set" id="a]yR,?2V:Y{m[l@LB21d"><field name="VAR">testTable</field><value name="VALUE"><block type="loadTable" id="fk_p6Sad,f:)m!aga1=/"><value name="PARAM_0"><shadow type="text" id="kzOpIV1e?gT;WG;vkW(0"><field name="TEXT">test_table</field></shadow></value></block></value><next><block type="displayTable" id=",`vFND|DG-thvpo?[!*h"><value name="PARAM_0"><block type="variables_get" id="eX}C#H;I@ep@`krGs._m"><field name="VAR">testTable</field></block></value><value name="PARAM_1"><block type="lists_create_with" id="eJck9xqe(BAu+[+YwNzR"><mutation items="4"></mutation><value name="ADD0"><block type="text" id="~(IMsSdX=oJfbw:F;prx"><field name="TEXT">id</field></block></value><value name="ADD1"><block type="text" id="!vX`z7e]|Vwz)sj*~)dN"><field name="TEXT">image</field></block></value><value name="ADD2"><block type="text" id="s6GeqLT,t)Znb::/f=r;"><field name="TEXT">name</field></block></value><value name="ADD3"><block type="text" id="h!`nE@pJO#)gvd@HEc7U"><field name="TEXT">date</field></block></value></block></value></block></next></block></next></block></xml>'
        }
    }

    var test_table = {
        columnNames: [
            'id', 'image', 'name', 'date'
        ],
        columnTypes: [
            'number', 'image', 'string', 'date'
        ],
        records: [
            [ 1, 'img/apple.jpg', 'apple', '2018-01-01' ],
            [ 2, 'img/banana.jpg', 'banana', '2019-01-01' ],
            [ 3, 'img/kiwi.jpg', 'kiwi', '2020-01-01' ],
            [ 4, null, 'null_image_here_null_image_here_null_image_here_null_image_here', '2021-01-01' ],
        ]
    }

    var valid_table = {
        columnNames: [
            'id', 'image', 'name', 'date'
        ],
        columnTypes: [
            'number', 'image', 'string', 'date'
        ],
        records: [
            [ 1, 'img/apple.jpg', 'apple', '2018-01-01' ],
            [ 2, 'img/banana.jpg', 'banana', '2019-01-01' ],
            [ 3, 'img/kiwi.jpg', 'kiwi', '2020-01-01' ]
        ]
    }

    subTask.data = {
        easy: [{
            tables: {
                test_table: test_table,
                valid_table: valid_table
            }
        }]
    }
    initBlocklySubTask(subTask)
}
initWrapper(initTask, null, null)<|endoftext|>


<commit_before>/*
  Created by: Anton Debner 2016
*/

var WIDTH=1000, HEIGHT=600, pi=Math.PI;
var UpArrow=38, DownArrow=40, LeftArrow=37, RightArrow=39;
var canvas, ctx, keystate;
var tank;

class Tank {

  constructor() {
    this.x = 10;
    this.y = 10;
    this.color = "#000";
    this.size = 10;
  }

  update() {
    if (keystate[UpArrow]) this.y -= 1;
    else if (keystate[DownArrow]) this.y += 1;
    if (keystate[LeftArrow]) this.x -= 1;
    else if (keystate[RightArrow]) this.x += 1;
  }

  draw() {
    var x = this.x;
    var y = this.y;
    var s = this.size/2;
    ctx.fillRect(x-s, y-s, s*2, s*2);
  }

};

function main() {
  /*
    Creates a new HTML5 canvas element, adds listeners for input and
    contains the main loop.
  */
  canvas = document.createElement("canvas")
  canvas.width = WIDTH;
  canvas.height = HEIGHT;
  ctx = canvas.getContext("2d");

  // Attempt to find a document element with specific id, otherwise attach the
  // canvas to document body.
  attach_to = document.getElementById('game_window');
  if (attach_to == null)
  {
      attach_to = document.body;
  }
  attach_to.appendChild(canvas);

  // Add listeners for keydown and keyup
  keystate = {};
  document.addEventListener("keydown", function(evt) {
    if (evt.keyCode === UpArrow || evt.keyCode === DownArrow) {
      // Prevent up and down arrows from scrolling the website
      evt.preventDefault();
    }
    keystate[evt.keyCode] = true;
  });

  document.addEventListener("keyup", function(evt) {
    delete keystate[evt.keyCode];
  });

  tank = new Tank();

  init();
  var loop = function() {
    /*
      The main loop where all the magic happens.
    */
    update();
    draw();
    window.requestAnimationFrame(loop, canvas);
  };
  window.requestAnimationFrame(loop, canvas);
}

function init() {
  /*
    Sets gameobjects to their starting values.
  */
  keystate = {}; // Reset the keystate to avoid stuck buttons
}

function update() {
  /*
    Handles game logic by moving all objects and checking collisions.
  */
  tank.update();
}

function draw() {
  /*
    Handles all drawing on the HTML5 canvas.
  */
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, WIDTH, HEIGHT);
  ctx.save(); // Save current drawing state

  // Draw borders
  ctx.fillStyle = "#000";
  ctx.moveTo(0,0);
  ctx.lineTo(WIDTH, 0);
  ctx.lineTo(WIDTH, HEIGHT);
  ctx.lineTo(0, HEIGHT);
  ctx.lineTo(0, 0);
  ctx.stroke();

  tank.draw();

  ctx.restore(); // Restore saved drawing state
}

main();
<commit_msg>Implement tank-like movement with turning and forward/reverse<commit_after>/*
  Created by: Anton Debner 2016
*/

var WIDTH=1000, HEIGHT=600, pi=Math.PI;
var UpArrow=38, DownArrow=40, LeftArrow=37, RightArrow=39;
var canvas, ctx, keystate;
var tank;

class Tank {

  constructor() {
    this.x = 10;
    this.y = 10;
    this.color = "#000";
    this.size = 10;
    this.dir = 0; // degrees
    this.speed = 1;
    this.turn_speed = 5;
  }

  update() {
    var radians = this.dir * (Math.PI/180);
    if (keystate[UpArrow]) {
      this.x -= this.speed * Math.sin(radians);
      this.y -= this.speed * Math.cos(radians);
    }
    else if (keystate[DownArrow]) {
      this.x += this.speed * Math.sin(radians);
      this.y += this.speed * Math.cos(radians);
    }
    if (keystate[LeftArrow]) {
      this.dir += this.turn_speed;
      if (this.dir >= 360) this.dir -= 360;
    }
    else if (keystate[RightArrow]) {
      this.dir -= this.turn_speed;
      if (this.dir < 0) this.dir += 360;
    }
  }

  draw() {
    var x = this.x;
    var y = this.y;
    var s = this.size/2;
    ctx.save();
    ctx.translate(x, y);
    ctx.rotate(-this.dir * (Math.PI/180));
    ctx.fillRect(-s, -s, s*2, s*2);
    ctx.fillRect(-s/2, -s*2, s, s*2);
    ctx.restore();
  }

};

function main() {
  /*
    Creates a new HTML5 canvas element, adds listeners for input and
    contains the main loop.
  */
  canvas = document.createElement("canvas")
  canvas.width = WIDTH;
  canvas.height = HEIGHT;
  ctx = canvas.getContext("2d");

  // Attempt to find a document element with specific id, otherwise attach the
  // canvas to document body.
  attach_to = document.getElementById('game_window');
  if (attach_to == null)
  {
      attach_to = document.body;
  }
  attach_to.appendChild(canvas);

  // Add listeners for keydown and keyup
  keystate = {};
  document.addEventListener("keydown", function(evt) {
    if (evt.keyCode === UpArrow || evt.keyCode === DownArrow) {
      // Prevent up and down arrows from scrolling the website
      evt.preventDefault();
    }
    keystate[evt.keyCode] = true;
  });

  document.addEventListener("keyup", function(evt) {
    delete keystate[evt.keyCode];
  });

  tank = new Tank();

  init();
  var loop = function() {
    /*
      The main loop where all the magic happens.
    */
    update();
    draw();
    window.requestAnimationFrame(loop, canvas);
  };
  window.requestAnimationFrame(loop, canvas);
}

function init() {
  /*
    Sets gameobjects to their starting values.
  */
  keystate = {}; // Reset the keystate to avoid stuck buttons
}

function update() {
  /*
    Handles game logic by moving all objects and checking collisions.
  */
  tank.update();
}

function draw() {
  /*
    Handles all drawing on the HTML5 canvas.
  */
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, WIDTH, HEIGHT);
  //ctx.save(); // Save current drawing state

  // Draw borders
  ctx.fillStyle = "#000";
  ctx.moveTo(0,0);
  ctx.lineTo(WIDTH, 0);
  ctx.lineTo(WIDTH, HEIGHT);
  ctx.lineTo(0, HEIGHT);
  ctx.lineTo(0, 0);
  ctx.stroke();

  tank.draw();

  //ctx.restore(); // Restore saved drawing state
}

main();
<|endoftext|>


<commit_before>/* global APP, $ */

import {processReplacements, linkify} from './Replacement';
import CommandsProcessor from './Commands';
import ToolbarToggler from '../../toolbars/ToolbarToggler';
import VideoLayout from "../../videolayout/VideoLayout";

import UIUtil from '../../util/UIUtil';
import UIEvents from '../../../../service/UI/UIEvents';

import { smileys } from './smileys';

let unreadMessages = 0;
const sidePanelsContainerId = 'sideToolbarContainer';
const htmlStr = `

            <form>
                <input type='text'
                       class="input-control" id="nickinput" autofocus
                    data-i18n="[placeholder]chat.nickname.popover">
            </form>

        <audio id="chatNotification" src="sounds/incomingMessage.wav"
            preload="auto"></audio>
        <textarea id="usermsg" autofocus
            data-i18n="[placeholder]chat.messagebox"></textarea>

`;

function initHTML() {
    $(`#${sidePanelsContainerId}`)
        .append(htmlStr);
}

/**
 * The container id, which is and the element id.
 */
var CHAT_CONTAINER_ID = "chat_container";

/**
 *  Updates visual notification, indicating that a message has arrived.
 */
function updateVisualNotification() {
    var unreadMsgElement = document.getElementById('unreadMessages');

    if (unreadMessages) {
        unreadMsgElement.innerHTML = unreadMessages.toString();

        ToolbarToggler.dockToolbar(true);

        var chatButtonElement
            = document.getElementById('toolbar_button_chat');
        var leftIndent = (UIUtil.getTextWidth(chatButtonElement) -
            UIUtil.getTextWidth(unreadMsgElement)) / 2;
        var topIndent = (UIUtil.getTextHeight(chatButtonElement) -
            UIUtil.getTextHeight(unreadMsgElement)) / 2 - 5;

        unreadMsgElement.setAttribute(
            'style',
                'top:' + topIndent +
                '; left:' + leftIndent + ';');
    }
    else {
        unreadMsgElement.innerHTML = '';
    }

    $(unreadMsgElement).parent()[unreadMessages > 0 ? 'show' : 'hide']();
}

/**
 * Returns the current time in the format it is shown to the user
 * @returns {string}
 */
function getCurrentTime(stamp) {
    var now     = (stamp? new Date(stamp): new Date());
    var hour    = now.getHours();
    var minute  = now.getMinutes();
    var second  = now.getSeconds();
    if(hour.toString().length === 1) {
        hour = '0'+hour;
    }
    if(minute.toString().length === 1) {
        minute = '0'+minute;
    }
    if(second.toString().length === 1) {
        second = '0'+second;
    }
    return hour+':'+minute+':'+second;
}

function toggleSmileys() {
    var smileys = $('#smileysContainer');
    if(!smileys.is(':visible')) {
        smileys.show("slide", { direction: "down", duration: 300});
    } else {
        smileys.hide("slide", { direction: "down", duration: 300});
    }
    $('#usermsg').focus();
}

function addClickFunction(smiley, number) {
    smiley.onclick = function addSmileyToMessage() {
        var usermsg = $('#usermsg');
        var message = usermsg.val();
        message += smileys['smiley' + number];
        usermsg.val(message);
        usermsg.get(0).setSelectionRange(message.length, message.length);
        toggleSmileys();
        usermsg.focus();
    };
}

/**
 * Adds the smileys container to the chat
 */
function addSmileys() {
    var smileysContainer = document.createElement('div');
    smileysContainer.id = 'smileysContainer';
    for(var i = 1; i <= 21; i++) {
        var smileyContainer = document.createElement('div');
        smileyContainer.id = 'smiley' + i;
        smileyContainer.className = 'smileyContainer';
        var smiley = document.createElement('img');
        smiley.src = 'images/smileys/smiley' + i + '.svg';
        smiley.className =  'smiley';
        addClickFunction(smiley, i);
        smileyContainer.appendChild(smiley);
        smileysContainer.appendChild(smileyContainer);
    }

    $("#chat_container").append(smileysContainer);
}

/**
 * Resizes the chat conversation.
 */
function resizeChatConversation() {
    var msgareaHeight = $('#usermsg').outerHeight();
    var chatspace = $('#' + CHAT_CONTAINER_ID);
    var width = chatspace.width();
    var chat = $('#chatconversation');
    var smileys = $('#smileysarea');

    smileys.height(msgareaHeight);
    $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
    $('#smileysContainer').css('bottom', msgareaHeight);
    chat.width(width - 10);
    chat.height(window.innerHeight - 15 - msgareaHeight);
}

/**
 * Chat related user interface.
 */
var Chat = {
    /**
     * Initializes chat related interface.
     */
    init (eventEmitter) {
        initHTML();
        if (APP.settings.getDisplayName()) {
            Chat.setChatConversationMode(true);
        }

        $("#toggle_smileys").click(function() {
            Chat.toggleSmileys();
        });

        $('#nickinput').keydown(function (event) {
            if (event.keyCode === 13) {
                event.preventDefault();
                let val = this.value;
                this.value = '';
                eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
            }
        });

        var usermsg = $('#usermsg');
        usermsg.keydown(function (event) {
            if (event.keyCode === 13) {
                event.preventDefault();
                var value = this.value;
                usermsg.val('').trigger('autosize.resize');
                this.focus();
                var command = new CommandsProcessor(value, eventEmitter);
                if (command.isCommand()) {
                    command.processCommand();
                } else {
                    var message = UIUtil.escapeHtml(value);
                    eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
                }
            }
        });

        var onTextAreaResize = function () {
            resizeChatConversation();
            Chat.scrollChatToBottom();
        };
        usermsg.autosize({callback: onTextAreaResize});

        eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
            function(containerId, isVisible) {
                if (containerId !== CHAT_CONTAINER_ID || !isVisible)
                    return;

                unreadMessages = 0;
                updateVisualNotification();

                // Undock the toolbar when the chat is shown and if we're in a
                // video mode.
                if (VideoLayout.isLargeVideoVisible()) {
                    ToolbarToggler.dockToolbar(false);
                }

                // if we are in conversation mode focus on the text input
                // if we are not, focus on the display name input
                if (APP.settings.getDisplayName())
                    $('#usermsg').focus();
                else
                    $('#nickinput').focus();
            });

        addSmileys();
        updateVisualNotification();
    },

    /**
     * Appends the given message to the chat conversation.
     */
    updateChatConversation (id, displayName, message, stamp) {
        var divClassName = '';

        if (APP.conference.isLocalId(id)) {
            divClassName = "localuser";
        } else {
            divClassName = "remoteuser";

            if (!Chat.isVisible()) {
                unreadMessages++;
                UIUtil.playSoundNotification('chatNotification');
                updateVisualNotification();
            }
        }

        // replace links and smileys
        // Strophe already escapes special symbols on sending,
        // so we escape here only tags to avoid double &
        var escMessage = message.replace(/</g, '<').
            replace(/>/g, '>').replace(/\n/g, '
');
        var escDisplayName = UIUtil.escapeHtml(displayName);
        message = processReplacements(escMessage);

        var messageContainer =
            '
'+
                '' +
                '
' + escDisplayName +
                '
' + '
' + getCurrentTime(stamp) +
                '
' + '
' + message + '
' +
            '
';

        $('#chatconversation').append(messageContainer);
        $('#chatconversation').animate(
                { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
    },

    /**
     * Appends error message to the conversation
     * @param errorMessage the received error message.
     * @param originalText the original message.
     */
    chatAddError (errorMessage, originalText) {
        errorMessage = UIUtil.escapeHtml(errorMessage);
        originalText = UIUtil.escapeHtml(originalText);

        $('#chatconversation').append(
            '
Error: ' + 'Your message' +
            (originalText? (' \"'+ originalText + '\"') : "") +
            ' was not sent.' +
            (errorMessage? (' Reason: ' + errorMessage) : '') +  '
');
        $('#chatconversation').animate(
            { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
    },

    /**
     * Sets the subject to the UI
     * @param subject the subject
     */
    setSubject (subject) {
        let toggleFunction;
        if (subject) {
            subject = subject.trim();
        }

        toggleFunction = subject ? UIUtil.showElement : UIUtil.hideElement;
        toggleFunction = toggleFunction.bind(UIUtil);

        let subjectId = 'subject';
        let html = linkify(UIUtil.escapeHtml(subject));
        $(`#${subjectId}`).html(html);
        toggleFunction(subjectId);
    },

    /**
     * Sets the chat conversation mode.
     * Conversation mode is the normal chat mode, non conversation mode is
     * where we ask user to input its display name.
     * @param {boolean} isConversationMode if chat should be in
     * conversation mode or not.
     */
    setChatConversationMode (isConversationMode) {
        $('#' + CHAT_CONTAINER_ID)
            .toggleClass('is-conversation-mode', isConversationMode);

        // this is needed when we transition from no conversation mode to
        // conversation mode. When user enters his nickname and hits enter,
        // to focus on the write area.
        if (isConversationMode) {
            $('#usermsg').focus();
        }
    },

    /**
     * Resizes the chat area.
     */
    resizeChat (width, height) {
        $('#' + CHAT_CONTAINER_ID).width(width).height(height);

        resizeChatConversation();
    },

    /**
     * Indicates if the chat is currently visible.
     */
    isVisible () {
        return UIUtil.isVisible(
            document.getElementById(CHAT_CONTAINER_ID));
    },
    /**
     * Shows and hides the window with the smileys
     */
    toggleSmileys,

    /**
     * Scrolls chat to the bottom.
     */
    scrollChatToBottom () {
        setTimeout(function () {
            $('#chatconversation').scrollTop(
                $('#chatconversation')[0].scrollHeight);
        }, 5);
    }
};

export default Chat;
<commit_msg>focus for chat changes<commit_after>/* global APP, $ */

import {processReplacements, linkify} from './Replacement';
import CommandsProcessor from './Commands';
import ToolbarToggler from '../../toolbars/ToolbarToggler';
import VideoLayout from "../../videolayout/VideoLayout";

import UIUtil from '../../util/UIUtil';
import UIEvents from '../../../../service/UI/UIEvents';

import { smileys } from './smileys';

let unreadMessages = 0;
const sidePanelsContainerId = 'sideToolbarContainer';
const htmlStr = `

            <form>
                <input type='text'
                       class="input-control" id="nickinput" autofocus
                    data-i18n="[placeholder]chat.nickname.popover">
            </form>

        <audio id="chatNotification" src="sounds/incomingMessage.wav"
            preload="auto"></audio>
        <textarea id="usermsg" autofocus
            data-i18n="[placeholder]chat.messagebox"></textarea>

`;

function initHTML() {
    $(`#${sidePanelsContainerId}`)
        .append(htmlStr);
}

/**
 * The container id, which is and the element id.
 */
var CHAT_CONTAINER_ID = "chat_container";

/**
 *  Updates visual notification, indicating that a message has arrived.
 */
function updateVisualNotification() {
    var unreadMsgElement = document.getElementById('unreadMessages');

    if (unreadMessages) {
        unreadMsgElement.innerHTML = unreadMessages.toString();

        ToolbarToggler.dockToolbar(true);

        var chatButtonElement
            = document.getElementById('toolbar_button_chat');
        var leftIndent = (UIUtil.getTextWidth(chatButtonElement) -
            UIUtil.getTextWidth(unreadMsgElement)) / 2;
        var topIndent = (UIUtil.getTextHeight(chatButtonElement) -
            UIUtil.getTextHeight(unreadMsgElement)) / 2 - 5;

        unreadMsgElement.setAttribute(
            'style',
                'top:' + topIndent +
                '; left:' + leftIndent + ';');
    }
    else {
        unreadMsgElement.innerHTML = '';
    }

    $(unreadMsgElement).parent()[unreadMessages > 0 ? 'show' : 'hide']();
}

/**
 * Returns the current time in the format it is shown to the user
 * @returns {string}
 */
function getCurrentTime(stamp) {
    var now     = (stamp? new Date(stamp): new Date());
    var hour    = now.getHours();
    var minute  = now.getMinutes();
    var second  = now.getSeconds();
    if(hour.toString().length === 1) {
        hour = '0'+hour;
    }
    if(minute.toString().length === 1) {
        minute = '0'+minute;
    }
    if(second.toString().length === 1) {
        second = '0'+second;
    }
    return hour+':'+minute+':'+second;
}

function toggleSmileys() {
    var smileys = $('#smileysContainer');
    if(!smileys.is(':visible')) {
        smileys.show("slide", { direction: "down", duration: 300});
    } else {
        smileys.hide("slide", { direction: "down", duration: 300});
    }
    $('#usermsg').focus();
}

function addClickFunction(smiley, number) {
    smiley.onclick = function addSmileyToMessage() {
        var usermsg = $('#usermsg');
        var message = usermsg.val();
        message += smileys['smiley' + number];
        usermsg.val(message);
        usermsg.get(0).setSelectionRange(message.length, message.length);
        toggleSmileys();
        usermsg.focus();
    };
}

/**
 * Adds the smileys container to the chat
 */
function addSmileys() {
    var smileysContainer = document.createElement('div');
    smileysContainer.id = 'smileysContainer';
    for(var i = 1; i <= 21; i++) {
        var smileyContainer = document.createElement('div');
        smileyContainer.id = 'smiley' + i;
        smileyContainer.className = 'smileyContainer';
        var smiley = document.createElement('img');
        smiley.src = 'images/smileys/smiley' + i + '.svg';
        smiley.className =  'smiley';
        addClickFunction(smiley, i);
        smileyContainer.appendChild(smiley);
        smileysContainer.appendChild(smileyContainer);
    }

    $("#chat_container").append(smileysContainer);
}

/**
 * Resizes the chat conversation.
 */
function resizeChatConversation() {
    var msgareaHeight = $('#usermsg').outerHeight();
    var chatspace = $('#' + CHAT_CONTAINER_ID);
    var width = chatspace.width();
    var chat = $('#chatconversation');
    var smileys = $('#smileysarea');

    smileys.height(msgareaHeight);
    $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
    $('#smileysContainer').css('bottom', msgareaHeight);
    chat.width(width - 10);
    chat.height(window.innerHeight - 15 - msgareaHeight);
}

function deferredFocus(id){
    setTimeout(function (){
        $(`#${id}`).focus();
    }, 400);
}
/**
 * Chat related user interface.
 */
var Chat = {
    /**
     * Initializes chat related interface.
     */
    init (eventEmitter) {
        initHTML();
        if (APP.settings.getDisplayName()) {
            Chat.setChatConversationMode(true);
        }

        $("#toggle_smileys").click(function() {
            Chat.toggleSmileys();
        });

        $('#nickinput').keydown(function (event) {
            if (event.keyCode === 13) {
                event.preventDefault();
                let val = this.value;
                this.value = '';
                eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
                deferredFocus('usermsg');
            }
        });

        var usermsg = $('#usermsg');
        usermsg.keydown(function (event) {
            if (event.keyCode === 13) {
                event.preventDefault();
                var value = this.value;
                usermsg.val('').trigger('autosize.resize');
                this.focus();
                var command = new CommandsProcessor(value, eventEmitter);
                if (command.isCommand()) {
                    command.processCommand();
                } else {
                    var message = UIUtil.escapeHtml(value);
                    eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
                }
            }
        });

        var onTextAreaResize = function () {
            resizeChatConversation();
            Chat.scrollChatToBottom();
        };
        usermsg.autosize({callback: onTextAreaResize});

        eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
            function(containerId, isVisible) {
                if (containerId !== CHAT_CONTAINER_ID || !isVisible)
                    return;

                unreadMessages = 0;
                updateVisualNotification();

                // Undock the toolbar when the chat is shown and if we're in a
                // video mode.
                if (VideoLayout.isLargeVideoVisible()) {
                    ToolbarToggler.dockToolbar(false);
                }

                // if we are in conversation mode focus on the text input
                // if we are not, focus on the display name input
                if (APP.settings.getDisplayName())
                    deferredFocus('usermsg');
                else
                    deferredFocus('nickinput');
            });

        addSmileys();
        updateVisualNotification();
    },

    /**
     * Appends the given message to the chat conversation.
     */
    updateChatConversation (id, displayName, message, stamp) {
        var divClassName = '';

        if (APP.conference.isLocalId(id)) {
            divClassName = "localuser";
        } else {
            divClassName = "remoteuser";

            if (!Chat.isVisible()) {
                unreadMessages++;
                UIUtil.playSoundNotification('chatNotification');
                updateVisualNotification();
            }
        }

        // replace links and smileys
        // Strophe already escapes special symbols on sending,
        // so we escape here only tags to avoid double &
        var escMessage = message.replace(/</g, '<').
            replace(/>/g, '>').replace(/\n/g, '
');
        var escDisplayName = UIUtil.escapeHtml(displayName);
        message = processReplacements(escMessage);

        var messageContainer =
            '
'+
                '' +
                '
' + escDisplayName +
                '
' + '
' + getCurrentTime(stamp) +
                '
' + '
' + message + '
' +
            '
';

        $('#chatconversation').append(messageContainer);
        $('#chatconversation').animate(
                { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
    },

    /**
     * Appends error message to the conversation
     * @param errorMessage the received error message.
     * @param originalText the original message.
     */
    chatAddError (errorMessage, originalText) {
        errorMessage = UIUtil.escapeHtml(errorMessage);
        originalText = UIUtil.escapeHtml(originalText);

        $('#chatconversation').append(
            '
Error: ' + 'Your message' +
            (originalText? (' \"'+ originalText + '\"') : "") +
            ' was not sent.' +
            (errorMessage? (' Reason: ' + errorMessage) : '') +  '
');
        $('#chatconversation').animate(
            { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
    },

    /**
     * Sets the subject to the UI
     * @param subject the subject
     */
    setSubject (subject) {
        let toggleFunction;
        if (subject) {
            subject = subject.trim();
        }

        toggleFunction = subject ? UIUtil.showElement : UIUtil.hideElement;
        toggleFunction = toggleFunction.bind(UIUtil);

        let subjectId = 'subject';
        let html = linkify(UIUtil.escapeHtml(subject));
        $(`#${subjectId}`).html(html);
        toggleFunction(subjectId);
    },

    /**
     * Sets the chat conversation mode.
     * Conversation mode is the normal chat mode, non conversation mode is
     * where we ask user to input its display name.
     * @param {boolean} isConversationMode if chat should be in
     * conversation mode or not.
     */
    setChatConversationMode (isConversationMode) {
        $('#' + CHAT_CONTAINER_ID)
            .toggleClass('is-conversation-mode', isConversationMode);
    },

    /**
     * Resizes the chat area.
     */
    resizeChat (width, height) {
        $('#' + CHAT_CONTAINER_ID).width(width).height(height);

        resizeChatConversation();
    },

    /**
     * Indicates if the chat is currently visible.
     */
    isVisible () {
        return UIUtil.isVisible(
            document.getElementById(CHAT_CONTAINER_ID));
    },
    /**
     * Shows and hides the window with the smileys
     */
    toggleSmileys,

    /**
     * Scrolls chat to the bottom.
     */
    scrollChatToBottom () {
        setTimeout(function () {
            $('#chatconversation').scrollTop(
                $('#chatconversation')[0].scrollHeight);
        }, 5);
    }
};

export default Chat;
<|endoftext|>


<commit_before>import assert from 'assert';
import expect, { createSpy, spyOn } from 'expect';
import NavigationTypes from '../NavigationTypes';
import History, { RequiredSubclassMethods } from '../History';

function describeHistory(history) {
  it('is a History', function () {
    assert(History.isHistory(history));
  });

  RequiredSubclassMethods.forEach(function (method) {
    it('has a ' + method + ' method', function () {
      expect(history[method]).toBeA('function');
    });
  });

  describe('adding/removing a listener', function () {
    var pushStateSpy, goSpy;
    beforeEach(function () {
      // It's a bit tricky to test change listeners properly because
      // they are triggered when the URL changes. So we need to stub
      // out push/go to only notify listeners ... but we can't make
      // assertions on the location because it will be wrong.
      pushStateSpy = spyOn(history, 'pushState').andCall(history._notifyChange);
      goSpy = spyOn(history, 'go').andCall(history._notifyChange);
    });

    afterEach(function () {
      pushStateSpy.restore();
      goSpy.restore();
    });

    it('works', function () {
      var spy = expect.createSpy(function () {});

      history.addChangeListener(spy);
      history.pushState(null, '/home'); // call #1
      expect(pushStateSpy).toHaveBeenCalled();

      expect(spy.calls.length).toEqual(1);

      history.removeChangeListener(spy)
      history.back(); // call #2
      expect(goSpy).toHaveBeenCalled();

      expect(spy.calls.length).toEqual(1);
    });
  });

  describe('when the user cancels a transition', function () {
    var location, confirmationMessage, getTransitionConfirmationMessageSpy, getUserConfirmationSpy;
    beforeEach(function () {
      window.location.href = '/';
      confirmationMessage = 'Are you sure?';
      getTransitionConfirmationMessageSpy = spyOn(history, 'getTransitionConfirmationMessage').andReturn(confirmationMessage);
      getUserConfirmationSpy = spyOn(history, 'getUserConfirmation').andCall(function (message, callback) {
        expect(message).toBe(confirmationMessage);
        callback(false);
      });
      location = history.location;
    });

    afterEach(function () {
      getTransitionConfirmationMessageSpy.restore();
      getUserConfirmationSpy.restore();
      location = null;
    });

    it('does not update the location', function () {
      history.pushState(null, '/home');
      expect(history.location).toBe(location);
    });
  });

  describe('when the user confirms a transition', function () {
    var location, confirmationMessage, getTransitionConfirmationMessageSpy, getUserConfirmationSpy;
    beforeEach(function () {
      window.location.href = '/';
      confirmationMessage = 'Are you sure?';
      getTransitionConfirmationMessageSpy = spyOn(history, 'getTransitionConfirmationMessage').andReturn(confirmationMessage);
      getUserConfirmationSpy = spyOn(history, 'getUserConfirmation').andCall(function (message, callback) {
        expect(message).toBe(confirmationMessage);
        callback(true);
      });
      location = history.location;
    });

    afterEach(function () {
      getTransitionConfirmationMessageSpy.restore();
      getUserConfirmationSpy.restore();
      location = null;
    });

    it('updates the location', function () {
      history.pushState(null, '/home');
      expect(history.location).toNotBe(location);
    });
  });

  describe('pushState', function () {
    var unlisten, listener, location;
    beforeEach(function () {
      window.location.href = '/';

      unlisten = history.listen(listener = function (loc) {
        location = loc;
      });
    });

    afterEach(function () {
      unlisten();
      unlisten = listener = location = null;
    });

    it('calls change listeners with the new location', function () {
      history.pushState({ the: 'state' }, '/home?the=query');

      assert(location);
      expect(location.pathname).toEqual('/home');
      expect(location.search).toEqual('?the=query');
      //expect(location.state).toEqual({ the: 'state' });
      expect(location.navigationType).toEqual(NavigationTypes.PUSH);
    });
  });
}

export default describeHistory;
<commit_msg>Small refactor<commit_after>import assert from 'assert';
import expect, { createSpy, spyOn } from 'expect';
import NavigationTypes from '../NavigationTypes';
import History, { RequiredSubclassMethods } from '../History';

function describeHistory(history) {
  beforeEach(function () {
    window.location.href = '/';
  });

  it('is a History', function () {
    assert(History.isHistory(history));
  });

  RequiredSubclassMethods.forEach(function (method) {
    it('has a ' + method + ' method', function () {
      expect(history[method]).toBeA('function');
    });
  });

  describe('adding/removing a listener', function () {
    var pushStateSpy, goSpy;
    beforeEach(function () {
      // It's a bit tricky to test change listeners properly because
      // they are triggered when the URL changes. So we need to stub
      // out push/go to only notify listeners ... but we can't make
      // assertions on the location because it will be wrong.
      pushStateSpy = spyOn(history, 'pushState').andCall(history._notifyChange);
      goSpy = spyOn(history, 'go').andCall(history._notifyChange);
    });

    afterEach(function () {
      pushStateSpy.restore();
      goSpy.restore();
    });

    it('works', function () {
      var spy = expect.createSpy(function () {});

      history.addChangeListener(spy);
      history.pushState(null, '/home'); // call #1
      expect(pushStateSpy).toHaveBeenCalled();

      expect(spy.calls.length).toEqual(1);

      history.removeChangeListener(spy)
      history.back(); // call #2
      expect(goSpy).toHaveBeenCalled();

      expect(spy.calls.length).toEqual(1);
    });
  });

  describe('when the user cancels a transition', function () {
    var location, confirmationMessage, getTransitionConfirmationMessageSpy, getUserConfirmationSpy;
    beforeEach(function () {
      location = history.location;
      confirmationMessage = 'Are you sure?';
      getTransitionConfirmationMessageSpy = spyOn(history, 'getTransitionConfirmationMessage').andReturn(confirmationMessage);
      getUserConfirmationSpy = spyOn(history, 'getUserConfirmation').andCall(function (message, callback) {
        expect(message).toBe(confirmationMessage);
        callback(false);
      });
    });

    afterEach(function () {
      getTransitionConfirmationMessageSpy.restore();
      getUserConfirmationSpy.restore();
      location = null;
    });

    it('does not update the location', function () {
      history.pushState(null, '/home');
      expect(history.location).toBe(location);
    });
  });

  describe('when the user confirms a transition', function () {
    var location, confirmationMessage, getTransitionConfirmationMessageSpy, getUserConfirmationSpy;
    beforeEach(function () {
      location = history.location;
      confirmationMessage = 'Are you sure?';
      getTransitionConfirmationMessageSpy = spyOn(history, 'getTransitionConfirmationMessage').andReturn(confirmationMessage);
      getUserConfirmationSpy = spyOn(history, 'getUserConfirmation').andCall(function (message, callback) {
        expect(message).toBe(confirmationMessage);
        callback(true);
      });
    });

    afterEach(function () {
      getTransitionConfirmationMessageSpy.restore();
      getUserConfirmationSpy.restore();
      location = null;
    });

    it('updates the location', function () {
      history.pushState(null, '/home');
      expect(history.location).toNotBe(location);
    });
  });

  describe('pushState', function () {
    var unlisten, listener, location;
    beforeEach(function () {
      unlisten = history.listen(listener = function (loc) {
        location = loc;
      });
    });

    afterEach(function () {
      unlisten();
      unlisten = listener = location = null;
    });

    it('calls change listeners with the new location', function () {
      history.pushState({ the: 'state' }, '/home?the=query');

      assert(location);
      expect(location.pathname).toEqual('/home');
      expect(location.search).toEqual('?the=query');
      //expect(location.state).toEqual({ the: 'state' });
      expect(location.navigationType).toEqual(NavigationTypes.PUSH);
    });
  });
}

export default describeHistory;
<|endoftext|>


<commit_before>import expect from 'expect'
import { PUSH, REPLACE, POP } from '../Actions'
import useQueries from '../useQueries'
import execSteps from './execSteps'

function stripHash(path) {
  return path.replace(/^#/, '')
}

function describeQueries(createHistory) {
  describe('query serialization', function () {
    let history, unlisten
    beforeEach(function () {
      history = useQueries(createHistory)({
        parseQueryString(queryString) {
          return 'PARSE_QUERY_STRING'
        },
        stringifyQuery(query) {
          return 'STRINGIFY_QUERY'
        }
      })
    })

    afterEach(function () {
      if (unlisten)
        unlisten()
    })

    describe('in pushState', function () {
      it('works', function (done) {
        let steps = [
          function (location) {
            expect(location.pathname).toEqual('/')
            expect(location.search).toEqual('')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual(null)
            expect(location.action).toEqual(POP)

            history.pushState({ the: 'state' }, '/home', { the: 'query' })
          },
          function (location) {
            expect(location.pathname).toEqual('/home')
            expect(location.search).toEqual('?STRINGIFY_QUERY')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual({ the: 'state' })
            expect(location.action).toEqual(PUSH)
          }
        ]

        unlisten = history.listen(execSteps(steps, done))
      })
    })

    describe('in replaceState', function () {
      it('works', function (done) {
        let steps = [
          function (location) {
            expect(location.pathname).toEqual('/')
            expect(location.search).toEqual('')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual(null)
            expect(location.action).toEqual(POP)

            history.replaceState({ the: 'state' }, '/home', { the: 'query' })
          },
          function (location) {
            expect(location.pathname).toEqual('/home')
            expect(location.search).toEqual('?STRINGIFY_QUERY')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual({ the: 'state' })
            expect(location.action).toEqual(REPLACE)
          }
        ]

        unlisten = history.listen(execSteps(steps, done))
      })
    })

    describe('in createPath', function () {
      it('works', function () {
        expect(
          history.createPath('/the/path', { the: 'query' })
        ).toEqual('/the/path?STRINGIFY_QUERY')
      })
    })

    describe('in createHref', function () {
      it('works', function () {
        expect(
          stripHash(history.createHref('/the/path', { the: 'query' }))
        ).toEqual('/the/path?STRINGIFY_QUERY')
      })
    })
  })
}

export default describeQueries
<commit_msg>add test for rackt/react-router#1148<commit_after>import expect from 'expect'
import { PUSH, REPLACE, POP } from '../Actions'
import useQueries from '../useQueries'
import execSteps from './execSteps'

function stripHash(path) {
  return path.replace(/^#/, '')
}

function describeQueries(createHistory) {
  describe('query serialization', function () {
    let history, unlisten
    beforeEach(function () {
      history = useQueries(createHistory)({
        parseQueryString(queryString) {
          return 'PARSE_QUERY_STRING'
        },
        stringifyQuery(query) {
          return 'STRINGIFY_QUERY'
        }
      })
    })

    afterEach(function () {
      if (unlisten)
        unlisten()
    })

    describe('in pushState', function () {
      it('works', function (done) {
        let steps = [
          function (location) {
            expect(location.pathname).toEqual('/')
            expect(location.search).toEqual('')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual(null)
            expect(location.action).toEqual(POP)

            history.pushState({ the: 'state' }, '/home', { the: 'query' })
          },
          function (location) {
            expect(location.pathname).toEqual('/home')
            expect(location.search).toEqual('?STRINGIFY_QUERY')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual({ the: 'state' })
            expect(location.action).toEqual(PUSH)
          }
        ]

        unlisten = history.listen(execSteps(steps, done))
      })
    })

    describe('in replaceState', function () {
      it('works', function (done) {
        let steps = [
          function (location) {
            expect(location.pathname).toEqual('/')
            expect(location.search).toEqual('')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual(null)
            expect(location.action).toEqual(POP)

            history.replaceState({ the: 'state' }, '/home', { the: 'query' })
          },
          function (location) {
            expect(location.pathname).toEqual('/home')
            expect(location.search).toEqual('?STRINGIFY_QUERY')
            expect(location.query).toEqual('PARSE_QUERY_STRING')
            expect(location.state).toEqual({ the: 'state' })
            expect(location.action).toEqual(REPLACE)
          }
        ]

        unlisten = history.listen(execSteps(steps, done))
      })
    })

    describe('in createPath', function () {
      it('works', function () {
        expect(
          history.createPath('/the/path', { the: 'query' })
        ).toEqual('/the/path?STRINGIFY_QUERY')
      })

      it('does not strip trailing slash', function () {
        expect(
          history.createPath('/the/path/', { the: 'query' })
        ).toEqual('/the/path/?STRINGIFY_QUERY')
      })
    })

    describe('in createHref', function () {
      it('works', function () {
        expect(
          stripHash(history.createHref('/the/path', { the: 'query' }))
        ).toEqual('/the/path?STRINGIFY_QUERY')
      })
    })
  })
}

export default describeQueries
<|endoftext|>