<commit_before>var fs = require('graceful-fs')
var index = require('./index.js')
var recursive = require('recursive-readdir')
var Entities = require('html-entities').XmlEntities
var entities = new Entities()
var _ = require('lodash')
var debug = require('debug')('canary-perch:extract')
var BulkUploader = require('./bulkupload')

var numberOfFiles
var finished

var extractor = function (hosts, inputIndex, outputIndex, inputType, outputType, dictDir) {
  this.hosts = hosts
  this.inputIndex = inputIndex
  this.outputIndex = outputIndex
  this.inputType = inputType
  this.outputType = outputType
  this.dictDir = dictDir
  this.client = index.ESClient(hosts)
  this.uploader = new BulkUploader(this.client)
  this.uploader.runUpload()
}

extractor.prototype.readDictionaries = function () {
  var Extractor = this
  var folder = Extractor.dictDir + '/json/'
  var client = Extractor.client
  debug('starting extractions with dictionaries from: ' + folder)
  recursive(folder, function (err, files) {
    if (err) throw err
    numberOfFiles = files.length
    finished = _.after(numberOfFiles, () => {
      if (err) throw err
      console.log('all extractions finished')
      Extractor.uploader.shutdown()
    })
    files.forEach(function (file) {
      fs.readFile(file, 'utf8', function (err, data) {
        if (err) throw err
        Extractor.dictionaryQuery(JSON.parse(data), client)
      })
    })
  })
}

// Pass it the full dictionary first time. On the last successful upload of data
// run again with the first entry removed and repeate until empty
extractor.prototype.dictionaryQuery = function (dictionary, client) {
  var Extractor = this
  if (!dictionary.entries) {
    debug('Malformed Dictionary: ' + dictionary)
    return
  }
  if (dictionary.entries.length) {
    var entry = dictionary.entries.shift()
    Extractor.dictionarySingleQuery(entry, dictionary, client)
  } else {
    debug('finished extraction')
    finished()
    return
  }
}

extractor.prototype.handleDictionarySingleQueryResponse = function (error, response, dictionary, entry, client) {
  var Extractor = this
  if (error) {
    console.log(error)
  }
  if (!error) {
    if (response.hits.hits.length === 0) {
      Extractor.dictionaryQuery.bind(Extractor, dictionary, client)()
    } else {
      debug('got back' + response.hits.hits.length + 'hits searching for term: ' + entry.term)
      for (var j = 0; j < response.hits.hits.length; j++) {
        Extractor.uploadOneDocFacts(response.hits.hits[j], dictionary, entry, client)
      }

      Extractor.dictionaryQuery.bind(Extractor, dictionary, client)()
    }
  }
}

extractor.prototype.dictionarySingleQuery = function (entry, dictionary, client) {
  var Extractor = this
  var callBacker = function (error, response) {
    Extractor.handleDictionarySingleQueryResponse.bind(Extractor, error, response, dictionary, entry, client)()
  }
  client.search({
    index: Extractor.inputIndex,
    body: {
      _source: false,
      fields: ['cprojectID'],
      query: {
        match_phrase: {
          fulltext: entry.term
        }
      },
      highlight: {
        encoder: 'html',
        fields: {
          fulltext: { boundary_chars: '.,!?\t\n' }
        }
      }
    }
  }, callBacker)
}

// insert all the facts from one document as returned by ES
extractor.prototype.uploadOneDocFacts = function (oneDocFacts, dictionary, entry, client) {
  var Extractor = this
  // console.log('snippet array is: ' + snippetArray)
  var snippetArray = oneDocFacts.highlight.fulltext
  for (var i = 0; i < snippetArray.length; i++) {
    var match = snippetArray[i]
    var fact = {}
    if (match.indexOf('') !== -1) {
      fact.prefix = match.split('')[0]
      fact.term = match.split('')[1].split('')[0]
      fact.postfix = match.split('')[1]
    } else {
      fact.prefix = ''
      fact.term = match
      fact.postfix = ''
    }
    fact.prefix = entities.decode(fact.prefix)
    fact.term = entities.decode(fact.term)
    fact.postfix = entities.decode(fact.postfix)
    fact.docId = oneDocFacts._id
    fact.cprojectID = oneDocFacts.fields.cprojectID
    Extractor.uploadOneFact(fact, dictionary, entry, client)
  }
}

extractor.prototype.uploadOneFact = function (fact, dictionary, entry, client) {
  var Extractor = this
  // console.log("uploading one fact")
  var d = new Date()
  Extractor.uploader.addUpload({
    index: Extractor.outputIndex,
    type: Extractor.outputType,
    body: {
      'prefix': fact.prefix,
      'post': fact.postfix,
      'term': fact.term,
      'documentID': fact.docId,
      'cprojectID': fact.cprojectID,
      'identifiers': entry.identifiers,
      'ingestionDate': d.toJSON()
    }
  })
}

module.exports = extractor
<commit_msg>add git hash to facts<commit_after>var fs = require('graceful-fs')
var index = require('./index.js')
var recursive = require('recursive-readdir')
var Entities = require('html-entities').XmlEntities
var entities = new Entities()
var _ = require('lodash')
var debug = require('debug')('canary-perch:extract')
var BulkUploader = require('./bulkupload')
var cprocess = require('child_process')

var numberOfFiles
var finished

var extractor = function (hosts, inputIndex, outputIndex, inputType, outputType, dictDir) {
  this.hosts = hosts
  this.inputIndex = inputIndex
  this.outputIndex = outputIndex
  this.inputType = inputType
  this.outputType = outputType
  this.dictDir = dictDir
  this.client = index.ESClient(hosts)
  this.uploader = new BulkUploader(this.client)
  this.uploader.runUpload()
}

extractor.prototype.readDictionaries = function () {
  var Extractor = this
  var folder = Extractor.dictDir + '/json/'
  var client = Extractor.client
  Extractor.dictHash = cprocess.execSync('git -C ' + folder + ' rev-parse HEAD', {encoding: 'utf8'}).trim()
  console.log(Extractor.dictHash)
  debug('starting extractions with dictionaries from: ' + folder)
  recursive(folder, function (err, files) {
    if (err) throw err
    numberOfFiles = files.length
    finished = _.after(numberOfFiles, () => {
      if (err) throw err
      console.log('all extractions finished')
      Extractor.uploader.shutdown()
    })
    files.forEach(function (file) {
      fs.readFile(file, 'utf8', function (err, data) {
        if (err) throw err
        Extractor.dictionaryQuery(JSON.parse(data), client)
      })
    })
  })
}

// Pass it the full dictionary first time. On the last successful upload of data
// run again with the first entry removed and repeate until empty
extractor.prototype.dictionaryQuery = function (dictionary, client) {
  var Extractor = this
  if (!dictionary.entries) {
    debug('Malformed Dictionary: ' + dictionary)
    return
  }
  if (dictionary.entries.length) {
    var entry = dictionary.entries.shift()
    Extractor.dictionarySingleQuery(entry, dictionary, client)
  } else {
    debug('finished extraction')
    finished()
    return
  }
}

extractor.prototype.handleDictionarySingleQueryResponse = function (error, response, dictionary, entry, client) {
  var Extractor = this
  if (error) {
    console.log(error)
  }
  if (!error) {
    if (response.hits.hits.length === 0) {
      Extractor.dictionaryQuery.bind(Extractor, dictionary, client)()
    } else {
      debug('got back' + response.hits.hits.length + 'hits searching for term: ' + entry.term)
      for (var j = 0; j < response.hits.hits.length; j++) {
        Extractor.uploadOneDocFacts(response.hits.hits[j], dictionary, entry, client)
      }

      Extractor.dictionaryQuery.bind(Extractor, dictionary, client)()
    }
  }
}

extractor.prototype.dictionarySingleQuery = function (entry, dictionary, client) {
  var Extractor = this
  var callBacker = function (error, response) {
    Extractor.handleDictionarySingleQueryResponse.bind(Extractor, error, response, dictionary, entry, client)()
  }
  client.search({
    index: Extractor.inputIndex,
    body: {
      _source: false,
      fields: ['cprojectID'],
      query: {
        match_phrase: {
          fulltext: entry.term
        }
      },
      highlight: {
        encoder: 'html',
        fields: {
          fulltext: { boundary_chars: '.,!?\t\n' }
        }
      }
    }
  }, callBacker)
}

// insert all the facts from one document as returned by ES
extractor.prototype.uploadOneDocFacts = function (oneDocFacts, dictionary, entry, client) {
  var Extractor = this
  // console.log('snippet array is: ' + snippetArray)
  var snippetArray = oneDocFacts.highlight.fulltext
  for (var i = 0; i < snippetArray.length; i++) {
    var match = snippetArray[i]
    var fact = {}
    if (match.indexOf('') !== -1) {
      fact.prefix = match.split('')[0]
      fact.term = match.split('')[1].split('')[0]
      fact.postfix = match.split('')[1]
    } else {
      fact.prefix = ''
      fact.term = match
      fact.postfix = ''
    }
    fact.prefix = entities.decode(fact.prefix)
    fact.term = entities.decode(fact.term)
    fact.postfix = entities.decode(fact.postfix)
    fact.docId = oneDocFacts._id
    fact.cprojectID = oneDocFacts.fields.cprojectID
    Extractor.uploadOneFact(fact, dictionary, entry, client)
  }
}

extractor.prototype.uploadOneFact = function (fact, dictionary, entry, client) {
  var Extractor = this
  // console.log("uploading one fact")
  var d = new Date()
  Extractor.uploader.addUpload({
    index: Extractor.outputIndex,
    type: Extractor.outputType,
    body: {
      'prefix': fact.prefix,
      'post': fact.postfix,
      'term': fact.term,
      'documentID': fact.docId,
      'cprojectID': fact.cprojectID,
      'identifiers': entry.identifiers,
      'ingestionDate': d.toJSON(),
      'dictionaryHash': Extractor.dictHash
    }
  })
}

module.exports = extractor
<|endoftext|>


<commit_before>import React from 'react';
import TestUtils from 'react-addons-test-utils';
import { expect } from 'chai';
import Button from 'components/Button';

describe('Button', () => {
  it('has title', () => {
    var button = TestUtils.renderIntoDocument(
      <Button title="Test Button" />
    );

    var div = TestUtils.findRenderedDOMComponentWithTag(button, 'button');
    expect(div.textContent).to.equal('Test Button');
  });

  it('renders children after title', () => {
    var button = TestUtils.renderIntoDocument(
      <Button title="Test Button">
        1
        2
      </Button>
    );

    var div = TestUtils.findRenderedDOMComponentWithTag(button, 'button');
    expect(div.textContent).to.equal('Test Button12');
  });
});
<commit_msg>Improve Button specs<commit_after>import React from 'react';
import TestUtils from 'react-addons-test-utils';
import { expect } from 'chai';
import Button from 'components/Button';

