<commit_before>/* global require console process describe it */

const tap = require('tap')

const setter = require('../couch_set_state')
const getter = require('couch_check_state')

const superagent = require('superagent')

const path    = require('path')
const rootdir = path.normalize(__dirname)
const config_okay = require('config_okay')
const config_file = rootdir+'/../test.config.json'
const config={}

const utils = require('./utils.js')

tap.plan(1)

const date = new Date()
const inprocess_string = date.toISOString()+' inprocess'

const docs = []

function populate_db(config){

    const mydocs = {'docs':[{'_id':'doc1'
                             ,foo:'bar'}
                            ,{'_id':'doc2'
                              ,'baz':'bat'}

                            ,{"_id": "801245",
                              "2006": {
                              },
                              "2007": {
                                  "vdsimputed": "todo",
                                  "wim_neigbors_ready": {
                                      "wim_id": 77,
                                      "distance": 14788,
                                      "direction": "east"
                                  },
                                  "wim_neigbors": {
                                      "wim_id": 77,
                                      "distance": 14788,
                                      "direction": "east"
                                  },
                                  "truckimputed": "2013-04-06T04:45:11.832Z finish",
                                  "paired_wim": null,
                                  "vdsdata": "0",
                                  "rawdata": "1",
                                  "row": 1,
                                  "vdsraw_chain_lengths": [2,2,2,2,2],
                                  "vdsraw_max_iterations": 0,
                                  "occupancy_averaged": 1,
                                  "truckimputation_chain_lengths": [
                                      145,
                                      147,
                                      144,
                                      139,
                                      143
                                  ],
                                  "truckimputation_max_iterations": 0
                              },
                              "2008": {
                                  "vdsimputed": "todo",
                                  "wim_neigbors_ready": {
                                      "wim_id": 77,
                                      "distance": 14788,
                                      "direction": "east"
                                  },
                                  "wim_neigbors": {
                                      "wim_id": 77,
                                      "distance": 14788,
    "direction": "east"
                                  },
                                  "vdsdata": "0",
                                  "rawdata": "1",
                                  "row": 1,
                                  "truckimputed": "2012-05-21 inprocess",
                                  "vdsraw_chain_lengths": [2,2,2,2,2],
                                  "vdsraw_max_iterations": 0
                              }}

                           ]}
    const cdb =
        [config.couchdb.host+':'+config.couchdb.port
        ,config.couchdb.db].join('/')

    return superagent.post(cdb+'/_bulk_docs')
        .type('json')
        .send(mydocs)

}

