<commit_before>'use strict'

const _ = require('lodash')
const aws = require('aws-sdk')
const jwt = require('jsonwebtoken')
const { MongoClient, ObjectId } = require('mongodb')

let ssmParameters = {}
const ssmParameter = async (name) => {
  if (ssmParameters[name]) { return ssmParameters[name] }

  const ssm = new aws.SSM()
  const ssmValue = await ssm.getParameter({ Name: name, WithDecryption: true }).promise()

  ssmParameters[name] = ssmValue.Parameter.Value

  return ssmValue.Parameter.Value
}
exports.ssmParameter = ssmParameter

let dbConnection
const db = async (dbName) => {
  if (dbConnection) { return dbConnection.db(dbName) }

  const mongoUrl = await ssmParameter('entu-api-mongodb')

  dbConnection = await MongoClient.connect(mongoUrl, { ssl: true, sslValidate: true, useNewUrlParser: true, useUnifiedTopology: true })
  dbConnection.on('close', () => {
    dbConnection = null
    console.log(`Disconnected from ${dbName}`)
  })

  console.log(`Connected to ${dbName}`)

  return dbConnection.db(dbName)
}
exports.db = db

const getSignedUrl = async (key) => {
  const s3Endpoint = await ssmParameter('entu-api-files-s3-endpoint')
  const s3Bucket = await ssmParameter('entu-api-files-s3-bucket')

  return new Promise((resolve, reject) => {
    let conf

    if (s3Endpoint) {
      conf = { endpoint: s3Endpoint, s3BucketEndpoint: true }
    }

    aws.config = new aws.Config()
    const s3 = new aws.S3(conf)
    s3.getSignedUrl('getObject', { Bucket: s3Bucket, Key: key, Expires: 60 }, (err, url) => {
      if (err) { return reject(err) }

      resolve(url)
    })
  })
}
exports.getSignedUrl = getSignedUrl

exports.user = async (event) => {
  const jwtSecret = await ssmParameter('entu-api-jwt-secret')

  return new Promise((resolve, reject) => {
    const jwtToken = _.get(event, 'headers.Authorization', '').replace('Bearer ', '')
    const jwtConf = {
      issuer: _.get(event, 'queryStringParameters.account'),
      audience: _.get(event, 'requestContext.identity.sourceIp')
    }

    let result = {
      account: jwtConf.issuer
    }

    if (jwtToken) {
      try {
        const decoded = jwt.verify(jwtToken, jwtSecret, jwtConf)

        if (decoded.aud !== jwtConf.audience) {
          return reject([401, 'Invalid JWT audience'])
        }

        result = {
          id: decoded.sub,
          account: decoded.iss
        }
      } catch (e) {
        return reject([401, e.message || e])
      }
    }

    if (!result.account) {
      return reject([401, 'No account parameter'])
    }

    db(result.account).then((x) => {
      result.db = x
      resolve(result)
    })
  })
}

// Create user session
exports.addUserSession = async (user) => {
  const jwtSecret = await ssmParameter('entu-api-jwt-secret')

  return new Promise((resolve, reject) => {
    if (!user) { return reject('No user') }

    const session = {
      created: new Date(),
      user: user
    }

    db('entu').then((connection) => {
      connection.collection('session').insertOne(_.pickBy(session, _.identity)).then((result) => {
        const token = jwt.sign({}, jwtSecret, {
          audience: user.ip,
          subject: result.insertedId.toString(),
          expiresIn: '5m'
        })

        resolve(token)
      }).catch((err) => {
        reject(err)
      })
    }).catch((err) => {
      reject(err)
    })
  })
}

// Add to entu-api-entity-aggregate-queue
exports.addEntityAggregateSqs = async (context, account, entity, dt) => {
  const region = context.invokedFunctionArn.split(':')[3]
  const accountId = context.invokedFunctionArn.split(':')[4]
  const queueUrl = `https://sqs.${region}.amazonaws.com/${accountId}/entu-api-entity-aggregate-queue.fifo`
  const message = {
    account: account,
    entity: entity.toString(),
    dt: dt
  }

  const sqs = new aws.SQS()
  const sqsResponse = await sqs.sendMessage({ QueueUrl: queueUrl, MessageGroupId: account, MessageBody: JSON.stringify(message) }).promise()

  return sqsResponse
}

const strToId = (str) => {
  try {
    return new ObjectId(str)
  } catch (e) {
    throw 'Invalid _id'
  }
}
exports.strToId = strToId

exports.json = (data, code, headers) => {
  if (headers) {
    headers['Access-Control-Allow-Origin'] = '*'
  } else {
    headers = {
      'Access-Control-Allow-Origin': '*'
    }
  }
  if (process.env.GIT_SHA1) {
    headers['X-Entu-Version'] = process.env.GIT_SHA1
  }

  return {
    statusCode: code || 200,
    headers: headers || {},
    body: JSON.stringify(data),
    isBase64Encoded: false
  }
}

exports.error = (err) => {
  let code
  let message
  let headers = {
    'Access-Control-Allow-Origin': '*'
  }

  if (process.env.GIT_SHA1) {
    headers['X-Entu-Version'] = process.env.GIT_SHA1
  }

  if (err.constructor === Array) {
    code = err[0]
    message = err[1]

    console.error(code.toString(), message)
  } else {
    message = err.toString()

    console.error(err)
  }

  return {
    statusCode: code || 500,
    headers: headers,
    body: JSON.stringify({ message: message }),
    isBase64Encoded: false
  }
}

exports.redirect = (url, code, headers) => {
  if (headers) {
    headers['Location'] = url
  } else {
    headers = {
      Location: url
    }
  }
  headers['Access-Control-Allow-Origin'] = '*'

  return {
    statusCode: code || 302,
    headers: headers,
    body: null
  }
}
<commit_msg>Use account based SQS queue<commit_after>'use strict'

const _ = require('lodash')
const aws = require('aws-sdk')
const jwt = require('jsonwebtoken')
const { MongoClient, ObjectId } = require('mongodb')

let ssmParameters = {}
const ssmParameter = async (name) => {
  if (ssmParameters[name]) { return ssmParameters[name] }

  const ssm = new aws.SSM()
  const ssmValue = await ssm.getParameter({ Name: name, WithDecryption: true }).promise()

  ssmParameters[name] = ssmValue.Parameter.Value

  return ssmValue.Parameter.Value
}
exports.ssmParameter = ssmParameter

let dbConnection
const db = async (dbName) => {
  if (dbConnection) { return dbConnection.db(dbName) }

  const mongoUrl = await ssmParameter('entu-api-mongodb')

  dbConnection = await MongoClient.connect(mongoUrl, { ssl: true, sslValidate: true, useNewUrlParser: true, useUnifiedTopology: true })
  dbConnection.on('close', () => {
    dbConnection = null
    console.log(`Disconnected from ${dbName}`)
  })

  console.log(`Connected to ${dbName}`)

  return dbConnection.db(dbName)
}
exports.db = db

const getSignedUrl = async (key) => {
  const s3Endpoint = await ssmParameter('entu-api-files-s3-endpoint')
  const s3Bucket = await ssmParameter('entu-api-files-s3-bucket')

  return new Promise((resolve, reject) => {
    let conf

    if (s3Endpoint) {
      conf = { endpoint: s3Endpoint, s3BucketEndpoint: true }
    }

    aws.config = new aws.Config()
    const s3 = new aws.S3(conf)
    s3.getSignedUrl('getObject', { Bucket: s3Bucket, Key: key, Expires: 60 }, (err, url) => {
      if (err) { return reject(err) }

      resolve(url)
    })
  })
}
exports.getSignedUrl = getSignedUrl

exports.user = async (event) => {
  const jwtSecret = await ssmParameter('entu-api-jwt-secret')

  return new Promise((resolve, reject) => {
    const jwtToken = _.get(event, 'headers.Authorization', '').replace('Bearer ', '')
    const jwtConf = {
      issuer: _.get(event, 'queryStringParameters.account'),
      audience: _.get(event, 'requestContext.identity.sourceIp')
    }

    let result = {
      account: jwtConf.issuer
    }

    if (jwtToken) {
      try {
        const decoded = jwt.verify(jwtToken, jwtSecret, jwtConf)

        if (decoded.aud !== jwtConf.audience) {
          return reject([401, 'Invalid JWT audience'])
        }

        result = {
          id: decoded.sub,
          account: decoded.iss
        }
      } catch (e) {
        return reject([401, e.message || e])
      }
    }

    if (!result.account) {
      return reject([401, 'No account parameter'])
    }

    db(result.account).then((x) => {
      result.db = x
      resolve(result)
    })
  })
}

// Create user session
exports.addUserSession = async (user) => {
  const jwtSecret = await ssmParameter('entu-api-jwt-secret')

  return new Promise((resolve, reject) => {
    if (!user) { return reject('No user') }

    const session = {
      created: new Date(),
      user: user
    }

    db('entu').then((connection) => {
      connection.collection('session').insertOne(_.pickBy(session, _.identity)).then((result) => {
        const token = jwt.sign({}, jwtSecret, {
          audience: user.ip,
          subject: result.insertedId.toString(),
          expiresIn: '5m'
        })

        resolve(token)
      }).catch((err) => {
        reject(err)
      })
    }).catch((err) => {
      reject(err)
    })
  })
}

// Add to entu-api-entity-aggregate-queue
exports.addEntityAggregateSqs = async (context, account, entity, dt) => {
  const region = context.invokedFunctionArn.split(':')[3]
  const accountId = context.invokedFunctionArn.split(':')[4]
  const queueUrl = `https://sqs.${region}.amazonaws.com/${accountId}/entu-api-entity-aggregate-queue-${account}.fifo`
  const message = {
    account: account,
    entity: entity.toString(),
    dt: dt
  }

  const sqs = new aws.SQS()
  const sqsResponse = await sqs.sendMessage({ QueueUrl: queueUrl, MessageGroupId: account, MessageBody: JSON.stringify(message) }).promise()

  return sqsResponse
}

const strToId = (str) => {
  try {
    return new ObjectId(str)
  } catch (e) {
    throw 'Invalid _id'
  }
}
exports.strToId = strToId

exports.json = (data, code, headers) => {
  if (headers) {
    headers['Access-Control-Allow-Origin'] = '*'
  } else {
    headers = {
      'Access-Control-Allow-Origin': '*'
    }
  }
  if (process.env.GIT_SHA1) {
    headers['X-Entu-Version'] = process.env.GIT_SHA1
  }

  return {
    statusCode: code || 200,
    headers: headers || {},
    body: JSON.stringify(data),
    isBase64Encoded: false
  }
}

