<commit_before>var C = require( '../constants/constants' );

/**
 * This class retrieves a single record from the cache or - if it isn't in the
 * cache - from storage. If it isn't there either it will notify its initiator
 * by passing null to onComplete (but not call onError).
 *
 * It also handles all the timeout and destruction steps around this operation
 *
 * @param {String} recordName 			the unique name of the record
 * @param {Object} options 				deepstream options
 * @param {SocketWrapper} socketWrapper the sender whos message initiated the recordRequest
 * @param {Function} onComplete    		callback for successful requests (even if the record wasn't found)
 * @param {[Function]} onError       		callback for errors
 *
 * @constructor
 */
var RecordRequest = function( recordName, options, socketWrapper, onComplete, onError ) {
	this._recordName = recordName;
	this._options = options;
	this._socketWrapper = socketWrapper;
	this._storageRetrievalTimeout = null;
	this._onComplete = onComplete;
	this._onError = onError;
	this._isDestroyed = false;

	this._cacheRetrievalTimeout = setTimeout(
		this._sendError.bind( this, C.EVENT.CACHE_RETRIEVAL_TIMEOUT, this._recordName ),
		this._options.cacheRetrievalTimeout
	);

	this._options.cache.get( this._recordName, this._onCacheResponse.bind( this ) );
};

/**
 * Callback for responses returned by the cache connector
 *
 * @param   {String} error  null if no error has occured
 * @param   {Object} record the record data structure, e.g. { _v: 33, _d: { some: 'data' } }
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._onCacheResponse = function( error, record ) {
	clearTimeout( this._cacheRetrievalTimeout );

	if( this._isDestroyed === true ) {
		return;
	}

	if( error ) {
		this._sendError( C.EVENT.RECORD_LOAD_ERROR, 'error while loading ' + this._recordName + ' from cache:' + error );
	}
	else if( record ) {
		this._onComplete( record );
	}
	else {
		this._storageRetrievalTimeout = setTimeout(
			this._sendError.bind( this, C.EVENT.STORAGE_RETRIEVAL_TIMEOUT, this._recordName ),
			this._options.storageRetrievalTimeout
		);

		this._options.storage.get( this._recordName, this._onStorageResponse.bind( this ) );
	}
};

/**
 * Callback for responses returned by the storage connector. The request will complete or error
 * here, if the record couldn't be found in storage no further attempts to retrieve it will be made
 *
 * @param   {String} error  null if no error has occured
 * @param   {Object} record the record data structure, e.g. { _v: 33, _d: { some: 'data' } }
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._onStorageResponse = function( error, record ) {
	clearTimeout( this._storageRetrievalTimeout );

	if( this._isDestroyed === true ) {
		return;
	}

	if( error ) {
		this._sendError( C.EVENT.RECORD_LOAD_ERROR, 'error while loading ' + this._recordName + ' from storage' );
	} else {
		this._onComplete( record || null );

		if( record ) {
			/*
			 * Load record from storage into cache
			 */
			this._options.cache.set( this._recordName, record, function(){});
		}

		this._destroy();
	}
};

/**
 * Sends an error to the socketWrapper that requested the
 * record
 *
 * @param   {String} event   		Error event
 * @param   {String} message 		Error message
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._sendError = function( event, message ) {
	this._options.logger.log( C.LOG_LEVEL.ERROR, event, message );
	this._socketWrapper.sendError( C.TOPIC.RECORD, event, message );
	if( this._onError ) {
		this._onError( event, message );
	}
	this._destroy();
};

/**
 * Destroys the record request. Clears down all references and stops
 * all pending timeouts
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._destroy = function() {
	clearTimeout( this._cacheRetrievalTimeout );
	clearTimeout( this._storageRetrievalTimeout );
	this._recordName = null;
	this._options = null;
	this._socketWrapper = null;
	this._storageRetrievalTimeout = null;
	this._onComplete = null;
	this._onError = null;
	this._isDestroyed = true;
};

module.exports = RecordRequest;<commit_msg>Added error to record request<commit_after>var C = require( '../constants/constants' );

/**
 * This class retrieves a single record from the cache or - if it isn't in the
 * cache - from storage. If it isn't there either it will notify its initiator
 * by passing null to onComplete (but not call onError).
 *
 * It also handles all the timeout and destruction steps around this operation
 *
 * @param {String} recordName 			the unique name of the record
 * @param {Object} options 				deepstream options
 * @param {SocketWrapper} socketWrapper the sender whos message initiated the recordRequest
 * @param {Function} onComplete    		callback for successful requests (even if the record wasn't found)
 * @param {[Function]} onError       		callback for errors
 *
 * @constructor
 */
var RecordRequest = function( recordName, options, socketWrapper, onComplete, onError ) {
	this._recordName = recordName;
	this._options = options;
	this._socketWrapper = socketWrapper;
	this._storageRetrievalTimeout = null;
	this._onComplete = onComplete;
	this._onError = onError;
	this._isDestroyed = false;

	this._cacheRetrievalTimeout = setTimeout(
		this._sendError.bind( this, C.EVENT.CACHE_RETRIEVAL_TIMEOUT, this._recordName ),
		this._options.cacheRetrievalTimeout
	);

	this._options.cache.get( this._recordName, this._onCacheResponse.bind( this ) );
};

/**
 * Callback for responses returned by the cache connector
 *
 * @param   {String} error  null if no error has occured
 * @param   {Object} record the record data structure, e.g. { _v: 33, _d: { some: 'data' } }
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._onCacheResponse = function( error, record ) {
	clearTimeout( this._cacheRetrievalTimeout );

	if( this._isDestroyed === true ) {
		return;
	}

	if( error ) {
		this._sendError( C.EVENT.RECORD_LOAD_ERROR, 'error while loading ' + this._recordName + ' from cache:' + error );
	}
	else if( record ) {
		this._onComplete( record );
	}
	else {
		this._storageRetrievalTimeout = setTimeout(
			this._sendError.bind( this, C.EVENT.STORAGE_RETRIEVAL_TIMEOUT, this._recordName ),
			this._options.storageRetrievalTimeout
		);

		this._options.storage.get( this._recordName, this._onStorageResponse.bind( this ) );
	}
};

/**
 * Callback for responses returned by the storage connector. The request will complete or error
 * here, if the record couldn't be found in storage no further attempts to retrieve it will be made
 *
 * @param   {String} error  null if no error has occured
 * @param   {Object} record the record data structure, e.g. { _v: 33, _d: { some: 'data' } }
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._onStorageResponse = function( error, record ) {
	clearTimeout( this._storageRetrievalTimeout );

	if( this._isDestroyed === true ) {
		return;
	}

	if( error ) {
		this._sendError( C.EVENT.RECORD_LOAD_ERROR, 'error while loading ' + this._recordName + ' from storage', error.toString() );
	} else {
		this._onComplete( record || null );

		if( record ) {
			/*
			 * Load record from storage into cache
			 */
			this._options.cache.set( this._recordName, record, function(){});
		}

		this._destroy();
	}
};

/**
 * Sends an error to the socketWrapper that requested the
 * record
 *
 * @param   {String} event   		Error event
 * @param   {String} message 		Error message
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._sendError = function( event, message ) {
	this._options.logger.log( C.LOG_LEVEL.ERROR, event, message );
	this._socketWrapper.sendError( C.TOPIC.RECORD, event, message );
	if( this._onError ) {
		this._onError( event, message );
	}
	this._destroy();
};

/**
 * Destroys the record request. Clears down all references and stops
 * all pending timeouts
 *
 * @private
 * @returns {void}
 */
RecordRequest.prototype._destroy = function() {
	clearTimeout( this._cacheRetrievalTimeout );
	clearTimeout( this._storageRetrievalTimeout );
	this._recordName = null;
	this._options = null;
	this._socketWrapper = null;
	this._storageRetrievalTimeout = null;
	this._onComplete = null;
	this._onError = null;
	this._isDestroyed = true;
};

module.exports = RecordRequest;<|endoftext|>


