<commit_before>import ApolloClient, { createNetworkInterface, createBatchingNetworkInterface } from 'apollo-client';
import 'cross-fetch/polyfill';
import { Meteor } from 'meteor/meteor';
import { getSetting, registerSetting } from './settings.js';
import { getFragmentMatcher } from './fragment_matcher.js';
import { runCallbacks } from './callbacks.js';

registerSetting('developmentServerIp', Meteor.absoluteUrl(), 'Development server IP');

const defaultNetworkInterfaceConfig = {
  path: '/graphql', // default graphql server endpoint
  opts: {}, // additional fetch options like `credentials` or `headers`
  useMeteorAccounts: true, // if true, send an eventual Meteor login token to identify the current user with every request
  batchingInterface: true, // use a BatchingNetworkInterface by default instead of a NetworkInterface
  batchInterval: 10, // default batch interval
};

const createMeteorNetworkInterface = (givenConfig = {}) => {
  const config = { ...defaultNetworkInterfaceConfig, ...givenConfig };

  // absoluteUrl adds a '/', so let's remove it first
  let path = config.path;
  if (path[0] === '/') {
    path = path.slice(1);
  }

  const uri = Meteor.absoluteUrl(
    path,
    { rootUrl: getSetting('developmentServerIp', Meteor.absoluteUrl()) },
  );

  // allow the use of a batching network interface; if the options.batchingInterface is not specified, fallback to the standard network interface
  const interfaceToUse = config.batchingInterface ? createBatchingNetworkInterface : createNetworkInterface;

  // default interface options
  const interfaceOptions = {
    uri,
    opts: {
      credentials: 'same-origin', // http://dev.apollodata.com/react/auth.html#Cookie
    },
  };

  // if a BatchingNetworkInterface is used with a correct batch interval, add it to the options
  if (config.batchingInterface && config.batchInterval) {
    interfaceOptions.batchInterval = config.batchInterval;
  }

  // if 'fetch' has been configured to be called with specific opts, add it to the options
  if (Object.keys(config.opts).length > 0) {
    interfaceOptions.opts = config.opts;
  }

  const networkInterface = interfaceToUse(interfaceOptions);

  if (config.useMeteorAccounts) {
    networkInterface.use([{
      applyBatchMiddleware(request, next) {
        const currentUserToken = Meteor.isClient ? global.localStorage['Meteor.loginToken'] : config.loginToken;

        if (!currentUserToken) {
          next();
          return;
        }

        if (!request.options.headers) {
          request.options.headers = new Headers();
        }

        request.options.headers.Authorization = currentUserToken;

        next();
      },
    }]);
  }

  return networkInterface;
};

const meteorClientConfig = networkInterfaceConfig => {

  return {
    ssrMode: Meteor.isServer,
    networkInterface: createMeteorNetworkInterface(networkInterfaceConfig),
    queryDeduplication: true, // http://dev.apollodata.com/core/network.html#query-deduplication
    addTypename: true,
    fragmentMatcher: getFragmentMatcher(),

    // Default to using Mongo _id, must use _id for queries.
    dataIdFromObject(result) {
      if (result._id && result.__typename) {
        const dataId = result.__typename + result._id;
        return dataId;
      }
      return null;
    },
  }
};

export const createApolloClient = options => {

  runCallbacks('apolloclient.init.before');

  return new ApolloClient(meteorClientConfig(options));

};
<commit_msg>add graphQLEndpointURL setting to make endpoint URL configurable (to use different GraphQL back-end for example)<commit_after>import ApolloClient, { createNetworkInterface, createBatchingNetworkInterface } from 'apollo-client';
import 'cross-fetch/polyfill';
import { Meteor } from 'meteor/meteor';
import { getSetting, registerSetting } from './settings.js';
import { getFragmentMatcher } from './fragment_matcher.js';
import { runCallbacks } from './callbacks.js';

registerSetting('graphQLendpointURL', '/graphql', 'GraphQL endpoint URL');

const defaultNetworkInterfaceConfig = {
  path: '/graphql', // default graphql server endpoint
  opts: {}, // additional fetch options like `credentials` or `headers`
  useMeteorAccounts: true, // if true, send an eventual Meteor login token to identify the current user with every request
  batchingInterface: true, // use a BatchingNetworkInterface by default instead of a NetworkInterface
  batchInterval: 10, // default batch interval
};

const createMeteorNetworkInterface = (givenConfig = {}) => {
  const config = { ...defaultNetworkInterfaceConfig, ...givenConfig };

  // absoluteUrl adds a '/', so let's remove it first
  let path = config.path;
  if (path[0] === '/') {
    path = path.slice(1);
  }

  const defaultUri = Meteor.absoluteUrl(path);
  const uri = getSetting('graphQLendpointURL', defaultUri);

  // allow the use of a batching network interface; if the options.batchingInterface is not specified, fallback to the standard network interface
  const interfaceToUse = config.batchingInterface ? createBatchingNetworkInterface : createNetworkInterface;

  // default interface options
  const interfaceOptions = {
    uri,
    opts: {
      credentials: 'same-origin', // http://dev.apollodata.com/react/auth.html#Cookie
    },
  };

  // if a BatchingNetworkInterface is used with a correct batch interval, add it to the options
  if (config.batchingInterface && config.batchInterval) {
    interfaceOptions.batchInterval = config.batchInterval;
  }

  // if 'fetch' has been configured to be called with specific opts, add it to the options
  if (Object.keys(config.opts).length > 0) {
    interfaceOptions.opts = config.opts;
  }

  const networkInterface = interfaceToUse(interfaceOptions);

  if (config.useMeteorAccounts) {
    networkInterface.use([{
      applyBatchMiddleware(request, next) {
        const currentUserToken = Meteor.isClient ? global.localStorage['Meteor.loginToken'] : config.loginToken;

        if (!currentUserToken) {
          next();
          return;
        }

        if (!request.options.headers) {
          request.options.headers = new Headers();
        }

        request.options.headers.Authorization = currentUserToken;

        next();
      },
    }]);
  }

  return networkInterface;
};

const meteorClientConfig = networkInterfaceConfig => {

  return {
    ssrMode: Meteor.isServer,
    networkInterface: createMeteorNetworkInterface(networkInterfaceConfig),
    queryDeduplication: true, // http://dev.apollodata.com/core/network.html#query-deduplication
    addTypename: true,
    fragmentMatcher: getFragmentMatcher(),

    // Default to using Mongo _id, must use _id for queries.
    dataIdFromObject(result) {
      if (result._id && result.__typename) {
        const dataId = result.__typename + result._id;
        return dataId;
      }
      return null;
    },
  }
};

export const createApolloClient = options => {

  runCallbacks('apolloclient.init.before');

  return new ApolloClient(meteorClientConfig(options));

};
<|endoftext|>


<commit_before>/* @flow */

import Path from 'path'
import Pundle from 'pundle'
import PundleDev from 'pundle-dev'
import send from 'send'
import { DIRECTORY_NAME } from './config'
import type CLI from './cli'
import type State from './state'
import type { Motion$Config } from './types'

export const X = '✗'
export const TICK = '✓'

export function fillConfig(config: Motion$Config) {
  if (typeof config.dataDirectory !== 'string') {
    config.dataDirectory = Path.join(config.rootDirectory, DIRECTORY_NAME)
  }
}

export function getLocalModulePath(name: string): string {
  return Path.dirname(require.resolve(`${name}/package.json`))
}

// From: goo.gl/fZA6BF
export function getRandomNumber(min: number, max: number): number {
  return Math.floor(Math.random() * (max - min)) + min
}

export async function getPundleInstance(state: State, config: Motion$Config, cli: CLI, terminal: boolean, development: boolean, errorCallback: Function): Object {
  const pundleConfig = {
    hmr: development,
    entry: [require.resolve('babel-regenerator-runtime'), config.rootDirectory],
    rootDirectory: config.rootDirectory,
    resolve: {
      root: config.rootDirectory
    },
    replaceVariables: {
      'process.env.NODE_ENV': `"${development ? 'development' : 'production'}"`
    }
  }
  const plugins = [[require.resolve('pundle-npm-installer'), {
    save: state.get().npm_save,
    rootDirectory: config.rootDirectory,
    onBeforeInstall(id, name) {
      if (terminal) {
        const message = `Installing ${name}`
        cli.addSpinner(message)
      }
    },
    onAfterInstall(id, name, error) {
      if (terminal) {
        const message = `Installing ${name}`
        cli.removeSpinner(message)
        if (error) {
          cli.log(`Install ${name} ${X}`)
          cli.log(error)
        } else {
          cli.log(`Install ${name} ${TICK}`)
        }
      } else if (error) {
        errorCallback(error)
      }
    }
  }], [require.resolve('babel-pundle'), {
    config: {
      presets: [require.resolve('babel-preset-motion')]
    },
    ignored: /(node_modules|bower_components|\.motion)/
  }], require.resolve('./pundle/resolver')]
  if (!development) {
    const pundle = new Pundle(pundleConfig)
    await pundle.loadPlugins(plugins)
    return pundle
  }
  const pundle = new PundleDev({
    pundle: pundleConfig,
    watcher: {
      onError(error) {
        errorCallback(error)
      }
    },
    middleware: {
      sourceMap: true,
      sourceRoot: config.dataDirectory,
      publicPath: '/',
      publicBundlePath: '/_/bundle.js'
    },
    server: {
      port: state.get().web_server_port
    }
  })
  await pundle.pundle.loadPlugins(plugins)
  pundle.server.use('*', function serveRequest(req, res, next, error = false) {
    // Ignore both bundle and it's map
    if (req.baseUrl.indexOf('/_/bundle.js') === 0) {
      next()
      return
    }
    send(req, req.baseUrl, { root: config.dataDirectory, index: 'index.html' })
      .on('error', function() {
        if (error) {
          next()
        } else {
          req.baseUrl = '/index.html'
          serveRequest(req, res, next, true)
        }
      })
      .on('directory', function() {
        next()
      })
      .pipe(res)
  })
  return pundle
}
<commit_msg>:new: adding in user plugins initial attempt<commit_after>/* @flow */

import Path from 'path'
import Pundle from 'pundle'
import PundleDev from 'pundle-dev'
import send from 'send'
import { DIRECTORY_NAME } from './config'
import type CLI from './cli'
import type State from './state'
import type { Motion$Config } from './types'

export const X = '✗'
export const TICK = '✓'

export function fillConfig(config: Motion$Config) {
  if (typeof config.dataDirectory !== 'string') {
    config.dataDirectory = Path.join(config.rootDirectory, DIRECTORY_NAME)
  }
}

export function getLocalModulePath(name: string): string {
  return Path.dirname(require.resolve(`${name}/package.json`))
}

// From: goo.gl/fZA6BF
export function getRandomNumber(min: number, max: number): number {
  return Math.floor(Math.random() * (max - min)) + min
}

