<commit_before>'use strict';

// MODULES //

var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
var isPositive = require( '@stdlib/assert/is-positive-number' ).isPrimitive;
var isnan = require( '@stdlib/assert/is-nan' );

// MAIN //

/**
* Validates parameters.
*
* @private
* @param {number} mu - mean
* @param {PositiveNumber} b - shape parameter
* @returns {(Error|null)} error or null
*
* @example
* var err = validate( 1.0, 2.0 );
* if ( err ) {
*     throw err;
* }
*/
function validate( mu, b ) {
	if ( !isNumber( mu ) || isnan( mu ) ) {
		return new TypeError( 'invalid input argument. `mu` must be a number primitive and not `NaN`. Value: `' + mu + '`.' );
	}
	if ( !isPositive( b ) ) {
		return new TypeError( 'invalid input argument. `b` must be a positive number. Value: `' + b + '`.' );
	}
	return null;
} // end FUNCTION validate()

// EXPORTS //

module.exports = validate;
<commit_msg>Fix parameter description<commit_after>'use strict';

// MODULES //

var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
var isPositive = require( '@stdlib/assert/is-positive-number' ).isPrimitive;
var isnan = require( '@stdlib/assert/is-nan' );

// MAIN //

/**
* Validates parameters.
*
* @private
* @param {number} mu - mean
* @param {PositiveNumber} b - scale parameter
* @returns {(Error|null)} error or null
*
* @example
* var err = validate( 1.0, 2.0 );
* if ( err ) {
*     throw err;
* }
*/
function validate( mu, b ) {
	if ( !isNumber( mu ) || isnan( mu ) ) {
		return new TypeError( 'invalid input argument. `mu` must be a number primitive and not `NaN`. Value: `' + mu + '`.' );
	}
	if ( !isPositive( b ) ) {
		return new TypeError( 'invalid input argument. `b` must be a positive number. Value: `' + b + '`.' );
	}
	return null;
} // end FUNCTION validate()

// EXPORTS //

module.exports = validate;
<|endoftext|>


<commit_before>/*!
 * Copyright 2017 Pentaho Corporation. All rights reserved.
 *
 * 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.
 */

/**
 * The Data Service
 *
 * The Data Service, a collection of endpoints used by the application
 *
 * @module services/data.service
 * @property {String} name The name of the module.
 */
define(
    [],
    function() {
      'use strict';

      var factoryArray = ["$http", factory];
      var module = {
        name: "dataService",
        factory: factoryArray
      };

      return module;

      /**
       * The dataService factory
       *
       * @param {Object} $http - The $http angular helper service
       *
       * @return {Object} The dataService api
       */
      function factory($http) {
        var baseUrl = "/cxf/browser";
        return {
          getDirectoryTree: getDirectoryTree,
          getFiles: getFiles,
          getActiveFileName: getActiveFileName,
          getRecentFiles: getRecentFiles,
          getRecentSearches: getRecentSearches,
          storeRecentSearch: storeRecentSearch,
          openRecent: openRecent,
          openFile: openFile,
          saveFile: saveFile,
          rename: rename,
          create: create,
          remove: remove
        };

        /**
         * Gets the directory tree for the currently connected repository
         *
         * @return {Promise} - a promise resolved once data is returned
         */
        function getDirectoryTree() {
          return _httpGet([baseUrl, "loadDirectoryTree"].join("/"));
        }

        /**
         * Load files for a specific directory
         *
         * @param {String} id - The object id for a directory
         * @return {Promise} - a promise resolved once data is returned
         */
        function getFiles(id) {
          return _httpGet([baseUrl, "loadFiles", encodeURIComponent(id)].join("/"));
        }

        /**
         * Gets the Active File Name Opened in Spoon
         * @return {Promise} - a promise resolved once data is returned
         */
        function getActiveFileName() {
          return _httpGet([baseUrl, "getActiveFileName"].join("/"));
        }

        /**
         * Load a file
         *
         * @param {String} id - The object id for a file
         * @param {String} type - The file type (job/transformation)
         * @return {Promise} - a promise resolved once data is returned
         */
        function openFile(id, type) {
          return _httpGet([baseUrl, "loadFile", encodeURIComponent(id), type].join("/"));
        }

        /**
         * Save a file
         *
         * @param {String} path - The path to which to save file
         * @param {String} name - The file name
         * @return {Promise} - a promise resolved once data is returned
         */
        function saveFile(path, name) {
          return _httpGet([baseUrl, "saveFile", encodeURIComponent(path), name].join("/"));
        }

        /**
         * Returns the recent files for the connected repository
         *
         * @return {Promise} - a promise resolved once data is returned
         */
        function getRecentFiles() {
          return _httpGet([baseUrl, "recentFiles"].join("/"));
        }

        /**
         * Returns the 5 recent searches performed
         *
         * @return {Promise} - a promise resolved once data is returned
         */
        function getRecentSearches() {
          return _httpGet([baseUrl, "recentSearches"].join("/"));
        }

        /**
         * Stores the most recent search performed
         *
         * @param {String} recentSearch - The most recent search to be stored
         * @return {Promise} - a promise resolved once data is returned
         */
        function storeRecentSearch(recentSearch) {
          return _httpGet([baseUrl, "storeRecentSearch", encodeURIComponent(recentSearch) + "?ts=" + new Date().getTime()].join("/"));
        }

        /**
         * Renames a repository object
         *
         * @param {String} id - The repository object id
         * @param {String} name - The new name
         * @param {String} path - The new path
         * @param {String} type - The object type
         * @return {Promise} - a promise resolved once data is returned
         */
        function rename(id, name, path, type) {
          return _httpPost([baseUrl, "rename", encodeURIComponent(id), encodeURIComponent(path), name, type].join("/"));
        }

        /**
         * Create a new folder
         *
         * @param {String} parent - The parent folder
         * @param {String} name - The new folder name
         * @return {Promise} - a promise resolved once data is returned
         */
        function create(parent, name) {
          return _httpPost([baseUrl, "create", encodeURIComponent(parent), name].join("/"), null);
        }

        /**
         * Remove a repository object
         *
         * @param {String} id - The repository object id
         * @param {String} type - The object type
         * @return {Promise} - a promise resolved once data is returned
         */
        function remove(id, type) {
          return _httpDelete([baseUrl, "remove", encodeURIComponent(id), type].join("/"));
        }

        /**
         * Open a recent file
         *
         * @param {String} repo - The name of the repository
         * @param {String} id - The repository object id
         * @return {Promise} - a promise resolved once data is returned
         */
        function openRecent(repo, id) {
          return _httpGet([baseUrl, "loadRecent", repo, id].join("/"));
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} url - the url
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _httpGet(url) {
          return _wrapHttp("GET", url);
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} url - the url
         * @param {String} data - the post data
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _httpPost(url, data) {
          return _wrapHttp("POST", url, data);
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} url - the url
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _httpDelete(url) {
          return _wrapHttp("DELETE", url);
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} method - the http method to use
         * @param {String} url - the url
         * @param {String} data - the data to send to the server
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _wrapHttp(method, url, data) {
          var options = {
            method: method,
            url: url,
            headers: {
              Accept: "application/json"
            }
          };
          if (data !== null) {
            options.data = data;
          }
          return $http(options);
        }
      }
    });