<commit_before>/* global angular */
;(function () {
  angular.module('resilienzManager')
    .controller('resilienzManager-Layout', ['$scope', 'resilienzManagerDataProvider', '$uibModal', '$rootScope', '$window', function ($scope, resilienzManagerDataProvider, $uibModal, $rootScope, $window) {
      var self = this
      self.categories = []
      self.final = false
      self.actionid = $rootScope.action
      self.catLoading = true
      self.pageLoading = true

      self.selectedCategory = {}
      self.selectedLayout = {}
      self.selectedPage = -1

      self.selectCategory = function () {
        self.catLoading = true
        self.selectedPage = self.selectedCategory.startpage
        self.catLoading = false
        reloadLayoutPositions(function () {}) // uses page to selectLayout
      }
      self.selectPage = function () {
        reloadLayoutPositions(function () {}) // uses page to selectLayout
      }
      self.selectLayout = function () {
        if (!self.final) {
          if (self.selectedLayout) {
            self.pageLoading = true
            resilienzManagerDataProvider.actionSaveLayout(self.actionid, self.selectedPage, self.selectedLayout).then(function (something) {
              reloadLayoutPositions(function () { })
            })
          }
        }
      }

      // load cats with layouts and positions
      resilienzManagerDataProvider.categoriesFull().then(function (categories) {
        self.categories = categories.data // {id, sort: -1, name: '', pages: -1, startpage: 0, layouts: [], translation}
        self.selectedCategory = self.categories[0]
        self.selectedPage = self.selectedCategory.startpage
        self.catLoading = false
        resilienzManagerDataProvider.action($rootScope.id).then(function (action) {
          self.final = (action.data.finalized === 1)
          reloadLayoutPositions(function () {})
        }, function (error) {
          console.error(error)
        })
      })

      self.openEditor = function (position) {
        if (!self.final) {
          var data = {}
          data.image = position.image
          data.width = position.width
          data.height = position.height
          var modalInstance = $uibModal.open({
            animation: true,
            templateUrl: 'modals/editor',
            controller: 'resilienzManager-Editor',
            controllerAs: 'ctrl',
            size: 'lg',
            resolve: {
              data: function () {
                return data
              }
            }
          })
          modalInstance.result.then(function (image) {
            position.style['background-image'] = 'url(/layout/image/' + image + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
          })
        }
      }
      self.delete = function (position) {
        if (!self.final) {
          position.deleting = true
          resilienzManagerDataProvider.imageDelete(position.image).then(function (something) {
            position.style['background-image'] = 'url(/layout/image/placeholder)'
            position.image = undefined
          })
        }
      }
      self.uploadError = function (file, errorMessage) {
        console.error(errorMessage)
      }
      function reloadLayoutPositions (callback) {
        resilienzManagerDataProvider.getLayoutImagesByActionPage(self.actionid, self.selectedPage).then(function (layoutWithImages) {
          self.pageLoading = true
          self.selectedLayout = {}
          self.selectedLayout = layoutWithImages.data
          self.pageImage = {
            'background-image': 'url(/layout/background/' + self.selectedPage + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
          }
          var orgWidth = (self.selectedCategory.id === '1') ? 720 : 1440
          var orgHeight = 1040
          var pageHeight = 700
          var pageWidth = ((orgWidth * pageHeight) / orgHeight)
          for (var i = 0; i < self.selectedLayout.positions.length; i++) {
            var position = self.selectedLayout.positions[i]
            position.style = {
              'left': (position.x * pageWidth / orgWidth) + 'px',
              'top': (position.y * pageHeight / orgHeight) + 'px',
              'width': (position.width * pageWidth / orgWidth) + 'px',
              'height': (position.height * pageHeight / orgHeight) + 'px',
              'transform': 'rotate(' + position.spin + 'deg)',
              'background-image': 'url(/layout/image/' + position.image + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
            }
            position.dropzoneConfig = {
              parallelUploads: 1,
              maxFileSize: 10,
              url: position.action,
              paramName: 'dropzone',
              method: 'post'
            }
            position.dragEnter = function (event, selPos) {
              selPos.style.outline = '2px solid #1BFF1B'
              $scope.$apply()
            }
            position.dragLeave = function (event, selPos) {
              delete selPos.style.outline
              $scope.$apply()
            }
            position.sending = function (file, xhr, formData, selPos) {
              selPos.sending = true
              $scope.$apply()
            }
            position.success = function (selPos) {
              resilienzManagerDataProvider.getPositionImage(self.actionid, selPos.id).then(function (image) {
                selPos.image = image.data
                selPos.sending = false
                selPos.deleting = false
                selPos.style['background-image'] = 'url(/layout/image/' + image.data + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
              })
            }
            position.sending = false
            position.deleting = false
          }
          self.pageLoading = false
          callback()
        })
      }
    }])
}())
<commit_msg>ux ficing<commit_after>/* global angular */
;(function () {
  angular.module('resilienzManager')
    .controller('resilienzManager-Layout', ['$scope', 'resilienzManagerDataProvider', '$uibModal', '$rootScope', '$window', function ($scope, resilienzManagerDataProvider, $uibModal, $rootScope, $window) {
      var self = this
      self.categories = []
      self.final = false
      self.actionid = $rootScope.action
      self.catLoading = true
      self.pageLoading = true

      self.selectedCategory = {}
      self.selectedLayout = {}
      self.selectedPage = -1

      self.selectCategory = function () {
        self.catLoading = true
        self.selectedPage = self.selectedCategory.startpage
        self.catLoading = false
        reloadLayoutPositions(function () {}) // uses page to selectLayout
      }
      self.selectPage = function () {
        reloadLayoutPositions(function () {}) // uses page to selectLayout
      }
      self.selectLayout = function () {
        if (!self.final) {
          if (self.selectedLayout) {
            self.pageLoading = true
            resilienzManagerDataProvider.actionSaveLayout(self.actionid, self.selectedPage, self.selectedLayout).then(function (something) {
              reloadLayoutPositions(function () { })
            })
          }
        }
      }

      // load cats with layouts and positions
      resilienzManagerDataProvider.categoriesFull().then(function (categories) {
        self.categories = categories.data // {id, sort: -1, name: '', pages: -1, startpage: 0, layouts: [], translation}
        self.selectedCategory = self.categories[0]
        self.selectedPage = self.selectedCategory.startpage
        self.catLoading = false
        resilienzManagerDataProvider.action($rootScope.id).then(function (action) {
          self.final = (action.data.finalized === 1)
          reloadLayoutPositions(function () {})
        }, function (error) {
          console.error(error)
        })
      })

      self.openEditor = function (position) {
        if (!self.final) {
          var data = {}
          data.image = position.image
          data.width = position.width
          data.height = position.height
          var modalInstance = $uibModal.open({
            animation: true,
            templateUrl: 'modals/editor',
            controller: 'resilienzManager-Editor',
            controllerAs: 'ctrl',
            size: 'lg',
            resolve: {
              data: function () {
                return data
              }
            }
          })
          modalInstance.result.then(function (image) {
            position.style['background-image'] = 'url(/layout/image/' + image + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
          })
        }
      }
      self.delete = function (position) {
        if (!self.final) {
          position.deleting = true
          resilienzManagerDataProvider.imageDelete(position.image).then(function (something) {
            position.style['background-image'] = 'url(/layout/image/placeholder)'
            position.image = undefined
          })
        }
      }
      self.uploadError = function (file, errorMessage) {
        console.error(errorMessage)
      }
      function reloadLayoutPositions (callback) {
        resilienzManagerDataProvider.getLayoutImagesByActionPage(self.actionid, self.selectedPage).then(function (layoutWithImages) {
          self.pageLoading = true
          self.selectedLayout = {}
          self.selectedLayout = layoutWithImages.data
          self.pageImage = {
            'background-image': 'url(/layout/background/' + self.selectedPage + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
          }
          var orgWidth = (self.selectedCategory.id === '1') ? 720 : 1440
          var orgHeight = 1040
          var pageHeight = 700
          var pageWidth = ((orgWidth * pageHeight) / orgHeight)
          for (var i = 0; i < self.selectedLayout.positions.length; i++) {
            var position = self.selectedLayout.positions[i]
            position.style = {
              'left': (position.x * pageWidth / orgWidth) + 'px',
              'top': (position.y * pageHeight / orgHeight) + 'px',
              'width': (position.width * pageWidth / orgWidth) + 'px',
              'height': (position.height * pageHeight / orgHeight) + 'px',
              'transform': 'rotate(' + position.spin + 'deg)',
              'background-image': 'url(/layout/image/' + position.image + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
            }
            position.dropzoneConfig = {
              parallelUploads: 1,
              maxFileSize: 10,
              url: position.action,
              paramName: 'dropzone',
              method: 'post'
            }
            position.dragEnter = function (event) {
              event.currentTarget.parentElement.style.outline = '2px solid #1BFF1B'
              $scope.$apply()
            }
            position.dragLeave = function (event) {
              event.currentTarget.parentElement.style.outline
              $scope.$apply()
            }
            position.sending = function (file, xhr, formData) {
              position.sending = true
              $scope.$apply()
            }
            position.success = function (position) {
              resilienzManagerDataProvider.getPositionImage(self.actionid, position.id).then(function (image) {
                position.image = image.data
                position.sending = false
                position.deleting = false
                position.style['background-image'] = 'url(/layout/image/' + image.data + '?v=' + Math.floor((Math.random() * 1000) + 1) + ')'
              })
            }
            position.sending = false
            position.deleting = false
          }
          self.pageLoading = false
          callback()
        })
      }
    }])
}())
<|endoftext|>


<commit_before>/*
Copyright 2016 OpenMarket Ltd

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.
*/

var q = require("q");
var React = require('react');
var ObjectUtils = require("../../../ObjectUtils");
var MatrixClientPeg = require('../../../MatrixClientPeg');
var sdk = require("../../../index");
var Modal = require("../../../Modal");