export async function getPundleInstance(
  state: State,
  config: Motion$Config,
  cli: CLI,
  terminal: boolean,
  development: boolean,
  errorCallback: Function
): Object {
  const pundleConfig = {
    hmr: development,
    entry: [require.resolve('babel-regenerator-runtime'), config.rootDirectory],
    rootDirectory: config.rootDirectory,
    resolve: {
      root: config.rootDirectory
    },
    replaceVariables: {
      'process.env.NODE_ENV': `"${development ? 'development' : 'production'}"`
    }
  }

  const userPlugins = (
    state.config.babel && state.config.babel.plugins || []
  )
  .map(plugin =>
    require.resolve(Path.join(config.rootDirectory, '.motion', plugin))
  )

  const plugins = [userPlugins, [require.resolve('pundle-npm-installer'), {
    save: state.get().npm_save,
    rootDirectory: config.rootDirectory,
    onBeforeInstall(id, name) {
      if (terminal) {
        const message = `Installing ${name}`
        cli.addSpinner(message)
      }
    },
    onAfterInstall(id, name, error) {
      if (terminal) {
        const message = `Installing ${name}`
        cli.removeSpinner(message)
        if (error) {
          cli.log(`Install ${name} ${X}`)
          cli.log(error)
        } else {
          cli.log(`Install ${name} ${TICK}`)
        }
      } else if (error) {
        errorCallback(error)
      }
    }
  }], [require.resolve('babel-pundle'), {
    config: {
      presets: [require.resolve('babel-preset-motion')]
    },
    ignored: /(node_modules|bower_components|\.motion)/
  }], require.resolve('./pundle/resolver')]

  if (!development) {
    const pundle = new Pundle(pundleConfig)
    await pundle.loadPlugins(plugins)
    return pundle
  }
  const pundle = new PundleDev({
    pundle: pundleConfig,
    watcher: {
      onError(error) {
        errorCallback(error)
      }
    },
    middleware: {
      sourceMap: true,
      sourceRoot: config.dataDirectory,
      publicPath: '/',
      publicBundlePath: '/_/bundle.js'
    },
    server: {
      port: state.get().web_server_port
    }
  })
  await pundle.pundle.loadPlugins(plugins)
  pundle.server.use('*', function serveRequest(req, res, next, error = false) {
    // Ignore both bundle and it's map
    if (req.baseUrl.indexOf('/_/bundle.js') === 0) {
      next()
      return
    }
    send(req, req.baseUrl, { root: config.dataDirectory, index: 'index.html' })
      .on('error', function() {
        if (error) {
          next()
        } else {
          req.baseUrl = '/index.html'
          serveRequest(req, res, next, true)
        }
      })
      .on('directory', function() {
        next()
      })
      .pipe(res)
  })
  return pundle
}
<|endoftext|>


<commit_before>'use strict';
const os = require('os');
const http = require('http');
const libui = require('..');

const win = new libui.UiWindow('Test window', 800, 600, false);
win.margined = 1;

const box = new libui.UiVerticalBox();
const hBox = new libui.UiHorizontalBox();
const e1 = new libui.UiEntry();
e1.enabled = 0;
const lblCiao = new libui.UiLabel('ciao');
hBox.append(lblCiao, false);

hBox.append(e1, false);
let idxLbl = 0;

const interval = setInterval(() => {
	lblCiao.text = String(idxLbl++);
}, 1000);

// Create an HTTP tunneling proxy
const proxy = http.createServer((req, res) => {
	lblCiao.text = String(idxLbl++);
	res.writeHead(200, {'Content-Type': 'text/plain'});
	res.end(String(idxLbl));
});
proxy.listen(3000, '127.0.0.1', () => {
	console.log('listening...');
});

win.onClosing(() => {
	win.close();
	clearInterval(interval);
	proxy.close();
	libui.stopLoop();
});

box.append(new libui.UiEntry(), false);
box.append(hBox, false);

if (os.platform() !== 'darwin') {
	box.append(new libui.UiSearchEntry(), false);
}

box.append(new libui.UiPasswordEntry(), false);

const cmb = new libui.UiCombobox();

cmb.append('item 1');
cmb.append('item 2');
cmb.append('item 3');

box.append(cmb, false);
const hBox4 = new libui.UiHorizontalBox();
hBox4.append(new libui.UiDateTimePicker(), false);
hBox4.append(new libui.UiVerticalSeparator(), false);
hBox4.append(new libui.UiEditableCombobox(), false);
hBox4.append(new libui.UiCheckbox('Optionally'), false);

box.append(hBox4, false);

const group = new libui.UiGroup('Options');
const radios = new libui.UiRadioButtons();
radios.append('option 1');
radios.append('option 2');
radios.append('option 3');

group.setChild(radios);
box.append(group, true);

box.append(new libui.UiHorizontalSeparator(), true);

const hBox2 = new libui.UiHorizontalBox();
const spin = new libui.UiSpinbox(0, 100);
spin.value = 33;
hBox2.append(new libui.UiLabel('Number'), false);
hBox2.append(spin, true);
box.append(hBox2, false);

const hBox3 = new libui.UiHorizontalBox();
const slider = new libui.UiSlider(0, 100);
slider.value = 33;
hBox3.append(new libui.UiLabel('Number'), false);
hBox3.append(slider, false);
box.append(hBox3, false);

box.append(new libui.UiMultilineEntry(), false);

const buttons = new libui.UiHorizontalBox();
buttons.append(new libui.UiButton('Ok'), false);
buttons.append(new libui.UiButton('Maybe'), false);
buttons.append(new libui.UiButton('Cancel'), false);

box.append(new libui.UiProgressBar(), false);
box.append(new libui.UiFontButton(), false);

box.append(buttons, false);

const tabs = new libui.UiTab();

tabs.append('controls', box);
tabs.append('text', new libui.UiMultilineEntry());

win.setChild(tabs);

win.show();
libui.startLoop();
<commit_msg>Removed test code<commit_after>'use strict';
const os = require('os');
const libui = require('..');

const win = new libui.UiWindow('Test window', 800, 600, false);
win.margined = 1;

const box = new libui.UiVerticalBox();
const hBox = new libui.UiHorizontalBox();
const e1 = new libui.UiEntry();
e1.enabled = 0;
const lblCiao = new libui.UiLabel('ciao');
hBox.append(lblCiao, false);

hBox.append(e1, false);

win.onClosing(() => {
	win.close();
	libui.stopLoop();
});

box.append(new libui.UiEntry(), false);
box.append(hBox, false);

if (os.platform() !== 'darwin') {
	box.append(new libui.UiSearchEntry(), false);
}

box.append(new libui.UiPasswordEntry(), false);

const cmb = new libui.UiCombobox();

cmb.append('item 1');
cmb.append('item 2');
cmb.append('item 3');

box.append(cmb, false);
const hBox4 = new libui.UiHorizontalBox();
hBox4.append(new libui.UiDateTimePicker(), false);
hBox4.append(new libui.UiVerticalSeparator(), false);
hBox4.append(new libui.UiEditableCombobox(), false);
hBox4.append(new libui.UiCheckbox('Optionally'), false);

box.append(hBox4, false);

const group = new libui.UiGroup('Options');
const radios = new libui.UiRadioButtons();
radios.append('option 1');
radios.append('option 2');
radios.append('option 3');

group.setChild(radios);
box.append(group, true);

box.append(new libui.UiHorizontalSeparator(), true);

const hBox2 = new libui.UiHorizontalBox();
const spin = new libui.UiSpinbox(0, 100);
spin.value = 33;
hBox2.append(new libui.UiLabel('Number'), false);
hBox2.append(spin, true);
box.append(hBox2, false);

const hBox3 = new libui.UiHorizontalBox();
const slider = new libui.UiSlider(0, 100);
slider.value = 33;
hBox3.append(new libui.UiLabel('Number'), false);
hBox3.append(slider, false);
box.append(hBox3, false);

box.append(new libui.UiMultilineEntry(), false);

const buttons = new libui.UiHorizontalBox();
buttons.append(new libui.UiButton('Ok'), false);
buttons.append(new libui.UiButton('Maybe'), false);
buttons.append(new libui.UiButton('Cancel'), false);

box.append(new libui.UiProgressBar(), false);
box.append(new libui.UiFontButton(), false);

box.append(buttons, false);

const tabs = new libui.UiTab();

tabs.append('controls', box);
tabs.append('text', new libui.UiMultilineEntry());

win.setChild(tabs);

win.show();
libui.startLoop();
<|endoftext|>


<commit_before>/**
 * Test for mb-logging-api
 *
 * References:
 *   - HOW TO BUILD AND TEST YOUR REST API WITH NODE.JS, EXPRESS AND MOCHA
 *     https://thewayofcode.wordpress.com/tag/supertest
 *
 *   - Shpuld Library
 *     https://www.npmjs.com/package/should
 *
 *   - Test your REST api using Mocha and supertest
 *     https://codeforgeek.com/2015/07/unit-testing-nodejs-application-using-mocha/
 */

var util = require('util');
var request = require('supertest');
var should = require('should');
var app = require('./mb-logging-api-server');

/**
 *
 */
describe('Requests to the root (/api) path', function() {

  it('GET: Returns a 200 status code', function(done) {

    request(app)
      .get('/api')
      .expect(200, done);
  });

  it('GET: Returns JSON format', function(done) {

    request(app)
      .get('/api')
      .expect("content-type", /json/, done)
  });

});

/**
 *
 */