describe('Button', () => {
  it('has title', () => {
    var button = TestUtils.renderIntoDocument(
      <Button title="Test Button" />
    );

    var domButton = TestUtils.findRenderedDOMComponentWithTag(button, 'button');
    expect(domButton.textContent).to.equal('Test Button');
  });

  it('renders children after title', () => {
    var button = TestUtils.renderIntoDocument(
      <Button title="Test Button">
        1
        2
      </Button>
    );

    var domButton = TestUtils.findRenderedDOMComponentWithTag(button, 'button');
    expect(domButton.textContent).to.equal('Test Button12');
  });

  describe('states', () => {
    before(() => {
      // Set a global theme for Button
      global.oldTheme = Button.defaultTheme;
      Button.defaultTheme = {
        button: 'button',
        disabled: 'buttonDisabled',
        active: 'buttonActive'
      };
    });

    after(() => {
      // Restore the global theme
      Button.defaultTheme = global.oldTheme;
    });

    it('correctly renders disabled state', () => {
      var button = TestUtils.renderIntoDocument(
        <Button title="Test Button" disabled />
      );
      var domButton = TestUtils.findRenderedDOMComponentWithTag(button, 'button');

      expect(domButton.disabled).to.be.true;
      expect(domButton.className).to.be.contain('buttonDisabled');
    });

    it('correctly renders active state', () => {
      var button = TestUtils.renderIntoDocument(
        <Button title="Test Button" active />
      );
      var domButton = TestUtils.findRenderedDOMComponentWithTag(button, 'button');

      expect(domButton.className).to.be.contain('buttonActive');
    });
  });
});
<|endoftext|>


<commit_before>const dayjs = require('dayjs');
const getConfig = require('./get_confg');

const JOB_METRICS = {
  data_join: [],
  psi_data_join: [],
  tree_model: [],
  nn_model: [
    {
      query: 'name%20:%22auc%22',
      mode: 'avg',
      title: 'auc',
    },
    {
      query: 'name%20:%22loss%22',
      mode: 'avg',
      title: 'loss',
    },
    {
      query: 'name%20:%22receive_timer%22',
      mode: 'avg',
      title: 'receive spend',
    },
    {
      query: 'name%20:%22iter_spend%22',
      mode: 'avg',
      title: 'per session run spend',
    },
    {
      query: 'name%20:%22resend_counter%22',
      mode: 'sum',
      title: 'count of resend',
    },
    {
      query: 'name%20:%22send_counter%22',
      mode: 'sum',
      title: 'count of send',
    },
    {
      query: 'name%20:%22reconnect_counter%22',
      mode: 'sum',
      title: 'count of reconnect',
    },
    {
      query: 'name%20:%22load_data_block_counter%22',
      mode: 'sum',
      title: 'count of load data block',
    },
    {
      query: 'name%20:%22load_data_block_fail_counter%22',
      mode: 'sum',
      title: 'count of fail to load data block',
    },
  ],
};

const config = getConfig({
  KIBANA_HOST: process.env.NEXT_PUBLIC_KIBANA_HOST,
  KIBANA_PORT: process.env.NEXT_PUBLIC_KIBANA_PORT,
});

function getBaseUrl(application_id, from, to) {
  return `https://${config.KIBANA_HOST}:${config.KIBANA_PORT}/fedlearner/app/kibana#/visualize/edit/95e50f80-dd3a-11ea-a472-39251c5aaace?embed=true&_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'${from}',to:'${to}'))&_a=(filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:'73340100-dd33-11ea-a472-39251c5aaace',key:tags.application_id,negate:!f,params:(query:${application_id}),type:phrase),query:(match_phrase:(tags.application_id:${application_id})))),linked:!f,`;
}

/**
 * used for job creation at server-side
 *
 * @param {string} application_id - name of Kubernetes application
 * @param {string} from - date string in ISO format
 * @param {string} to - date string in ISO format
 * @param {string} query - metrics target
 * @param {string} mode - computing function of ElasticSearch
 * @param {string} title - metrics title
 * @return {string} - a Kibana dashboard url
 */
function getDashboardUrl(application_id, from, to, query, mode, title) {
  const baseUrl = getBaseUrl(application_id, from, to);
  return `${baseUrl}query:(language:kuery,query:'${query}'),uiState:(),vis:(aggs:!((enabled:!t,id:'1',params:(field:value),schema:metric,type:${mode}),(enabled:!t,id:'2',params:(drop_partials:!f,extended_bounds:(),field:date_time,interval:auto,min_doc_count:1,scaleMetricValues:!f,timeRange:(from:'${from}',to:'${to}'),useNormalizedEsInterval:!t),schema:segment,type:date_histogram),(enabled:!t,id:'3',params:(field:name.keyword,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:group,type:terms)),params:(addLegend:!t,addTimeMarker:!f,addTooltip:!t,categoryAxes:!((id:CategoryAxis-1,labels:(filter:!t,show:!t,truncate:100),position:bottom,scale:(type:linear),show:!t,style:(),title:(),type:category)),dimensions:(series:!((accessor:1,aggType:terms,format:(id:terms,params:(id:string,missingBucketLabel:Missing,otherBucketLabel:Other,parsedUrl:(basePath:%2Ffedlearner,origin:'https:%2F%2F${config.KIBANA_HOST}',pathname:%2Ffedlearner%2Fapp%2Fkibana))),label:'name.keyword:%20Descending',params:())),x:(accessor:0,aggType:date_histogram,format:(id:date,params:(pattern:'HH:mm:ss')),label:'date_time%20per%20second',params:(bounds:(max:'${to}',min:'${from}'),date:!t,format:'HH:mm:ss',interval:PT1S,intervalESUnit:s,intervalESValue:1)),y:!((accessor:2,aggType:avg,format:(id:number,params:(parsedUrl:(basePath:%2Ffedlearner,origin:'https:%2F%2F${config.KIBANA_HOST}',pathname:%2Ffedlearner%2Fapp%2Fkibana))),label:'Average%20value',params:()))),grid:(categoryLines:!f),labels:(),legendPosition:right,seriesParams:!((data:(id:'1',label:'${mode}%20of%20value'),drawLinesBetweenPoints:!t,interpolate:linear,lineWidth:2,mode:normal,show:!t,showCircles:!t,type:line,valueAxis:ValueAxis-1)),thresholdLine:(color:%23E7664C,show:!f,style:full,value:10,width:1),times:!(),type:line,valueAxes:!((id:ValueAxis-1,labels:(filter:!f,rotate:0,show:!t,truncate:100),name:LeftAxis-1,position:left,scale:(mode:normal,type:linear),show:!t,style:(),title:(text:'${mode}%20of%20value'),type:value))),title:${title},type:line))`;
}

/**
 * get Kibana dashboard urls of a job
 *
 * @param {Object} job - a job instance
 * @return {string[]} - a list of Kibana dashboard url
 */
function getJobDashboardUrls(job) {
  const { name, job_type, created_at } = job;
  const from = dayjs(created_at).toISOString();
  const to = dayjs().toISOString();
  return JOB_METRICS[job_type].map(({ query, mode, title }) => getDashboardUrl(name, from, to, query, mode, title));
}