module.exports = React.createClass({
    displayName: 'AliasSettings',

    propTypes: {
        roomId: React.PropTypes.string.isRequired,
        canSetCanonicalAlias: React.PropTypes.bool.isRequired,
        canSetAliases: React.PropTypes.bool.isRequired,
        aliasEvents: React.PropTypes.array, // [MatrixEvent]
        canonicalAliasEvent: React.PropTypes.object // MatrixEvent
    },

    getDefaultProps: function() {
        return {
            canSetAliases: false,
            canSetCanonicalAlias: false,
            aliasEvents: []
        };
    },

    getInitialState: function() {
        return this.recalculateState(this.props.aliasEvents, this.props.canonicalAliasEvent);
    },

    recalculateState: function(aliasEvents, canonicalAliasEvent) {
        aliasEvents = aliasEvents || [];

        var state = {
            domainToAliases: {}, // { domain.com => [#alias1:domain.com, #alias2:domain.com] }
            remoteDomains: [], // [ domain.com, foobar.com ]
            canonicalAlias: null // #canonical:domain.com
        };
        var localDomain = MatrixClientPeg.get().getDomain();

        state.domainToAliases = this.aliasEventsToDictionary(aliasEvents);

        state.remoteDomains = Object.keys(state.domainToAliases).filter((alias) => {
            return alias !== localDomain;
        });

        if (canonicalAliasEvent) {
            state.canonicalAlias = canonicalAliasEvent.getContent().alias;
        }

        return state;
    },

    saveSettings: function() {
        var promises = [];

        // save new canonical alias
        var oldCanonicalAlias = null;
        if (this.props.canonicalAliasEvent) {
            oldCanonicalAlias = this.props.canonicalAliasEvent.getContent().alias;
        }
        if (oldCanonicalAlias !== this.state.canonicalAlias) {
            console.log("AliasSettings: Updating canonical alias");
            promises.push(
                MatrixClientPeg.get().sendStateEvent(
                    this.props.roomId, "m.room.canonical_alias", {
                        alias: this.state.canonicalAlias
                    }, ""
                )
            );
        }

        // save new aliases for m.room.aliases
        var aliasOperations = this.getAliasOperations();
        for (var i = 0; i < aliasOperations.length; i++) {
            var alias_operation = aliasOperations[i];
            console.log("alias %s %s", alias_operation.place, alias_operation.val);
            switch (alias_operation.place) {
                case 'add':
                    promises.push(
                        MatrixClientPeg.get().createAlias(
                            alias_operation.val, this.props.roomId
                        )
                    );
                    break;
                case 'del':
                    promises.push(
                        MatrixClientPeg.get().deleteAlias(
                            alias_operation.val
                        )
                    );
                    break;
                default:
                    console.log("Unknown alias operation, ignoring: " + alias_operation.place);
            }
        }

        return promises;
    },

    aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events
        var dict = {};
        aliasEvents.forEach((event) => {
            dict[event.getStateKey()] = (
                (event.getContent().aliases || []).slice() // shallow-copy
            );
        });
        return dict;
    },

    isAliasValid: function(alias) {
        // XXX: FIXME SPEC-1
        return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
    },

    getAliasOperations: function() {
        var oldAliases = this.aliasEventsToDictionary(this.props.aliasEvents);
        return ObjectUtils.getKeyValueArrayDiffs(oldAliases, this.state.domainToAliases);
    },

    onAliasAdded: function(alias) {
        if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases

        if (this.isAliasValid(alias)) {
            // add this alias to the domain to aliases dict
            var domain = alias.replace(/^.*?:/, '');
            // XXX: do we need to deep copy aliases before editing it?
            this.state.domainToAliases[domain] = this.state.domainToAliases[domain] || [];
            this.state.domainToAliases[domain].push(alias);
            this.setState({
                domainToAliases: this.state.domainToAliases
            });

            // reset the add field
            this.refs.add_alias.setValue(''); // FIXME
        }
        else {
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Invalid alias format",
                description: "'" + alias + "' is not a valid format for an alias",
            });
        }
    },

    onAliasChanged: function(domain, index, alias) {
        if (alias === "") return; // hit the delete button to delete please
        var oldAlias;
        if (this.isAliasValid(alias)) {
            oldAlias = this.state.domainToAliases[domain][index];
            this.state.domainToAliases[domain][index] = alias;
        }
        else {
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Invalid address format",
                description: "'" + alias + "' is not a valid format for an address",
            });
        }
    },

    onAliasDeleted: function(domain, index) {
        // It's a bit naughty to directly manipulate this.state, and React would
        // normally whine at you, but it can't see us doing the splice.  Given we
        // promptly setState anyway, it's just about acceptable.  The alternative
        // would be to arbitrarily deepcopy to a temp variable and then setState
        // that, but why bother when we can cut this corner.
        var alias = this.state.domainToAliases[domain].splice(index, 1);
        this.setState({
            domainToAliases: this.state.domainToAliases
        });
    },

    onCanonicalAliasChange: function(event) {
        this.setState({
            canonicalAlias: event.target.value
        });
    },

    render: function() {
        var self = this;
        var EditableText = sdk.getComponent("elements.EditableText");
        var localDomain = MatrixClientPeg.get().getDomain();

        var canonical_alias_section;
        if (this.props.canSetCanonicalAlias) {
            canonical_alias_section = (
                <select onChange={this.onCanonicalAliasChange} defaultValue={ this.state.canonicalAlias }>
                    <option value="" key="unset">not specified</option>
                    {
                        Object.keys(self.state.domainToAliases).map(function(domain, i) {
                            return self.state.domainToAliases[domain].map(function(alias, j) {
                                return (
                                    <option value={ alias } key={ i + "_" + j }>
                                        { alias }
                                    </option>
                                );
                            });
                        })
                    }
                </select>
            );
        }
        else {
            canonical_alias_section = (
                { this.state.canonicalAlias || "not set" }
            );
        }

        var remote_aliases_section;
        if (this.state.remoteDomains.length) {
            remote_aliases_section = (

                        Remote addresses for this room:

                        { this.state.remoteDomains.map((domain, i) => {
                            return this.state.domainToAliases[domain].map(function(alias, j) {
                                return (

                                        <EditableText
                                             className="mx_RoomSettings_alias mx_RoomSettings_editable"
                                             blurToCancel={ false }
                                             editable={ false }
                                             initialValue={ alias } />

                                );
                            });
                        })}

            );
        }

        return (

Addresses

                    The main address for this room is: { canonical_alias_section }

                    { (this.state.domainToAliases[localDomain] &&
                        this.state.domainToAliases[localDomain].length > 0)
                      ? "Local addresses for this room:"
                      : "This room has no local addresses" }

                    { (this.state.domainToAliases[localDomain] || []).map((alias, i) => {
                        var deleteButton;
                        if (this.props.canSetAliases) {
                            deleteButton = (

                            );
                        }
                        return (

                                <EditableText
                                    className="mx_RoomSettings_alias mx_RoomSettings_editable"
                                    placeholderClassName="mx_RoomSettings_aliasPlaceholder"
                                    placeholder={ "New address (e.g. #foo:" + localDomain + ")" }
                                    blurToCancel={ false }
                                    onValueChanged={ self.onAliasChanged.bind(self, localDomain, i) }
                                    editable={ self.props.canSetAliases }
                                    initialValue={ alias } />

                                     { deleteButton }

                        );
                    })}

                    { this.props.canSetAliases ?

                            <EditableText
                                ref="add_alias"
                                className="mx_RoomSettings_alias mx_RoomSettings_editable"
                                placeholderClassName="mx_RoomSettings_aliasPlaceholder"
                                placeholder={ "New address (e.g. #foo:" + localDomain + ")" }
                                blurToCancel={ false }
                                onValueChanged={ self.onAliasAdded } />

 : ""
                    }

                { remote_aliases_section }

        );
    }
});<commit_msg>fix race between setting canonical alias and creating aliases<commit_after>/*
Copyright 2016 OpenMarket Ltd

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.
*/

var q = require("q");
var React = require('react');
var ObjectUtils = require("../../../ObjectUtils");
var MatrixClientPeg = require('../../../MatrixClientPeg');
var sdk = require("../../../index");
var Modal = require("../../../Modal");

module.exports = React.createClass({
    displayName: 'AliasSettings',

    propTypes: {
        roomId: React.PropTypes.string.isRequired,
        canSetCanonicalAlias: React.PropTypes.bool.isRequired,
        canSetAliases: React.PropTypes.bool.isRequired,
        aliasEvents: React.PropTypes.array, // [MatrixEvent]
        canonicalAliasEvent: React.PropTypes.object // MatrixEvent
    },

    getDefaultProps: function() {
        return {
            canSetAliases: false,
            canSetCanonicalAlias: false,
            aliasEvents: []
        };
    },

    getInitialState: function() {
        return this.recalculateState(this.props.aliasEvents, this.props.canonicalAliasEvent);
    },

    recalculateState: function(aliasEvents, canonicalAliasEvent) {
        aliasEvents = aliasEvents || [];

        var state = {
            domainToAliases: {}, // { domain.com => [#alias1:domain.com, #alias2:domain.com] }
            remoteDomains: [], // [ domain.com, foobar.com ]
            canonicalAlias: null // #canonical:domain.com
        };
        var localDomain = MatrixClientPeg.get().getDomain();

        state.domainToAliases = this.aliasEventsToDictionary(aliasEvents);

        state.remoteDomains = Object.keys(state.domainToAliases).filter((alias) => {
            return alias !== localDomain;
        });

        if (canonicalAliasEvent) {
            state.canonicalAlias = canonicalAliasEvent.getContent().alias;
        }

        return state;
    },

    saveSettings: function() {
        var promises = [];

        // save new aliases for m.room.aliases
        var aliasOperations = this.getAliasOperations();
        for (var i = 0; i < aliasOperations.length; i++) {
            var alias_operation = aliasOperations[i];
            console.log("alias %s %s", alias_operation.place, alias_operation.val);
            switch (alias_operation.place) {
                case 'add':
                    promises.push(
                        MatrixClientPeg.get().createAlias(
                            alias_operation.val, this.props.roomId
                        )
                    );
                    break;
                case 'del':
                    promises.push(
                        MatrixClientPeg.get().deleteAlias(
                            alias_operation.val
                        )
                    );
                    break;
                default:
                    console.log("Unknown alias operation, ignoring: " + alias_operation.place);
            }
        }

        // save new canonical alias
        var oldCanonicalAlias = null;
        if (this.props.canonicalAliasEvent) {
            oldCanonicalAlias = this.props.canonicalAliasEvent.getContent().alias;
        }
        if (oldCanonicalAlias !== this.state.canonicalAlias) {
            console.log("AliasSettings: Updating canonical alias");
            promises = [ q.all(promises).then(
                MatrixClientPeg.get().sendStateEvent(
                    this.props.roomId, "m.room.canonical_alias", {
                        alias: this.state.canonicalAlias
                    }, ""
                )
            ) ];
        }

        return promises;
    },

    aliasEventsToDictionary: function(aliasEvents) { // m.room.alias events
        var dict = {};
        aliasEvents.forEach((event) => {
            dict[event.getStateKey()] = (
                (event.getContent().aliases || []).slice() // shallow-copy
            );
        });
        return dict;
    },

    isAliasValid: function(alias) {
        // XXX: FIXME SPEC-1
        return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
    },

    getAliasOperations: function() {
        var oldAliases = this.aliasEventsToDictionary(this.props.aliasEvents);
        return ObjectUtils.getKeyValueArrayDiffs(oldAliases, this.state.domainToAliases);
    },

    onAliasAdded: function(alias) {
        if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases

        if (this.isAliasValid(alias)) {
            // add this alias to the domain to aliases dict
            var domain = alias.replace(/^.*?:/, '');
            // XXX: do we need to deep copy aliases before editing it?
            this.state.domainToAliases[domain] = this.state.domainToAliases[domain] || [];
            this.state.domainToAliases[domain].push(alias);
            this.setState({
                domainToAliases: this.state.domainToAliases
            });

            // reset the add field
            this.refs.add_alias.setValue(''); // FIXME
        }
        else {
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Invalid alias format",
                description: "'" + alias + "' is not a valid format for an alias",
            });
        }
    },

    onAliasChanged: function(domain, index, alias) {
        if (alias === "") return; // hit the delete button to delete please
        var oldAlias;
        if (this.isAliasValid(alias)) {
            oldAlias = this.state.domainToAliases[domain][index];
            this.state.domainToAliases[domain][index] = alias;
        }
        else {
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Invalid address format",
                description: "'" + alias + "' is not a valid format for an address",
            });
        }
    },

    onAliasDeleted: function(domain, index) {
        // It's a bit naughty to directly manipulate this.state, and React would
        // normally whine at you, but it can't see us doing the splice.  Given we
        // promptly setState anyway, it's just about acceptable.  The alternative
        // would be to arbitrarily deepcopy to a temp variable and then setState
        // that, but why bother when we can cut this corner.
        var alias = this.state.domainToAliases[domain].splice(index, 1);
        this.setState({
            domainToAliases: this.state.domainToAliases
        });
    },

    onCanonicalAliasChange: function(event) {
        this.setState({
            canonicalAlias: event.target.value
        });
    },

    render: function() {
        var self = this;
        var EditableText = sdk.getComponent("elements.EditableText");
        var localDomain = MatrixClientPeg.get().getDomain();

        var canonical_alias_section;
        if (this.props.canSetCanonicalAlias) {
            canonical_alias_section = (
                <select onChange={this.onCanonicalAliasChange} defaultValue={ this.state.canonicalAlias }>
                    <option value="" key="unset">not specified</option>
                    {
                        Object.keys(self.state.domainToAliases).map(function(domain, i) {
                            return self.state.domainToAliases[domain].map(function(alias, j) {
                                return (
                                    <option value={ alias } key={ i + "_" + j }>
                                        { alias }
                                    </option>
                                );
                            });
                        })
                    }
                </select>
            );
        }
        else {
            canonical_alias_section = (
                { this.state.canonicalAlias || "not set" }
            );
        }

        var remote_aliases_section;
        if (this.state.remoteDomains.length) {
            remote_aliases_section = (

                        Remote addresses for this room:

                        { this.state.remoteDomains.map((domain, i) => {
                            return this.state.domainToAliases[domain].map(function(alias, j) {
                                return (

                                        <EditableText
                                             className="mx_RoomSettings_alias mx_RoomSettings_editable"
                                             blurToCancel={ false }
                                             editable={ false }
                                             initialValue={ alias } />

                                );
                            });
                        })}

            );
        }

        return (

Addresses

                    The main address for this room is: { canonical_alias_section }

                    { (this.state.domainToAliases[localDomain] &&
                        this.state.domainToAliases[localDomain].length > 0)
                      ? "Local addresses for this room:"
                      : "This room has no local addresses" }

                    { (this.state.domainToAliases[localDomain] || []).map((alias, i) => {
                        var deleteButton;
                        if (this.props.canSetAliases) {
                            deleteButton = (

                            );
                        }
                        return (

                                <EditableText
                                    className="mx_RoomSettings_alias mx_RoomSettings_editable"
                                    placeholderClassName="mx_RoomSettings_aliasPlaceholder"
                                    placeholder={ "New address (e.g. #foo:" + localDomain + ")" }
                                    blurToCancel={ false }
                                    onValueChanged={ self.onAliasChanged.bind(self, localDomain, i) }
                                    editable={ self.props.canSetAliases }
                                    initialValue={ alias } />

                                     { deleteButton }

                        );
                    })}

                    { this.props.canSetAliases ?

                            <EditableText
                                ref="add_alias"
                                className="mx_RoomSettings_alias mx_RoomSettings_editable"
                                placeholderClassName="mx_RoomSettings_aliasPlaceholder"
                                placeholder={ "New address (e.g. #foo:" + localDomain + ")" }
                                blurToCancel={ false }
                                onValueChanged={ self.onAliasAdded } />

 : ""
                    }

                { remote_aliases_section }

        );
    }
});<|endoftext|>