describe('Requests to v1 root (/api/v1) path', function() {

  it('GET: Returns a 200 status code', function(done) {

    request(app)
      .get('/api/v1')
      .expect(200, done);
  });

  it('GET: Returns JSON format', function(done) {

    request(app)
      .get('/api/v1')
      .expect("content-type", /json/, done)
  });

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/imports) path', function() {

  it('POST: Returns a 400 status code when required parameters "type", "exists", "source", "origin", "processed_timestamp" and "email" OR "phone" or "drupal_uid" are not defined.', function(done) {

    request(app)
      .post('/api/v1/imports')
      .expect(400, done);
  });

  it('POST: Returns JSON format with 400 response.', function(done) {

    request(app)
      .post('/api/v1/imports')
      .expect('content-type', 'application/json', done);
  });

  // @todo
  /*
  it('GET: Lookup of missing import log entry returns 404 response code.', function(done) {

  });
  */

  it('POST: Addition of import log entry returns 201 response code and "OK" message.', function(done) {

    urlParams = '?source=niche&exists=1&origin=Niche-12-12-15.csv&processed_timestamp=1000000000&type=user_import';
    request(app)
      .post('/api/v1/imports' + urlParams)
      .send({
        "logging_timestamp": "1410000000",
        "phone": "1234567890",
        "phone_status": "Still a phone number",
        "email": "test@test.com",
        "email_status": "We got this one too.",
        "email_acquired_timestamp": "1400000000",
        "drupal_uid": "12000000",
        "drupal_email": "test@test.com"
      })
      .expect("content-type", /json/)
      .expect(201)
      .end(function(err, response) {
        if (err) {
          throw err;
        }
        response.status.should.equal(201)
        response.body.should.equal("OK")
        done();
      });
  });

  // @todo
  /*
  it('GET: Lookup of import log entry returns 200 response code. Returned data is formatted as expected.', function(done) {

  });
  */

  // @todo
  /*
  it('DELETE: Test import log entry returns 200 response code.', function(done) {

  });
  */

  // @todo
  /*
  it('GET: Lookup of deleted import log entry returns 404 response code.', function(done) {

  });
  */

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/imports/summaries) path', function() {

  it('POST: Returns a 400 status code when required parameters "type", "source", "target_CSV_file", "signup_count" and "skipped" are not defined.', function(done) {

    request(app)
      .post('/api/v1/imports/summaries')
      .expect(400, done);
  });

  it('POST: Returns JSON format with 400 response.', function(done) {

    request(app)
      .post('/api/v1/imports/summaries')
      .expect('content-type', 'application/json', done);
  });

  // @todo
  /*
  it('GET: Lookup of missing import summary log entries returns 404 response code.', function(done) {

  });
  */

  it('POST: Addition of import log summary entry returns 201 response code and "OK" message.', function(done) {

    urlParams = '?source=niche&type=user_import';
    request(app)
      .post('/api/v1/imports/summaries' + urlParams)
      .send({
        "logging_timestamp": "1410000000",
        "target_CSV_file": "2015-13-00.csv",
        "signup_count": "69",
        "skipped": "1"
      })
      .expect("content-type", /json/)
      .expect(201)
      .end(function(err, response) {
        if (err) {
          throw err;
        }
        response.status.should.equal(201)
        response.body.should.equal("OK")
        done();
      });
  });

  // @todo
  /*
  it('GET: Lookup of summary import log entry returns 200 response code. Returned data is formatted as expected.', function(done) {

  });
  */

  // @todo
  /*
  it('DELETE: Test summary log entry returns 200 response code.', function(done) {

  });
  */

  // @todo
  /*
  it('GET: Lookup of deleted import summary log entry returns 404 response code.', function(done) {

  });
  */

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/user/activity) path', function() {

  it('POST: Returns a 400 status code when required parameter "vote" is not defined.', function(done) {

    request(app)
      .post('/api/v1/user/activity')
      .expect(400, done);
  });

  it('POST: Returns JSON format', function(done) {

    request(app)
      .post('/api/v1/user/activity')
      .expect('content-type', 'application/json', done);
  });

  it('GET: Returns a 400 status code when required parameter "type" and "source" are not defined.', function(done) {

    request(app)
      .get('/api/v1/user/activity')
      .expect(400, done);
  });

  it('GET: Returns JSON format', function(done) {

    request(app)
      .get('/api/v1/user/activity')
      .expect("content-type", /json/, done);
  });

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/user/transactional) path', function() {

  it('POST: Returns a 400 status code when required parameter "email" and "activity" are not defined.', function(done) {

    request(app)
      .post('/api/v1/user/transactional')
      .expect(400, done);
  });

  it('POST: Returns JSON format with 400 response.', function(done) {

    request(app)
      .post('/api/v1/user/transactional')
      .expect("content-type", /json/, done);
  });

  it('POST: Addition of user activity "user_register" entry returns 201 response code and "OK" message.', function(done) {

    urlParams = '?email=test%40test.com&activity=user_registration';
    request(app)
      .post('/api/v1/user/transactional' + urlParams)
      .send({
        "source": "US",
        "activity_timestamp": "1450143371",
        "message": "a:13:{s:8:\"activity\";s:13:\"user_register\";s:5:\"email\";s:13:\"test@test.com\";s:3:\"uid\";s:7:\"3400745\";s:10:\"merge_vars\";a:2:{s:12:\"MEMBER_COUNT\";s:11:\"4.6 million\";s:5:\"FNAME\";s:4:\"Test\";}s:12:\"user_country\";s:2:\"US\";s:13:\"user_language\";s:2:\"en\";s:14:\"email_template\";s:19:\"mb-user-register-US\";s:17:\"mailchimp_list_id\";s:10:\"f2fab1dfd4\";s:9:\"birthdate\";s:9:\"133574400\";s:10:\"subscribed\";i:1;s:10:\"email_tags\";a:1:{i:0;s:20:\"drupal_user_register\";}s:18:\"activity_timestamp\";i:1450143371;s:14:\"application_id\";s:2:\"US\";}"
      })
      .expect("content-type", /json/)
      .expect(201)
      .end(function(err, response) {
        if (err) {
          throw err;
        }
        response.status.should.equal(201)
        response.body.should.equal("OK")
        done();
      });
  });

  it('GET: Lookup of user activity log entries returns 200 response code and JSON message. Returned data is formatted as expected.', function(done) {

    urlParams = '?email=test%40test.com';
    request(app)
      .get('/api/v1/user/transactional' + urlParams)
      .expect(200)
      .expect("content-type", /json/)
      .end(function(err, res) {
        if (err) throw err;
        res.status.should.equal(200);
        res.body[0].email.should.equal("test@test.com");
        res.body[0].activity.should.equal("user_registration");
        res.body[0].activity_details.should.not.equal(null);
        res.body[0].should.have.property('activity_date');
        res.body[0].should.have.property('logged_date');
        done();
      });
  });

  // @todo
  /*
  it('DELETE: Test user activity log entry returns 200 response code.', function(done) {

  });
  */

  // @todo
  /*
  it('GET: Lookup of deleted user activity log entry returns 404 response code.', function(done) {

  });
  */

});
<commit_msg>DELETE test for /api/v1/user/transactional<commit_after>/**
 * Test for mb-logging-api
 *
 * References:
 *   - HOW TO BUILD AND TEST YOUR REST API WITH NODE.JS, EXPRESS AND MOCHA
 *     https://thewayofcode.wordpress.com/tag/supertest
 *
 *   - Shpuld Library
 *     https://www.npmjs.com/package/should
 *
 *   - Test your REST api using Mocha and supertest
 *     https://codeforgeek.com/2015/07/unit-testing-nodejs-application-using-mocha/
 */

var util = require('util');
var request = require('supertest');
var should = require('should');
var app = require('./mb-logging-api-server');

/**
 *
 */
describe('Requests to the root (/api) path', function() {

  it('GET: Returns a 200 status code', function(done) {

    request(app)
      .get('/api')
      .expect(200, done);
  });

  it('GET: Returns JSON format', function(done) {

    request(app)
      .get('/api')
      .expect("content-type", /json/, done)
  });

});

/**
 *
 */
describe('Requests to v1 root (/api/v1) path', function() {

  it('GET: Returns a 200 status code', function(done) {

    request(app)
      .get('/api/v1')
      .expect(200, done);
  });

  it('GET: Returns JSON format', function(done) {

    request(app)
      .get('/api/v1')
      .expect("content-type", /json/, done)
  });

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/imports) path', function() {

  it('POST: Returns a 400 status code when required parameters "type", "exists", "source", "origin", "processed_timestamp" and "email" OR "phone" or "drupal_uid" are not defined.', function(done) {

    request(app)
      .post('/api/v1/imports')
      .expect(400, done);
  });

  it('POST: Returns JSON format with 400 response.', function(done) {

    request(app)
      .post('/api/v1/imports')
      .expect('content-type', 'application/json', done);
  });

  // @todo
  /*
  it('GET: Lookup of missing import log entry returns 404 response code.', function(done) {

  });
  */

  it('POST: Addition of import log entry returns 201 response code and "OK" message.', function(done) {

    urlParams = '?source=niche&exists=1&origin=Niche-12-12-15.csv&processed_timestamp=1000000000&type=user_import';
    request(app)
      .post('/api/v1/imports' + urlParams)
      .send({
        "logging_timestamp": "1410000000",
        "phone": "1234567890",
        "phone_status": "Still a phone number",
        "email": "test@test.com",
        "email_status": "We got this one too.",
        "email_acquired_timestamp": "1400000000",
        "drupal_uid": "12000000",
        "drupal_email": "test@test.com"
      })
      .expect("content-type", /json/)
      .expect(201)
      .end(function(err, response) {
        if (err) {
          throw err;
        }
        response.status.should.equal(201)
        response.body.should.equal("OK")
        done();
      });
  });

  // @todo
  /*
  it('GET: Lookup of import log entry returns 200 response code. Returned data is formatted as expected.', function(done) {

  });
  */

  // @todo
  /*
  it('DELETE: Test import log entry returns 200 response code.', function(done) {

  });
  */

  // @todo
  /*
  it('GET: Lookup of deleted import log entry returns 404 response code.', function(done) {

  });
  */

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/imports/summaries) path', function() {

  it('POST: Returns a 400 status code when required parameters "type", "source", "target_CSV_file", "signup_count" and "skipped" are not defined.', function(done) {

    request(app)
      .post('/api/v1/imports/summaries')
      .expect(400, done);
  });

  it('POST: Returns JSON format with 400 response.', function(done) {

    request(app)
      .post('/api/v1/imports/summaries')
      .expect('content-type', 'application/json', done);
  });

  // @todo
  /*
  it('GET: Lookup of missing import summary log entries returns 404 response code.', function(done) {

  });
  */

  it('POST: Addition of import log summary entry returns 201 response code and "OK" message.', function(done) {

    urlParams = '?source=niche&type=user_import';
    request(app)
      .post('/api/v1/imports/summaries' + urlParams)
      .send({
        "logging_timestamp": "1410000000",
        "target_CSV_file": "2015-13-00.csv",
        "signup_count": "69",
        "skipped": "1"
      })
      .expect("content-type", /json/)
      .expect(201)
      .end(function(err, response) {
        if (err) {
          throw err;
        }
        response.status.should.equal(201)
        response.body.should.equal("OK")
        done();
      });
  });

  // @todo
  /*
  it('GET: Lookup of summary import log entry returns 200 response code. Returned data is formatted as expected.', function(done) {

  });
  */

  // @todo
  /*
  it('DELETE: Test summary log entry returns 200 response code.', function(done) {

  });
  */

  // @todo
  /*
  it('GET: Lookup of deleted import summary log entry returns 404 response code.', function(done) {

  });
  */

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/user/activity) path', function() {

  it('POST: Returns a 400 status code when required parameter "vote" is not defined.', function(done) {

    request(app)
      .post('/api/v1/user/activity')
      .expect(400, done);
  });

  it('POST: Returns JSON format', function(done) {

    request(app)
      .post('/api/v1/user/activity')
      .expect('content-type', 'application/json', done);
  });

  it('GET: Returns a 400 status code when required parameter "type" and "source" are not defined.', function(done) {

    request(app)
      .get('/api/v1/user/activity')
      .expect(400, done);
  });

  it('GET: Returns JSON format', function(done) {

    request(app)
      .get('/api/v1/user/activity')
      .expect("content-type", /json/, done);
  });

});

/**
 *
 */
describe('Requests to v1 imports (/api/v1/user/transactional) path', function() {

  it('POST: Returns a 400 status code when required parameter "email" and "activity" are not defined.', function(done) {

    request(app)
      .post('/api/v1/user/transactional')
      .expect(400, done);
  });

  it('POST: Returns JSON format with 400 response.', function(done) {

    request(app)
      .post('/api/v1/user/transactional')
      .expect("content-type", /json/, done);
  });

  it('POST: Addition of user activity "user_register" entry returns 201 response code and "OK" message.', function(done) {

    urlParams = '?email=test%40test.com&activity=user_registration';
    request(app)
      .post('/api/v1/user/transactional' + urlParams)
      .send({
        "source": "US",
        "activity_timestamp": "1450143371",
        "message": "a:13:{s:8:\"activity\";s:13:\"user_register\";s:5:\"email\";s:13:\"test@test.com\";s:3:\"uid\";s:7:\"3400745\";s:10:\"merge_vars\";a:2:{s:12:\"MEMBER_COUNT\";s:11:\"4.6 million\";s:5:\"FNAME\";s:4:\"Test\";}s:12:\"user_country\";s:2:\"US\";s:13:\"user_language\";s:2:\"en\";s:14:\"email_template\";s:19:\"mb-user-register-US\";s:17:\"mailchimp_list_id\";s:10:\"f2fab1dfd4\";s:9:\"birthdate\";s:9:\"133574400\";s:10:\"subscribed\";i:1;s:10:\"email_tags\";a:1:{i:0;s:20:\"drupal_user_register\";}s:18:\"activity_timestamp\";i:1450143371;s:14:\"application_id\";s:2:\"US\";}"
      })
      .expect("content-type", /json/)
      .expect(201)
      .end(function(err, response) {
        if (err) {
          throw err;
        }
        response.status.should.equal(201)
        response.body.should.equal("OK")
        done();
      });
  });

  it('GET: Lookup of user activity log entries returns 200 response code and JSON message. Returned data is formatted as expected.', function(done) {

    urlParams = '?email=test%40test.com';
    request(app)
      .get('/api/v1/user/transactional' + urlParams)
      .expect(200)
      .expect("content-type", /json/)
      .end(function(err, res) {
        if (err) throw err;
        res.status.should.equal(200);
        res.body[0].email.should.equal("test@test.com");
        res.body[0].activity.should.equal("user_registration");
        res.body[0].activity_details.should.not.equal(null);
        res.body[0].should.have.property('activity_date');
        res.body[0].should.have.property('logged_date');
        done();
      });
  });

  it('DELETE: Test user "test@test.com" activity log entry returns 200 response code and JSON "OK".', function(done) {

    urlParams = '?email=test%40test.com';
    request(app)
      .delete('/api/v1/user/transactional' + urlParams)
      .expect(200)
      .expect("content-type", /json/)
      .end(function(err, response) {
        if (err) throw err;
        response.status.should.equal(200);
        response.body.should.equal("OK");
        done();
      });

  });

  // @todo
  /*
  it('GET: Lookup of deleted user activity log entry returns 404 response code.', function(done) {

  });
  */

});
<|endoftext|>