exports.error = (err) => {
  let code
  let message
  let headers = {
    'Access-Control-Allow-Origin': '*'
  }

  if (process.env.GIT_SHA1) {
    headers['X-Entu-Version'] = process.env.GIT_SHA1
  }

  if (err.constructor === Array) {
    code = err[0]
    message = err[1]

    console.error(code.toString(), message)
  } else {
    message = err.toString()

    console.error(err)
  }

  return {
    statusCode: code || 500,
    headers: headers,
    body: JSON.stringify({ message: message }),
    isBase64Encoded: false
  }
}

exports.redirect = (url, code, headers) => {
  if (headers) {
    headers['Location'] = url
  } else {
    headers = {
      Location: url
    }
  }
  headers['Access-Control-Allow-Origin'] = '*'

  return {
    statusCode: code || 302,
    headers: headers,
    body: null
  }
}
<|endoftext|>


<commit_before>/**
    @function accessor
    @desc Wraps an object key in a simple accessor function.
    @param {String} key The key to be returned from each Object passed to the function.
    @example
this

constant("id");
    @example
returns this

function(d) {
  return d["id"];
}
*/
export default function(key) {
  return function accessor(d) {
    return d[key];
  };
}
<commit_msg>fixes accessor example doc<commit_after>/**
    @function accessor
    @desc Wraps an object key in a simple accessor function.
    @param {String} key The key to be returned from each Object passed to the function.
    @example
this

accessor("id");
    @example
returns this

function(d) {
  return d["id"];
}
*/
export default function(key) {
  return function accessor(d) {
    return d[key];
  };
}
<|endoftext|>


<commit_before>/**
 * @Author: Wahaj Shamim <wahaj>
 * @Date:   2017-07-31T14:53:10+10:00
 * @Email:  wahaj@southbanksoftware.com
 * @Last modified by:   wahaj
 * @Last modified time: 2017-08-23T12:06:01+10:00
 */

import { action } from 'mobx';
import { Broker, EventType } from '~/helpers/broker';
import { featherClient } from '~/helpers/feathers';

export default class TreeApi {
  store;
  api;

  constructor(store, api) {
    this.store = store;
    this.api = api;
  }

  @action.bound
  addNewEditorForTreeAction = (options = { type: 'TreeAction' }) => {
    this.store.editorToolbar.newEditorForTreeAction = true;
    this.api.addEditor({ type: options.type });
  };

  @action.bound
  openNewTableViewForCollection(targetData, limit, skip) {
    // Set up broken to listen on result.
    const editor = this.store.editors.get(
      this.store.editorPanel.activeEditorId,
    );
    Broker.on(
      EventType.createAggregatorResultReceived(editor.id + '_table'),
      this._onAggregatorResultReceived,
    );

    // Send request to Feathers:
    featherClient()
      .service('aggregators')
      .create({
        editorId: editor.id + '_table',
        connectionId: editor.currentProfile,
        database: targetData.database,
        collection: targetData.collection,
        pipeline: [{ $limit: limit }],
        options: { allowDiskUse: true },
      })
      .catch(this._handleError);
    // Render Table:
    this.api.outputApi.createJSONTableViewFromJSONArray(
      [{ loading: 'isLoading' }],
      editor.id,
    );
  }

  @action.bound
  _onAggregatorResultReceived(result) {
    const editor = this.store.editors.get(
      this.store.editorPanel.activeEditorId,
    );

    this.api.outputApi.createJSONTableViewFromJSONArray(result, editor.id);

    Broker.off(
      EventType.createAggregatorResultReceived(editor.id + '_table'),
      this._onAggregatorResultReceived,
    );
  }

  @action.bound
  _handleError(error) {
    console.error(error);
  }
}
<commit_msg>Linting error.<commit_after>/**
 * @Author: Wahaj Shamim <wahaj>
 * @Date:   2017-07-31T14:53:10+10:00
 * @Email:  wahaj@southbanksoftware.com
 * @Last modified by:   wahaj
 * @Last modified time: 2017-08-23T12:06:01+10:00
 */

import { action } from 'mobx';
import { Broker, EventType } from '~/helpers/broker';
import { featherClient } from '~/helpers/feathers';

export default class TreeApi {
  store;
  api;

  constructor(store, api) {
    this.store = store;
    this.api = api;
  }

  @action.bound
  addNewEditorForTreeAction = (options = { type: 'TreeAction' }) => {
    this.store.editorToolbar.newEditorForTreeAction = true;
    this.api.addEditor({ type: options.type });
  };

  @action.bound
  openNewTableViewForCollection(targetData, limit) {
    // Set up broken to listen on result.
    const editor = this.store.editors.get(
      this.store.editorPanel.activeEditorId,
    );
    Broker.on(
      EventType.createAggregatorResultReceived(editor.id + '_table'),
      this._onAggregatorResultReceived,
    );

    // Send request to Feathers:
    featherClient()
      .service('aggregators')
      .create({
        editorId: editor.id + '_table',
        connectionId: editor.currentProfile,
        database: targetData.database,
        collection: targetData.collection,
        pipeline: [{ $limit: limit }],
        options: { allowDiskUse: true },
      })
      .catch(this._handleError);
    // Render Table:
    this.api.outputApi.createJSONTableViewFromJSONArray(
      [{ loading: 'isLoading' }],
      editor.id,
    );
  }

  @action.bound
  _onAggregatorResultReceived(result) {
    const editor = this.store.editors.get(
      this.store.editorPanel.activeEditorId,
    );

    this.api.outputApi.createJSONTableViewFromJSONArray(result, editor.id);

    Broker.off(
      EventType.createAggregatorResultReceived(editor.id + '_table'),
      this._onAggregatorResultReceived,
    );
  }

  @action.bound
  _handleError(error) {
    console.error(error);
  }
}
<|endoftext|>


<commit_before>const mediaType = 'application/vnd.cignium.resource+json'

export async function request(method, href, data, config) {
  const request = {
    body: data && JSON.stringify(data),
    credentials: 'include',
    headers: new Headers({ Accept: 'application/json' }),
    method,
  }

  const response = await fetch(href, request)
  const contentType = response.headers.get('Content-Type')

  if (response.status == 200) {
    if (contentType.startsWith(mediaType)) {
      return await response.json()
    }

    if (config && config.onRedirect) {
      let content = await response.text()
      content = config.onRedirect(response.url, content)
      if (content) {
        content.type = 'html'
        content.links = [{ rel: 'self', href: response.url }]
      }
      return content
    }

    location.href = response.url

    return null
  }

  throw Error(`${response.status}: ${response.statusText}`)
}
<commit_msg>fix: redirect on response status 401<commit_after>const mediaType = 'application/vnd.cignium.resource+json'

export async function request(method, href, data, config) {
  const request = {
    body: data && JSON.stringify(data),
    credentials: 'include',
    headers: new Headers({ Accept: 'application/json' }),
    method,
  }

  const response = await fetch(href, request)
  const contentType = response.headers.get('Content-Type')

  if (response.status == 401 && contentType && contentType.startsWith('text/html')) {
    location.href = method.toLowerCase() == 'get' ? response.url : location.href
    return
  }

  if (response.status >= 400 && response.status < 600) {
    throw Error(`${response.status}: ${response.statusText}`)
  }

  if (contentType.startsWith(mediaType)) {
    return await response.json()
  }

  if (config && config.onRedirect) {
    let content = await response.text()
    content = config.onRedirect(response.url, content)

    if (content) {
      content.type = 'html'
      content.links = [{ rel: 'self', href: response.url }]
    }

    return content
  }

  location.href = response.url

  return null
}
<|endoftext|>


<commit_before>/* global define */

require('./sandbox')(function () {
  'use strict';

  function once (fn) {
    var result;
    return function () {
      if( fn ) {
        result = fn.apply(this, arguments);
        fn = null;
      }
      return result;
    };
  }

  var aplazame = require('./core/core'),
      api = require('./core/api'),
      events = require('./core/events');

  aplazame.checkout = require('./apps/checkout');
  aplazame.button = require('./apps/button');
  aplazame.simulator = require('./apps/simulator');
  aplazame.modal = require('./apps/modal');

  aplazame.info = function () {
    return {
      api: require('./core/api'),
      log: require('./tools/log').history,
      version: require('../.tmp/aplazame-version')
    };
  };

  aplazame.log = function () {
    require('./tools/log').history.forEach(function (l) {
      console.log(l.time);
      console.log.apply(console, l.args);
    });
  };

  require('./apps/http-service');

  // global.aplazame = aplazame;

  require('./loaders/data-aplazame')(aplazame);

  var runLaunchers = once(function () {
    require('./loaders/data-button')(aplazame);
    require('./loaders/data-simulator')(aplazame);
  });

  if( api.publicKey ) runLaunchers();
  events.on('init', runLaunchers);

  if (typeof define === 'function' && define.amd) {
    define([], function () {
      return aplazame;
    });
  } else {
    global.aplazame = aplazame;
  }

  aplazame._.ready(function () {
    if( api.callback ) {
      if(  typeof global[api.callback] !== 'function' ) {
        throw new Error('callback should be a global function');
      }

      global[api.callback](aplazame);
    }
  });

});
<commit_msg>aplazame should be globaly available even when any amd loader present<commit_after>/* global define */

require('./sandbox')(function () {
  'use strict';

  function once (fn) {
    var result;
    return function () {
      if( fn ) {
        result = fn.apply(this, arguments);
        fn = null;
      }
      return result;
    };
  }

  var aplazame = require('./core/core'),
      api = require('./core/api'),
      events = require('./core/events');

  aplazame.checkout = require('./apps/checkout');
  aplazame.button = require('./apps/button');
  aplazame.simulator = require('./apps/simulator');
  aplazame.modal = require('./apps/modal');

  aplazame.info = function () {
    return {
      api: require('./core/api'),
      log: require('./tools/log').history,
      version: require('../.tmp/aplazame-version')
    };
  };

  aplazame.log = function () {
    require('./tools/log').history.forEach(function (l) {
      console.log(l.time);
      console.log.apply(console, l.args);
    });
  };

  require('./apps/http-service');

  global.aplazame = aplazame;

  require('./loaders/data-aplazame')(aplazame);

  var runLaunchers = once(function () {
    require('./loaders/data-button')(aplazame);
    require('./loaders/data-simulator')(aplazame);
  });

  if( api.publicKey ) runLaunchers();
  events.on('init', runLaunchers);

  if (typeof define === 'function' && define.amd) {
    define([], function () {
      return aplazame;
    });
  }

  aplazame._.ready(function () {
    if( api.callback ) {
      if(  typeof global[api.callback] !== 'function' ) {
        throw new Error('callback should be a global function');
      }

      global[api.callback](aplazame);
    }
  });

});
<|endoftext|>