<commit_before>const once = require('event-promise');

module.exports.server=function(serv)
{
  serv.quit=async(reason="Going down") => {
    await Promise.all(serv.players.map((player) => {
      player.kick(reason);
      return once(player,'disconnected');
    }));
    serv._server.close();
    await once(serv._server,"close");
  };
};

module.exports.player=function(player,serv)
{
  player.despawnEntities = entities => player._client.write('entity_destroy', {
    'entityIds': entities.map(e => e.id)
  });

  player._client.on('end', () => {
    if(player) {
      serv.broadcast(serv.color.yellow + player.username + ' quit the game.');
      player._writeOthers('player_info', {
        action: 4,
        data: [{
          UUID: player._client.uuid
        }]
      });
      player.nearbyPlayers().forEach(otherPlayer => otherPlayer.despawnEntities([player]));
      delete serv.entities[player.id];
      player.emit('disconnected');
      const index = serv.players.indexOf(player);
      if (index > -1) {
        serv.players.splice(index, 1);
      }
      delete serv.uuidToPlayer[player._client.uuid];
    }
  });
};<commit_msg>fix undefined disconnected<commit_after>const once = require('event-promise');

module.exports.server=function(serv)
{
  serv.quit=async(reason="Going down") => {
    await Promise.all(serv.players.map((player) => {
      player.kick(reason);
      return once(player,'disconnected');
    }));
    serv._server.close();
    await once(serv._server,"close");
  };
};

module.exports.player=function(player,serv)
{
  player.despawnEntities = entities => player._client.write('entity_destroy', {
    'entityIds': entities.map(e => e.id)
  });

  player._client.on('end', () => {
    if(player && player.username) {
      serv.broadcast(serv.color.yellow + player.username + ' quit the game.');
      player._writeOthers('player_info', {
        action: 4,
        data: [{
          UUID: player._client.uuid
        }]
      });
      player.nearbyPlayers().forEach(otherPlayer => otherPlayer.despawnEntities([player]));
      delete serv.entities[player.id];
      player.emit('disconnected');
      const index = serv.players.indexOf(player);
      if (index > -1) {
        serv.players.splice(index, 1);
      }
      delete serv.uuidToPlayer[player._client.uuid];
    }
  });
};<|endoftext|>


<commit_before>import classNames from 'classnames';
import {Link} from 'react-router';
var React = require('react');

import Cluster from '../utils/Cluster';
var EventTypes = require('../constants/EventTypes');
import Framework from '../structs/Framework';
import HealthBar from './HealthBar';
import Icon from './Icon';
var MarathonStore = require('../stores/MarathonStore');
import NestedServiceLinks from '../components/NestedServiceLinks';
var ResourceTableUtil = require('../utils/ResourceTableUtil');
var ServiceTableHeaderLabels = require('../constants/ServiceTableHeaderLabels');
import ServiceTableUtil from '../utils/ServiceTableUtil';
import ServiceTree from '../structs/ServiceTree';
import StringUtil from '../utils/StringUtil';
import {Table} from 'reactjs-components';
import TableUtil from '../utils/TableUtil';
var Units = require('../utils/Units');

const StatusMapping = {
  'Running': 'running-state'
};

var ServicesTable = React.createClass({

  displayName: 'ServicesTable',

  defaultProps: {
    isFiltered: false
  },

  propTypes: {
    isFiltered: React.PropTypes.bool,
    services: React.PropTypes.array.isRequired
  },

  componentDidMount: function () {
    MarathonStore.addChangeListener(
      EventTypes.MARATHON_APPS_CHANGE,
      this.onMarathonAppsChange
    );
  },

  componentWillUnmount: function () {
    MarathonStore.removeChangeListener(
      EventTypes.MARATHON_APPS_CHANGE,
      this.onMarathonAppsChange
    );
  },

  getDefaultProps: function () {
    return {
      services: []
    };
  },

  getOpenInNewWindowLink(service) {
    if (!(service instanceof Framework) || !service.getWebURL()) {
      return null;
    }

    return (

        <Icon
          color="white"
          className="icon-margin-left icon-margin-left-wide"
          family="mini"
          id="open-external"
          size="mini" />

    );
  },

  onMarathonAppsChange: function () {
    this.forceUpdate();
  },

  getServiceLink: function (service) {
    const id = encodeURIComponent(service.getId());

    if (this.props.isFiltered) {
      return (
        <NestedServiceLinks
          serviceID={id}
          className="service-breadcrumb"
          majorLinkClassName="service-breadcrumb-service-id"
          minorLinkWrapperClassName="service-breadcrumb-crumb" />
      );
    }

    return (
      <Link to="services-detail"
        className="headline table-cell-value flex-box flex-box-col"
        params={{id}}>

          {service.getName()}

      </Link>
    );
  },

  getImage: function (service) {
    if (service instanceof ServiceTree) {
      // Get serviceTree image/icon
      return (
        <Icon
          className="icon-margin-right"
          color="grey"
          id="folder"
          size="small"
          family="small" />
      );
    }

    // Get service image/icon
    return (

    );
  },

  renderHeadline: function (prop, service) {
    const id = encodeURIComponent(service.getId());

    return (

        <Link to="services-detail"
          className="table-cell-icon"
          params={{id}}>
          {this.getImage(service)}
        </Link>
        {this.getServiceLink(service)}
        {this.getOpenInNewWindowLink(service)}

    );
  },

  renderStatus: function (prop, service) {
    let instanceCount = service.getInstancesCount();
    let serviceStatus = service.getStatus();
    let serviceStatusClassSet = StatusMapping[serviceStatus] || '';
    let taskSummary = service.getTasksSummary();
    let {tasksRunning} = taskSummary;

    let conciseOverview = ` (${tasksRunning}/${instanceCount})`;
    let verboseOverview = ` (${tasksRunning} ${StringUtil.pluralize('Task', tasksRunning)})`;
    if (tasksRunning !== instanceCount) {
      verboseOverview = ` (${tasksRunning} of ${instanceCount} Tasks)`;
    }

    return (

          <HealthBar tasksSummary={taskSummary} instancesCount={instanceCount} />

          {serviceStatus}
          {verboseOverview}
          {conciseOverview}

    );
  },

  renderStats: function (prop, service) {
    return (

        {Units.formatResource(prop, service.getResources()[prop])}

    );
  },

  renderStatsHeading: function (prop, sortBy, row) {
    let isHeader = row == null;

    return classNames('flush-left text-align-right hidden-mini hidden-small', {
      'highlight': prop === sortBy.prop,
      'clickable': isHeader
    });
  },

  getColumns: function () {
    let className = ResourceTableUtil.getClassName;
    let heading = ResourceTableUtil.renderHeading(ServiceTableHeaderLabels);
    let {isFiltered} = this.props;

    return [
      {
        className: function () {
          return classNames([
            className.apply(this, arguments),
            {'table-cell-short': isFiltered}
          ]);
        },
        headerClassName: className,
        prop: 'name',
        render: this.renderHeadline,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className,
        headerClassName: className,
        prop: 'status',
        helpText: 'At-a-glance overview of the global application or group state',
        render: this.renderStatus,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className: this.renderStatsHeading,
        headerClassName: this.renderStatsHeading,
        prop: 'cpus',
        render: this.renderStats,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className: this.renderStatsHeading,
        headerClassName: this.renderStatsHeading,
        prop: 'mem',
        render: this.renderStats,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className: this.renderStatsHeading,
        headerClassName: this.renderStatsHeading,
        prop: 'disk',
        render: this.renderStats,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      }
    ];
  },

  getColGroup: function () {
    return (
      <colgroup>
        <col />
        <col className="status-bar-column"/>
        <col className="hidden-mini hidden-small" style={{width: '85px'}} />
        <col className="hidden-mini hidden-small" style={{width: '75px'}} />
        <col className="hidden-mini hidden-small" style={{width: '85px'}} />
      </colgroup>
    );
  },

  render: function () {
    return (

    );
  }
});