<commit_before>const Tests = require('./testModel.js').Tests;
const Students = require('./../student/studentModel.js').Students;
const answerKeys = require('./../key/keyModel.js').answerKeys;

//promise import?

//MVP: 1 key

const compareArrays = (array1, array2) => {
  if (array1.length !== array2.length) {
    return false;
  }
  return array1.reduce((acc, val, index) => {
    return acc && val === array2[index];
  }, true);
};

const calculateResult = (studentAnswers, keyAnswers, cb) => {
  let amountPossible = 0;
  for (let key in keyAnswers) {
    if (keyAnswers[key].length > 0) {
      amountPossible++;
    }
  }
  let amountCorrect = 0;
  for (let key in studentAnswers) {
    if ()
  }
};

exports.getStudentAnswers = (test, cb) => {
  //TODO: coordinate input file with server
};

exports.addTest = (test, cb) => {
  answerKeys.findOne(where: {id: test.answerKeysId})
  .then((answerKey) => {
    let keyAnswers = JSON.parse(answerKey.answers);
    Tests.findOne(where: {id: test.id})
    .then((testResult) => {
      let studentResponses = JSON.parse(testResult.studentAnswers);
      let amountCorrect = 0;
      calculateResult(studentResponses, keyAnswers, (percentage) => {
        cb(null, percentage);
      });
    }).catch((err) => {
      cb(err);
    });
  }).catch((err) => {
    cb(err);
  });
};
<commit_msg>(feat) implement calculateResult function<commit_after>const Tests = require('./testModel.js').Tests;
const Students = require('./../student/studentModel.js').Students;
const answerKeys = require('./../key/keyModel.js').answerKeys;

//MVP: 1 key
const compareArrays = (array1, array2) => {
  if (array1.length !== array2.length) {
    return false;
  }
  return array1.reduce((acc, val, index) => {
    return acc && val === array2[index];
  }, true);
};

const calculateResult = (studentAnswers, keyAnswers, cb) => {
  let amountPossible = 0;
  for (let key in keyAnswers) {
    if (keyAnswers[key].length > 0) {
      amountPossible++;
    }
  }

  let amountCorrect = 0;
  for (let key in studentAnswers) {
    if (keyAnswers[key].length > 0 && compareArrays(studentAnswers[key], keyAnswers[key])) {
      amountCorrect++;
    }
  }

  //round to two decimal places
  let percentage = Math.round((amountCorrect/amountPossible) * 100) / 100
  cb(percentage);
};

exports.getStudentAnswers = (test, cb) => {
  //TODO: coordinate input file with server
};

exports.addTest = (test, cb) => {
  answerKeys.findOne(where: {id: test.answerKeysId})
  .then((answerKey) => {
    let keyAnswers = JSON.parse(answerKey.answers);
    Tests.findOne(where: {id: test.id})
    .then((testResult) => {
      let studentResponses = JSON.parse(testResult.studentAnswers);
      let amountCorrect = 0;
      calculateResult(studentResponses, keyAnswers, (percentage) => {
        cb(null, percentage);
      });
    }).catch((err) => {
      cb(err);
    });
  }).catch((err) => {
    cb(err);
  });
};
<|endoftext|>


<commit_before>/**
 * Created by Tamar mamo on 23/06/2016.
 */
<commit_msg>Fix loading problem<commit_after>function buyController($scope, $routeParams, $http) {

    $scope.onLoad=onLoad;
    $scope.title={};
    $scope.session = {};

    onLoad();

    function onLoad(){
        var text;
        var signed;
        console.log("in on load");

        $http.post('/userManage/getSessionInfo')
            .success(function(data){
                signed = data.signed;
                $scope.session = data.session;

                if(signed)
                {
                    document.getElementById("name").textContent = $scope.session.user.userName+" | ";

                }

            })
            .error(function(data){
                console.log("Error: "+data);
            });
    }

}

<|endoftext|>


<commit_before>
/*
 *  OpenWFEru - open source ruby workflow and bpm engine
 *  (c) 2008 John Mettraux
 *
 *  OpenWFEru is freely distributable under the terms
 *  of a BSD-style license.
 *  For details, see the OpenWFEru web site: http://openwferu.rubyforge.org
 *
 *  This piece of hack was created during the RubyKaigi2008,
 *  between Tsukuba and Akihabara.
 */

//var flow = [ 'process-definition', { 'name': 'toto', 'revision': '1.0' }, [
//    [ 'sequence', {}, [
//      [ 'participant', { 'ref': 'alpha' }, [] ],
//      [ 'bravo', {}, [] ]
//    ]]
//  ]
//]

HTMLElement.prototype.firstChildOfClass = function (className) {

  for (var i=0; i < this.childNodes.length; i++) {
    var c = this.childNodes[i];
    if (c.className == className) return c;
  }

  return null;
}
String.prototype.tstrip = function () {
  var s = this;
  while (s.charAt(0) == ' ') s = s.substring(1);
  while (s.charAt(s.length - 1) == ' ') s = s.substring(0, s.length - 1);
  return s;
}

var Tred = function () {

  var ExpressionHead = function () {

    function createButton (imgsrc, tooltip, callback) {

      var i = document.createElement("img");
      i.callback = callback;
      i.className = "tred_button";
      i.setAttribute('src', imgsrc);
      i.setAttribute('title', tooltip);
      i.setAttribute("onclick", "this.callback()");
      return i;
    }

    function addHeadButtons (expdiv) {

      var outOpacity = 0.0;

      var buttons = document.createElement("span");
      buttons.style.opacity = outOpacity;

      expdiv.onmouseover = function () {
        buttons.style.opacity = 1.0;
        Tred.onOver(computeExpId(expdiv.parentNode));
      };
      expdiv.onmouseout = function () {
        buttons.style.opacity = outOpacity;
        Tred.onOver(null);
      };

      buttons.appendChild(createButton(
        'images/btn-add.gif',
        'add a child expression',
        function () {
          Tred.addExpression(expdiv.parentNode, [ "---", {}, [] ]);
        }));
      buttons.appendChild(createButton(
        'images/btn-cut.gif',
        'cut expression',
        function () {
          Tred.removeExpression(expdiv.parentNode);
        }));

      buttons.appendChild(createButton(
        'images/btn-moveup.gif',
        'move expression up',
        function () {
          Tred.moveExpression(expdiv.parentNode, -1);
          buttons.style.opacity = outOpacity;
        }));

      buttons.appendChild(createButton(
        'images/btn-movedown.gif',
        'move expression down',
        function () {
          Tred.moveExpression(expdiv.parentNode, +1);
          buttons.style.opacity = outOpacity;
        }));

      buttons.appendChild(createButton(
        'images/btn-paste.gif',
        'paste expression here',
        function () {
          var clip = document._tred_clipboard;
          if (clip) Tred.insertExpression(expdiv.parentNode, clip);
        }));

      expdiv.appendChild(buttons);
    }

    return {

      render: function (exp) {

        var expname = exp[0];

        var text = '';
        if ((typeof exp[2][0]) == 'string') text = exp[2].shift();

        //var atts = [];
        //for (key in exp[1]) {
        //  var skey = key.replace(/-/, '_');
        //  var sval = fluoToJson(exp[1][key]);
        //  atts.push("" + skey + ': ' + sval);
        //}
        //atts = atts.join(", ");
        var atts = fluoToJson(exp[1]);
        atts = atts.substring(1, atts.length - 1);

        var d = document.createElement('div');

        var sen = document.createElement('span');
        sen.setAttribute('class', 'tred_exp_span tred_expression_name');
        sen.appendChild(document.createTextNode(expname));
        d.appendChild(sen);

        var ses = document.createElement('span');
        ses.setAttribute('class', 'tred_exp_span tred_expression_string');
        var t = text;
        if (t != '') t = ' ' + t;
        ses.appendChild(document.createTextNode(t));
        d.appendChild(ses);

        var sea = document.createElement('span');
        sea.setAttribute('class', 'tred_exp_span tred_expression_atts');
        sea.appendChild(document.createTextNode(' ' + atts));
        d.appendChild(sea);

        addHeadButtons(d);

        var onblur = function () {

          var p = d.parentNode;
          var d2 = ExpressionHead.render(ExpressionHead.parse(this.value));
          p.replaceChild(d2, d);

          triggerChange(p); // trigger onChange()...
        };

        var onkeyup = function (evt) {

          var e = evt || window.event;
          var c = e.charCode || e.keyCode;
          if (c == 13) this.blur();

          return false;
        }

        var onclick = function () {
          d.removeChild(sen);
          d.removeChild(ses);
          var input = document.createElement('input');
          input.setAttribute('type', 'text');
          input.value = expname + ' ' + atts;
          if (text != '') input.value = expname + ' ' + text + ' ' + atts;
          d.replaceChild(input, sea);
          input.onblur = onblur;
          input.onkeyup = onkeyup;
          input.focus();
        };

        sen.onclick = onclick;
        ses.onclick = onclick;
        sea.onclick = onclick;

        return d;
      },

      parse: function (s) {

        var m = s.match(/^(\S*)( [.]*[^:]*)?( .*)?$/);

        if (m == null) return ['---', {}, []];

        var expname = m[1];

        var children = [];
        if (m[2]) {
          var t = m[2].tstrip();
          if (t != '') children.push(t);
        }

        var atts = m[3];
        atts = atts ? fluoFromJson('({' + atts + '})') : {};

        return [ expname, atts, children ];
      },

      toExp: function (node) {

        node = node.firstChild;

        var name = node.childNodes[0].firstChild.nodeValue;
        var text = node.childNodes[1].firstChild.nodeValue;
        var atts = node.childNodes[2].firstChild.nodeValue;

        atts = fluoFromJson('({' + atts + '})');

        var children = [];
        if (text != '') children.push(text.tstrip());
          // child is just a string...

        return [ name, atts, children ];
      }
    };
  }();

  function asJson (node) {

    if ((typeof node) == 'string')
      node = document.getElementById(node);

    return fluoToJson(toTree(node));
  }

  function onChange (tree) {

    alert("Tred.onChange(tree) : please override me");
  }

  function onOver (expid) {

    alert("Tred.onOver(expid) : please override me");
  }

  function renderOpening (node, exp) {

    var opening = ExpressionHead.render(exp);

    //var outOpacity = 0.03;
    var outOpacity = 0.0;

    node.appendChild(opening);
  }

  function renderEnding (node, exp) {

    var ending = document.createElement("div");
    ending.className = "tred_text";
    if (exp[2].length > 0) ending.appendChild(document.createTextNode("end"));
    node.appendChild(ending);
  }

  function renderExpressionString (node, s) {

    var opening = document.createElement("div");

    var sname = document.createElement("span");
    sname.appendChild(document.createTextNode(s));
    sname.setAttribute("onclick", "EditableSpan.toInput(this);");
    sname.className = "tred_expression_string";
    opening.appendChild(sname);

    node.appendChild(opening);
  }

  function addExpression (parentExpNode, exp) {

    var end = parentExpNode.lastChild;
    var node = renderExpression(parentExpNode, exp);
    parentExpNode.replaceChild(node, end);
    parentExpNode.appendChild(end);

    triggerChange(parentExpNode);
  }

  function removeExpression (expNode) {

    var p = expNode.parentNode;
    p.removeChild(expNode);

    document._tred_clipboard = toTree(expNode);

    triggerChange(p);
  }

  function renderExpression (parentNode, exp, isRootExp) {

    //
    // draw expression

    var node = document.createElement("div");
    node.className = "tred_expression";
    if ( ! isRootExp) {
      //node.setAttribute("style", "margin-left: "+this.indentation+"px;");
      node.setAttribute("style", "margin-left: 14px;");
    }
    parentNode.appendChild(node);

    if ( ! (exp instanceof Array)) {

      renderExpressionString(node, exp.toString());
      return;
    }

    renderOpening(node, exp);

    //
    // draw children

    for (var i=0; i < exp[2].length; i++) {

      var child = exp[2][i];

      renderExpression(node, child);
    }

    renderEnding(node, exp);

    return node;
  }

  function renderFlow (parentNode, flow) {

    renderExpression(parentNode, flow, true);

    parentNode.className = "tred_root";

    parentNode.stack = []; // the undo stack
    parentNode.currentTree = flow;
  }

  function moveExpression (elt, delta) {

    var p = elt.parentNode;

    if (delta == -1) { // move up
      if (elt.previousSibling.className != "tred_expression") return;
      p.insertBefore(elt, elt.previousSibling);
    }
    else { // move down
      if (elt.nextSibling.className != "tred_expression") return;
      p.insertBefore(elt, elt.nextSibling.nextSibling);
    }

    Tred.triggerChange(p); // onChange() points to the original version !
  }

  function insertExpression (before, exp) {

    var newNode = renderExpression(before.parentNode, exp);

    before.parentNode.insertBefore(newNode, before);

    Tred.triggerChange(before.parentNode);
  }

  function triggerChange (elt) {

    var tredRoot = findTredRoot(elt);
    var tree = toTree(tredRoot);

    stack(tredRoot, tree);

    Tred.onChange(tree); // onChange() points to the original version !
  }

  function stack(root, tree) {
    root.stack.push(root.currentTree);
    root.currentTree = tree;
  }

  function undo (root) {

    if ((typeof root) == 'string') root = document.getElementById(root);
    if (root.stack.length < 1) return;

    while (root.firstChild != null) root.removeChild(root.firstChild);

    var tree = root.stack.pop();

    root.currentTree = tree;
    renderExpression(root, tree, true);

    //triggerChange(root);
    Tred.onChange(tree);
  }

  function findTredRoot (node) {

      if (node.className == 'tred_root') return node;
      return findTredRoot(node.parentNode);
  }

  function computeExpId (node, from, expid) {

    if (from == null) {
      from = findTredRoot(node);
      expid = '';
    }
    if (from == node) return expid.substring(1, expid.length);

    var divs = from.childNodes;
    var childid = -1;

    for (var i=0; i<divs.length; i++) {
      var e = divs[i];
      if (e.nodeType != 1) continue;
      if (e.className != "tred_expression") continue;
      childid += 1;
      var ei = computeExpId(node, e, expid + "." + childid);
      if (ei != null) return ei;
    }

    return null;
  }

  function toTree (node) {

    node.focus();
      //
      // making sure all the input boxes get blurred...

    if (node.className != 'tred_expression') {
      node = node.firstChildOfClass('tred_expression');
    }

    //
    // expression itself

    var exp = ExpressionHead.toExp(node);

    //
    // children

    var divs = node.childNodes;

    var children = exp[2];

    for (var i=0; i<divs.length; i++) {
      var e = divs[i];
      if (e.nodeType != 1) continue;
      if (e.className != "tred_expression") continue;
      children.push(toTree(e));
    }

    //
    // done

    return exp;
  }

  //
  // public methods
  //
  return {
    renderFlow: renderFlow,
    onChange: onChange,
    onOver: onOver,
    addExpression: addExpression,
    removeExpression: removeExpression,
    moveExpression: moveExpression,
    insertExpression: insertExpression,
    triggerChange: triggerChange,
    undo: undo,
    asJson: asJson
  };
}();

