<commit_before>/*
 ---

 name: Eyes

 description: The main type - to be used by the users of the library to access all functionality.

 provides: [Eyes]
 requires: [eyes.sdk, ElementFinderWrapper, ViewportSize, protractor]

 ---
 */

(function () {
    "use strict";

    var EyesSDK = require('eyes.sdk'),
        EyesBase = EyesSDK.EyesBase,
        MutableImage = EyesSDK.MutableImage,
        ViewportSize = require('./ViewportSize'),
        promise = require('protractor').promise,
        ElementFinderWrapper = require('./ElementFinderWrappers').ElementFinderWrapper,
        ElementArrayFinderWrapper = require('./ElementFinderWrappers').ElementArrayFinderWrapper;

    var EyesUtils = require('eyes.utils'),
        PromiseFactory = EyesUtils.PromiseFactory,
        BrowserUtils = EyesUtils.BrowserUtils;

    /**
     *
     * @param {String} serverUrl
     * @param {Boolean} isDisabled - set to true to disable Applitools Eyes and use the protractor webdriver directly.
     * @constructor
     **/
    function Eyes(serverUrl, isDisabled) {
        this._promiseFactory = new PromiseFactory();
        EyesBase.call(this, this._promiseFactory, serverUrl || EyesBase.DEFAULT_EYES_SERVER, isDisabled);
    }

    Eyes.prototype = new EyesBase();
    Eyes.prototype.constructor = Eyes;

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype._getBaseAgentId = function () {
        return 'eyes-protractor/0.0.35';

    };

    function _init(that, flow, isDisabled) {
        // extend protractor element to return ours
        if (!isDisabled) {
            var originalElementFn = global.element;
            global.element = function (locator) {
                return new ElementFinderWrapper(originalElementFn(locator), that, that._logger);
            };

            global.element.all = function (locator) {
                return new ElementArrayFinderWrapper(originalElementFn.all(locator), that, that._logger);
            };
        }
        // Set PromiseFactory to work with the protractor control flow and promises
        this._promiseFactory.setFactoryMethods(function (asyncAction) {
            return flow.execute(function () {
                var deferred = promise.defer();
                asyncAction(deferred.fulfill, deferred.reject);
                return deferred.promise;
            });
        }, function () {
            return promise.defer();
        });
    }

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.open = function (driver, appName, testName, viewportSize) {
        var that = this,
            flow = that._flow = driver.controlFlow();

        that._driver = driver;

        _init(that, flow, this._isDisabled);

        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }

        return flow.execute(function () {
            return EyesBase.prototype.open.call(that, appName, testName, viewportSize);
        });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.close = function (throwEx) {
        var that = this;

        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }

        if (throwEx === undefined) {
            throwEx = true;
        }

        return that._flow.execute(function () {
            return EyesBase.prototype.close.call(that, false)
                .then(function (results) {
                    if (results.isPassed || !throwEx) {
                        return results;
                    } else {
                        throw EyesBase.buildTestError(results, that._sessionStartInfo.scenarioIdOrName,
                            that._sessionStartInfo.appIdOrName);
                    }
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     *
     * @param mode Use one of the values in EyesBase.FailureReport.
     */
    Eyes.prototype.setFailureReport = function (mode) {
        if (mode === EyesBase.FailureReport.Immediate) {
            this._failureReportOverridden = true;
            mode = EyesBase.FailureReport.OnClose;
        }

        EyesBase.prototype.setFailureReport.call(this, mode);
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.checkWindow = function (tag, matchTimeout) {
        var that = this;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout)
                .then(function (result) {
                    if (result.asExpected || !that._failureReportOverridden) {
                        return result;
                    } else {
                        throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                            that._sessionStartInfo.appIdOrName);
                    }
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     * Visually validates a region in the screenshot.
     *
     * @param {Object} region The region to validate (in screenshot coordinates).
     *                          Object is {width: *, height: *, top: *, left: *}
     * @param {string} tag An optional tag to be associated with the screenshot.
     * @param {int} matchTimeout The amount of time to retry matching.
     * @return {Promise} A promise which is resolved when the validation is finished.
     */
    Eyes.prototype.checkRegion = function (region, tag, matchTimeout) {
        var that = this;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout, region)
                .then(function (result) {
                    if (result.asExpected || !that._failureReportOverridden) {
                        return result;
                    } else {
                        throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                            that._sessionStartInfo.appIdOrName);
                    }
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     * Visually validates a region in the screenshot.
     *
     * @param {WebElement} element The element defining the region to validate.
     * @param {string} tag An optional tag to be associated with the screenshot.
     * @param {int} matchTimeout The amount of time to retry matching.
     * @return {Promise} A promise which is resolved when the validation is finished.
     */
    Eyes.prototype.checkRegionByElement = function (element, tag, matchTimeout) {
        var that = this,
            size;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return element.getSize()
                .then(function (elementSize) {
                    size = elementSize;
                    return element.getLocation();
                })
                .then(function (point) {
                    var region = {height: size.height, width: size.width, left: point.x, top: point.y, relative: true};
                    return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout, region)
                        .then(function (result) {
                            if (result.asExpected || !that._failureReportOverridden) {
                                return result;
                            } else {
                                throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                                    that._sessionStartInfo.appIdOrName);
                            }
                        });
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     * Visually validates a region in the screenshot.
     *
     * @param {By} by The WebDriver selector used for finding the region to validate.
     * @param {string} tag An optional tag to be associated with the screenshot.
     * @param {int} matchTimeout The amount of time to retry matching.
     * @return {Promise} A promise which is resolved when the validation is finished.
     */
    Eyes.prototype.checkRegionBy = function (by, tag, matchTimeout) {
        var that = this,
            element,
            size;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return that._driver.findElement(by)
                .then(function (elem) {
                    element = elem;
                    return element.getSize();
                })
                .then(function (elementSize) {
                    size = elementSize;
                    return element.getLocation();
                })
                .then(function (point) {
                    var region = {height: size.height, width: size.width, left: point.x, top: point.y, relative: true};
                    return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout, region)
                        .then(function (result) {
                            if (result.asExpected || !that._failureReportOverridden) {
                                return result;
                            } else {
                                throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                                    that._sessionStartInfo.appIdOrName);
                            }
                        });
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype._waitTimeout = function (ms) {
        return this._flow.timeout(ms);
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getScreenShot = function () {
        var that = this;
        var parsedImage;
        return that._driver.takeScreenshot()
            .then(function(screenshot64) {
                parsedImage = new MutableImage(new Buffer(screenshot64, 'base64'), that._promiseFactory);
                return parsedImage.getSize();
            })
            .then(function(imageSize) {
                return BrowserUtils.findImageNormalizationFactor(that._driver, imageSize, that._viewportSize);
            }).then(function(factor) {
                if (factor === 0.5) {
                    that._logger.verbose('Eyes.getScreenshot() - scaling to fix retina size issue!');
                    return parsedImage.scaleImage(factor);
                }
                return parsedImage;
            }).then(function () {
                return parsedImage.getSize();
            }).then(function (imageSize) {
                // If the image is a viewport screenshot, we want to save the current scroll position (we'll need it
                // for check region).
                var isViewportScreenshot = imageSize.width <= that._viewportSize.width
                    && imageSize.height <= that._viewportSize.height;
                if (isViewportScreenshot) {
					that._logger.verbose('Eyes.getScreenshot() - viewport screenshot found!');
                    return BrowserUtils.getCurrentScrollPosition(that._driver).then(function (scrollPosition) {
						that._logger.verbose('Eyes.getScreenshot() - scroll position: ', scrollPosition);
						return parsedImage.setCoordinates(scrollPosition);
                    });
                }
            }).then(function () {
                return parsedImage;
            });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getTitle = function () {
        return this._driver.getTitle();
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getInferredEnvironment = function () {
        var res = "useragent:";
        return this._driver.executeScript('return navigator.userAgent').then(function (userAgent) {
            return res + userAgent;
        }, function () {
            return res;
        });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getViewportSize = function () {
        return ViewportSize.getViewportSize(this._driver, this._promiseFactory);
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.setViewportSize = function (size) {
        return ViewportSize.setViewportSize(this._driver, size, this._promiseFactory);
    };

    module.exports = Eyes;
}());
<commit_msg>stupid stupid bug<commit_after>/*
 ---

 name: Eyes

 description: The main type - to be used by the users of the library to access all functionality.

 provides: [Eyes]
 requires: [eyes.sdk, ElementFinderWrapper, ViewportSize, protractor]

 ---
 */

(function () {
    "use strict";

    var EyesSDK = require('eyes.sdk'),
        EyesBase = EyesSDK.EyesBase,
        MutableImage = EyesSDK.MutableImage,
        ViewportSize = require('./ViewportSize'),
        promise = require('protractor').promise,
        ElementFinderWrapper = require('./ElementFinderWrappers').ElementFinderWrapper,
        ElementArrayFinderWrapper = require('./ElementFinderWrappers').ElementArrayFinderWrapper;

    var EyesUtils = require('eyes.utils'),
        PromiseFactory = EyesUtils.PromiseFactory,
        BrowserUtils = EyesUtils.BrowserUtils;

    /**
     *
     * @param {String} serverUrl
     * @param {Boolean} isDisabled - set to true to disable Applitools Eyes and use the protractor webdriver directly.
     * @constructor
     **/
    function Eyes(serverUrl, isDisabled) {
        this._promiseFactory = new PromiseFactory();
        EyesBase.call(this, this._promiseFactory, serverUrl || EyesBase.DEFAULT_EYES_SERVER, isDisabled);
    }

    Eyes.prototype = new EyesBase();
    Eyes.prototype.constructor = Eyes;

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype._getBaseAgentId = function () {
        return 'eyes-protractor/0.0.35';

    };

    function _init(that, flow, isDisabled) {
        // extend protractor element to return ours
        if (!isDisabled) {
            var originalElementFn = global.element;
            global.element = function (locator) {
                return new ElementFinderWrapper(originalElementFn(locator), that, that._logger);
            };

            global.element.all = function (locator) {
                return new ElementArrayFinderWrapper(originalElementFn.all(locator), that, that._logger);
            };
        }
        // Set PromiseFactory to work with the protractor control flow and promises
        that._promiseFactory.setFactoryMethods(function (asyncAction) {
            return flow.execute(function () {
                var deferred = promise.defer();
                asyncAction(deferred.fulfill, deferred.reject);
                return deferred.promise;
            });
        }, function () {
            return promise.defer();
        });
    }

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.open = function (driver, appName, testName, viewportSize) {
        var that = this,
            flow = that._flow = driver.controlFlow();

        that._driver = driver;

        _init(that, flow, this._isDisabled);

        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }

        return flow.execute(function () {
            return EyesBase.prototype.open.call(that, appName, testName, viewportSize);
        });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.close = function (throwEx) {
        var that = this;

        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }

        if (throwEx === undefined) {
            throwEx = true;
        }

        return that._flow.execute(function () {
            return EyesBase.prototype.close.call(that, false)
                .then(function (results) {
                    if (results.isPassed || !throwEx) {
                        return results;
                    } else {
                        throw EyesBase.buildTestError(results, that._sessionStartInfo.scenarioIdOrName,
                            that._sessionStartInfo.appIdOrName);
                    }
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     *
     * @param mode Use one of the values in EyesBase.FailureReport.
     */
    Eyes.prototype.setFailureReport = function (mode) {
        if (mode === EyesBase.FailureReport.Immediate) {
            this._failureReportOverridden = true;
            mode = EyesBase.FailureReport.OnClose;
        }

        EyesBase.prototype.setFailureReport.call(this, mode);
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.checkWindow = function (tag, matchTimeout) {
        var that = this;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout)
                .then(function (result) {
                    if (result.asExpected || !that._failureReportOverridden) {
                        return result;
                    } else {
                        throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                            that._sessionStartInfo.appIdOrName);
                    }
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     * Visually validates a region in the screenshot.
     *
     * @param {Object} region The region to validate (in screenshot coordinates).
     *                          Object is {width: *, height: *, top: *, left: *}
     * @param {string} tag An optional tag to be associated with the screenshot.
     * @param {int} matchTimeout The amount of time to retry matching.
     * @return {Promise} A promise which is resolved when the validation is finished.
     */
    Eyes.prototype.checkRegion = function (region, tag, matchTimeout) {
        var that = this;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout, region)
                .then(function (result) {
                    if (result.asExpected || !that._failureReportOverridden) {
                        return result;
                    } else {
                        throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                            that._sessionStartInfo.appIdOrName);
                    }
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     * Visually validates a region in the screenshot.
     *
     * @param {WebElement} element The element defining the region to validate.
     * @param {string} tag An optional tag to be associated with the screenshot.
     * @param {int} matchTimeout The amount of time to retry matching.
     * @return {Promise} A promise which is resolved when the validation is finished.
     */
    Eyes.prototype.checkRegionByElement = function (element, tag, matchTimeout) {
        var that = this,
            size;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return element.getSize()
                .then(function (elementSize) {
                    size = elementSize;
                    return element.getLocation();
                })
                .then(function (point) {
                    var region = {height: size.height, width: size.width, left: point.x, top: point.y, relative: true};
                    return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout, region)
                        .then(function (result) {
                            if (result.asExpected || !that._failureReportOverridden) {
                                return result;
                            } else {
                                throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                                    that._sessionStartInfo.appIdOrName);
                            }
                        });
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    /**
     * Visually validates a region in the screenshot.
     *
     * @param {By} by The WebDriver selector used for finding the region to validate.
     * @param {string} tag An optional tag to be associated with the screenshot.
     * @param {int} matchTimeout The amount of time to retry matching.
     * @return {Promise} A promise which is resolved when the validation is finished.
     */
    Eyes.prototype.checkRegionBy = function (by, tag, matchTimeout) {
        var that = this,
            element,
            size;
        if (this._isDisabled) {
            return that._flow.execute(function () {
            });
        }
        return that._flow.execute(function () {
            return that._driver.findElement(by)
                .then(function (elem) {
                    element = elem;
                    return element.getSize();
                })
                .then(function (elementSize) {
                    size = elementSize;
                    return element.getLocation();
                })
                .then(function (point) {
                    var region = {height: size.height, width: size.width, left: point.x, top: point.y, relative: true};
                    return EyesBase.prototype.checkWindow.call(that, tag, false, matchTimeout, region)
                        .then(function (result) {
                            if (result.asExpected || !that._failureReportOverridden) {
                                return result;
                            } else {
                                throw EyesBase.buildTestError(result, that._sessionStartInfo.scenarioIdOrName,
                                    that._sessionStartInfo.appIdOrName);
                            }
                        });
                });
        });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype._waitTimeout = function (ms) {
        return this._flow.timeout(ms);
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getScreenShot = function () {
        var that = this;
        var parsedImage;
        return that._driver.takeScreenshot()
            .then(function(screenshot64) {
                parsedImage = new MutableImage(new Buffer(screenshot64, 'base64'), that._promiseFactory);
                return parsedImage.getSize();
            })
            .then(function(imageSize) {
                return BrowserUtils.findImageNormalizationFactor(that._driver, imageSize, that._viewportSize);
            }).then(function(factor) {
                if (factor === 0.5) {
                    that._logger.verbose('Eyes.getScreenshot() - scaling to fix retina size issue!');
                    return parsedImage.scaleImage(factor);
                }
                return parsedImage;
            }).then(function () {
                return parsedImage.getSize();
            }).then(function (imageSize) {
                // If the image is a viewport screenshot, we want to save the current scroll position (we'll need it
                // for check region).
                var isViewportScreenshot = imageSize.width <= that._viewportSize.width
                    && imageSize.height <= that._viewportSize.height;
                if (isViewportScreenshot) {
					that._logger.verbose('Eyes.getScreenshot() - viewport screenshot found!');
                    return BrowserUtils.getCurrentScrollPosition(that._driver).then(function (scrollPosition) {
						that._logger.verbose('Eyes.getScreenshot() - scroll position: ', scrollPosition);
						return parsedImage.setCoordinates(scrollPosition);
                    });
                }
            }).then(function () {
                return parsedImage;
            });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getTitle = function () {
        return this._driver.getTitle();
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getInferredEnvironment = function () {
        var res = "useragent:";
        return this._driver.executeScript('return navigator.userAgent').then(function (userAgent) {
            return res + userAgent;
        }, function () {
            return res;
        });
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.getViewportSize = function () {
        return ViewportSize.getViewportSize(this._driver, this._promiseFactory);
    };

    //noinspection JSUnusedGlobalSymbols
    Eyes.prototype.setViewportSize = function (size) {
        return ViewportSize.setViewportSize(this._driver, size, this._promiseFactory);
    };

    module.exports = Eyes;
}());
<|endoftext|>


<commit_before>
  ///////////////////////////////////////////////////////////////////////////////////////////////
  //                                                                                //
  //  sQuery 0.1                                                                               //
  //                                                                                //
  ///////////////////////////////////////////////////////////////////////////////////////////////

  var doc = context.document;
  var sQuery, $;

(function(){

  sQuery = $ = function(selector) {
    return new SQUERY(selector);
  };

  allLayers = [];
  function fillArray(sel) {
    var layers = sel.layers();
    var len = layers.length();

    for (var i=0; i < len; i++) {
      var layer = layers.objectAtIndex(i);

      if ([layer class] == MSLayerGroup) {
        allLayers.push(layer);
        fillArray(layer);
      } else {
        allLayers.push(layer);
      }

    }
  };

  var SQUERY = function(selector) {

    // this
    this.typename =  "sQuery";
    this.version = "0.1";
    this.autor = "Francis Vega";
    this.layers = [];

    // vars
    var _docs = [];
    var _layers = [];
    var len;
    var i;
    var keyChar = "%";

    // this
    this.typename =  "psdQuery";
    this.version = "1.0";
    this.autor = "Francis Vega";
    this.layers = [];

    /**
     * Filtra el array de capas para dejar solo aquellas que coincidan en el tipo (klass)
     * @param {object|string} klass Determina el tipo de capa a filtrar
     * @return {[MSLayerClass]}
     * @example
     * filterLayersByClass(MSLayerGroup);
     * @example
     * filterLayersByClass("*");
     */
    function filterLayersByClass(klass) {
      allLayers = [];
      fillArray(doc.currentPage().currentArtboard());

      if (typeof(klass) == "object") {
        var _layers = [];
        var layer;
        var len = allLayers.length;

        for(i=0; i<len; i++) {
          layer = allLayers[i];
          if(sQuery().is(layer, klass)) {
            _layers.push(layer);
          }
        }
        return _layers;
      }

      if (typeof(klass) == "string") {

        switch(klass) {

          case "*":
            return allLayers;
            break;

          case "selected":
            var _mslayers = context.selection;
            var _layers = [];
            for(var i=0; i<_mslayers.count(); i++) {
              _layers.push(_mslayers.objectAtIndex(i));
            }
            return _layers;
            break;

        }

      }

    };

    if (typeof selector === "string") {

      switch(selector) {

        case "*":
          _layers = filterLayersByClass("*");
          break;

        case "%groups%":
          _layers = filterLayersByClass(MSLayerGroup);
          break;

        case "%shapes%":
          _layers = filterLayersByClass(MSShapeGroup);
          break;

        case "%images%":
          _layers = filterLayersByClass(MSBitmapLayer);
          break;

        case "%textLayer%":
          _layers = filterLayersByClass(MSTextLayer);
          break;

        case "%selected%":
          _layers = filterLayersByClass("selected");
          break;

        default:
          break;

      }

    }

    this.layers = _layers.slice();
    this.length = _layers.length;

    // Return self object
    return this;

  };

  /* @psdQuery API */

  sQuery.fn = SQUERY.prototype = {

    is: function(layer, theClass){
      var klass = [layer class];
      return klass === theClass;
    },

    isPage: function(layer){
      return SQUERY.prototype.is(layer, MSPage);
    },

    isArtboard: function(layer){
      return SQUERY.prototype.is(layer, MSArtboardGroup);
    },

    isGroup: function(layer){
      return SQUERY.prototype.is(layer, MSLayerGroup);
    },

    isText: function(layer){
      return SQUERY.prototype.is(layer, MSTextLayer);
    },

    isShape: function(layer){
      return SQUERY.prototype.is(layer, MSShapeGroup);
    },

    isImageLayer: function(layer) {
      return SQUERY.prototype.is(layer, MSBitmapLayer);
    },

     //@LOOP METHODS

    /**
     * Itera por cada uno de los elementos previamente seleccionados y devuelve el elemento
     * @param {function} callback Una función a la que each llama por cada iteración
     * @return {this} Devuelve this
     */
    each: function(callback) {
      for(var i = 0; i < this.layers.length; ++i) {
        callback.call(this.layers[i], i);
      }

      return this;
    },

    /**
     * Itera por cada uno de los elementos filtrando los que devuelvan true
     * @param {function} callback Una función a la que filter llama por cada iteración
     * @return {this} Devuelve this
     */
    filter: function(callback) {
      var r = [];
      var k;
      for(var i = 0; i < this.layers.length; ++i) {
        k = callback.call(this.layers[i], i);
        if (k){
          r.push(this.layers[i]);
        }
      }
      this.layers = r.slice();

      return this;
    },

    rename: function(name) {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].name = name;
      }
      return this;
    },

    isLocked: function(neg) {
      var _layers = [];

      for (var i=0; i<this.layers.length; i++) {
        if (this.layers[i].isLocked()) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    startsWith: function(str) {
      var _layers = [];
      var strLen = str.length;
      var layerName;
      for (var i=0; i<this.layers.length; i++) {
        layerName = this.layers[i].name();

        if(layerName.substr(0, strLen) == str) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    endsWith: function(str) {
      var _layers = [];
      var strLen = str.length;
      var layerName;
      for (var i=0; i<this.layers.length; i++) {
        layerName = this.layers[i].name();
        layerNameLen = layerName.length();

        if(layerName.substr(layerNameLen-strLen, layerNameLen) == str) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    contains: function(str) {
      var _layers = [];
      var layerName;
      for (var i=0; i<this.layers.length; i++) {
        layerName = this.layers[i].name();

        if(layerName.split(str).length > 1) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    UISelect: function(){
      // Primero deseleccionamos todo
      doc.currentPage().deselectAllLayers()
        for (var i=0; i<this.layers.length; i++) {
          this.layers[i].select_byExpandingSelection(true, true);
        }
      return this;
    },

    brothers: function(){
      var bigBrother = this.layers[0];
      var bigParent = bigBrother.parentGroup();
      var brothers = bigParent.layers();

      var _layers = [];
      for (var i=0; i<brothers.count(); i++) {
        _layers.push(brothers.objectAtIndex(i));
      }

      this.layers = _layers.slice();
      return this;
    },

    childs: function() {
      var parent = this.layers[0];
      var childs = parent.layers();

      var _layers = [];
      for (var i=0; i<childs.count(); i++) {
        _layers.push(childs.objectAtIndex(i));
      }

      this.layers = _layers.slice();
      return this;
    },

    descendants: function() {
      var _layers = [];
      allLayers = [];

      fillArray(this.layers[0]);

      this.layers = allLayers.slice();
      return this;
    },

    isEmpty: function() {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if (this.isGroup(this.layers[i].class())) {
          if (this.layers[i].layers().length() == 0) {
            _layers.push(this.layers[i]);
          }
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    isVisible: function() {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if(this.layers[i].isVisible()) {
          _layers.push(this.layers[i]);
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    isHidden: function() {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if(!this.layers[i].isVisible()) {
          _layers.push(this.layers[i]);
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    show: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsVisible(true);
      }
      return this;
    },

    hide: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsVisible(false);
      }
      return this;
    },

    lock: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsLocked(true);
      }
      return this;
    },

    unlock: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsLocked(false);
      }
      return this;
    },

    duplicate: function(name) {
      return this;
    },

    remove: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].parentGroup().removeLayer(this.layers[i]);
      }
      return this;
    }

  };
}
)();
<commit_msg>Añadido método getLayer()<commit_after>
  ///////////////////////////////////////////////////////////////////////////////////////////////
  //                                                                                //
  //  sQuery 0.1                                                                               //
  //                                                                                //
  ///////////////////////////////////////////////////////////////////////////////////////////////

  var doc = context.document;
  var sQuery, $;

(function(){

  sQuery = $ = function(selector) {
    return new SQUERY(selector);
  };

  allLayers = [];
  function fillArray(sel) {
    var layers = sel.layers();
    var len = layers.length();

    for (var i=0; i < len; i++) {
      var layer = layers.objectAtIndex(i);

      if ([layer class] == MSLayerGroup) {
        allLayers.push(layer);
        fillArray(layer);
      } else {
        allLayers.push(layer);
      }

    }
  };

  var SQUERY = function(selector) {

    // this
    this.typename =  "sQuery";
    this.version = "0.1";
    this.autor = "Francis Vega";
    this.layers = [];

    // vars
    var _docs = [];
    var _layers = [];
    var len;
    var i;
    var keyChar = "%";

    // this
    this.typename =  "psdQuery";
    this.version = "1.0";
    this.autor = "Francis Vega";
    this.layers = [];

    /**
     * Filtra el array de capas para dejar solo aquellas que coincidan en el tipo (klass)
     * @param {object|string} klass Determina el tipo de capa a filtrar
     * @return {[MSLayerClass]}
     * @example
     * filterLayersByClass(MSLayerGroup);
     * @example
     * filterLayersByClass("*");
     */
    function filterLayersByClass(klass) {
      allLayers = [];
      fillArray(doc.currentPage().currentArtboard());

      if (typeof(klass) == "object") {
        var _layers = [];
        var layer;
        var len = allLayers.length;

        for(i=0; i<len; i++) {
          layer = allLayers[i];
          if(sQuery().is(layer, klass)) {
            _layers.push(layer);
          }
        }
        return _layers;
      }

      if (typeof(klass) == "string") {

        switch(klass) {

          case "*":
            return allLayers;
            break;

          case "selected":
            var _mslayers = context.selection;
            var _layers = [];
            for(var i=0; i<_mslayers.count(); i++) {
              _layers.push(_mslayers.objectAtIndex(i));
            }
            return _layers;
            break;

        }

      }

    };

    if (typeof selector === "string") {

      switch(selector) {

        case "*":
          _layers = filterLayersByClass("*");
          break;

        case "%groups%":
          _layers = filterLayersByClass(MSLayerGroup);
          break;

        case "%shapes%":
          _layers = filterLayersByClass(MSShapeGroup);
          break;

        case "%images%":
          _layers = filterLayersByClass(MSBitmapLayer);
          break;

        case "%textLayer%":
          _layers = filterLayersByClass(MSTextLayer);
          break;

        case "%selected%":
          _layers = filterLayersByClass("selected");
          break;

        default:
          break;

      }

    }

    this.layers = _layers.slice();
    this.length = _layers.length;

    // Return self object
    return this;

  };

  /* @psdQuery API */

  sQuery.fn = SQUERY.prototype = {

    is: function(layer, theClass){
      var klass = [layer class];
      return klass === theClass;
    },

    isPage: function(layer){
      return SQUERY.prototype.is(layer, MSPage);
    },

    isArtboard: function(layer){
      return SQUERY.prototype.is(layer, MSArtboardGroup);
    },

    isGroup: function(layer){
      return SQUERY.prototype.is(layer, MSLayerGroup);
    },

    isText: function(layer){
      return SQUERY.prototype.is(layer, MSTextLayer);
    },

    isShape: function(layer){
      return SQUERY.prototype.is(layer, MSShapeGroup);
    },

    isImageLayer: function(layer) {
      return SQUERY.prototype.is(layer, MSBitmapLayer);
    },

     //@LOOP METHODS

    /**
     * Itera por cada uno de los elementos previamente seleccionados y devuelve el elemento
     * @param {function} callback Una función a la que each llama por cada iteración
     * @return {this} Devuelve this
     */
    each: function(callback) {
      for(var i = 0; i < this.layers.length; ++i) {
        callback.call(this.layers[i], i);
      }

      return this;
    },

    /**
     * Itera por cada uno de los elementos filtrando los que devuelvan true
     * @param {function} callback Una función a la que filter llama por cada iteración
     * @return {this} Devuelve this
     */
    filter: function(callback) {
      var r = [];
      var k;
      for(var i = 0; i < this.layers.length; ++i) {
        k = callback.call(this.layers[i], i);
        if (k){
          r.push(this.layers[i]);
        }
      }
      this.layers = r.slice();

      return this;
    },

    rename: function(name) {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].name = name;
      }
      return this;
    },

    isLocked: function(neg) {
      var _layers = [];

      for (var i=0; i<this.layers.length; i++) {
        if (this.layers[i].isLocked()) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    startsWith: function(str) {
      var _layers = [];
      var strLen = str.length;
      var layerName;
      for (var i=0; i<this.layers.length; i++) {
        layerName = this.layers[i].name();

        if(layerName.substr(0, strLen) == str) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    endsWith: function(str) {
      var _layers = [];
      var strLen = str.length;
      var layerName;
      for (var i=0; i<this.layers.length; i++) {
        layerName = this.layers[i].name();
        layerNameLen = layerName.length();

        if(layerName.substr(layerNameLen-strLen, layerNameLen) == str) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    contains: function(str) {
      var _layers = [];
      var layerName;
      for (var i=0; i<this.layers.length; i++) {
        layerName = this.layers[i].name();

        if(layerName.split(str).length > 1) {
          _layers.push(this.layers[i]);
        }
      }

      this.layers = _layers.slice();

      return this;
    },

    UISelect: function(){
      // Primero deseleccionamos todo
      doc.currentPage().deselectAllLayers()
        for (var i=0; i<this.layers.length; i++) {
          this.layers[i].select_byExpandingSelection(true, true);
        }
      return this;
    },

    brothers: function(){
      var bigBrother = this.layers[0];
      var bigParent = bigBrother.parentGroup();
      var brothers = bigParent.layers();

      var _layers = [];
      for (var i=0; i<brothers.count(); i++) {
        _layers.push(brothers.objectAtIndex(i));
      }

      this.layers = _layers.slice();
      return this;
    },

    childs: function() {
      var parent = this.layers[0];
      var childs = parent.layers();

      var _layers = [];
      for (var i=0; i<childs.count(); i++) {
        _layers.push(childs.objectAtIndex(i));
      }

      this.layers = _layers.slice();
      return this;
    },

    descendants: function() {
      var _layers = [];
      allLayers = [];

      fillArray(this.layers[0]);

      this.layers = allLayers.slice();
      return this;
    },

    withName: function(name) {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if (this.layers[i].name() == name) {
          _layers.push(this.layers[i]);
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    isEmpty: function() {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if (this.isGroup(this.layers[i].class())) {
          if (this.layers[i].layers().length() == 0) {
            _layers.push(this.layers[i]);
          }
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    isVisible: function() {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if(this.layers[i].isVisible()) {
          _layers.push(this.layers[i]);
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    isHidden: function() {
      var _layers = [];
      for (var i=0; i<this.layers.length; i++) {
        if(!this.layers[i].isVisible()) {
          _layers.push(this.layers[i]);
        }
      }
      this.layers = _layers.slice();
      return this;
    },

    show: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsVisible(true);
      }
      return this;
    },

    hide: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsVisible(false);
      }
      return this;
    },

    lock: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsLocked(true);
      }
      return this;
    },

    unlock: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].setIsLocked(false);
      }
      return this;
    },

    duplicate: function(name) {
      return this;
    },

    remove: function() {
      for (var i=0; i<this.layers.length; i++) {
        this.layers[i].parentGroup().removeLayer(this.layers[i]);
      }
      return this;
    },

    getLayer: function() {
      return this.layers[0];
    }

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


<commit_before>/* @flow */

import * as React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { SchemaModel, Schema } from 'rsuite-schema';
import classNames from 'classnames';

import { getUnhandledProps, prefix } from './utils';
import { defaultClassPrefix } from './utils/prefix';

type Props = {
  className?: string,
  layout?: 'horizontal' | 'vertical' | 'inline',
  fluid?: boolean,
  formValue?: Object,
  formDefaultValue?: Object,
  formError?: Object,
  checkDelay?: number,
  checkTrigger?: 'change' | 'blur' | 'none',
  onChange?: (formValue: Object, event: SyntheticEvent<*>) => void,
  onError?: (formError: Object) => void,
  onCheck?: (formError: Object) => void,
  model: typeof Schema,
  classPrefix: string
};

type State = {
  formError?: Object,
  formValue?: Object
};

class Form extends React.Component<Props, State> {
  static defaultProps = {
    classPrefix: defaultClassPrefix('form'),
    model: SchemaModel({}),
    layout: 'vertical',
    formDefaultValue: {},
    checkDelay: 500,
    checkTrigger: 'change'
  };

  static childContextTypes = {
    form: PropTypes.object.isRequired
  };

  constructor(props: Props) {
    super(props);
    this.state = {
      formError: props.formError || {},
      formValue: props.formDefaultValue
    };
  }
  getChildContext() {
    const { formDefaultValue, model, checkTrigger } = this.props;
    const formValue = this.getFormValue();
    const formError = this.getFormError();
    return {
      form: {
        onFieldChange: this.handleFieldChange,
        onFieldError: this.handleFieldError,
        onFieldSuccess: this.handleFieldSuccess,
        checkTrigger,
        formValue,
        formDefaultValue,
        formError,
        model
      }
    };
  }
  getFormValue() {
    const { formValue } = this.props;
    return _.isUndefined(formValue) ? this.state.formValue : formValue;
  }

  getFormError() {
    const { formError } = this.props;
    return _.isUndefined(formError) ? this.state.formError : formError;
  }

  /**
   * public APIs
   */
  check = (callback: (formError: Object) => void) => {
    const formValue = this.getFormValue() || {};
    const { model, onCheck, onError } = this.props;
    const formError = {};
    let errorCount = 0;

    Object.keys(model.schema).forEach(key => {
      const checkResult = model.checkForField(key, formValue[key]);

      if (checkResult.hasError === true) {
        errorCount += 1;
        formError[key] = checkResult.errorMessage;
      }
    });

    this.setState({ formError });
    onCheck && onCheck(formError);
    callback && callback(formError);
    if (errorCount > 0) {
      onError && onError(formError);
      return false;
    }

    return true;
  };

  /**
   * public APIs
   */
  cleanErrors(callback: () => void) {
    this.setState({ formError: {} }, callback);
  }

  /**
   * public APIs
   */
  resetErrors(formError: Object = {}, callback: () => void) {
    this.setState({ formError }, callback);
  }

  handleFieldError = (name: string, errorMessage: string) => {
    const { onError, onCheck } = this.props;
    const formError = {
      ...this.state.formError,
      [name]: errorMessage
    };

    this.setState({ formError }, () => {
      onError && onError(formError);
      onCheck && onCheck(formError);
    });
  };

  handleFieldSuccess = (name: string) => {
    const { onCheck } = this.props;
    const formError = _.omit(this.state.formError, [name]);
    this.setState({ formError }, () => {
      onCheck && onCheck(formError);
    });
  };

  handleFieldChange = (name: string, value: any, event: SyntheticEvent<*>) => {
    const { onChange } = this.props;
    const formValue = this.getFormValue();
    const nextFormValue = {
      ...formValue,
      [name]: value
    };
    onChange && onChange(nextFormValue, event);
  };

  render() {
    const { layout, classPrefix, fluid, className, ...props } = this.props;
    const addPrefix = prefix(classPrefix);
    const clesses = classNames(
      classPrefix,
      addPrefix(layout),
      className,
      addPrefix(fluid && layout === 'vertical' ? 'fluid' : 'fixed-width')
    );
    const unhandled = getUnhandledProps(Form, props);

    return <form {...unhandled} onSubmit={e => e.preventDefault()} className={clesses} />;
  }
}

export default Form;
<commit_msg>Update Form<commit_after>/* @flow */

import * as React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { SchemaModel, Schema } from 'rsuite-schema';
import classNames from 'classnames';

import { getUnhandledProps, prefix } from './utils';
import { defaultClassPrefix } from './utils/prefix';

type Props = {
  className?: string,
  layout?: 'horizontal' | 'vertical' | 'inline',
  fluid?: boolean,
  formValue?: Object,
  formDefaultValue?: Object,
  formError?: Object,
  checkDelay?: number,
  checkTrigger?: 'change' | 'blur' | 'none',
  onChange?: (formValue: Object, event: SyntheticEvent<*>) => void,
  onError?: (formError: Object) => void,
  onCheck?: (formError: Object) => void,
  model: typeof Schema,
  classPrefix: string
};

type State = {
  formError?: Object,
  formValue?: Object
};

class Form extends React.Component<Props, State> {
  static defaultProps = {
    classPrefix: defaultClassPrefix('form'),
    model: SchemaModel({}),
    layout: 'vertical',
    formDefaultValue: {},
    checkDelay: 500,
    checkTrigger: 'change'
  };

  static childContextTypes = {
    form: PropTypes.object.isRequired
  };

  constructor(props: Props) {
    super(props);
    this.state = {
      formError: props.formError || {},
      formValue: props.formDefaultValue
    };
  }
  getChildContext() {
    const { formDefaultValue, formValue, model, checkTrigger } = this.props;
    const formError = this.getFormError();
    return {
      form: {
        onFieldChange: this.handleFieldChange,
        onFieldError: this.handleFieldError,
        onFieldSuccess: this.handleFieldSuccess,
        checkTrigger,
        formValue,
        formDefaultValue,
        formError,
        model
      }
    };
  }
  getFormValue() {
    const { formValue } = this.props;
    return _.isUndefined(formValue) ? this.state.formValue : formValue;
  }

  getFormError() {
    const { formError } = this.props;
    return _.isUndefined(formError) ? this.state.formError : formError;
  }

  /**
   * public APIs
   */
  check = (callback: (formError: Object) => void) => {
    const formValue = this.getFormValue() || {};
    const { model, onCheck, onError } = this.props;
    const formError = {};
    let errorCount = 0;

    Object.keys(model.schema).forEach(key => {
      const checkResult = model.checkForField(key, formValue[key]);

      if (checkResult.hasError === true) {
        errorCount += 1;
        formError[key] = checkResult.errorMessage;
      }
    });

    this.setState({ formError });
    onCheck && onCheck(formError);
    callback && callback(formError);
    if (errorCount > 0) {
      onError && onError(formError);
      return false;
    }

    return true;
  };

  /**
   * public APIs
   */
  cleanErrors(callback: () => void) {
    this.setState({ formError: {} }, callback);
  }

  /**
   * public APIs
   */
  resetErrors(formError: Object = {}, callback: () => void) {
    this.setState({ formError }, callback);
  }

  handleFieldError = (name: string, errorMessage: string) => {
    const { onError, onCheck } = this.props;
    const formError = {
      ...this.state.formError,
      [name]: errorMessage
    };

    this.setState({ formError }, () => {
      onError && onError(formError);
      onCheck && onCheck(formError);
    });
  };

  handleFieldSuccess = (name: string) => {
    const { onCheck } = this.props;
    const formError = _.omit(this.state.formError, [name]);
    this.setState({ formError }, () => {
      onCheck && onCheck(formError);
    });
  };

  handleFieldChange = (name: string, value: any, event: SyntheticEvent<*>) => {
    const { onChange } = this.props;
    const formValue = this.getFormValue();
    const nextFormValue = {
      ...formValue,
      [name]: value
    };
    onChange && onChange(nextFormValue, event);
  };

  render() {
    const { layout, classPrefix, fluid, className, ...props } = this.props;
    const addPrefix = prefix(classPrefix);
    const clesses = classNames(
      classPrefix,
      addPrefix(layout),
      className,
      addPrefix(fluid && layout === 'vertical' ? 'fluid' : 'fixed-width')
    );
    const unhandled = getUnhandledProps(Form, props);

    return <form {...unhandled} onSubmit={e => e.preventDefault()} className={clesses} />;
  }
}

export default Form;
<|endoftext|>


<commit_before>import React, {PropTypes as T} from 'react'
import {unnest, last} from 'ramda'

const MONO_FONT = 'Menlo, Monaco, Consolas, "Lucida Console", monospace'
const SERIF_FONT = '"Lucida Grande", Helvetica, arial, sans-serif'

const styles = {
  metaWrap({fullWidth}) {
    return {
      padding: fullWidth ? '0 10px' : 0,
    }
  },
  location: {
    fontSize: 18,
    fontFamily: SERIF_FONT,
    color: '#aaa',
    marginBottom: 10,
  },
  locationItem({last}) {
    return {
      color: last ? '#000' : 'inerit',
    }
  },
  locationDel: {
    margin: '0 .2em',
    color: '#aaa',
  },
  import: {
    fontFamily: MONO_FONT,
    fontSize: 14,
    marginBottom: 10,
    color: '#aaa',
    float: 'right',
  },
  description: {
    maxWidth: 600,
    marginBottom: 10,
    fontFamily: SERIF_FONT,
    fontSize: 14,
  },
  files({fullWidth}) {
    return {
      margin: fullWidth ? '20px 10px' : '20px 0',
    }
  },
  fileName: {
    fontFamily: SERIF_FONT,
    fontSize: 14,
    fontWeight: 'bold',
  },
  fileContnet: {
    fontFamily: MONO_FONT,
    fontSize: 11,
    margin: '5px 0 20px 0',
    background: '#d7e5ec',
    padding: 5,
    borderRadius: 3,
    overflow: 'auto',
  },
}

function locationItem(name, i, {length}) {
  const last = length === i + 1
  return [
    <span key={`${i}item`} style={styles.locationItem({last})}>{name},
    !last && <span key={`${i}del`} style={styles.locationDel}>/,
  ]
}

export default React.createClass({

  propTypes: {
    demo: T.node,
    fullWidth: T.bool,
    location: T.array.isRequired,
    importPath: T.string,
    description: T.node,
    files: T.arrayOf(T.shape({name: T.string.isRequired, content: T.string.isRequired}).isRequired),
  },

  renderFile(file, index) {
    return

{file.name}

{file.content}

  },

  render() {
    const {demo, fullWidth, location, importPath, description, files} = this.props
    const name = last(location)
    return

          import {name} from '{importPath}'

          {unnest(location.map(locationItem))}

          {description}

        {demo}

      {
        files &&

          {files.map(this.renderFile)}

      }

  },

})
<commit_msg>Permit override of `name` for demo (#8)<commit_after>import React, {PropTypes as T} from 'react'
import {unnest, last} from 'ramda'

const MONO_FONT = 'Menlo, Monaco, Consolas, "Lucida Console", monospace'
const SERIF_FONT = '"Lucida Grande", Helvetica, arial, sans-serif'

const styles = {
  metaWrap({fullWidth}) {
    return {
      padding: fullWidth ? '0 10px' : 0,
    }
  },
  location: {
    fontSize: 18,
    fontFamily: SERIF_FONT,
    color: '#aaa',
    marginBottom: 10,
  },
  locationItem({last}) {
    return {
      color: last ? '#000' : 'inerit',
    }
  },
  locationDel: {
    margin: '0 .2em',
    color: '#aaa',
  },
  import: {
    fontFamily: MONO_FONT,
    fontSize: 14,
    marginBottom: 10,
    color: '#aaa',
    float: 'right',
  },
  description: {
    maxWidth: 600,
    marginBottom: 10,
    fontFamily: SERIF_FONT,
    fontSize: 14,
  },
  files({fullWidth}) {
    return {
      margin: fullWidth ? '20px 10px' : '20px 0',
    }
  },
  fileName: {
    fontFamily: SERIF_FONT,
    fontSize: 14,
    fontWeight: 'bold',
  },
  fileContnet: {
    fontFamily: MONO_FONT,
    fontSize: 11,
    margin: '5px 0 20px 0',
    background: '#d7e5ec',
    padding: 5,
    borderRadius: 3,
    overflow: 'auto',
  },
}

function locationItem(name, i, {length}) {
  const last = length === i + 1
  return [
    <span key={`${i}item`} style={styles.locationItem({last})}>{name},
    !last && <span key={`${i}del`} style={styles.locationDel}>/,
  ]
}

export default React.createClass({

  propTypes: {
    demo: T.node,
    fullWidth: T.bool,
    location: T.array.isRequired,
    importPath: T.string,
    name: T.string,
    description: T.node,
    files: T.arrayOf(T.shape({name: T.string.isRequired, content: T.string.isRequired}).isRequired),
  },

  renderFile(file, index) {
    return

{file.name}

{file.content}

  },

  render() {
    const {demo, fullWidth, location, importPath, description, files, name = last(location)} = this.props
    return

          import {name} from '{importPath}'

          {unnest(location.map(locationItem))}

          {description}

        {demo}

      {
        files &&

          {files.map(this.renderFile)}

      }

  },

})
<|endoftext|>


<commit_before>import React from 'react';
import InputContainer from './InputContainer';
import ValidatedInput from './ValidatedInput';
import RadioGroup from './RadioGroup';

import Validator from './Validator';
import FileValidator from './FileValidator';
import createFragment from 'react-addons-create-fragment'

function getInputErrorMessage(input, ruleName) {
    let errorHelp = input.props.errorHelp;

    if (typeof errorHelp === 'object') {
        return errorHelp[ruleName];
    } else {
        return errorHelp;
    }
}

export default class Form extends InputContainer {
    constructor(props) {
        super(props);

        this.state = {
            isValid: true,
            invalidInputs: {}
        };
    }

    componentWillMount() {
        super.componentWillMount();

        this._validators = {};
    }

    registerInput(input) {
        super.registerInput(input);

        if (typeof input.props.validate === 'string') {
            this._validators[input.props.name] = this._compileValidationRules(input, input.props.validate);
        }
    }

    unregisterInput(input) {
        super.unregisterInput(input);

        delete this._validators[input.props.name];
    }

    render() {
        return (
            <form ref="form"
                  onSubmit={this._handleSubmit.bind(this)}
                  action="#"
                  className={this.props.className}>
                {this._renderChildren(this.props.children)}
            </form>
        );
    }

    getValues() {
        return Object.keys(this._inputs).reduce((values, name) => {
            values[name] = this._getValue(name);

            return values;
        }, {});
    }

    submit() {
        this._handleSubmit();
    }

    _renderChildren(children) {
        if (typeof children !== 'object' || children === null) {
            return children;
        }

        let childrenCount = React.Children.count(children);

        if (childrenCount > 1) {
            return React.Children.map(children, child => this._renderChild(child));
        } else if (childrenCount === 1) {
            return this._renderChild(Array.isArray(children) ? children[0] : children);
        }
    }

    _renderChild(child) {
        if (typeof child !== 'object' || child === null) {
            return child;
        }

        let model = this.props.model || {};

        if (child.type === ValidatedInput ||
            child.type === RadioGroup || (
                child.type &&
                child.type.prototype !== null && (
                    child.type.prototype instanceof ValidatedInput ||
                    child.type.prototype instanceof RadioGroup
                )
            )
        ) {
            let name = child.props && child.props.name;

            if (!name) {
                throw new Error('Can not add input without "name" attribute');
            }

            let newProps = {
                _registerInput  : this.registerInput.bind(this),
                _unregisterInput: this.unregisterInput.bind(this)
            };

            let evtName = child.props.validationEvent ?
                    child.props.validationEvent : this.props.validationEvent;

            let origCallback = child.props[evtName];

            newProps[evtName] = e => {
                this._validateInput(name);

                return origCallback && origCallback(e);
            };

            if (name in model) {
                if (child.props.type === 'checkbox') {
                    newProps.defaultChecked = model[name];
                } else {
                    newProps.defaultValue = model[name];
                }
            }

            let error = this._hasError(name);

            if (error) {
                newProps.bsStyle = 'error';

                if (typeof error === 'string') {
                    newProps.help = error;
                } else if (child.props.errorHelp) {
                    newProps.help = createFragment(child.props.errorHelp);
                }
            }

            return React.cloneElement(child, newProps);
        } else {
            return React.cloneElement(child, {}, this._renderChildren(child.props && child.props.children));
        }
    }

    _validateInput(name) {
        this._validateOne(name, this.getValues());
    }

    _hasError(iptName) {
        return this.state.invalidInputs[iptName];
    }

    _setError(iptName, isError, errText) {
        if (isError && errText &&
            typeof errText !== 'string' &&
            typeof errText !== 'boolean')
        {
            errText = errText + '';
        }

        // set value to either bool or error description string
        this.setState({
            invalidInputs: Object.assign(
                this.state.invalidInputs,
                {
                    [iptName]: isError ? errText || true : false
                }
            )
        });
    }

    _validateOne(iptName, context) {
        let input = this._inputs[iptName];

        if (Array.isArray(input)) {
            console.warn('Multiple inputs use the same name "' + iptName + '"');

            return false;
        }

        let value = context[iptName];
        let isValid = true;
        let validate = input.props.validate;
        let result, error;

         if (typeof validate === 'function') {
            result = validate(value, context);
        } else if (typeof validate === 'string') {
            result = this._validators[iptName](value);
        } else {
            result = true;
        }

		if (typeof this.props.validateOne === 'function') {
            result = this.props.validateOne(iptName, value, context, result);
        }
        // if result is !== true, it is considered an error
        // it can be either bool or string error
        if (result !== true) {
            isValid = false;

            if (typeof result === 'string') {
                error = result;
            }
        }

        this._setError(iptName, !isValid, error);

        return isValid;
    }

    _validateAll(context) {
        let isValid = true;
        let errors = [];

        if (typeof this.props.validateAll === 'function') {
            let result = this.props.validateAll(context);

            if (result !== true) {
                isValid = false;

                Object.keys(result).forEach(iptName => {
                    errors.push(iptName);

                    this._setError(iptName, true, result[iptName]);
                });
            }
        } else {
            Object.keys(this._inputs).forEach(iptName => {
                if (!this._validateOne(iptName, context)) {
                    isValid = false;
                    errors.push(iptName);
                }
            });
        }

        return {
            isValid: isValid,
            errors: errors
        };
    }

    _compileValidationRules(input, ruleProp) {
        let rules = ruleProp.split(',').map(rule => {
            let params = rule.split(':');
            let name = params.shift();
            let inverse = name[0] === '!';

            if (inverse) {
                name = name.substr(1);
            }

            return { name, inverse, params };
        });

        let validator = (input.props && input.props.type) === 'file' ? FileValidator : Validator;

        return val => {
            let result = true;

            rules.forEach(rule => {
                if (typeof validator[rule.name] !== 'function') {
                    throw new Error('Invalid input validation rule "' + rule.name + '"');
                }

                let ruleResult = validator[rule.name](val, ...rule.params);

                if (rule.inverse) {
                    ruleResult = !ruleResult;
                }

                if (result === true && ruleResult !== true) {
                    result = getInputErrorMessage(input, rule.name) ||
                        getInputErrorMessage(this, rule.name) || false;
                }
            });

            return result;
        };
    }

    _getValue(iptName) {
        let input = this._inputs[iptName];

        if (Array.isArray(input)) {
            console.warn('Multiple inputs use the same name "' + iptName + '"');

            return false;
        }

        let value;

        if (input.props.type === 'checkbox') {
            value = input.getChecked();
        } else if (input.props.type === 'file') {
            value = input.getInputDOMNode().files;
        } else {
            value = input.getValue();
        }

        return value;
    }

    _handleSubmit(e) {
        if (e) {
            e.preventDefault();
        }

        let values = this.getValues();

        let { isValid, errors } = this._validateAll(values);

        if (isValid) {
            this.props.onValidSubmit(values);
        } else {
            this.props.onInvalidSubmit(errors, values);
        }
    }
}

Form.propTypes = {
    className      : React.PropTypes.string,
    model          : React.PropTypes.object,
    onValidSubmit  : React.PropTypes.func.isRequired,
    onInvalidSubmit: React.PropTypes.func,
    validateOne    : React.PropTypes.func,
    validateAll    : React.PropTypes.func,
    validationEvent: React.PropTypes.oneOf([
        'onChange', 'onBlur', 'onFocus'
    ]),
    errorHelp      : React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.object
    ])
};

Form.defaultProps = {
    model          : {},
    validationEvent: 'onChange',
    onInvalidSubmit: () => {}
};
<commit_msg>Allow to pass in a method to the form<commit_after>import React from 'react';
import InputContainer from './InputContainer';
import ValidatedInput from './ValidatedInput';
import RadioGroup from './RadioGroup';

import Validator from './Validator';
import FileValidator from './FileValidator';
import createFragment from 'react-addons-create-fragment'

function getInputErrorMessage(input, ruleName) {
    let errorHelp = input.props.errorHelp;

    if (typeof errorHelp === 'object') {
        return errorHelp[ruleName];
    } else {
        return errorHelp;
    }
}

export default class Form extends InputContainer {
    constructor(props) {
        super(props);

        this.state = {
            isValid: true,
            invalidInputs: {}
        };
    }

    componentWillMount() {
        super.componentWillMount();

        this._validators = {};
    }

    registerInput(input) {
        super.registerInput(input);

        if (typeof input.props.validate === 'string') {
            this._validators[input.props.name] = this._compileValidationRules(input, input.props.validate);
        }
    }

    unregisterInput(input) {
        super.unregisterInput(input);

        delete this._validators[input.props.name];
    }

    render() {
        return (
            <form ref="form"
                  onSubmit={this._handleSubmit.bind(this)}
                  method={this.props.method}
                  action="#"
                  className={this.props.className}>
                {this._renderChildren(this.props.children)}
            </form>
        );
    }

    getValues() {
        return Object.keys(this._inputs).reduce((values, name) => {
            values[name] = this._getValue(name);

            return values;
        }, {});
    }

    submit() {
        this._handleSubmit();
    }

    _renderChildren(children) {
        if (typeof children !== 'object' || children === null) {
            return children;
        }

        let childrenCount = React.Children.count(children);

        if (childrenCount > 1) {
            return React.Children.map(children, child => this._renderChild(child));
        } else if (childrenCount === 1) {
            return this._renderChild(Array.isArray(children) ? children[0] : children);
        }
    }

    _renderChild(child) {
        if (typeof child !== 'object' || child === null) {
            return child;
        }

        let model = this.props.model || {};

        if (child.type === ValidatedInput ||
            child.type === RadioGroup || (
                child.type &&
                child.type.prototype !== null && (
                    child.type.prototype instanceof ValidatedInput ||
                    child.type.prototype instanceof RadioGroup
                )
            )
        ) {
            let name = child.props && child.props.name;

            if (!name) {
                throw new Error('Can not add input without "name" attribute');
            }

            let newProps = {
                _registerInput  : this.registerInput.bind(this),
                _unregisterInput: this.unregisterInput.bind(this)
            };

            let evtName = child.props.validationEvent ?
                    child.props.validationEvent : this.props.validationEvent;

            let origCallback = child.props[evtName];

            newProps[evtName] = e => {
                this._validateInput(name);

                return origCallback && origCallback(e);
            };

            if (name in model) {
                if (child.props.type === 'checkbox') {
                    newProps.defaultChecked = model[name];
                } else {
                    newProps.defaultValue = model[name];
                }
            }

            let error = this._hasError(name);

            if (error) {
                newProps.bsStyle = 'error';

                if (typeof error === 'string') {
                    newProps.help = error;
                } else if (child.props.errorHelp) {
                    newProps.help = createFragment(child.props.errorHelp);
                }
            }

            return React.cloneElement(child, newProps);
        } else {
            return React.cloneElement(child, {}, this._renderChildren(child.props && child.props.children));
        }
    }

    _validateInput(name) {
        this._validateOne(name, this.getValues());
    }

    _hasError(iptName) {
        return this.state.invalidInputs[iptName];
    }

    _setError(iptName, isError, errText) {
        if (isError && errText &&
            typeof errText !== 'string' &&
            typeof errText !== 'boolean')
        {
            errText = errText + '';
        }

        // set value to either bool or error description string
        this.setState({
            invalidInputs: Object.assign(
                this.state.invalidInputs,
                {
                    [iptName]: isError ? errText || true : false
                }
            )
        });
    }

    _validateOne(iptName, context) {
        let input = this._inputs[iptName];

        if (Array.isArray(input)) {
            console.warn('Multiple inputs use the same name "' + iptName + '"');

            return false;
        }

        let value = context[iptName];
        let isValid = true;
        let validate = input.props.validate;
        let result, error;

         if (typeof validate === 'function') {
            result = validate(value, context);
        } else if (typeof validate === 'string') {
            result = this._validators[iptName](value);
        } else {
            result = true;
        }

		if (typeof this.props.validateOne === 'function') {
            result = this.props.validateOne(iptName, value, context, result);
        }
        // if result is !== true, it is considered an error
        // it can be either bool or string error
        if (result !== true) {
            isValid = false;

            if (typeof result === 'string') {
                error = result;
            }
        }

        this._setError(iptName, !isValid, error);

        return isValid;
    }

    _validateAll(context) {
        let isValid = true;
        let errors = [];

        if (typeof this.props.validateAll === 'function') {
            let result = this.props.validateAll(context);

            if (result !== true) {
                isValid = false;

                Object.keys(result).forEach(iptName => {
                    errors.push(iptName);

                    this._setError(iptName, true, result[iptName]);
                });
            }
        } else {
            Object.keys(this._inputs).forEach(iptName => {
                if (!this._validateOne(iptName, context)) {
                    isValid = false;
                    errors.push(iptName);
                }
            });
        }

        return {
            isValid: isValid,
            errors: errors
        };
    }

    _compileValidationRules(input, ruleProp) {
        let rules = ruleProp.split(',').map(rule => {
            let params = rule.split(':');
            let name = params.shift();
            let inverse = name[0] === '!';

            if (inverse) {
                name = name.substr(1);
            }

            return { name, inverse, params };
        });

        let validator = (input.props && input.props.type) === 'file' ? FileValidator : Validator;

        return val => {
            let result = true;

            rules.forEach(rule => {
                if (typeof validator[rule.name] !== 'function') {
                    throw new Error('Invalid input validation rule "' + rule.name + '"');
                }

                let ruleResult = validator[rule.name](val, ...rule.params);

                if (rule.inverse) {
                    ruleResult = !ruleResult;
                }

                if (result === true && ruleResult !== true) {
                    result = getInputErrorMessage(input, rule.name) ||
                        getInputErrorMessage(this, rule.name) || false;
                }
            });

            return result;
        };
    }

    _getValue(iptName) {
        let input = this._inputs[iptName];

        if (Array.isArray(input)) {
            console.warn('Multiple inputs use the same name "' + iptName + '"');

            return false;
        }

        let value;

        if (input.props.type === 'checkbox') {
            value = input.getChecked();
        } else if (input.props.type === 'file') {
            value = input.getInputDOMNode().files;
        } else {
            value = input.getValue();
        }

        return value;
    }

    _handleSubmit(e) {
        if (e) {
            e.preventDefault();
        }

        let values = this.getValues();

        let { isValid, errors } = this._validateAll(values);

        if (isValid) {
            this.props.onValidSubmit(values);
        } else {
            this.props.onInvalidSubmit(errors, values);
        }
    }
}

Form.propTypes = {
    className      : React.PropTypes.string,
    model          : React.PropTypes.object,
    method         : React.PropTypes.oneOf(['get', 'post']),
    onValidSubmit  : React.PropTypes.func.isRequired,
    onInvalidSubmit: React.PropTypes.func,
    validateOne    : React.PropTypes.func,
    validateAll    : React.PropTypes.func,
    validationEvent: React.PropTypes.oneOf([
        'onChange', 'onBlur', 'onFocus'
    ]),
    errorHelp      : React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.object
    ])
};

Form.defaultProps = {
    model          : {},
    validationEvent: 'onChange',
    method         : 'get',
    onInvalidSubmit: () => {}
};
<|endoftext|>


<commit_before>'use strict';

var globals = require('./globals'),
  consts = require('./consts'),
  util = require('./util'),
  vlfield = require('./field'),
  vlenc = require('./enc'),
  schema = require('./schema/schema'),
  time = require('./compile/time');

var Encoding = module.exports = (function() {

  function Encoding(marktype, enc, config, filter, theme) {
    var defaults = schema.instantiate();

    var spec = {
      marktype: marktype,
      enc: enc,
      cfg: config,
      filter: filter || []
    };

    // type to bitcode
    for (var e in defaults.enc) {
      defaults.enc[e].type = consts.dataTypes[defaults.enc[e].type];
    }

    var specExtended = schema.util.merge(defaults, theme || {}, spec) ;

    this._marktype = specExtended.marktype;
    this._enc = specExtended.enc;
    this._cfg = specExtended.cfg;
    this._filter = specExtended.filter;
  }

  var proto = Encoding.prototype;

  proto.marktype = function() {
    return this._marktype;
  };

  proto.is = function(m) {
    return this._marktype === m;
  };

  proto.has = function(encType) {
    // equivalent to calling vlenc.has(this._enc, encType)
    return this._enc[encType].name !== undefined;
  };

  proto.enc = function(x) {
    return this._enc[x];
  };

  proto.filter = function() {
    var filterNull = [],
      fields = this.fields(),
      self = this;

    util.forEach(fields, function(fieldList, fieldName) {
      if (fieldName === '*') return; //count

      if ((self.config('filterNull').Q && fieldList.containsType[Q]) ||
          (self.config('filterNull').T && fieldList.containsType[T]) ||
          (self.config('filterNull').O && fieldList.containsType[O])) {
        filterNull.push({
          operands: [fieldName],
          operator: 'notNull'
        });
      }
    });

    return filterNull.concat(this._filter);
  };

  // get "field" property for vega
  proto.field = function(x, nodata, nofn) {
    if (!this.has(x)) return null;

    var f = (nodata ? '' : 'data.');

    if (this._enc[x].aggr === 'count') {
      return f + 'count';
    } else if (!nofn && this._enc[x].bin) {
      return f + 'bin_' + this._enc[x].name;
    } else if (!nofn && this._enc[x].aggr) {
      return f + this._enc[x].aggr + '_' + this._enc[x].name;
    } else if (!nofn && this._enc[x].fn) {
      return f + this._enc[x].fn + '_' + this._enc[x].name;
    } else {
      return f + this._enc[x].name;
    }
  };

  proto.fieldName = function(x) {
    return this._enc[x].name;
  };

  /*
   * return key-value pairs of field name and list of fields of that field name
   */
  proto.fields = function() {
    return vlenc.fields(this._enc);
  };

  proto.fieldTitle = function(x) {
    if (vlfield.isCount(this._enc[x])) {
      return vlfield.count.displayName;
    }
    var fn = this._enc[x].aggr || this._enc[x].fn || (this._enc[x].bin && "bin");
    if (fn) {
      return fn.toUpperCase() + '(' + this._enc[x].name + ')';
    } else {
      return this._enc[x].name;
    }
  };

  proto.scale = function(x) {
    return this._enc[x].scale || {};
  };

  proto.axis = function(x) {
    return this._enc[x].axis || {};
  };

  proto.band = function(x) {
    return this._enc[x].band || {};
  };

  proto.bandSize = function(encType, useSmallBand) {
    useSmallBand = useSmallBand ||
      //isBandInSmallMultiples
      (encType === Y && this.has(ROW) && this.has(Y)) ||
      (encType === X && this.has(COL) && this.has(X));

    // if band.size is explicitly specified, follow the specification, otherwise draw value from config.
    return this.band(encType).size ||
      this.config(useSmallBand ? 'smallBandSize' : 'largeBandSize');
  };

  proto.aggr = function(x) {
    return this._enc[x].aggr;
  };

  // returns false if binning is disabled, otherwise an object with binning properties
  proto.bin = function(x) {
    var bin = this._enc[x].bin;
    if (bin === {})
      return false;
    if (bin === true)
      return {
        maxbins: schema.MAXBINS_DEFAULT
      };
    return bin;
  };

  proto.legend = function(x) {
    return this._enc[x].legend;
  };

  proto.value = function(x) {
    return this._enc[x].value;
  };

  proto.fn = function(x) {
    return this._enc[x].fn;
  };

   proto.sort = function(x) {
    return this._enc[x].sort;
  };

  proto.any = function(f) {
    return util.any(this._enc, f);
  };

  proto.all = function(f) {
    return util.all(this._enc, f);
  };

  proto.length = function() {
    return util.keys(this._enc).length;
  };

  proto.map = function(f) {
    return vlenc.map(this._enc, f);
  };

  proto.reduce = function(f, init) {
    return vlenc.reduce(this._enc, f, init);
  };

  proto.forEach = function(f) {
    return vlenc.forEach(this._enc, f);
  };

  proto.type = function(et) {
    return this.has(et) ? this._enc[et].type : null;
  };

  proto.role = function(et) {
    return this.has(et) ? vlfield.role(this._enc[et]) : null;
  };

  proto.text = function(prop) {
    var text = this._enc[TEXT].text;
    return prop ? text[prop] : text;
  };

  proto.font = function(prop) {
    var font = this._enc[TEXT].font;
    return prop ? font[prop] : font;
  };

  proto.isType = function(x, type) {
    var field = this.enc(x);
    return field && Encoding.isType(field, type);
  };

  Encoding.isType = function (fieldDef, type) {
    return (fieldDef.type & type) > 0;
  };

  Encoding.isOrdinalScale = function(encoding, encType) {
    return vlfield.isOrdinalScale(encoding.enc(encType), true);
  };

  Encoding.isDimension = function(encoding, encType) {
    return vlfield.isDimension(encoding.enc(encType), true);
  };

  Encoding.isMeasure = function(encoding, encType) {
    return vlfield.isMeasure(encoding.enc(encType), true);
  };

  proto.isOrdinalScale = function(encType) {
    return this.has(encType) && Encoding.isOrdinalScale(this, encType);
  };

  proto.isDimension = function(encType) {
    return this.has(encType) && Encoding.isDimension(this, encType);
  };

  proto.isMeasure = function(encType) {
    return this.has(encType) && Encoding.isMeasure(this, encType);
  };

  proto.isAggregate = function() {
    return vlenc.isAggregate(this._enc);
  };

  Encoding.isAggregate = function(spec) {
    return vlenc.isAggregate(spec.enc);
  };

  Encoding.alwaysNoOcclusion = function(spec, stats) {
    // FIXME raw OxQ with # of rows = # of O
    return vlenc.isAggregate(spec.enc);
  };

  Encoding.isStack = function(spec) {
    // FIXME update this once we have control for stack ...
    return (spec.marktype === 'bar' || spec.marktype === 'area') &&
      spec.enc.color;
  };

  proto.isStack = function() {
    // FIXME update this once we have control for stack ...
    return (this.is('bar') || this.is('area')) && this.has('color');
  };

  proto.cardinality = function(encType, stats) {
    return vlfield.cardinality(this.enc(encType), stats, this.config('filterNull'), true);
  };

  proto.isRaw = function() {
    return !this.isAggregate();
  };

  proto.config = function(name) {
    return this._cfg[name];
  };

  proto.toSpec = function(excludeConfig) {
    var enc = util.duplicate(this._enc),
      spec;

    // convert type's bitcode to type name
    for (var e in enc) {
      enc[e].type = consts.dataTypeNames[enc[e].type];
    }

    spec = {
      marktype: this._marktype,
      enc: enc,
      filter: this._filter
    };

    if (!excludeConfig) {
      spec.cfg = util.duplicate(this._cfg);
    }

    // remove defaults
    var defaults = schema.instantiate();
    return schema.util.subtract(spec, defaults);
  };

  proto.toShorthand = function() {
    var c = consts.shorthand;
    return 'mark' + c.assign + this._marktype +
      c.delim + vlenc.shorthand(this._enc);
  };

  Encoding.shorthand = function (spec) {
    var c = consts.shorthand;
    return 'mark' + c.assign + spec.marktype +
      c.delim + vlenc.shorthand(spec.enc);
  };

  Encoding.parseShorthand = function(shorthand, cfg) {
    var c = consts.shorthand,
        split = shorthand.split(c.delim),
        marktype = split.shift().split(c.assign)[1].trim(),
        enc = vlenc.parseShorthand(split, true);

    return new Encoding(marktype, enc, cfg);
  };

  // FIXME remove this -- simply use Encoding.shorthand
  Encoding.shorthandFromSpec = function(/*spec, theme*/) {
    return Encoding.fromSpec.apply(null, arguments).toShorthand();
  };

  Encoding.specFromShorthand = function(shorthand, cfg, excludeConfig) {
    return Encoding.parseShorthand(shorthand, cfg).toSpec(excludeConfig);
  };

  Encoding.fromSpec = function(spec, theme) {
    var enc = util.duplicate(spec.enc || {});

    //convert type from string to bitcode (e.g, O=1)
    for (var e in enc) {
      enc[e].type = consts.dataTypes[enc[e].type];
    }

    return new Encoding(spec.marktype, enc, spec.cfg, spec.filter, theme);
  };

  Encoding.transpose = function(spec) {
    var oldenc = spec.enc,
      enc = util.duplicate(spec.enc);
    enc.x = oldenc.y;
    enc.y = oldenc.x;
    enc.row = oldenc.col;
    enc.col = oldenc.row;
    spec.enc = enc;
    return spec;
  };

  Encoding.toggleSort = function(spec) {
    if (!Encoding.toggleSort.support(spec)) { return; }
    var enc = spec.enc;

    var oField = enc.x.type === 'O' ? enc.x : enc.y,
      qField = enc.x.type === 'O' ? enc.y : enc.x;

    // FIXME add ascending / descending
    if (oField.sort && oField.sort.length > 0) {
      oField.sort = [];
    } else {
      oField.sort = [{
        name: qField.name,
        aggr: qField.aggr,
        type: qField.type,
        reverse: true
      }];
    }

    spec.enc = enc;
    return spec;
  };

  Encoding.toggleSort.direction = function(spec) {
    if (!Encoding.toggleSort.support(spec)) { return; }
    var enc = spec.enc;
    return enc.x.type === 'O' ? 'x' :  'y';
  };

  Encoding.toggleSort.mode = function(spec) {
    if (!Encoding.toggleSort.support(spec)) { return; }
    var enc = spec.enc;

    var oField = enc.x.type === 'O' ? enc.x : enc.y,
      qField = enc.x.type === 'O' ? enc.y : enc.x;

    // FIXME add ascending / descending
    if (oField.sort && oField.sort.length > 0) {
      return 'Q';
    } else {
      return 'O';
    }
  };

  Encoding.toggleSort.support = function(spec, stats) {
    var enc = spec.enc;
    if (vlenc.has(enc, ROW) || vlenc.has(enc, COL) ||
      !vlenc.has(enc, X) || !vlenc.has(enc, Y) ||
      !Encoding.alwaysNoOcclusion(spec, stats)) {
      return false;
    }
    return (enc.x.type === 'O' && vlfield.isMeasure(enc.y)) ? 'x' :
      (enc.y.type === 'O' && vlfield.isMeasure(enc.x)) ? 'y' : false;
  };

  Encoding.toggleFilterNullO = function(spec) {
    spec.cfg.filterNull.O = !spec.cfg.filterNull.O;
    return spec;
  };

  Encoding.toggleFilterNullO.support = function(spec, stats) {
    var fields = vlenc.fields(spec.enc);
    console.log('fields', fields);
    for (var fieldName in fields) {
      var fieldList = fields[fieldName];
      if (fieldList.containsType.O && stats[fieldName].numNulls > 0) {
        return true;
      }
    }
    return false;
  };

  return Encoding;
})();
<commit_msg>Remove log<commit_after>'use strict';

var globals = require('./globals'),
  consts = require('./consts'),
  util = require('./util'),
  vlfield = require('./field'),
  vlenc = require('./enc'),
  schema = require('./schema/schema'),
  time = require('./compile/time');

var Encoding = module.exports = (function() {

  function Encoding(marktype, enc, config, filter, theme) {
    var defaults = schema.instantiate();

    var spec = {
      marktype: marktype,
      enc: enc,
      cfg: config,
      filter: filter || []
    };

    // type to bitcode
    for (var e in defaults.enc) {
      defaults.enc[e].type = consts.dataTypes[defaults.enc[e].type];
    }

    var specExtended = schema.util.merge(defaults, theme || {}, spec) ;

    this._marktype = specExtended.marktype;
    this._enc = specExtended.enc;
    this._cfg = specExtended.cfg;
    this._filter = specExtended.filter;
  }

  var proto = Encoding.prototype;

  proto.marktype = function() {
    return this._marktype;
  };

  proto.is = function(m) {
    return this._marktype === m;
  };

  proto.has = function(encType) {
    // equivalent to calling vlenc.has(this._enc, encType)
    return this._enc[encType].name !== undefined;
  };

  proto.enc = function(x) {
    return this._enc[x];
  };

  proto.filter = function() {
    var filterNull = [],
      fields = this.fields(),
      self = this;

    util.forEach(fields, function(fieldList, fieldName) {
      if (fieldName === '*') return; //count

      if ((self.config('filterNull').Q && fieldList.containsType[Q]) ||
          (self.config('filterNull').T && fieldList.containsType[T]) ||
          (self.config('filterNull').O && fieldList.containsType[O])) {
        filterNull.push({
          operands: [fieldName],
          operator: 'notNull'
        });
      }
    });

    return filterNull.concat(this._filter);
  };

  // get "field" property for vega
  proto.field = function(x, nodata, nofn) {
    if (!this.has(x)) return null;

    var f = (nodata ? '' : 'data.');

    if (this._enc[x].aggr === 'count') {
      return f + 'count';
    } else if (!nofn && this._enc[x].bin) {
      return f + 'bin_' + this._enc[x].name;
    } else if (!nofn && this._enc[x].aggr) {
      return f + this._enc[x].aggr + '_' + this._enc[x].name;
    } else if (!nofn && this._enc[x].fn) {
      return f + this._enc[x].fn + '_' + this._enc[x].name;
    } else {
      return f + this._enc[x].name;
    }
  };

  proto.fieldName = function(x) {
    return this._enc[x].name;
  };

  /*
   * return key-value pairs of field name and list of fields of that field name
   */
  proto.fields = function() {
    return vlenc.fields(this._enc);
  };

  proto.fieldTitle = function(x) {
    if (vlfield.isCount(this._enc[x])) {
      return vlfield.count.displayName;
    }
    var fn = this._enc[x].aggr || this._enc[x].fn || (this._enc[x].bin && "bin");
    if (fn) {
      return fn.toUpperCase() + '(' + this._enc[x].name + ')';
    } else {
      return this._enc[x].name;
    }
  };

  proto.scale = function(x) {
    return this._enc[x].scale || {};
  };

  proto.axis = function(x) {
    return this._enc[x].axis || {};
  };

  proto.band = function(x) {
    return this._enc[x].band || {};
  };

  proto.bandSize = function(encType, useSmallBand) {
    useSmallBand = useSmallBand ||
      //isBandInSmallMultiples
      (encType === Y && this.has(ROW) && this.has(Y)) ||
      (encType === X && this.has(COL) && this.has(X));

    // if band.size is explicitly specified, follow the specification, otherwise draw value from config.
    return this.band(encType).size ||
      this.config(useSmallBand ? 'smallBandSize' : 'largeBandSize');
  };

  proto.aggr = function(x) {
    return this._enc[x].aggr;
  };

  // returns false if binning is disabled, otherwise an object with binning properties
  proto.bin = function(x) {
    var bin = this._enc[x].bin;
    if (bin === {})
      return false;
    if (bin === true)
      return {
        maxbins: schema.MAXBINS_DEFAULT
      };
    return bin;
  };

  proto.legend = function(x) {
    return this._enc[x].legend;
  };

  proto.value = function(x) {
    return this._enc[x].value;
  };

  proto.fn = function(x) {
    return this._enc[x].fn;
  };

   proto.sort = function(x) {
    return this._enc[x].sort;
  };

  proto.any = function(f) {
    return util.any(this._enc, f);
  };

  proto.all = function(f) {
    return util.all(this._enc, f);
  };

  proto.length = function() {
    return util.keys(this._enc).length;
  };

  proto.map = function(f) {
    return vlenc.map(this._enc, f);
  };

  proto.reduce = function(f, init) {
    return vlenc.reduce(this._enc, f, init);
  };

  proto.forEach = function(f) {
    return vlenc.forEach(this._enc, f);
  };

  proto.type = function(et) {
    return this.has(et) ? this._enc[et].type : null;
  };

  proto.role = function(et) {
    return this.has(et) ? vlfield.role(this._enc[et]) : null;
  };

  proto.text = function(prop) {
    var text = this._enc[TEXT].text;
    return prop ? text[prop] : text;
  };

  proto.font = function(prop) {
    var font = this._enc[TEXT].font;
    return prop ? font[prop] : font;
  };

  proto.isType = function(x, type) {
    var field = this.enc(x);
    return field && Encoding.isType(field, type);
  };

  Encoding.isType = function (fieldDef, type) {
    return (fieldDef.type & type) > 0;
  };

  Encoding.isOrdinalScale = function(encoding, encType) {
    return vlfield.isOrdinalScale(encoding.enc(encType), true);
  };

  Encoding.isDimension = function(encoding, encType) {
    return vlfield.isDimension(encoding.enc(encType), true);
  };

  Encoding.isMeasure = function(encoding, encType) {
    return vlfield.isMeasure(encoding.enc(encType), true);
  };

  proto.isOrdinalScale = function(encType) {
    return this.has(encType) && Encoding.isOrdinalScale(this, encType);
  };

  proto.isDimension = function(encType) {
    return this.has(encType) && Encoding.isDimension(this, encType);
  };

  proto.isMeasure = function(encType) {
    return this.has(encType) && Encoding.isMeasure(this, encType);
  };

  proto.isAggregate = function() {
    return vlenc.isAggregate(this._enc);
  };

  Encoding.isAggregate = function(spec) {
    return vlenc.isAggregate(spec.enc);
  };

  Encoding.alwaysNoOcclusion = function(spec, stats) {
    // FIXME raw OxQ with # of rows = # of O
    return vlenc.isAggregate(spec.enc);
  };

  Encoding.isStack = function(spec) {
    // FIXME update this once we have control for stack ...
    return (spec.marktype === 'bar' || spec.marktype === 'area') &&
      spec.enc.color;
  };

  proto.isStack = function() {
    // FIXME update this once we have control for stack ...
    return (this.is('bar') || this.is('area')) && this.has('color');
  };

  proto.cardinality = function(encType, stats) {
    return vlfield.cardinality(this.enc(encType), stats, this.config('filterNull'), true);
  };

  proto.isRaw = function() {
    return !this.isAggregate();
  };

  proto.config = function(name) {
    return this._cfg[name];
  };

  proto.toSpec = function(excludeConfig) {
    var enc = util.duplicate(this._enc),
      spec;

    // convert type's bitcode to type name
    for (var e in enc) {
      enc[e].type = consts.dataTypeNames[enc[e].type];
    }

    spec = {
      marktype: this._marktype,
      enc: enc,
      filter: this._filter
    };

    if (!excludeConfig) {
      spec.cfg = util.duplicate(this._cfg);
    }

    // remove defaults
    var defaults = schema.instantiate();
    return schema.util.subtract(spec, defaults);
  };

  proto.toShorthand = function() {
    var c = consts.shorthand;
    return 'mark' + c.assign + this._marktype +
      c.delim + vlenc.shorthand(this._enc);
  };

  Encoding.shorthand = function (spec) {
    var c = consts.shorthand;
    return 'mark' + c.assign + spec.marktype +
      c.delim + vlenc.shorthand(spec.enc);
  };

  Encoding.parseShorthand = function(shorthand, cfg) {
    var c = consts.shorthand,
        split = shorthand.split(c.delim),
        marktype = split.shift().split(c.assign)[1].trim(),
        enc = vlenc.parseShorthand(split, true);

    return new Encoding(marktype, enc, cfg);
  };

  // FIXME remove this -- simply use Encoding.shorthand
  Encoding.shorthandFromSpec = function(/*spec, theme*/) {
    return Encoding.fromSpec.apply(null, arguments).toShorthand();
  };

  Encoding.specFromShorthand = function(shorthand, cfg, excludeConfig) {
    return Encoding.parseShorthand(shorthand, cfg).toSpec(excludeConfig);
  };

  Encoding.fromSpec = function(spec, theme) {
    var enc = util.duplicate(spec.enc || {});

    //convert type from string to bitcode (e.g, O=1)
    for (var e in enc) {
      enc[e].type = consts.dataTypes[enc[e].type];
    }

    return new Encoding(spec.marktype, enc, spec.cfg, spec.filter, theme);
  };

  Encoding.transpose = function(spec) {
    var oldenc = spec.enc,
      enc = util.duplicate(spec.enc);
    enc.x = oldenc.y;
    enc.y = oldenc.x;
    enc.row = oldenc.col;
    enc.col = oldenc.row;
    spec.enc = enc;
    return spec;
  };

  Encoding.toggleSort = function(spec) {
    if (!Encoding.toggleSort.support(spec)) { return; }
    var enc = spec.enc;

    var oField = enc.x.type === 'O' ? enc.x : enc.y,
      qField = enc.x.type === 'O' ? enc.y : enc.x;

    // FIXME add ascending / descending
    if (oField.sort && oField.sort.length > 0) {
      oField.sort = [];
    } else {
      oField.sort = [{
        name: qField.name,
        aggr: qField.aggr,
        type: qField.type,
        reverse: true
      }];
    }

    spec.enc = enc;
    return spec;
  };

  Encoding.toggleSort.direction = function(spec) {
    if (!Encoding.toggleSort.support(spec)) { return; }
    var enc = spec.enc;
    return enc.x.type === 'O' ? 'x' :  'y';
  };

  Encoding.toggleSort.mode = function(spec) {
    if (!Encoding.toggleSort.support(spec)) { return; }
    var enc = spec.enc;

    var oField = enc.x.type === 'O' ? enc.x : enc.y,
      qField = enc.x.type === 'O' ? enc.y : enc.x;

    // FIXME add ascending / descending
    if (oField.sort && oField.sort.length > 0) {
      return 'Q';
    } else {
      return 'O';
    }
  };

  Encoding.toggleSort.support = function(spec, stats) {
    var enc = spec.enc;
    if (vlenc.has(enc, ROW) || vlenc.has(enc, COL) ||
      !vlenc.has(enc, X) || !vlenc.has(enc, Y) ||
      !Encoding.alwaysNoOcclusion(spec, stats)) {
      return false;
    }
    return (enc.x.type === 'O' && vlfield.isMeasure(enc.y)) ? 'x' :
      (enc.y.type === 'O' && vlfield.isMeasure(enc.x)) ? 'y' : false;
  };

  Encoding.toggleFilterNullO = function(spec) {
    spec.cfg.filterNull.O = !spec.cfg.filterNull.O;
    return spec;
  };

  Encoding.toggleFilterNullO.support = function(spec, stats) {
    var fields = vlenc.fields(spec.enc);
    for (var fieldName in fields) {
      var fieldList = fields[fieldName];
      if (fieldList.containsType.O && stats[fieldName].numNulls > 0) {
        return true;
      }
    }
    return false;
  };

  return Encoding;
})();
<|endoftext|>