module.exports = ServicesTable;
<commit_msg>Fix animating of healthbar in service table<commit_after>import classNames from 'classnames';
import {Link} from 'react-router';
var React = require('react');

import Cluster from '../utils/Cluster';
var EventTypes = require('../constants/EventTypes');
import Framework from '../structs/Framework';
import HealthBar from './HealthBar';
import Icon from './Icon';
var MarathonStore = require('../stores/MarathonStore');
import NestedServiceLinks from '../components/NestedServiceLinks';
var ResourceTableUtil = require('../utils/ResourceTableUtil');
var ServiceTableHeaderLabels = require('../constants/ServiceTableHeaderLabels');
import ServiceTableUtil from '../utils/ServiceTableUtil';
import ServiceTree from '../structs/ServiceTree';
import StringUtil from '../utils/StringUtil';
import {Table} from 'reactjs-components';
import TableUtil from '../utils/TableUtil';
var Units = require('../utils/Units');

const StatusMapping = {
  'Running': 'running-state'
};

var ServicesTable = React.createClass({

  displayName: 'ServicesTable',

  defaultProps: {
    isFiltered: false
  },

  propTypes: {
    isFiltered: React.PropTypes.bool,
    services: React.PropTypes.array.isRequired
  },

  componentDidMount: function () {
    MarathonStore.addChangeListener(
      EventTypes.MARATHON_APPS_CHANGE,
      this.onMarathonAppsChange
    );
  },

  componentWillUnmount: function () {
    MarathonStore.removeChangeListener(
      EventTypes.MARATHON_APPS_CHANGE,
      this.onMarathonAppsChange
    );
  },

  getDefaultProps: function () {
    return {
      services: []
    };
  },

  getOpenInNewWindowLink(service) {
    if (!(service instanceof Framework) || !service.getWebURL()) {
      return null;
    }

    return (

        <Icon
          color="white"
          className="icon-margin-left icon-margin-left-wide"
          family="mini"
          id="open-external"
          size="mini" />

    );
  },

  onMarathonAppsChange: function () {
    this.forceUpdate();
  },

  getServiceLink: function (service) {
    const id = encodeURIComponent(service.getId());

    if (this.props.isFiltered) {
      return (
        <NestedServiceLinks
          serviceID={id}
          className="service-breadcrumb"
          majorLinkClassName="service-breadcrumb-service-id"
          minorLinkWrapperClassName="service-breadcrumb-crumb" />
      );
    }

    return (
      <Link to="services-detail"
        className="headline table-cell-value flex-box flex-box-col"
        params={{id}}>

          {service.getName()}

      </Link>
    );
  },

  getImage: function (service) {
    if (service instanceof ServiceTree) {
      // Get serviceTree image/icon
      return (
        <Icon
          className="icon-margin-right"
          color="grey"
          id="folder"
          size="small"
          family="small" />
      );
    }

    // Get service image/icon
    return (

    );
  },

  renderHeadline: function (prop, service) {
    const id = encodeURIComponent(service.getId());

    return (

        <Link to="services-detail"
          className="table-cell-icon"
          params={{id}}>
          {this.getImage(service)}
        </Link>
        {this.getServiceLink(service)}
        {this.getOpenInNewWindowLink(service)}

    );
  },

  renderStatus: function (prop, service) {
    let instanceCount = service.getInstancesCount();
    let serviceId = service.getId();
    let serviceStatus = service.getStatus();
    let serviceStatusClassSet = StatusMapping[serviceStatus] || '';
    let taskSummary = service.getTasksSummary();
    let {tasksRunning} = taskSummary;

    let conciseOverview = ` (${tasksRunning}/${instanceCount})`;
    let verboseOverview = ` (${tasksRunning} ${StringUtil.pluralize('Task', tasksRunning)})`;
    if (tasksRunning !== instanceCount) {
      verboseOverview = ` (${tasksRunning} of ${instanceCount} Tasks)`;
    }

    return (

          <HealthBar
            key={serviceId}
            tasksSummary={taskSummary}
            instancesCount={instanceCount} />

          {serviceStatus}
          {verboseOverview}
          {conciseOverview}

    );
  },

  renderStats: function (prop, service) {
    return (

        {Units.formatResource(prop, service.getResources()[prop])}

    );
  },

  renderStatsHeading: function (prop, sortBy, row) {
    let isHeader = row == null;

    return classNames('flush-left text-align-right hidden-mini hidden-small', {
      'highlight': prop === sortBy.prop,
      'clickable': isHeader
    });
  },

  getColumns: function () {
    let className = ResourceTableUtil.getClassName;
    let heading = ResourceTableUtil.renderHeading(ServiceTableHeaderLabels);
    let {isFiltered} = this.props;

    return [
      {
        className: function () {
          return classNames([
            className.apply(this, arguments),
            {'table-cell-short': isFiltered}
          ]);
        },
        headerClassName: className,
        prop: 'name',
        render: this.renderHeadline,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className,
        headerClassName: className,
        prop: 'status',
        helpText: 'At-a-glance overview of the global application or group state',
        render: this.renderStatus,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className: this.renderStatsHeading,
        headerClassName: this.renderStatsHeading,
        prop: 'cpus',
        render: this.renderStats,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className: this.renderStatsHeading,
        headerClassName: this.renderStatsHeading,
        prop: 'mem',
        render: this.renderStats,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      },
      {
        className: this.renderStatsHeading,
        headerClassName: this.renderStatsHeading,
        prop: 'disk',
        render: this.renderStats,
        sortable: true,
        sortFunction: ServiceTableUtil.propCompareFunctionFactory,
        heading
      }
    ];
  },

  getColGroup: function () {
    return (
      <colgroup>
        <col />
        <col className="status-bar-column"/>
        <col className="hidden-mini hidden-small" style={{width: '85px'}} />
        <col className="hidden-mini hidden-small" style={{width: '75px'}} />
        <col className="hidden-mini hidden-small" style={{width: '85px'}} />
      </colgroup>
    );
  },

  render: function () {
    return (

    );
  }
});

module.exports = ServicesTable;
<|endoftext|>


<commit_before>/**
 * licy.js
 *
 * Copyright (c) 2012 Maximilian Antoni <mail@maxantoni.de>
 *
 * @license MIT
 */
'use strict';

var licy  = require('licy');
var fs    = require('fs');
var path  = require('path');

function typeOf(value) {
  if (value === null) {
    return 'null';
  }
  var type = Object.prototype.toString.call(value);
  return type.substring(8, type.length - 1).toLowerCase();
}

module.exports = function (config) {
  var cwd         = process.cwd();
  var configType  = typeOf(config);
  var file;
  if (configType === 'string') {
    file        = config;
    cwd         = path.resolve(cwd, config, '..');
    config      = JSON.parse(fs.readFileSync(file));
    configType  = typeOf(config);
  }
  if (configType !== 'object') {
    if (file) {
      throw new TypeError('Config \'' + file + '\' is ' + configType +
        '. Must be object.');
    }
    throw new TypeError('Config is ' + configType +
      '. Must be string or object.');
  }
  Object.keys(config).forEach(function (name) {
    var module      = config[name];
    var moduleType  = typeOf(module);
    var dependencies;

    if (moduleType === 'object') {
      dependencies  = module.dependencies;
      module        = module.module;
      moduleType    = typeOf(module);
    }
    if (moduleType !== 'string') {
      throw new TypeError('Module reference for \'' + name + '\' is ' +
        moduleType + '. Must be string or array.');
    }
    var file    = path.resolve(cwd, module);
    var plugin  = require(file);
    if (dependencies) {
      licy.plugin(name, dependencies, plugin);
    } else {
      licy.plugin(name, plugin);
    }
  });
  return licy;
};
<commit_msg>Allowing to override directory used to load modules from<commit_after>/**
 * licy.js
 *
 * Copyright (c) 2012 Maximilian Antoni <mail@maxantoni.de>
 *
 * @license MIT
 */
'use strict';

var licy  = require('licy');
var fs    = require('fs');
var path  = require('path');

function typeOf(value) {
  if (value === null) {
    return 'null';
  }
  var type = Object.prototype.toString.call(value);
  return type.substring(8, type.length - 1).toLowerCase();
}