<commit_before>angular.module('ontrack.extension.jenkins', [
    'ui.router',
    'ot.service.core'
])
    .config(function ($stateProvider) {
        // Jenkins settings
        $stateProvider.state('jenkins-settings', {
            url: '/extension/jenkins/settings',
            templateUrl: 'app/extension/jenkins/jenkins.settings.tpl.html',
            controller: 'JenkinsSettingsCtrl'
        });
    })
    .controller('JenkinsSettingsCtrl', function ($scope, ot) {
        var view = ot.view();
        view.title = 'Jenkins settings';
        view.description = 'Management of the Jenkins settings and configurations.';
        view.commands = [
            ot.viewCloseCommand('/home')
        ];

        // TODO Loading the Jenkins configurations
        function loadJenkinsConfigurations() {
        }
        loadJenkinsConfigurations();
    })
;<commit_msg>Jenkins: settings client load<commit_after>angular.module('ontrack.extension.jenkins', [
    'ui.router',
    'ot.service.core'
])
    .config(function ($stateProvider) {
        // Jenkins settings
        $stateProvider.state('jenkins-settings', {
            url: '/extension/jenkins/settings',
            templateUrl: 'app/extension/jenkins/jenkins.settings.tpl.html',
            controller: 'JenkinsSettingsCtrl'
        });
    })
    .controller('JenkinsSettingsCtrl', function ($scope, $http, ot) {
        var view = ot.view();
        view.title = 'Jenkins settings';
        view.description = 'Management of the Jenkins settings and configurations.';
        view.commands = [
            ot.viewCloseCommand('/home')
        ];

        // Loading the Jenkins settings
        function loadJenkinsSettings() {
            ot.call($http.get('extension/jenkins/settings')).then(function (settings) {
                $scope.settings = settings;
            });
        }

        loadJenkinsSettings();
    })
;<|endoftext|>


<commit_before>import States from './action/states'

let uid = 0
const FALLBACK = 'microcosm_action'

/**
 * Uniquely tag a function. This is used to identify actions.
 *
 * @param {function} fn The target function to add action identifiers to.
 * @param {string} [name] An override to use instead of `fn.name`.
 * @return {function} The tagged function (same as `fn`).
 * @private
 */
export default function tag (fn, name) {
  if (fn == null) {
    throw new TypeError('Unable to identify ' + fn + ' action. Did you push the correct action?')
  }

  if (fn.hasOwnProperty('toString')) {
    return fn
  }

  if (typeof fn === 'string') {
    name = fn
    fn = n => n
  }

  /**
   * Auto-increment a stepper suffix to prevent two actions with the
   * same name from colliding.
   */
  uid += 1

  /**
   * Function.name lacks legacy support. For these browsers, fallback
   * to a consistent name:
   */
  const symbol = name || (fn.name || FALLBACK) + '_' + uid

  fn.open      = symbol + '_open'
  fn.loading   = symbol + '_loading'
  fn.done      = symbol // intentional
  fn.failed    = symbol + '_failed'
  fn.cancelled = symbol + '_cancelled'

  // The default state is done
  fn.toString = () => fn.done

  return fn
}
<commit_msg>Fix linting<commit_after>let uid = 0
const FALLBACK = 'microcosm_action'

/**
 * Uniquely tag a function. This is used to identify actions.
 *
 * @param {function} fn The target function to add action identifiers to.
 * @param {string} [name] An override to use instead of `fn.name`.
 * @return {function} The tagged function (same as `fn`).
 * @private
 */
export default function tag (fn, name) {
  if (fn == null) {
    throw new TypeError('Unable to identify ' + fn + ' action. Did you push the correct action?')
  }

  if (fn.hasOwnProperty('toString')) {
    return fn
  }

  if (typeof fn === 'string') {
    name = fn
    fn = n => n
  }

  /**
   * Auto-increment a stepper suffix to prevent two actions with the
   * same name from colliding.
   */
  uid += 1

  /**
   * Function.name lacks legacy support. For these browsers, fallback
   * to a consistent name:
   */
  const symbol = name || (fn.name || FALLBACK) + '_' + uid

  fn.open      = symbol + '_open'
  fn.loading   = symbol + '_loading'
  fn.done      = symbol // intentional
  fn.failed    = symbol + '_failed'
  fn.cancelled = symbol + '_cancelled'

  // The default state is done
  fn.toString = () => fn.done

  return fn
}
<|endoftext|>


<commit_before>var app = require('./app.js');
var jsdom = require('mocha-jsdom');
var expect = require('chai').expect;

function printDom() {
  var window = document.defaultView;
  console.log(window.document.documentElement.outerHTML);
}

describe('App', function() {
  // https://www.npmjs.com/package/mocha-jsdom
  jsdom();

  before(function() {
    var div = document.createElement('div');
    div.id = 'appContainer';
    document.body.appendChild(div);
  });

  describe('loading', function() {
    it('it should load our application', function() {
      app.init();

      var content = document.getElementById('appContainer').textContent;
      expect(content).eq('welcome to my app');
    });
  });
});

<commit_msg>test text<commit_after>var app = require('./app.js');
var jsdom = require('mocha-jsdom');
var expect = require('chai').expect;

function printDom() {
  var window = document.defaultView;
  console.log(window.document.documentElement.outerHTML);
}

describe('app', function() {
  // https://www.npmjs.com/package/mocha-jsdom
  jsdom();

  before(function() {
    var div = document.createElement('div');
    div.id = 'appContainer';
    document.body.appendChild(div);
  });

  describe('#init', function() {
    it('it should load our application to our appContainer element', function() {
      app.init();

      var content = document.getElementById('appContainer').textContent;
      expect(content).eq('welcome to my app');
    });
  });
});

<|endoftext|>


<commit_before>angular.module('nOrg', [
])

  .controller('NOrgCtrl', function NOrgCtrl ($scope, $http) {
    var reserved_headers = {"Subject": true, "Message-ID": true};
    $scope.listChildren = function (parent) {
      var children;
      if (typeof parent == "undefined") {
        children = $scope.children;
      } else {
        children = parent.children;
      }

      // Process nodes adding utility attributes deduced from the raw JSON
      for (var idx in children) {
        var child = children[idx];

        // Parent/Children processing
        child.parent = parent;
        child.siblings = children;
        child.children = child.children || [];
        if (typeof child.parent != "undefined") {
          child.promotable = true;
        }

        // Sibling processing
        child.index = parseInt(idx, 10);
        if (child.index > 0) {
          child.demotable = true;
          child.movableUp = true;
        }
        if (child.index < child.siblings.length - 1) {
          child.movableDown = true;
        }

        // Generate a valid HTML ID and CSS selector from the message
        // ID using base64 encoding
        child.id = window.btoa(child.headers["Message-ID"]).slice(0, -1);

        // A list of header names that the UI will care about
        child.header_keys = [];
        for (var key in child.headers) {
          if (!(key in reserved_headers)) {
            child.header_keys.push(key);
          }}

        }
      return children;
    };
    $http.get('app/nodes.json').success(function (data) {
      // Load the initial nodes JSON
      $scope.cursor = data[0];
      data[0].cursor = true;
      $scope.children = data;
    });

    $scope.demote = function (node) {
      // Demote a node if appropriate
      if (node.index === 0) {
        throw new Error("Cannot promote first sibling!");
      }

      var parent = node.siblings[node.index - 1];
      parent.children.push(node);
      node.parent = parent;
      node.siblings.splice(node.index, 1);
      node.siblings = node.parent.children;
      node.index = 0;

      if (node.index === 0) {
        node.demotable = false;
      }
    };

    $scope.promote = function (node) {
      // Promote a node if appropriate
      if (typeof node.parent == "undefined") {
        throw new Error("Cannot promote nodes without parents!");
      }
      var old_parent = node.parent;
      node.parent = node.parent.parent;
      old_parent.siblings.splice(old_parent.index + 1, 0, node);
      old_parent.children.splice(node.index, 1);
      node.index = old_parent.index + 1;

      if (typeof node.parent == "undefined") {
        node.promotable = false;
      }
    };

    $scope.moveUp = function (node) {
      // Move a node up relative to it's siblings if appropriate
      if (node.index === 0) {
        throw new Error("Cannot move first nodes up!");
      }

      var next = node.siblings[node.index - 1];
      node.siblings.splice(node.index - 1, 2, node, next);
      node.index -= 1;
      next.index += 1;

      if (node.index === 0) {
        node.movableUp = false;
      }
    };

    $scope.moveDown = function (node) {
      // Move a node down relative to it's siblings if appropriate
      if (node.index == node.siblings.length - 1) {
        throw new Error("Cannot move last nodes down!");
      }

      var previous = node.siblings[node.index + 1];
      node.siblings.splice(node.index, 2, previous , node);
      node.index += 1;
      previous.index -= 1;

      if (node.index == node.siblings.length - 1) {
        node.movableDown = false;
      }
    };

    $scope.setCursor = function (node) {
      // Move the cursor to the given node
      if (typeof node == "undefined") {
        throw new Error("Cannot move cursor to undefined!");
      }
      $scope.cursor.cursor = false;
      $scope.cursor = node;
      node.cursor = true;
    };

    $scope.keymap = {
      37: function () {         // left arrow
        $scope.setCursor($scope.cursor.parent);
        },
      38: function () {         // up arrow
        $scope.setCursor($scope.cursor.siblings[$scope.cursor.index - 1]);
        },
      39: function () {         // right arrow
        $scope.setCursor($scope.cursor.children[0]);
        },
      40: function () {         // down arrow
        $scope.setCursor($scope.cursor.siblings[$scope.cursor.index + 1]);
        }
    };
    $scope.handleKeydown = function ($event) {
      $scope.keymap[$event.keyCode]();
    };

  });