module.exports = getJobDashboardUrls;
<commit_msg>[fix]fix kibana metrics_list (#310)<commit_after>const dayjs = require('dayjs');
const getConfig = require('./get_confg');

const JOB_METRICS = {
  data_join: [],
  psi_data_join: [],
  tree_model: [],
  nn_model: [
    {
      query: 'name%20:%22auc%22',
      mode: 'avg',
      title: 'auc',
    },
    {
      query: 'name%20:%22loss%22',
      mode: 'avg',
      title: 'loss',
    },
    {
      query: 'name%20:%22receive_timer%22',
      mode: 'avg',
      title: 'receive%20spend',
    },
    {
      query: 'name%20:%22iter_spend%22',
      mode: 'avg',
      title: 'per%20session%20run%20spend',
    },
    {
      query: 'name%20:%22resend_counter%22',
      mode: 'sum',
      title: 'count%20of%20resend',
    },
    {
      query: 'name%20:%22send_counter%22',
      mode: 'sum',
      title: 'count%20of%20send',
    },
    {
      query: 'name%20:%22reconnect_counter%22',
      mode: 'sum',
      title: 'count%20of%20reconnect',
    },
    {
      query: 'name%20:%22load_data_block_counter%22',
      mode: 'sum',
      title: 'count%20of%20load%20data%20block',
    },
    {
      query: 'name%20:%22load_data_block_fail_counter%22',
      mode: 'sum',
      title: 'count%20of%20fail%20to%20load%20data%20block',
    },
  ],
};

const config = getConfig({
  KIBANA_HOST: process.env.NEXT_PUBLIC_KIBANA_HOST,
  KIBANA_PORT: process.env.NEXT_PUBLIC_KIBANA_PORT,
});

function getBaseUrl(application_id, from, to) {
  return `https://${config.KIBANA_HOST}:${config.KIBANA_PORT}/fedlearner/app/kibana#/visualize/edit/95e50f80-dd3a-11ea-a472-39251c5aaace?embed=true&_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:'${from}',to:'${to}'))&_a=(filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:'73340100-dd33-11ea-a472-39251c5aaace',key:tags.application_id,negate:!f,params:(query:${application_id}),type:phrase),query:(match_phrase:(tags.application_id:${application_id})))),linked:!f,`;
}

/**
 * used for job creation at server-side
 *
 * @param {string} application_id - name of Kubernetes application
 * @param {string} from - date string in ISO format
 * @param {string} to - date string in ISO format
 * @param {string} query - metrics target
 * @param {string} mode - computing function of ElasticSearch
 * @param {string} title - metrics title
 * @return {string} - a Kibana dashboard url
 */
function getDashboardUrl(application_id, from, to, query, mode, title) {
  const baseUrl = getBaseUrl(application_id, from, to);
  return `${baseUrl}query:(language:kuery,query:'${query}'),uiState:(),vis:(aggs:!((enabled:!t,id:'1',params:(field:value),schema:metric,type:${mode}),(enabled:!t,id:'2',params:(drop_partials:!f,extended_bounds:(),field:date_time,interval:auto,min_doc_count:1,scaleMetricValues:!f,timeRange:(from:'${from}',to:'${to}'),useNormalizedEsInterval:!t),schema:segment,type:date_histogram),(enabled:!t,id:'3',params:(field:name.keyword,missingBucket:!f,missingBucketLabel:Missing,order:desc,orderBy:'1',otherBucket:!f,otherBucketLabel:Other,size:5),schema:group,type:terms)),params:(addLegend:!t,addTimeMarker:!f,addTooltip:!t,categoryAxes:!((id:CategoryAxis-1,labels:(filter:!t,show:!t,truncate:100),position:bottom,scale:(type:linear),show:!t,style:(),title:(),type:category)),dimensions:(series:!((accessor:1,aggType:terms,format:(id:terms,params:(id:string,missingBucketLabel:Missing,otherBucketLabel:Other,parsedUrl:(basePath:%2Ffedlearner,origin:'https:%2F%2F${config.KIBANA_HOST}',pathname:%2Ffedlearner%2Fapp%2Fkibana))),label:'name.keyword:%20Descending',params:())),x:(accessor:0,aggType:date_histogram,format:(id:date,params:(pattern:'HH:mm:ss')),label:'date_time%20per%20second',params:(bounds:(max:'${to}',min:'${from}'),date:!t,format:'HH:mm:ss',interval:PT1S,intervalESUnit:s,intervalESValue:1)),y:!((accessor:2,aggType:avg,format:(id:number,params:(parsedUrl:(basePath:%2Ffedlearner,origin:'https:%2F%2F${config.KIBANA_HOST}',pathname:%2Ffedlearner%2Fapp%2Fkibana))),label:'Average%20value',params:()))),grid:(categoryLines:!f),labels:(),legendPosition:right,seriesParams:!((data:(id:'1',label:'${mode}%20of%20value'),drawLinesBetweenPoints:!t,interpolate:linear,lineWidth:2,mode:normal,show:!t,showCircles:!t,type:line,valueAxis:ValueAxis-1)),thresholdLine:(color:%23E7664C,show:!f,style:full,value:10,width:1),times:!(),type:line,valueAxes:!((id:ValueAxis-1,labels:(filter:!f,rotate:0,show:!t,truncate:100),name:LeftAxis-1,position:left,scale:(mode:normal,type:linear),show:!t,style:(),title:(text:'${mode}%20of%20value'),type:value))),title:${title},type:line))`;
}

/**
 * get Kibana dashboard urls of a job
 *
 * @param {Object} job - a job instance
 * @return {string[]} - a list of Kibana dashboard url
 */
function getJobDashboardUrls(job) {
  const { name, job_type, created_at } = job;
  const from = dayjs(created_at).toISOString();
  const to = dayjs().toISOString();
  return JOB_METRICS[job_type].map(({ query, mode, title }) => getDashboardUrl(name, from, to, query, mode, title));
}

module.exports = getJobDashboardUrls;
<|endoftext|>


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

// partial implementation of nsITreeView (https://developer.mozilla.org/en/NsITreeView)

var ResultType = {
  ITEM:0,
  ATTR_KEY:1,
  ATTR_VAL:2
}

function Result(domain, name, children, isExpanded, isVisible) {
  this.index = -1;
  this.domain = domain;
  this.name = name;
  this.children = children;
  if(!children) this.children = []; // default to empty
  this.parent = null;
  this.parent_index = -1;
  this.isExpanded = isExpanded;
  this.isVisible = isVisible;
  for(var i = 0; i < this.children.length; i++) {
  	this.children[i].parent = this; // set parent reference
  	this.children[i].parent_index = i; // for next sibling
  }

  this.hasNextSibling = function() {
  	if(parent == null) return -1; // return number or bool
  	return (parent_index != parent.children.length - 1);
  }

  this.type = function() {
    if(this.parent == null) return ResultType.ITEM;
    if(this.children.length == 0) return ResultType.ATTR_VAL;
    return ResultType.ATTR_KEY;
  }
}

var nameSorter = function(a,b){if(a.name < b.name) return -1;if(a.name > b.name)return 1; return 0;}

var itemsToResults = function(domain, results) {
  var new_items = [];
  for(var i = 0; i < results.items.length; i++) {
  	new_items.push(itemToResult(domain, results.items[i]));
  }
  return new_items;
}

var itemToResult = function(domain, item) {
  var children = [];
  for(var attr_name in item.attrs) {
    var vals = item.attrs[attr_name];
    var val_results = [];
    for(var j = 0; j < vals.length; j++) {
      val_results.push(new Result(domain, vals[j]))
    }
    children.push(new Result(domain, attr_name, val_results))
  }
  return new Result(domain, item.name, children, false, true);
}

var results_tree_view = {
  visibleData : [],

  treeBox: null,
  selection: null,

  get rowCount()                     { return this.visibleData.length; },
  setTree: function(treeBox)         { this.treeBox = treeBox; },
  getCellText: function(idx, column) {
    if(this.visibleData[idx].type() == column.index) {
      this.visibleData[idx].index = idx;
      return this.visibleData[idx].name;
    }
    return '';
  },
  isContainer: function(idx)         { return this.visibleData[idx].type() != ResultType.ATTR_VAL; },
  isContainerOpen: function(idx)     { return this.visibleData[idx].isExpanded; },
  isContainerEmpty: function(idx)    { return false; },
  isSeparator: function(idx)         { return false; },
  isSorted: function()               { return false; },
  isEditable: function(idx, column)  { return false; },

  getParentIndex: function(idx) {
    if (this.visibleData[idx].type() == ResultType.ITEM) return -1;
    if (this.visibleData[idx].type() == ResultType.ATTR_KEY) {
      for (var t = idx - 1; t >= 0 ; t--) {
      	if(this.visibleData[idx].type() == ResultType.ITEM) return t;
  	  }
    }
    if (this.visibleData[idx].type() == ResultType.ATTR_VAL) {
  	  for (var t = idx - 1; t >= 0 ; t--) {
  	  	if(this.visibleData[idx].type() == ResultType.ATTR_KEY) return t;
  	  }
  	}
  },

  getLevel: function(idx) {
	  return this.visibleData[idx].type()
  },

  hasNextSibling: function(idx, after) {
  	var ns = this.visibleData[idx].hasNextSibling();
  	if(typeof ns == 'boolean') return ns;
  	//else must be ResultType.ITEM
  	var thislevel = this.getLevel(idx);
  	for (var t = idx + 1; t < this.visibleData.length; t++) {
      if (this.getLevel(t) == thislevel) return true;
    }
  	return false;
  },

  toggleOpenState: function(idx) {
    var item = this.visibleData[idx];
    if (!this.isContainer(idx)) return;

    if (item.isExpanded) {
      item.isExpanded = false;

      var thisLevel = this.getLevel(idx);
      var deletecount = 0;
      for (var t = idx + 1; t < this.visibleData.length; t++) {
        if (this.getLevel(t) > thisLevel) {
          deletecount++;
        }
        else {
          break;
        }
      }
      if (deletecount) {
        for(var i = idx+1; i < idx + deletecount;i++) {
          this.visibleData[i].isExpanded = false;
        }
        this.visibleData.splice(idx + 1, deletecount);
        this.treeBox.rowCountChanged(idx + 1, -deletecount);
      }
    }
    else {
      // need to fetch item
      if(item.children.length == 0) {
        var get_dn = item.domain;
        var get_it = null;
        var get_names = [];
        if(item.type() == ResultType.ITEM) {
          get_it = item.name;
        } else if(item.type() == ResultType.ATTR_KEY) {
          get_it = item.parent.name;
          get_names.push(item.name);
        }
        getAttributes(get_dn, get_it, get_names);
      } else {
        item.isExpanded = true;

        var label = item.name;
        var toinsert = item.children;
        for (var i = 0; i < toinsert.length; i++) {
          this.visibleData.splice(idx + i + 1, 0, toinsert[i]);
        }
        this.treeBox.rowCountChanged(idx + 1, toinsert.length);
      }
    }
  },

  expandAll: function() {
    var current_index = 0;
    while(current_index < this.visibleData.length) {
      var item = this.visibleData[current_index];
      if(!item.isExpanded) {
        this.toggleOpenState(current_index);
      }
      current_index++;
    }
  },

  getImageSrc: function(idx, column) {},
  getProgressMode : function(idx,column) {},
  getCellValue: function(idx, column) {},
  cycleHeader: function(col, elem) {},
  selectionChanged: function() {},
  cycleCell: function(idx, column) {},
  performAction: function(action) {},
  performActionOnCell: function(action, index, column) {},
  getRowProperties: function(idx, column, prop) {},
  getCellProperties: function(idx, column, prop) {},
  getColumnProperties: function(column, element, prop) {},

  // write entire tree
  setResults : function(results) {
    this.treeBox.rowCountChanged(0, -this.visibleData.length);

    // sort item attributes / values
    for(var i = 0; i < results.length; i++) {
      var item = results[i];
      for(var j = 0; j < item.children.length; j++) {
        var attr = item.children[j];
        attr.children = attr.children.sort(nameSorter);
      }
      item.children = item.children.sort(nameSorter);
    }

    this.visibleData = results;
    this.treeBox.rowCountChanged(0, this.visibleData.length);
  },

  findItemIndex : function(item_name, item_type) {
    var type = item_type == null ? ResultType.ITEM : item_type;
    var index = -1;
    for(var i = 0; i < this.visibleData.length; i++) {
      var vis_item = this.visibleData[i];
      if(vis_item.type() != type) continue;
      if(vis_item.name == item_name) {
        index = i;
        break;
      }
    }
    return index;
  },

  removeItem : function(item, type, index) {
    var item_index = index;
    if(index == -1 || index == 0) { // don't trust 0
      item_index = this.findItemIndex(item.name);
      if(item_index == -1) return;
    }
    // close item at index then delete
    var cur_item = this.visibleData[item_index];
    if(cur_item.isExpanded) this.toggleOpenState(item_index);

    // delete
    this.visibleData.splice(item_index, 1);
    this.treeBox.rowCountChanged(item_index, -1);

    // delete parent references to this child
    if(cur_item.parent != null) {
      cur_item.parent.children.splice(cur_item.parent_index, 1);
      if(cur_item.parent.children.length == 0) {
       // recurse if the only child
        this.removeItem(cur_item.parent, cur_item.parent.type(), index-1);
      }
    }
  },

  // set specific item in tree -- don't change/delete others
  setItem : function(item, index) {
    var item_index = index;
    // expand clicked but row not selected
    if(index == -1 || index == 0) { // can't trust tree control...
      item_index = this.findItemIndex(item.name);
      if(item_index == -1) return;
    }
    // close item at index then delete
    var cur_item = this.visibleData[item_index];
    if(cur_item.isExpanded) this.toggleOpenState(item_index);
    // sort item attributes
    for(var j = 0; j < item.children.length; j++) {
      var attr = item.children[j];
      attr.children = attr.children.sort(nameSorter);
    }
    item.children = item.children.sort(nameSorter);

    // overwrite
    this.treeBox.rowCountChanged(item_index, -1);
    this.visibleData[item_index] = item;
    this.treeBox.rowCountChanged(item_index, 1);
    // auto expand names
    this.toggleOpenState(item_index);
  },

  // insert item at the top
  addItem : function(item) {

    // sort item attributes
    for(var j = 0; j < item.children.length; j++) {
      var attr = item.children[j];
      attr.children = attr.children.sort(nameSorter);
    }
    item.children = item.children.sort(nameSorter);

    this.visibleData.splice(0, 0, item);
    this.treeBox.rowCountChanged(0, 1);

    // auto expand names
    this.toggleOpenState(0);
  }

};
<commit_msg>fixed removing first item bug<commit_after>/*
 * Copyright 2010 Bizo, Inc (Donnie Flood [donnie@bizo.com])
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
 * ANY KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */

// partial implementation of nsITreeView (https://developer.mozilla.org/en/NsITreeView)

var ResultType = {
  ITEM:0,
  ATTR_KEY:1,
  ATTR_VAL:2
}

function Result(domain, name, children, isExpanded, isVisible) {
  this.index = -1;
  this.domain = domain;
  this.name = name;
  this.children = children;
  if(!children) this.children = []; // default to empty
  this.parent = null;
  this.parent_index = -1;
  this.isExpanded = isExpanded;
  this.isVisible = isVisible;
  for(var i = 0; i < this.children.length; i++) {
  	this.children[i].parent = this; // set parent reference
  	this.children[i].parent_index = i; // for next sibling
  }

  this.hasNextSibling = function() {
  	if(parent == null) return -1; // return number or bool
  	return (parent_index != parent.children.length - 1);
  }

  this.type = function() {
    if(this.parent == null) return ResultType.ITEM;
    if(this.children.length == 0) return ResultType.ATTR_VAL;
    return ResultType.ATTR_KEY;
  }
}

var nameSorter = function(a,b){if(a.name < b.name) return -1;if(a.name > b.name)return 1; return 0;}

var itemsToResults = function(domain, results) {
  var new_items = [];
  for(var i = 0; i < results.items.length; i++) {
  	new_items.push(itemToResult(domain, results.items[i]));
  }
  return new_items;
}

var itemToResult = function(domain, item) {
  var children = [];
  for(var attr_name in item.attrs) {
    var vals = item.attrs[attr_name];
    var val_results = [];
    for(var j = 0; j < vals.length; j++) {
      val_results.push(new Result(domain, vals[j]))
    }
    children.push(new Result(domain, attr_name, val_results))
  }
  return new Result(domain, item.name, children, false, true);
}

var results_tree_view = {
  visibleData : [],

  treeBox: null,
  selection: null,

  get rowCount()                     { return this.visibleData.length; },
  setTree: function(treeBox)         { this.treeBox = treeBox; },
  getCellText: function(idx, column) {
    if(this.visibleData[idx].type() == column.index) {
      this.visibleData[idx].index = idx;
      return this.visibleData[idx].name;
    }
    return '';
  },
  isContainer: function(idx)         { return this.visibleData[idx].type() != ResultType.ATTR_VAL; },
  isContainerOpen: function(idx)     { return this.visibleData[idx].isExpanded; },
  isContainerEmpty: function(idx)    { return false; },
  isSeparator: function(idx)         { return false; },
  isSorted: function()               { return false; },
  isEditable: function(idx, column)  { return false; },

  getParentIndex: function(idx) {
    if (this.visibleData[idx].type() == ResultType.ITEM) return -1;
    if (this.visibleData[idx].type() == ResultType.ATTR_KEY) {
      for (var t = idx - 1; t >= 0 ; t--) {
      	if(this.visibleData[idx].type() == ResultType.ITEM) return t;
  	  }
    }
    if (this.visibleData[idx].type() == ResultType.ATTR_VAL) {
  	  for (var t = idx - 1; t >= 0 ; t--) {
  	  	if(this.visibleData[idx].type() == ResultType.ATTR_KEY) return t;
  	  }
  	}
  },

  getLevel: function(idx) {
	  return this.visibleData[idx].type()
  },

  hasNextSibling: function(idx, after) {
  	var ns = this.visibleData[idx].hasNextSibling();
  	if(typeof ns == 'boolean') return ns;
  	//else must be ResultType.ITEM
  	var thislevel = this.getLevel(idx);
  	for (var t = idx + 1; t < this.visibleData.length; t++) {
      if (this.getLevel(t) == thislevel) return true;
    }
  	return false;
  },

  toggleOpenState: function(idx) {
    var item = this.visibleData[idx];
    if (!this.isContainer(idx)) return;

    if (item.isExpanded) {
      item.isExpanded = false;

      var thisLevel = this.getLevel(idx);
      var deletecount = 0;
      for (var t = idx + 1; t < this.visibleData.length; t++) {
        if (this.getLevel(t) > thisLevel) {
          deletecount++;
        }
        else {
          break;
        }
      }
      if (deletecount) {
        for(var i = idx+1; i < idx + deletecount;i++) {
          this.visibleData[i].isExpanded = false;
        }
        this.visibleData.splice(idx + 1, deletecount);
        this.treeBox.rowCountChanged(idx + 1, -deletecount);
      }
    }
    else {
      // need to fetch item
      if(item.children.length == 0) {
        var get_dn = item.domain;
        var get_it = null;
        var get_names = [];
        if(item.type() == ResultType.ITEM) {
          get_it = item.name;
        } else if(item.type() == ResultType.ATTR_KEY) {
          get_it = item.parent.name;
          get_names.push(item.name);
        }
        getAttributes(get_dn, get_it, get_names);
      } else {
        item.isExpanded = true;

        var label = item.name;
        var toinsert = item.children;
        for (var i = 0; i < toinsert.length; i++) {
          this.visibleData.splice(idx + i + 1, 0, toinsert[i]);
        }
        this.treeBox.rowCountChanged(idx + 1, toinsert.length);
      }
    }
  },

  expandAll: function() {
    var current_index = 0;
    while(current_index < this.visibleData.length) {
      var item = this.visibleData[current_index];
      if(!item.isExpanded) {
        this.toggleOpenState(current_index);
      }
      current_index++;
    }
  },

  getImageSrc: function(idx, column) {},
  getProgressMode : function(idx,column) {},
  getCellValue: function(idx, column) {},
  cycleHeader: function(col, elem) {},
  selectionChanged: function() {},
  cycleCell: function(idx, column) {},
  performAction: function(action) {},
  performActionOnCell: function(action, index, column) {},
  getRowProperties: function(idx, column, prop) {},
  getCellProperties: function(idx, column, prop) {},
  getColumnProperties: function(column, element, prop) {},

  // write entire tree
  setResults : function(results) {
    this.treeBox.rowCountChanged(0, -this.visibleData.length);

    // sort item attributes / values
    for(var i = 0; i < results.length; i++) {
      var item = results[i];
      for(var j = 0; j < item.children.length; j++) {
        var attr = item.children[j];
        attr.children = attr.children.sort(nameSorter);
      }
      item.children = item.children.sort(nameSorter);
    }

    this.visibleData = results;
    this.treeBox.rowCountChanged(0, this.visibleData.length);
  },

  findItemIndex : function(item_name, item_type) {
    var type = item_type == null ? ResultType.ITEM : item_type;
    var index = -1;
    for(var i = 0; i < this.visibleData.length; i++) {
      var vis_item = this.visibleData[i];
      if(vis_item.type() != type) continue;
      if(vis_item.name == item_name) {
        index = i;
        break;
      }
    }
    return index;
  },

  removeItem : function(item_name, type, index) {
    var item_index = index;
    if(index == -1 || index == 0) { // don't trust 0
      item_index = this.findItemIndex(item_name, type);
      if(item_index == -1) return;
    }
    // close item at index then delete
    var cur_item = this.visibleData[item_index];
    if(cur_item.isExpanded) this.toggleOpenState(item_index);

    // delete
    this.visibleData.splice(item_index, 1);
    this.treeBox.rowCountChanged(item_index, -1);

    // delete parent references to this child
    if(cur_item.parent != null) {
      cur_item.parent.children.splice(cur_item.parent_index, 1);
      if(cur_item.parent.children.length == 0) {
       // recurse if the only child
        this.removeItem(cur_item.parent, cur_item.parent.type(), index-1);
      }
    }
  },

  // set specific item in tree -- don't change/delete others
  setItem : function(item, index) {
    var item_index = index;
    // expand clicked but row not selected
    if(index == -1 || index == 0) { // can't trust tree control...
      item_index = this.findItemIndex(item.name);
      if(item_index == -1) return;
    }
    // close item at index then delete
    var cur_item = this.visibleData[item_index];
    if(cur_item.isExpanded) this.toggleOpenState(item_index);
    // sort item attributes
    for(var j = 0; j < item.children.length; j++) {
      var attr = item.children[j];
      attr.children = attr.children.sort(nameSorter);
    }
    item.children = item.children.sort(nameSorter);

    // overwrite
    this.treeBox.rowCountChanged(item_index, -1);
    this.visibleData[item_index] = item;
    this.treeBox.rowCountChanged(item_index, 1);
    // auto expand names
    this.toggleOpenState(item_index);
  },

  // insert item at the top
  addItem : function(item) {

    // sort item attributes
    for(var j = 0; j < item.children.length; j++) {
      var attr = item.children[j];
      attr.children = attr.children.sort(nameSorter);
    }
    item.children = item.children.sort(nameSorter);

    this.visibleData.splice(0, 0, item);
    this.treeBox.rowCountChanged(0, 1);

    // auto expand names
    this.toggleOpenState(0);
  }

};
<|endoftext|>


<commit_before>// Each suite should begin with a `describe`
describe('In the Chaise search app,', function () {
  var EC = protractor.ExpectedConditions;

  describe('on load,', function () {
    beforeAll(function () {
      browser.get('');
    });
    it('should show the spinner', function (done) {
      var spinner = element(by.id('spinner'));
      // Browser waits (up to 500ms) for spinner to become visible before continuing
      browser.wait(EC.visibilityOf(spinner), 500).then(function () {
        expect(spinner.isDisplayed()).toBe(true);
        done();
      });
    });

    it('should open the initial sidebar', function (done) {
      var spinner = element(by.id('spinner'));
      var sidebar = element(by.id('sidebar'));
      browser.wait(EC.visibilityOf(sidebar), 10000).then(function () {
        expect(sidebar.isDisplayed()).toBe(true);
        expect(spinner.isDisplayed()).toBe(false);
        done();
      });
    });

    it('should have > 1 visible facets to choose from', function (done) {
      var facets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope'));
      facets.then(function () {
        expect(facets.count()).toBeGreaterThan(0);
      });
      var hiddenFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope.ng-hide'));
      hiddenFacets.then(function () {
        expect(hiddenFacets.count()).toBeLessThan(facets.count());
        done();
      });
    });
  });

  describe('the initial facet selection sidebar', function () {
    var expectedFacetsNum = 0;
    //choose the first element found, because it's the one we are looking for
    //use first() instead of [0], so the Promise can be resolved
    var searchBox = element.all(by.model('FacetsData.searchFilter')).first();
    it('should display 0 attributes when searching for something nonexistent', function (done) {
      browser.wait(EC.visibilityOf(searchBox), 500).then(function () {
        // Set values (usually inputs) via sendKeys();
        searchBox.sendKeys('hello');
      });

      var allFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope'));
      var hiddenFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope.ng-hide'));
      //use then to get the resolved result of Promise count()
      allFacets.count().then(function () {
        //use then to get the resolved result of Promise count()
        hiddenFacets.count().then(function () {
          allFacets.count().then(function (allFacetsNum) {
            hiddenFacets.count().then(function (hiddenFacetsNum) {
              expect(allFacetsNum).toBeGreaterThan(0);
              expect(hiddenFacetsNum).toBeGreaterThan(0);
              var shownFacetsNum = allFacetsNum - hiddenFacetsNum;
              expect(shownFacetsNum).toEqual(expectedFacetsNum);
              done();
            });
          });
        });
      });
    });

    it('should find 8 attributes when searching for \'RNA\' in the search box', function (done) {
      var expectedAttrNum = 8;
      browser.wait(EC.visibilityOf(searchBox), 500).then(function () {
        // Set values (usually inputs) via sendKeys();
        searchBox.clear();
        searchBox.sendKeys('RNA');
      });
      var allFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope'));
      var hiddenFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope.ng-hide'));
      //use then to get the resolved result of Promise count()
      allFacets.count().then(function () {
        //use then to get the resolved result of Promise count()
        hiddenFacets.count().then(function () {
          allFacets.count().then(function (allFacetsNum) {
            hiddenFacets.count().then(function (hiddenFacetsNum) {
              expect(allFacetsNum).toBeGreaterThan(0);
              expect(hiddenFacetsNum).toBeGreaterThan(0);
              var shownFacetsNum = allFacetsNum - hiddenFacetsNum;
              expect(shownFacetsNum).toEqual(expectedAttrNum);
              done();
            });
          });
        });
      });
    });

    it('should show 3 attributes after clicking \"Experiment Type\"', function (done) {
      var expectedAttrNum = 3;
      var searchBoxInput = searchBox.getAttribute('value');
      expect(searchBoxInput).toBe('RNA');

      var experimentFacet = element(by.cssContainingText('.field-toggle.ng-binding', 'Experiment Type'));
      browser.wait(EC.visibilityOf(experimentFacet), 500).then(function () {
        experimentFacet.click();
      });
      var allFacets = element.all(by.css('#editfilter ul.nav.filteritems li.ng-scope'));
      var hiddenFacets = element.all(by.css('#editfilter ul.nav.filteritems li.ng-scope.ng-hide'));
      //use then to get the resolved result of Promise count()
      allFacets.count().then(function (allFacetsNum) {
        //use then to get the resolved result of Promise count()
        hiddenFacets.count().then(function (hiddenFacetsNum) {
          expect(allFacetsNum).toBeGreaterThan(0);
          expect(hiddenFacetsNum).toBeGreaterThan(0);
          var shownFacets = allFacetsNum - hiddenFacetsNum;
          expect(shownFacets).toBe(expectedAttrNum);
          done();
        });
      });
    });

    it('should find \'RNA express (microarray)\', click it and wait for 5s', function (done) {
      var nameOfResultFilter = 'RNA expression (microarray)';
      var microarrayFilterLabel = element(by.cssContainingText('label.ng-binding.toggler', nameOfResultFilter))
      browser.wait(EC.visibilityOf(microarrayFilterLabel), 500).then(function () {
        microarrayFilterLabel.click();
        setTimeout(function () {
          done();
        }, 15000);
      });
    });

    it('should show 25 out of 42 results', function (done) {
      var expectedShownResultsNum = 25;
      var expectedTotalResultsNum = 42;
      var allResults = element.all(by.repeater('row in FacetsData.ermrestData'));
      //choose the second #results_tally
      var resultTally = element.all(by.css('#results_tally')).get(1);
      var totalResults = resultTally.element(by.binding("FacetsData.totalServerItems"));
      allResults.count().then(function (allResultsNum) {
        totalResults.getText().then(function (totalResultsText) {
          //test = "42"
          expect(totalResultsText).toBe(expectedTotalResultsNum + "");
          expect(allResultsNum).toBe(expectedShownResultsNum);
          done();
        });
      });
    });

  });
});
<commit_msg>click result and go into record detail page, with hard-coded url verification<commit_after>// Each suite should begin with a `describe`
describe('In the Chaise search app,', function () {
  var EC = protractor.ExpectedConditions;

  describe('on load,', function () {
    beforeAll(function () {
      browser.get('');
    });
    it('should show the spinner', function (done) {
      var spinner = element(by.id('spinner'));
      // Browser waits (up to 500ms) for spinner to become visible before continuing
      browser.wait(EC.visibilityOf(spinner), 500).then(function () {
        expect(spinner.isDisplayed()).toBe(true);
        done();
      });
    });

    it('should open the initial sidebar', function (done) {
      var spinner = element(by.id('spinner'));
      var sidebar = element(by.id('sidebar'));
      browser.wait(EC.visibilityOf(sidebar), 10000).then(function () {
        expect(sidebar.isDisplayed()).toBe(true);
        expect(spinner.isDisplayed()).toBe(false);
        done();
      });
    });

    it('should have > 1 visible facets to choose from', function (done) {
      var facets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope'));
      facets.then(function () {
        expect(facets.count()).toBeGreaterThan(0);
      });
      var hiddenFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope.ng-hide'));
      hiddenFacets.then(function () {
        expect(hiddenFacets.count()).toBeLessThan(facets.count());
        done();
      });
    });
  });

  describe('the initial facet selection sidebar', function () {
    var expectedFacetsNum = 0;
    //choose the first element found, because it's the one we are looking for
    //use first() instead of [0], so the Promise can be resolved
    var searchBox = element.all(by.model('FacetsData.searchFilter')).first();
    it('should display 0 attributes when searching for something nonexistent', function (done) {
      browser.wait(EC.visibilityOf(searchBox), 500).then(function () {
        // Set values (usually inputs) via sendKeys();
        searchBox.sendKeys('hello');
      });

      var allFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope'));
      var hiddenFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope.ng-hide'));
      //use then to get the resolved result of Promise count()
      allFacets.count().then(function () {
        //use then to get the resolved result of Promise count()
        hiddenFacets.count().then(function () {
          allFacets.count().then(function (allFacetsNum) {
            hiddenFacets.count().then(function (hiddenFacetsNum) {
              expect(allFacetsNum).toBeGreaterThan(0);
              expect(hiddenFacetsNum).toBeGreaterThan(0);
              var shownFacetsNum = allFacetsNum - hiddenFacetsNum;
              expect(shownFacetsNum).toEqual(expectedFacetsNum);
              done();
            });
          });
        });
      });
    });

    it('should find 8 attributes when searching for \'RNA\' in the search box', function (done) {
      var expectedAttrNum = 8;
      browser.wait(EC.visibilityOf(searchBox), 500).then(function () {
        // Set values (usually inputs) via sendKeys();
        searchBox.clear();
        searchBox.sendKeys('RNA');
      });
      var allFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope'));
      var hiddenFacets = element.all(by.css('#sidebar ul.sidebar-nav li.ng-scope.ng-hide'));
      //use then to get the resolved result of Promise count()
      allFacets.count().then(function () {
        //use then to get the resolved result of Promise count()
        hiddenFacets.count().then(function () {
          allFacets.count().then(function (allFacetsNum) {
            hiddenFacets.count().then(function (hiddenFacetsNum) {
              expect(allFacetsNum).toBeGreaterThan(0);
              expect(hiddenFacetsNum).toBeGreaterThan(0);
              var shownFacetsNum = allFacetsNum - hiddenFacetsNum;
              expect(shownFacetsNum).toEqual(expectedAttrNum);
              done();
            });
          });
        });
      });
    });

    it('should show 3 attributes after clicking \"Experiment Type\"', function (done) {
      var expectedAttrNum = 3;
      var searchBoxInput = searchBox.getAttribute('value');
      expect(searchBoxInput).toBe('RNA');

      var experimentFacet = element(by.cssContainingText('.field-toggle.ng-binding', 'Experiment Type'));
      browser.wait(EC.visibilityOf(experimentFacet), 500).then(function () {
        experimentFacet.click();
      });
      var allFacets = element.all(by.css('#editfilter ul.nav.filteritems li.ng-scope'));
      var hiddenFacets = element.all(by.css('#editfilter ul.nav.filteritems li.ng-scope.ng-hide'));
      //use then to get the resolved result of Promise count()
      allFacets.count().then(function (allFacetsNum) {
        //use then to get the resolved result of Promise count()
        hiddenFacets.count().then(function (hiddenFacetsNum) {
          expect(allFacetsNum).toBeGreaterThan(0);
          expect(hiddenFacetsNum).toBeGreaterThan(0);
          var shownFacets = allFacetsNum - hiddenFacetsNum;
          expect(shownFacets).toBe(expectedAttrNum);
          done();
        });
      });
    });

    it('should find \'RNA express (microarray)\', click it and wait for 5s', function (done) {
      var nameOfResultFilter = 'RNA expression (microarray)';
      var microarrayFilterLabel = element(by.cssContainingText('label.ng-binding.toggler', nameOfResultFilter))
      browser.wait(EC.visibilityOf(microarrayFilterLabel), 500).then(function () {
        microarrayFilterLabel.click();
        setTimeout(function () {
          done();
        }, 10000);
      });
    });

    it('should show 25 out of 42 results', function (done) {
      var expectedShownResultsNum = 25;
      var expectedTotalResultsNum = 42;
      var allResults = element.all(by.repeater('row in FacetsData.ermrestData'));
      //choose the second #results_tally
      var resultTally = element.all(by.css('#results_tally')).get(1);
      var totalResults = resultTally.element(by.binding("FacetsData.totalServerItems"));
      allResults.count().then(function (allResultsNum) {
        totalResults.getText().then(function (totalResultsText) {
          //test = "42"
          expect(totalResultsText).toBe(expectedTotalResultsNum + "");
          expect(allResultsNum).toBe(expectedShownResultsNum);
          done();
        });
      });
    });

    it('should go to the right URL and show details when clicked', function(done) {
      var detailUrl = "https://dev.misd.isi.edu/chaise/record/#1/legacy:dataset/id=263";
      //var titleSpan = element(by.cssContainingText('span.panel-title', titleTxt));
      var titleSpan = element.all(by.css('span.panel-title.ng-binding')).first();
      titleSpan.click();
      setTimeout(function() {
        browser.rootEl = "#recordApp";
        expect(browser.getCurrentUrl()).toBe(detailUrl);
        done();
      }, 2000);
    });

  });
});
<|endoftext|>


<commit_before>/*!
 * SmoothScroll v1.2.1
 * https://github.com/galambalazs/smoothscroll
 * Licensed under the terms of the MIT license.
 *
 * People involved
 * - Balazs Galambosi (maintainer)
 * - Patrick Brunner  (original idea)
 * - Michael Herf     (Pulse Algorithm)
 *
 * modified by Sebastian Meyer
 */
define([
	"utils/platform"
], function(
	platform
) {

	var options = {
		animationTime: 400,
		stepSize     : 120,

		pulseAlgorithm: true,
		pulseScale    : 4,
		pulseNormalize: 1,

		accelerationDelta: 20,
		accelerationMax  : 1,

		arrowScroll: 50
	};

	var enabled = false;

	var document  = window.document;
	var direction = { x: 0, y: 0 };
	var key       = {
		left    : 37,
		up      : 38,
		right   : 39,
		down    : 40,
		spacebar: 32,
		pageup  : 33,
		pagedown: 34,
		end     : 35,
		home    : 36
	};

	var icon = document.createElement( "i" );
	icon.classList.add( "fa" );
	icon.classList.add( "fa-arrows-alt" );
	icon.classList.add( "middleclick-scroll-icon" );

	var isMiddleClickScrolling = false;

	/************************************************
	 * SCROLLING
	 ************************************************/

	var queue = [];
	var pending = false;
	var lastScroll = +new Date();

	/**
	 * Pushes scroll actions to the scrolling queue.
	 */
	function scrollArray( elem, left, top ) {
		directionCheck( left, top );

		if ( options.accelerationMax !== 1 ) {
			var now = +new Date();
			var elapsed = now - lastScroll;
			if ( elapsed < options.accelerationDelta ) {
				var factor = ( 1 + ( 30 / elapsed ) ) / 2;
				if ( factor > 1 ) {
					factor = Math.min( factor, options.accelerationMax );
					left *= factor;
					top  *= factor;
				}
			}
			lastScroll = +new Date();
		}

		// push a scroll command
		queue.push({
			x    : left,
			y    : top,
			lastX: left < 0 ? 0.99 : -0.99,
			lastY: top  < 0 ? 0.99 : -0.99,
			start: +new Date()
		});

		// don't act if there's a pending queue
		if ( pending ) {
			return;
		}

		var scrollWindow = elem === document.body;

		function step() {
			var now = +new Date();
			var scrollX = 0;
			var scrollY = 0;

			for ( var i = 0; i < queue.length; i++ ) {
				var item     = queue[ i ];
				var elapsed  = now - item.start;
				var finished = elapsed >= options.animationTime;

				// scroll position: [0, 1]
				var position = finished ? 1 : elapsed / options.animationTime;

				// easing [optional]
				if ( options.pulseAlgorithm ) {
					position = pulse( position );
				}

				// only need the difference
				var x = ( item.x * position - item.lastX ) >> 0;
				var y = ( item.y * position - item.lastY ) >> 0;

				// add this to the total scrolling
				scrollX += x;
				scrollY += y;

				// update last values
				item.lastX += x;
				item.lastY += y;

				// delete and step back if it's over
				if ( finished ) {
					queue.splice( i, 1 );
					i--;
				}
			}

			// scroll left and top
			if ( scrollWindow ) {
				window.scrollBy( scrollX, scrollY );

			} else if ( elem ) {
				if ( scrollX ) { elem.scrollLeft += scrollX; }
				if ( scrollY ) { elem.scrollTop  += scrollY; }
			}

			// clean up if there's nothing left to do
			if ( !left && !top ) {
				queue = [];
			}

			if ( queue.length ) {
				requestAnimationFrame( step );
			} else {
				pending = false;
			}
		}

		// start a new queue of actions
		requestAnimationFrame( step );
		pending = true;
	}

	/***********************************************
	 * EVENTS
	 ***********************************************/

	/**
	 * Mouse wheel handler.
	 * @param {MouseEvent} event
	 */
	function onMousewheel( event ) {
		if ( event.defaultPrevented ) {
			return;
		}

		var target = event.target;
		var overflowing = overflowingAncestor( target );

		// use default if there's no overflowing element
		if ( !overflowing ) {
			return true;
		}

		var deltaX = event.wheelDeltaX || 0;
		var deltaY = event.wheelDeltaY || 0;

		// use wheelDelta if deltaX/Y is not available
		if ( !deltaX && !deltaY ) {
			deltaY = event.wheelDelta || 0;
		}

		// scale by step size
		// delta is 120 most of the time
		// synaptics seems to send 1 sometimes
		if ( Math.abs( deltaX ) > 1.2 ) {
			deltaX *= options.stepSize / 120;
		}
		if ( Math.abs( deltaY ) > 1.2 ) {
			deltaY *= options.stepSize / 120;
		}

		scrollArray( overflowing, -deltaX, -deltaY );
		event.preventDefault();
	}

	/**
	 * Keydown event handler.
	 * @param {KeyboardEvent} event
	 */
	function onKeydown( event ) {
		var target   = event.target;
		var modifier = event.ctrlKey
			|| event.altKey
			|| event.metaKey
			|| event.shiftKey && event.keyCode !== key.spacebar;

		if (
			// do nothing if using a modifier key (except shift)
			// or user is editing text
			// or in a dropdown
			   modifier
			|| event.defaultPrevented
			|| target.isContentEditable
			|| /INPUT|TEXTAREA|SELECT/.test( target.tagName )
			// spacebar should trigger button press
			|| target.tagName === "BUTTON" && event.keyCode === key.spacebar
		) {
			return true;
		}

		var x = 0;
		var y = 0;
		var elem = document.querySelector( "main.content" );
		var clientHeight = !elem || elem === document.body
			? window.innerHeight
			: elem.clientHeight;

		switch ( event.keyCode ) {
			case key.up:
				y = -options.arrowScroll;
				break;
			case key.down:
				y = options.arrowScroll;
				break;
			case key.spacebar:
				y = ( event.shiftKey ? -1 : 1 ) * clientHeight * 0.9;
				break;
			case key.pageup:
				y = -clientHeight * 0.9;
				break;
			case key.pagedown:
				y = clientHeight * 0.9;
				break;
			case key.home:
				y = -elem.scrollTop;
				break;
			case key.end:
				var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
				y = damt > 0 ? damt + 10 : 0;
				break;
			case key.left:
				x = -options.arrowScroll;
				break;
			case key.right:
				x = options.arrowScroll;
				break;
			default:
				return true;
		}

		scrollArray( elem, x, y );
		event.preventDefault();
	}

	/**
	 * Middle mouse button handler
	 * @param {MouseEvent} e
	 */
	function onMousedown( e ) {
		if ( isMiddleClickScrolling ) {
			return;
		}

		// watch for middle clicks only
		if ( e.button !== 1 ) {
			return;
		}

		var elem = e.target;

		// linux middle mouse shouldn't be overwritten (paste)
		if ( platform.isLinux && ( elem.tagName === "INPUT" || elem.tagName === "TEXTAREA" ) ) {
			return;
		}

		do {
			if (
				// ignore anchors
				   elem.tagName === "A"
				// ignore "no-middleclick-scroll" data attributes
				|| elem.parentNode && elem.dataset.noMiddleclickScroll
			) {
				e.preventDefault();
				return;
			}
		} while ( ( elem = elem.parentNode ) );

		elem = overflowingAncestor( e.target );
		// only apply to scrollable regions
		if ( !elem || elem.clientHeight === elem.scrollHeight ) {
			return;
		}

		// we don't want the default by now
		e.preventDefault();

		// set up a new scrolling phase
		isMiddleClickScrolling = true;

		// reference point
		icon.style.left = e.clientX + "px";
		icon.style.top  = e.clientY + "px";
		document.body.appendChild( icon );

		var refereceX = e.clientX;
		var refereceY = e.clientY;

		var speedX = 0;
		var speedY = 0;

		// animation loop
		var last = +new Date();
		var finished = false;

		function step( time ) {
			var now = time || +new Date();
			var elapsed = now - last;
			elem.scrollLeft += ( speedX * elapsed ) >> 0;
			elem.scrollTop  += ( speedY * elapsed ) >> 0;
			last = now;
			if ( !finished ) {
				requestAnimationFrame( step );
			}
		}
		requestAnimationFrame( step );

		var first = true;

		function mousemove( e ) {
			var deltaX = Math.abs( refereceX - e.clientX );
			var deltaY = Math.abs( refereceY - e.clientY );
			var movedEnough = Math.max( deltaX, deltaY ) > 10;
			if ( first && movedEnough ) {
				window.addEventListener( "mouseup", remove, false );
				first = false;
			}
			speedX = ( e.clientX - refereceX ) * 10 / 1000;
			speedY = ( e.clientY - refereceY ) * 10 / 1000;
		}

		function remove() {
			window.removeEventListener( "mousemove", mousemove, false );
			window.removeEventListener( "mousedown", remove, false );
			window.removeEventListener( "mouseup", remove, false );
			window.removeEventListener( "keydown", remove, false );
			document.body.removeChild( icon );
			isMiddleClickScrolling = false;
			finished = true;
		}

		window.addEventListener( "mousemove", mousemove, false );
		window.addEventListener( "mousedown", remove, false );
		window.addEventListener( "keydown", remove, false );
	}

	/***********************************************
	 * OVERFLOW
	 ***********************************************/

	var cache = {};
	var cacheAccess    = +new Date();
	var cacheThreshold = 10 * 1000;
	var cacheID        = 0;
	var cacheProperty  = "smoothscrollOverflowID";

	function getCacheID( el ) {
		return el[ cacheProperty ] || ( el[ cacheProperty ] = ++cacheID );
	}

	function setCache( elems, overflowing ) {
		var now = +new Date();
		if ( cacheAccess + cacheThreshold < now ) {
			cache = {};
		}
		cacheAccess = now;

		for ( var i = elems.length; i--; ) {
			cache[ getCacheID( elems[ i ] ) ] = overflowing;
		}

		return overflowing;
	}

	function overflowingAncestor( el ) {
		var elems = [];
		do {
			var cached = cache[ getCacheID( el ) ];
			if ( cached ) {
				return setCache( elems, cached );
			}
			elems.push( el );
			if ( el.clientHeight < el.scrollHeight ) {
				var overflow = getComputedStyle( el, "" ).getPropertyValue( "overflow-y" );
				if ( overflow === "scroll" || overflow === "auto" ) {
					return setCache( elems, el );
				}
			}
		} while ( ( el = el.parentNode ) );
	}

	/***********************************************
	 * HELPERS
	 ***********************************************/

	function directionCheck( x, y ) {
		x = x > 0 ? 1 : -1;
		y = y > 0 ? 1 : -1;
		if ( direction.x !== x || direction.y !== y ) {
			direction.x = x;
			direction.y = y;
			queue = [];
			lastScroll = 0;
		}
	}

	/***********************************************
	 * PULSE
	 ***********************************************/

	/**
	 * Viscous fluid with a pulse for part and decay for the rest.
	 * - Applies a fixed force over an interval (a damped acceleration), and
	 * - Lets the exponential bleed away the velocity over a longer interval
	 * - Michael Herf, http://stereopsis.com/stopping/
	 */
	function pulse_( x ) {
		var val, start, expx;
		// test
		x = x * options.pulseScale;

		if ( x < 1 ) {
			// acceleration
			val = x - ( 1 - Math.exp( -x ) );
		} else {
			// tail
			// the previous animation ended here:
			start = Math.exp( -1 );
			// simple viscous drag
			x -= 1;
			expx = 1 - Math.exp( -x );
			val = start + ( expx * ( 1 - start ) );
		}

		return val * options.pulseNormalize;
	}

	function pulse( x ) {
		if ( x >= 1 ) { return 1; }
		if ( x <= 0 ) { return 0; }

		if ( options.pulseNormalize === 1 ) {
			options.pulseNormalize /= pulse_( 1 );
		}

		return pulse_( x );
	}

	return {
		enable: function() {
			if ( enabled ) { return; }
			window.addEventListener( "mousewheel", onMousewheel, false );
			window.addEventListener( "mousedown", onMousedown, false );
			window.addEventListener( "keydown", onKeydown, false );
			enabled = true;
		},

		disable: function() {
			if ( !enabled ) { return; }
			window.removeEventListener( "mousewheel", onMousewheel, false );
			window.removeEventListener( "mousedown", onMousedown, false );
			window.removeEventListener( "keydown", onKeydown, false );
			enabled = false;
		}
	};

});
<commit_msg>Clear cache when disabling smooth scrolling<commit_after>/*!
 * SmoothScroll v1.2.1
 * https://github.com/galambalazs/smoothscroll
 * Licensed under the terms of the MIT license.
 *
 * People involved
 * - Balazs Galambosi (maintainer)
 * - Patrick Brunner  (original idea)
 * - Michael Herf     (Pulse Algorithm)
 *
 * modified by Sebastian Meyer
 */
define([
	"utils/platform"
], function(
	platform
) {

	var options = {
		animationTime: 400,
		stepSize     : 120,

		pulseAlgorithm: true,
		pulseScale    : 4,
		pulseNormalize: 1,

		accelerationDelta: 20,
		accelerationMax  : 1,

		arrowScroll: 50
	};

	var enabled = false;

	var document  = window.document;
	var direction = { x: 0, y: 0 };
	var key       = {
		left    : 37,
		up      : 38,
		right   : 39,
		down    : 40,
		spacebar: 32,
		pageup  : 33,
		pagedown: 34,
		end     : 35,
		home    : 36
	};

	var icon = document.createElement( "i" );
	icon.classList.add( "fa" );
	icon.classList.add( "fa-arrows-alt" );
	icon.classList.add( "middleclick-scroll-icon" );

	var isMiddleClickScrolling = false;

	/************************************************
	 * SCROLLING
	 ************************************************/

	var queue = [];
	var pending = false;
	var lastScroll = +new Date();

	/**
	 * Pushes scroll actions to the scrolling queue.
	 */
	function scrollArray( elem, left, top ) {
		directionCheck( left, top );

		if ( options.accelerationMax !== 1 ) {
			var now = +new Date();
			var elapsed = now - lastScroll;
			if ( elapsed < options.accelerationDelta ) {
				var factor = ( 1 + ( 30 / elapsed ) ) / 2;
				if ( factor > 1 ) {
					factor = Math.min( factor, options.accelerationMax );
					left *= factor;
					top  *= factor;
				}
			}
			lastScroll = +new Date();
		}

		// push a scroll command
		queue.push({
			x    : left,
			y    : top,
			lastX: left < 0 ? 0.99 : -0.99,
			lastY: top  < 0 ? 0.99 : -0.99,
			start: +new Date()
		});

		// don't act if there's a pending queue
		if ( pending ) {
			return;
		}

		var scrollWindow = elem === document.body;

		function step() {
			var now = +new Date();
			var scrollX = 0;
			var scrollY = 0;

			for ( var i = 0; i < queue.length; i++ ) {
				var item     = queue[ i ];
				var elapsed  = now - item.start;
				var finished = elapsed >= options.animationTime;

				// scroll position: [0, 1]
				var position = finished ? 1 : elapsed / options.animationTime;

				// easing [optional]
				if ( options.pulseAlgorithm ) {
					position = pulse( position );
				}

				// only need the difference
				var x = ( item.x * position - item.lastX ) >> 0;
				var y = ( item.y * position - item.lastY ) >> 0;

				// add this to the total scrolling
				scrollX += x;
				scrollY += y;

				// update last values
				item.lastX += x;
				item.lastY += y;

				// delete and step back if it's over
				if ( finished ) {
					queue.splice( i, 1 );
					i--;
				}
			}

			// scroll left and top
			if ( scrollWindow ) {
				window.scrollBy( scrollX, scrollY );

			} else if ( elem ) {
				if ( scrollX ) { elem.scrollLeft += scrollX; }
				if ( scrollY ) { elem.scrollTop  += scrollY; }
			}

			// clean up if there's nothing left to do
			if ( !left && !top ) {
				queue = [];
			}

			if ( queue.length ) {
				requestAnimationFrame( step );
			} else {
				pending = false;
			}
		}

		// start a new queue of actions
		requestAnimationFrame( step );
		pending = true;
	}

	/***********************************************
	 * EVENTS
	 ***********************************************/

	/**
	 * Mouse wheel handler.
	 * @param {MouseEvent} event
	 */
	function onMousewheel( event ) {
		if ( event.defaultPrevented ) {
			return;
		}

		var target = event.target;
		var overflowing = overflowingAncestor( target );

		// use default if there's no overflowing element
		if ( !overflowing ) {
			return true;
		}

		var deltaX = event.wheelDeltaX || 0;
		var deltaY = event.wheelDeltaY || 0;

		// use wheelDelta if deltaX/Y is not available
		if ( !deltaX && !deltaY ) {
			deltaY = event.wheelDelta || 0;
		}

		// scale by step size
		// delta is 120 most of the time
		// synaptics seems to send 1 sometimes
		if ( Math.abs( deltaX ) > 1.2 ) {
			deltaX *= options.stepSize / 120;
		}
		if ( Math.abs( deltaY ) > 1.2 ) {
			deltaY *= options.stepSize / 120;
		}

		scrollArray( overflowing, -deltaX, -deltaY );
		event.preventDefault();
	}

	/**
	 * Keydown event handler.
	 * @param {KeyboardEvent} event
	 */
	function onKeydown( event ) {
		var target   = event.target;
		var modifier = event.ctrlKey
			|| event.altKey
			|| event.metaKey
			|| event.shiftKey && event.keyCode !== key.spacebar;

		if (
			// do nothing if using a modifier key (except shift)
			// or user is editing text
			// or in a dropdown
			   modifier
			|| event.defaultPrevented
			|| target.isContentEditable
			|| /INPUT|TEXTAREA|SELECT/.test( target.tagName )
			// spacebar should trigger button press
			|| target.tagName === "BUTTON" && event.keyCode === key.spacebar
		) {
			return true;
		}

		var x = 0;
		var y = 0;
		var elem = document.querySelector( "main.content" );
		var clientHeight = !elem || elem === document.body
			? window.innerHeight
			: elem.clientHeight;

		switch ( event.keyCode ) {
			case key.up:
				y = -options.arrowScroll;
				break;
			case key.down:
				y = options.arrowScroll;
				break;
			case key.spacebar:
				y = ( event.shiftKey ? -1 : 1 ) * clientHeight * 0.9;
				break;
			case key.pageup:
				y = -clientHeight * 0.9;
				break;
			case key.pagedown:
				y = clientHeight * 0.9;
				break;
			case key.home:
				y = -elem.scrollTop;
				break;
			case key.end:
				var damt = elem.scrollHeight - elem.scrollTop - clientHeight;
				y = damt > 0 ? damt + 10 : 0;
				break;
			case key.left:
				x = -options.arrowScroll;
				break;
			case key.right:
				x = options.arrowScroll;
				break;
			default:
				return true;
		}

		scrollArray( elem, x, y );
		event.preventDefault();
	}

	/**
	 * Middle mouse button handler
	 * @param {MouseEvent} e
	 */
	function onMousedown( e ) {
		if ( isMiddleClickScrolling ) {
			return;
		}

		// watch for middle clicks only
		if ( e.button !== 1 ) {
			return;
		}

		var elem = e.target;

		// linux middle mouse shouldn't be overwritten (paste)
		if ( platform.isLinux && ( elem.tagName === "INPUT" || elem.tagName === "TEXTAREA" ) ) {
			return;
		}

		do {
			if (
				// ignore anchors
				   elem.tagName === "A"
				// ignore "no-middleclick-scroll" data attributes
				|| elem.parentNode && elem.dataset.noMiddleclickScroll
			) {
				e.preventDefault();
				return;
			}
		} while ( ( elem = elem.parentNode ) );

		elem = overflowingAncestor( e.target );
		// only apply to scrollable regions
		if ( !elem || elem.clientHeight === elem.scrollHeight ) {
			return;
		}

		// we don't want the default by now
		e.preventDefault();

		// set up a new scrolling phase
		isMiddleClickScrolling = true;

		// reference point
		icon.style.left = e.clientX + "px";
		icon.style.top  = e.clientY + "px";
		document.body.appendChild( icon );

		var refereceX = e.clientX;
		var refereceY = e.clientY;

		var speedX = 0;
		var speedY = 0;

		// animation loop
		var last = +new Date();
		var finished = false;

		function step( time ) {
			var now = time || +new Date();
			var elapsed = now - last;
			elem.scrollLeft += ( speedX * elapsed ) >> 0;
			elem.scrollTop  += ( speedY * elapsed ) >> 0;
			last = now;
			if ( !finished ) {
				requestAnimationFrame( step );
			}
		}
		requestAnimationFrame( step );

		var first = true;

		function mousemove( e ) {
			var deltaX = Math.abs( refereceX - e.clientX );
			var deltaY = Math.abs( refereceY - e.clientY );
			var movedEnough = Math.max( deltaX, deltaY ) > 10;
			if ( first && movedEnough ) {
				window.addEventListener( "mouseup", remove, false );
				first = false;
			}
			speedX = ( e.clientX - refereceX ) * 10 / 1000;
			speedY = ( e.clientY - refereceY ) * 10 / 1000;
		}

		function remove() {
			window.removeEventListener( "mousemove", mousemove, false );
			window.removeEventListener( "mousedown", remove, false );
			window.removeEventListener( "mouseup", remove, false );
			window.removeEventListener( "keydown", remove, false );
			document.body.removeChild( icon );
			isMiddleClickScrolling = false;
			finished = true;
		}

		window.addEventListener( "mousemove", mousemove, false );
		window.addEventListener( "mousedown", remove, false );
		window.addEventListener( "keydown", remove, false );
	}

	/***********************************************
	 * OVERFLOW
	 ***********************************************/

	var cache = {};
	var cacheAccess    = +new Date();
	var cacheThreshold = 10 * 1000;
	var cacheID        = 0;
	var cacheProperty  = "smoothscrollOverflowID";

	function getCacheID( el ) {
		return el[ cacheProperty ] || ( el[ cacheProperty ] = ++cacheID );
	}

	function setCache( elems, overflowing ) {
		var now = +new Date();
		if ( cacheAccess + cacheThreshold < now ) {
			cache = {};
		}
		cacheAccess = now;

		for ( var i = elems.length; i--; ) {
			cache[ getCacheID( elems[ i ] ) ] = overflowing;
		}

		return overflowing;
	}

	function overflowingAncestor( el ) {
		var elems = [];
		do {
			var cached = cache[ getCacheID( el ) ];
			if ( cached ) {
				return setCache( elems, cached );
			}
			elems.push( el );
			if ( el.clientHeight < el.scrollHeight ) {
				var overflow = getComputedStyle( el, "" ).getPropertyValue( "overflow-y" );
				if ( overflow === "scroll" || overflow === "auto" ) {
					return setCache( elems, el );
				}
			}
		} while ( ( el = el.parentNode ) );
	}

	/***********************************************
	 * HELPERS
	 ***********************************************/

	function directionCheck( x, y ) {
		x = x > 0 ? 1 : -1;
		y = y > 0 ? 1 : -1;
		if ( direction.x !== x || direction.y !== y ) {
			direction.x = x;
			direction.y = y;
			queue = [];
			lastScroll = 0;
		}
	}

	/***********************************************
	 * PULSE
	 ***********************************************/

	/**
	 * Viscous fluid with a pulse for part and decay for the rest.
	 * - Applies a fixed force over an interval (a damped acceleration), and
	 * - Lets the exponential bleed away the velocity over a longer interval
	 * - Michael Herf, http://stereopsis.com/stopping/
	 */
	function pulse_( x ) {
		var val, start, expx;
		// test
		x = x * options.pulseScale;

		if ( x < 1 ) {
			// acceleration
			val = x - ( 1 - Math.exp( -x ) );
		} else {
			// tail
			// the previous animation ended here:
			start = Math.exp( -1 );
			// simple viscous drag
			x -= 1;
			expx = 1 - Math.exp( -x );
			val = start + ( expx * ( 1 - start ) );
		}

		return val * options.pulseNormalize;
	}

	function pulse( x ) {
		if ( x >= 1 ) { return 1; }
		if ( x <= 0 ) { return 0; }

		if ( options.pulseNormalize === 1 ) {
			options.pulseNormalize /= pulse_( 1 );
		}

		return pulse_( x );
	}

	return {
		enable: function() {
			if ( enabled ) { return; }
			window.addEventListener( "mousewheel", onMousewheel, false );
			window.addEventListener( "mousedown", onMousedown, false );
			window.addEventListener( "keydown", onKeydown, false );
			enabled = true;
		},

		disable: function() {
			if ( !enabled ) { return; }
			window.removeEventListener( "mousewheel", onMousewheel, false );
			window.removeEventListener( "mousedown", onMousedown, false );
			window.removeEventListener( "keydown", onKeydown, false );
			cache = {};
			enabled = false;
		}
	};

});
<|endoftext|>


<commit_before>// framework/entities/createFactories.js
// ------------------

function isBeforeInitMixin(mixin) {
  return !!mixin.runBeforeInit;
}

function entityMixinOrNothingFrom(thing) {
  return ((isArray(thing) && thing.length) || isObject(thing) ? thing : {});
}

function entityClassFactory(descriptor, configParams) {
  var entityCtor = null;
  var privateDataMixin = {
    _preInit: function() {
      var privateDataStore = {
        inFlightChildren: fw.observableArray()
      };
      this.__private = privateData.bind(this, privateDataStore, configParams);
    }
  };

  configParams = extend({}, descriptor.defaultConfig, configParams || {});

  var descriptorBehavior = [];
  map(descriptor.behavior, function(behavior, index) {
    descriptorBehavior.push(isFunction(behavior) ? behavior(descriptor, configParams || {}) : behavior);
  });

  var ctor = configParams.initialize || noop;
  var userExtendProps = { mixin: configParams.extend || {} };
  if (!descriptor.isEntityCtor(ctor)) {
    var isEntityDuckTagMixin = {};
    isEntityDuckTagMixin[descriptor.isEntityDuckTag] = true;
    isEntityDuckTagMixin = { mixin: isEntityDuckTagMixin };

    var newInstanceCheckMixin = {
      _preInit: function() {
        if (this === windowObject) {
          throw new Error('Must use the new operator when instantiating a ' + descriptor.methodName + '.');
        }
      }
    };
    var afterInitMixins = reject(entityMixins, isBeforeInitMixin);
    var beforeInitMixins = map(filter(entityMixins, isBeforeInitMixin), function(mixin) {
      delete mixin.runBeforeInit;
      return mixin;
    });

    var composure = [ctor].concat(
      entityMixinOrNothingFrom(privateDataMixin),
      entityMixinOrNothingFrom(userExtendProps),
      entityMixinOrNothingFrom(newInstanceCheckMixin),
      entityMixinOrNothingFrom(isEntityDuckTagMixin),
      entityMixinOrNothingFrom(afterInitMixins),
      entityMixinOrNothingFrom(beforeInitMixins),
      entityMixinOrNothingFrom(configParams.mixins),
      entityMixinOrNothingFrom(descriptorBehavior)
    );

    entityCtor = riveter.compose.apply( undefined, composure );

    entityCtor[descriptor.isEntityCtorDuckTag] = true;

    var privateDataStore = {};
    entityCtor.__private = privateData.bind(this, privateDataStore, configParams);
  } else {
    // user has specified another entity constructor as the 'initialize' function, we extend it with the current constructor to create an inheritance chain
    entityCtor = ctor;
  }

  if (!isNull(entityCtor) && isFunction(configParams.parent)) {
    entityCtor.inherits(configParams.parent);
  }

  if (configParams.autoRegister) {
    descriptor.resource.register(configParams.namespace, entityCtor);
  }

  return entityCtor;
}

function createEntityFactories() {
  // create the class factory method for each entity descriptor
  filter(entityDescriptors, function getOnlyDescriptorsWithMethodName(descriptor) {
    return isString(descriptor.methodName);
  }).forEach(function setupClassFactory(descriptor) {
    fw[descriptor.methodName].create = entityClassFactory.bind(null, descriptor);
  });
};

runPostInit.unshift(createEntityFactories);
<commit_msg>integrated new createFactories.js code<commit_after>// framework/entities/createFactories.js
// ------------------

function isBeforeInitMixin(mixin) {
  return !!mixin.runBeforeInit;
}

function entityMixinOrNothingFrom(thing) {
  return ((isArray(thing) && thing.length) || isObject(thing) ? thing : {});
}

function entityClassFactory(descriptor, configParams) {
  var entityCtor = null;
  var privateDataMixin = {
    _preInit: function() {
      this.__private = privateData.bind(this, {
        inFlightChildren: fw.observableArray()
      }, configParams);
    }
  };

  configParams = extend({}, descriptor.defaultConfig, configParams || {});

  var descriptorBehavior = [];
  map(descriptor.behavior, function(behavior, index) {
    descriptorBehavior.push(isFunction(behavior) ? behavior(descriptor, configParams || {}) : behavior);
  });

  var ctor = configParams.initialize || noop;
  var userExtendProps = { mixin: configParams.extend || {} };
  if (!descriptor.isEntityCtor(ctor)) {
    var isEntityDuckTagMixin = {};
    isEntityDuckTagMixin[descriptor.isEntityDuckTag] = true;
    isEntityDuckTagMixin = { mixin: isEntityDuckTagMixin };

    var newInstanceCheckMixin = {
      _preInit: function() {
        if (this === windowObject) {
          throw new Error('Must use the new operator when instantiating a ' + descriptor.methodName + '.');
        }
      }
    };
    var afterInitMixins = reject(entityMixins, isBeforeInitMixin);
    var beforeInitMixins = map(filter(entityMixins, isBeforeInitMixin), function(mixin) {
      delete mixin.runBeforeInit;
      return mixin;
    });

    var composure = [ctor].concat(
      entityMixinOrNothingFrom(privateDataMixin),
      entityMixinOrNothingFrom(userExtendProps),
      entityMixinOrNothingFrom(newInstanceCheckMixin),
      entityMixinOrNothingFrom(isEntityDuckTagMixin),
      entityMixinOrNothingFrom(afterInitMixins),
      entityMixinOrNothingFrom(beforeInitMixins),
      entityMixinOrNothingFrom(configParams.mixins),
      entityMixinOrNothingFrom(descriptorBehavior)
    );

    entityCtor = riveter.compose.apply( undefined, composure );
    entityCtor[descriptor.isEntityCtorDuckTag] = true;
    entityCtor.__private = privateData.bind(this, {}, configParams);
  } else {
    // user has specified another entity constructor as the 'initialize' function, we extend it with the current constructor to create an inheritance chain
    entityCtor = ctor;
  }

  if (!isNull(entityCtor) && isFunction(configParams.parent)) {
    entityCtor.inherits(configParams.parent);
  }

  if (configParams.autoRegister) {
    descriptor.resource.register(configParams.namespace, entityCtor);
  }

  return entityCtor;
}

function createEntityFactories() {
  // create the class factory method for each entity descriptor
  filter(entityDescriptors, function getOnlyDescriptorsWithMethodName(descriptor) {
    return isString(descriptor.methodName);
  }).forEach(function setupClassFactory(descriptor) {
    fw[descriptor.methodName].create = entityClassFactory.bind(null, descriptor);
  });
};

runPostInit.unshift(createEntityFactories);
<|endoftext|>