<commit_msg>[BACKLOG-15718] Added cache busting (#4141)<commit_after>/*!
 * Copyright 2017 Pentaho Corporation. All rights reserved.
 *
 * 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.
 */

/**
 * The Data Service
 *
 * The Data Service, a collection of endpoints used by the application
 *
 * @module services/data.service
 * @property {String} name The name of the module.
 */
define(
    [],
    function() {
      'use strict';

      var factoryArray = ["$http", factory];
      var module = {
        name: "dataService",
        factory: factoryArray
      };

      return module;

      /**
       * The dataService factory
       *
       * @param {Object} $http - The $http angular helper service
       *
       * @return {Object} The dataService api
       */
      function factory($http) {
        var baseUrl = "/cxf/browser";
        return {
          getDirectoryTree: getDirectoryTree,
          getFiles: getFiles,
          getActiveFileName: getActiveFileName,
          getRecentFiles: getRecentFiles,
          getRecentSearches: getRecentSearches,
          storeRecentSearch: storeRecentSearch,
          openRecent: openRecent,
          openFile: openFile,
          saveFile: saveFile,
          rename: rename,
          create: create,
          remove: remove
        };

        /**
         * Gets the directory tree for the currently connected repository
         *
         * @return {Promise} - a promise resolved once data is returned
         */
        function getDirectoryTree() {
          return _httpGet([baseUrl, "loadDirectoryTree"].join("/"));
        }

        /**
         * Load files for a specific directory
         *
         * @param {String} id - The object id for a directory
         * @return {Promise} - a promise resolved once data is returned
         */
        function getFiles(id) {
          return _httpGet([baseUrl, "loadFiles", encodeURIComponent(id)].join("/"));
        }

        /**
         * Gets the Active File Name Opened in Spoon
         * @return {Promise} - a promise resolved once data is returned
         */
        function getActiveFileName() {
          return _httpGet([baseUrl, "getActiveFileName"].join("/"));
        }

        /**
         * Load a file
         *
         * @param {String} id - The object id for a file
         * @param {String} type - The file type (job/transformation)
         * @return {Promise} - a promise resolved once data is returned
         */
        function openFile(id, type) {
          return _httpGet([baseUrl, "loadFile", encodeURIComponent(id), type].join("/"));
        }

        /**
         * Save a file
         *
         * @param {String} path - The path to which to save file
         * @param {String} name - The file name
         * @return {Promise} - a promise resolved once data is returned
         */
        function saveFile(path, name) {
          return _httpGet([baseUrl, "saveFile", encodeURIComponent(path), name].join("/"));
        }

        /**
         * Returns the recent files for the connected repository
         *
         * @return {Promise} - a promise resolved once data is returned
         */
        function getRecentFiles() {
          return _httpGet([baseUrl, "recentFiles"].join("/"));
        }

        /**
         * Returns the 5 recent searches performed
         *
         * @return {Promise} - a promise resolved once data is returned
         */
        function getRecentSearches() {
          return _httpGet([baseUrl, "recentSearches"].join("/"));
        }

        /**
         * Stores the most recent search performed
         *
         * @param {String} recentSearch - The most recent search to be stored
         * @return {Promise} - a promise resolved once data is returned
         */
        function storeRecentSearch(recentSearch) {
          return _httpGet([baseUrl, "storeRecentSearch", encodeURIComponent(recentSearch) + "?ts=" + new Date().getTime()].join("/"));
        }

        /**
         * Renames a repository object
         *
         * @param {String} id - The repository object id
         * @param {String} name - The new name
         * @param {String} path - The new path
         * @param {String} type - The object type
         * @return {Promise} - a promise resolved once data is returned
         */
        function rename(id, name, path, type) {
          return _httpPost([baseUrl, "rename", encodeURIComponent(id), encodeURIComponent(path), name, type].join("/"));
        }

        /**
         * Create a new folder
         *
         * @param {String} parent - The parent folder
         * @param {String} name - The new folder name
         * @return {Promise} - a promise resolved once data is returned
         */
        function create(parent, name) {
          return _httpPost([baseUrl, "create", encodeURIComponent(parent), name].join("/"), null);
        }

        /**
         * Remove a repository object
         *
         * @param {String} id - The repository object id
         * @param {String} type - The object type
         * @return {Promise} - a promise resolved once data is returned
         */
        function remove(id, type) {
          return _httpDelete([baseUrl, "remove", encodeURIComponent(id), type].join("/"));
        }

        /**
         * Open a recent file
         *
         * @param {String} repo - The name of the repository
         * @param {String} id - The repository object id
         * @return {Promise} - a promise resolved once data is returned
         */
        function openRecent(repo, id) {
          return _httpGet([baseUrl, "loadRecent", repo, id].join("/"));
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} url - the url
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _httpGet(url) {
          return _wrapHttp("GET", url);
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} url - the url
         * @param {String} data - the post data
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _httpPost(url, data) {
          return _wrapHttp("POST", url, data);
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} url - the url
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _httpDelete(url) {
          return _wrapHttp("DELETE", url);
        }

        /**
         * Wraps the http angular service to provide sensible defaults
         *
         * @param {String} method - the http method to use
         * @param {String} url - the url
         * @param {String} data - the data to send to the server
         * @return {Promise} - a promise to be resolved as soon as we get confirmation from the server.
         * @private
         */
        function _wrapHttp(method, url, data) {
          var options = {
            method: method,
            url: _cacheBust(url),
            headers: {
              Accept: "application/json"
            }
          };
          if (data !== null) {
            options.data = data;
          }
          return $http(options);
        }

        function _cacheBust(url) {
          var value = Math.round(new Date().getTime() / 1000) + Math.random();
          if (url.indexOf("?") != -1) {
            url += "&v=" + value;
          } else {
            url += "?v=" + value;
          }
          return url;
        }
      }
    });
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import SubPage from '../Components/SubPage'

class About extends Component {
  render() {
    return (
      <SubPage pageName="About Me">

        <Biography/>
      </SubPage>
    );
  }
}

function Biography() {
  return (

        Ashwin Nath Chatterji

        Software Engineer - DXC Techology

        BBA (Marketing), Nanyang Technological University

        I taught myself to write software and made it my profession. I write enterprise software for a living in Java but I do not restrict my technology stack to only that. I spend most of my free time experimenting with slightly more modern technology such as Redis, Node.js, React.js etc.

        <button onClick={gotoResume}
          className="btn resume-btn">
          Download Resume
        </button>

  )
}

function gotoResume() {
  window.location = "/resume";
}

function gotoWebsite(event) {
  window.location = icons[event.target.id].website;
}

const icons = {
  react: {
    icon: "devicon-react-original",
    desc: "Modern frontend web development.",
    website: "https://facebook.github.io/react/"
  },
  nodejs: {
    icon: "devicon-nodejs-plain",
    desc: "Build highly concurrent software with Node.",
    website: "https://nodejs.org/en/"
  },
  java: {
    icon: "devicon-java-plain",
    desc: "Enterprise software development.",
    website: "https://www.java.com/en/"
  }
};

function Summary() {
  return (

      {Object.entries(icons).map(([type, value]) => {
        // Please note that the background colours per icon
        return (

            <i id={type}
              onClick={gotoWebsite}
              className={`icon ${value.icon}`}/>

              {value.desc}

        )
      })}

  )
}

export default About;
<commit_msg>changed some wording<commit_after>import React, { Component } from 'react';
import SubPage from '../Components/SubPage'

class About extends Component {
  render() {
    return (
      <SubPage pageName="About Me">

        <Biography/>
      </SubPage>
    );
  }
}

function Biography() {
  return (

        Ashwin Nath Chatterji

        Software Engineer - DXC Techology

        BBA (Marketing), Nanyang Technological University

        I taught myself to write software and made it my profession. I write enterprise software for a living using Java but I do not restrict my technology stack to only that. I spend most of my free time experimenting with slightly more modern technology such as Redis, Node.js, React.js etc.

        <button onClick={gotoResume}
          className="btn resume-btn">
          Download Resume
        </button>

  )
}

function gotoResume() {
  window.location = "/resume";
}

function gotoWebsite(event) {
  window.location = icons[event.target.id].website;
}

const icons = {
  react: {
    icon: "devicon-react-original",
    desc: "Modern frontend web development.",
    website: "https://facebook.github.io/react/"
  },
  nodejs: {
    icon: "devicon-nodejs-plain",
    desc: "Build highly concurrent software with Node.",
    website: "https://nodejs.org/en/"
  },
  java: {
    icon: "devicon-java-plain",
    desc: "Enterprise software development.",
    website: "https://www.java.com/en/"
  }
};

function Summary() {
  return (

      {Object.entries(icons).map(([type, value]) => {
        // Please note that the background colours per icon
        return (

            <i id={type}
              onClick={gotoWebsite}
              className={`icon ${value.icon}`}/>

              {value.desc}

        )
      })}

  )
}

export default About;
<|endoftext|>


<commit_before>import { userMessage } from './messageReducers';
import * as types from './messageActionTypes';
import expect from 'expect.js';

describe('userMessages Reducer', function() {
  describe(`userMessages() -  ${ types.SEND_MESSAGE }`, function() {
    const testUid = 123;
    const testMessage = 'a test message';
    const testCreatedAt = 999343454;

    const result = userMessage(
      undefined, {
        type: types.SEND_MESSAGE,
        uid: testUid,
        message: testMessage,
        createdAt: testCreatedAt
      });

    it('is expected to return an object', function() {
      expect(result).to.be.an('object');
    });
    it('is expected to return an object with items array', function() {
      expect(result.items).to.be.an('array');
    });

    describe('items[] array in userMessage', function() {
      it('is expected to have length 1', function() {
        expect(result.items).to.have.length(1);
      });
      it('is expected to have length 2 after next action', function() {
        expect(
          userMessage(
            result, {
              type: types.SEND_MESSAGE,
              uid: testUid,
              message: testMessage,
              createdAt: testCreatedAt
            }).items
        ).to.have.length(2);
      })
    });

    it('is expected to return the uid, message and createdAt properties from action', function() {
      expect(result.items[0].uid).to.be(testUid);
      expect(result.items[0].message).to.be(testMessage);
      expect(result.items[0].createdAt).to.be(testCreatedAt);
    });
    it('is expected to trigger isSending to true', function() {
      expect(result.isSending).to.be(true);
    });
  });

  describe(`userMessages() -  ${ types.SEND_MESSAGE_SUCCESS }`, function() {
    it('is expected to return an object', function() {
      expect(
        userMessage(undefined, {
          type: types.SEND_MESSAGE_SUCCESS
        })
      ).to.be.an('object');
    });
    it('is expected to trigger isSending to false', function() {
      expect(
        userMessage(undefined, {
          type: types.SEND_MESSAGE_SUCCESS
        }).isSending
      ).to.be(false);
    });
  });

  describe(`userMessages() -  ${ types.SEND_MESSAGE_ERROR }`, function() {
    it('is expected to return an object', function() {
      expect(userMessage(undefined, {
        type: types.SEND_MESSAGE_ERROR
      })).to.be.an('object');
    });
    it('is expected to trigger hasError to true', function() {
      expect(userMessage(undefined, {
        type: types.SEND_MESSAGE_ERROR
      }).hasError).to.be(true);
    });
    it('is expected to add errorMessage to the state', function() {
      const testErrorMessage = 'this is test error';
      const errorState = userMessage(
        undefined,
        {
          type: types.SEND_MESSAGE_ERROR,
          errorMessage: testErrorMessage
        }
      );

      expect(errorState.errorMessage).to.be(testErrorMessage);
    });
  });
});
<commit_msg>write tests for messages reducer - retrieving message<commit_after>import { userMessage, messages } from './messageReducers';
import * as types from './messageActionTypes';
import expect from 'expect.js';

describe('userMessages Reducer', function() {
  describe(`userMessages() -  ${ types.SEND_MESSAGE }`, function() {
    const testUid = 123;
    const testMessage = 'a test message';
    const testCreatedAt = 999343454;

    const result = userMessage(
      undefined, {
        type: types.SEND_MESSAGE,
        uid: testUid,
        message: testMessage,
        createdAt: testCreatedAt
      });

    it('is expected to return an object', function() {
      expect(result).to.be.an('object');
    });
    it('is expected to return an object with items array', function() {
      expect(result.items).to.be.an('array');
    });

    describe('items[] array in userMessage', function() {
      it('is expected to have length 1', function() {
        expect(result.items).to.have.length(1);
      });
      it('is expected to have length 2 after next action', function() {
        expect(
          userMessage(
            result, {
              type: types.SEND_MESSAGE,
              uid: testUid,
              message: testMessage,
              createdAt: testCreatedAt
            }).items
        ).to.have.length(2);
      })
    });

    it('is expected to return the uid, message and createdAt properties from action', function() {
      expect(result.items[0].uid).to.be(testUid);
      expect(result.items[0].message).to.be(testMessage);
      expect(result.items[0].createdAt).to.be(testCreatedAt);
    });
    it('is expected to trigger isSending to true', function() {
      expect(result.isSending).to.be(true);
    });
  });

  describe(`userMessages() -  ${ types.SEND_MESSAGE_SUCCESS }`, function() {
    it('is expected to return an object', function() {
      expect(
        userMessage(undefined, {
          type: types.SEND_MESSAGE_SUCCESS
        })
      ).to.be.an('object');
    });
    it('is expected to trigger isSending to false', function() {
      expect(
        userMessage(undefined, {
          type: types.SEND_MESSAGE_SUCCESS
        }).isSending
      ).to.be(false);
    });
  });

  describe(`userMessages() -  ${ types.SEND_MESSAGE_ERROR }`, function() {
    it('is expected to return an object', function() {
      expect(userMessage(undefined, {
        type: types.SEND_MESSAGE_ERROR
      })).to.be.an('object');
    });
    it('is expected to trigger hasError to true', function() {
      expect(userMessage(undefined, {
        type: types.SEND_MESSAGE_ERROR
      }).hasError).to.be(true);
    });
    it('is expected to add errorMessage to the state', function() {
      const testErrorMessage = 'this is test error';
      const errorState = userMessage(
        undefined,
        {
          type: types.SEND_MESSAGE_ERROR,
          errorMessage: testErrorMessage
        }
      );

      expect(errorState.errorMessage).to.be(testErrorMessage);
    });
  });
});

describe('messages Reducer', function() {
  describe(`messages() - ${ types.RETRIEVE_MESSAGE }`, function() {
    it('is expected to return an array', function() {
      expect(
        messages(undefined, { type: types.RETRIEVE_MESSAGE })
      ).to.be.an('array');
    });
    it('is expected to add the message and uid props as an object to array', function() {
      const testUid = 123;
      const testMessage = 'this is a test message';

      const result = messages(
        undefined,
        {
          type: types.RETRIEVE_MESSAGE,
          message: testMessage,
          uid: testUid
        }
      );

      expect(result).to.have.length(1);
      expect(result[0].message).to.be(testMessage);
      expect(result[0].uid).to.be(testUid);

    });
    it('is expected to add the second message with keeping a previous state', function() {
      const testUid = 123;
      const testMessage = 'this is a test message';

      const testUid2 = 123;
      const testMessage2 = 'this is a test message';

      const result = messages(
        [
          {
            uid: testUid,
            message: testMessage
          }
        ],
        {
          type: types.RETRIEVE_MESSAGE,
          message: testMessage2,
          uid: testUid2
        }
      );

      expect(result).to.have.length(2);
      expect(result[0].message).to.be(testMessage);
      expect(result[0].uid).to.be(testUid);

      expect(result[1].message).to.be(testMessage2);
      expect(result[1].uid).to.be(testUid2);

    });
  });
});
<|endoftext|>


<commit_before>var childProcess = require("child_process");

var processState = {
  "available": 0,
  "executing": 1
}

function Pool(size, file, options) {
  size = size || 2;
  this.id = 1;
  this.pending = {};
  this.messageQueue = [];

  this.procs = Array
    .apply(null, Array(size))
    .map(() => ({
      state: processState.available,
      handle: childProcess.fork(file, [], Object.assign({
        cwd: process.cwd(),
        env: process.env,
        silent: true
      }, options))
    }));

  this.procs.forEach(proc => registerProcHandlers(this, proc));
}

Pool.prototype.send = function(type, data, proc) {
  var id = this.id++;

  return new Promise((resolve, reject) => {
    this.messageQueue.push({
      message: {
        id: id,
        type: type,
        data: data
      },
      resolve: resolve,
      reject: reject
    });

    // console.log("queue", id, message.type);
    processNextMessage(this, proc);
  })
  .then((result) => {
    processNextMessage(this);
    return result;
  });
};

function processNextMessage(pool, proc) {
  if (!pool.messageQueue.length) {
    return;
  }

  var availableProc = proc && proc.state === processState.available ? proc : pool.procs.find((proc) => proc.state === processState.available);

  if (availableProc) {
    var envelope = pool.messageQueue.shift();
    pool.pending[envelope.message.id] = envelope;
    availableProc.state = processState.executing;
    availableProc.handle.send(envelope.message);
    // console.log(`process [${availableProc.handle.pid}]`, envelope.message.id, envelope.message.content.type, envelope.message.content.data.name || "");
  }
}

function registerProcHandlers(pool, proc) {
  proc.handle
    .on("error", (error) => {
      console.error(`===> process error [${proc.handle.pid}]` + error);
    })
    .on("message", (message) => {
      if (pool.pending.hasOwnProperty(message.id)) {
        proc.state = processState.available;
        handleResult(message, pool.pending[message.id], proc);
        delete pool.pending[message.id];
      }
      // else if (message.id && pool.forwarding.hasOwnProperty(message.type)) {
      //   Promise.resolve(pool.forwarding[message.type](message.data))
      //     .then((data) => { proc.handle.send({ id: message.id, data: data }); })
      //     .catch((error) => { proc.handle.send({ id: message.id, error: error }); });
      // }
    });
}

function handleResult(message, pending, proc) {
  message.error ?
    pending.reject(message.error) :
    pending.resolve(message.data);
}

module.exports = Pool;
<commit_msg>added ability to detect max processors so that we don't create more processes than we can really take advantage of<commit_after>var childProcess = require("child_process");
var maxProcess = require("os").cpus().length;

var processState = {
  "available": 0,
  "executing": 1
}

function Pool(file, options) {
  var settings = Object.assign({
    cwd: process.cwd(),
    env: process.env,
    silent: true,
    size: 2
  }, options);

  var size = Math.min(options.size, maxProcess);

  this.id = 1;
  this.pending = {};
  this.messageQueue = [];

  this.procs = Array.apply(null, Array(size)).map(() => ({
    state: processState.available,
    handle: childProcess.fork(file, [], settings)
  }));

  this.procs.forEach(proc => registerProcHandlers(this, proc));
}

Pool.prototype.send = function(type, data, proc) {
  var id = this.id++;

  return new Promise((resolve, reject) => {
    this.messageQueue.push({
      message: {
        id: id,
        type: type,
        data: data
      },
      resolve: resolve,
      reject: reject
    });

    // console.log("queue", id, message.type);
    processNextMessage(this, proc);
  })
  .then((result) => {
    processNextMessage(this);
    return result;
  });
};

function processNextMessage(pool, proc) {
  if (!pool.messageQueue.length) {
    return;
  }

  var availableProc = proc && proc.state === processState.available ? proc : pool.procs.find((proc) => proc.state === processState.available);

  if (availableProc) {
    var envelope = pool.messageQueue.shift(); // FILO
    pool.pending[envelope.message.id] = envelope;
    availableProc.state = processState.executing;
    availableProc.handle.send(envelope.message);
    // console.log(`process [${availableProc.handle.pid}]`, envelope.message.id, envelope.message.content.type, envelope.message.content.data.name || "");
  }
}

function registerProcHandlers(pool, proc) {
  proc.handle
    .on("error", (error) => {
      console.error(`===> process error [${proc.handle.pid}]` + error);
    })
    .on("message", (message) => {
      if (pool.pending.hasOwnProperty(message.id)) {
        proc.state = processState.available;
        handleResult(message, pool.pending[message.id], proc);
        delete pool.pending[message.id];
      }
      // else if (message.id && pool.forwarding.hasOwnProperty(message.type)) {
      //   Promise.resolve(pool.forwarding[message.type](message.data))
      //     .then((data) => { proc.handle.send({ id: message.id, data: data }); })
      //     .catch((error) => { proc.handle.send({ id: message.id, error: error }); });
      // }
    });
}

function handleResult(message, pending, proc) {
  message.error ?
    pending.reject(message.error) :
    pending.resolve(message.data);
}

module.exports = Pool;
<|endoftext|>


<commit_before>/* jshint browser: true */
/* globals define */
define(function() {
	window.paraffinCoverageResults = ''; //Prevent mocha to detect the iframe as new global

	var stringify = window.JSON && JSON.stringify || function (obj) {
		var t = typeof obj;
		if (t !== 'object' || obj === null) {
			if (t === 'string') obj = '"' + obj.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
			return '' + obj;
		} else {
			var json = [], arr = (obj.constructor === Array);
			for (var k in obj) {
				json.push((arr ? '' : stringify(k) + ':') + stringify(obj[k]));
			}
			return (arr ? '[' : '{') + json + (arr ? ']' : '}');
		}
	};

	return function(runner) {
		runner.on('end', function() {
			var COVERAGE_KEY = '__coverage__'; //Coverage published by istanbul
			if (window[COVERAGE_KEY]) {
				// Poor man AJAX
				var iframe = document.createElement('iframe');
				iframe.style.display = 'none';
				iframe.name = 'paraffinCoverageResults';
				document.body.appendChild(iframe);
				var ta = document.createElement('textarea');
				ta.name = 'coverage';
				ta.value = stringify(window[COVERAGE_KEY]);
				var form = document.createElement('form');
				form.method = 'post';
				form.target = 'paraffinCoverageResults';
				form.action = location.protocol + '//' + location.host + '/postResults';
				form.appendChild(ta);
				form.style.display = 'none';
				document.body.appendChild(form);
				form.submit();
			}
		});
	};
});
<commit_msg>Avoid new window in IE7 when posting coverage data<commit_after>/* jshint browser: true */
/* globals define */
define(function() {
	window.paraffinCoverageResults = ''; //Prevent mocha to detect the iframe as new global

	var stringify = window.JSON && JSON.stringify || function (obj) {
		var t = typeof obj;
		if (t !== 'object' || obj === null) {
			if (t === 'string') obj = '"' + obj.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
			return '' + obj;
		} else {
			var json = [], arr = (obj.constructor === Array);
			for (var k in obj) {
				json.push((arr ? '' : stringify(k) + ':') + stringify(obj[k]));
			}
			return (arr ? '[' : '{') + json + (arr ? ']' : '}');
		}
	};

	return function(runner) {
		runner.on('end', function() {
			var COVERAGE_KEY = '__coverage__'; //Coverage published by istanbul
			if (window[COVERAGE_KEY]) {
				// Poor man AJAX
				var actionUrl = location.protocol + '//' + location.host + '/postResults';
				var div = document.createElement('div');
				div.innerHTML = '<iframe name="paraffinCoverageResults" style="display:none"></iframe>' +
				                '<form method="post" target="paraffinCoverageResults" action="' + actionUrl + '">' +
				                    '<textarea style="display:none" name="coverage" />' +
				                '</form>';
				document.body.appendChild(div);
				div.getElementsByTagName('textarea')[0].value = stringify(window[COVERAGE_KEY]);
				div.getElementsByTagName('form')[0].submit();
			}
		});
	};
});
<|endoftext|>


<commit_before>/*
 * Copyright 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.api.rest.subscribe',
    dependencies: ['og.api.common', 'og.api.rest', 'og.common.routes'],
    obj: function () {
        var common = og.api.common;
        var api = og.api.rest;
        var subscribe;
        var RESUBSCRIBE = 10000;
        var warn = og.dev.warn;
        subscribe = api.handshake.get.partial({handler: function (result) {
            var listen, fire_updates;
            if (result.error) {
                warn(api.name + ': handshake failed\n', result.message);
                return setTimeout(subscribe, RESUBSCRIBE);
            }
            api.id = result.data['clientId'];
            fire_updates = function (reset, result) {
                var current = og.common.routes.current();
                if (reset && api.disconnected) {
                    api.disconnected = false;
                    api.fire('reconnect');
                }
                // throw out stale registrations
                api.registrations = api.registrations.filter(function (reg) { return !common.request_expired(reg, current); });
                // fire all updates if connection is reset
                if (reset) {
                    api.registrations = api.registrations.filter(
                        function (reg) {return reg.update($.extend({reset: true}, reg)) && false; }
                    );
                    return api.registrations;
                }
                result.data.updates.filter(function (update) {
                    var simple = typeof update === 'string', promise, request;
                    if (!simple && (promise = (request = api.outstanding_requests[update.id]) && request.promise)) {
                        promise.deferred.resolve({
                            error: false, data: null, meta: {id: update.message.split('/').pop()}, promise: promise.id
                        });
                        delete api.outstanding_requests[promise.id];
                    }
                    return simple;
                }).forEach(
                    function (update) {
                        var lcv, reg;
                        var len = api.registrations.length;
                        for (lcv = 0; lcv < len; lcv += 1) {
                            reg = api.registrations[lcv];
                            if (reg && reg.url === update) {
                                api.registrations[lcv] = null;
                                reg.update(reg);
                            }
                        }
                        api.registrations = api.registrations.filter(Boolean);
                    }
                );
            };
            fire_updates(true, null); // there are no registrations when subscribe() is called unless the connection's been reset
            listen = function () {
                api.updates.get({handler: function (result) {
                    if (result.error) {
                        if (!api.disconnected) {
                            api.disconnected = true;
                            api.fire('disconnect');
                            api.id = null;
                        }
                        warn(api.name + ': subscription failed\n', result.message);
                        return setTimeout(subscribe, RESUBSCRIBE);
                    }
                    if (!result.data || !result.data.updates.length) {
                        return setTimeout(listen, common.INSTANT);
                    }
                    fire_updates(false, result);
                    setTimeout(listen, common.INSTANT);
                }});
            };
            listen();
        }});
        return subscribe;
    }
});
<commit_msg>PLAT-4546 - Revert unwanted changes<commit_after>/*
 * Copyright 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.api.rest.subscribe',
    dependencies: ['og.api.common', 'og.api.rest', 'og.common.routes'],
    obj: function () {
        var common = og.api.common, api = og.api.rest, str = common.str, check = common.check,
            subscribe, RESUBSCRIBE = 10000 /* 10s */, warn = og.dev.warn;
        return subscribe = api.handshake.get.partial({handler: function (result) {
            var listen, fire_updates;
            if (result.error)
                return warn(api.name + ': handshake failed\n', result.message), setTimeout(subscribe, RESUBSCRIBE);
            api.id = result.data['clientId'];
            (fire_updates = function (reset, result) {
                var current = og.common.routes.current();
                if (reset && api.disconnected) (api.disconnected = false), api.fire('reconnect');
                api.registrations = api.registrations // throw out stale registrations
                    .filter(function (reg) {return !common.request_expired(reg, current);});
                if (reset) return api.registrations = api.registrations // fire all updates if connection is reset
                    .filter(function (reg) {return reg.update($.extend({reset: true}, reg)) && false;});
                result.data.updates.filter(function (update) {
                    var simple = typeof update === 'string', promise, request;
                    if (!simple && (promise = (request = api.outstanding_requests[update.id]) && request.promise)) {
                        promise.deferred.resolve({
                            error: false, data: null, meta: {id: update.message.split('/').pop()}, promise: promise.id
                        });
                        delete api.outstanding_requests[promise.id];
                    }
                    return simple;
                }).forEach(function (update) {
                    var lcv, len = api.registrations.length, reg;
                    for (lcv = 0; lcv < len; lcv += 1)
                        if ((reg = api.registrations[lcv]) && reg.url === update)
                            (api.registrations[lcv] = null), reg.update(reg);
                    api.registrations = api.registrations.filter(Boolean);
                });
            })(true, null); // there are no registrations when subscribe() is called unless the connection's been reset
            (listen = function () {
                api.updates.get({handler: function (result) {
                    if (result.error) {
                        if (!api.disconnected) (api.disconnected = true), api.fire('disconnect'), (api.id = null);
                        warn(api.name + ': subscription failed\n', result.message);
                        return setTimeout(subscribe, RESUBSCRIBE);
                    }
                    if (!result.data || !result.data.updates.length) return setTimeout(listen, common.INSTANT);
                    fire_updates(false, result);
                    setTimeout(listen, common.INSTANT);
                }});
            })();
        }});
    }
});
<|endoftext|>