//NOrgCtrl.$inject = ['$scope', '$http'];
<commit_msg>keypress aliases<commit_after>angular.module('nOrg', [
])

  .controller('NOrgCtrl', function NOrgCtrl ($scope, $http) {
    var reserved_headers = {"Subject": true, "Message-ID": true};
    $scope.listChildren = function (parent) {
      var children;
      if (typeof parent == "undefined") {
        children = $scope.children;
      } else {
        children = parent.children;
      }

      // Process nodes adding utility attributes deduced from the raw JSON
      for (var idx in children) {
        var child = children[idx];

        // Parent/Children processing
        child.parent = parent;
        child.siblings = children;
        child.children = child.children || [];
        if (typeof child.parent != "undefined") {
          child.promotable = true;
        }

        // Sibling processing
        child.index = parseInt(idx, 10);
        if (child.index > 0) {
          child.demotable = true;
          child.movableUp = true;
        }
        if (child.index < child.siblings.length - 1) {
          child.movableDown = true;
        }

        // Generate a valid HTML ID and CSS selector from the message
        // ID using base64 encoding
        child.id = window.btoa(child.headers["Message-ID"]).slice(0, -1);

        // A list of header names that the UI will care about
        child.header_keys = [];
        for (var key in child.headers) {
          if (!(key in reserved_headers)) {
            child.header_keys.push(key);
          }}

        }
      return children;
    };
    $http.get('app/nodes.json').success(function (data) {
      // Load the initial nodes JSON
      $scope.cursor = data[0];
      data[0].cursor = true;
      $scope.children = data;
    });

    $scope.demote = function (node) {
      // Demote a node if appropriate
      if (node.index === 0) {
        throw new Error("Cannot promote first sibling!");
      }

      var parent = node.siblings[node.index - 1];
      parent.children.push(node);
      node.parent = parent;
      node.siblings.splice(node.index, 1);
      node.siblings = node.parent.children;
      node.index = 0;

      if (node.index === 0) {
        node.demotable = false;
      }
    };

    $scope.promote = function (node) {
      // Promote a node if appropriate
      if (typeof node.parent == "undefined") {
        throw new Error("Cannot promote nodes without parents!");
      }
      var old_parent = node.parent;
      node.parent = node.parent.parent;
      old_parent.siblings.splice(old_parent.index + 1, 0, node);
      old_parent.children.splice(node.index, 1);
      node.index = old_parent.index + 1;

      if (typeof node.parent == "undefined") {
        node.promotable = false;
      }
    };

    $scope.moveUp = function (node) {
      // Move a node up relative to it's siblings if appropriate
      if (node.index === 0) {
        throw new Error("Cannot move first nodes up!");
      }

      var next = node.siblings[node.index - 1];
      node.siblings.splice(node.index - 1, 2, node, next);
      node.index -= 1;
      next.index += 1;

      if (node.index === 0) {
        node.movableUp = false;
      }
    };

    $scope.moveDown = function (node) {
      // Move a node down relative to it's siblings if appropriate
      if (node.index == node.siblings.length - 1) {
        throw new Error("Cannot move last nodes down!");
      }

      var previous = node.siblings[node.index + 1];
      node.siblings.splice(node.index, 2, previous , node);
      node.index += 1;
      previous.index -= 1;

      if (node.index == node.siblings.length - 1) {
        node.movableDown = false;
      }
    };

    $scope.setCursor = function (node) {
      // Move the cursor to the given node
      if (typeof node == "undefined") {
        throw new Error("Cannot move cursor to undefined!");
      }
      $scope.cursor.cursor = false;
      $scope.cursor = node;
      node.cursor = true;
    };

    $scope.keymap = {
      37: function () {         // left arrow
        $scope.setCursor($scope.cursor.parent);
        },
      38: function () {         // up arrow
        $scope.setCursor($scope.cursor.siblings[$scope.cursor.index - 1]);
        },
      39: function () {         // right arrow
        $scope.setCursor($scope.cursor.children[0]);
        },
      40: function () {         // down arrow
        $scope.setCursor($scope.cursor.siblings[$scope.cursor.index + 1]);
        }
    };
    $scope.keymapAliases = {
      74: 40, 75: 38            // j/k -> down/up
    };
    for (var from in $scope.keymapAliases) {
      $scope.keymap[from] = $scope.keymap[$scope.keymapAliases[from]];
    }
    $scope.handleKeydown = function ($event) {
      $scope.keymap[$event.keyCode]();
    };

  });

//NOrgCtrl.$inject = ['$scope', '$http'];
<|endoftext|>


<commit_before>import setupCalendar from './utils/setup';
import Calendar from './components/Calendar';
import DatePicker from './components/DatePicker';
import Locale from './utils/locale';
import DateInfo from './utils/dateInfo';
import Attribute from './utils/attribute';
import AttributeStore from './utils/attributeStore';
import * as helpers from './utils/helpers';
import * as touch from './utils/touch';

// Export components individually
export {
  setupCalendar,
  Calendar,
  DatePicker,
  Locale,
  DateInfo,
  Attribute,
  AttributeStore,
  helpers,
  touch,
};

// Installs the library as a plugin
const components = {
  Calendar,
  DatePicker,
};

// Declare install function executed by Vue.use()
export default function install(Vue, opts) {
  // Don't install more than once
  if (install.installed) return;
  install.installed = true;
  // Manually setup calendar with options
  const defaults = setupCalendar(opts);
  // Register components
  Object.keys(components).forEach(k =>
    Vue.component(`${defaults.componentPrefix}${k}`, components[k]),
  );
}

// Create module definition for Vue.use()
const plugin = {
  install,
};

// Use automatically when global Vue instance detected
let GlobalVue = null;
if (typeof window !== 'undefined') {
  GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
  GlobalVue = global.Vue;
}
if (GlobalVue) {
  GlobalVue.use(plugin);
}
<commit_msg>Export plugin as object<commit_after>import setupCalendar from './utils/setup';
import Calendar from './components/Calendar';
import DatePicker from './components/DatePicker';
import Popover from './components/Popover';
import PopoverRef from './components/PopoverRef';
import Locale from './utils/locale';
import DateInfo from './utils/dateInfo';
import Attribute from './utils/attribute';
import AttributeStore from './utils/attributeStore';
import * as helpers from './utils/helpers';
import * as touch from './utils/touch';

// Installs the library as a plugin
const components = {
  Calendar,
  DatePicker,
};

// Declare install function executed by Vue.use()
function install(Vue, opts) {
  // Don't install more than once
  if (install.installed) return;
  install.installed = true;
  // Manually setup calendar with options
  const defaults = setupCalendar(opts);
  // Register components
  Object.keys(components).forEach(k =>
    Vue.component(`${defaults.componentPrefix}${k}`, components[k]),
  );
}

// Create module definition for Vue.use()
const plugin = {
  install,
  setupCalendar,
  Calendar,
  DatePicker,
  Popover,
  PopoverRef,
  Locale,
  DateInfo,
  Attribute,
  AttributeStore,
  helpers,
  touch,
};

// Use automatically when global Vue instance detected
let GlobalVue = null;
if (typeof window !== 'undefined') {
  GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
  GlobalVue = global.Vue;
}
if (GlobalVue) {
  GlobalVue.use(plugin);
}

// Export components/helpers individually
export {
  setupCalendar,
  Calendar,
  DatePicker,
  Popover,
  PopoverRef,
  Locale,
  DateInfo,
  Attribute,
  AttributeStore,
  helpers,
  touch,
};

export default plugin;
<|endoftext|>


<commit_before>// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration.
var CIconfiguration = {
  'Chrome':       { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Firefox':      { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  // FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true
  // Currently deactivated due to https://github.com/angular/angular/issues/7560
  'ChromeBeta':   { unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
  'FirefoxBeta':  { unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
  'ChromeDev':    { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'FirefoxDev':   { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'IE9':          { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'IE10':         { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'IE11':         { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Edge':         { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.1':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.2':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.3':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.4':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android5':     { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Safari7':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'Safari8':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'Safari9':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'iOS7':         { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
  'iOS8':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'iOS9':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};

var customLaunchers = {
  'DartiumWithWebPlatform': {
    base: 'Dartium',
    flags: ['--enable-experimental-web-platform-features'] },
  'ChromeNoSandbox': {
    base: 'Chrome',
    flags: ['--no-sandbox'] },
  'SL_CHROME': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: '50'
  },
  'SL_CHROMEBETA': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: 'beta'
  },
  'SL_CHROMEDEV': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: 'dev'
  },
  'SL_FIREFOX': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: '45'
  },
  'SL_FIREFOXBETA': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'beta'
  },
  'SL_FIREFOXDEV': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'dev'
  },
  'SL_SAFARI7': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.9',
    version: '7'
  },
  'SL_SAFARI8': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.10',
    version: '8'
  },
  'SL_SAFARI9': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: '9.0'
  },
  'SL_IOS7': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '7.1'
  },
  'SL_IOS8': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '8.4'
  },
  'SL_IOS9': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '9.1'
  },
  'SL_IE9': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 2008',
    version: '9'
  },
  'SL_IE10': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 2012',
    version: '10'
  },
  'SL_IE11': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 8.1',
    version: '11'
  },
  'SL_EDGE': {
    base: 'SauceLabs',
    browserName: 'MicrosoftEdge',
    platform: 'Windows 10',
    version: '13.10586'
  },
  'SL_ANDROID4.1': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.1'
  },
  'SL_ANDROID4.2': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.2'
  },
  'SL_ANDROID4.3': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.3'
  },
  'SL_ANDROID4.4': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.4'
  },
  'SL_ANDROID5': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '5.1'
  },

  'BS_CHROME': {
    base: 'BrowserStack',
    browser: 'chrome',
    os: 'OS X',
    os_version: 'Yosemite'
  },
  'BS_FIREFOX': {
    base: 'BrowserStack',
    browser: 'firefox',
    os: 'Windows',
    os_version: '10'
  },
  'BS_SAFARI7': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'Mavericks'
  },
  'BS_SAFARI8': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'Yosemite'
  },
  'BS_SAFARI9': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'El Capitan'
  },
  'BS_IOS7': {
    base: 'BrowserStack',
    device: 'iPhone 5S',
    os: 'ios',
    os_version: '7.0'
  },
  'BS_IOS8': {
    base: 'BrowserStack',
    device: 'iPhone 6',
    os: 'ios',
    os_version: '8.3'
  },
  'BS_IOS9': {
    base: 'BrowserStack',
    device: 'iPhone 6S',
    os: 'ios',
    os_version: '9.0'
  },
  'BS_IE9': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '9.0',
    os: 'Windows',
    os_version: '7'
  },
  'BS_IE10': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '10.0',
    os: 'Windows',
    os_version: '8'
  },
  'BS_IE11': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '11.0',
    os: 'Windows',
    os_version: '10'
  },
  'BS_EDGE': {
    base: 'BrowserStack',
    browser: 'edge',
    os: 'Windows',
    os_version: '10'
  },
  'BS_WINDOWSPHONE' : {
    base: 'BrowserStack',
    device: 'Nokia Lumia 930',
    os: 'winphone',
    os_version: '8.1'
  },
  'BS_ANDROID5': {
    base: 'BrowserStack',
    device: 'Google Nexus 5',
    os: 'android',
    os_version: '5.0'
  },
  'BS_ANDROID4.4': {
    base: 'BrowserStack',
    device: 'HTC One M8',
    os: 'android',
    os_version: '4.4'
  },
  'BS_ANDROID4.3': {
    base: 'BrowserStack',
    device: 'Samsung Galaxy S4',
    os: 'android',
    os_version: '4.3'
  },
  'BS_ANDROID4.2': {
    base: 'BrowserStack',
    device: 'Google Nexus 4',
    os: 'android',
    os_version: '4.2'
  },
  'BS_ANDROID4.1': {
    base: 'BrowserStack',
    device: 'Google Nexus 7',
    os: 'android',
    os_version: '4.1'
  }
};