<commit_msg>taking care of adding or removing 'end' as needed<commit_after>
/*
 *  OpenWFEru - open source ruby workflow and bpm engine
 *  (c) 2008 John Mettraux
 *
 *  OpenWFEru is freely distributable under the terms
 *  of a BSD-style license.
 *  For details, see the OpenWFEru web site: http://openwferu.rubyforge.org
 *
 *  This piece of hack was created during the RubyKaigi2008,
 *  between Tsukuba and Akihabara.
 */

//var flow = [ 'process-definition', { 'name': 'toto', 'revision': '1.0' }, [
//    [ 'sequence', {}, [
//      [ 'participant', { 'ref': 'alpha' }, [] ],
//      [ 'bravo', {}, [] ]
//    ]]
//  ]
//]

HTMLElement.prototype.firstChildOfClass = function (className) {
  for (var i=0; i < this.childNodes.length; i++) {
    var c = this.childNodes[i];
    if (c.className == className) return c;
  }
  return null;
}
String.prototype.tstrip = function () {
  var s = this;
  while (s.charAt(0) == ' ') s = s.substring(1);
  while (s.charAt(s.length - 1) == ' ') s = s.substring(0, s.length - 1);
  return s;
}

var Tred = function () {

  var ExpressionHead = function () {

    function createButton (imgsrc, tooltip, callback) {

      var i = document.createElement("img");
      i.callback = callback;
      i.className = "tred_button";
      i.setAttribute('src', imgsrc);
      i.setAttribute('title', tooltip);
      i.setAttribute("onclick", "this.callback()");
      return i;
    }

    function addHeadButtons (expdiv) {

      var outOpacity = 0.0;

      var buttons = document.createElement('span');
      buttons.style.opacity = outOpacity;

      expdiv.onmouseover = function () {
        buttons.style.opacity = 1.0;
        Tred.onOver(computeExpId(expdiv.parentNode));
      };
      expdiv.onmouseout = function () {
        buttons.style.opacity = outOpacity;
        Tred.onOver(null);
      };

      buttons.appendChild(createButton(
        'images/btn-add.gif',
        'add a child expression',
        function () {
          Tred.addExpression(expdiv.parentNode, [ '---', {}, [] ]);
        }));
      buttons.appendChild(createButton(
        'images/btn-cut.gif',
        'cut expression',
        function () {
          Tred.removeExpression(expdiv.parentNode);
        }));

      buttons.appendChild(createButton(
        'images/btn-moveup.gif',
        'move expression up',
        function () {
          Tred.moveExpression(expdiv.parentNode, -1);
          buttons.style.opacity = outOpacity;
        }));

      buttons.appendChild(createButton(
        'images/btn-movedown.gif',
        'move expression down',
        function () {
          Tred.moveExpression(expdiv.parentNode, +1);
          buttons.style.opacity = outOpacity;
        }));

      buttons.appendChild(createButton(
        'images/btn-paste.gif',
        'paste expression here',
        function () {
          var clip = document._tred_clipboard;
          if (clip) Tred.insertExpression(expdiv.parentNode, clip);
        }));

      expdiv.appendChild(buttons);
    }

    return {

      render: function (exp) {

        var expname = exp[0];

        var text = '';
        if ((typeof exp[2][0]) == 'string') text = exp[2].shift();

        //var atts = [];
        //for (key in exp[1]) {
        //  var skey = key.replace(/-/, '_');
        //  var sval = fluoToJson(exp[1][key]);
        //  atts.push("" + skey + ': ' + sval);
        //}
        //atts = atts.join(", ");
        var atts = fluoToJson(exp[1]);
        atts = atts.substring(1, atts.length - 1);

        var d = document.createElement('div');

        var sen = document.createElement('span');
        sen.setAttribute('class', 'tred_exp_span tred_expression_name');
        sen.appendChild(document.createTextNode(expname));
        d.appendChild(sen);

        var ses = document.createElement('span');
        ses.setAttribute('class', 'tred_exp_span tred_expression_string');
        var t = text;
        if (t != '') t = ' ' + t;
        ses.appendChild(document.createTextNode(t));
        d.appendChild(ses);

        var sea = document.createElement('span');
        sea.setAttribute('class', 'tred_exp_span tred_expression_atts');
        sea.appendChild(document.createTextNode(' ' + atts));
        d.appendChild(sea);

        addHeadButtons(d);

        var onblur = function () {

          var p = d.parentNode;
          var d2 = ExpressionHead.render(ExpressionHead.parse(this.value));
          p.replaceChild(d2, d);

          triggerChange(p); // trigger onChange()...
        };

        var onkeyup = function (evt) {

          var e = evt || window.event;
          var c = e.charCode || e.keyCode;
          if (c == 13) this.blur();

          return false;
        }

        var onclick = function () {
          d.removeChild(sen);
          d.removeChild(ses);
          var input = document.createElement('input');
          input.setAttribute('type', 'text');
          input.value = expname + ' ' + atts;
          if (text != '') input.value = expname + ' ' + text + ' ' + atts;
          d.replaceChild(input, sea);
          input.onblur = onblur;
          input.onkeyup = onkeyup;
          input.focus();
        };

        sen.onclick = onclick;
        ses.onclick = onclick;
        sea.onclick = onclick;

        return d;
      },

      parse: function (s) {

        var m = s.match(/^(\S*)( [.]*[^:]*)?( .*)?$/);

        if (m == null) return ['---', {}, []];

        var expname = m[1];

        var children = [];
        if (m[2]) {
          var t = m[2].tstrip();
          if (t != '') children.push(t);
        }

        var atts = m[3];
        atts = atts ? fluoFromJson('({' + atts + '})') : {};

        return [ expname, atts, children ];
      },

      toExp: function (node) {

        node = node.firstChild;

        var name = node.childNodes[0].firstChild.nodeValue;
        var text = node.childNodes[1].firstChild.nodeValue;
        var atts = node.childNodes[2].firstChild.nodeValue;

        atts = fluoFromJson('({' + atts + '})');

        var children = [];
        if (text != '') children.push(text.tstrip());
          // child is just a string...

        return [ name, atts, children ];
      }
    };
  }();

  function asJson (node) {

    if ((typeof node) == 'string')
      node = document.getElementById(node);

    return fluoToJson(toTree(node));
  }

  function onChange (tree) {

    alert('Tred.onChange(tree) : please override me');
  }

  function onOver (expid) {

    alert('Tred.onOver(expid) : please override me');
  }

  function renderOpening (node, exp) {

    var opening = ExpressionHead.render(exp);

    //var outOpacity = 0.03;
    var outOpacity = 0.0;

    node.appendChild(opening);
  }

  function renderEnding (node, exp) {

    var ending = document.createElement('div');
    ending.className = 'tred_text';
    if (exp[2].length > 0) ending.appendChild(document.createTextNode('end'));
    node.appendChild(ending);
  }

  function renderExpressionString (node, s) {

    var opening = document.createElement('div');

    var sname = document.createElement('span');
    sname.appendChild(document.createTextNode(s));
    sname.setAttribute('onclick', 'EditableSpan.toInput(this);');
    sname.className = 'tred_expression_string';
    opening.appendChild(sname);

    node.appendChild(opening);
  }

  function addExpression (parentExpNode, exp) {

    var end = parentExpNode.lastChild;
    var node = renderExpression(parentExpNode, exp);
    parentExpNode.replaceChild(node, end);
    parentExpNode.appendChild(end);

    if (end.childNodes.length == 0)
      end.appendChild(document.createTextNode('end'));

    triggerChange(parentExpNode);
  }

  function removeExpression (expNode) {

    var p = expNode.parentNode;
    p.removeChild(expNode);

    if (p.childNodes.length == 2) {
      p.lastChild.removeChild(p.lastChild.firstChild);
    }

    document._tred_clipboard = toTree(expNode);

    triggerChange(p);
  }

  function renderExpression (parentNode, exp, isRootExp) {

    //
    // draw expression

    var node = document.createElement('div');
    node.className = 'tred_expression';
    if ( ! isRootExp) {
      //node.setAttribute('style', 'margin-left: '+this.indentation+'px;');
      node.setAttribute('style', 'margin-left: 14px;');
    }
    parentNode.appendChild(node);

    if ( ! (exp instanceof Array)) {

      renderExpressionString(node, exp.toString());
      return;
    }

    renderOpening(node, exp);

    //
    // draw children

    for (var i=0; i < exp[2].length; i++) {

      var child = exp[2][i];

      renderExpression(node, child);
    }

    renderEnding(node, exp);

    return node;
  }

  function renderFlow (parentNode, flow) {

    renderExpression(parentNode, flow, true);

    parentNode.className = 'tred_root';

    parentNode.stack = []; // the undo stack
    parentNode.currentTree = flow;
  }

  function moveExpression (elt, delta) {

    var p = elt.parentNode;

    if (delta == -1) { // move up
      if (elt.previousSibling.className != 'tred_expression') return;
      p.insertBefore(elt, elt.previousSibling);
    }
    else { // move down
      if (elt.nextSibling.className != 'tred_expression') return;
      p.insertBefore(elt, elt.nextSibling.nextSibling);
    }

    Tred.triggerChange(p); // onChange() points to the original version !
  }

  function insertExpression (before, exp) {

    var newNode = renderExpression(before.parentNode, exp);

    before.parentNode.insertBefore(newNode, before);

    Tred.triggerChange(before.parentNode);
  }

  function triggerChange (elt) {

    var tredRoot = findTredRoot(elt);
    var tree = toTree(tredRoot);

    stack(tredRoot, tree);

    Tred.onChange(tree); // onChange() points to the original version !
  }

  function stack(root, tree) {
    root.stack.push(root.currentTree);
    root.currentTree = tree;
  }

  function undo (root) {

    if ((typeof root) == 'string') root = document.getElementById(root);
    if (root.stack.length < 1) return;

    while (root.firstChild != null) root.removeChild(root.firstChild);

    var tree = root.stack.pop();

    root.currentTree = tree;
    renderExpression(root, tree, true);

    //triggerChange(root);
    Tred.onChange(tree);
  }

  function findTredRoot (node) {

      if (node.className == 'tred_root') return node;
      return findTredRoot(node.parentNode);
  }

  function computeExpId (node, from, expid) {

    if (from == null) {
      from = findTredRoot(node);
      expid = '';
    }
    if (from == node) return expid.substring(1, expid.length);

    var divs = from.childNodes;
    var childid = -1;

    for (var i=0; i<divs.length; i++) {
      var e = divs[i];
      if (e.nodeType != 1) continue;
      if (e.className != 'tred_expression') continue;
      childid += 1;
      var ei = computeExpId(node, e, expid + '.' + childid);
      if (ei != null) return ei;
    }

    return null;
  }

  function toTree (node) {

    node.focus();
      //
      // making sure all the input boxes get blurred...

    if (node.className != 'tred_expression') {
      node = node.firstChildOfClass('tred_expression');
    }

    //
    // expression itself

    var exp = ExpressionHead.toExp(node);

    //
    // children

    var divs = node.childNodes;

    var children = exp[2];

    for (var i=0; i<divs.length; i++) {
      var e = divs[i];
      if (e.nodeType != 1) continue;
      if (e.className != 'tred_expression') continue;
      children.push(toTree(e));
    }

    //
    // done

    return exp;
  }

  //
  // public methods
  //
  return {
    renderFlow: renderFlow,
    onChange: onChange,
    onOver: onOver,
    addExpression: addExpression,
    removeExpression: removeExpression,
    moveExpression: moveExpression,
    insertExpression: insertExpression,
    triggerChange: triggerChange,
    undo: undo,
    asJson: asJson
  };
}();