function testing (t){
    t.plan(6)
    return t.test(
        'should set chain lengths state for doc1, 2007'
        ,function(tt){
          var task = Object.assign({}
                                   ,config.couchdb
                                   ,{'doc':'801245'
                                     ,'year':2008
                                     ,'state':'truckimputed'
                                     ,'value':inprocess_string
                                    })

          setter(task
                 ,function(err,state){
                     tt.notOk(err,'should not get an error')
                     delete task.value
                     getter(task
                            ,function(errr,state){
                                tt.notOk(errr,'should not get an error')
                                tt.is(state,inprocess_string)
                                tt.end()
                                return null
                            })
                     return null
                  })
      }).then(function(t){
          return t.test(
              'should set inprocess string'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'doc1'
                                             ,'year':2008
                                             ,'state':'vdsraw_chain_lengths'
                                             ,'value':[11,23,19,22,15]})
                  setter(task
                         ,function(err,state){
                             tt.notOk(err,'should not get an error from setter')
                             delete task.value
                             getter(task
                                    ,function(err,state){
                                        tt.notOk(err,'should not get error')
                                        tt.ok(state.length)
                                        tt.is(state.length,5,'length of 5')
                                        tt.same(state,[11,23,19,22,15])
                                        tt.end()
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'should remove entirely if variable is defined but null'
              ,function(tt){
                  // now you see it
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'doc1'
                                             ,'year':2008
                                             ,'state':'vdsraw_chain_lengths'
                                             ,'value':[1111,23,19,22,15]})
                  setter(task
                         ,function(err,state){
                             tt.notOk(err,'should not get an error from setter')
                             delete task.value
                             getter(task
                                    ,function(err,state){
                                        tt.notOk(err,'should not get an error')
                                        tt.same(state,[1111,23,19,22,15])
                                        // now you don't
                                        task.value = null
                                        setter(task
                                               ,function(err,state){
                                                   tt.notOk(err,'should not get an error from setter')
                                                   delete task.value
                                                   getter(task
                                                          ,function(err,state){
                                                              tt.notOk(err,'should not get an error from setter')
                                                              tt.notOk(state,'should not have state')
                                                              tt.end()
                                                              return null
                                                          })
                                                   return null
                                               })
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'should create a clean, new document if needed'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'doc5'
                                             ,'year':2008
                                             ,'state':'look_at_the_birdie'})

                  getter(task
                         ,function(err,state){
                             //console.log(err)
                             tt.ok(err,'should get error from get, doc is not there')
                             // now set that value
                             task.value='poof'
                             setter(task
                                    ,function(err){
                                        tt.notOk(err,'should.not.exist(err)---created doc')
                                        delete task.value
                                        getter(task
                                               ,function(err,state){
                                                   tt.notOk(err,'should.not.exist(err)')
                                                   tt.ok(state,'should get state now')
                                                   tt.is(state,'poof')
                                                   tt.end()
                                                   return null
                                               })
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'should not need year to be set'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'docnoyear'
                                             ,'state':'look_at_the_birdie'})

                  getter(task
                         ,function(err,state){
                             tt.ok(err,'should get error from get, doc is not there')
                             // now set that value
                             task.value='tweet'
                             setter(task
                                    ,function(err){
                                        tt.notOk(err,'should.not.exist(err)')
                                        delete task.value
                                        getter(task
                                               ,function(err,state){
                                                   tt.notOk(err,'should.not.exist(err)')
                                                   tt.ok(state,'should get state now')
                                                   tt.is(state,'tweet')
                                                   tt.end()
                                                   return null
                                               })
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'do not use callback, expect a promise'
              ,function(tt){
                  //tt.plan(3)
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'docnoyear'
                                             ,'year':'haveyear'
                                             ,'state':'look_at_the_birdie'})
                  // set that value
                  task.value='tweet'
                  const set_req =  setter(task)
                  set_req
                      .then( ()=>{
                          // value should be set, now check it
                          delete task.value
                          getter(task
                                 ,function(err,state){
                                     tt.notOk(err,'should.not.exist(err)')
                                     tt.ok(state,'should get state now')
                                     tt.is(state,'tweet')
                                     tt.end()
                                     return null
                                 })
                          return null
                      })
                      .catch( (e)=>{
                          tt.fail('should not error out')
                      })
              })

      })
}

config_okay(config_file)
    .then(function(c){
        if(!c.couchdb.db){ throw new Error('need valid db defined in test.config.json')}
        config.couchdb = c.couchdb
        return utils.create_tempdb(config)
    })
    .then(()=>{
        return populate_db(config)
    })
    .then( r => {
        docs.push ({doc:{ '_id':r.body.id
                          ,'_rev':r.body.rev}})
    })
    .then( function (){
        return tap.test('test setting state',testing)
    })
    .then(function(){
        tap.end()
        return utils.teardown(config)
    })
    .catch(function(e){
        throw e
    })
<commit_msg>minor additional test that did not fail<commit_after>/* global require console process describe it */

const tap = require('tap')

const setter = require('../couch_set_state')
const getter = require('couch_check_state')

const superagent = require('superagent')

const path    = require('path')
const rootdir = path.normalize(__dirname)
const config_okay = require('config_okay')
const config_file = rootdir+'/../test.config.json'
const config={}

const utils = require('./utils.js')

tap.plan(1)

const date = new Date()
const inprocess_string = date.toISOString()+' inprocess'

const docs = []

function populate_db(config){

    const mydocs = {'docs':[{'_id':'doc1'
                             ,foo:'bar'}
                            ,{'_id':'doc2'
                              ,'baz':'bat'}

                            ,{"_id": "801245",
                              "2006": {
                              },
                              "2007": {
                                  "vdsimputed": "todo",
                                  "wim_neigbors_ready": {
                                      "wim_id": 77,
                                      "distance": 14788,
                                      "direction": "east"
                                  },
                                  "wim_neigbors": {
                                      "wim_id": 77,
                                      "distance": 14788,
                                      "direction": "east"
                                  },
                                  "truckimputed": "2013-04-06T04:45:11.832Z finish",
                                  "paired_wim": null,
                                  "vdsdata": "0",
                                  "rawdata": "1",
                                  "row": 1,
                                  "vdsraw_chain_lengths": [2,2,2,2,2],
                                  "vdsraw_max_iterations": 0,
                                  "occupancy_averaged": 1,
                                  "truckimputation_chain_lengths": [
                                      145,
                                      147,
                                      144,
                                      139,
                                      143
                                  ],
                                  "truckimputation_max_iterations": 0
                              },
                              "2008": {
                                  "vdsimputed": "todo",
                                  "wim_neigbors_ready": {
                                      "wim_id": 77,
                                      "distance": 14788,
                                      "direction": "east"
                                  },
                                  "wim_neigbors": {
                                      "wim_id": 77,
                                      "distance": 14788,
    "direction": "east"
                                  },
                                  "vdsdata": "0",
                                  "rawdata": "1",
                                  "row": 1,
                                  "truckimputed": "2012-05-21 inprocess",
                                  "vdsraw_chain_lengths": [2,2,2,2,2],
                                  "vdsraw_max_iterations": 0
                              }}

                           ]}
    const cdb =
        [config.couchdb.host+':'+config.couchdb.port
        ,config.couchdb.db].join('/')

    return superagent.post(cdb+'/_bulk_docs')
        .type('json')
        .send(mydocs)

}

function testing (t){
    t.plan(7)
    return t.test(
        'should set chain lengths state for doc1, 2007'
        ,function(tt){
          var task = Object.assign({}
                                   ,config.couchdb
                                   ,{'doc':'801245'
                                     ,'year':2008
                                     ,'state':'truckimputed'
                                     ,'value':inprocess_string
                                    })

          setter(task
                 ,function(err,state){
                     tt.notOk(err,'should not get an error')
                     delete task.value
                     getter(task
                            ,function(errr,state){
                                tt.notOk(errr,'should not get an error')
                                tt.is(state,inprocess_string)
                                tt.end()
                                return null
                            })
                     return null
                  })
      }).then(function(t){
          return t.test(
              'should set inprocess string'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'doc1'
                                             ,'year':2008
                                             ,'state':'vdsraw_chain_lengths'
                                             ,'value':[11,23,19,22,15]})
                  setter(task
                         ,function(err,state){
                             tt.notOk(err,'should not get an error from setter')
                             delete task.value
                             getter(task
                                    ,function(err,state){
                                        tt.notOk(err,'should not get error')
                                        tt.ok(state.length)
                                        tt.is(state.length,5,'length of 5')
                                        tt.same(state,[11,23,19,22,15])
                                        tt.end()
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'should remove entirely if variable is defined but null'
              ,function(tt){
                  // now you see it
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'doc1'
                                             ,'year':2008
                                             ,'state':'vdsraw_chain_lengths'
                                             ,'value':[1111,23,19,22,15]})
                  setter(task
                         ,function(err,state){
                             tt.notOk(err,'should not get an error from setter')
                             delete task.value
                             getter(task
                                    ,function(err,state){
                                        tt.notOk(err,'should not get an error')
                                        tt.same(state,[1111,23,19,22,15])
                                        // now you don't
                                        task.value = null
                                        setter(task
                                               ,function(err,state){
                                                   tt.notOk(err,'should not get an error from setter')
                                                   delete task.value
                                                   getter(task
                                                          ,function(err,state){
                                                              tt.notOk(err,'should not get an error from setter')
                                                              tt.notOk(state,'should not have state')
                                                              tt.end()
                                                              return null
                                                          })
                                                   return null
                                               })
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'should create a clean, new document if needed'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'doc5'
                                             ,'year':2008
                                             ,'state':'look_at_the_birdie'})

                  getter(task
                         ,function(err,state){
                             //console.log(err)
                             tt.ok(err,'should get error from get, doc is not there')
                             // now set that value
                             task.value='poof'
                             setter(task
                                    ,function(err){
                                        tt.notOk(err,'should.not.exist(err)---created doc')
                                        delete task.value
                                        getter(task
                                               ,function(err,state){
                                                   tt.notOk(err,'should.not.exist(err)')
                                                   tt.ok(state,'should get state now')
                                                   tt.is(state,'poof')
                                                   tt.end()
                                                   return null
                                               })
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'should not need year to be set'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'docnoyear'
                                             ,'state':'look_at_the_birdie'})

                  getter(task
                         ,function(err,state){
                             tt.ok(err,'should get error from get, doc is not there')
                             // now set that value
                             task.value='tweet'
                             setter(task
                                    ,function(err){
                                        tt.notOk(err,'should.not.exist(err)')
                                        delete task.value
                                        getter(task
                                               ,function(err,state){
                                                   tt.notOk(err,'should.not.exist(err)')
                                                   tt.ok(state,'should get state now')
                                                   tt.is(state,'tweet')
                                                   tt.end()
                                                   return null
                                               })
                                        return null
                                    })
                             return null
                         })
                  return null
              })
      }).then(function(t){
          return t.test(
              'do not use callback, expect a promise'
              ,function(tt){
                  //tt.plan(3)
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'docnoyear'
                                             ,'year':'haveyear'
                                             ,'state':'look_at_the_birdie'})
                  // set that value
                  task.value='tweet'
                  const set_req =  setter(task)
                  set_req
                      .then( ()=>{
                          // value should be set, now check it
                          delete task.value
                          getter(task
                                 ,function(err,state){
                                     tt.notOk(err,'should.not.exist(err)')
                                     tt.ok(state,'should get state now')
                                     tt.is(state,'tweet')
                                     tt.end()
                                     return null
                                 })
                          return null
                      })
                      .catch( (e)=>{
                          tt.fail('should not error out')
                      })
              })

      }).then(function(t){
          return t.test(
              'can change setting without hitting a conflict error in promise case'
              ,function(tt){
                  var task = Object.assign({}
                                           ,config.couchdb
                                           ,{'doc':'docnoyear'
                                             ,'year':'haveyear'
                                             ,'state':'look_at_the_birdie'})
                  // set that value to something different now
                  task.value='fly away'
                  const set_req =  setter(task)

                  set_req
                      .then( ()=>{
                          // value should be set, now check it
                          tt.pass('did not throw')
                          tt.end()
                          return null
                      })
                      .catch( (e)=>{
                          tt.fail('should not error out')
                      })
              })

      })
}

config_okay(config_file)
    .then(function(c){
        if(!c.couchdb.db){ throw new Error('need valid db defined in test.config.json')}
        config.couchdb = c.couchdb
        return utils.create_tempdb(config)
    })
    .then(()=>{
        return populate_db(config)
    })
    .then( r => {
        docs.push ({doc:{ '_id':r.body.id
                          ,'_rev':r.body.rev}})
    })
    .then( function (){
        return tap.test('test setting state',testing)
    })
    .then(function(){
        tap.end()
        return utils.teardown(config)
    })
    .catch(function(e){
        throw e
    })
<|endoftext|>


<commit_before>var d3Chart = {};

/**
 * Create the D3 chart object
 */
d3Chart.create = function (el, props, state) {
  var svg = d3.select(el).append('svg')
      .attr('class', 'd3')
      .attr('width', props.width)
      .attr('height', props.height);

  // Add a group for the map
  svg.append('g')
      .attr('class', 'd3-map');

  // Add a group for the points
  svg.append('g')
      .attr('class', 'd3-points');

  this._drawMap(el, state.places, state.settings, state.data);
  // this._drawPoints(el, state.places, state.settings, state.data);

  // this.update(el, state);
};

/**
 * Update the D3 chart when the React props change
 */
d3Chart.update = function (el, state) {
  const mapPath = d3.select('path.states');
  mapPath.remove();
  this._drawMap(el, state.places, state.settings, state.data);
};

d3Chart.destroy = function (el) {
  // Clean up chart
};

d3Chart._drawMap = function (el, places, settings, data) {
  var projection = d3.geo.mercator()
      .scale(settings.mapScale)
      .center([settings.mapX, settings.mapY])
      .precision(0.1);
  var path = d3.geo.path()
    .projection(projection);

  var g = d3.select(el).selectAll('.d3-map');

  d3.json('/data/counties.json', function (error, counties) {
    g.append('path')
    .datum(topojson.feature(counties, counties.objects.counties))
    .attr('d', path)
    .attr('class', 'states');
  });

  var point = g.selectAll('.d3-points')
    .data(places, function (d) { return d.id; });

  point.enter().append('circle')
    .attr('cx', function (d) {
      const latLong = [d.long, d.lat];
      return projection(latLong)[0];
    })
    .attr('cy', function (d) {
      const latLong = [d.long, d.lat];
      return projection(latLong)[1];
    })
    .attr('r', '8px')
    .attr('fill', 'red');
};

export default d3Chart;
<commit_msg>Fixing data point drawing<commit_after>var d3Chart = {};

/**
 * Create the D3 chart object
 */
d3Chart.create = function (el, props, state) {
  var svg = d3.select(el).append('svg')
      .attr('class', 'd3')
      .attr('width', props.width)
      .attr('height', props.height);

  // Add a group for the map
  svg.append('g')
      .attr('class', 'd3-map');

  // Add a group for the points
  svg.append('g')
      .attr('class', 'd3-points');

  this._drawMap(el, state.places, state.settings, state.data);
  // this._drawPoints(el, state.places, state.settings, state.data);

  // this.update(el, state);
};

/**
 * Update the D3 chart when the React props change
 */
d3Chart.update = function (el, state) {
  const mapPath = d3.select('path.states');
  mapPath.remove();
  this._drawMap(el, state.places, state.settings, state.data);
};

d3Chart.destroy = function (el) {
  // Clean up chart
};

d3Chart._drawMap = function (el, places, settings, data) {

  // Set up map projection
  var projection = d3.geo.mercator()
      .scale(settings.mapScale)
      .center([settings.mapX, settings.mapY])
      .precision(0.1);

  // Draw county boundaries
  var path = d3.geo.path().projection(projection);
  var mapG = d3.select(el).selectAll('.d3-map');
  d3.json('/data/counties.json', function (error, counties) {
    mapG.append('path')
    .datum(topojson.feature(counties, counties.objects.counties))
    .attr('d', path)
    .attr('class', 'states');
  });

  // Draw points at each location
  var pointG = d3.select(el).selectAll('.d3-points');
  var point = pointG.selectAll('dot')
      .data(places)
    .enter().append('circle')
      .attr('cx', function (d) { return projection([d.long, d.lat])[0]; })
      .attr('cy', function (d) { return projection([d.long, d.lat])[1]; })
      .attr('r', '8px')
      .attr('fill', 'red');
};

export default d3Chart;
<|endoftext|>


<commit_before>const assign = require('xtend/mutable')
const Patch = require('./patch')

const mutationDefaults = {returnIds: true}

function DataClient(client) {
  this.client = client
}

assign(DataClient.prototype, {
  fetch(query, params) {
    return this.dataRequest('fetch', 'q', {query, params}).then(res => res.result || [])
  },

  getDocument(id) {
    return this.fetch('*[.$id == %id]', {id}).then(results => results[0])
  },

  create(doc) {
    return this._create(doc, 'create')
  },

  createIfNotExists(doc) {
    return this._create(doc, 'createIfNotExists')
  },

  createOrReplace(doc) {
    return this._create(doc, 'createOrReplace')
  },

  patch(documentId, operations) {
    return new Patch(this, documentId, operations)
  },

  delete(id) {
    return this.dataRequest('delete', 'm', {delete: {id: id}})
  },

  mutate(mutations) {
    return this.dataRequest('mutate', 'm', mutations)
  },

  dataRequest(method, endpoint, body) {
    const query = endpoint === 'm' && mutationDefaults
    return this.client.emit('request', method, body).then(() => {
      const dataset = checkDataset(this.client.clientConfig)
      return this.client.request({
        method: 'POST',
        uri: `/data/${endpoint}/${dataset}`,
        json: body,
        query: query
      })
    })
  },

  _create(doc, op) {
    const dataset = checkDataset(this.clientConfig)
    const mutation = {}
    mutation[op] = assign({}, doc, {$id: doc.$id || `${dataset}:`})
    return this.dataRequest(op, 'm', mutation)
  }
})

function checkDataset(config) {
  if (!config.dataset) {
    throw new Error('`dataset` must be provided to perform queries')
  }

  return config.dataset
}

module.exports = DataClient
<commit_msg>Fix incorrect reference in create handler<commit_after>const assign = require('xtend/mutable')
const Patch = require('./patch')

const mutationDefaults = {returnIds: true}

function DataClient(client) {
  this.client = client
}

assign(DataClient.prototype, {
  fetch(query, params) {
    return this.dataRequest('fetch', 'q', {query, params}).then(res => res.result || [])
  },

  getDocument(id) {
    return this.fetch('*[.$id == %id]', {id}).then(results => results[0])
  },

  create(doc) {
    return this._create(doc, 'create')
  },

  createIfNotExists(doc) {
    return this._create(doc, 'createIfNotExists')
  },

  createOrReplace(doc) {
    return this._create(doc, 'createOrReplace')
  },

  patch(documentId, operations) {
    return new Patch(this, documentId, operations)
  },

  delete(id) {
    return this.dataRequest('delete', 'm', {delete: {id: id}})
  },

  mutate(mutations) {
    return this.dataRequest('mutate', 'm', mutations)
  },

  dataRequest(method, endpoint, body) {
    const query = endpoint === 'm' && mutationDefaults
    return this.client.emit('request', method, body).then(() => {
      const dataset = checkDataset(this.client.clientConfig)
      return this.client.request({
        method: 'POST',
        uri: `/data/${endpoint}/${dataset}`,
        json: body,
        query: query
      })
    })
  },

  _create(doc, op) {
    const dataset = checkDataset(this.client.clientConfig)
    const mutation = {}
    mutation[op] = assign({}, doc, {$id: doc.$id || `${dataset}:`})
    return this.dataRequest(op, 'm', mutation)
  }
})

function checkDataset(config) {
  if (!config.dataset) {
    throw new Error('`dataset` must be provided to perform queries')
  }

  return config.dataset
}

module.exports = DataClient
<|endoftext|>


<commit_before>import isNode from '../helpers/isNode'

const __CACHE__ = {}
const _cache = ({ttl, original} = {}) => {
  return (...args) => {
    const key = JSON.stringify(args)
    const now = +new Date()
    if (__CACHE__[key] === undefined) {
      __CACHE__[key] = {createdAt: now, returns: original.apply(original, args)}
    }

    if ((now - __CACHE__[key].createdAt) > ttl) {
      delete __CACHE__[key]
    }

    // Dump cache to console if setting to truthy '__dumpCache__' key in localStorage
    window.localStorage.__dumpCache__ && !!JSON.parse(window.localStorage.__dumpCache__) &&
    (console.clear() || console.log(__CACHE__))

    return __CACHE__[key] !== undefined ? __CACHE__[key].returns
                                        : original.apply(original, args)
  }
}

export default ({ttl = 500} = {}) => {
  return (Target, name, descriptor) => {
    return isNode ? descriptor
                  : Object.assign({}, descriptor, {value: _cache({ttl, original: descriptor.value})})
  }
}
<commit_msg>refactor(cache): improve the key cache using md5, target name and method name<commit_after>import isNode from '../helpers/isNode'
import md5 from '../helpers/md5'

const __CACHE__ = {}
const _cache = ({ttl, Target, name, original} = {}) => {
  return (...args) => {
    const key = `${Target.constructor.name}::${name}::${md5.hash(JSON.stringify(args))}`
    const now = +new Date()
    if (__CACHE__[key] === undefined) {
      __CACHE__[key] = {createdAt: now, returns: original.apply(original, args)}
    }

    if ((now - __CACHE__[key].createdAt) > ttl) {
      delete __CACHE__[key]
    }

    // Dump cache to console if setting to truthy '__dumpCache__' key in localStorage
    window.localStorage.__dumpCache__ && !!JSON.parse(window.localStorage.__dumpCache__) &&
    (console.clear() || console.log(__CACHE__))

    return __CACHE__[key] !== undefined ? __CACHE__[key].returns
                                        : original.apply(original, args)
  }
}

export default ({ttl = 500} = {}) => {
  return (Target, name, descriptor) => {
    return isNode ? descriptor
                  : Object.assign({}, descriptor, {value: _cache({ttl, Target, name, original: descriptor.value})})
  }
}
<|endoftext|>


<commit_before>require('buster').spec.expose();
var expect = require('buster').expect;
var assertSame = require('./helper/stream-helper').assertSame;

var transform = require('../lib/combinators/transform');
var observe = require('../lib/combinators/observe').observe;
var delay = require('../lib/combinators/timed').delay;
var reduce = require('../lib/combinators/reduce').reduce;
var Stream = require('../lib/Stream');

var map = transform.map;
var ap = transform.ap;
var flatMap = transform.flatMap;
var scan = transform.scan;
var tap = transform.tap;
var constant = transform.constant;

var sentinel = { value: 'sentinel' };
var other = { value: 'other' };

describe('map', function() {

	it('should satisfy identity', function() {
		// u.map(function(a) { return a; })) ~= u
		var u = Stream.of(sentinel);
		return assertSame(map(function(x) { return x; }, u), u);
	});

	it('should satisfy composition', function() {
		//u.map(function(x) { return f(g(x)); }) ~= u.map(g).map(f)
		function f(x) { return x + 'f'; }
		function g(x) { return x + 'g'; }

		var u = Stream.of('e');

		return assertSame(
			map(function(x) { return f(g(x)); }, u),
			map(f, map(g, u))
		);
	});

});

describe('constant', function() {

	it('should satisfy identity', function() {
		// u.constant(x) ~= u.map(function(){return x;})
		var u = Stream.of('e');
		var x = 1;
		function f() { return x; }
		return assertSame(
			constant(x, u),
			map(f, u)
		);
	});

});

describe('tap', function() {

	it('should not transform stream items', function() {
		return tap(function() {
			return other;
		}, Stream.of(sentinel)).observe(function(x) {
			expect(x).toBe(sentinel);
		});
	});

});

describe('flatMap', function() {

	it('should satisfy associativity', function() {
		// m.flatMap(f).flatMap(g) ~= m.flatMap(function(x) { return f(x).flatMap(g); })
		function f(x) { return Stream.of(x + 'f'); }
		function g(x) { return Stream.of(x + 'g'); }

		var m = Stream.of('m');

		return assertSame(
			flatMap(function(x) { return flatMap(g, f(x)); }, m),
			flatMap(g, flatMap(f, m))
		);
	});

	it('should preserve time order', function() {
		var s = flatMap(function(x) {
			return delay(x, Stream.of(x));
		}, Stream.from([20, 10]));

		return reduce(function(a, x) {
			return a.concat(x);
		}, [], s)
			.then(function(a) {
				expect(a).toEqual([10, 20]);
			});
	});
});

describe('ap', function() {

	it('should satisfy identity', function() {
		// P.of(function(a) { return a; }).ap(v) ~= v
		var v = Stream.of(sentinel);
		return assertSame(Stream.of(function(x) { return x; }).ap(v), v);
	});

	it('should satisfy composition', function() {
		//P.of(function(f) { return function(g) { return function(x) { return f(g(x))}; }; }).ap(u).ap(v
		var u = Stream.of(function(x) { return 'u' + x; });
		var v = Stream.of(function(x) { return 'v' + x; });
		var w = Stream.of('w');

		return assertSame(
			Stream.of(function(f) {
				return function(g) {
					return function(x) {
						return f(g(x));
					};
				};
			}).ap(u).ap(v).ap(w),
			u.ap(v.ap(w))
		);
	});

	it('should satisfy homomorphism', function() {
		//P.of(f).ap(P.of(x)) ~= P.of(f(x)) (homomorphism)
		function f(x) { return x + 'f'; }
		var x = 'x';
		return assertSame(Stream.of(f).ap(Stream.of(x)), Stream.of(f(x)));
	});

	it('should satisfy interchange', function() {
		// u.ap(a.of(y)) ~= a.of(function(f) { return f(y); }).ap(u)
		function f(x) { return x + 'f'; }

		var u = Stream.of(f);
		var y = 'y';

		return assertSame(
			u.ap(Stream.of(y)),
			Stream.of(function(f) { return f(y); }).ap(u)
		);
	});

});

describe('scan', function() {
	it('should yield combined values', function() {
		var i = 0;
		var expected = ['a', 'b', 'c', 'd'];
		return scan(function(arr, x) {
			return arr.concat(x);
		}, expected.slice(0, 1), Stream.from(expected.slice(1))).observe(function(arr) {
			++i;
			expect(arr).toEqual(expected.slice(0, i));
		});
	});

	it('should dispose', function() {
		var dispose = this.spy();
		var end = new Stream.End(1, 0, sentinel);
		var source = new Stream(function(x) {
			return x;
		}, new Stream.Yield(0, 0, end), void 0, dispose);

		var s = scan(function(z, x) { return x; }, 0, source);
		return observe(function() {}, s).then(function() {
			expect(dispose).toHaveBeenCalledWith(1, 0, sentinel);
		});
	});
});

<commit_msg>Simplify scan unit tests<commit_after>require('buster').spec.expose();
var expect = require('buster').expect;
var assertSame = require('./helper/stream-helper').assertSame;

var transform = require('../lib/combinators/transform');
var observe = require('../lib/combinators/observe').observe;
var delay = require('../lib/combinators/timed').delay;
var reduce = require('../lib/combinators/reduce').reduce;
var Stream = require('../lib/Stream');

var map = transform.map;
var ap = transform.ap;
var flatMap = transform.flatMap;
var scan = transform.scan;
var tap = transform.tap;
var constant = transform.constant;

var sentinel = { value: 'sentinel' };
var other = { value: 'other' };

describe('map', function() {

	it('should satisfy identity', function() {
		// u.map(function(a) { return a; })) ~= u
		var u = Stream.of(sentinel);
		return assertSame(map(function(x) { return x; }, u), u);
	});

	it('should satisfy composition', function() {
		//u.map(function(x) { return f(g(x)); }) ~= u.map(g).map(f)
		function f(x) { return x + 'f'; }
		function g(x) { return x + 'g'; }

		var u = Stream.of('e');

		return assertSame(
			map(function(x) { return f(g(x)); }, u),
			map(f, map(g, u))
		);
	});

});

describe('constant', function() {

	it('should satisfy identity', function() {
		// u.constant(x) ~= u.map(function(){return x;})
		var u = Stream.of('e');
		var x = 1;
		function f() { return x; }
		return assertSame(
			constant(x, u),
			map(f, u)
		);
	});

});

describe('tap', function() {

	it('should not transform stream items', function() {
		return tap(function() {
			return other;
		}, Stream.of(sentinel)).observe(function(x) {
			expect(x).toBe(sentinel);
		});
	});

});

describe('flatMap', function() {

	it('should satisfy associativity', function() {
		// m.flatMap(f).flatMap(g) ~= m.flatMap(function(x) { return f(x).flatMap(g); })
		function f(x) { return Stream.of(x + 'f'); }
		function g(x) { return Stream.of(x + 'g'); }

		var m = Stream.of('m');

		return assertSame(
			flatMap(function(x) { return flatMap(g, f(x)); }, m),
			flatMap(g, flatMap(f, m))
		);
	});

	it('should preserve time order', function() {
		var s = flatMap(function(x) {
			return delay(x, Stream.of(x));
		}, Stream.from([20, 10]));

		return reduce(function(a, x) {
			return a.concat(x);
		}, [], s)
			.then(function(a) {
				expect(a).toEqual([10, 20]);
			});
	});
});

describe('ap', function() {

	it('should satisfy identity', function() {
		// P.of(function(a) { return a; }).ap(v) ~= v
		var v = Stream.of(sentinel);
		return assertSame(Stream.of(function(x) { return x; }).ap(v), v);
	});

	it('should satisfy composition', function() {
		//P.of(function(f) { return function(g) { return function(x) { return f(g(x))}; }; }).ap(u).ap(v
		var u = Stream.of(function(x) { return 'u' + x; });
		var v = Stream.of(function(x) { return 'v' + x; });
		var w = Stream.of('w');

		return assertSame(
			Stream.of(function(f) {
				return function(g) {
					return function(x) {
						return f(g(x));
					};
				};
			}).ap(u).ap(v).ap(w),
			u.ap(v.ap(w))
		);
	});

	it('should satisfy homomorphism', function() {
		//P.of(f).ap(P.of(x)) ~= P.of(f(x)) (homomorphism)
		function f(x) { return x + 'f'; }
		var x = 'x';
		return assertSame(Stream.of(f).ap(Stream.of(x)), Stream.of(f(x)));
	});

	it('should satisfy interchange', function() {
		// u.ap(a.of(y)) ~= a.of(function(f) { return f(y); }).ap(u)
		function f(x) { return x + 'f'; }

		var u = Stream.of(f);
		var y = 'y';

		return assertSame(
			u.ap(Stream.of(y)),
			Stream.of(function(f) { return f(y); }).ap(u)
		);
	});

});

describe('scan', function() {
	it('should yield combined values', function() {
		var i = 0;
		var items = 'abcd';

		var stream = scan(function (s, x) {
			return s + x;
		}, items[0], Stream.from(items.slice(1)));

		return observe(function(s) {
			++i;
			expect(s).toEqual(items.slice(0, i));
		}, stream);
	});

	it('should dispose', function() {
		var dispose = this.spy();

		var items = new Stream.Yield(0, 0, new Stream.End(1, 0, sentinel));

		var stream = new Stream(function(x) {
			return x;
		}, items, void 0, dispose);

		var s = scan(function(z, x) { return x; }, 0, stream);
		return observe(function() {}, s).then(function() {
			expect(dispose).toHaveBeenCalledWith(1, 0, sentinel);
		});
	});
});

<|endoftext|>


<commit_before>/* global document, Element */

import test from 'ava'

import { $, $$, find, findAll, children } from '../lib/traversal.js'
import { CathedralError } from '../lib/cathedral-error.js'

test.beforeEach(() => { document.body.innerHTML = '' })

/**
 * $
 */

test('wrapper function $ is specified', t => {
  t.is(typeof $, 'function')
})

test('$ retrieves a single dom item', t => {
  document.body.innerHTML = `

  `

  t.truthy($('.part-of-many') instanceof Element)
  t.is($('.part-of-many').outerHTML, '

')
})

test('$ retrieves sub results based on find, if a context is given', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')
  const child = $('#child')

  // check $ context search based on find
  t.truthy($('#child', '#parent') === child)
  t.truthy($('#child', parent) === child)
})

test('$ retrieves sub results based on find, if a context is given', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')
  const child = $('#child')

  // check $ context search based on find
  t.truthy($('#child', '#parent') === child)
  t.truthy($('#child', parent) === child)
})

test('$ creates and returns an HTML Element, if an HTML fragment string is given', t => {
  const htmlFragment = '
Fubar
'
  const newElement = $(htmlFragment)

  t.is(newElement.outerHTML, htmlFragment)
})

test('$ returns only first node of given fragment string', t => {
  const htmlFragment = `

Fubar

Fubar

  `
  const newElement = $(htmlFragment)

  t.is(newElement.outerHTML, '
Fubar
')
})

test('$ works for nested html', t => {
  const htmlFragment = `<div>Fubar<div>Falala</div></div>`
  const newElement = $(htmlFragment)

  t.is(newElement.outerHTML, htmlFragment)
})

/**
 * $$
 */

test('wrapper function $$ is specified', t => {
  t.is(typeof $$, 'function')
})

test('$$ retrieves an array of dom elements', t => {
  document.body.innerHTML = `

  `

  t.truthy($$('.part-of-many') instanceof Array)
  t.is($$('.part-of-many').length, 2)
})

test('$$ retrieves sub results based on findAll, if a context is given', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')

  // check $$ context search based on findAll
  t.is($$('.child', '#parent').length, 3)
  t.is($$('.child', parent).length, 3)
})
/**
 * find
 */

test('find function is specified', t => {
  t.is(typeof find, 'function')
})

test('find function is specified', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')
  const child = $('#child')

  t.truthy(find(parent, '#child') === child)
})

/**
 * findAll
 */

test('findAll function is specified', t => {
  t.is(typeof findAll, 'function')
})

test('findAll function is specified', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')

  t.truthy(findAll(parent, '.child') instanceof Array)
  t.is(findAll(parent, '.child').length, 3)
})

/**
 * children
 */
test('children function is specified', t => {
  t.is(typeof children, 'function')
})

test('children returns an array of child elements if given', t => {
  document.body.innerHTML = `

  `

  const parent = $('.parent')
  t.is(children(parent).length, 3)
})

test('children with a selector passed returns only child elements that match the given selector', t => {
  document.body.innerHTML = `

  `

  const parent = $('.parent')
  t.is(children(parent, '.active').length, 2)
})
<commit_msg>removed unused dependency in tests<commit_after>/* global document, Element */

import test from 'ava'

import { $, $$, find, findAll, children } from '../lib/traversal.js'

test.beforeEach(() => { document.body.innerHTML = '' })

/**
 * $
 */

test('wrapper function $ is specified', t => {
  t.is(typeof $, 'function')
})

test('$ retrieves a single dom item', t => {
  document.body.innerHTML = `

  `

  t.truthy($('.part-of-many') instanceof Element)
  t.is($('.part-of-many').outerHTML, '

')
})

test('$ retrieves sub results based on find, if a context is given', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')
  const child = $('#child')

  // check $ context search based on find
  t.truthy($('#child', '#parent') === child)
  t.truthy($('#child', parent) === child)
})

test('$ retrieves sub results based on find, if a context is given', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')
  const child = $('#child')

  // check $ context search based on find
  t.truthy($('#child', '#parent') === child)
  t.truthy($('#child', parent) === child)
})

test('$ creates and returns an HTML Element, if an HTML fragment string is given', t => {
  const htmlFragment = '
Fubar
'
  const newElement = $(htmlFragment)

  t.is(newElement.outerHTML, htmlFragment)
})

test('$ returns only first node of given fragment string', t => {
  const htmlFragment = `

Fubar

Fubar

  `
  const newElement = $(htmlFragment)

  t.is(newElement.outerHTML, '
Fubar
')
})

test('$ works for nested html', t => {
  const htmlFragment = `<div>Fubar<div>Falala</div></div>`
  const newElement = $(htmlFragment)

  t.is(newElement.outerHTML, htmlFragment)
})

/**
 * $$
 */

test('wrapper function $$ is specified', t => {
  t.is(typeof $$, 'function')
})

test('$$ retrieves an array of dom elements', t => {
  document.body.innerHTML = `

  `

  t.truthy($$('.part-of-many') instanceof Array)
  t.is($$('.part-of-many').length, 2)
})

test('$$ retrieves sub results based on findAll, if a context is given', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')

  // check $$ context search based on findAll
  t.is($$('.child', '#parent').length, 3)
  t.is($$('.child', parent).length, 3)
})
/**
 * find
 */

test('find function is specified', t => {
  t.is(typeof find, 'function')
})

test('find function is specified', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')
  const child = $('#child')

  t.truthy(find(parent, '#child') === child)
})

/**
 * findAll
 */

test('findAll function is specified', t => {
  t.is(typeof findAll, 'function')
})

test('findAll function is specified', t => {
  document.body.innerHTML = `

  `

  const parent = $('#parent')

  t.truthy(findAll(parent, '.child') instanceof Array)
  t.is(findAll(parent, '.child').length, 3)
})

/**
 * children
 */
test('children function is specified', t => {
  t.is(typeof children, 'function')
})

test('children returns an array of child elements if given', t => {
  document.body.innerHTML = `

  `

  const parent = $('.parent')
  t.is(children(parent).length, 3)
})

test('children with a selector passed returns only child elements that match the given selector', t => {
  document.body.innerHTML = `

  `

  const parent = $('.parent')
  t.is(children(parent, '.active').length, 2)
})
<|endoftext|>


<commit_before>import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { spy } from 'sinon';

chai.use(chaiAsPromised);
const { assert } = chai;
import Shepherd from '../../src/js/shepherd.js';
import { Step } from '../../src/js/step.js';
// since importing non UMD, needs assignment
window.Shepherd = Shepherd;

describe('Step', () => {
  describe('Shepherd.Step()', () => {
    const instance = new Shepherd.Tour({
      defaults: {
        classes: 'shepherd-theme-arrows',
        scrollTo: true
      }
    });

    const testStep = instance.addStep('test', {
      id: 'test',
      text: 'This is a step for testing',
      classes: 'example-step-extra-class',
      buttons: [
        {
          text: 'Next',
          action: instance.next
        }
      ]
    });

    const showTestStep = instance.addStep('test2', {
      id: 'test2',
      text: 'Another Step'
    });

    const beforeShowPromise = new Promise((resolve) => {
      return setTimeout(1000, resolve('beforeShowPromise worked!'));
    });

    const beforeShowPromiseTestStep = instance.addStep('test3', {
      id: 'test3',
      text: 'Before Show Promise Step',
      beforeShowPromise() {
        return beforeShowPromise;
      }
    });

    after(() => {
      instance.cancel();
    });

    it('has all the correct properties', () => {
      const values = ['classes', 'scrollTo', 'id', 'text', 'buttons'];
      assert.deepEqual(values, Object.keys(testStep.options));
    });

    describe('.hide()', () => {
      it('shows step evoking method, regardless of order', () => {
        instance.start();
        testStep.hide();

        assert.notEqual(document.querySelector('[data-id=test]').getAttribute('hidden'), null);
      });
    });

    describe('.show()', () => {
      it('beforeShowPromise called before `show`', () => {
        assert.eventually.equal(beforeShowPromise, 'beforeShowPromise worked!', 'beforeShowPromise is called');
        beforeShowPromiseTestStep.show();
      });

      it('shows step evoking method, regardless of order', () => {
        showTestStep.show();

        assert.equal(document.querySelector('[data-id=test2]').dataset.id, 'test2');
      });
    });
  });

  describe('bindAdvance()', () => {
    it('should trigger the advanceOn option via string', () => {
      const el = document.createElement('div');
      const event = new Event('test');
      const link = document.createElement('a');
      let advanced = false;
      link.classList.add('click-test');
      document.body.appendChild(link);

      const step = new Step({
        next: () => advanced = true
      }, {
        advanceOn: '.click-test test'
      });
      step.el = el;
      step.el.hidden = false;

      step.bindAdvance();
      link.dispatchEvent(event);

      assert.isOk(link.classList.contains('click-test'));
      assert.isOk(advanced);
    });

    it('should trigger the advanceOn option via object', () => {
      const el = document.createElement('div');
      const event = new Event('test');
      const link = document.createElement('a');
      let advanced = false;
      link.classList.add('object-test');
      document.body.appendChild(link);

      const step = new Step({
        next: () => advanced = true
      }, {
        advanceOn: { selector: '.object-test', event: 'test' }
      });
      step.el = el;
      step.el.hidden = false;

      step.bindAdvance();
      link.dispatchEvent(event);

      assert.isOk(link.classList.contains('object-test'));
      assert.isOk(advanced, 'next triggered for advanceOn');
    });

    it('should capture events attached to no selector', () => {
      const event = new Event('test');
      let advanced = false;

      const step = new Step({
        next: () => advanced = true
      }, {
        advanceOn: { event: 'test' }
      });

      step.el = document.body;
      step.el.hidden = false;

      step.bindAdvance();
      document.body.dispatchEvent(event);

      assert.isOk(advanced, 'next triggered for advanceOn');
    });

    it('it should call removeEventListener when destoryed', function(done){
      const el = document.createElement('div');
      const body = spy(document.body, 'removeEventListener');
      const step = new Step({
        next: () => true
      }, {
        advanceOn: { event: 'test' }
      });
      step.el = el;
      step.el.hidden = false;

      step.bindAdvance();
      step.trigger('destroy');
      assert.ok(body.called);
      body.restore();
      done();
    });

  });

  describe('bindButtonEvents()', () => {
    const link = document.createElement('a');
    const step = new Step();
    it('adds button events', () => {
      const event = new Event('test');
      let eventTriggered = false;

      step.bindButtonEvents({
        events: {
          test: () => eventTriggered = true
        },
        text: 'Next',
        action: () => {}
      }, link);

      link.dispatchEvent(event);
      assert.isOk(eventTriggered, 'custom button event was bound/triggered');
    });

    it('removes events once destroyed', () => {
      step.destroy();

      assert.isNotOk(link.hasAttribute('data-button-event'), 'attribute to confirm event is removed');
    });

  });

  describe('bindCancelLink()', () => {
    it('adds an event handler for the cancel button', () => {
      const event = new MouseEvent('click', {
        view: window,
        bubbles: true,
        cancelable: true
      });
      const link = document.createElement('a');
      const step = new Step();
      let cancelCalled = false;

      step.cancel = () => cancelCalled = true;
      step.bindCancelLink(link);

      link.dispatchEvent(event);
      assert.isOk(cancelCalled, 'cancel method was called from bound click event');
    });
  });

  describe('bindMethods()', () => {
    it('binds the expected methods', () => {
      const step = new Step();
      const methods = [
        '_show',
        'show',
        'hide',
        'isOpen',
        'cancel',
        'complete',
        'scrollTo',
        'destroy',
        'render'
      ];
      methods.forEach((method) => {
        assert.isOk(step[method], `${method} has been bound`);
      });
    });
  });

  describe('cancel()', () => {
    it('triggers the cancel event and tour method', () => {
      let cancelCalled = false;
      let eventTriggered = false;
      const step = new Step({
        cancel() {
          cancelCalled = true;
        }
      });
      step.on('cancel', () => eventTriggered = true);
      step.cancel();

      assert.isOk(cancelCalled, 'cancel method from tour called');
      assert.isOk(eventTriggered, 'cancel event was triggered');
    });
  });

  describe('complete()', () => {
    it('triggers the complete event and tour method', () => {
      let completeCalled = false;
      let eventTriggered = false;
      const step = new Step({
        complete() {
          completeCalled = true;
        }
      });
      step.on('complete', () => eventTriggered = true);
      step.complete();

      assert.isOk(completeCalled, 'complete method from tour called');
      assert.isOk(eventTriggered, 'complete event was triggered');
    });
  });

  describe('destroy()', () => {
    it('triggers the destroy event', () => {
      const step = new Step();
      let eventTriggered = false;
      step.on('destroy', () => eventTriggered = true);
      step.destroy();

      assert.isOk(eventTriggered, 'destroy event was triggered');
    });
  });

  describe('hide()', () => {
    const step = new Step();
    let eventTriggered = false;

    before(() => {
      document.body.setAttribute('data-shepherd-step', 1);
    });

    it('triggers the before-hide event', () => {
      step.on('before-hide', () => eventTriggered = true);
      step.hide();

      assert.isOk(eventTriggered, 'before-hide event was triggered');
    });

    it('removes the data-shepherd-step attribute', () => {
      assert.isNotOk(document.body.hasAttribute('data-shepherd-step'), 'step attribute is removed');
    });
  });

  describe('render()', () => {
    it('calls destroy if element is already set', () => {
      const step = new Step();
      let destroyCalled = false;
      step.el = document.createElement('a');
      step.destroy = () => destroyCalled = true;
      step.render();
      assert.isOk(destroyCalled, 'render method called destroy with element set');
    });
  });

  describe('scrollTo()', () => {
    it('calls the scroll native method', () => {
      const div = document.createElement('div');
      let handlerCalled = false;
      div.classList.add('scroll-test');
      document.body.appendChild(div);
      const step = new Step('test', {
        attachTo: { element: '.scroll-test', on: 'center' }
      });
      div.scrollIntoView = () => handlerCalled = true;

      step.scrollTo();
      assert.isOk(handlerCalled);
    });

    it('calls the custom handler', () => {
      let handlerAdded = false;
      const step = new Step('test', {
        scrollToHandler: () => handlerAdded = true
      });

      step.scrollTo();
      assert.isOk(handlerAdded);
    });
  });

  describe('setOptions()', () => {
    it('calls the function passed in the when option', () => {
      let whenCalled = false;
      const step = new Step('test', {
        when: {
          destroy: () => whenCalled = true
        }
      });

      step.destroy();
      assert.isOk(whenCalled);
    });

  });

  describe('getTour()', () => {
    it('returns the tour value', () => {
      const step = new Step(new Shepherd.Tour());

      assert.isOk(step.getTour() instanceof Shepherd.Tour);
    });

  });

  describe('_addContent()', () => {
    it('adds plain text to the content', () => {
      const content = document.createElement('div');
      const step = new Step();
      step.options.text = 'I am some test text.';

      step._addContent(content);

      assert.equal(step.options.text, content.querySelector('.shepherd-text p').innerHTML);
    });

    it('maps mutiple strings to paragraphs', () => {
      const content = document.createElement('div');
      const step = new Step();
      step.options.text = ['I am some test text.', 'I am even more test text.'];

      step._addContent(content);
      assert.equal(content.querySelectorAll('.shepherd-text p').length, 2);
      assert.equal(step.options.text.join(' '),
        Array.from(content.querySelectorAll('.shepherd-text p')).map((text) => text.innerHTML).join(' '));
    });

    it('applies HTML element directly to content', () => {
      const content = document.createElement('div');
      const text = document.createElement('p');
      const step = new Step();
      text.innerHTML = 'I am some test text.';
      step.options.text = text;

      step._addContent(content);

      assert.equal('I am some test text.', content.querySelector('.shepherd-text p').innerHTML);
    });

    it('applies the text from a function', () => {
      const content = document.createElement('div');
      const step = new Step();
      step.options.text = () => 'I am some test text.';

      step._addContent(content);

      assert.isOk(typeof step.options.text === 'function');
      assert.equal('I am some test text.', content.querySelector('.shepherd-text p').innerHTML);
    });
  });

  describe('_attach()', () => {
    it('uses a passed renderLocation as string', () => {
      const element = document.createElement('div');
      const testElement = document.createElement('div');
      element.classList.add('string-element');
      testElement.classList.add('test-element');
      document.body.appendChild(element);

      const step = new Step('test', {
        renderLocation: '.string-element'
      });

      step._attach(testElement);
      assert.isOk(element.querySelector('.test-element'));
    });

    it('uses a passed renderLocation as an HTML element', () => {
      const element = document.createElement('div');
      const renderLocation = document.createElement('div');
      element.classList.add('html-element');
      renderLocation.classList.add('render-element');
      document.body.appendChild(renderLocation);

      const step = new Step('test', {
        renderLocation
      });

      step._attach(element);
      assert.isOk(renderLocation.querySelector('.html-element'));
    });
  });
});
<commit_msg>add more tests for increased coverage (#230)<commit_after>import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { spy } from 'sinon';

chai.use(chaiAsPromised);
const { assert } = chai;
import Shepherd from '../../src/js/shepherd.js';
import { Step } from '../../src/js/step.js';
import { Tour } from '../../src/js/tour.js';
// since importing non UMD, needs assignment
window.Shepherd = Shepherd;

describe('Step', () => {
  describe('Shepherd.Step()', () => {
    const instance = new Shepherd.Tour({
      defaults: {
        classes: 'shepherd-theme-arrows',
        scrollTo: true
      }
    });

    const testStep = instance.addStep('test', {
      id: 'test',
      text: 'This is a step for testing',
      classes: 'example-step-extra-class',
      buttons: [
        {
          text: 'Next',
          action: instance.next
        }
      ]
    });

    const showTestStep = instance.addStep('test2', {
      buttons: [],
      id: 'test2',
      text: 'Another Step'
    });

    // Add more steps for total _setUpButtons coverage
    instance.addStep('test3', {
      buttons: {
        text: 'Next',
        action: instance.next
      },
      id: 'test3',
      text: 'Another Step part deux'
    });

    const beforeShowPromise = new Promise((resolve) => {
      return setTimeout(1000, resolve('beforeShowPromise worked!'));
    });

    const beforeShowPromiseTestStep = instance.addStep('test3', {
      id: 'test3',
      text: 'Before Show Promise Step',
      beforeShowPromise() {
        return beforeShowPromise;
      }
    });

    after(() => {
      instance.cancel();
    });

    it('has all the correct properties', () => {
      const values = ['classes', 'scrollTo', 'id', 'text', 'buttons'];
      assert.deepEqual(values, Object.keys(testStep.options));
    });

    describe('.hide()', () => {
      it('shows step evoking method, regardless of order', () => {
        instance.start();
        testStep.hide();

        assert.notEqual(document.querySelector('[data-id=test]').getAttribute('hidden'), null);
      });
    });

    describe('.show()', () => {
      it('beforeShowPromise called before `show`', () => {
        assert.eventually.equal(beforeShowPromise, 'beforeShowPromise worked!', 'beforeShowPromise is called');
        beforeShowPromiseTestStep.show();
      });

      it('shows step evoking method, regardless of order', () => {
        showTestStep.show();

        assert.equal(document.querySelector('[data-id=test2]').dataset.id, 'test2');
      });
    });
  });

  describe('bindAdvance()', () => {
    it('should trigger the advanceOn option via string', () => {
      const el = document.createElement('div');
      const event = new Event('test');
      const link = document.createElement('a');
      let advanced = false;
      link.classList.add('click-test');
      document.body.appendChild(link);

      const step = new Step({
        next: () => advanced = true
      }, {
        advanceOn: '.click-test test'
      });
      step.el = el;
      step.el.hidden = false;

      step.bindAdvance();
      link.dispatchEvent(event);

      assert.isOk(link.classList.contains('click-test'));
      assert.isOk(advanced);
    });

    it('should trigger the advanceOn option via object', () => {
      const el = document.createElement('div');
      const event = new Event('test');
      const link = document.createElement('a');
      let advanced = false;
      link.classList.add('object-test');
      document.body.appendChild(link);

      const step = new Step({
        next: () => advanced = true
      }, {
        advanceOn: { selector: '.object-test', event: 'test' }
      });
      step.el = el;
      step.el.hidden = false;

      step.bindAdvance();
      link.dispatchEvent(event);

      assert.isOk(link.classList.contains('object-test'));
      assert.isOk(advanced, 'next triggered for advanceOn');
    });

    it('should capture events attached to no selector', () => {
      const event = new Event('test');
      let advanced = false;

      const step = new Step({
        next: () => advanced = true
      }, {
        advanceOn: { event: 'test' }
      });

      step.el = document.body;
      step.el.hidden = false;

      step.bindAdvance();
      document.body.dispatchEvent(event);

      assert.isOk(advanced, 'next triggered for advanceOn');
    });

    it('it should call removeEventListener when destoryed', function(done){
      const el = document.createElement('div');
      const body = spy(document.body, 'removeEventListener');
      const step = new Step({
        next: () => true
      }, {
        advanceOn: { event: 'test' }
      });
      step.el = el;
      step.el.hidden = false;

      step.bindAdvance();
      step.trigger('destroy');
      assert.ok(body.called);
      body.restore();
      done();
    });

  });

  describe('bindButtonEvents()', () => {
    const link = document.createElement('a');
    const step = new Step(new Tour(), {});
    it('adds button events', () => {
      const event = new Event('test');
      const hover = new Event('mouseover');
      let eventTriggered = false;

      step.bindButtonEvents({
        events: {
          'mouseover': '1',
          test: () => eventTriggered = true
        },
        text: 'Next',
        action: () => {}
      }, link);

      link.dispatchEvent(event);
      link.dispatchEvent(hover);
      assert.isOk(eventTriggered, 'custom button event was bound/triggered');
    });

    it('removes events once destroyed', () => {
      step.destroy();

      assert.isNotOk(link.hasAttribute('data-button-event'), 'attribute to confirm event is removed');
    });

  });

  describe('bindCancelLink()', () => {
    it('adds an event handler for the cancel button', () => {
      const event = new MouseEvent('click', {
        view: window,
        bubbles: true,
        cancelable: true
      });
      const link = document.createElement('a');
      const step = new Step();
      let cancelCalled = false;

      step.cancel = () => cancelCalled = true;
      step.bindCancelLink(link);

      link.dispatchEvent(event);
      assert.isOk(cancelCalled, 'cancel method was called from bound click event');
    });
  });

  describe('bindMethods()', () => {
    it('binds the expected methods', () => {
      const step = new Step();
      const methods = [
        '_show',
        'show',
        'hide',
        'isOpen',
        'cancel',
        'complete',
        'scrollTo',
        'destroy',
        'render'
      ];
      methods.forEach((method) => {
        assert.isOk(step[method], `${method} has been bound`);
      });
    });
  });

  describe('cancel()', () => {
    it('triggers the cancel event and tour method', () => {
      let cancelCalled = false;
      let eventTriggered = false;
      const step = new Step({
        cancel() {
          cancelCalled = true;
        }
      });
      step.on('cancel', () => eventTriggered = true);
      step.cancel();

      assert.isOk(cancelCalled, 'cancel method from tour called');
      assert.isOk(eventTriggered, 'cancel event was triggered');
    });
  });

  describe('complete()', () => {
    it('triggers the complete event and tour method', () => {
      let completeCalled = false;
      let eventTriggered = false;
      const step = new Step({
        complete() {
          completeCalled = true;
        }
      });
      step.on('complete', () => eventTriggered = true);
      step.complete();

      assert.isOk(completeCalled, 'complete method from tour called');
      assert.isOk(eventTriggered, 'complete event was triggered');
    });
  });

  describe('destroy()', () => {
    it('triggers the destroy event', () => {
      const step = new Step();
      let eventTriggered = false;
      step.on('destroy', () => eventTriggered = true);
      step.destroy();

      assert.isOk(eventTriggered, 'destroy event was triggered');
    });
  });

  describe('hide()', () => {
    const step = new Step();
    let eventTriggered = false;

    before(() => {
      document.body.setAttribute('data-shepherd-step', 1);
    });

    it('triggers the before-hide event', () => {
      step.on('before-hide', () => eventTriggered = true);
      step.hide();

      assert.isOk(eventTriggered, 'before-hide event was triggered');
    });

    it('removes the data-shepherd-step attribute', () => {
      assert.isNotOk(document.body.hasAttribute('data-shepherd-step'), 'step attribute is removed');
    });
  });

  describe('getAttachTo()', function(){
    it('fails if element does not exist', function(){
      const step = new Step({}, {
        attachTo: { element: '.scroll-test', on: 'center' }
      });

      const { element } = step.getAttachTo();
      assert.notOk(element);
    });
  });

  describe('render()', () => {
    it('calls destroy if element is already set', () => {
      const step = new Step();
      let destroyCalled = false;
      step.el = document.createElement('a');
      step.destroy = () => destroyCalled = true;
      step.render();
      assert.isOk(destroyCalled, 'render method called destroy with element set');
    });

    it('calls bindAdvance() if advanceOn passed', () => {
      const step = new Step({
        next: () =>  true
      }, {
          advanceOn: '.click-test test'
      });
      const bindFunction = spy(step, 'bindAdvance');
      step.render();

      assert.ok(bindFunction.called);
    });
  });

  describe('scrollTo()', () => {
    it('calls the scroll native method', () => {
      const div = document.createElement('div');
      let handlerCalled = false;
      div.classList.add('scroll-test');
      document.body.appendChild(div);
      const step = new Step('test', {
        attachTo: { element: '.scroll-test', on: 'center' }
      });
      div.scrollIntoView = () => handlerCalled = true;

      step.scrollTo();
      assert.isOk(handlerCalled);
    });

    it('calls the custom handler', () => {
      let handlerAdded = false;
      const step = new Step('test', {
        scrollToHandler: () => handlerAdded = true
      });

      step.scrollTo();
      assert.isOk(handlerAdded);
    });
  });

  describe('setOptions()', () => {
    it('calls the function passed in the when option', () => {
      let whenCalled = false;
      const step = new Step('test', {
        when: {
          destroy: () => whenCalled = true
        }
      });

      step.destroy();
      assert.isOk(whenCalled);
    });

  });

  describe('getTour()', () => {
    it('returns the tour value', () => {
      const step = new Step(new Shepherd.Tour());

      assert.isOk(step.getTour() instanceof Shepherd.Tour);
    });

  });

  describe('_addContent()', () => {
    it('adds plain text to the content', () => {
      const content = document.createElement('div');
      const step = new Step();
      step.options.text = 'I am some test text.';

      step._addContent(content);

      assert.equal(step.options.text, content.querySelector('.shepherd-text p').innerHTML);
    });

    it('maps mutiple strings to paragraphs', () => {
      const content = document.createElement('div');
      const step = new Step();
      step.options.text = ['I am some test text.', 'I am even more test text.'];

      step._addContent(content);
      assert.equal(content.querySelectorAll('.shepherd-text p').length, 2);
      assert.equal(step.options.text.join(' '),
        Array.from(content.querySelectorAll('.shepherd-text p')).map((text) => text.innerHTML).join(' '));
    });

    it('applies HTML element directly to content', () => {
      const content = document.createElement('div');
      const text = document.createElement('p');
      const step = new Step();
      text.innerHTML = 'I am some test text.';
      step.options.text = text;

      step._addContent(content);

      assert.equal('I am some test text.', content.querySelector('.shepherd-text p').innerHTML);
    });

    it('applies the text from a function', () => {
      const content = document.createElement('div');
      const step = new Step();
      step.options.text = () => 'I am some test text.';

      step._addContent(content);

      assert.isOk(typeof step.options.text === 'function');
      assert.equal('I am some test text.', content.querySelector('.shepherd-text p').innerHTML);
    });
  });

  describe('_attach()', () => {
    it('uses a passed renderLocation as string', () => {
      const element = document.createElement('div');
      const testElement = document.createElement('div');
      element.classList.add('string-element');
      testElement.classList.add('test-element');
      document.body.appendChild(element);

      const step = new Step('test', {
        renderLocation: '.string-element'
      });

      step._attach(testElement);
      assert.isOk(element.querySelector('.test-element'));
    });

    it('uses a passed renderLocation as an HTML element', () => {
      const element = document.createElement('div');
      const renderLocation = document.createElement('div');
      element.classList.add('html-element');
      renderLocation.classList.add('render-element');
      document.body.appendChild(renderLocation);

      const step = new Step('test', {
        renderLocation
      });

      step._attach(element);
      assert.isOk(renderLocation.querySelector('.html-element'));
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import Snakeskin from '../core';
import { scopeMod } from '../consts/regs';
import { SYS_CONSTS } from '../consts/literals';
import { $consts, $constPositions } from '../consts/cache';

Snakeskin.addDirective(
	'const',

	{
		deferInit: true,
		group: ['const', 'inherit', 'inlineInherit']
	},

	function (command, commandLength) {
		const
			{tplName} = this;

		if (!tplName) {
			Snakeskin.Directives['global'].call(this, ...arguments);
			return;
		}

		this.startInlineDir('const');

		const
			output = command.slice(-1) === '?';

		if (output) {
			command = command.slice(0, -1);
		}

		const
			parts = command.split('=');

		if (!parts[1] || !parts[1].trim()) {
			return this.error(`invalid "${this.name}" declaration`);
		}

		let
			prop = parts[0].trim();

		if (scopeMod.test(prop)) {
			prop = this.out(prop, {unsafe: true});
		}

		const
			name = this.pasteDangerBlocks(prop).replace(/\[(['"`])(.*?)\1]/g, '.$2');

		if (!/[.\[]/.test(prop)) {
			this.consts.push(`var ${prop};`);
		}

		const
			str = `${prop} = ${this.out(parts.slice(1).join('='), {unsafe: !output})};`;

		this.text = output;
		this.append(output ? this.wrap(str) : str);

		if (this.isAdvTest()) {
			if ($consts[tplName][name]) {
				return this.error(`the constant "${name}" is already defined`);
			}

			if (this.vars[tplName][name]) {
				return this.error(`the constant "${name}" is already defined as variable`);
			}

			if (SYS_CONSTS[name]) {
				return this.error(`can't declare the constant "${name}", try another name`);
			}

			const
				parentTpl = this.parentTplName,
				start = this.i - this.startTemplateI;

			let
				parent,
				insideCallBlock = this.hasParentBlock('block', true);

			if (parentTpl) {
				parent = $consts[parentTpl][name];
			}

			if (insideCallBlock && insideCallBlock.name === 'block' && !insideCallBlock.params.args) {
				insideCallBlock = false;
			}

			$consts[tplName][name] = {
				block: Boolean(insideCallBlock || parentTpl && parent && parent.block),
				from: start - commandLength,
				needPrfx: this.needPrfx,
				output: output ? '?' : null,
				to: start
			};

			if (!insideCallBlock) {
				$constPositions[tplName] = start + 1;
			}
		}
	}

);
<commit_msg>:wrench:<commit_after>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import Snakeskin from '../core';
import { scopeMod } from '../consts/regs';
import { SYS_CONSTS } from '../consts/literals';
import { $consts, $constPositions } from '../consts/cache';

Snakeskin.addDirective(
	'const',

	{
		deferInit: true,
		group: ['const', 'inherit', 'inlineInherit']
	},

	function (command, commandLength) {
		const
			{tplName} = this;

		if (!tplName) {
			Snakeskin.Directives['global'].call(this, ...arguments);
			return;
		}

		const
			output = command.slice(-1) === '?';

		if (output) {
			command = command.slice(0, -1);
		}

		const
			parts = command.split('=');

		if (!parts[1] || !parts[1].trim()) {
			return this.error(`invalid "${this.name}" declaration`);
		}

		let
			prop = parts[0].trim();

		if (scopeMod.test(prop)) {
			prop = this.out(prop, {unsafe: true});
		}

		const
			name = this.pasteDangerBlocks(prop).replace(/\[(['"`])(.*?)\1]/g, '.$2');

		this.startInlineDir('const', {name});

		if (!/[.\[]/.test(prop)) {
			this.consts.push(`var ${prop};`);
		}

		const
			str = `${prop} = ${this.out(parts.slice(1).join('='), {unsafe: !output})};`;

		this.text = output;
		this.append(output ? this.wrap(str) : str);

		if (this.isAdvTest()) {
			if ($consts[tplName][name]) {
				return this.error(`the constant "${name}" is already defined`);
			}

			if (this.vars[tplName][name]) {
				return this.error(`the constant "${name}" is already defined as variable`);
			}

			if (SYS_CONSTS[name]) {
				return this.error(`can't declare the constant "${name}", try another name`);
			}

			const
				parentTpl = this.parentTplName,
				start = this.i - this.startTemplateI;

			let
				parent,
				insideCallBlock = this.hasParentBlock('block', true);

			if (parentTpl) {
				parent = $consts[parentTpl][name];
			}

			if (insideCallBlock && insideCallBlock.name === 'block' && !insideCallBlock.params.args) {
				insideCallBlock = false;
			}

			$consts[tplName][name] = {
				block: Boolean(insideCallBlock || parentTpl && parent && parent.block),
				from: start - commandLength,
				needPrfx: this.needPrfx,
				output: output ? '?' : null,
				to: start
			};

			if (!insideCallBlock) {
				$constPositions[tplName] = start + 1;
			}
		}
	}

);
<|endoftext|>


<commit_before><commit_msg>Fleshing it out, this will definitely change<commit_after>define(['jquery'], function ($) {

  function extract(target) {
    var serialized = target.serializeArray();

    return _(serialized).reduce(function(acc, field) {
      if (field.name.slice(0,1) != "_") {
        acc[field.name] = field.value;
      }
      return acc;
    }, {});
  }

  function handle_error(x,s,e) {
    // Remove any prior error messages
    $(this).children("small.error").remove();

    // Get new messages
    var err_fields = $.parseJSON(s.responseText);
    for (var fieldk in err_fields) {
      var p = $("input[name="+fieldk+"]").parent();
      var c = p.children("small");
      var m = '<small class="error">'+err_fields[fieldk]+'</small>';
      c.length > 0 ? c.replaceWith(m) : p.prepend(m);
    }
  }

  function handle_success(d,s,x) {
    $(this).children("small.error").remove();
  }

  function handle_submit(succ, err) {
    return (function(e) {
      $.ajax({
        url: e.attr("action"),
        data: extract(e),
        dataType: "json",
        context: e,
        success: succ ? succ : handle_success,
        error: err ? err : handle_error
      });
      return false;
    });
  }

  return function(succ=undefined, err=undefined) {
    $("#deform").submit(handle_submit(succ, err));
  };
});
<|endoftext|>


<commit_before>$.fn.ajaxform = function (success, failure, formAttributes) {
    $.fn.ajaxform.increment = ($.fn.ajaxform.increment || 0) + 1;

    var form = $(this);
    if (form.size() > 1) throw 'ajaxform: don\'t call ajaxform on a jquery object with more than one element';
    var iframeId = 'asyncForm' + $.fn.ajaxform.increment;
    var iframe = $("<iframe id='" + iframeId + "' name='" + iframeId + "' src='' style='display:none'>");
    var files = $("[type='file']", form);

    //save original values for later
    var old = {
        target: form.attr('target'),
        enctype: form.attr('enctype'),
        encoding: form.attr('encoding'),
        method: form.attr('method')
    };

    var done = false;

    iframe.bind("load", function () {
        setTimeout(function() {
            iframe.unbind("load").bind("load", function() {
                setTimeout(function() {
                    form.attr(old); //reset
                    done = true;
                    try {
                        var iframeElem = iframe[0];
                        var doc = iframeElem.contentWindow ? iframeElem.contentWindow.document : (iframeElem.contentDocument || iframeElem.document);

                        if (doc) {
                            var respElem = doc.getElementById("response");

                            if (respElem)
                                success($.parseJSON(respElem.innerHTML));
                            else
                                failure({ success: false, error: "No response tag" });
                        } else {
                            failure({ success: false, error: "There was an invalid response from the server. Were you uploading anything large?" });
                        }

                    } catch(e) {
                        failure({ success: false, error: e });
                    }
                    iframe.remove();
                }, 100);
            });

            // set target and form type and submit
            form.attr('target', iframeId);
            form.attr('method', 'POST');
            if (attr) form.attr(attr);
            if (files.size() > 0) {
                form.attr('enctype', 'multipart/form-data');
                form.attr('encoding', 'multipart/form-data');
            }
            form[0].submit();
        }, 100);
    });

    iframe.appendTo('body');

    return {
        timeout: function (time, onTimeout) {
            setTimeout(function () {
                if (done) return;

                try {
                    var iframeElem = iframe[0];
                    var doc = iframeElem.contentWindow ? iframeElem.contentWindow.document : (iframeElem.contentDocument || iframeElem.document);

                    if (doc) {
                        var respElem = doc.getElementById("response");
                        if (respElem) {
                            success($.parseJSON(respElem.innerHTML));
                            return;
                        }

                    }

                } catch (e) { }
				if (onTimeout) { onTimeout(); }
            }, time);
        }
    };
}<commit_msg>add licence to code<commit_after>/*
  MIT License
  Copyright (c) 2014 Luke Schafer luke.schafer@gmail.com
  https://github.com/lukeschafer/jquery.ajaxform/
*/

$.fn.ajaxform = function (success, failure, formAttributes) {
    $.fn.ajaxform.increment = ($.fn.ajaxform.increment || 0) + 1;

    var form = $(this);
    if (form.size() > 1) throw 'ajaxform: don\'t call ajaxform on a jquery object with more than one element';
    var iframeId = 'asyncForm' + $.fn.ajaxform.increment;
    var iframe = $("<iframe id='" + iframeId + "' name='" + iframeId + "' src='' style='display:none'>");
    var files = $("[type='file']", form);

    //save original values for later
    var old = {
        target: form.attr('target'),
        enctype: form.attr('enctype'),
        encoding: form.attr('encoding'),
        method: form.attr('method')
    };

    var done = false;

    iframe.bind("load", function () {
        setTimeout(function() {
            iframe.unbind("load").bind("load", function() {
                setTimeout(function() {
                    form.attr(old); //reset
                    done = true;
                    try {
                        var iframeElem = iframe[0];
                        var doc = iframeElem.contentWindow ? iframeElem.contentWindow.document : (iframeElem.contentDocument || iframeElem.document);

                        if (doc) {
                            var respElem = doc.getElementById("response");

                            if (respElem)
                                success($.parseJSON(respElem.innerHTML));
                            else
                                failure({ success: false, error: "No response tag" });
                        } else {
                            failure({ success: false, error: "There was an invalid response from the server. Were you uploading anything large?" });
                        }

                    } catch(e) {
                        failure({ success: false, error: e });
                    }
                    iframe.remove();
                }, 100);
            });

            // set target and form type and submit
            form.attr('target', iframeId);
            form.attr('method', 'POST');
            if (attr) form.attr(attr);
            if (files.size() > 0) {
                form.attr('enctype', 'multipart/form-data');
                form.attr('encoding', 'multipart/form-data');
            }
            form[0].submit();
        }, 100);
    });

    iframe.appendTo('body');

    return {
        timeout: function (time, onTimeout) {
            setTimeout(function () {
                if (done) return;

                try {
                    var iframeElem = iframe[0];
                    var doc = iframeElem.contentWindow ? iframeElem.contentWindow.document : (iframeElem.contentDocument || iframeElem.document);

                    if (doc) {
                        var respElem = doc.getElementById("response");
                        if (respElem) {
                            success($.parseJSON(respElem.innerHTML));
                            return;
                        }

                    }

                } catch (e) { }
				if (onTimeout) { onTimeout(); }
            }, time);
        }
    };
}
<|endoftext|>