module.exports = function (config, dir) {
  var cwd         = dir || process.cwd();
  var configType  = typeOf(config);
  var file;
  if (configType === 'string') {
    file        = config;
    cwd         = path.resolve(cwd, config, '..');
    config      = JSON.parse(fs.readFileSync(file));
    configType  = typeOf(config);
  }
  if (configType !== 'object') {
    if (file) {
      throw new TypeError('Config \'' + file + '\' is ' + configType +
        '. Must be object.');
    }
    throw new TypeError('Config is ' + configType +
      '. Must be string or object.');
  }
  Object.keys(config).forEach(function (name) {
    var module      = config[name];
    var moduleType  = typeOf(module);
    var dependencies;

    if (moduleType === 'object') {
      dependencies  = module.dependencies;
      module        = module.module;
      moduleType    = typeOf(module);
    }
    if (moduleType !== 'string') {
      throw new TypeError('Module reference for \'' + name + '\' is ' +
        moduleType + '. Must be string or array.');
    }
    var file    = path.resolve(cwd, module);
    var plugin  = require(file);
    if (dependencies) {
      licy.plugin(name, dependencies, plugin);
    } else {
      licy.plugin(name, plugin);
    }
  });
  return licy;
};
<|endoftext|>


<commit_before>import * as types from '../actions/actionTypes';
import { initializeFrame } from '../utils/frame';

const frame = initializeFrame();
const defaultState = {
    frame,
    frames: [frame],
    redoFrames: [],
    animate: [frame],
    selectedFrame: 0,
    isEditing: true,
    fps: 30,
    isPlaying: false,
    isReversed: false,
    clipboard: null,
};

export default (state = defaultState, action) => {
    switch (action.type) {
        case types.UNDO:
            return {
                ...state,
                frame: state.frames.slice(-2)[0],
                frames: state.frames.slice(0, state.frames.length - 1),
                redoFrames: state.redoFrames.concat(state.frame),
            };
        case types.REDO:
            return {
                ...state,
                frame: state.redoFrames.slice(-1)[0],
                frames: state.frames.concat(state.redoFrames.slice(-1)[0]),
                redoFrames: state.redoFrames.slice(0, -1),
            };
        case types.PAINT_FRAME: {
            if (state.isEditing && !state.isPlaying) {
                const newAnimation = [...state.animate];
                newAnimation[state.selectedFrame] = action.payload;
                return { ...state, frame: action.payload, redoFrames: [], animate: newAnimation };
            }
            return { ...state, frame: action.payload, redoFrames: [] };
        }
        case types.KEYFRAME:
            return { ...state, frames: state.frames.concat(state.frame) };
        case types.CAPTURE:
            return { ...state, animate: state.animate.concat(state.frame) };
        case types.TOGGLE_EDITING:
            return { ...state, isEditing: !state.isEditing };
        case types.SELECT_ANIMATION_FRAME: {
            if (typeof action.payload === 'number') {
                return {
                    ...state,
                    frame: state.animate[action.payload],
                    frames: state.frames.concat(state.animate[action.payload]),
                    redoFrames: [],
                    selectedFrame: action.payload,
                };
            }
            return { ...state, selectedFrame: null };
        }
        case types.DELETE_FRAME: {
            const withoutFrame = state.animate.filter((e, i) => (i !== state.selectedFrame));
            const newAnimation = withoutFrame.length ? state.animate.filter((e, i) => (i !== state.selectedFrame)) : [frame];

            const selectedFrame = state.selectedFrame >= state.animate.length - 1
                    ? Math.max(state.selectedFrame - 1, 0)
                    : state.selectedFrame;

            return { ...state,
                animate: newAnimation,
                selectedFrame,
                frame: newAnimation[selectedFrame],
            };
        }
        case types.INSERT_FRAME:
            return {
                ...state,
                selectedFrame: state.selectedFrame + 1,
                animate: [
                    ...state.animate.slice(0, state.selectedFrame + 1),
                    state.frame,
                    ...state.animate.slice(state.selectedFrame + 1)],
            };
        case types.LOAD_FRAME:
            return {
                ...state,
                frame: state.animate[state.selectedFrame],
                frames: state.frames.concat(state.frame),
            };
        case types.LOAD_FILE:
            return {
                ...state,
                frame: action.payload.frame,
                animate: action.payload.animate,
                fps: action.payload.fps,
            };
        case types.SET_IS_PLAYING:
            return {
                ...state,
                isPlaying: action.payload,
            };
        case types.TOGGLE_REVERSE:
            return {
                ...state,
                isReversed: !state.isReversed,
            };
        case types.SET_FPS:
            return {
                ...state,
                fps: action.payload,
            };
        case types.COPY:
            return {
                ...state,
                clipboard: state.frame,
            };
        default:
            return state;
    }
};
<commit_msg>Added cap for undo to avoid large memory size<commit_after>import * as types from '../actions/actionTypes';
import { initializeFrame } from '../utils/frame';

const MAX_UNDO = -40;
const frame = initializeFrame();
const defaultState = {
    frame,
    frames: [frame],
    redoFrames: [],
    animate: [frame],
    selectedFrame: 0,
    isEditing: true,
    fps: 30,
    isPlaying: false,
    isReversed: false,
    clipboard: null,
};