<|endoftext|>


<commit_before>import {
	SELECT_ITEM,
	LOAD_DATA,
	DATA_LOADING_SUCCESS,
	DATA_LOADING_ERROR,
	DELETE_ITEM,
} from './constants';

/**
 * Select an item
 *
 * @param  {String} itemId The item ID
 */
export function selectItem (itemId) {
	return {
		type: SELECT_ITEM,
		id: itemId,
	};
}

/**
 * Load the item data of the current item
 */
export function loadItemData () {
	return (dispatch, getState) => {
		// Hold on to the id of the item we currently want to load.
		// Dispatch this reference to our redux store to hold on to as a 'loadingRef'.
		const currentItemID = getState().item.id;
		dispatch({
			type: LOAD_DATA,
		});
		const state = getState();
		const list = state.lists.currentList;

		// const itemID = state.item.id;
		// Load a specific item with the utils/List.js helper
		list.loadItem(state.item.id, { drilldown: true }, (err, itemData) => {

			// Once this async request has fired this callback, check that
			// the item id referenced by thisLoadRef is the same id
			// referenced by loadingRef in the redux store.

			// If it is, then this is the latest request, and it is safe to resolve it normally.
			// If it is not the same id however,
			// this means that this request is NOT the latest fired request,
			// and so we'll bail out of it early.

			if (getState().item.id !== currentItemID) return;
			if (err || !itemData) {
				dispatch(dataLoadingError(err));
			} else {
				dispatch(dataLoaded(itemData));
			}
		});
	};
}

/**
 * Called when data of the current item is loaded
 *
 * @param  {Object} data The item data
 */
export function dataLoaded (data) {
	return {
		type: DATA_LOADING_SUCCESS,
		loadingRef: null,
		data,
	};
}

/**
 * Called when there was an error during the loading of the current item data,
 * will retry loading the data ever NETWORK_ERROR_RETRY_DELAY milliseconds
 *
 * @param  {Object} error The error
 */
export function dataLoadingError (err) {
	return {
		type: DATA_LOADING_ERROR,
		loadingRef: null,
		error: err,
	};
}

/**
 * Deletes an item and optionally redirects to the current list URL
 *
 * @param  {String} id     The ID of the item we want to delete
 * @param  {Object} router A react-router router object. If this is passed, we
 *                         redirect to Keystone.adminPath/currentList.path!
 */
export function deleteItem (id, router) {
	return (dispatch, getState) => {
		const list = getState().lists.currentList;
		list.deleteItem(id, (err) => {
			// If a router is passed, redirect to the current list path,
			// otherwise stay where we are
			if (router) {
				router.push(`${Keystone.adminPath}/${list.path}`);
			}
			// TODO Proper error handling
			if (err) {
				alert('Error deleting item, please try again!');
			} else {
				dispatch({
					type: DELETE_ITEM,
					id,
				});
			}
		});
	};
}
<commit_msg>Redirect to same page after deleting an item<commit_after>import {
	SELECT_ITEM,
	LOAD_DATA,
	DATA_LOADING_SUCCESS,
	DATA_LOADING_ERROR,
	DELETE_ITEM,
} from './constants';

/**
 * Select an item
 *
 * @param  {String} itemId The item ID
 */
export function selectItem (itemId) {
	return {
		type: SELECT_ITEM,
		id: itemId,
	};
}

/**
 * Load the item data of the current item
 */
export function loadItemData () {
	return (dispatch, getState) => {
		// Hold on to the id of the item we currently want to load.
		// Dispatch this reference to our redux store to hold on to as a 'loadingRef'.
		const currentItemID = getState().item.id;
		dispatch({
			type: LOAD_DATA,
		});
		const state = getState();
		const list = state.lists.currentList;

		// const itemID = state.item.id;
		// Load a specific item with the utils/List.js helper
		list.loadItem(state.item.id, { drilldown: true }, (err, itemData) => {

			// Once this async request has fired this callback, check that
			// the item id referenced by thisLoadRef is the same id
			// referenced by loadingRef in the redux store.

			// If it is, then this is the latest request, and it is safe to resolve it normally.
			// If it is not the same id however,
			// this means that this request is NOT the latest fired request,
			// and so we'll bail out of it early.

			if (getState().item.id !== currentItemID) return;
			if (err || !itemData) {
				dispatch(dataLoadingError(err));
			} else {
				dispatch(dataLoaded(itemData));
			}
		});
	};
}

/**
 * Called when data of the current item is loaded
 *
 * @param  {Object} data The item data
 */
export function dataLoaded (data) {
	return {
		type: DATA_LOADING_SUCCESS,
		loadingRef: null,
		data,
	};
}

/**
 * Called when there was an error during the loading of the current item data,
 * will retry loading the data ever NETWORK_ERROR_RETRY_DELAY milliseconds
 *
 * @param  {Object} error The error
 */
export function dataLoadingError (err) {
	return {
		type: DATA_LOADING_ERROR,
		loadingRef: null,
		error: err,
	};
}

/**
 * Deletes an item and optionally redirects to the current list URL
 *
 * @param  {String} id     The ID of the item we want to delete
 * @param  {Object} router A react-router router object. If this is passed, we
 *                         redirect to Keystone.adminPath/currentList.path!
 */
export function deleteItem (id, router) {
	return (dispatch, getState) => {
		const state = getState();
		const list = state.lists.currentList;
		list.deleteItem(id, (err) => {
			// If a router is passed, redirect to the current list path,
			// otherwise stay where we are
			if (router) {
				let redirectUrl = `${Keystone.adminPath}/${list.path}`;
				if (state.lists.page.index && state.lists.page.index > 1) {
					redirectUrl = `${redirectUrl}?page=${state.lists.page.index}`;
				}
				console.log(state, redirectUrl);
				router.push(redirectUrl);
			}
			// TODO Proper error handling
			if (err) {
				alert('Error deleting item, please try again!');
			} else {
				dispatch({
					type: DELETE_ITEM,
					id,
				});
			}
		});
	};
}
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */
/*global define:1, Components:1, MouseEvent:1, Window: 1, Firebug:1*/