var sauceAliases = {
  'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
  'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
  'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
  'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
  'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
  'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
  'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
  'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
  'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
  'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
  'CI_OPTIONAL': buildConfiguration('unitTest', 'SL', false)
};

var browserstackAliases = {
  'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
  'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
  'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
  'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
  'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
  'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
  'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
  'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
  'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
};

module.exports = {
  customLaunchers: customLaunchers,
  sauceAliases: sauceAliases,
  browserstackAliases: browserstackAliases
};

function buildConfiguration(type, target, required) {
  return Object.keys(CIconfiguration)
    .filter((item) => {
      var conf = CIconfiguration[item][type];
      return conf.required === required && conf.target === target;
    })
    .map((item) => {
      return target + '_' + item.toUpperCase();
    });
}
<commit_msg>ci(browser providers): update browsers in SL and BS (#10425)<commit_after>// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration.
var CIconfiguration = {
  'Chrome':       { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Firefox':      { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  // FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true
  // Currently deactivated due to https://github.com/angular/angular/issues/7560
  'ChromeBeta':   { unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
  'FirefoxBeta':  { unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
  'ChromeDev':    { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'FirefoxDev':   { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
  'IE9':          { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'IE10':         { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'IE11':         { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
  'Edge':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'Android4.1':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.2':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.3':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android4.4':   { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Android5':     { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
  'Safari7':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'Safari8':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'Safari9':      { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'iOS7':         { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
  'iOS8':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'iOS9':         { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
  'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};

var customLaunchers = {
  'DartiumWithWebPlatform': {
    base: 'Dartium',
    flags: ['--enable-experimental-web-platform-features'] },
  'ChromeNoSandbox': {
    base: 'Chrome',
    flags: ['--no-sandbox'] },
  'SL_CHROME': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: '52'
  },
  'SL_CHROMEBETA': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: 'beta'
  },
  'SL_CHROMEDEV': {
    base: 'SauceLabs',
    browserName: 'chrome',
    version: 'dev'
  },
  'SL_FIREFOX': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: '46'
  },
  'SL_FIREFOXBETA': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'beta'
  },
  'SL_FIREFOXDEV': {
    base: 'SauceLabs',
    browserName: 'firefox',
    version: 'dev'
  },
  'SL_SAFARI7': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.9',
    version: '7.0'
  },
  'SL_SAFARI8': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.10',
    version: '8.0'
  },
  'SL_SAFARI9': {
    base: 'SauceLabs',
    browserName: 'safari',
    platform: 'OS X 10.11',
    version: '9.0'
  },
  'SL_IOS7': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '7.1'
  },
  'SL_IOS8': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '8.4'
  },
  'SL_IOS9': {
    base: 'SauceLabs',
    browserName: 'iphone',
    platform: 'OS X 10.10',
    version: '9.3'
  },
  'SL_IE9': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 2008',
    version: '9'
  },
  'SL_IE10': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 2012',
    version: '10'
  },
  'SL_IE11': {
    base: 'SauceLabs',
    browserName: 'internet explorer',
    platform: 'Windows 8.1',
    version: '11'
  },
  'SL_EDGE': {
    base: 'SauceLabs',
    browserName: 'MicrosoftEdge',
    platform: 'Windows 10',
    version: '13.10586'
  },
  'SL_ANDROID4.1': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.1'
  },
  'SL_ANDROID4.2': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.2'
  },
  'SL_ANDROID4.3': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.3'
  },
  'SL_ANDROID4.4': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '4.4'
  },
  'SL_ANDROID5': {
    base: 'SauceLabs',
    browserName: 'android',
    platform: 'Linux',
    version: '5.1'
  },

  'BS_CHROME': {
    base: 'BrowserStack',
    browser: 'chrome',
    os: 'OS X',
    os_version: 'Yosemite'
  },
  'BS_FIREFOX': {
    base: 'BrowserStack',
    browser: 'firefox',
    os: 'Windows',
    os_version: '10'
  },
  'BS_SAFARI7': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'Mavericks'
  },
  'BS_SAFARI8': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'Yosemite'
  },
  'BS_SAFARI9': {
    base: 'BrowserStack',
    browser: 'safari',
    os: 'OS X',
    os_version: 'El Capitan'
  },
  'BS_IOS7': {
    base: 'BrowserStack',
    device: 'iPhone 5S',
    os: 'ios',
    os_version: '7.0'
  },
  'BS_IOS8': {
    base: 'BrowserStack',
    device: 'iPhone 6',
    os: 'ios',
    os_version: '8.3'
  },
  'BS_IOS9': {
    base: 'BrowserStack',
    device: 'iPhone 6S',
    os: 'ios',
    os_version: '9.1'
  },
  'BS_IE9': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '9.0',
    os: 'Windows',
    os_version: '7'
  },
  'BS_IE10': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '10.0',
    os: 'Windows',
    os_version: '8'
  },
  'BS_IE11': {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '11.0',
    os: 'Windows',
    os_version: '10'
  },
  'BS_EDGE': {
    base: 'BrowserStack',
    browser: 'edge',
    os: 'Windows',
    os_version: '10'
  },
  'BS_WINDOWSPHONE' : {
    base: 'BrowserStack',
    device: 'Nokia Lumia 930',
    os: 'winphone',
    os_version: '8.1'
  },
  'BS_ANDROID5': {
    base: 'BrowserStack',
    device: 'Google Nexus 5',
    os: 'android',
    os_version: '5.0'
  },
  'BS_ANDROID4.4': {
    base: 'BrowserStack',
    device: 'HTC One M8',
    os: 'android',
    os_version: '4.4'
  },
  'BS_ANDROID4.3': {
    base: 'BrowserStack',
    device: 'Samsung Galaxy S4',
    os: 'android',
    os_version: '4.3'
  },
  'BS_ANDROID4.2': {
    base: 'BrowserStack',
    device: 'Google Nexus 4',
    os: 'android',
    os_version: '4.2'
  },
  'BS_ANDROID4.1': {
    base: 'BrowserStack',
    device: 'Google Nexus 7',
    os: 'android',
    os_version: '4.1'
  }
};

var sauceAliases = {
  'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
  'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
  'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
  'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
  'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
  'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
  'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
  'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
  'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
  'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
  'CI_OPTIONAL': buildConfiguration('unitTest', 'SL', false)
};

var browserstackAliases = {
  'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
  'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
  'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
  'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
  'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
  'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
  'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
  'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
  'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
};

module.exports = {
  customLaunchers: customLaunchers,
  sauceAliases: sauceAliases,
  browserstackAliases: browserstackAliases
};

function buildConfiguration(type, target, required) {
  return Object.keys(CIconfiguration)
    .filter((item) => {
      var conf = CIconfiguration[item][type];
      return conf.required === required && conf.target === target;
    })
    .map((item) => {
      return target + '_' + item.toUpperCase();
    });
}
<|endoftext|>