<commit_before>import dataRows from '../common/dataRows';
import { defTable } from '../support/constants';
import formToUrl from '../common/formToUrl';
import getElementsByTagName from '../common/getElementsByTagName';
import getText from '../common/getText';
import on from '../common/on';
import { pCC } from '../support/layout';
import searchPlayerHref from '../common/searchPlayerHref';
import setInnerHtml from '../dom/setInnerHtml';

function globalQuestAllowBack(topTable) { // jQuery
  const thisSelect = getElementsByTagName('select', topTable)[0];
  $(thisSelect).off();
  on(pCC, 'change', (e) => formToUrl(e.target.form));
}

function playerLink(el) {
  const aCell = el.cells[1];
  setInnerHtml(searchPlayerHref(getText(aCell)), aCell);
}

export default function globalQuest() {
  const topTable = getElementsByTagName(defTable, pCC)[3];
  globalQuestAllowBack(topTable);
  dataRows(topTable.rows, 4, 1).forEach(playerLink);
}
<commit_msg>fix bug in globalQuest (#322)<commit_after>import dataRows from '../common/dataRows';
import { defTable } from '../support/constants';
import formToUrl from '../common/formToUrl';
import getElementsByTagName from '../common/getElementsByTagName';
import getText from '../common/getText';
import on from '../common/on';
import { pCC } from '../support/layout';
import searchPlayerHref from '../common/searchPlayerHref';
import setInnerHtml from '../dom/setInnerHtml';

function globalQuestAllowBack(topTable) { // jQuery
  const thisSelect = getElementsByTagName('select', topTable)[0];
  $(thisSelect).off();
  on(pCC, 'change', (e) => formToUrl({ target: e.target.form }));
}

function playerLink(el) {
  const aCell = el.cells[1];
  setInnerHtml(searchPlayerHref(getText(aCell)), aCell);
}

export default function globalQuest() {
  const topTable = getElementsByTagName(defTable, pCC)[3];
  globalQuestAllowBack(topTable);
  dataRows(topTable.rows, 4, 1).forEach(playerLink);
}
<|endoftext|>


<commit_before>/**
 * 需要支持：
 * 1. 大数据，后台分页
 * 2. 少量数据全加载，前端分页
 */

var Vue = require('lib/vue');
var App = require('common/app');

Vue.component('datagrid', {
    template: __inline('main.html'),
    data: function() {
        return {
            tableElem: undefined, //table的jQuery对象
            tableId: undefined // table的Id
        };
    },
    ready: function() {
        // 缓存该值，避免重复获取
        this.$set('tableElem', $(this.$el));

        _init(this);
    }
});

function _init(vm) {
    $(function() {
        initTable(vm);
    });
}

var initTable = function(vm) {
    var tableElem = vm.tableElem;

    /* Table tools samples: https://www.datatables.net/release-datatables/extras/TableTools/ */

    /* Set tabletools buttons and button container */

    $.extend(true, $.fn.DataTable.TableTools.classes, {
        "container": "btn-group tabletools-dropdown-on-portlet",
        "buttons": {
            "normal": "btn btn-sm btn-default",
            "disabled": "btn btn-sm btn-default disabled"
        },
        "collection": {
            "container": "DTTT_dropdown dropdown-menu tabletools-dropdown-menu"
        }
    });

    var oTable = tableElem.dataTable({
        "order": [
            [0, 'asc']
        ],

        "lengthMenu": [
            [10, 20, 50, -1],
            [10, 20, 50, "All"] // change per page values here
        ],

        /**
         * https://datatables.net/reference/option/pageLength
         * Change the initial page length (number of rows per page).
         * Default value: 10.
         *
         * 设置每一页展示多少条记录，最好在lengthMenu中定义了该值，否则会导致lengthMenu中没有选中的值
         */
        "pageLength": 10,

        "language": {
            "info": "第 _START_ 条到第 _END_ 条记录 (总计 _TOTAL_ 条记录)",
            "processing": "加载中，请稍后...",
            "search": "搜索: ",
            "infoFiltered": "从 _MAX_ 条记录过滤后的结果"
        },

        "dom": "<'row' <'col-md-12'T>><'row'<'col-md-6 col-sm-12'l><'col-md-6 col-sm-12'f>r><'table-scrollable't><'row'<'col-md-5 col-sm-12'i><'col-md-7 col-sm-12'p>>", // horizobtal scrollable datatable

        "tableTools": {
            "sSwfPath": "/static/plugins/datatables/extensions/TableTools/swf/copy_csv_xls_pdf.swf",
            "aButtons": [{
                "sExtends": "pdf",
                "sButtonText": "PDF"
            }, {
                "sExtends": "csv",
                "sButtonText": "CSV"
            }, {
                "sExtends": "xls",
                "sButtonText": "Excel"
            }, {
                "sExtends": "print",
                "sButtonText": "Print",
                "sInfo": 'Please press "CTR+P" to print or "ESC" to quit',
                "sMessage": "Generated by DataTables"
            }]
        },
        "ordering": false, //关闭列排序

        "processing": true,

        /**
         * https://datatables.net/reference/option/serverSide
         * 服务器模式，在分页和查找时会重新去请求数据
         */
        "serverSide": true,

        /**
         * https://datatables.net/reference/option/deferRender
         * 默认是 false 。即默认情况下，DataTables会将获得的数据全部渲染成 HTML 元素，但这种处理在大数据时会影响性能，尤其在 IE6-IE8。
         * 推荐在后台分页处理时，将其设置为 true，即延迟渲染，按需渲染。
         */
        // "deferRender": true,

        /**
         * https://datatables.net/reference/option/destroy
         * Destroy any existing table matching the selector and replace with the new options.
         * Default value: false.
         *
         * 如果某个table已经被渲染成了DataTables，是否采用销毁的方式来重渲染表格。
         */
        // "destroy": true,
        "ajax": {
            // "url": "/static/mock/datagrid.json",
            "url": "https://www.datatables.net/examples/server_side/scripts/post.php",
            "type": "POST",
            "data": function(d) {
                d.myKey = "myValue";
                // d.custom = $('#myInput').val();
                // etc
                // 此处可以追加一些请求参数
            }
        },
        "columns": [{
            "data": "first_name",
            "title": "first_name"
        }, {
            "data": "last_name",
            "title": "last_name"
        }, {
            "data": "position",
            "title": "position"
        }, {
            "data": "office",
            "title": "office"
        }, {
            "data": "start_date",
            "title": "start_date"
        }, {
            "data": "salary",
            "title": "salary",
            "render": function(data, type, row, meta ) {
                return data.replace(/\$/g,"￥");
            }
        }]

        // "columnDefs": aoColumnDefs,
        // "columns": aoColumns
    });

    // 获取并缓存table的id
    vm.$set('tableId', tableElem.attr('id'));

    // datatable creates the table wrapper by adding with id {your_table_jd}_wrapper
    var tableWrapper = $('#' + vm.tableId + '_wrapper');

    // initialize select2 dropdown
    tableWrapper.find('.dataTables_length select').select2();
};
<commit_msg>datagrid:调试columnDefs<commit_after>/**
 * 需要支持：
 * 1. 大数据，后台分页
 * 2. 少量数据全加载，前端分页
 */

var Vue = require('lib/vue');
var App = require('common/app');

Vue.component('datagrid', {
    template: __inline('main.html'),
    data: function() {
        return {
            tableElem: undefined, //table的jQuery对象
            tableId: undefined // table的Id
        };
    },
    ready: function() {
        // 缓存该值，避免重复获取
        this.$set('tableElem', $(this.$el));

        _init(this);
    }
});

function _init(vm) {
    $(function() {
        initTable(vm);
    });
}

var initTable = function(vm) {
    var tableElem = vm.tableElem;

    /* Table tools samples: https://www.datatables.net/release-datatables/extras/TableTools/ */

    /* Set tabletools buttons and button container */

    $.extend(true, $.fn.DataTable.TableTools.classes, {
        "container": "btn-group tabletools-dropdown-on-portlet",
        "buttons": {
            "normal": "btn btn-sm btn-default",
            "disabled": "btn btn-sm btn-default disabled"
        },
        "collection": {
            "container": "DTTT_dropdown dropdown-menu tabletools-dropdown-menu"
        }
    });

    var oTable = tableElem.dataTable({
        "order": [
            [0, 'asc']
        ],

        "lengthMenu": [
            [10, 20, 50, -1],
            [10, 20, 50, "All"] // change per page values here
        ],

        /**
         * https://datatables.net/reference/option/pageLength
         * Change the initial page length (number of rows per page).
         * Default value: 10.
         *
         * 设置每一页展示多少条记录，最好在lengthMenu中定义了该值，否则会导致lengthMenu中没有选中的值
         */
        "pageLength": 10,

        "language": {
            "info": "第 _START_ 条到第 _END_ 条记录 (总计 _TOTAL_ 条记录)",
            "processing": "加载中，请稍后...",
            "search": "搜索: ",
            "infoFiltered": "从 _MAX_ 条记录过滤后的结果"
        },

        "dom": "<'row' <'col-md-12'T>><'row'<'col-md-6 col-sm-12'l><'col-md-6 col-sm-12'f>r><'table-scrollable't><'row'<'col-md-5 col-sm-12'i><'col-md-7 col-sm-12'p>>", // horizobtal scrollable datatable

        "tableTools": {
            "sSwfPath": "/static/plugins/datatables/extensions/TableTools/swf/copy_csv_xls_pdf.swf",
            "aButtons": [{
                "sExtends": "pdf",
                "sButtonText": "PDF"
            }, {
                "sExtends": "csv",
                "sButtonText": "CSV"
            }, {
                "sExtends": "xls",
                "sButtonText": "Excel"
            }, {
                "sExtends": "print",
                "sButtonText": "Print",
                "sInfo": 'Please press "CTR+P" to print or "ESC" to quit',
                "sMessage": "Generated by DataTables"
            }]
        },
        "ordering": false, //关闭列排序

        "processing": true,

        /**
         * https://datatables.net/reference/option/serverSide
         * 服务器模式，在分页和查找时会重新去请求数据
         */
        "serverSide": true,

        /**
         * https://datatables.net/reference/option/deferRender
         * 默认是 false 。即默认情况下，DataTables会将获得的数据全部渲染成 HTML 元素，但这种处理在大数据时会影响性能，尤其在 IE6-IE8。
         * 推荐在后台分页处理时，将其设置为 true，即延迟渲染，按需渲染。
         */
        // "deferRender": true,

        /**
         * https://datatables.net/reference/option/destroy
         * Destroy any existing table matching the selector and replace with the new options.
         * Default value: false.
         *
         * 如果某个table已经被渲染成了DataTables，是否采用销毁的方式来重渲染表格。
         */
        // "destroy": true,
        "ajax": {
            // "url": "/static/mock/datagrid.json",
            "url": "https://www.datatables.net/examples/server_side/scripts/post.php",
            "type": "POST",
            "data": function(d) {
                d.myKey = "myValue";
                // d.custom = $('#myInput').val();
                // etc
                // 此处可以追加一些请求参数
            }
        },
        "columns": [{
            "data": "first_name",
            "title": "first_name"
        }, {
            "data": "last_name",
            "title": "last_name"
        }, {
            "data": "position",
            "title": "position"
        }, {
            "data": "office",
            "title": "office"
        }, {
            "data": "start_date",
            "title": "start_date"
        }, {
            "data": "salary",
            "title": "salary",
            "render": function(data, type, row, meta) {
                return data.replace(/\$/g, "￥");
            }
        }],

        /**
         * https://datatables.net/reference/option/columnDefs
         * Set column definition initialisation properties.
         *
         * 非常像 columns，用于定义如何初始化属性，但它不要求每一列都要定义。因为下面的冲突规则，因此建议如果需要动态改变的，则使用 columnDefs 来定义，例如 visible 属性，这样便于控制。而且也方便集中批量配置。
         *
         * 定义冲突规则：
         * 1. columns 中的优先级要高
         * 2. columnDefs 中使用数组来定义的属性要比其他的定义的高，比如下例中第一列和第二列将显示，其他列隐藏
         *
         */
        "columnDefs": [{
            targets: [0, 1],
            visible: true
        }, {
            targets: '_all',
            visible: false
        }]

    });

    // 获取并缓存table的id
    vm.$set('tableId', tableElem.attr('id'));

    // datatable creates the table wrapper by adding with id {your_table_jd}_wrapper
    var tableWrapper = $('#' + vm.tableId + '_wrapper');

    // initialize select2 dropdown
    tableWrapper.find('.dataTables_length select').select2();
};
<|endoftext|>


<commit_before>import times from 'lodash/times';

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import {
  View, Text, Animated, PanResponder, Image,
  StyleSheet, Platform
} from 'react-native';

// RATING IMAGES WITH STATIC BACKGROUND COLOR (white)
const STAR_IMAGE = require('./images/star.png');
const HEART_IMAGE = require('./images/heart.png');
const ROCKET_IMAGE = require('./images/rocket.png');
const BELL_IMAGE = require('./images/bell.png');

const TYPES = {
  star: {
    source: STAR_IMAGE,
    color: '#f1c40f',
    backgroundColor: 'white'
  },
  heart: {
    source: HEART_IMAGE,
    color: '#e74c3c',
    backgroundColor: 'white'
  },
  rocket: {
    source: ROCKET_IMAGE,
    color: '#2ecc71',
    backgroundColor: 'white'
  },
  bell: {
    source: BELL_IMAGE,
    color: '#f39c12',
    backgroundColor: 'white'
  }
};

export default class SwipeRating extends Component {
  static defaultProps = {
    type: 'star',
    ratingImage: require('./images/star.png'),
    ratingColor: '#f1c40f',
    ratingBackgroundColor: 'white',
    ratingCount: 5,
    showReadOnlyText: true,
    imageSize: 40,
    minValue: 0
  };

  constructor(props) {
    super(props);
    const { onStartRating, onFinishRating, fractions } = this.props;
    const position = new Animated.ValueXY();

    const panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        if (typeof onStartRating === 'function') {
          onStartRating();
        }
      },
      onPanResponderMove: (event, gesture) => {
        const newPosition = new Animated.ValueXY();
        newPosition.setValue({ x: gesture.dx, y: 0 });
        if (this.state.isComponentMounted) {
          this.setState({position: newPosition, value: gesture.dx});
        }
      },
      onPanResponderRelease: event => {
        const rating = this.getCurrentRating(this.state.value);
        if (rating >= this.props.minValue) {
          if (!fractions) {
            // 'round up' to the nearest rating image
            this.setCurrentRating(rating);
          }
          if (typeof onFinishRating === 'function') onFinishRating(rating);
        }
      }
    });

    this.state = { panResponder, position, display: false, isComponentMounted: false };
  }

  async componentDidMount() {
    try {
      const STAR_IMAGE = await require('./images/star.png');
      const HEART_IMAGE = await require('./images/heart.png');
      const ROCKET_IMAGE = await require('./images/rocket.png');
      const BELL_IMAGE = await require('./images/bell.png');

      this.setState({ display: true, isComponentMounted: false });
    } catch(err) {
      console.log(err)
    }

    this.setCurrentRating(this.props.startingValue);
  }

  componentDidUpdate(prevProps) {
    if (this.props.startingValue !== prevProps.startingValue) {
      this.setCurrentRating(this.props.startingValue);
    }
  }

  getPrimaryViewStyle() {
    const { position } = this.state;
    const { imageSize, ratingCount, type } = this.props;

    const color = TYPES[type].color;

    const width = position.x.interpolate(
      {
        inputRange: [-ratingCount * (imageSize / 2), 0, ratingCount * (imageSize / 2)],
        outputRange: [0, (ratingCount * imageSize) / 2, ratingCount * imageSize],
        extrapolate: 'clamp'
      },
      {
        useNativeDriver: true
      }
    );

    return {
      backgroundColor: color,
      width,
      height: width ? imageSize : 0
    };
  }

  getSecondaryViewStyle() {
    const { position } = this.state;
    const { imageSize, ratingCount, type } = this.props;

    const backgroundColor = TYPES[type].backgroundColor;

    const width = position.x.interpolate(
      {
        inputRange: [-ratingCount * (imageSize / 2), 0, ratingCount * (imageSize / 2)],
        outputRange: [ratingCount * imageSize, (ratingCount * imageSize) / 2, 0],
        extrapolate: 'clamp'
      },
      {
        useNativeDriver: true
      }
    );

    return {
      backgroundColor,
      width,
      height: width ? imageSize : 0
    };
  }

  renderRatings() {
    const { imageSize, ratingCount, type, tintColor } = this.props;
    const source = TYPES[type].source;

    return times(ratingCount, index => (
      <View key={index} style={styles.starContainer}>
        <Image source={source} style={{ width: imageSize, height: imageSize, tintColor }} />
      </View>
    ));
  }

  getCurrentRating(value) {
    // const { value } = this.state;
    const { fractions, imageSize, ratingCount } = this.props;

    const startingValue = ratingCount / 2;
    let currentRating = (this.props.minValue) ? this.props.minValue : 0;

    if (value > (ratingCount * imageSize) / 2) {
      currentRating = ratingCount;
    } else if (value < (-ratingCount * imageSize) / 2) {
      currentRating = (this.props.minValue) ? this.props.minValue : 0;
    } else if (value <= imageSize || value > imageSize) {
      currentRating = startingValue + value / imageSize;
      currentRating = !fractions ? Math.ceil(currentRating) : +currentRating.toFixed(fractions);
    } else {
      currentRating = !fractions ? Math.ceil(startingValue) : +startingValue.toFixed(fractions);
    }

    return currentRating;
  }

  setCurrentRating(rating) {
    const { imageSize, ratingCount } = this.props;

    // `initialRating` corresponds to `startingValue` in the getter. Naming it
    // differently here avoids confusion with `value` below.
    const initialRating = ratingCount / 2;
    let value = null;

    if (rating > ratingCount) {
      value = (ratingCount * imageSize) / 2;
    } else if (rating < 0) {
      value = (-ratingCount * imageSize) / 2;
    } else if (rating < ratingCount / 2 || rating > ratingCount / 2) {
      value = (rating - initialRating) * imageSize;
    } else {
      value = 0;
    }

    const newPosition = new Animated.ValueXY();
    newPosition.setValue({ x: value, y: 0 });
    if (this.state.isComponentMounted) {
      this.setState({position: newPosition, value});
    }
  }

  displayCurrentRating() {
    const { ratingCount, type, readonly, showReadOnlyText, ratingTextColor } = this.props;
    const color = ratingTextColor || TYPES[type].color;

    return (
      <View style={styles.showRatingView}>
        <View style={styles.ratingView}>
          <Text style={[styles.ratingText, { color }]}>Rating:{' '}</Text>
          <Text style={[styles.currentRatingText, { color }]}>{this.getCurrentRating(this.state.value)}</Text>
          <Text style={[styles.maxRatingText, { color }]}>/{ratingCount}</Text>
        </View>
        <View>{readonly && showReadOnlyText && <Text style={[styles.readonlyLabel, { color }]}>(readonly)</Text>}</View>
      </View>
    );
  }

  render() {
    const { readonly, type, ratingImage, ratingColor, ratingBackgroundColor, style, showRating } = this.props;

    if (type === 'custom') {
      let custom = {
        source: ratingImage,
        color: ratingColor,
        backgroundColor: ratingBackgroundColor
      };
      TYPES.custom = custom;
    }

    return (
      this.state.display ?
      <View pointerEvents={readonly ? 'none' : 'auto'} style={style}>
        {showRating && this.displayCurrentRating()}
        <View style={styles.starsWrapper} {...this.state.panResponder.panHandlers}>
          <View style={styles.starsInsideWrapper}>
            <Animated.View style={this.getPrimaryViewStyle()} />
            <Animated.View style={this.getSecondaryViewStyle()} />
          </View>
          {this.renderRatings()}
        </View>
      </View> :
      null
    );
  }

  componentWillUnmount() {
    this.setState({ isComponentMounted: false });
  }

}