define([
    "firebug/lib/trace",
    "firebug/lib/xpcom",
    "firebug/lib/wrapper" // dependency will go away with jsd2
],
function(FBTrace, Xpcom, Wrapper) {
"use strict";

// ********************************************************************************************* //
// Constants

const Cu = Components.utils;
var elService = Xpcom.CCSV("@mozilla.org/eventlistenerservice;1", "nsIEventListenerService");
var Events = {};

// ********************************************************************************************* //

Events.dispatch = function(listeners, name, args)
{
    if (!listeners)
    {
        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Events.dispatch " + name + " without listeners");

        return;
    }

    try
    {
        var noMethods;
        if (FBTrace.DBG_DISPATCH)
            noMethods = [];

        for (var i = 0; i < listeners.length; ++i)
        {
            var listener = listeners[i];
            if (!listener)
            {
                if (FBTrace.DBG_DISPATCH || FBTrace.DBG_ERRORS)
                    FBTrace.sysout("Events.dispatch ERROR " + i + " " + name + " to null listener.");
                continue;
            }

            if (listener[name])
            {
                try
                {
                    listener[name].apply(listener, args);
                }
                catch(exc)
                {
                    if (FBTrace.DBG_ERRORS)
                    {
                        if (exc.stack)
                        {
                            var stack = exc.stack;
                            exc.stack = stack.split('\n');
                        }

                        var culprit = listeners[i] ? listeners[i].dispatchName : null;
                        var loc = (exc.fileName ? exc.fileName + ":" + exc.lineNumber : "<unknown>");
                        FBTrace.sysout("EXCEPTION in Events.dispatch " +
                            (culprit ? culprit + "." : "") + name + ": " + exc + " in " + loc, exc);
                    }
                }
            }
            else
            {
                if (FBTrace.DBG_DISPATCH)
                    noMethods.push(listener);
            }
        }

        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Events.dispatch " + name + " to " + listeners.length + " listeners, " +
                noMethods.length + " had no such method", noMethods);
    }
    catch (exc)
    {
        if (FBTrace.DBG_ERRORS)
        {
            if (exc.stack)
            {
                var stack = exc.stack;
                exc.stack = stack.split('\n');
            }

            var culprit = listeners[i] ? listeners[i].dispatchName : null;
            FBTrace.sysout("Exception in Events.dispatch " + (culprit ? culprit + "." : "") +
                name + ": " + exc, exc);
        }
    }
};

Events.dispatch2 = function(listeners, name, args)
{
    try
    {
        var noMethods;
        if (FBTrace.DBG_DISPATCH)
            noMethods = [];

        if (!listeners)
        {
            if (FBTrace.DBG_DISPATCH)
                FBTrace.sysout("dispatch2, no listeners for " + name);
            return;
        }

        for (var i = 0; i < listeners.length; ++i)
        {
            var listener = listeners[i];
            if (listener[name])
            {
                var result = listener[name].apply(listener, args);

                if (FBTrace.DBG_DISPATCH)
                    FBTrace.sysout("dispatch2 " + name + " to #" + i + " of " + listeners.length +
                        " listeners, result " + result, {result: result, listener: listeners[i],
                        fn: listener[name].toSource()});

                if (result)
                    return result;
            }
            else
            {
                if (FBTrace.DBG_DISPATCH)
                    noMethods.push(listener);
            }
        }

        if (FBTrace.DBG_DISPATCH && noMethods.length === listeners.length)
            FBTrace.sysout("Events.dispatch2 " + name + " to " + listeners.length + " listeners, " +
                noMethods.length + " had no such method:", noMethods);
    }
    catch (exc)
    {
        if (FBTrace.DBG_ERRORS)
        {
            if (exc.stack)
                exc.stack = exc.stack.split('/n');

            FBTrace.sysout("Exception in Events.dispatch2 " + name + " exc: " + exc, exc);
        }
    }
};

// ********************************************************************************************* //
// Events

Events.cancelEvent = function(event)
{
    event.stopPropagation();
    event.preventDefault();
};

Events.isLeftClick = function(event, allowKeyModifiers)
{
    return event.button === 0 && (allowKeyModifiers || this.noKeyModifiers(event));
};

Events.isMiddleClick = function(event, allowKeyModifiers)
{
    return event.button === 1 && (allowKeyModifiers || this.noKeyModifiers(event));
};

Events.isRightClick = function(event, allowKeyModifiers)
{
    return event.button === 2 && (allowKeyModifiers || this.noKeyModifiers(event));
};

Events.isSingleClick = function(event)
{
    return event instanceof MouseEvent && event.detail === 1;
};

Events.isDoubleClick = function(event)
{
    return event instanceof MouseEvent && event.detail === 2;
};

Events.noKeyModifiers = function(event)
{
    return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
};

Events.isControlClick = function(event)
{
    return event.button === 0 && this.isControl(event);
};

Events.isShiftClick = function(event)
{
    return event.button === 0 && this.isShift(event);
};

Events.isControl = function(event)
{
    return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey;
};

Events.isAlt = function(event)
{
    return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey;
};

Events.isAltClick = function(event)
{
    return event.button === 0 && this.isAlt(event);
};

Events.isControlShift = function(event)
{
    return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey;
};

Events.isControlAlt = function(event)
{
    return (event.metaKey || event.ctrlKey) && !event.shiftKey && event.altKey;
};

Events.isShift = function(event)
{
    return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey;
};

// ********************************************************************************************* //
// DOM Events

const eventTypes =
{
    composition: [
        "composition",
        "compositionstart",
        "compositionend"
    ],

    contextmenu: [
        "contextmenu"
    ],

    drag: [
        "dragenter",
        "dragover",
        "dragexit",
        "dragdrop",
        "draggesture"
    ],

    focus: [
        "focus",
        "blur"
    ],

    form: [
        "submit",
        "reset",
        "change",
        "select",
        "input"
    ],

    key: [
        "keydown",
        "keyup",
        "keypress"
    ],

    load: [
        "load",
        "beforeunload",
        "unload",
        "abort",
        "error"
    ],

    mouse: [
        "mousedown",
        "mouseup",
        "click",
        "dblclick",
        "mouseover",
        "mouseout",
        "mousemove"
    ],

    mutation: [
        "DOMSubtreeModified",
        "DOMNodeInserted",
        "DOMNodeRemoved",
        "DOMNodeRemovedFromDocument",
        "DOMNodeInsertedIntoDocument",
        "DOMAttrModified",
        "DOMCharacterDataModified"
    ],

    paint: [
        "paint",
        "resize",
        "scroll"
    ],

    scroll: [
        "overflow",
        "underflow",
        "overflowchanged"
    ],

    text: [
        "text"
    ],

    ui: [
        "DOMActivate",
        "DOMFocusIn",
        "DOMFocusOut"
    ],

    // xxxHonza: As Simon says, XUL events must die!
    /*xul: [
        "popupshowing",
        "popupshown",
        "popuphiding",
        "popuphidden",
        "close",
        "command",
        "broadcast",
        "commandupdate"
    ],*/

    clipboard: [
        "cut",
        "copy",
        "paste"
    ],

    touch: [
        "touchstart",
        "touchend",
        "touchmove",
        "touchenter",
        "touchleave",
        "touchcancel"
    ]
};

Events.getEventFamilies = function()
{
    var families = [];
    for (var eventFamily in eventTypes)
        families.push(eventFamily);
    return families;
};

Events.getEventTypes = function(family)
{
    var types = [];
    for (var eventFamily in eventTypes)
    {
        if (!family || family === eventFamily)
        {
            for (var type in eventTypes[eventFamily])
                types.push(eventTypes[eventFamily][type]);
        }
    }

    return types;
};

Events.isEventFamily = function(eventType)
{
    return eventTypes.hasOwnProperty(eventType);
};

Events.getEventFamily = function(eventType)
{
    if (!this.families)
    {
        this.families = {};

        for (var family in eventTypes)
        {
            var types = eventTypes[family];
            for (var i = 0; i < types.length; ++i)
                this.families[types[i]] = family;
        }
    }

    return this.families[eventType];
};

Events.attachAllListeners = function(object, listener)
{
    for (var family in eventTypes)
    {
        if (family !== "mutation" || Firebug.attachMutationEvents)
            this.attachFamilyListeners(family, object, listener);
    }
};

Events.detachAllListeners = function(object, listener)
{
    for (var family in eventTypes)
    {
        if (family !== "mutation" || Firebug.attachMutationEvents)
            this.detachFamilyListeners(family, object, listener);
    }
};

Events.attachFamilyListeners = function(family, object, listener)
{
    var types = eventTypes[family];
    for (var i = 0; i < types.length; ++i)
        object.addEventListener(types[i], listener, false);
};

Events.detachFamilyListeners = function(family, object, listener)
{
    var types = eventTypes[family];
    for (var i = 0; i < types.length; ++i)
        object.removeEventListener(types[i], listener, false);
};

// ********************************************************************************************* //
// Event Listeners (+ support for tracking)

var listeners = [];

Events.addEventListener = function(parent, eventId, listener, capturing)
{
    if (FBTrace.DBG_EVENTLISTENERS)
    {
        for (var i = 0; i < listeners.length; i++)
        {
            var l = listeners[i];
            if (l.parent === parent && l.eventId === eventId && l.listener === listener &&
                l.capturing === capturing)
            {
                FBTrace.sysout("Events.addEventListener; ERROR already registered!", l);
                return;
            }
        }
    }

    parent.addEventListener(eventId, listener, capturing);

    if (FBTrace.DBG_EVENTLISTENERS)
    {
        var frames = [];
        for (var frame = Components.stack; frame; frame = frame.caller)
            frames.push(frame.filename + " (" + frame.lineNumber + ")");

        frames.shift();

        var pid = (parent.location ? parent.location + "" : typeof parent);

        listeners.push({
            parentId: pid,
            eventId: eventId,
            capturing: capturing,
            listener: listener,
            stack: frames,
            parent: parent,
        });
    }
};

Events.removeEventListener = function(parent, eventId, listener, capturing)
{
    try
    {
        parent.removeEventListener(eventId, listener, capturing);
    }
    catch (e)
    {
        if (FBTrace.DBG_ERRORS)
            FBTrace.sysout("events.removeEventListener; (" + eventId + ") " + e, e);
    }

    if (FBTrace.DBG_EVENTLISTENERS)
    {
        for (var i = 0; i < listeners.length; i++)
        {
            var l = listeners[i];
            if (l.parent === parent && l.eventId === eventId && l.listener === listener &&
                l.capturing === capturing)
            {
                listeners.splice(i, 1);
                return;
            }
        }

        // xxxHonza: it's not necessary to pollute the tracing console with this message.
        /*
        var frames = [];
        for (var frame = Components.stack; frame; frame = frame.caller)
            frames.push(frame.filename + " (" + frame.lineNumber + ")");

        frames.shift();

        var info = {
            eventId: eventId,
            capturing: capturing,
            listener: listener,
            stack: frames,
        };

        FBTrace.sysout("Events.removeEventListener; ERROR not registered!", info);
        */
    }
};

Events.getEventListenersForTarget = function(target)
{
    var listeners = elService.getListenerInfoFor(target, {});
    var ret = [];
    for (var i = 0; i < listeners.length; ++i)
    {
        var rawListener = listeners[i];
        var listener = {
            type: rawListener.type,
            capturing: rawListener.capturing,
            allowsUntrusted: rawListener.allowsUntrusted,
            func: null
        };
        if ("listenerObject" in rawListener)
        {
            listener.func = rawListener.listenerObject;
        }
        else
        {
            var debugObject = rawListener.getDebugObject();
            listener.func = (debugObject && Wrapper.unwrapIValue(debugObject));
        }

        // Skip chrome event listeners.
        if (!listener.func || rawListener.inSystemEventGroup)
            continue;
        var funcGlobal = Cu.getGlobalForObject(listener.func);
        if (!(funcGlobal instanceof Window))
            continue;
        if (funcGlobal.document.nodePrincipal.subsumes(document.nodePrincipal))
            continue;

        ret.push(listener);
    }
    return ret;
};

if (FBTrace.DBG_EVENTLISTENERS && typeof Firebug !== "undefined")
{
    Firebug.Events = {};
    Firebug.Events.getRegisteredListeners = function()
    {
        return listeners;
    };
}

// ********************************************************************************************* //

return Events;

// ********************************************************************************************* //
});
<commit_msg>Fix the pre-Fx23 path for getting event listeners<commit_after>/* See license.txt for terms of usage */
/*global define:1, Components:1, MouseEvent:1, Window: 1, Firebug:1*/