<commit_before>BookShelf.TagListView = function(params) {

    var items = ko.observableArray();
    var selected = ko.observableArray();

    var id = ko.observable();
    var title = ko.observable();
    var editing = ko.observable();

    var viewModel = {

        items: items,
        selectionEnabled: params.selectionEnabled,
        scrollingEnabled: (params.scrollingEnabled === undefined) ? true : params.scrollingEnabled,
        editingEnabled: (params.editingEnabled === undefined) ? true : params.editingEnabled,
        selected: selected,

        editing: editing,

        tag: {
            id: id,
            title: title,
            invalid: ko.computed(function() {
                return !title();
            })
        },

        getTag: function() {
            return {
                id: id(),
                title: title()
            };
        },

        prepareTag: function(tag) {
            id(tag.id);
            title(tag.title);
        },

        resetTag: function() {
            editing(false);
            this.prepareTag({});
        },

        saveTag: function() {
            var tag = this.getTag();

            var currentSelected = selected();
            if(editing()) {
                BookShelf.db.tags.update(tag);
                this.reloadItems();
                BookShelf.app.bookListShowing.fire({ reloadTag: tag.id });
            } else {
                var newTag = BookShelf.db.tags.get(BookShelf.db.tags.add(tag));
                items.unshift(newTag);
                currentSelected.push(newTag);
            }
            selected(currentSelected);

            this.resetTag();
        },

        cancelEditTag: function() {
            this.resetTag();
        },

        editTag: function(args) {
            this.prepareTag(args.itemData);
            editing(true);

            $(".tag-form-field").dxTextBox("focus");
        },

        deleteTagConfirmation: function(args) {
            var booksByTag = BookShelf.db.books.getByTag(args.itemData.id);

            if(!booksByTag.length)
                return;

            return DevExpress.ui.dialog.confirm("Are you sure you want to delete category \"" + args.itemData.title + "\"? There are books associated with this category.", "Delete category");
        },

        deleteTag: function(args) {
            BookShelf.db.tags.remove(args.itemData.id);
            BookShelf.app.bookListShowing.fire({ reloadTag: args.itemData.id });
        },

        listTnit: function(args) {
            this.list = args.component;
        },

        onShowing: function() {
            this.resetTag();

            var currentSelected = selected();
            this.reloadItems();
            selected(currentSelected);
        },

        reloadItems: function() {
            items(BookShelf.db.tags.getAll().slice().sort(function(a, b) { return b.title < a.title }));
        },

        onShown: function() {
            this.list.element().off("dxactive.listBetterActiveState dxinactive.listBetterActiveState");
            if(params.selectionEnabled) {
                this.list.element()
                    .on("dxactive.listBetterActiveState", ".dx-list-item", { timeout: 30 }, function(e) {
                        $(e.currentTarget).addClass("dx-state-active");
                    })
                    .on("dxinactive.listBetterActiveState", ".dx-list-item", { timeout: 400 }, function(e) {
                        $(e.currentTarget).removeClass("dx-state-active");
                    });
            }
        }

    };

    return viewModel;
};<commit_msg>Views: Fix focus text field on tag edit<commit_after>BookShelf.TagListView = function(params) {

    var items = ko.observableArray();
    var selected = ko.observableArray();

    var id = ko.observable();
    var title = ko.observable();
    var editing = ko.observable();

    var viewModel = {

        items: items,
        selectionEnabled: params.selectionEnabled,
        scrollingEnabled: (params.scrollingEnabled === undefined) ? true : params.scrollingEnabled,
        editingEnabled: (params.editingEnabled === undefined) ? true : params.editingEnabled,
        selected: selected,

        editing: editing,

        tag: {
            id: id,
            title: title,
            invalid: ko.computed(function() {
                return !title();
            })
        },

        getTag: function() {
            return {
                id: id(),
                title: title()
            };
        },

        prepareTag: function(tag) {
            id(tag.id);
            title(tag.title);
        },

        resetTag: function() {
            editing(false);
            this.prepareTag({});
        },

        saveTag: function() {
            var tag = this.getTag();

            var currentSelected = selected();
            if(editing()) {
                BookShelf.db.tags.update(tag);
                this.reloadItems();
                BookShelf.app.bookListShowing.fire({ reloadTag: tag.id });
            } else {
                var newTag = BookShelf.db.tags.get(BookShelf.db.tags.add(tag));
                items.unshift(newTag);
                currentSelected.push(newTag);
            }
            selected(currentSelected);

            this.resetTag();
        },

        cancelEditTag: function() {
            this.resetTag();
        },

        editTag: function(args) {
            this.prepareTag(args.itemData);
            editing(true);

            setTimeout(function() {
                $(".tag-form-field").dxTextBox("focus");
            }, 500);
        },

        deleteTagConfirmation: function(args) {
            var booksByTag = BookShelf.db.books.getByTag(args.itemData.id);

            if(!booksByTag.length)
                return;

            return DevExpress.ui.dialog.confirm("Are you sure you want to delete category \"" + args.itemData.title + "\"? There are books associated with this category.", "Delete category");
        },

        deleteTag: function(args) {
            BookShelf.db.tags.remove(args.itemData.id);
            BookShelf.app.bookListShowing.fire({ reloadTag: args.itemData.id });
        },

        listTnit: function(args) {
            this.list = args.component;
        },

        onShowing: function() {
            this.resetTag();

            var currentSelected = selected();
            this.reloadItems();
            selected(currentSelected);
        },

        reloadItems: function() {
            items(BookShelf.db.tags.getAll().slice().sort(function(a, b) { return b.title < a.title }));
        },

        onShown: function() {
            this.list.element().off("dxactive.listBetterActiveState dxinactive.listBetterActiveState");
            if(params.selectionEnabled) {
                this.list.element()
                    .on("dxactive.listBetterActiveState", ".dx-list-item", { timeout: 30 }, function(e) {
                        $(e.currentTarget).addClass("dx-state-active");
                    })
                    .on("dxinactive.listBetterActiveState", ".dx-list-item", { timeout: 400 }, function(e) {
                        $(e.currentTarget).removeClass("dx-state-active");
                    });
            }
        }

    };

    return viewModel;
};<|endoftext|>


<commit_before>/** Related User autocomplete widget. */
Ext.define('devilry_subjectadmin.view.managestudents.AutocompleteGroupWidget', {
    extend: 'devilry_usersearch.AutocompleteUserWidget',
    alias: 'widget.autocompletegroupwidget',
    cls: 'devilry_usersearch_autocompletegroupwidget',

    hideTrigger: true,
    displayField: 'id',
    minChars: 1,
    store: 'SearchForGroups',

    //fieldLabel: gettext('Select by search'),
    //labelWidth: 120,
    hideLabel: true,
    emptyText: gettext('Search (adds to selection)') + ' ...',

    listGetInnerTpl: function() {
        return[
            '
',
                '
',
                '<tpl for="candidates">',
                    '
',
                        '<tpl if="user.full_name">',
                            '{user.full_name}',
                            ' ({user.username})',
                        '<tpl else>',
                            '{user.username}',
                        '</tpl>',
                    '
',
                '</tpl>',
                '
',
            '
'
        ].join('');
    }
});
<commit_msg>devilry_subjectadmin...AutocompleteGroupWidget: Cleanup.<commit_after>/** Related User autocomplete widget. */
Ext.define('devilry_subjectadmin.view.managestudents.AutocompleteGroupWidget', {
    extend: 'devilry_usersearch.AutocompleteUserWidget',
    alias: 'widget.autocompletegroupwidget',
    cls: 'devilry_usersearch_autocompletegroupwidget',

    hideTrigger: true,
    displayField: 'id',
    minChars: 1,
    store: 'SearchForGroups',

    //fieldLabel: gettext('Select by search'),
    //labelWidth: 120,
    hideLabel: true,

    listGetInnerTpl: function() {
        return[
            '
',
                '
',
                '<tpl for="candidates">',
                    '
',
                        '<tpl if="user.full_name">',
                            '{user.full_name}',
                            ' ({user.username})',
                        '<tpl else>',
                            '{user.username}',
                        '</tpl>',
                    '
',
                '</tpl>',
                '
',
            '
'
        ].join('');
    }
});
<|endoftext|>