const styles = StyleSheet.create({
  starsWrapper: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  starsInsideWrapper: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  showRatingView: {
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    paddingBottom: 5
  },
  ratingView: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingBottom: 5
  },
  ratingText: {
    fontSize: 15,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null,
    color: '#34495e'
  },
  readonlyLabel: {
    justifyContent: 'center',
    alignItems: 'center',
    fontSize: 12,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null,
    color: '#34495a'
  },
  currentRatingText: {
    fontSize: 30,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null
  },
  maxRatingText: {
    fontSize: 18,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null,
    color: '#34495e'
  }
});

const fractionsType = (props, propName, componentName) => {
  if (props[propName]) {
    const value = props[propName];
    if (typeof value === 'number') {
      return value >= 0 && value <= 20
        ? null
        : new Error(`\`${propName}\` in \`${componentName}\` must be between 0 and 20`);
    }

    return new Error(`\`${propName}\` in \`${componentName}\` must be a number`);
  }
};

SwipeRating.propTypes = {
  type: PropTypes.string,
  ratingImage: PropTypes.object,
  ratingColor: PropTypes.string,
  ratingBackgroundColor: PropTypes.string,
  ratingCount: PropTypes.number,
  ratingTextColor: PropTypes.string,
  imageSize: PropTypes.number,
  onStartRating: PropTypes.func,
  onFinishRating: PropTypes.func,
  showRating: PropTypes.bool,
  style: PropTypes.object,
  readonly: PropTypes.bool,
  showReadOnlyText: PropTypes.bool,
  startingValue: PropTypes.number,
  fractions: fractionsType,
  minValue: PropTypes.number
};
<commit_msg>update image source prop to node<commit_after>import times from 'lodash/times';

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import {
  View, Text, Animated, PanResponder, Image,
  StyleSheet, Platform
} from 'react-native';