define([
    "firebug/lib/trace",
    "firebug/lib/xpcom",
    "firebug/lib/wrapper" // dependency will go away with jsd2
],
function(FBTrace, Xpcom, Wrapper) {
"use strict";

// ********************************************************************************************* //
// Constants

const Cu = Components.utils;
const Ci = Components.interfaces;
var elService = Xpcom.CCSV("@mozilla.org/eventlistenerservice;1", "nsIEventListenerService");
var Events = {};

// ********************************************************************************************* //

Events.dispatch = function(listeners, name, args)
{
    if (!listeners)
    {
        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Events.dispatch " + name + " without listeners");

        return;
    }

    try
    {
        var noMethods;
        if (FBTrace.DBG_DISPATCH)
            noMethods = [];

        for (var i = 0; i < listeners.length; ++i)
        {
            var listener = listeners[i];
            if (!listener)
            {
                if (FBTrace.DBG_DISPATCH || FBTrace.DBG_ERRORS)
                    FBTrace.sysout("Events.dispatch ERROR " + i + " " + name + " to null listener.");
                continue;
            }

            if (listener[name])
            {
                try
                {
                    listener[name].apply(listener, args);
                }
                catch(exc)
                {
                    if (FBTrace.DBG_ERRORS)
                    {
                        if (exc.stack)
                        {
                            var stack = exc.stack;
                            exc.stack = stack.split('\n');
                        }

                        var culprit = listeners[i] ? listeners[i].dispatchName : null;
                        var loc = (exc.fileName ? exc.fileName + ":" + exc.lineNumber : "<unknown>");
                        FBTrace.sysout("EXCEPTION in Events.dispatch " +
                            (culprit ? culprit + "." : "") + name + ": " + exc + " in " + loc, exc);
                    }
                }
            }
            else
            {
                if (FBTrace.DBG_DISPATCH)
                    noMethods.push(listener);
            }
        }

        if (FBTrace.DBG_DISPATCH)
            FBTrace.sysout("Events.dispatch " + name + " to " + listeners.length + " listeners, " +
                noMethods.length + " had no such method", noMethods);
    }
    catch (exc)
    {
        if (FBTrace.DBG_ERRORS)
        {
            if (exc.stack)
            {
                var stack = exc.stack;
                exc.stack = stack.split('\n');
            }

            var culprit = listeners[i] ? listeners[i].dispatchName : null;
            FBTrace.sysout("Exception in Events.dispatch " + (culprit ? culprit + "." : "") +
                name + ": " + exc, exc);
        }
    }
};

Events.dispatch2 = function(listeners, name, args)
{
    try
    {
        var noMethods;
        if (FBTrace.DBG_DISPATCH)
            noMethods = [];

        if (!listeners)
        {
            if (FBTrace.DBG_DISPATCH)
                FBTrace.sysout("dispatch2, no listeners for " + name);
            return;
        }

        for (var i = 0; i < listeners.length; ++i)
        {
            var listener = listeners[i];
            if (listener[name])
            {
                var result = listener[name].apply(listener, args);

                if (FBTrace.DBG_DISPATCH)
                    FBTrace.sysout("dispatch2 " + name + " to #" + i + " of " + listeners.length +
                        " listeners, result " + result, {result: result, listener: listeners[i],
                        fn: listener[name].toSource()});

                if (result)
                    return result;
            }
            else
            {
                if (FBTrace.DBG_DISPATCH)
                    noMethods.push(listener);
            }
        }

        if (FBTrace.DBG_DISPATCH && noMethods.length === listeners.length)
            FBTrace.sysout("Events.dispatch2 " + name + " to " + listeners.length + " listeners, " +
                noMethods.length + " had no such method:", noMethods);
    }
    catch (exc)
    {
        if (FBTrace.DBG_ERRORS)
        {
            if (exc.stack)
                exc.stack = exc.stack.split('/n');

            FBTrace.sysout("Exception in Events.dispatch2 " + name + " exc: " + exc, exc);
        }
    }
};

// ********************************************************************************************* //
// Events

Events.cancelEvent = function(event)
{
    event.stopPropagation();
    event.preventDefault();
};

Events.isLeftClick = function(event, allowKeyModifiers)
{
    return event.button === 0 && (allowKeyModifiers || this.noKeyModifiers(event));
};

Events.isMiddleClick = function(event, allowKeyModifiers)
{
    return event.button === 1 && (allowKeyModifiers || this.noKeyModifiers(event));
};

Events.isRightClick = function(event, allowKeyModifiers)
{
    return event.button === 2 && (allowKeyModifiers || this.noKeyModifiers(event));
};

Events.isSingleClick = function(event)
{
    return event instanceof MouseEvent && event.detail === 1;
};

Events.isDoubleClick = function(event)
{
    return event instanceof MouseEvent && event.detail === 2;
};

Events.noKeyModifiers = function(event)
{
    return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
};

Events.isControlClick = function(event)
{
    return event.button === 0 && this.isControl(event);
};

Events.isShiftClick = function(event)
{
    return event.button === 0 && this.isShift(event);
};

Events.isControl = function(event)
{
    return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey;
};

Events.isAlt = function(event)
{
    return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey;
};

Events.isAltClick = function(event)
{
    return event.button === 0 && this.isAlt(event);
};

Events.isControlShift = function(event)
{
    return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey;
};

Events.isControlAlt = function(event)
{
    return (event.metaKey || event.ctrlKey) && !event.shiftKey && event.altKey;
};

Events.isShift = function(event)
{
    return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey;
};

// ********************************************************************************************* //
// DOM Events

const eventTypes =
{
    composition: [
        "composition",
        "compositionstart",
        "compositionend"
    ],

    contextmenu: [
        "contextmenu"
    ],

    drag: [
        "dragenter",
        "dragover",
        "dragexit",
        "dragdrop",
        "draggesture"
    ],

    focus: [
        "focus",
        "blur"
    ],

    form: [
        "submit",
        "reset",
        "change",
        "select",
        "input"
    ],

    key: [
        "keydown",
        "keyup",
        "keypress"
    ],

    load: [
        "load",
        "beforeunload",
        "unload",
        "abort",
        "error"
    ],

    mouse: [
        "mousedown",
        "mouseup",
        "click",
        "dblclick",
        "mouseover",
        "mouseout",
        "mousemove"
    ],

    mutation: [
        "DOMSubtreeModified",
        "DOMNodeInserted",
        "DOMNodeRemoved",
        "DOMNodeRemovedFromDocument",
        "DOMNodeInsertedIntoDocument",
        "DOMAttrModified",
        "DOMCharacterDataModified"
    ],

    paint: [
        "paint",
        "resize",
        "scroll"
    ],

    scroll: [
        "overflow",
        "underflow",
        "overflowchanged"
    ],

    text: [
        "text"
    ],

    ui: [
        "DOMActivate",
        "DOMFocusIn",
        "DOMFocusOut"
    ],

    // xxxHonza: As Simon says, XUL events must die!
    /*xul: [
        "popupshowing",
        "popupshown",
        "popuphiding",
        "popuphidden",
        "close",
        "command",
        "broadcast",
        "commandupdate"
    ],*/

    clipboard: [
        "cut",
        "copy",
        "paste"
    ],

    touch: [
        "touchstart",
        "touchend",
        "touchmove",
        "touchenter",
        "touchleave",
        "touchcancel"
    ]
};

Events.getEventFamilies = function()
{
    var families = [];
    for (var eventFamily in eventTypes)
        families.push(eventFamily);
    return families;
};

Events.getEventTypes = function(family)
{
    var types = [];
    for (var eventFamily in eventTypes)
    {
        if (!family || family === eventFamily)
        {
            for (var type in eventTypes[eventFamily])
                types.push(eventTypes[eventFamily][type]);
        }
    }

    return types;
};

Events.isEventFamily = function(eventType)
{
    return eventTypes.hasOwnProperty(eventType);
};

Events.getEventFamily = function(eventType)
{
    if (!this.families)
    {
        this.families = {};

        for (var family in eventTypes)
        {
            var types = eventTypes[family];
            for (var i = 0; i < types.length; ++i)
                this.families[types[i]] = family;
        }
    }

    return this.families[eventType];
};

Events.attachAllListeners = function(object, listener)
{
    for (var family in eventTypes)
    {
        if (family !== "mutation" || Firebug.attachMutationEvents)
            this.attachFamilyListeners(family, object, listener);
    }
};

Events.detachAllListeners = function(object, listener)
{
    for (var family in eventTypes)
    {
        if (family !== "mutation" || Firebug.attachMutationEvents)
            this.detachFamilyListeners(family, object, listener);
    }
};

Events.attachFamilyListeners = function(family, object, listener)
{
    var types = eventTypes[family];
    for (var i = 0; i < types.length; ++i)
        object.addEventListener(types[i], listener, false);
};

Events.detachFamilyListeners = function(family, object, listener)
{
    var types = eventTypes[family];
    for (var i = 0; i < types.length; ++i)
        object.removeEventListener(types[i], listener, false);
};

// ********************************************************************************************* //
// Event Listeners (+ support for tracking)

var listeners = [];

Events.addEventListener = function(parent, eventId, listener, capturing)
{
    if (FBTrace.DBG_EVENTLISTENERS)
    {
        for (var i = 0; i < listeners.length; i++)
        {
            var l = listeners[i];
            if (l.parent === parent && l.eventId === eventId && l.listener === listener &&
                l.capturing === capturing)
            {
                FBTrace.sysout("Events.addEventListener; ERROR already registered!", l);
                return;
            }
        }
    }

    parent.addEventListener(eventId, listener, capturing);

    if (FBTrace.DBG_EVENTLISTENERS)
    {
        var frames = [];
        for (var frame = Components.stack; frame; frame = frame.caller)
            frames.push(frame.filename + " (" + frame.lineNumber + ")");

        frames.shift();

        var pid = (parent.location ? parent.location + "" : typeof parent);

        listeners.push({
            parentId: pid,
            eventId: eventId,
            capturing: capturing,
            listener: listener,
            stack: frames,
            parent: parent,
        });
    }
};

Events.removeEventListener = function(parent, eventId, listener, capturing)
{
    try
    {
        parent.removeEventListener(eventId, listener, capturing);
    }
    catch (e)
    {
        if (FBTrace.DBG_ERRORS)
            FBTrace.sysout("events.removeEventListener; (" + eventId + ") " + e, e);
    }

    if (FBTrace.DBG_EVENTLISTENERS)
    {
        for (var i = 0; i < listeners.length; i++)
        {
            var l = listeners[i];
            if (l.parent === parent && l.eventId === eventId && l.listener === listener &&
                l.capturing === capturing)
            {
                listeners.splice(i, 1);
                return;
            }
        }

        // xxxHonza: it's not necessary to pollute the tracing console with this message.
        /*
        var frames = [];
        for (var frame = Components.stack; frame; frame = frame.caller)
            frames.push(frame.filename + " (" + frame.lineNumber + ")");

        frames.shift();

        var info = {
            eventId: eventId,
            capturing: capturing,
            listener: listener,
            stack: frames,
        };

        FBTrace.sysout("Events.removeEventListener; ERROR not registered!", info);
        */
    }
};

Events.getEventListenersForTarget = function(target)
{
    var listeners = elService.getListenerInfoFor(target, {});
    var ret = [];
    for (var i = 0; i < listeners.length; ++i)
    {
        var rawListener = listeners[i];
        var listener = {
            type: rawListener.type,
            capturing: rawListener.capturing,
            allowsUntrusted: rawListener.allowsUntrusted,
            func: null
        };
        if ("listenerObject" in rawListener)
        {
            listener.func = rawListener.listenerObject;
        }
        else
        {
            var debugObject = rawListener.getDebugObject();
            listener.func = (debugObject instanceof Ci.jsdIValue && Wrapper.unwrapIValue(debugObject));
        }

        // Skip chrome event listeners.
        if (!listener.func || rawListener.inSystemEventGroup)
            continue;
        var funcGlobal = Cu.getGlobalForObject(listener.func);
        if (!(funcGlobal instanceof Window))
            continue;
        if (funcGlobal.document.nodePrincipal.subsumes(document.nodePrincipal))
            continue;

        ret.push(listener);
    }
    return ret;
};

if (FBTrace.DBG_EVENTLISTENERS && typeof Firebug !== "undefined")
{
    Firebug.Events = {};
    Firebug.Events.getRegisteredListeners = function()
    {
        return listeners;
    };
}

// ********************************************************************************************* //

return Events;

// ********************************************************************************************* //
});
<|endoftext|>