export default (state = defaultState, action) => {
    switch (action.type) {
        case types.UNDO:
            return {
                ...state,
                frame: state.frames.slice(-2)[0],
                frames: state.frames.slice(0, state.frames.length - 1),
                redoFrames: state.redoFrames.concat(state.frame),
            };
        case types.REDO:
            return {
                ...state,
                frame: state.redoFrames.slice(-1)[0],
                frames: state.frames.concat(state.redoFrames.slice(-1)[0]),
                redoFrames: state.redoFrames.slice(0, -1),
            };
        case types.PAINT_FRAME: {
            if (state.isEditing && !state.isPlaying) {
                const newAnimation = [...state.animate];
                newAnimation[state.selectedFrame] = action.payload;
                return { ...state, frame: action.payload, redoFrames: [], animate: newAnimation };
            }
            return { ...state, frame: action.payload, redoFrames: [] };
        }
        case types.KEYFRAME:
            return { ...state, frames: state.frames.slice(MAX_UNDO).concat(state.frame) };
        case types.CAPTURE:
            return { ...state, animate: state.animate.concat(state.frame) };
        case types.TOGGLE_EDITING:
            return { ...state, isEditing: !state.isEditing };
        case types.SELECT_ANIMATION_FRAME: {
            if (typeof action.payload === 'number') {
                return {
                    ...state,
                    frame: state.animate[action.payload],
                    frames: state.frames.slice(MAX_UNDO).concat(state.animate[action.payload]),
                    redoFrames: [],
                    selectedFrame: action.payload,
                };
            }
            return { ...state, selectedFrame: null };
        }
        case types.DELETE_FRAME: {
            const withoutFrame = state.animate.filter((e, i) => (i !== state.selectedFrame));
            const newAnimation = withoutFrame.length ? state.animate.filter((e, i) => (i !== state.selectedFrame)) : [frame];

            const selectedFrame = state.selectedFrame >= state.animate.length - 1
                    ? Math.max(state.selectedFrame - 1, 0)
                    : state.selectedFrame;

            return { ...state,
                animate: newAnimation,
                selectedFrame,
                frame: newAnimation[selectedFrame],
            };
        }
        case types.INSERT_FRAME:
            return {
                ...state,
                selectedFrame: state.selectedFrame + 1,
                animate: [
                    ...state.animate.slice(0, state.selectedFrame + 1),
                    state.frame,
                    ...state.animate.slice(state.selectedFrame + 1)],
            };
        case types.LOAD_FRAME:
            return {
                ...state,
                frame: state.animate[state.selectedFrame],
                frames: state.frames.slice(MAX_UNDO).concat(state.frame),
            };
        case types.LOAD_FILE:
            return {
                ...state,
                frame: action.payload.frame,
                animate: action.payload.animate,
                fps: action.payload.fps,
            };
        case types.SET_IS_PLAYING:
            return {
                ...state,
                isPlaying: action.payload,
            };
        case types.TOGGLE_REVERSE:
            return {
                ...state,
                isReversed: !state.isReversed,
            };
        case types.SET_FPS:
            return {
                ...state,
                fps: action.payload,
            };
        case types.COPY:
            return {
                ...state,
                clipboard: state.frame,
            };
        default:
            return state;
    }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import styled, { css } from 'styled-components';
import { useCallback, useState } from 'react';

/**
 * Internal dependencies
 */
import { elementFillContent, elementWithFlip } from '../shared';
import { useStory } from '../../app';
import StoryPropTypes from '../../types';
import WithMask from '../../masks/display';
import getTransformFlip from '../shared/getTransformFlip';
import EditCropMovable from './editCropMovable';
import { mediaWithScale } from './util';
import getMediaSizePositionProps from './getMediaSizePositionProps';
import EditPanMovable from './editPanMovable';
import ScalePanel from './scalePanel';
import { CropBox, MEDIA_MASK_OPACITY } from './';

const Element = styled.div`
  ${elementFillContent}
`;

// Opacity of the mask is reduced depending on the opacity assigned to the media.
const fadedMediaCSS = css`
  position: absolute;
  opacity: ${({ opacity }) =>
    opacity ? opacity * MEDIA_MASK_OPACITY : MEDIA_MASK_OPACITY};
  pointer-events: none;
  ${mediaWithScale}
  ${elementWithFlip}
`;

const FadedImage = styled.img`
  ${fadedMediaCSS}
`;

const FadedVideo = styled.video`
  ${fadedMediaCSS}
  max-width: initial;
  max-height: initial;
`;

// Opacity is adjusted so that the double image opacity would equal
// the opacity assigned to the image.
const cropMediaCSS = css`
  ${mediaWithScale}
  ${elementWithFlip}
  position: absolute;
  opacity: ${({ opacity }) =>
    opacity ? 1 - (1 - opacity) / (1 - opacity * MEDIA_MASK_OPACITY) : null};
`;

const CropImage = styled.img`
  ${cropMediaCSS}
`;

// Opacity of the mask is reduced depending on the opacity assigned to the video.
const CropVideo = styled.video`
  ${cropMediaCSS}
  max-width: initial;
  max-height: initial;
`;

function MediaEdit({ element, box }) {
  const {
    id,
    resource,
    opacity,
    scale,
    flip,
    focalX,
    focalY,
    isBackground,
    type,
  } = element;
  const { x, y, width, height, rotationAngle } = box;
  const [fullMedia, setFullMedia] = useState(null);
  const [croppedMedia, setCroppedMedia] = useState(null);
  const [cropBox, setCropBox] = useState(null);

  const { updateElementById } = useStory((state) => ({
    updateElementById: state.actions.updateElementById,
  }));
  const setProperties = useCallback(
    (properties) => updateElementById({ elementId: id, properties }),
    [id, updateElementById]
  );

  const mediaProps = getMediaSizePositionProps(
    resource,
    width,
    height,
    scale,
    flip?.horizontal ? 100 - focalX : focalX,
    flip?.vertical ? 100 - focalY : focalY
  );

  mediaProps.transformFlip = getTransformFlip(flip);

  const fadedMediaProps = {
    ref: setFullMedia,
    draggable: false,
    opacity: opacity / 100,
    ...mediaProps,
  };

  const cropMediaProps = {
    ref: setCroppedMedia,
    draggable: false,
    src: resource.src,
    alt: resource.alt,
    opacity: opacity / 100,
    ...mediaProps,
  };

  const isImage = 'image' === type;
  const isVideo = 'video' === type;
  return (
    <Element>
      {isImage && <FadedImage {...fadedMediaProps} src={resource.src} />}
      {isVideo && (
        <FadedVideo {...fadedMediaProps}>
          <source src={resource.src} type={resource.mimeType} />
        </FadedVideo>
      )}
      <CropBox ref={setCropBox}>
        <WithMask element={element} fill={true} applyFlip={false} box={box}>
          {isImage && <CropImage {...cropMediaProps} />}
          {isVideo && (
            <CropVideo {...cropMediaProps}>
              <source src={resource.src} type={resource.mimeType} />
            </CropVideo>
          )}
        </WithMask>
      </CropBox>

      {fullMedia && croppedMedia && (
        <EditPanMovable
          setProperties={setProperties}
          fullMedia={fullMedia}
          croppedMedia={croppedMedia}
          flip={flip}
          x={x}
          y={y}
          width={width}
          height={height}
          rotationAngle={rotationAngle}
          offsetX={mediaProps.offsetX}
          offsetY={mediaProps.offsetY}
          mediaWidth={mediaProps.width}
          mediaHeight={mediaProps.height}
        />
      )}

      {!isBackground && cropBox && croppedMedia && (
        <EditCropMovable
          setProperties={setProperties}
          cropBox={cropBox}
          croppedMedia={croppedMedia}
          flip={flip}
          x={x}
          y={y}
          width={width}
          height={height}
          rotationAngle={rotationAngle}
          offsetX={mediaProps.offsetX}
          offsetY={mediaProps.offsetY}
          mediaWidth={mediaProps.width}
          mediaHeight={mediaProps.height}
        />
      )}

      <ScalePanel
        setProperties={setProperties}
        x={x}
        y={y}
        width={width}
        height={height}
        scale={scale || 100}
      />
    </Element>
  );
}

MediaEdit.propTypes = {
  element: StoryPropTypes.elements.media.isRequired,
  box: StoryPropTypes.box.isRequired,
};

export default MediaEdit;
<commit_msg>Media: Use different cursor on the image editor indicating panning (#2754)<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * External dependencies
 */
import styled, { css } from 'styled-components';
import { useCallback, useState } from 'react';

/**
 * Internal dependencies
 */
import { elementFillContent, elementWithFlip } from '../shared';
import { useStory } from '../../app';
import StoryPropTypes from '../../types';
import WithMask from '../../masks/display';
import getTransformFlip from '../shared/getTransformFlip';
import EditCropMovable from './editCropMovable';
import { mediaWithScale } from './util';
import getMediaSizePositionProps from './getMediaSizePositionProps';
import EditPanMovable from './editPanMovable';
import ScalePanel from './scalePanel';
import { CropBox, MEDIA_MASK_OPACITY } from './';

const Element = styled.div`
  ${elementFillContent}
`;

// Opacity of the mask is reduced depending on the opacity assigned to the media.
const fadedMediaCSS = css`
  position: absolute;
  opacity: ${({ opacity }) =>
    opacity ? opacity * MEDIA_MASK_OPACITY : MEDIA_MASK_OPACITY};
  pointer-events: none;
  ${mediaWithScale}
  ${elementWithFlip}
`;

const FadedImage = styled.img`
  ${fadedMediaCSS}
`;

const FadedVideo = styled.video`
  ${fadedMediaCSS}
  max-width: initial;
  max-height: initial;
`;

// Opacity is adjusted so that the double image opacity would equal
// the opacity assigned to the image.
const cropMediaCSS = css`
  ${mediaWithScale}
  ${elementWithFlip}
  position: absolute;
  cursor: grab;
  opacity: ${({ opacity }) =>
    opacity ? 1 - (1 - opacity) / (1 - opacity * MEDIA_MASK_OPACITY) : null};
`;

const CropImage = styled.img`
  ${cropMediaCSS}
`;

// Opacity of the mask is reduced depending on the opacity assigned to the video.
const CropVideo = styled.video`
  ${cropMediaCSS}
  max-width: initial;
  max-height: initial;
`;

function MediaEdit({ element, box }) {
  const {
    id,
    resource,
    opacity,
    scale,
    flip,
    focalX,
    focalY,
    isBackground,
    type,
  } = element;
  const { x, y, width, height, rotationAngle } = box;
  const [fullMedia, setFullMedia] = useState(null);
  const [croppedMedia, setCroppedMedia] = useState(null);
  const [cropBox, setCropBox] = useState(null);

  const { updateElementById } = useStory((state) => ({
    updateElementById: state.actions.updateElementById,
  }));
  const setProperties = useCallback(
    (properties) => updateElementById({ elementId: id, properties }),
    [id, updateElementById]
  );

  const mediaProps = getMediaSizePositionProps(
    resource,
    width,
    height,
    scale,
    flip?.horizontal ? 100 - focalX : focalX,
    flip?.vertical ? 100 - focalY : focalY
  );

  mediaProps.transformFlip = getTransformFlip(flip);

  const fadedMediaProps = {
    ref: setFullMedia,
    draggable: false,
    opacity: opacity / 100,
    ...mediaProps,
  };

  const cropMediaProps = {
    ref: setCroppedMedia,
    draggable: false,
    src: resource.src,
    alt: resource.alt,
    opacity: opacity / 100,
    ...mediaProps,
  };

  const isImage = 'image' === type;
  const isVideo = 'video' === type;
  return (
    <Element>
      {isImage && <FadedImage {...fadedMediaProps} src={resource.src} />}
      {isVideo && (
        <FadedVideo {...fadedMediaProps}>
          <source src={resource.src} type={resource.mimeType} />
        </FadedVideo>
      )}
      <CropBox ref={setCropBox}>
        <WithMask element={element} fill={true} applyFlip={false} box={box}>
          {isImage && <CropImage {...cropMediaProps} />}
          {isVideo && (
            <CropVideo {...cropMediaProps}>
              <source src={resource.src} type={resource.mimeType} />
            </CropVideo>
          )}
        </WithMask>
      </CropBox>

      {fullMedia && croppedMedia && (
        <EditPanMovable
          setProperties={setProperties}
          fullMedia={fullMedia}
          croppedMedia={croppedMedia}
          flip={flip}
          x={x}
          y={y}
          width={width}
          height={height}
          rotationAngle={rotationAngle}
          offsetX={mediaProps.offsetX}
          offsetY={mediaProps.offsetY}
          mediaWidth={mediaProps.width}
          mediaHeight={mediaProps.height}
        />
      )}

      {!isBackground && cropBox && croppedMedia && (
        <EditCropMovable
          setProperties={setProperties}
          cropBox={cropBox}
          croppedMedia={croppedMedia}
          flip={flip}
          x={x}
          y={y}
          width={width}
          height={height}
          rotationAngle={rotationAngle}
          offsetX={mediaProps.offsetX}
          offsetY={mediaProps.offsetY}
          mediaWidth={mediaProps.width}
          mediaHeight={mediaProps.height}
        />
      )}

      <ScalePanel
        setProperties={setProperties}
        x={x}
        y={y}
        width={width}
        height={height}
        scale={scale || 100}
      />
    </Element>
  );
}

MediaEdit.propTypes = {
  element: StoryPropTypes.elements.media.isRequired,
  box: StoryPropTypes.box.isRequired,
};

export default MediaEdit;
<|endoftext|>


<commit_before>/*global require, module, setTimeout*/
/** @jsx React.DOM */
var React = require('react'),
    AppStore = require('../stores/app-base-store'),
    AppActions = require('../actions/app-actions'),
    SearchResult = require('../components/app-SearchResult'),
    Menu = require('../components/app-Menu'),
    Rx = require('rx'),
    EventHandler = require('../util/eventHandler');

var SearchBox = React.createClass({
    ActiveItem: 0,
    MinimumQueryLength: 2,
    getInitialState: function () {
        "use strict";
        return {
            "showResults": true
        };
    },
    componentWillMount: function () {
        "use strict";
        /*Search requests to the store are throttled with the help of RxJs to
         * minimize the performance hit */
        var filter = EventHandler.create();
            filter.select(function (event) {
                return event.target.value;
            })
            .skipWhile(function (query) {
                return query.length < this.MinimumQueryLength;
            }.bind(this))
            .throttle(500)
            .distinctUntilChanged()
            .subscribe(function (query) {
                if (query.length > this.MinimumQueryLength) {
                    AppActions.search(query);
                    this._toggleResultsPanel(true);
                    if (this.refs.searchResult._getCurrentActiveResult()) {
                        this.refs.searchResult._getCurrentActiveResult()._addActive();
                    }
                } else {
                    //clear the search results on the removing the filter text
                    //so that it'll not be picked when search box focused
                    AppActions.clearSearch();
                    this._toggleResultsPanel(false);
                }
            }.bind(this));

        this.filter = filter;
    },
    _toggleResultsPanel: function (show) {
        "use strict";
        this.setState({
            "showResults": show
        });
    },

    _navigate: function (event) {
        "use strict";
        this.refs.searchResult._navigate(event);
    },

    _showResults: function () {
        "use strict";
        this._toggleResultsPanel(true);
    },
    _hideResults: function () {
        "use strict";
        //setTimeout is there to handle the special event handling issue with onBlur
        setTimeout(function () {
            this._toggleResultsPanel(false);
        }.bind(this), 200);
    },
    render: function () {
        "use strict";
        return (

                    <input id="search" ref="searchBox" type="text" className="form-control search-control"
                        onChange={this.filter} onKeyUp={this._navigate} onFocus={this._showResults} onClick={this._showResults}
                        onBlur={this._hideResults} placeholder="Type name or use tags #p #id #t #a ..."/>
                    <Menu />
                    {
                        this.state.showResults
                            ? <SearchResult ref="searchResult" results={this.props.items}
                                            toggleResultsPanel={this._toggleResultsPanel}/>
                            : null
                    }

        );
    }
});

module.exports = SearchBox;<commit_msg>Show search result set before navigate<commit_after>/*global require, module, setTimeout*/
/** @jsx React.DOM */
var React = require('react'),
    AppStore = require('../stores/app-base-store'),
    AppActions = require('../actions/app-actions'),
    SearchResult = require('../components/app-SearchResult'),
    Menu = require('../components/app-Menu'),
    Rx = require('rx'),
    EventHandler = require('../util/eventHandler');

var SearchBox = React.createClass({
    ActiveItem: 0,
    MinimumQueryLength: 2,
    getInitialState: function () {
        "use strict";
        return {
            "showResults": true
        };
    },
    componentWillMount: function () {
        "use strict";
        /*Search requests to the store are throttled with the help of RxJs to
         * minimize the performance hit */
        var filter = EventHandler.create();
            filter.select(function (event) {
                return event.target.value;
            })
            .skipWhile(function (query) {
                return query.length < this.MinimumQueryLength;
            }.bind(this))
            .throttle(500)
            .distinctUntilChanged()
            .subscribe(function (query) {
                if (query.length > this.MinimumQueryLength) {
                    AppActions.search(query);
                    this._toggleResultsPanel(true);
                    if (this.refs.searchResult._getCurrentActiveResult()) {
                        this.refs.searchResult._getCurrentActiveResult()._addActive();
                    }
                } else {
                    //clear the search results on the removing the filter text
                    //so that it'll not be picked when search box focused
                    AppActions.clearSearch();
                    this._toggleResultsPanel(false);
                }
            }.bind(this));

        this.filter = filter;
    },
    _toggleResultsPanel: function (show) {
        "use strict";
        this.setState({
            "showResults": show
        });
    },

    _navigate: function (event) {
        "use strict";
        this._showResults();
        this.refs.searchResult._navigate(event);
    },

    _showResults: function () {
        "use strict";
        this._toggleResultsPanel(true);
    },
    _hideResults: function () {
        "use strict";
        //setTimeout is there to handle the special event handling issue with onBlur
        setTimeout(function () {
            this._toggleResultsPanel(false);
        }.bind(this), 200);
    },
    render: function () {
        "use strict";
        return (

                    <input id="search" ref="searchBox" type="text" className="form-control search-control"
                        onChange={this.filter} onKeyUp={this._navigate} onFocus={this._showResults} onClick={this._showResults}
                        onBlur={this._hideResults} placeholder="Type name or use tags #p #id #t #a ..."/>
                    <Menu />
                    {
                        this.state.showResults
                            ? <SearchResult ref="searchResult" results={this.props.items}
                                            toggleResultsPanel={this._toggleResultsPanel}/>
                            : null
                    }

        );
    }
});

module.exports = SearchBox;<|endoftext|>


<commit_before>
// link the supplied folder to .npm/{name}/{version}/package

var npm = require("../npm")
  , chain = require("./utils/chain")
  , log = require("./utils/log")
  , fs = require("./utils/graceful-fs")
  , readJson = require("./utils/read-json")
  , rm = require("./utils/rm-rf")
  , mkdir = require("./utils/mkdir-p")
  , path = require("path")
  , crypto
  , readInstalled = require("./utils/read-installed")
  , semver = require("./utils/semver")

try {
  crypto = process.binding("crypto") && require("crypto")
} catch (ex) {}

module.exports = link

function link (args, cb) {
  if (!crypto) return cb(new Error(
    "You must compile node with ssl support to use the link feature"))
  var folder = args.shift() || "."
  // folder's root MUST contain a package.json
  // read that for package info, then link it in, clobbering if necessary.
  if (folder.charAt(0) !== "/") folder = path.join(process.cwd(), folder)
  var jsonFile = path.join(folder, "package.json")
  log(folder, "link")
  chain
    ( function (cb) { fs.stat(folder, function (er, stats) {
        if (er) return cb(er)
        if (!stats.isDirectory()) return cb(new Error(
          "npm link requires a directory"))
        cb()
      })}
    , [log.verbose, "reading "+jsonFile, "link"]
    , [readAndLink, jsonFile, folder]
    , cb
    )
}

function readAndLink (jsonFile, folder, cb) {
  readJson
    ( jsonFile
    , { "tag" : "-1-LINK-"+(
        crypto.createHash("sha1").update(folder).digest("hex").substr(0,8)
      )}
    , doLink(folder, cb)
    )
}
function getDeps (data) {
  var deps = data.dependencies || {}
    , devDeps = data.devDependencies || {}
  Object.keys(devDeps).forEach(function (d) { deps[d] = devDeps[d] })
  return deps
}
function doLink (folder, cb) { return function (er, data) {
  if (er) return cb(er)
  log.verbose(data.name+" "+data.version, "link")
  var pkgDir = path.join(npm.dir, data.name, data.version, "package")
    , deps = getDeps(data)
    , depNames = Object.keys(deps)

  // skip any that are installed
  readInstalled(depNames, function (er, inst) {
    if (er) return log.er(cb, "Couldn't read installed packages")(er)
    for (var d in inst) if (deps[d]) {
      var satis = semver.maxSatisfying(Object.keys(inst[d]), deps[d])
      if (satis) delete deps[d]
    }
    var depsNeeded = Object.keys(deps).map(function (d) {
      return d+"@"+deps[d]
    })
    log.verbose(depsNeeded, "link install deps")
    chain
      ( depsNeeded.length
        ? [ npm.commands, "install", depsNeeded.slice(0) ]
        : function (cb) { cb() }
      , [ require("./utils/link"), folder, pkgDir ]
      , [ npm.commands, "build", [data] ]
      , function (er) {
          if (!er) return cb()
          // error, rollback
          npm.ROLLBACK = true
          log.error(er, "error linking, rollback")
          var rb = depsNeeded.concat([data.name+"@"+data.version])
          npm.commands.rm(rb, function (er_) {
            if (er_) log.error(er_, "error rolling back")
            cb(er)
          })
        }
      )
  })
}}
<commit_msg>require the symlink util at the top of the file<commit_after>
// link the supplied folder to .npm/{name}/{version}/package

var npm = require("../npm")
  , chain = require("./utils/chain")
  , log = require("./utils/log")
  , fs = require("./utils/graceful-fs")
  , readJson = require("./utils/read-json")
  , rm = require("./utils/rm-rf")
  , mkdir = require("./utils/mkdir-p")
  , path = require("path")
  , crypto
  , readInstalled = require("./utils/read-installed")
  , semver = require("./utils/semver")
  , symlink = require("./utils/link")

try {
  crypto = process.binding("crypto") && require("crypto")
} catch (ex) {}

module.exports = link

function link (args, cb) {
  if (!crypto) return cb(new Error(
    "You must compile node with ssl support to use the link feature"))
  var folder = args.shift() || "."
  // folder's root MUST contain a package.json
  // read that for package info, then link it in, clobbering if necessary.
  if (folder.charAt(0) !== "/") folder = path.join(process.cwd(), folder)
  var jsonFile = path.join(folder, "package.json")
  log(folder, "link")
  chain
    ( function (cb) { fs.stat(folder, function (er, stats) {
        if (er) return cb(er)
        if (!stats.isDirectory()) return cb(new Error(
          "npm link requires a directory"))
        cb()
      })}
    , [log.verbose, "reading "+jsonFile, "link"]
    , [readAndLink, jsonFile, folder]
    , cb
    )
}

function readAndLink (jsonFile, folder, cb) {
  readJson
    ( jsonFile
    , { "tag" : "-1-LINK-"+(
        crypto.createHash("sha1").update(folder).digest("hex").substr(0,8)
      )}
    , doLink(folder, cb)
    )
}
function getDeps (data) {
  var deps = data.dependencies || {}
    , devDeps = data.devDependencies || {}
  Object.keys(devDeps).forEach(function (d) { deps[d] = devDeps[d] })
  return deps
}
function doLink (folder, cb) { return function (er, data) {
  if (er) return cb(er)
  log.verbose(data._id, "link")
  var pkgDir = path.join(npm.dir, data.name, data.version, "package")
    , deps = getDeps(data)
    , depNames = Object.keys(deps)

  // skip any that are installed
  readInstalled(depNames, function (er, inst) {
    if (er) return log.er(cb, "Couldn't read installed packages")(er)
    for (var d in inst) if (deps[d]) {
      var satis = semver.maxSatisfying(Object.keys(inst[d]), deps[d])
      if (satis) delete deps[d]
    }
    var depsNeeded = Object.keys(deps).map(function (d) {
      return d+"@"+deps[d]
    })
    log.verbose(depsNeeded, "link install deps")
    chain
      ( depsNeeded.length
        ? [ npm.commands, "install", depsNeeded.slice(0) ]
        : function (cb) { cb() }
      , [ symlink, folder, pkgDir ]
      , [ npm.commands, "build", [data] ]
      , function (er) {
          if (!er) return cb()
          // error, rollback
          npm.ROLLBACK = true
          log.error(er, "error linking, rollback")
          var rb = depsNeeded.concat([data.name+"@"+data.version])
          npm.commands.rm(rb, function (er_) {
            if (er_) log.error(er_, "error rolling back")
            cb(er)
          })
        }
      )
  })
}}
<|endoftext|>