// RATING IMAGES WITH STATIC BACKGROUND COLOR (white)
const STAR_IMAGE = require('./images/star.png');
const HEART_IMAGE = require('./images/heart.png');
const ROCKET_IMAGE = require('./images/rocket.png');
const BELL_IMAGE = require('./images/bell.png');

const TYPES = {
  star: {
    source: STAR_IMAGE,
    color: '#f1c40f',
    backgroundColor: 'white'
  },
  heart: {
    source: HEART_IMAGE,
    color: '#e74c3c',
    backgroundColor: 'white'
  },
  rocket: {
    source: ROCKET_IMAGE,
    color: '#2ecc71',
    backgroundColor: 'white'
  },
  bell: {
    source: BELL_IMAGE,
    color: '#f39c12',
    backgroundColor: 'white'
  }
};

export default class SwipeRating extends Component {
  static defaultProps = {
    type: 'star',
    ratingImage: require('./images/star.png'),
    ratingColor: '#f1c40f',
    ratingBackgroundColor: 'white',
    ratingCount: 5,
    showReadOnlyText: true,
    imageSize: 40,
    minValue: 0
  };

  constructor(props) {
    super(props);
    const { onStartRating, onFinishRating, fractions } = this.props;
    const position = new Animated.ValueXY();

    const panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        if (typeof onStartRating === 'function') {
          onStartRating();
        }
      },
      onPanResponderMove: (event, gesture) => {
        const newPosition = new Animated.ValueXY();
        newPosition.setValue({ x: gesture.dx, y: 0 });
        if (this.state.isComponentMounted) {
          this.setState({position: newPosition, value: gesture.dx});
        }
      },
      onPanResponderRelease: event => {
        const rating = this.getCurrentRating(this.state.value);
        if (rating >= this.props.minValue) {
          if (!fractions) {
            // 'round up' to the nearest rating image
            this.setCurrentRating(rating);
          }
          if (typeof onFinishRating === 'function') onFinishRating(rating);
        }
      }
    });

    this.state = { panResponder, position, display: false, isComponentMounted: false };
  }

  async componentDidMount() {
    try {
      const STAR_IMAGE = await require('./images/star.png');
      const HEART_IMAGE = await require('./images/heart.png');
      const ROCKET_IMAGE = await require('./images/rocket.png');
      const BELL_IMAGE = await require('./images/bell.png');

      this.setState({ display: true, isComponentMounted: false });
    } catch(err) {
      console.log(err)
    }

    this.setCurrentRating(this.props.startingValue);
  }

  componentDidUpdate(prevProps) {
    if (this.props.startingValue !== prevProps.startingValue) {
      this.setCurrentRating(this.props.startingValue);
    }
  }

  getPrimaryViewStyle() {
    const { position } = this.state;
    const { imageSize, ratingCount, type } = this.props;

    const color = TYPES[type].color;

    const width = position.x.interpolate(
      {
        inputRange: [-ratingCount * (imageSize / 2), 0, ratingCount * (imageSize / 2)],
        outputRange: [0, (ratingCount * imageSize) / 2, ratingCount * imageSize],
        extrapolate: 'clamp'
      },
      {
        useNativeDriver: true
      }
    );

    return {
      backgroundColor: color,
      width,
      height: width ? imageSize : 0
    };
  }

  getSecondaryViewStyle() {
    const { position } = this.state;
    const { imageSize, ratingCount, type } = this.props;

    const backgroundColor = TYPES[type].backgroundColor;

    const width = position.x.interpolate(
      {
        inputRange: [-ratingCount * (imageSize / 2), 0, ratingCount * (imageSize / 2)],
        outputRange: [ratingCount * imageSize, (ratingCount * imageSize) / 2, 0],
        extrapolate: 'clamp'
      },
      {
        useNativeDriver: true
      }
    );

    return {
      backgroundColor,
      width,
      height: width ? imageSize : 0
    };
  }

  renderRatings() {
    const { imageSize, ratingCount, type, tintColor } = this.props;
    const source = TYPES[type].source;

    return times(ratingCount, index => (
      <View key={index} style={styles.starContainer}>
        <Image source={source} style={{ width: imageSize, height: imageSize, tintColor }} />
      </View>
    ));
  }

  getCurrentRating(value) {
    // const { value } = this.state;
    const { fractions, imageSize, ratingCount } = this.props;

    const startingValue = ratingCount / 2;
    let currentRating = (this.props.minValue) ? this.props.minValue : 0;

    if (value > (ratingCount * imageSize) / 2) {
      currentRating = ratingCount;
    } else if (value < (-ratingCount * imageSize) / 2) {
      currentRating = (this.props.minValue) ? this.props.minValue : 0;
    } else if (value <= imageSize || value > imageSize) {
      currentRating = startingValue + value / imageSize;
      currentRating = !fractions ? Math.ceil(currentRating) : +currentRating.toFixed(fractions);
    } else {
      currentRating = !fractions ? Math.ceil(startingValue) : +startingValue.toFixed(fractions);
    }

    return currentRating;
  }

  setCurrentRating(rating) {
    const { imageSize, ratingCount } = this.props;

    // `initialRating` corresponds to `startingValue` in the getter. Naming it
    // differently here avoids confusion with `value` below.
    const initialRating = ratingCount / 2;
    let value = null;

    if (rating > ratingCount) {
      value = (ratingCount * imageSize) / 2;
    } else if (rating < 0) {
      value = (-ratingCount * imageSize) / 2;
    } else if (rating < ratingCount / 2 || rating > ratingCount / 2) {
      value = (rating - initialRating) * imageSize;
    } else {
      value = 0;
    }

    const newPosition = new Animated.ValueXY();
    newPosition.setValue({ x: value, y: 0 });
    if (this.state.isComponentMounted) {
      this.setState({position: newPosition, value});
    }
  }

  displayCurrentRating() {
    const { ratingCount, type, readonly, showReadOnlyText, ratingTextColor } = this.props;
    const color = ratingTextColor || TYPES[type].color;

    return (
      <View style={styles.showRatingView}>
        <View style={styles.ratingView}>
          <Text style={[styles.ratingText, { color }]}>Rating:{' '}</Text>
          <Text style={[styles.currentRatingText, { color }]}>{this.getCurrentRating(this.state.value)}</Text>
          <Text style={[styles.maxRatingText, { color }]}>/{ratingCount}</Text>
        </View>
        <View>{readonly && showReadOnlyText && <Text style={[styles.readonlyLabel, { color }]}>(readonly)</Text>}</View>
      </View>
    );
  }

  render() {
    const { readonly, type, ratingImage, ratingColor, ratingBackgroundColor, style, showRating } = this.props;

    if (type === 'custom') {
      let custom = {
        source: ratingImage,
        color: ratingColor,
        backgroundColor: ratingBackgroundColor
      };
      TYPES.custom = custom;
    }

    return (
      this.state.display ?
      <View pointerEvents={readonly ? 'none' : 'auto'} style={style}>
        {showRating && this.displayCurrentRating()}
        <View style={styles.starsWrapper} {...this.state.panResponder.panHandlers}>
          <View style={styles.starsInsideWrapper}>
            <Animated.View style={this.getPrimaryViewStyle()} />
            <Animated.View style={this.getSecondaryViewStyle()} />
          </View>
          {this.renderRatings()}
        </View>
      </View> :
      null
    );
  }

  componentWillUnmount() {
    this.setState({ isComponentMounted: false });
  }

}