<commit_before>(function($){
	"use strict";

	var debug, debugLog;
	debug = $('.js-listfilter-form').data('debug');
	if (debug) {
		debugLog = function(message) {
			console.log(message);
			alert(message);
		};
	} else {
		debugLog = function() {};
	}

	$(document).ready(function() {
		formsInit();
	});

	function FormSubmit(e) {
		var $form = $(this);
		if (!$form.data('ajax')) {
			return true;
		}
		e.preventDefault();
		if ($form.data('is-loading') === true) {
			return;
		}
		var ajaxBefore = $form.triggerHandler('ListFilterAJAXBefore');
		if (ajaxBefore === false) {
			return;
		}

		// Update listing areas specifically using the same 'data-listfilter-id'
		var $relatedListing = $('.js-listfilter-listing[data-listfilter-id="'+$form.data('listfilter-id')+'"]');
		// Update all listings in global scope (ie. without a 'data-listfilter-id' value)
		var $globalListing = $('.js-listfilter-listing:not([data-listfilter-id])');
		var $relatedWidget = $('.js-listfilter-widget[data-listfilter-id="'+$form.data('listfilter-id')+'"]');
		var $showingMessage = $('.js-listfilter-listing-showingmessage');

		// Add class to signify its loading
		// todo(Jake): Make state class below configurable
		var loadingClass = 'is-listfilter-loading';
		var loadingElements = [];
		if (loadingClass) {
			loadingElements.push($form);
			if ($relatedListing.length > 0) { loadingElements.push($relatedListing); }
			if ($globalListing.length > 0)  { loadingElements.push($globalListing);  }
			if ($relatedWidget.length > 0)  { loadingElements.push($relatedWidget);  }
			if ($showingMessage.length > 0) { loadingElements.push($showingMessage); }
		}
		for (var l = 0; l < loadingElements.length; ++l) {
			$(loadingElements[l]).addClass(loadingClass);
		}
		jQuery.support.cors = true;
		$form.data('is-loading', true);
		jQuery.ajax({
			type: 'GET',
			url: $form.attr('action'),
			crossDomain: true,
			headers: {
				// Force sending of header for IE7/8
				'X-Requested-With': 'XMLHttpRequest'
			},
			data: $form.serialize()
		}).done(function(data, textStatus, jqXHR) {
			$form.data('is-loading', false);
			var template, filterGroups, fields;
			if (typeof data === 'object') {
				filterGroups = data.FilterGroups;
				template = data.Listing;
			} else {
				filterGroups = null;
				template = data;
			}
			if (template.indexOf('<form') > -1) {
				var validateBefore = $form.triggerHandler('ListFilterFormValidateBefore', [data, textStatus, jqXHR]);
				if (validateBefore === false) {
					// Stop default execution.
					return;
				}
				// todo(Jake): Ideally make this more robust and "diff" the two HTML sets better.
				// Extract error message elements out of form and place semi-appropriately.
				var errorMessageQuery = '.message.validation, .message.required, .message.warning, .message.error';
				if (typeof validateBefore === 'string' && validateBefore !== '') {
					errorMessageQuery = validateBefore;
				}

				var $dataForm = $(data);
				if ($dataForm.length === 0) {
					debugLog('Cannot find <form> element.');
					return;
				}
				if ($dataForm[0].tagName !== 'FORM') {
					$dataForm = $form.find('form').first();
					if ($dataForm.length === 0 || $dataForm[0].tagName !== 'FORM') {
						debugLog('Cannot find <form> element.');
						return;
					}
				}
				var form = $dataForm[0];
				for (var fieldIndex = 0; fieldIndex < form.elements.length; ++fieldIndex) {
					var dataField = form.elements[fieldIndex];
					if (dataField.tagName === 'FIELDSET' || dataField.tagName === 'BUTTON') {
						continue;
					}
					var $dataErrorMessage = null;
					var $formField = null;
					var dataFieldParent = dataField.parentNode;
					// Handle when  is under FormField.ss template
					$dataErrorMessage = $(dataFieldParent.childNodes).filter(errorMessageQuery).first();
					if ($dataErrorMessage.length > 0) {
						$formField = $form.find('[name="'+dataField.name+'"]').first();
						if ($formField.length > 0) {
							$formField.siblings().find(errorMessageQuery).remove();
							if ($(dataField).nextAll(errorMessageQuery).length > 0) {
								$formField.after($dataErrorMessage);
							} else {
								$formField.before($dataErrorMessage);
							}
						}
					}
					// Handle when  is under FieldHolder.ss template
					$dataErrorMessage = $(dataFieldParent.parentNode.childNodes).filter(errorMessageQuery).first();
					if ($dataErrorMessage.length > 0) {
						$formField = $form.find('[name="'+dataField.name+'"]').first();
						if ($formField.length > 0) {
							var $middleColumn = $formField.parent();
							var $holder = $middleColumn.parent();
							$holder.find(errorMessageQuery).remove();
							if ($(dataField).parent().nextAll(errorMessageQuery).length > 0) {
								$holder.append($dataErrorMessage);
							} else {
								$holder.prepend($dataErrorMessage);
							}
						}
					}
				}
			} else {
				// Update listing areas specifically using the same 'data-listfilter-id'
				$relatedListing.html(template);
				// Update all listings in global scope (ie. without a 'data-listfilter-id' value)
				$globalListing.html(template);
				if ($relatedListing.length + $globalListing.length === 0) {
					debugLog('Missing .js-listfilter-listing element. Unable to put form result anywhere.');
				}
				if (typeof data === 'object') {
					for (var field in data) {
						if (field === 'Listing' || field === 'FilterGroups') {
							continue;
						}
						var value = data[field];
						var selector = '.js-listfilter-listing-' + field.toLowerCase();
						var $relatedListingCount = $(selector+'[data-listfilter-id="'+$form.data('listfilter-id')+'"]');
						$relatedListingCount.html(value);
						var $globalListingCount = $(selector+':not([data-listfilter-id])');
						$globalListingCount.html(value);
					}
				}
			}
			if (filterGroups !== null) {
				$form.data('listfilter-backend', filterGroups);
				$form.trigger('ListFilterFormUpdate');
			}
			$form.trigger('ListFilterAJAXDone', [data, textStatus, jqXHR]);
		}).fail(function(x, e, exception) {
			$form.data('is-loading', false);
			$form.trigger('ListFilterAJAXFail', [x, e, exception]);
			if (debug) {
				if(x.status === 0){
					alert('You are offline!!\n Please Check Your Network.');
				} else if(x.status == 404){
					alert('Requested URL not found.');
				} else if(x.status == 500){
					//$result.html(x.responseText);
					alert('Internal Server Error.');
				} else if(e == 'parsererror'){
					//$result.html(x.responseText);
					alert('Error.\nParsing JSON Request failed.');
				} else if(e == 'timeout'){
					alert('Request Time out.');
				} else {
					alert('Unknown Error.\n'+x.responseText);
				}
			}
		}).complete(function(dataOrJqXHR, textStatus, jqXHROrErrorThrown) {
			$form.data('is-loading', false);
			for (var l = 0; l < loadingElements.length; ++l) {
				$(loadingElements[l]).removeClass(loadingClass);
			}
			$form.trigger('ListFilterAJAXComplete', [dataOrJqXHR, textStatus, jqXHROrErrorThrown]);
		});
	}

	function FormFieldChange(e) {
		var $filterGroupHolder = $(this).parents('.js-listfilter-filter').first();
		var $form = $(this.form);
		if (!$filterGroupHolder.length) {
			debugLog("Missing .js-listfilter-filter as parent element. ListFilterBase_holder must have been modified"
			+ " incorrectly.\n\nOmit the 'name' attribute or add class '.js-listfilter-ignore' if its unrelated to"
			+ " the ListFilterForm.\n\nThis is also known to occur when CompositeField_holder.ss is put into an"
			+ " /Includes/ folder, rather than /forms/. Old versions of Unclecheese's Display Logic module will do this"
			+ " and break this module.");
			return;
		}
		$form.trigger('ListFilterFormUpdate');
	}

	function formsInit() {
		$('.js-listfilter-form').each(function() {
			var $form = $(this);
			if ($form.data('listfilter-initiated')) {
				return;
			}
			var $widget = $('.js-listfilter-widget[data-listfilter-id="'+$(this).data('listfilter-id')+'"]');
			if ($widget.length) {
				$form.data('widget', $widget);
				$widget.data('form', $form);
			}
			// Setup callbacks
			for (var i = 0; i < this.elements.length; ++i) {
				var it = this.elements[i];
				if (it.tagName === 'FIELDSET' || $(it).hasClass('js-listfilter-ignore') || !($(it).attr('name'))) {
					continue;
				}
				$(it).change(FormFieldChange);
			}
			if ($form.data('ajax')) {
				$form.on('submit', FormSubmit);
			}
			$form.on('ListFilterFormSubmit', FormSubmit);

			$form.data('listfilter-initiated', true);
			$form.trigger('ListFilterFormInit');
		});
	}

	$('.js-listfilter-widget').bind('ListFilterWidgetInit', function(e) {
		var $form = $(this).data('form');
		if (typeof $form === 'undefined' || !$form || !$form.length) {
			return;
		}
		$form.trigger('ListFilterFormUpdate');
	});

	$('.js-listfilter-form').bind('ListFilterFormUpdate', function(e) {
		var $form = $(this);
		var $widget = $form.data('widget');
		if (typeof $widget === 'undefined' || !$widget || !$widget.length || !$widget.is(':visible')) {
			return;
		}
		var allRecords = $widget.data('listfilter-records');
		if (allRecords === false || allRecords === null || typeof allRecords === 'undefined') {
			if (allRecords !== false) {
				debugLog('js-listfilter-form::ListFilterFormUpdate: Missing data-listfilter-records. Widget-specific code like the Google Map should set this data up. Initialize "data-listfilter-records" to false while waiting on AJAX calls.');
			}
			return;
		}
		var backendFilters = $form.data('listfilter-backend');
		var recordsInFilterGroups = {};
		$(this).find('.js-listfilter-filter').each(function() {
			var fieldGroupCallback = $(this).data('fieldgroup-callback');
			if (fieldGroupCallback) {
				var fieldGroupID = $(this).data('fieldgroup-id');
				var backendFilter;
				if (typeof backendFilters[fieldGroupID] !== 'undefined') {
					backendFilter = backendFilters[fieldGroupID];
				} else {
					backendFilter = null;
				}
				var value = $(this).triggerHandler(fieldGroupCallback, [allRecords, backendFilter]);
				if (value) {
					recordsInFilterGroups[fieldGroupID] = value;
				}
			}
		});

		// Show all markers if no filters present
		if ($.isEmptyObject(recordsInFilterGroups)) {
			$widget.trigger('ListFilterRecordsUpdate', [allRecords, true]);
			return;
		}

		// Do 'AND' logic across filter groups.
		// ie. Ensure a record has tags AND fits into the date range.
		var recordsThatMatchFilter = [];
		var recordsMap = null;
		for (var fieldGroupID in recordsInFilterGroups) {
			if (!recordsInFilterGroups.hasOwnProperty(fieldGroupID)) {
				continue;
			}
			recordsMap = recordsInFilterGroups[fieldGroupID];
			break;
		}
		if (recordsMap !== null) {
			for (var recordID in recordsMap) {
				if (!recordsMap.hasOwnProperty(recordID)) {
					continue;
				}
				var isInAllFilters = true;
				for (var otherFieldGroupID in recordsInFilterGroups) {
					if (otherFieldGroupID == fieldGroupID || !recordsInFilterGroups.hasOwnProperty(otherFieldGroupID)) {
						continue;
					}
					var otherFieldGroup = recordsInFilterGroups[otherFieldGroupID];
					if (typeof otherFieldGroup[recordID] === 'undefined') {
						isInAllFilters = false;
						break;
					}
				}
				if (isInAllFilters) {
					var record = recordsMap[recordID];
					recordsThatMatchFilter.push(record);
				}
			}
		}
		// Hide all markers
		$widget.trigger('ListFilterRecordsUpdate', [allRecords, false]);

		// Show markers that match filter criterion
		$widget.trigger('ListFilterRecordsUpdate', [recordsThatMatchFilter, true]);
	});
})(jQuery);<commit_msg>FIX: Non-AJAX submissions now show as though they're loading.<commit_after>(function($){
	"use strict";

	var debug, debugLog;
	debug = $('.js-listfilter-form').data('debug');
	if (debug) {
		debugLog = function(message) {
			console.log(message);
			alert(message);
		};
	} else {
		debugLog = function() {};
	}

	$(document).ready(function() {
		formsInit();
	});

	function FormSubmit(e) {
		var $form = $(e.target);

		if ($form.data('is-loading') === true) {
			return;
		}
		var ajaxBefore = $form.triggerHandler('ListFilterAJAXBefore');
		if (ajaxBefore === false) {
			return;
		}

		// Update listing areas specifically using the same 'data-listfilter-id'
		var $relatedListing = $('.js-listfilter-listing[data-listfilter-id="'+$form.data('listfilter-id')+'"]');
		// Update all listings in global scope (ie. without a 'data-listfilter-id' value)
		var $globalListing = $('.js-listfilter-listing:not([data-listfilter-id])');
		var $relatedWidget = $('.js-listfilter-widget[data-listfilter-id="'+$form.data('listfilter-id')+'"]');
		var $showingMessage = $('.js-listfilter-listing-showingmessage');

		// Add class to signify its loading
		// todo(Jake): Make state class below configurable
		var loadingClass = 'is-listfilter-loading';
		var loadingElements = [];
		if (loadingClass) {
			loadingElements.push($form);
			if ($relatedListing.length > 0) { loadingElements.push($relatedListing); }
			if ($globalListing.length > 0)  { loadingElements.push($globalListing);  }
			if ($relatedWidget.length > 0)  { loadingElements.push($relatedWidget);  }
			if ($showingMessage.length > 0) { loadingElements.push($showingMessage); }
		}
		for (var l = 0; l < loadingElements.length; ++l) {
			$(loadingElements[l]).addClass(loadingClass);
		}

		// This happens here so the page looks like it's loading even when AJAX isn't being used.
		if (!$form.data('ajax')) {
			return true;
		}
		e.preventDefault();

		jQuery.support.cors = true;
		$form.data('is-loading', true);
		jQuery.ajax({
			type: 'GET',
			url: $form.attr('action'),
			crossDomain: true,
			headers: {
				// Force sending of header for IE7/8
				'X-Requested-With': 'XMLHttpRequest'
			},
			data: $form.serialize()
		}).done(function(data, textStatus, jqXHR) {
			$form.data('is-loading', false);
			var template, filterGroups, fields;
			if (typeof data === 'object') {
				filterGroups = data.FilterGroups;
				template = data.Listing;
			} else {
				filterGroups = null;
				template = data;
			}
			if (template.indexOf('<form') > -1) {
				var validateBefore = $form.triggerHandler('ListFilterFormValidateBefore', [data, textStatus, jqXHR]);
				if (validateBefore === false) {
					// Stop default execution.
					return;
				}
				// todo(Jake): Ideally make this more robust and "diff" the two HTML sets better.
				// Extract error message elements out of form and place semi-appropriately.
				var errorMessageQuery = '.message.validation, .message.required, .message.warning, .message.error';
				if (typeof validateBefore === 'string' && validateBefore !== '') {
					errorMessageQuery = validateBefore;
				}

				var $dataForm = $(data);
				if ($dataForm.length === 0) {
					debugLog('Cannot find <form> element.');
					return;
				}
				if ($dataForm[0].tagName !== 'FORM') {
					$dataForm = $form.find('form').first();
					if ($dataForm.length === 0 || $dataForm[0].tagName !== 'FORM') {
						debugLog('Cannot find <form> element.');
						return;
					}
				}
				var form = $dataForm[0];
				for (var fieldIndex = 0; fieldIndex < form.elements.length; ++fieldIndex) {
					var dataField = form.elements[fieldIndex];
					if (dataField.tagName === 'FIELDSET' || dataField.tagName === 'BUTTON') {
						continue;
					}
					var $dataErrorMessage = null;
					var $formField = null;
					var dataFieldParent = dataField.parentNode;
					// Handle when  is under FormField.ss template
					$dataErrorMessage = $(dataFieldParent.childNodes).filter(errorMessageQuery).first();
					if ($dataErrorMessage.length > 0) {
						$formField = $form.find('[name="'+dataField.name+'"]').first();
						if ($formField.length > 0) {
							$formField.siblings().find(errorMessageQuery).remove();
							if ($(dataField).nextAll(errorMessageQuery).length > 0) {
								$formField.after($dataErrorMessage);
							} else {
								$formField.before($dataErrorMessage);
							}
						}
					}
					// Handle when  is under FieldHolder.ss template
					$dataErrorMessage = $(dataFieldParent.parentNode.childNodes).filter(errorMessageQuery).first();
					if ($dataErrorMessage.length > 0) {
						$formField = $form.find('[name="'+dataField.name+'"]').first();
						if ($formField.length > 0) {
							var $middleColumn = $formField.parent();
							var $holder = $middleColumn.parent();
							$holder.find(errorMessageQuery).remove();
							if ($(dataField).parent().nextAll(errorMessageQuery).length > 0) {
								$holder.append($dataErrorMessage);
							} else {
								$holder.prepend($dataErrorMessage);
							}
						}
					}
				}
			} else {
				// Update listing areas specifically using the same 'data-listfilter-id'
				$relatedListing.html(template);
				// Update all listings in global scope (ie. without a 'data-listfilter-id' value)
				$globalListing.html(template);
				if ($relatedListing.length + $globalListing.length === 0) {
					debugLog('Missing .js-listfilter-listing element. Unable to put form result anywhere.');
				}
				if (typeof data === 'object') {
					for (var field in data) {
						if (field === 'Listing' || field === 'FilterGroups') {
							continue;
						}
						var value = data[field];
						var selector = '.js-listfilter-listing-' + field.toLowerCase();
						var $relatedListingCount = $(selector+'[data-listfilter-id="'+$form.data('listfilter-id')+'"]');
						$relatedListingCount.html(value);
						var $globalListingCount = $(selector+':not([data-listfilter-id])');
						$globalListingCount.html(value);
					}
				}
			}
			if (filterGroups !== null) {
				$form.data('listfilter-backend', filterGroups);
				$form.trigger('ListFilterFormUpdate');
			}
			$form.trigger('ListFilterAJAXDone', [data, textStatus, jqXHR]);
		}).fail(function(x, e, exception) {
			$form.data('is-loading', false);
			$form.trigger('ListFilterAJAXFail', [x, e, exception]);
			if (debug) {
				if(x.status === 0){
					alert('You are offline!!\n Please Check Your Network.');
				} else if(x.status == 404){
					alert('Requested URL not found.');
				} else if(x.status == 500){
					//$result.html(x.responseText);
					alert('Internal Server Error.');
				} else if(e == 'parsererror'){
					//$result.html(x.responseText);
					alert('Error.\nParsing JSON Request failed.');
				} else if(e == 'timeout'){
					alert('Request Time out.');
				} else {
					alert('Unknown Error.\n'+x.responseText);
				}
			}
		}).complete(function(dataOrJqXHR, textStatus, jqXHROrErrorThrown) {
			$form.data('is-loading', false);
			for (var l = 0; l < loadingElements.length; ++l) {
				$(loadingElements[l]).removeClass(loadingClass);
			}
			$form.trigger('ListFilterAJAXComplete', [dataOrJqXHR, textStatus, jqXHROrErrorThrown]);
		});
	}

	function FormFieldChange(e) {
		var $filterGroupHolder = $(this).parents('.js-listfilter-filter').first();
		var $form = $(this.form);
		if (!$filterGroupHolder.length) {
			debugLog("Missing .js-listfilter-filter as parent element. ListFilterBase_holder must have been modified"
			+ " incorrectly.\n\nOmit the 'name' attribute or add class '.js-listfilter-ignore' if its unrelated to"
			+ " the ListFilterForm.\n\nThis is also known to occur when CompositeField_holder.ss is put into an"
			+ " /Includes/ folder, rather than /forms/. Old versions of Unclecheese's Display Logic module will do this"
			+ " and break this module.");
			return;
		}
		$form.trigger('ListFilterFormUpdate');
	}

	function formsInit() {
		$('.js-listfilter-form').each(function() {
			var $form = $(this);
			if ($form.data('listfilter-initiated')) {
				return;
			}
			var $widget = $('.js-listfilter-widget[data-listfilter-id="'+$(this).data('listfilter-id')+'"]');
			if ($widget.length) {
				$form.data('widget', $widget);
				$widget.data('form', $form);
			}
			// Setup callbacks
			for (var i = 0; i < this.elements.length; ++i) {
				var it = this.elements[i];
				if (it.tagName === 'FIELDSET' || $(it).hasClass('js-listfilter-ignore') || !($(it).attr('name'))) {
					continue;
				}
				$(it).change(FormFieldChange);
			}
			$(document).on('submit', $form, FormSubmit);
			$(document).on('ListFilterFormSubmit', $form, FormSubmit);

			$form.data('listfilter-initiated', true);
			$form.trigger('ListFilterFormInit');
		});
	}

	$('.js-listfilter-widget').bind('ListFilterWidgetInit', function(e) {
		var $form = $(this).data('form');
		if (typeof $form === 'undefined' || !$form || !$form.length) {
			return;
		}
		$form.trigger('ListFilterFormUpdate');
	});

	$('.js-listfilter-form').bind('ListFilterFormUpdate', function(e) {
		var $form = $(this);
		var $widget = $form.data('widget');
		if (typeof $widget === 'undefined' || !$widget || !$widget.length || !$widget.is(':visible')) {
			return;
		}
		var allRecords = $widget.data('listfilter-records');
		if (allRecords === false || allRecords === null || typeof allRecords === 'undefined') {
			if (allRecords !== false) {
				debugLog('js-listfilter-form::ListFilterFormUpdate: Missing data-listfilter-records. Widget-specific code like the Google Map should set this data up. Initialize "data-listfilter-records" to false while waiting on AJAX calls.');
			}
			return;
		}
		var backendFilters = $form.data('listfilter-backend');
		var recordsInFilterGroups = {};
		$(this).find('.js-listfilter-filter').each(function() {
			var fieldGroupCallback = $(this).data('fieldgroup-callback');
			if (fieldGroupCallback) {
				var fieldGroupID = $(this).data('fieldgroup-id');
				var backendFilter;
				if (typeof backendFilters[fieldGroupID] !== 'undefined') {
					backendFilter = backendFilters[fieldGroupID];
				} else {
					backendFilter = null;
				}
				var value = $(this).triggerHandler(fieldGroupCallback, [allRecords, backendFilter]);
				if (value) {
					recordsInFilterGroups[fieldGroupID] = value;
				}
			}
		});

		// Show all markers if no filters present
		if ($.isEmptyObject(recordsInFilterGroups)) {
			$widget.trigger('ListFilterRecordsUpdate', [allRecords, true]);
			return;
		}

		// Do 'AND' logic across filter groups.
		// ie. Ensure a record has tags AND fits into the date range.
		var recordsThatMatchFilter = [];
		var recordsMap = null;
		for (var fieldGroupID in recordsInFilterGroups) {
			if (!recordsInFilterGroups.hasOwnProperty(fieldGroupID)) {
				continue;
			}
			recordsMap = recordsInFilterGroups[fieldGroupID];
			break;
		}
		if (recordsMap !== null) {
			for (var recordID in recordsMap) {
				if (!recordsMap.hasOwnProperty(recordID)) {
					continue;
				}
				var isInAllFilters = true;
				for (var otherFieldGroupID in recordsInFilterGroups) {
					if (otherFieldGroupID == fieldGroupID || !recordsInFilterGroups.hasOwnProperty(otherFieldGroupID)) {
						continue;
					}
					var otherFieldGroup = recordsInFilterGroups[otherFieldGroupID];
					if (typeof otherFieldGroup[recordID] === 'undefined') {
						isInAllFilters = false;
						break;
					}
				}
				if (isInAllFilters) {
					var record = recordsMap[recordID];
					recordsThatMatchFilter.push(record);
				}
			}
		}
		// Hide all markers
		$widget.trigger('ListFilterRecordsUpdate', [allRecords, false]);

		// Show markers that match filter criterion
		$widget.trigger('ListFilterRecordsUpdate', [recordsThatMatchFilter, true]);
	});
})(jQuery);<|endoftext|>