const styles = StyleSheet.create({
  starsWrapper: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  starsInsideWrapper: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  showRatingView: {
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    paddingBottom: 5
  },
  ratingView: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    paddingBottom: 5
  },
  ratingText: {
    fontSize: 15,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null,
    color: '#34495e'
  },
  readonlyLabel: {
    justifyContent: 'center',
    alignItems: 'center',
    fontSize: 12,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null,
    color: '#34495a'
  },
  currentRatingText: {
    fontSize: 30,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null
  },
  maxRatingText: {
    fontSize: 18,
    textAlign: 'center',
    fontFamily: Platform.OS === 'ios' ? 'Trebuchet MS' : null,
    color: '#34495e'
  }
});

const fractionsType = (props, propName, componentName) => {
  if (props[propName]) {
    const value = props[propName];
    if (typeof value === 'number') {
      return value >= 0 && value <= 20
        ? null
        : new Error(`\`${propName}\` in \`${componentName}\` must be between 0 and 20`);
    }

    return new Error(`\`${propName}\` in \`${componentName}\` must be a number`);
  }
};

SwipeRating.propTypes = {
  type: PropTypes.string,
  ratingImage: PropTypes.node,
  ratingColor: PropTypes.string,
  ratingBackgroundColor: PropTypes.string,
  ratingCount: PropTypes.number,
  ratingTextColor: PropTypes.string,
  imageSize: PropTypes.number,
  onStartRating: PropTypes.func,
  onFinishRating: PropTypes.func,
  showRating: PropTypes.bool,
  style: PropTypes.object,
  readonly: PropTypes.bool,
  showReadOnlyText: PropTypes.bool,
  startingValue: PropTypes.number,
  fractions: fractionsType,
  minValue: PropTypes.number
};
<|endoftext|>


<commit_before>ace.define("ace/theme/idle_fingers",["require","exports","module","ace/lib/dom"], function(require, exports, module) {

exports.isDark = true;
exports.cssClass = "ace-idle-fingers";
exports.cssText = ".ace-idle-fingers .ace_gutter {\
background: #3b3b3b;\
color: rgb(153,153,153)\
}\
.ace-idle-fingers .ace_print-margin {\
width: 1px;\
background: #3b3b3b\
}\
.ace-idle-fingers {\
background-color: #323232;\
color: #FFFFFF\
}\
.ace-idle-fingers .ace_cursor {\
color: #91FF00\
}\
.ace-idle-fingers .ace_marker-layer .ace_selection {\
background: rgba(90, 100, 126, 0.88)\
}\
.ace-idle-fingers.ace_multiselect .ace_selection.ace_start {\
box-shadow: 0 0 3px 0px #323232;\
}\
.ace-idle-fingers .ace_marker-layer .ace_step {\
background: rgb(102, 82, 0)\
}\
.ace-idle-fingers .ace_marker-layer .ace_bracket {\
margin: -1px 0 0 -1px;\
border: 1px solid #404040\
}\
.ace-idle-fingers .ace_marker-layer .ace_active-line {\
background: #353637\
}\
.ace-idle-fingers .ace_gutter-active-line {\
background-color: #353637\
}\
.ace-idle-fingers .ace_marker-layer .ace_selected-word {\
border: 1px solid rgba(90, 100, 126, 0.88)\
}\
.ace-idle-fingers .ace_invisible {\
color: #404040\
}\
.ace-idle-fingers .ace_keyword,\
.ace-idle-fingers .ace_meta {\
color: #CC7833\
}\
.ace-idle-fingers .ace_constant,\
.ace-idle-fingers .ace_constant.ace_character,\
.ace-idle-fingers .ace_constant.ace_character.ace_escape,\
.ace-idle-fingers .ace_constant.ace_other,\
.ace-idle-fingers .ace_support.ace_constant {\
color: #6C99BB\
}\
.ace-idle-fingers .ace_invalid {\
color: #FFFFFF;\
background-color: #FF0000\
}\
.ace-idle-fingers .ace_fold {\
background-color: #CC7833;\
border-color: #FFFFFF\
}\
.ace-idle-fingers .ace_support.ace_function {\
color: #B83426\
}\
.ace-idle-fingers .ace_variable.ace_parameter {\
font-style: italic\
}\
.ace-idle-fingers .ace_string {\
color: #A5C261\
}\
.ace-idle-fingers .ace_string.ace_regexp {\
color: #CCCC33\
}\
.ace-idle-fingers .ace_comment {\
font-style: italic;\
color: #BC9458\
}\
.ace-idle-fingers .ace_meta.ace_tag {\
color: #FFE5BB\
}\
.ace-idle-fingers .ace_entity.ace_name {\
color: #FFC66D\
}\
.ace-idle-fingers .ace_collab.ace_user1 {\
color: #323232;\
background-color: #FFF980\
}\
.ace-idle-fingers .ace_indent-guide {\
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWMwMjLyZYiPj/8PAAreAwAI1+g0AAAAAElFTkSuQmCC) right repeat-y\
}";

var dom = require("../lib/dom");
dom.importCssString(exports.cssText, exports.cssClass);
});
<commit_msg>Update public/libs/bower_components/ace-builds/src-noconflict/theme-idle_fingers.js<commit_after><|endoftext|>


<commit_before>// FIXME should possibly show tooltip when dragging?

goog.provide('ol.control.ZoomSlider');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.fx.DragDropEvent');
goog.require('goog.fx.Dragger');
goog.require('goog.fx.Dragger.EventType');
goog.require('goog.math');
goog.require('goog.math.Rect');
goog.require('goog.style');
goog.require('ol.Size');
goog.require('ol.ViewHint');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');

/**
 * @classdesc
 * A slider type of control for zooming.
 *
 * Example:
 *
 *     map.addControl(new ol.control.ZoomSlider());
 *
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options.
 * @api stable
 */
ol.control.ZoomSlider = function(opt_options) {

  var options = goog.isDef(opt_options) ? opt_options : {};

  /**
   * Will hold the current resolution of the view.
   *
   * @type {number|undefined}
   * @private
   */
  this.currentResolution_ = undefined;

  /**
   * The direction of the slider. Will be determined from actual display of the
   * container and defaults to ol.control.ZoomSlider.direction.VERTICAL.
   *
   * @type {ol.control.ZoomSlider.direction}
   * @private
   */
  this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;

  /**
   * The calculated thumb size (border box plus margins).  Set when initSlider_
   * is called.
   * @type {ol.Size}
   * @private
   */
  this.thumbSize_ = null;

  /**
   * Whether the slider is initialized.
   * @type {boolean}
   * @private
   */
  this.sliderInitialized_ = false;

  /**
   * @private
   * @type {number}
   */
  this.duration_ = goog.isDef(options.duration) ? options.duration : 200;

  var className = goog.isDef(options.className) ?
      options.className : 'ol-zoomslider';
  var thumbElement = goog.dom.createDom(goog.dom.TagName.DIV,
      [className + '-thumb', ol.css.CLASS_UNSELECTABLE]);
  var containerElement = goog.dom.createDom(goog.dom.TagName.DIV,
      [className, ol.css.CLASS_UNSELECTABLE, ol.css.CLASS_CONTROL],
      thumbElement);

  /**
   * @type {goog.fx.Dragger}
   * @private
   */
  this.dragger_ = new goog.fx.Dragger(thumbElement);
  this.registerDisposable(this.dragger_);

  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START,
      this.handleDraggerStart_, false, this);
  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
      this.handleDraggerDrag_, false, this);
  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
      this.handleDraggerEnd_, false, this);

  goog.events.listen(containerElement, goog.events.EventType.CLICK,
      this.handleContainerClick_, false, this);
  goog.events.listen(thumbElement, goog.events.EventType.CLICK,
      goog.events.Event.stopPropagation);

  var render = goog.isDef(options.render) ?
      options.render : ol.control.ZoomSlider.render;

  goog.base(this, {
    element: containerElement,
    render: render
  });
};
goog.inherits(ol.control.ZoomSlider, ol.control.Control);

/**
 * The enum for available directions.
 *
 * @enum {number}
 */
ol.control.ZoomSlider.direction = {
  VERTICAL: 0,
  HORIZONTAL: 1
};

/**
 * @inheritDoc
 */
ol.control.ZoomSlider.prototype.setMap = function(map) {
  goog.base(this, 'setMap', map);
  if (!goog.isNull(map)) {
    map.render();
  }
};

/**
 * Initializes the slider element. This will determine and set this controls
 * direction_ and also constrain the dragging of the thumb to always be within
 * the bounds of the container.
 *
 * @private
 */
ol.control.ZoomSlider.prototype.initSlider_ = function() {
  var container = this.element;
  var containerSize = goog.style.getSize(container);

  var thumb = goog.dom.getFirstElementChild(container);
  var thumbMargins = goog.style.getMarginBox(thumb);
  var thumbBorderBoxSize = goog.style.getBorderBoxSize(thumb);
  var thumbWidth = thumbBorderBoxSize.width +
      thumbMargins.right + thumbMargins.left;
  var thumbHeight = thumbBorderBoxSize.height +
      thumbMargins.top + thumbMargins.bottom;
  this.thumbSize_ = [thumbWidth, thumbHeight];

  var width = containerSize.width - thumbWidth;
  var height = containerSize.height - thumbHeight;

  var limits;
  if (containerSize.width > containerSize.height) {
    this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL;
    limits = new goog.math.Rect(0, 0, width, 0);
  } else {
    this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
    limits = new goog.math.Rect(0, 0, 0, height);
  }
  this.dragger_.setLimits(limits);
  this.sliderInitialized_ = true;
};

/**
 * Update the zoomslider element.
 * @param {ol.MapEvent} mapEvent Map event.
 * @this {ol.control.ZoomSlider}
 * @api
 */
ol.control.ZoomSlider.render = function(mapEvent) {
  if (goog.isNull(mapEvent.frameState)) {
    return;
  }
  goog.asserts.assert(goog.isDefAndNotNull(mapEvent.frameState.viewState),
      'viewState should be defined');
  if (!this.sliderInitialized_) {
    this.initSlider_();
  }
  var res = mapEvent.frameState.viewState.resolution;
  if (res !== this.currentResolution_) {
    this.currentResolution_ = res;
    this.setThumbPosition_(res);
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
 * @private
 */
ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) {
  var map = this.getMap();
  var view = map.getView();
  var currentResolution = view.getResolution();
  goog.asserts.assert(goog.isDef(currentResolution),
      'currentResolution should be defined');
  map.beforeRender(ol.animation.zoom({
    resolution: currentResolution,
    duration: this.duration_,
    easing: ol.easing.easeOut
  }));
  var relativePosition = this.getRelativePosition_(
      browserEvent.offsetX - this.thumbSize_[0] / 2,
      browserEvent.offsetY - this.thumbSize_[1] / 2);
  var resolution = this.getResolutionForPosition_(relativePosition);
  view.setResolution(view.constrainResolution(resolution));
};

/**
 * Handle dragger start events.
 * @param {goog.fx.DragDropEvent} event The dragdropevent.
 * @private
 */
ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
  this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1);
};

/**
 * Handle dragger drag events.
 *
 * @param {goog.fx.DragDropEvent} event The dragdropevent.
 * @private
 */
ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
  var relativePosition = this.getRelativePosition_(event.left, event.top);
  this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
  this.getMap().getView().setResolution(this.currentResolution_);
};

/**
 * Handle dragger end events.
 * @param {goog.fx.DragDropEvent} event The dragdropevent.
 * @private
 */
ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {
  var map = this.getMap();
  var view = map.getView();
  view.setHint(ol.ViewHint.INTERACTING, -1);
  goog.asserts.assert(goog.isDef(this.currentResolution_),
      'this.currentResolution_ should be defined');
  map.beforeRender(ol.animation.zoom({
    resolution: this.currentResolution_,
    duration: this.duration_,
    easing: ol.easing.easeOut
  }));
  var resolution = view.constrainResolution(this.currentResolution_);
  view.setResolution(resolution);
};