<commit_before>$('#form').validator({
    custom: {
        'ppolicy': function($el) {
            if(! $el.prop('required') && $el.val() == 0){
                return true;
            };
            var $ret = 'PPolicy error';
            $.ajax({
                url: '/checkppolicy',
                type: 'POST',
                dataType: 'json',
                async: false,
                data: 'pwd=' + $el.val(),
                success: function(data) {
                    $ret = data;
                }
            });
            this.options.errors['ppolicy'] = $ret['reason'];
            return $ret['match'];
        }
    },
    errors: {
        'ppolicy': 'PPolicy error',
    }
})

// vim:set expandtab tabstop=4 shiftwidth=4:
<commit_msg>fix ppolicy client side javascript checker<commit_after>$('#form').validator({
    custom: {
        'ppolicy': function($el) {
            if(! $el.prop('required') && $el.val() == 0){
                return true;
            };
            var $ret = 'PPolicy error';
            $.ajax({
                url: '/checkppolicy',
                type: 'POST',
                dataType: 'json',
                async: false,
                data: 'pwd=' + encodeURIComponent($el.val()),
                success: function(data) {
                    $ret = data;
                },
                error: function(jqXHR, exception) {
                    switch (jqXHR.status) {
                        case 400:
                            $ret = {"reason":"Javascript ppolicy.js error","match":false};
                            break;
                        case 403:
                            $ret = {"reason":"Session expired, you must reconnect","match":false};
                            break;
                        case 500:
                            $ret = {"reason":"Server error","match":false};
                            break;
                        default:
                            $ret = {"reason":"Unknown error [" + jqXHR.status + "], check logs","match":false};
                    }
                }
            });
            this.options.errors['ppolicy'] = $ret['reason'];
            return $ret['match'];
        }
    },
    errors: {
        'ppolicy': 'PPolicy error',
    }
})

// vim:set expandtab tabstop=4 shiftwidth=4:
<|endoftext|>