/**
 * Positions the thumb inside its container according to the given resolution.
 *
 * @param {number} res The res.
 * @private
 */
ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) {
  var position = this.getPositionForResolution_(res);
  var dragger = this.dragger_;
  var thumb = goog.dom.getFirstElementChild(this.element);

  if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) {
    var left = dragger.limits.left + dragger.limits.width * position;
    goog.style.setPosition(thumb, left);
  } else {
    var top = dragger.limits.top + dragger.limits.height * position;
    goog.style.setPosition(thumb, dragger.limits.left, top);
  }
};

/**
 * Calculates the relative position of the thumb given x and y offsets.  The
 * relative position scales from 0 to 1.  The x and y offsets are assumed to be
 * in pixel units within the dragger limits.
 *
 * @param {number} x Pixel position relative to the left of the slider.
 * @param {number} y Pixel position relative to the top of the slider.
 * @return {number} The relative position of the thumb.
 * @private
 */
ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) {
  var draggerLimits = this.dragger_.limits;
  var amount;
  if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) {
    amount = (x - draggerLimits.left) / draggerLimits.width;
  } else {
    amount = (y - draggerLimits.top) / draggerLimits.height;
  }
  return goog.math.clamp(amount, 0, 1);
};

/**
 * Calculates the corresponding resolution of the thumb given its relative
 * position (where 0 is the minimum and 1 is the maximum).
 *
 * @param {number} position The relative position of the thumb.
 * @return {number} The corresponding resolution.
 * @private
 */
ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) {
  var fn = this.getMap().getView().getResolutionForValueFunction();
  return fn(1 - position);
};

/**
 * Determines the relative position of the slider for the given resolution.  A
 * relative position of 0 corresponds to the minimum view resolution.  A
 * relative position of 1 corresponds to the maximum view resolution.
 *
 * @param {number} res The resolution.
 * @return {number} The relative position value (between 0 and 1).
 * @private
 */
ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) {
  var fn = this.getMap().getView().getValueForResolutionFunction();
  return 1 - fn(res);
};
<commit_msg>Fix the event type fired by goog.fx.Dragger<commit_after>// FIXME should possibly show tooltip when dragging?

goog.provide('ol.control.ZoomSlider');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.fx.DragEvent');
goog.require('goog.fx.Dragger');
goog.require('goog.fx.Dragger.EventType');
goog.require('goog.math');
goog.require('goog.math.Rect');
goog.require('goog.style');
goog.require('ol.Size');
goog.require('ol.ViewHint');
goog.require('ol.animation');
goog.require('ol.control.Control');
goog.require('ol.css');
goog.require('ol.easing');

/**
 * @classdesc
 * A slider type of control for zooming.
 *
 * Example:
 *
 *     map.addControl(new ol.control.ZoomSlider());
 *
 * @constructor
 * @extends {ol.control.Control}
 * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options.
 * @api stable
 */
ol.control.ZoomSlider = function(opt_options) {

  var options = goog.isDef(opt_options) ? opt_options : {};

  /**
   * Will hold the current resolution of the view.
   *
   * @type {number|undefined}
   * @private
   */
  this.currentResolution_ = undefined;

  /**
   * The direction of the slider. Will be determined from actual display of the
   * container and defaults to ol.control.ZoomSlider.direction.VERTICAL.
   *
   * @type {ol.control.ZoomSlider.direction}
   * @private
   */
  this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;

  /**
   * The calculated thumb size (border box plus margins).  Set when initSlider_
   * is called.
   * @type {ol.Size}
   * @private
   */
  this.thumbSize_ = null;

  /**
   * Whether the slider is initialized.
   * @type {boolean}
   * @private
   */
  this.sliderInitialized_ = false;

  /**
   * @private
   * @type {number}
   */
  this.duration_ = goog.isDef(options.duration) ? options.duration : 200;

  var className = goog.isDef(options.className) ?
      options.className : 'ol-zoomslider';
  var thumbElement = goog.dom.createDom(goog.dom.TagName.DIV,
      [className + '-thumb', ol.css.CLASS_UNSELECTABLE]);
  var containerElement = goog.dom.createDom(goog.dom.TagName.DIV,
      [className, ol.css.CLASS_UNSELECTABLE, ol.css.CLASS_CONTROL],
      thumbElement);

  /**
   * @type {goog.fx.Dragger}
   * @private
   */
  this.dragger_ = new goog.fx.Dragger(thumbElement);
  this.registerDisposable(this.dragger_);

  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START,
      this.handleDraggerStart_, false, this);
  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
      this.handleDraggerDrag_, false, this);
  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
      this.handleDraggerEnd_, false, this);

  goog.events.listen(containerElement, goog.events.EventType.CLICK,
      this.handleContainerClick_, false, this);
  goog.events.listen(thumbElement, goog.events.EventType.CLICK,
      goog.events.Event.stopPropagation);

  var render = goog.isDef(options.render) ?
      options.render : ol.control.ZoomSlider.render;

  goog.base(this, {
    element: containerElement,
    render: render
  });
};
goog.inherits(ol.control.ZoomSlider, ol.control.Control);

/**
 * The enum for available directions.
 *
 * @enum {number}
 */
ol.control.ZoomSlider.direction = {
  VERTICAL: 0,
  HORIZONTAL: 1
};

/**
 * @inheritDoc
 */
ol.control.ZoomSlider.prototype.setMap = function(map) {
  goog.base(this, 'setMap', map);
  if (!goog.isNull(map)) {
    map.render();
  }
};

/**
 * Initializes the slider element. This will determine and set this controls
 * direction_ and also constrain the dragging of the thumb to always be within
 * the bounds of the container.
 *
 * @private
 */
ol.control.ZoomSlider.prototype.initSlider_ = function() {
  var container = this.element;
  var containerSize = goog.style.getSize(container);

  var thumb = goog.dom.getFirstElementChild(container);
  var thumbMargins = goog.style.getMarginBox(thumb);
  var thumbBorderBoxSize = goog.style.getBorderBoxSize(thumb);
  var thumbWidth = thumbBorderBoxSize.width +
      thumbMargins.right + thumbMargins.left;
  var thumbHeight = thumbBorderBoxSize.height +
      thumbMargins.top + thumbMargins.bottom;
  this.thumbSize_ = [thumbWidth, thumbHeight];

  var width = containerSize.width - thumbWidth;
  var height = containerSize.height - thumbHeight;

  var limits;
  if (containerSize.width > containerSize.height) {
    this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL;
    limits = new goog.math.Rect(0, 0, width, 0);
  } else {
    this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
    limits = new goog.math.Rect(0, 0, 0, height);
  }
  this.dragger_.setLimits(limits);
  this.sliderInitialized_ = true;
};

/**
 * Update the zoomslider element.
 * @param {ol.MapEvent} mapEvent Map event.
 * @this {ol.control.ZoomSlider}
 * @api
 */
ol.control.ZoomSlider.render = function(mapEvent) {
  if (goog.isNull(mapEvent.frameState)) {
    return;
  }
  goog.asserts.assert(goog.isDefAndNotNull(mapEvent.frameState.viewState),
      'viewState should be defined');
  if (!this.sliderInitialized_) {
    this.initSlider_();
  }
  var res = mapEvent.frameState.viewState.resolution;
  if (res !== this.currentResolution_) {
    this.currentResolution_ = res;
    this.setThumbPosition_(res);
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
 * @private
 */
ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) {
  var map = this.getMap();
  var view = map.getView();
  var currentResolution = view.getResolution();
  goog.asserts.assert(goog.isDef(currentResolution),
      'currentResolution should be defined');
  map.beforeRender(ol.animation.zoom({
    resolution: currentResolution,
    duration: this.duration_,
    easing: ol.easing.easeOut
  }));
  var relativePosition = this.getRelativePosition_(
      browserEvent.offsetX - this.thumbSize_[0] / 2,
      browserEvent.offsetY - this.thumbSize_[1] / 2);
  var resolution = this.getResolutionForPosition_(relativePosition);
  view.setResolution(view.constrainResolution(resolution));
};

/**
 * Handle dragger start events.
 * @param {goog.fx.DragEvent} event The drag event.
 * @private
 */
ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
  this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1);
};

/**
 * Handle dragger drag events.
 *
 * @param {goog.fx.DragEvent} event The drag event.
 * @private
 */
ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
  var relativePosition = this.getRelativePosition_(event.left, event.top);
  this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
  this.getMap().getView().setResolution(this.currentResolution_);
};

/**
 * Handle dragger end events.
 * @param {goog.fx.DragEvent} event The drag event.
 * @private
 */
ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {
  var map = this.getMap();
  var view = map.getView();
  view.setHint(ol.ViewHint.INTERACTING, -1);
  goog.asserts.assert(goog.isDef(this.currentResolution_),
      'this.currentResolution_ should be defined');
  map.beforeRender(ol.animation.zoom({
    resolution: this.currentResolution_,
    duration: this.duration_,
    easing: ol.easing.easeOut
  }));
  var resolution = view.constrainResolution(this.currentResolution_);
  view.setResolution(resolution);
};

/**
 * Positions the thumb inside its container according to the given resolution.
 *
 * @param {number} res The res.
 * @private
 */
ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) {
  var position = this.getPositionForResolution_(res);
  var dragger = this.dragger_;
  var thumb = goog.dom.getFirstElementChild(this.element);

  if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) {
    var left = dragger.limits.left + dragger.limits.width * position;
    goog.style.setPosition(thumb, left);
  } else {
    var top = dragger.limits.top + dragger.limits.height * position;
    goog.style.setPosition(thumb, dragger.limits.left, top);
  }
};

/**
 * Calculates the relative position of the thumb given x and y offsets.  The
 * relative position scales from 0 to 1.  The x and y offsets are assumed to be
 * in pixel units within the dragger limits.
 *
 * @param {number} x Pixel position relative to the left of the slider.
 * @param {number} y Pixel position relative to the top of the slider.
 * @return {number} The relative position of the thumb.
 * @private
 */
ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) {
  var draggerLimits = this.dragger_.limits;
  var amount;
  if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) {
    amount = (x - draggerLimits.left) / draggerLimits.width;
  } else {
    amount = (y - draggerLimits.top) / draggerLimits.height;
  }
  return goog.math.clamp(amount, 0, 1);
};

/**
 * Calculates the corresponding resolution of the thumb given its relative
 * position (where 0 is the minimum and 1 is the maximum).
 *
 * @param {number} position The relative position of the thumb.
 * @return {number} The corresponding resolution.
 * @private
 */
ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) {
  var fn = this.getMap().getView().getResolutionForValueFunction();
  return fn(1 - position);
};

/**
 * Determines the relative position of the slider for the given resolution.  A
 * relative position of 0 corresponds to the minimum view resolution.  A
 * relative position of 1 corresponds to the maximum view resolution.
 *
 * @param {number} res The resolution.
 * @return {number} The relative position value (between 0 and 1).
 * @private
 */
ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) {
  var fn = this.getMap().getView().getValueForResolutionFunction();
  return 1 - fn(res);
};
<|endoftext|>