<commit_before>var Server    = require('socket.io');
var msgRouter = require('./msgrouter.io');

/*
 * The standard socket.io options:
 *
 * opts {
 *    ...
 * }
 */
function BridgerIO(srv, opts) {
    "use strict";
    if (!(this instanceof BridgerIO))  { return new BridgerIO(srv, opts); }

    Server.call(this, srv, opts);

    var allServices = this.services    = {};

    this.on('connection', function(socket) {
        Object.keys(allServices).forEach(function(routeName) {
            allServices[routeName].route(socket);
        });

        // Keep an eye on this
        //
        // Normally, when sending a message that isn't handled by the server, it is just
        // silently swallowed.
        //
        // This logic overrides that behavior and attempts to send an error when an attempt
        // to call a method that isn't registered is made.
        //
        // The source for this socket is in: socket.io/lib/socket.js
        var real_onevent = socket.onevent;
        var ignore = { "message": true, "disconnect": true, "error": true };
        socket.onevent = function(packet) {
            if(packet.data && packet.data.length) {
                if(this._events[packet.data[0]]) {
                    return real_onevent.call(this, packet);
                } else if(!ignore[packet.data[0]]) {
                    return this.ack(packet.id)({ error: { message: "Invalid request" }});
                }
            }

            real_onevent.call(this, packet);
        };

        socket.on('describe', function(msg, cb) {
            if(typeof msg === "function") {
                cb  = msg;
                msg = Object.keys(allServices);
            }

            if(msg === 'all') { msg = Object.keys(allServices); }
            else if(typeof msg === "string") { msg = [msg]; }

            var retVal = {};
            msg.forEach(function(service) {
                retVal[service] = (allServices[service] || { describe: function() {} }).describe(service);
            });

            cb({ result: retVal });
        });
    });
}

/*
 * Inherit from socket.io Server
 */
BridgerIO.prototype = Object.create(Server.prototype);
BridgerIO.prototype.constructor = BridgerIO;

/*
 * "A service defines a set of resources and actions that can be accessed via URI endpoints"
 *
 * In this case:
 * - Service is the logical name for a set of resources
 * - Resources is one or more API's (api being a set of methods or methods exposed on an object)
 * - URI endpoints corresponds to the individual methods on the provided Resource/API
 *
 * @param service   - logical name for the service
 * @param resources - Set of one or more APIs keyed by name
 * @param routerFn  - optional function that generates a new router that can be used to replace the
 *                    default router (msg) with ArgsRouter or one of your own. If supplied, each
 *                    call to expose **MUST** pass in a new instance of a Router
 * @param routes    - optional set of route handlers that can be used to enhance/override the base
 *                    route handling behavior
 *
 */
BridgerIO.prototype.expose = function expose(service, resources, routerFn, routes) {
    "use strict";
    var args = Array.prototype.slice.call(arguments);
    var router;

    if(typeof service   !== "string"  ) { throw new Error("Invalid service name"); }
    if(typeof resources !== "object"  ) { throw new Error("Invalid resource object"); }

    if(typeof routerFn  !== "function" && args.length === 3) {
        routes = routerFn;
        routerFn = msgRouter;
    }

    router = (routerFn || msgRouter)(service);
    router.expose(resources, routes);

    this.services[service] = router;
};

module.exports = BridgerIO;<commit_msg>Removed misleading comment - constructor is passed in, not a new object<commit_after>var Server    = require('socket.io');
var msgRouter = require('./msgrouter.io');

/*
 * The standard socket.io options:
 *
 * opts {
 *    ...
 * }
 */
function BridgerIO(srv, opts) {
    "use strict";
    if (!(this instanceof BridgerIO))  { return new BridgerIO(srv, opts); }

    Server.call(this, srv, opts);

    var allServices = this.services    = {};

    this.on('connection', function(socket) {
        Object.keys(allServices).forEach(function(routeName) {
            allServices[routeName].route(socket);
        });

        // Keep an eye on this
        //
        // Normally, when sending a message that isn't handled by the server, it is just
        // silently swallowed.
        //
        // This logic overrides that behavior and attempts to send an error when an attempt
        // to call a method that isn't registered is made.
        //
        // The source for this socket is in: socket.io/lib/socket.js
        var real_onevent = socket.onevent;
        var ignore = { "message": true, "disconnect": true, "error": true };
        socket.onevent = function(packet) {
            if(packet.data && packet.data.length) {
                if(this._events[packet.data[0]]) {
                    return real_onevent.call(this, packet);
                } else if(!ignore[packet.data[0]]) {
                    return this.ack(packet.id)({ error: { message: "Invalid request" }});
                }
            }

            real_onevent.call(this, packet);
        };

        socket.on('describe', function(msg, cb) {
            if(typeof msg === "function") {
                cb  = msg;
                msg = Object.keys(allServices);
            }

            if(msg === 'all') { msg = Object.keys(allServices); }
            else if(typeof msg === "string") { msg = [msg]; }

            var retVal = {};
            msg.forEach(function(service) {
                retVal[service] = (allServices[service] || { describe: function() {} }).describe(service);
            });

            cb({ result: retVal });
        });
    });
}

/*
 * Inherit from socket.io Server
 */
BridgerIO.prototype = Object.create(Server.prototype);
BridgerIO.prototype.constructor = BridgerIO;

/*
 * "A service defines a set of resources and actions that can be accessed via URI endpoints"
 *
 * In this case:
 * - Service is the logical name for a set of resources
 * - Resources is one or more API's (api being a set of methods or methods exposed on an object)
 * - URI endpoints corresponds to the individual methods on the provided Resource/API
 *
 * @param service   - logical name for the service
 * @param resources - Set of one or more APIs keyed by name
 * @param routerFn  - optional function that generates a new router that can be used to replace the
 *                    default router (msg) with ArgsRouter or one of your own.
 * @param routes    - optional set of route handlers that can be used to enhance/override the base
 *                    route handling behavior
 *
 */
BridgerIO.prototype.expose = function expose(service, resources, routerFn, routes) {
    "use strict";
    var args = Array.prototype.slice.call(arguments);
    var router;

    if(typeof service   !== "string"  ) { throw new Error("Invalid service name"); }
    if(typeof resources !== "object"  ) { throw new Error("Invalid resource object"); }

    if(typeof routerFn  !== "function" && args.length === 3) {
        routes = routerFn;
        routerFn = msgRouter;
    }

    router = (routerFn || msgRouter)(service);
    router.expose(resources, routes);

    this.services[service] = router;
};

module.exports = BridgerIO;<|endoftext|>


<commit_before>(function(){

    angular.module('Energy', [])
        .controller('EnergyCtrl', EnergyCtrl)
        .service('EnergyService', EnergyService)

    /**
     * Model, store everything here
     */
    function EnergyService(){

        var self = this;

        self.energyExpendatures = [
            {name: '10km Bike ride', energy: 1464000, type:'distance'},

            {name: 'Shot by air gun', energy: 10, type:'kinetic'},
            {name: 'Shot by hunting rifle', energy: 1000, type:'kinetic'},
            {name: 'Human punch', energy: 150, type:'kinetic'},

            {name: 'World energy consumption by second', energy: 1.6288038e13}

        ];

        self.energyStores = [
            {name: 'Mars bar', energy: 963000, type:'store'},
            {name: 'Banana', energy: 418000, type:'store'}
        ];

        /**
         * Other ideas
         * Sunlight in seconds
         * Whole world energy consumption per second
         * Batteries
         * Fusion
         * Gasoline
         * Running
         * Lifting
         * Atom bomb
         * e=mc2
         * house hold
         * toasting bread
         * washing clothes
         * Industrial size wind turbine
         * Explosions
         * Burning a tree
         * Burning a candle
         * A smile
         * Sex
         * Shouting at someone
         * Shower
         * Cooking a liter of water
         * A punch
         * A Kick
         * Bullet
         */

        self.allEnergy = self.energyExpendatures.concat(self.energyStores);
    }

    /**
     *
     * @param $scope
     * @param EnergyService
     */
    function EnergyCtrl($scope, EnergyService){
        $scope.EnergyService = EnergyService;

        // after we've selected a thing, we need to trigger the recalculation

        $scope.recalc = function(){

            var comparable = $scope.selectedCompare;
            var comparee = $scope.selectedComparee;

            var ratio = Math.round((comparable.energy / comparee.energy)*100)/100;

            // Take the first thing. compare it to the other thing
            // How many bananas are there in a mars bar?
            if(ratio < 1){
                ratio = ratio * 100 +'%';
            }else{
                ratio += 'x'
            }
            $scope.ratio = ratio;
        }
    }

})();<commit_msg>More stuff<commit_after>(function(){

    angular.module('Energy', [])
        .controller('EnergyCtrl', EnergyCtrl)
        .service('EnergyService', EnergyService)

    /**
     * Model, store everything here
     */
    function EnergyService(){

        var self = this;

        self.energyExpendatures = [
            {name: '1km Bike ride', energy: 146400, type:'exp'},
            {name: '1km Car drive', energy: 2.72e6, type:'exp'},
            {name: 'Shot by air gun', energy: 10, type:'kinetic'},
            {name: 'Shot by hunting rifle', energy: 1000, type:'kinetic'},
            {name: 'Human punch', energy: 150, type:'exp'},
            {name: '1day of human life', energy: 10e6, type:'exp'},

            {name: 'World energy consumption by second', energy: 1.6288038e13}

        ];

        self.energyStores = [
            {name: 'Litre gasoline', energy: 33.92e6, type:'store'},
            {name: '1litre water at 10m', energy: 0.0001e6, type:'store'},
            {name: '1kg compressed air', energy: 0.5e6, type:'store'},
            {name: 'Anti matter', energy: 1.8e11, type:'store'},
            {name: '1kg Human Fat', energy: 37e6, type:'store'},
            {name: 'AA Battery', energy: 0.0154e6, type:'store'},
            {name: 'Car Battery', energy: 2.6e6, type:'store'},
            {name: 'Mars bar', energy: 963000, type:'store'},
            {name: 'Banana', energy: 418000, type:'store'}
        ];

        /**
         * Other ideas
         * Sunlight in seconds
         * Whole world energy consumption per second
         * Batteries
         * Fusion
         * Gasoline
         * Running
         * Lifting
         * Atom bomb
         * e=mc2
         * house hold
         * toasting bread
         * washing clothes
         * Industrial size wind turbine
         * Explosions
         * Burning a tree
         * Burning a candle
         * A smile
         * Sex
         * Shouting at someone
         * Shower
         * Cooking a liter of water
         * A punch
         * A Kick
         * Bullet
         */

        self.allEnergy = self.energyExpendatures.concat(self.energyStores);
    }

    /**
     *
     * @param $scope
     * @param EnergyService
     */
    function EnergyCtrl($scope, EnergyService){
        $scope.EnergyService = EnergyService;

        // after we've selected a thing, we need to trigger the recalculation

        $scope.recalc = function(){

            var comparable = $scope.selectedCompare;
            var comparee = $scope.selectedComparee;

            var ratio = Math.round((comparable.energy / comparee.energy)*100)/100;

            // Take the first thing. compare it to the other thing
            // How many bananas are there in a mars bar?
            if(ratio < 1){
                ratio = ratio * 100 +'%';
            }else{
                ratio += 'x'
            }
            $scope.ratio = ratio;
        }
    }

})();<|endoftext|>


<commit_before>var _ = require('underscore'),
    seq = require('seq'),
    error = require('../error'),
    query = require('../query'),
    i18nTools = require('../i18nTools');

module.exports = function (queryObj, localeIds) {
    return function cloneForEachLocale(err, assetGraph, cb) {
        if (err) {
            throw err;
        }
        seq.ap(assetGraph.findAssets(_.extend({type: 'HTML'}, queryObj)))
            .parEach(function (originalHTMLAsset) {
                var callback = this,
                    subgraph = assetGraph.createSubgraph(originalHTMLAsset, {type: ['HTMLScript', 'JavaScriptStaticInclude']}),
                    nonInlineJavaScriptsToCloneById = {};

                // First note which JavaScript assets need to be cloned for each locale:
                seq.ap(assetGraph.findRelations({type: 'HTMLScript', from: originalHTMLAsset, to: {url: query.defined}}))
                    .parEach(function (htmlScript) {
                        htmlScript.to.getParseTree(this);
                    })
                    .parEach(function (htmlScript) {
                        var hasOneTr = false;
                        i18nTools.eachOneTrInAST(htmlScript.to.parseTree, function () {
                            nonInlineJavaScriptsToCloneById[htmlScript.to.id] = htmlScript.to;
                            return false;
                        });
                        this();
                    })
                    .set(localeIds)
                    .flatten() // https://github.com/substack/node-seq/pull/9
                    .parEach(function (localeId) {
                        assetGraph.cloneAsset(originalHTMLAsset, this.into(localeId));
                    })
                    .parEach(function (localeId) {
                        var localizedHTML = this.vars[localeId];
                        assetGraph.setAssetUrl(localizedHTML, originalHTMLAsset.url.replace(/(?:\.html)?$/, '.' + localeId + '.html'));
                        localizedHTML.getParseTree(this);
                    })
                    .parEach(function (localeId) {
                        var callback2 = this,
                            localizedHTML = this.vars[localeId],
                            document = localizedHTML.parseTree;
                        document.documentElement.setAttribute('lang', localeId);
                        assetGraph.markAssetDirty(localizedHTML);
                        i18nTools.extractAllKeysForLocaleFromHTMLAsset(assetGraph, localeId, localizedHTML, error.passToFunction(callback2, function (allKeys) {
                            seq.ap(assetGraph.findRelations({type: 'HTMLScript', from: localizedHTML, to: _.values(nonInlineJavaScriptsToCloneById)}))
                                .parEach(function (htmlScript) {
                                    htmlScript.to.getParseTree(this);
                                })
                                .parMap(function (htmlScript) {
                                    assetGraph.cloneAsset(htmlScript.to, [htmlScript], this);
                                })
                                // Add localizedHTML's inline JavaScripts (already cloned when originalHTML was cloned):
                                .extend(assetGraph.findAssets({url: query.undefined, type: 'JavaScript', incoming: {from: localizedHTML}}))
                                .parEach(function (javaScript) {
                                    javaScript.getParseTree(this);
                                })
                                .parEach(function (javaScript) {
                                    i18nTools.eachOneTrInAST(javaScript.parseTree, i18nTools.createOneTrReplacer(allKeys, localeId));
                                    assetGraph.markAssetDirty(javaScript);
                                    this();
                                })
                                .seq(function () {
                                    callback2();
                                })
                                ['catch'](callback2);
                        }));
                    })
                    .seq(function () {
                        // Remove the original HTML and those of the cloned JavaScript assets that become orphaned:
                        assetGraph.removeAsset(originalHTMLAsset);
                        _.values(nonInlineJavaScriptsToCloneById).forEach(function (javaScript) {
                            if (assetGraph.findRelations({to: javaScript}).length === 0) {
                                assetGraph.removeAsset(javaScript);
                            }
                        });
                        callback();
                    })
                    ['catch'](callback);
            })
            .seq(function () {
                cb();
            })
            ['catch'](cb);
    };
};
<commit_msg>transforms.cloneForEachLocale: Fixed bug that caused the HTMLScript relations to be in a wrong order when some of the target assets had to be cloned.<commit_after>var _ = require('underscore'),
    seq = require('seq'),
    error = require('../error'),
    query = require('../query'),
    i18nTools = require('../i18nTools');

module.exports = function (queryObj, localeIds) {
    return function cloneForEachLocale(err, assetGraph, cb) {
        if (err) {
            throw err;
        }
        seq.ap(assetGraph.findAssets(_.extend({type: 'HTML'}, queryObj)))
            .parEach(function (originalHTMLAsset) {
                var callback = this,
                    subgraph = assetGraph.createSubgraph(originalHTMLAsset, {type: ['HTMLScript', 'JavaScriptStaticInclude']}),
                    nonInlineJavaScriptsToCloneById = {};

                // First note which JavaScript assets need to be cloned for each locale:
                seq.ap(assetGraph.findRelations({type: 'HTMLScript', from: originalHTMLAsset, to: {url: query.defined}}))
                    .parEach(function (htmlScript) {
                        htmlScript.to.getParseTree(this);
                    })
                    .parEach(function (htmlScript) {
                        var hasOneTr = false;
                        i18nTools.eachOneTrInAST(htmlScript.to.parseTree, function () {
                            nonInlineJavaScriptsToCloneById[htmlScript.to.id] = htmlScript.to;
                            return false;
                        });
                        this();
                    })
                    .set(localeIds)
                    .flatten() // https://github.com/substack/node-seq/pull/9
                    .parEach(function (localeId) {
                        assetGraph.cloneAsset(originalHTMLAsset, this.into(localeId));
                    })
                    .parEach(function (localeId) {
                        var localizedHTML = this.vars[localeId];
                        assetGraph.setAssetUrl(localizedHTML, originalHTMLAsset.url.replace(/(?:\.html)?$/, '.' + localeId + '.html'));
                        localizedHTML.getParseTree(this);
                    })
                    .parEach(function (localeId) {
                        var callback2 = this,
                            localizedHTML = this.vars[localeId],
                            document = localizedHTML.parseTree;
                        document.documentElement.setAttribute('lang', localeId);
                        assetGraph.markAssetDirty(localizedHTML);
                        i18nTools.extractAllKeysForLocaleFromHTMLAsset(assetGraph, localeId, localizedHTML, error.passToFunction(callback2, function (allKeys) {
                            seq.ap(assetGraph.findRelations({type: 'HTMLScript', from: localizedHTML}))
                                .parMap(function (htmlScript) {
                                    if (htmlScript.id in nonInlineJavaScriptsToCloneById) {
                                        assetGraph.cloneAsset(htmlScript.to, [htmlScript], this);
                                    } else {
                                        this(null, htmlScript.to);
                                    }
                                })
                                .parEach(function (javaScript) {
                                    javaScript.getParseTree(this);
                                })
                                .parEach(function (javaScript) {
                                    i18nTools.eachOneTrInAST(javaScript.parseTree, i18nTools.createOneTrReplacer(allKeys, localeId));
                                    assetGraph.markAssetDirty(javaScript);
                                    this();
                                })
                                .seq(function () {
                                    callback2();
                                })
                                ['catch'](callback2);
                        }));
                    })
                    .seq(function () {
                        // Remove the original HTML and those of the cloned JavaScript assets that become orphaned:
                        assetGraph.removeAsset(originalHTMLAsset);
                        _.values(nonInlineJavaScriptsToCloneById).forEach(function (javaScript) {
                            if (assetGraph.findRelations({to: javaScript}).length === 0) {
                                assetGraph.removeAsset(javaScript);
                            }
                        });
                        callback();
                    })
                    ['catch'](callback);
            })
            .seq(function () {
                cb();
            })
            ['catch'](cb);
    };
};
<|endoftext|>


<commit_before>define(["avalon"], function(avalon) {
    var defaults = {
        ghosting: false, //是否影子拖动，动态生成一个元素，拖动此元素，当拖动结束时，让原元素到达此元素的位置上,
        delay: 0,
        axis: "xy",
        started: true,
        start: avalon.noop,
        beforeStart: avalon.noop,
        drag: avalon.noop,
        beforeStop: avalon.noop,
        stop: avalon.noop,
        scrollPlugin: true,
        scrollSensitivity: 20,
        scrollSpeed: 20
    }
    var body
    var ua = navigator.userAgent;
    var isAndroid = /Android/i.test(ua);
    var isBlackBerry = /BlackBerry/i.test(ua)
    var isWindowPhone = /IEMobile/i.test(ua)
    var isIOS = /iPhone|iPad|iPod/i.test(ua)
    var isMobile = isAndroid || isBlackBerry || isWindowPhone || isIOS
    if (!isMobile) {
        var dragstart = "mousedown"
        var drag = "mousemove"
        var dragstop = "mouseup"
    } else {
        dragstart = "touchstart"
        drag = "touchmove"
        dragstop = "touchend"
    }

    var draggable = avalon.bindingHandlers.draggable = function(data, vmodels) {
        var fnName = data.value.trim(), completeCallback, model
        for (var i = 0, vm; vm = vmodels[i++]; ) {
            if (vm.hasOwnProperty(fnName)) {//根据函数名找到对应的VM的$model
                if (typeof vm[fnName] === "function") {
                    completeCallback = vm[fnName]
                    model = vm.$model
                    break;
                }
            }
        }
        if (typeof completeCallback !== "function") {
            throw "此绑定的格式为： ms-draggable-optsName?=fn"
        }
        var optsName = data.param, opts
        if (/\w/.test(optsName)) {//根据ID找到对应的VM的$model
            if (model && typeof model[optsName] === "object") {
                opts = model[optsName]
            } else {
                for (var i = 0, vm; vm = vmodels[i++]; ) {
                    var object = vm.$model
                    if (object && typeof object[optsName] === "object") {
                        opts = object[optsName]
                        break;
                    }
                }
            }
        }

        opts = opts || model

        var element = data.element
        var $element = avalon(element)
        var options = avalon.mix({}, defaults, opts, $element.data());
        if (completeCallback) {
            options.stop = completeCallback
        }

        //修正drag,stop为函数
        "drag,stop,start,beforeStart,beforeStop".replace(avalon.rword, function(name) {
            var method = options[name]
            if (typeof method === "string") {
                if (typeof opts[method] === "function") {
                    options[name] = opts[method]
                } else {
                    options[name] = avalon.noop
                }
            }
        })
        if (options.axis !== "" && !/^(x|y|xy)$/.test(options.axis)) {
            options.axis = "xy"
        }
        body = document.body //因为到这里时，肯定已经domReady
        $element.bind(dragstart, function(e) {
            var data = avalon.mix({}, options, {
                element: element,
                $element: $element,
                pageX: getPosition(e, "X"), //相对于页面的坐标, 会改动
                pageY: getPosition(e, "Y"), //相对于页面的坐标，会改动
                marginLeft: parseFloat($element.css("marginLeft")),
                marginTop: parseFloat($element.css("marginTop"))
            })

            data.startPageX = data.pageX//一次拖放只赋值一次
            data.startPageY = data.pageY//一次拖放只赋值一次
            options.axis.toUpperCase().replace(/./g, function(x) {
                if (data["drag" + x] === void 0) {
                    data["drag" + x ] = true
                }
            })

            fixUserSelect()
            //在处理手柄拖动前做些事情

               //在处理手柄拖动前做些事情
            if (typeof options.beforeStart === "function") {
                options.beforeStart.call(data.element, e, data)
            }

            if (data.handle && model) {// 实现手柄拖动
                var handle = model[data.handle]
                if (typeof handle === "function") {
                    var checked = handle.call(element, e, data)//要求返回一节点
                    if (checked && checked.nodeType === 1) {
                        if (!element.contains(checked)) {
                            return false
                        }
                    } else {
                        return false
                    }
                }
            }

            var position = $element.css("position")
            //如果原元素没有被定位
            if (!/^(?:r|a|f)/.test(position)) {
                element.style.position = "relative";
                element.style.top = "0px"
                element.style.left = "0px"
            }

            if (options.delay && isFinite(options.delay)) {
                data.started = false;
                setTimeout(function() {
                    data.started = true
                }, options.delay)
            }
            var startOffset = $element.offset()
            if (options.ghosting) {
                var clone = element.cloneNode(true)

                avalon(clone).css("opacity", .5).width(element.offsetWidth).height(element.offsetHeight)

                data.clone = clone
                if (position !== "fixed") {
                    clone.style.position = "absolute"
                    clone.style.top = startOffset.top - data.marginTop + "px"
                    clone.style.left = startOffset.left - data.marginLeft + "px"
                }
                body.appendChild(clone)
            }
            var activeElement = document.activeElement
            if (activeElement && activeElement !== element) {
                activeElement.blur()
            }
            var target = avalon(data.clone || data.element)
            //拖动前相对于offsetParent的坐标
            data.startLeft = target.css("left", true)
            data.startTop = target.css("top", true)
            //拖动后相对于offsetParent的坐标
            //如果是影子拖动，代理元素是绝对定位时，它与原元素的top, left是不一致的，因此当结束拖放时，不能直接将改变量赋给原元素
            data.endLeft = $element.css("left", true) - data.startLeft
            data.endTop = $element.css("top", true) - data.startTop

            data.clickX = data.pageX - startOffset.left //鼠标点击的位置与目标元素左上角的距离
            data.clickY = data.pageY - startOffset.top //鼠标点击的位置与目标元素左上角的距离
            setContainment(options, data)//修正containment
            draggable.dragData = data//决定有东西在拖动
            "start,drag,beforeStop,stop".replace(avalon.rword, function(name) {
                draggable[name].unshift(options[name])
            })

            draggable.plugin.call("start", e, data)
        })

    }
    var xy2prop = {
        "X": "Left",
        "Y": "Top"
    }
    //插件系统
    draggable.start = []
    draggable.drag = []
    draggable.stop = []
    draggable.beforeStop = []
    draggable.plugin = {
        add: function(name, set) {
            for (var i in set) {
                var fn = set[i]
                if (typeof fn === "function" && Array.isArray(draggable[i])) {
                    fn.isPlugin = true
                    fn.pluginName = name + "Plugin"
                    draggable[i].push(fn)
                }
            }
        },
        call: function(name, e, data) {
            var array = draggable[name]
            if (Array.isArray(array)) {
                array.forEach(function(fn) {
                    //用户回调总会执行，插件要看情况
                    if (typeof fn.pluginName === "undefined" ? true : data[fn.pluginName]) {
                        fn.call(data.element, e, data)
                    }
                })
            }
            if (name === "stop") {
                for (var i in draggable) {
                    array = draggable[i]
                    if (Array.isArray(array)) {
                        array.forEach(function(fn) {
                            if (!fn.isPlugin) {// 用户回调都是一次性的，插件的方法永远放在列队中
                                avalon.Array.remove(array, fn)
                            }
                        })
                    }
                }
            }
        }
    }

    function getPosition(e, pos) {
        var page = "page" + pos
        return isMobile ? e.changedTouches[0][page] : e[page]
    }

    function setPosition(e, element, data, pos, end) {
        var page = getPosition(e, pos)
        if (data.containment) {
            var min = pos === "X" ? data.containment[0] : data.containment[1]
            var max = pos === "X" ? data.containment[2] : data.containment[3]
            var check = page - (pos === "X" ? data.clickX : data.clickY)
            if (check < min) {
                page += Math.abs(min - check)
            } else if (check > max) {
                page -= Math.abs(max - check)
            }
        }
        data["page" + pos] = page//重设pageX, pageY
        var Prop = xy2prop[pos]
        var prop = Prop.toLowerCase()

        var number = data["start" + Prop] + page - data["startPage" + pos] + (end ? data["end" + Prop] : 0)

        data[prop] = number
        if (data["drag" + pos]) {//保存top, left
            element.style[ prop ] = number + "px"
        }
    }

    var styleEl = document.createElement("style")

    var cssText = "*{ -webkit-touch-callout: none!important;-webkit-user-select: none!important;-khtml-user-select: none!important;" +
            "-moz-user-select: none!important;-ms-user-select: none!important;user-select: none!important;}"
    function fixUserSelect() {
        body.appendChild(styleEl)
        //如果不插入DOM树，styleEl.styleSheet为null
        if (typeof styleEl.styleSheet === "object") {
            styleEl.styleSheet.cssText = cssText
        } else {
            styleEl.appendChild(document.createTextNode(cssText))
        }
    }
    function restoreUserSelect() {
        if (!styleEl.styleSheet) {
            styleEl.innerText = ""
            styleEl.removeChild(styleEl.firstChild)
        }
        body.removeChild(styleEl)
    }
    if (window.VBArray && !("msUserSelect" in document.documentElement.style)) {
        var _ieSelectBack;//fix IE6789
        function returnFalse() {
            return false;
        }
        function fixUserSelect() {
            _ieSelectBack = body.onselectstart;
            body.onselectstart = returnFalse;
        }
        function restoreUserSelect() {
            body.onselectstart = _ieSelectBack;
        }
    }
    //统一处理拖动的事件
    avalon(document).bind(drag, function(e) {
        var data = draggable.dragData
        if (!data || !data.started)
            return
        //fix touchmove bug;
        //IE 在 img 上拖动时默认不能拖动（不触发 mousemove，mouseup 事件，mouseup 后接着触发 mousemove ...）
        //防止 html5 draggable 元素的拖放默认行为 (选中文字拖放)
        e.preventDefault();
        //使用document.selection.empty()来清除选择，会导致捕获失败
        var element = data.clone || data.element

        setPosition(e, element, data, "X")
        setPosition(e, element, data, "Y")

        draggable.plugin.call("drag", e, data)
    })

    //统一处理拖动结束的事件
    avalon(document).bind(dragstop, function(e) {
        var data = draggable.dragData
        if (!data || !data.started)
            return
        restoreUserSelect()
        var element = data.element
        draggable.plugin.call("beforeStop", e, data)

        setPosition(e, element, data, "X", true)

        setPosition(e, element, data, "Y", true)

        if (data.clone) {
            body.removeChild(data.clone)
        }
        draggable.plugin.call("stop", e, data)
        delete draggable.dragData
    })

    function getWindow(node) {
        return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false;
    }
    function setContainment(o, data) {
        if (!o.containment) {
            if (Array.isArray(data.containment)) {
                return
            }
            data.containment = null;
            return;
        }

        if (o.containment === "window") {
            var $window = avalon(window)
            data.containment = [
                $window.scrollLeft(),
                $window.scrollTop(),
                $window.scrollLeft() + $window.width() - data.marginLeft,
                $window.scrollTop() + $window.height() - data.marginTop
            ];
            return;
        }

        if (o.containment === "document") {
            data.containment = [
                0,
                0,
                avalon(document).width() - data.marginLeft,
                avalon(document).height() - data.marginTop
            ];
            return;
        }

        if (Array.isArray(o.containment)) {
            data.containment = o.containment;
            return;
        }

        if (o.containment === "parent" || o.containment.charAt(0) === "#") {
            var elem
            if (o.containment === "parent") {
                elem = data.element.parentNode;
            } else {
                elem = document.getElementById(o.containment.slice(1))
            }
            if (elem) {
                var $offset = avalon(elem).offset()
                data.containment = [
                    $offset.left,
                    $offset.top,
                    Math.floor($offset.left + elem.offsetWidth - data.marginLeft - data.$element.width()),
                    Math.floor($offset.top + elem.offsetHeight - data.marginTop - data.$element.height())
                ]

            }
        }
    }

    return avalon
})
/*
 ms-draggable-xxx-fn , xxx为一个VM的对象属性, fn为一个函数， fn不能删略，xxx可省
 下面这些全部可用data-*进行配置
 drag 为VM中一个方法名
 stop 为VM中一个方法名
 start  为VM中一个方法名
 handle  要求为VM中的一个函数，它会重置data.handle为一个元素节点，如果事件源位于data.handle的里面或等于它则继续进行操作
 ghosting: false, //是否影子拖动，动态生成一个元素，拖动此元素，当拖动结束时，让原元素到达此元素的位置上,
 delay: 0, 延迟时间
 axis: "xy" "x", "y" 决定只能垂直拖动，还是水平拖动，还是任意拖动
 containment： 拖动范围，#id值， "window", "document", "parent", "[0, 0, 400, 300]"

item {{$index}}

 avalon.require("avalon.draggable", function() {
 avalon.define("xxx", function(vm) {
 vm.array = avalon.range(0, 10)
 vm.complete = function() {
 console.log("done")
 }
 vm.drag = function(e) {
 console.log(e.pageX + " : " + e.pageY)
 }
 })
 avalon.scan()
 })
 *
 */<commit_msg>update draggable<commit_after>define(["avalon"], function(avalon) {
    var defaults = {
        ghosting: false, //是否影子拖动，动态生成一个元素，拖动此元素，当拖动结束时，让原元素到达此元素的位置上,
        delay: 0,
        axis: "xy",
        started: true,
        start: avalon.noop,
        beforeStart: avalon.noop,
        drag: avalon.noop,
        beforeStop: avalon.noop,
        stop: avalon.noop,
        scrollPlugin: true,
        scrollSensitivity: 20,
        scrollSpeed: 20
    }
    var body
    var ua = navigator.userAgent;
    var isAndroid = /Android/i.test(ua);
    var isBlackBerry = /BlackBerry/i.test(ua)
    var isWindowPhone = /IEMobile/i.test(ua)
    var isIOS = /iPhone|iPad|iPod/i.test(ua)
    var isMobile = isAndroid || isBlackBerry || isWindowPhone || isIOS
    if (!isMobile) {
        var dragstart = "mousedown"
        var drag = "mousemove"
        var dragstop = "mouseup"
    } else {
        dragstart = "touchstart"
        drag = "touchmove"
        dragstop = "touchend"
    }

    var draggable = avalon.bindingHandlers.draggable = function(data, vmodels) {
        var fnName = data.value.trim(), completeCallback, model
        for (var i = 0, vm; vm = vmodels[i++]; ) {
            if (vm.hasOwnProperty(fnName)) {//根据函数名找到对应的VM的$model
                if (typeof vm[fnName] === "function") {
                    completeCallback = vm[fnName]
                    model = vm.$model
                    break;
                }
            }
        }
        if (typeof completeCallback !== "function") {
            throw "此绑定的格式为： ms-draggable-optsName?=fn"
        }
        var optsName = data.param, opts
        if (/\w/.test(optsName)) {//根据ID找到对应的VM的$model
            if (model && typeof model[optsName] === "object") {
                opts = model[optsName]
            } else {
                for (var i = 0, vm; vm = vmodels[i++]; ) {
                    var object = vm.$model
                    if (object && typeof object[optsName] === "object") {
                        opts = object[optsName]
                        break;
                    }
                }
            }
        }

        opts = opts || model

        var element = data.element
        var $element = avalon(element)
        var options = avalon.mix({}, defaults, opts, $element.data());
        if (completeCallback) {
            options.stop = completeCallback
        }

        //修正drag,stop为函数
        "drag,stop,start,beforeStart,beforeStop".replace(avalon.rword, function(name) {
            var method = options[name]
            if (typeof method === "string") {
                if (typeof opts[method] === "function") {
                    options[name] = opts[method]
                } else {
                    options[name] = avalon.noop
                }
            }
        })
        if (options.axis !== "" && !/^(x|y|xy)$/.test(options.axis)) {
            options.axis = "xy"
        }
        body = document.body //因为到这里时，肯定已经domReady
        $element.bind(dragstart, function(e) {
            var data = avalon.mix({}, options, {
                element: element,
                $element: $element,
                pageX: getPosition(e, "X"), //相对于页面的坐标, 会改动
                pageY: getPosition(e, "Y"), //相对于页面的坐标，会改动
                marginLeft: parseFloat($element.css("marginLeft")),
                marginTop: parseFloat($element.css("marginTop"))
            })

            data.startPageX = data.pageX//一次拖放只赋值一次
            data.startPageY = data.pageY//一次拖放只赋值一次
            options.axis.toUpperCase().replace(/./g, function(x) {
                if (data["drag" + x] === void 0) {
                    data["drag" + x ] = true
                }
            })

            fixUserSelect()
            //在处理手柄拖动前做些事情

            //在处理手柄拖动前做些事情
            if (typeof options.beforeStart === "function") {
                options.beforeStart.call(data.element, e, data)
            }

            if (data.handle && model) {// 实现手柄拖动
                var handle = model[data.handle]
                if (typeof handle === "function") {
                    var checked = handle.call(element, e, data)//要求返回一节点
                    if (checked && checked.nodeType === 1) {
                        if (!element.contains(checked)) {
                            return false
                        }
                    } else {
                        return false
                    }
                }
            }

            var position = $element.css("position")
            //如果原元素没有被定位
            if (!/^(?:r|a|f)/.test(position)) {
                element.style.position = "relative";
                element.style.top = "0px"
                element.style.left = "0px"
            }

            if (options.delay && isFinite(options.delay)) {
                data.started = false;
                setTimeout(function() {
                    data.started = true
                }, options.delay)
            }
            var startOffset = $element.offset()
            if (options.ghosting) {
                var clone = element.cloneNode(true)

                avalon(clone).css("opacity", .5).width(element.offsetWidth).height(element.offsetHeight)

                data.clone = clone
                if (position !== "fixed") {
                    clone.style.position = "absolute"
                    clone.style.top = startOffset.top - data.marginTop + "px"
                    clone.style.left = startOffset.left - data.marginLeft + "px"
                }
                body.appendChild(clone)
            }
            var activeElement = document.activeElement
            if (activeElement && activeElement !== element) {
                activeElement.blur()
            }
            var target = avalon(data.clone || data.element)
            //拖动前相对于offsetParent的坐标
            data.startLeft = target.css("left", true)
            data.startTop = target.css("top", true)
            // target.css("pointer-events","none")
            //拖动后相对于offsetParent的坐标
            //如果是影子拖动，代理元素是绝对定位时，它与原元素的top, left是不一致的，因此当结束拖放时，不能直接将改变量赋给原元素
            data.endLeft = $element.css("left", true) - data.startLeft
            data.endTop = $element.css("top", true) - data.startTop

            data.clickX = data.pageX - startOffset.left //鼠标点击的位置与目标元素左上角的距离
            data.clickY = data.pageY - startOffset.top //鼠标点击的位置与目标元素左上角的距离
            setContainment(options, data)//修正containment
            draggable.dragData = data//决定有东西在拖动
            "start,drag,beforeStop,stop".replace(avalon.rword, function(name) {
                draggable[name].unshift(options[name])
            })

            draggable.plugin.call("start", e, data)
        })

    }
    var xy2prop = {
        "X": "Left",
        "Y": "Top"
    }
    //插件系统
    draggable.start = []
    draggable.drag = []
    draggable.stop = []
    draggable.beforeStop = []
    draggable.plugin = {
        add: function(name, set) {
            for (var i in set) {
                var fn = set[i]
                if (typeof fn === "function" && Array.isArray(draggable[i])) {
                    fn.isPlugin = true
                    fn.pluginName = name + "Plugin"
                    draggable[i].push(fn)
                }
            }
        },
        call: function(name, e, data) {
            var array = draggable[name]
            if (Array.isArray(array)) {
                array.forEach(function(fn) {
                    //用户回调总会执行，插件要看情况
                    if (typeof fn.pluginName === "undefined" ? true : data[fn.pluginName]) {
                        fn.call(data.element, e, data)
                    }
                })
            }
            if (name === "stop") {
                for (var i in draggable) {
                    array = draggable[i]
                    if (Array.isArray(array)) {
                        array.forEach(function(fn) {
                            if (!fn.isPlugin) {// 用户回调都是一次性的，插件的方法永远放在列队中
                                avalon.Array.remove(array, fn)
                            }
                        })
                    }
                }
            }
        }
    }

    function getPosition(e, pos) {
        var page = "page" + pos
        return isMobile ? e.changedTouches[0][page] : e[page]
    }

    function setPosition(e, element, data, pos, end) {
        var page = getPosition(e, pos)
        if (data.containment) {
            var min = pos === "X" ? data.containment[0] : data.containment[1]
            var max = pos === "X" ? data.containment[2] : data.containment[3]
            var check = page - (pos === "X" ? data.clickX : data.clickY)
            if (check < min) {
                page += Math.abs(min - check)
            } else if (check > max) {
                page -= Math.abs(max - check)
            }
        }
        data["page" + pos] = page//重设pageX, pageY
        var Prop = xy2prop[pos]
        var prop = Prop.toLowerCase()

        var number = data["start" + Prop] + page - data["startPage" + pos] + (end ? data["end" + Prop] : 0)

        data[prop] = number
        if (data["drag" + pos]) {//保存top, left
            element.style[ prop ] = number + "px"
        }
    }

    var styleEl = document.createElement("style")

    var cssText = "*{ -webkit-touch-callout: none!important;-webkit-user-select: none!important;-khtml-user-select: none!important;" +
            "-moz-user-select: none!important;-ms-user-select: none!important;user-select: none!important;}"
    function fixUserSelect() {
        body.appendChild(styleEl)
        //如果不插入DOM树，styleEl.styleSheet为null
        if (typeof styleEl.styleSheet === "object") {
            styleEl.styleSheet.cssText = cssText
        } else {
            styleEl.appendChild(document.createTextNode(cssText))
        }
    }
    function restoreUserSelect() {
        if (!styleEl.styleSheet) {
            styleEl.innerHTML = ""
            try {
                styleEl.removeChild(styleEl.firstChild)
            } catch (e) {
            }
        }
        body.removeChild(styleEl)
    }
    if (window.VBArray && !("msUserSelect" in document.documentElement.style)) {
        var _ieSelectBack;//fix IE6789
        function returnFalse() {
            return false;
        }
        function fixUserSelect() {
            _ieSelectBack = body.onselectstart;
            body.onselectstart = returnFalse;
        }
        function restoreUserSelect() {
            body.onselectstart = _ieSelectBack;
        }
    }
    //统一处理拖动的事件
    avalon(document).bind(drag, function(e) {
        var data = draggable.dragData
        if (!data || !data.started)
            return
        //fix touchmove bug;
        //IE 在 img 上拖动时默认不能拖动（不触发 mousemove，mouseup 事件，mouseup 后接着触发 mousemove ...）
        //防止 html5 draggable 元素的拖放默认行为 (选中文字拖放)
        e.preventDefault();
        //使用document.selection.empty()来清除选择，会导致捕获失败
        var element = data.clone || data.element

        setPosition(e, element, data, "X")
        setPosition(e, element, data, "Y")

        draggable.plugin.call("drag", e, data)
    })

    //统一处理拖动结束的事件
    avalon(document).bind(dragstop, function(e) {
        var data = draggable.dragData
        if (!data || !data.started)
            return
        restoreUserSelect()
        var element = data.element
        draggable.plugin.call("beforeStop", e, data)

        setPosition(e, element, data, "X", true)

        setPosition(e, element, data, "Y", true)

        if (data.clone) {
            body.removeChild(data.clone)
        }
        draggable.plugin.call("stop", e, data)
        delete draggable.dragData
    })

    function getWindow(node) {
        return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false;
    }
    function setContainment(o, data) {
        if (!o.containment) {
            if (Array.isArray(data.containment)) {
                return
            }
            data.containment = null;
            return;
        }

        if (o.containment === "window") {
            var $window = avalon(window)
            data.containment = [
                $window.scrollLeft(),
                $window.scrollTop(),
                $window.scrollLeft() + $window.width() - data.marginLeft,
                $window.scrollTop() + $window.height() - data.marginTop
            ];
            return;
        }

        if (o.containment === "document") {
            data.containment = [
                0,
                0,
                avalon(document).width() - data.marginLeft,
                avalon(document).height() - data.marginTop
            ];
            return;
        }

        if (Array.isArray(o.containment)) {
            data.containment = o.containment;
            return;
        }

        if (o.containment === "parent" || o.containment.charAt(0) === "#") {
            var elem
            if (o.containment === "parent") {
                elem = data.element.parentNode;
            } else {
                elem = document.getElementById(o.containment.slice(1))
            }
            if (elem) {
                var $offset = avalon(elem).offset()
                data.containment = [
                    $offset.left,
                    $offset.top,
                    Math.floor($offset.left + elem.offsetWidth - data.marginLeft - data.$element.width()),
                    Math.floor($offset.top + elem.offsetHeight - data.marginTop - data.$element.height())
                ]

            }
        }
    }

    return avalon
})
/*
 ms-draggable-xxx-fn , xxx为一个VM的对象属性, fn为一个函数， fn不能删略，xxx可省
 下面这些全部可用data-*进行配置
 drag 为VM中一个方法名
 stop 为VM中一个方法名
 start  为VM中一个方法名
 handle  要求为VM中的一个函数，它会重置data.handle为一个元素节点，如果事件源位于data.handle的里面或等于它则继续进行操作
 ghosting: false, //是否影子拖动，动态生成一个元素，拖动此元素，当拖动结束时，让原元素到达此元素的位置上,
 delay: 0, 延迟时间
 axis: "xy" "x", "y" 决定只能垂直拖动，还是水平拖动，还是任意拖动
 containment： 拖动范围，#id值， "window", "document", "parent", "[0, 0, 400, 300]"

item {{$index}}

 avalon.require("avalon.draggable", function() {
 avalon.define("xxx", function(vm) {
 vm.array = avalon.range(0, 10)
 vm.complete = function() {
 console.log("done")
 }
 vm.drag = function(e) {
 console.log(e.pageX + " : " + e.pageY)
 }
 })
 avalon.scan()
 })
 *
 */<|endoftext|>


<commit_before>var Simulation = {
    initialize : function() {
        // Init rotors
        Rotors.initialize(['A', 'A', 'A']);

        // Init display
        Display.initialize();
        Display.update();
    },
};

var Display = {
    initialize : function() {
        this.rotor_disp = [];

        // Function to call when rotor up or down clicked
        var adjust_rotor = function(event) {
            var rtr = event.target.parentNode.id.charAt(6) - 1;
            Rotors.change_init_pos(rtr, (event.target.className == "up") ? -1 : 1);
            Display.update();
        }

        // Create rotor display
        for (var i = 1; i < 4; i++) {

            // Create rotor div
            var parent_d = document.createElement("div");
            parent_d.className = "rotor";
            parent_d.id = "rotor_" + i;
            document.getElementById("rotor_pane").appendChild(parent_d);

            // Create up arrow
            var up_d = document.createElement("div");
            up_d.innerHTML = '↑';
            up_d.className = "up";
            up_d.onclick = adjust_rotor;
            parent_d.appendChild(up_d);

            // Create rotor disp
            var rotor_d = document.createElement("div");
            this.rotor_disp[i - 1] = rotor_d;
            parent_d.appendChild(rotor_d);

            // Create down arrow
            var down_d = document.createElement("div");
            down_d.innerHTML = '↓';
            down_d.className = "down";
            down_d.onclick = adjust_rotor;
            parent_d.appendChild(down_d);
        }
    },

    update : function() {
        // Update rotor letters
        for (var i = 0; i < 3; i++)
            this.rotor_disp[i].innerHTML = Rotors.get_rts()[i];
    }
};

var Rotors = {
    initialize : function(init_pos) {
        // Init rotors
        this.rts = [init_pos[0], init_pos[1], init_pos[2]];
    },

    change_init_pos : function(rtr, change_by) {
        // Set rotor
        if (change_by == 1 && this.rts[rtr] == 'Z')
            this.update(rtr, 'A')
        else if (change_by == -1 && this.rts[rtr] == 'A')
            this.update(rtr, 'Z');
        else
            this.update(rtr, String.fromCharCode(this.rts[rtr].charCodeAt()
                        + change_by));
    },

    update : function(rtr, new_value) {
        // Update value
        this.rts[rtr] = new_value;
    },

    get_rts() {
        return this.rts;
    }
};
<commit_msg>Major refactor<commit_after>var Simulation = {
    initialize : function() {
        // Init rotors
        this.rotors = [];
        for (var i = 0; i < 3; i++) {
            this.rotors[i] = new Rotor();
        }

        // Init display
        Display.initialize();
        Display.update();
    },

    rotor_set_listener : function(event) {
        // Function to call when rotor up or down clicked
        var rtr = event.target.parentNode.id.charAt(6) - 1;
        Simulation.rotors[rtr].change_init_pos((event.target.className == "up") ? -1 : 1);
        Display.update();
    }
};

var Display = {
    initialize : function() {
        this.rotor_disp = [];

        // Create rotor display
        for (var i = 1; i < 4; i++) {

            // Create rotor div
            var parent_d = document.createElement("div");
            parent_d.className = "rotor";
            parent_d.id = "rotor_" + i;
            document.getElementById("rotor_pane").appendChild(parent_d);

            // Create up arrow
            var up_d = document.createElement("div");
            up_d.innerHTML = '↑';
            up_d.className = "up";
            up_d.onclick = Simulation.rotor_set_listener;
            parent_d.appendChild(up_d);

            // Create rotor disp
            var rotor_d = document.createElement("div");
            this.rotor_disp[i - 1] = rotor_d;
            parent_d.appendChild(rotor_d);

            // Create down arrow
            var down_d = document.createElement("div");
            down_d.innerHTML = '↓';
            down_d.className = "down";
            down_d.onclick = Simulation.rotor_set_listener;
            parent_d.appendChild(down_d);
        }
    },

    update : function() {
        // Update rotor letters
        for (var i = 0; i < 3; i++)
            this.rotor_disp[i].innerHTML = Simulation.rotors[i].pos;
    }
};

function Rotor() {
    // Rotor position
    this.pos = 'A';

    this.change_init_pos = function(change_by) {
        // Set rotor starting position
        if (change_by == 1 && this.pos == 'Z')
            this.pos = 'A';
        else if (change_by == -1 && this.pos == 'A')
            this.pos = 'Z';
        else
            this.pos = String.fromCharCode(this.pos.charCodeAt() + change_by);
    };
}
<|endoftext|>


<commit_before>define(
  'ephox.alloy.dom.DomRender',

  [
    'ephox.alloy.dom.DomDefinition',
    'ephox.compass.Arr',
    'ephox.peanut.Fun',
    'ephox.sugar.api.Attr',
    'ephox.sugar.api.Classes',
    'ephox.sugar.api.Css',
    'ephox.sugar.api.Element',
    'ephox.sugar.api.Html',
    'ephox.sugar.api.InsertAll',
    'ephox.sugar.api.Value',
    'global!Error'
  ],

  function (DomDefinition, Arr, Fun, Attr, Classes, Css, Element, Html, InsertAll, Value, Error) {
    var getChildren = function (definition) {
      return definition.domChildren().fold(function () {
        var defChildren = definition.defChildren().getOr([ ]);
        return Arr.map(defChildren, renderDef);
      }, function (domChildren) {
        return definition.defChildren().fold(Fun.constant(domChildren), function (defChildren) {
          throw new Error('Cannot specify children and child specs! Must be one or the other.\nDef: ' + DomDefinition.defToStr(definition));
        });
      });
    };

    var renderToDom = function (definition) {
      var subject = Element.fromTag(definition.tag());
      Classes.add(subject, definition.classes().getOr([ ]));
      Attr.setAll(subject, definition.attributes().getOr({ }));
      Css.setAll(subject, definition.styles().getOr({ }));
      // Remember: Order of innerHtml vs children is important.
      Html.set(subject, definition.innerHtml().getOr(''));

      // Children are already elements.
      var children = getChildren(definition);
      InsertAll.append(subject, children);

      definition.value().each(function (value) {
        Value.set(subject, value);
      });

      return subject;
    };

    var renderDef = function (spec) {
      var definition = DomDefinition.nu(spec);
      return renderToDom(definition);
    };

    return {
      renderToDom: renderToDom
    };
  }
);<commit_msg>VAN-1: cleaned up nested folds<commit_after>define(
  'ephox.alloy.dom.DomRender',

  [
    'ephox.alloy.dom.DomDefinition',
    'ephox.compass.Arr',
    'ephox.peanut.Fun',
    'ephox.sugar.api.Attr',
    'ephox.sugar.api.Classes',
    'ephox.sugar.api.Css',
    'ephox.sugar.api.Element',
    'ephox.sugar.api.Html',
    'ephox.sugar.api.InsertAll',
    'ephox.sugar.api.Value',
    'global!Error'
  ],

  function (DomDefinition, Arr, Fun, Attr, Classes, Css, Element, Html, InsertAll, Value, Error) {
    var getChildren = function (definition) {
      if (definition.domChildren().isSome() && definition.defChildren().isSome()) {
        throw new Error('Cannot specify children and child specs! Must be one or the other.\nDef: ' + DomDefinition.defToStr(definition));
      } else {
        return definition.domChildren().fold(function () {
          var defChildren = definition.defChildren().getOr([ ]);
          return Arr.map(defChildren, renderDef);
        }, function (domChildren) {
          return domChildren;
        });
      }
    };

    var renderToDom = function (definition) {
      var subject = Element.fromTag(definition.tag());
      Classes.add(subject, definition.classes().getOr([ ]));
      Attr.setAll(subject, definition.attributes().getOr({ }));
      Css.setAll(subject, definition.styles().getOr({ }));
      // Remember: Order of innerHtml vs children is important.
      Html.set(subject, definition.innerHtml().getOr(''));

      // Children are already elements.
      var children = getChildren(definition);
      InsertAll.append(subject, children);

      definition.value().each(function (value) {
        Value.set(subject, value);
      });

      return subject;
    };

    var renderDef = function (spec) {
      var definition = DomDefinition.nu(spec);
      return renderToDom(definition);
    };

    return {
      renderToDom: renderToDom
    };
  }
);<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Dropdown from './Dropdown';
import { omit } from './utils';

const omitKeys = ['defaultOpen'];

export default class UncontrolledDropdown extends Component {
  constructor(props) {
    super(props);

    this.state = { isOpen: props.defaultOpen || false };
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    this.setState({ isOpen: !this.state.isOpen });
  }

  render() {
    return <Dropdown isOpen={this.state.isOpen} toggle={this.toggle} {...omit(this.props, omitKeys)} />;
  }
}

UncontrolledDropdown.propTypes = {
  defaultOpen: PropTypes.bool,
  ...Dropdown.propTypes
};
<commit_msg>feat(UncontrolledDropdown): add onToggle callback (#1705)<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Dropdown from './Dropdown';
import { omit } from './utils';

const omitKeys = ['defaultOpen'];

export default class UncontrolledDropdown extends Component {
  constructor(props) {
    super(props);

    this.state = { isOpen: props.defaultOpen || false };
    this.toggle = this.toggle.bind(this);
  }

  toggle(e) {
    this.setState({ isOpen: !this.state.isOpen });
    if (this.props.onToggle) {
      this.props.onToggle(e, !this.state.isOpen);
    }
  }

  render() {
    return <Dropdown isOpen={this.state.isOpen} toggle={this.toggle} {...omit(this.props, omitKeys)} />;
  }
}

UncontrolledDropdown.propTypes = {
  defaultOpen: PropTypes.bool,
  onToggle: PropTypes.func,
  ...Dropdown.propTypes
};
<|endoftext|>


<commit_before>import styled, { css } from 'styled-components'
import rem from 'polished/lib/helpers/rem'
import { mobile } from '../../utils/media'
import { violetRed, gold } from '../../utils/colors'
import captureScroll from '../CaptureScroll'

const Sidebar = styled.nav`
  position: fixed;
  display: block;
  z-index: 1;

  left: 0;
  top: 0;
  bottom: 0;
  right: auto;

  width: ${rem(300)};
  height: 100%;
  background: linear-gradient(20deg, ${violetRed}, ${gold});
  box-sizing: border-box;
  color: white;
  overflow-y: scroll;

  ${mobile(css`
    bottom: auto;
    right: 0;
    height: auto;
    width: 100%;
    overflow-y: visible;
  `)}
`

export default captureScroll(Sidebar)
<commit_msg>reduce repaints on fixed sidebar<commit_after>import styled, { css } from 'styled-components'
import rem from 'polished/lib/helpers/rem'
import { mobile } from '../../utils/media'
import { violetRed, gold } from '../../utils/colors'
import captureScroll from '../CaptureScroll'

const Sidebar = styled.nav`
  position: fixed;
  transform: translateZ(0);
  display: block;
  z-index: 1;

  left: 0;
  top: 0;
  bottom: 0;
  right: auto;

  width: ${rem(300)};
  height: 100%;
  background: linear-gradient(20deg, ${violetRed}, ${gold});
  box-sizing: border-box;
  color: white;
  overflow-y: scroll;

  ${mobile(css`
    bottom: auto;
    right: 0;
    height: auto;
    width: 100%;
    overflow-y: visible;
  `)}
`

export default captureScroll(Sidebar)
<|endoftext|>


<commit_before>/**
 * @class CM_Frontend_AbstractTrait
 */
var CM_Frontend_AbstractTrait = {

  /**
   * @inner
   * @mixin
   */
  traitProperties: {},

  /**
   * @param {Object} obj
   * @returns {Object}
   */
  applyImplementation: function(obj) {
    if (!_.isObject(obj)) {
      throw new Error('Trait must be applied to an Object.');
    }
    _.each(this.getTraitProperties(), function(traitPropertyName) {
      var property = this.getTraitProperty(traitPropertyName);
      if (!(traitPropertyName in obj)) {
        if (property === this.abstractMethod) {
          throw new Error(traitPropertyName + ' not implemented.');
        } else {
          obj[traitPropertyName] = property;
        }
      }
    }, this);
    return obj;
  },

  /**
   * @param {*} value
   * @returns {Boolean}
   */
  isImplementedBy: function(value) {
    if (_.isObject(value)) {
      var traitProperties = this.getTraitProperties();
      return _.every(traitProperties, function(traitProperty) {
        return traitProperty in value;
      });
    }
    return false;
  },

  /**
   * @returns {Array}
   */
  getTraitProperties: function() {
    return Object.getOwnPropertyNames(this.traitProperties);
  },

  /**
   * @param {String} name
   * @returns {*}
   */
  getTraitProperty: function(name) {
    return this.traitProperties[name];
  },

  abstractMethod: function() {
    throw new Error('Abstract method.');
  }
};

<commit_msg>Simplify CM_Frontend_AbstractTrait<commit_after>/**
 * @class CM_Frontend_AbstractTrait
 */
var CM_Frontend_AbstractTrait = {

  /**
   * @inner
   * @mixin
   */
  traitProperties: {},

  /**
   * @param {Object} obj
   * @returns {Object}
   */
  applyImplementation: function(obj) {
    if (!_.isObject(obj)) {
      throw new Error('Trait must be applied to an Object.');
    }
    var abstractMethod = this.abstractMethod;
    _.each(this.traitProperties, function(property, traitPropertyName) {
      if (!(traitPropertyName in obj)) {
        if (property === abstractMethod) {
          throw new Error(traitPropertyName + ' not implemented.');
        } else {
          obj[traitPropertyName] = property;
        }
      }
    });
    return obj;
  },

  /**
   * @param {*} value
   * @returns {Boolean}
   */
  isImplementedBy: function(value) {
    if (_.isObject(value)) {
      return _.every(this.traitProperties, function(property, traitPropertyName) {
        return traitPropertyName in value;
      });
    }
    return false;
  },

  abstractMethod: function() {
    throw new Error('Abstract method.');
  }
};

<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import Head from 'next/head';

const PageHead = ({ meta }) => (
  <Head>
    <title>{meta.title}</title>
    <meta type="description" content={meta.desc} />
  </Head>
);

PageHead.propTypes = {
  meta: PropTypes.shape({
    title: PropTypes.string.isRequired,
    desc: PropTypes.string.isRequired,
  }).isRequired,
};

export default PageHead;
<commit_msg>Fixed meta attribute<commit_after>import PropTypes from 'prop-types';
import Head from 'next/head';

const PageHead = ({ meta }) => (
  <Head>
    <title>{meta.title}</title>
    <meta name="description" content={meta.desc} />
  </Head>
);

PageHead.propTypes = {
  meta: PropTypes.shape({
    title: PropTypes.string.isRequired,
    desc: PropTypes.string.isRequired,
  }).isRequired,
};

export default PageHead;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Autobind } from 'es-decorators';
import { toastr } from 'react-redux-toastr';
import { Link, Router } from 'routes';

// Redux
import { connect } from 'react-redux';
import { toggleModal, setModalOptions } from 'redactions/modal';
import { toggleTooltip } from 'redactions/tooltip';

// Components
import Spinner from 'components/ui/Spinner';
import Map from 'components/vis/Map';
import AreaSubscriptionModal from 'components/modal/AreaSubscriptionModal';
import AreaActionsTooltip from 'components/areas/AreaActionsTooltip';

// Services
import DatasetService from 'services/DatasetService';
import AreasService from 'services/AreasService';
import UserService from 'services/UserService';

// Utils
import LayerManager from 'utils/layers/LayerManager';

const MAP_CONFIG = {
  zoom: 3,
  latLng: {
    lat: 0,
    lng: 0
  },
  zoomControl: false
};

class AreaCard extends React.Component {
  /**
   * Return the position of the click within the page taking
   * into account the scroll (relative to the page, not the
   * viewport )
   * @static
   * @param {MouseEvent} e Event
   * @returns {{ x: number, y: number }}
   */
  static getClickPosition(e) {
    return {
      x: window.scrollX + e.clientX,
      y: window.scrollY + e.clientY
    };
  }

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      country: null,
      layer: {}
    };

    // Services
    this.datasetService = new DatasetService(null,
      { apiURL: process.env.WRI_API_URL });
    this.areasService = new AreasService({ apiURL: process.env.WRI_API_URL });
    this.userService = new UserService({ apiURL: process.env.WRI_API_URL });
  }

  componentDidMount() {
    this.loadData();
  }

  loadData() {
    this.setState({ loading: true });
    const attsObj = this.props.area.attributes;

    if (attsObj.geostore) {
      this.areasService.getGeostore(attsObj.geostore)
        .then((res) => {
          const obj = res.data;
          const fakeLayer = {
            id: `${obj.id}`,
            provider: 'geojson',
            layerConfig: {
              data: obj.attributes.geojson,
              fitBounds: true,
              bounds: obj.attributes.bbox
            }
          };

          this.setState({
            loading: false,
            country: obj.id,
            layer: fakeLayer
          });
        });
    } else if (attsObj.iso.country) {
      this.areasService.getCountry(attsObj.iso.country)
        .then((res) => {
          const country = res.data[0];

          const newGeoJson = {
            type: 'FeatureCollection',
            features: [
              {
                type: 'Feature',
                properties: {},
                geometry: JSON.parse(country.geojson)
              }
            ]
          };

          const fakeLayer = {
            id: `-${country.label}`,
            provider: 'geojson',
            active: true,
            layerConfig: {
              data: newGeoJson,
              fitBounds: true,
              bounds: JSON.parse(country.bounds)
            }
          };

          this.setState({
            loading: false,
            country: country.label,
            layerGroups: [{
              dataset: null,
              visible: true,
              layers: [fakeLayer]
            }]
          });
        });
    }
  }

  @Autobind
  handleEditArea() {
    Router.pushRoute('myrw_detail', { id: this.props.area.id, tab: 'areas' });
  }

  @Autobind
  handleEditSubscription() {
    const mode = this.props.area.subscription ? 'edit' : 'new';
    const options = {
      children: AreaSubscriptionModal,
      childrenProps: {
        area: this.props.area,
        toggleModal: this.props.toggleModal,
        onSubscriptionUpdated: this.handleSubscriptionUpdated,
        onSubscriptionCreated: this.handleSubscriptionUpdated,
        mode
      }
    };
    this.props.toggleModal(true);
    this.props.setModalOptions(options);
  }

  @Autobind
  handleSubscriptionCreated() {
    this.props.onChange();
  }

  @Autobind
  handleSubscriptionUpdated() {
    this.props.onChange();
  }

  @Autobind
  handleDeleteArea() {
    const { area, token } = this.props;
    const toastrConfirmOptions = {
      onOk: () => {
        this.setState({ loading: true });

        // Delete subscription associated to area if there's one
        if (area.subscription) {
          this.userService.deleteSubscription(area.subscription.id, token)
            .then(() => {
              this.userService.deleteArea(area.id, token)
                .then(() => {
                  this.props.onAreaRemoved();
                })
                // Fetch throws an error for some reason but the request is successful...
                .catch(err => this.props.onAreaRemoved()); // eslint-disable-line
            })
            .catch((err) => {
              this.setState({ loading: false });
              toastr.error('Error removing area', err);
            });
        } else {
          this.userService.deleteArea(area.id, token)
            .then(() => {
              this.props.onAreaRemoved();
            })
            // Fetch throws an error for some reason but the request is successful...
            .catch(err => this.props.onAreaRemoved()); // eslint-disable-line
        }
      }
    };
    toastr.confirm(`Are you sure you want to delete the area ${area.attributes.name}?
      Deleting an area will delete all the subscriptions associated to it`, toastrConfirmOptions);
  }

  @Autobind
  handleEdit(event) {
    const position = AreaCard.getClickPosition(event);
    this.props.toggleTooltip(true, {
      follow: false,
      position,
      children: AreaActionsTooltip,
      childrenProps: {
        toggleTooltip: this.props.toggleTooltip,
        onEditArea: this.handleEditArea,
        onEditSubscriptions: this.handleEditSubscription
      }
    });
  }

  render() {
    const { loading, layerGroups } = this.state;
    const { area } = this.props;
    const name = area.attributes.name;
    const subscription = area.subscription;
    const subscriptionConfirmed = area.subscription && area.subscription.attributes.confirmed;

    const borderContainerClassNames = classnames({
      'border-container': true,
      'blue-background': subscription && !subscriptionConfirmed
    });

    return (

            <Map
              LayerManager={LayerManager}
              mapConfig={MAP_CONFIG}
              layerGroups={layerGroups || []}
              interactionEnabled={false}
              useLightBasemap
            />

          <Spinner isLoading={loading} className="-small -light -relative -center" />

{name}

              {subscription &&

                    {subscription.attributes.datasets.map((datasetObj, index) =>
                      (<div
                        className="dataset-element"
                        key={`${datasetObj}-${index}`} // eslint-disable-line
                      >

                          <Link
                            route={'explore_detail'}
                            params={{ id: datasetObj.id }}
                          >

                              {datasetObj.label}

                          </Link>

                          {subscription.attributes.datasetsQuery
                            .find(elem => elem.id === datasetObj.id).type}
                           (≥{subscription.attributes.datasetsQuery
                            .find(elem => elem.id === datasetObj.id).threshold})

)
                    )}

              }
              {subscription &&

                    {!subscriptionConfirmed &&

                      Pending

                    }

              }

              <button
                className="c-btn -b -compressed"
                onClick={this.handleEdit}
              >
                Edit
              </button>

                Delete

    );
  }
}

AreaCard.propTypes = {
  token: PropTypes.string.isRequired,
  area: PropTypes.object.isRequired,
  // Callbacks
  onAreaRemoved: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired,
  // Store
  toggleModal: PropTypes.func.isRequired,
  setModalOptions: PropTypes.func.isRequired,
  toggleTooltip: PropTypes.func.isRequired
};

const mapDispatchToProps = dispatch => ({
  toggleModal: (open, opts) => { dispatch(toggleModal(open, opts)); },
  setModalOptions: (options) => { dispatch(setModalOptions(options)); },
  toggleTooltip: (opened, opts) => {
    dispatch(toggleTooltip(opened, opts));
  }
});

export default connect(null, mapDispatchToProps)(AreaCard);
<commit_msg>remove code that has become obsolete<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Autobind } from 'es-decorators';
import { toastr } from 'react-redux-toastr';
import { Link, Router } from 'routes';

// Redux
import { connect } from 'react-redux';
import { toggleModal, setModalOptions } from 'redactions/modal';
import { toggleTooltip } from 'redactions/tooltip';

// Components
import Spinner from 'components/ui/Spinner';
import Map from 'components/vis/Map';
import AreaSubscriptionModal from 'components/modal/AreaSubscriptionModal';
import AreaActionsTooltip from 'components/areas/AreaActionsTooltip';

// Services
import DatasetService from 'services/DatasetService';
import AreasService from 'services/AreasService';
import UserService from 'services/UserService';

// Utils
import LayerManager from 'utils/layers/LayerManager';

const MAP_CONFIG = {
  zoom: 3,
  latLng: {
    lat: 0,
    lng: 0
  },
  zoomControl: false
};

class AreaCard extends React.Component {
  /**
   * Return the position of the click within the page taking
   * into account the scroll (relative to the page, not the
   * viewport )
   * @static
   * @param {MouseEvent} e Event
   * @returns {{ x: number, y: number }}
   */
  static getClickPosition(e) {
    return {
      x: window.scrollX + e.clientX,
      y: window.scrollY + e.clientY
    };
  }

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      country: null,
      layer: {}
    };

    // Services
    this.datasetService = new DatasetService(null,
      { apiURL: process.env.WRI_API_URL });
    this.areasService = new AreasService({ apiURL: process.env.WRI_API_URL });
    this.userService = new UserService({ apiURL: process.env.WRI_API_URL });
  }

  componentDidMount() {
    this.loadData();
  }

  loadData() {
    this.setState({ loading: true });
    const attsObj = this.props.area.attributes;

    if (attsObj.geostore) {
      this.areasService.getGeostore(attsObj.geostore)
        .then((res) => {
          const obj = res.data;
          const fakeLayer = {
            id: `${obj.id}`,
            provider: 'geojson',
            active: true,
            layerConfig: {
              data: obj.attributes.geojson,
              fitBounds: true,
              bounds: obj.attributes.bbox
            }
          };

          this.setState({
            loading: false,
            country: obj.id,
            layer: fakeLayer
          });
        });
    }
  }

  @Autobind
  handleEditArea() {
    Router.pushRoute('myrw_detail', { id: this.props.area.id, tab: 'areas' });
  }

  @Autobind
  handleEditSubscription() {
    const mode = this.props.area.subscription ? 'edit' : 'new';
    const options = {
      children: AreaSubscriptionModal,
      childrenProps: {
        area: this.props.area,
        toggleModal: this.props.toggleModal,
        onSubscriptionUpdated: this.handleSubscriptionUpdated,
        onSubscriptionCreated: this.handleSubscriptionUpdated,
        mode
      }
    };
    this.props.toggleModal(true);
    this.props.setModalOptions(options);
  }

  @Autobind
  handleSubscriptionCreated() {
    this.props.onChange();
  }

  @Autobind
  handleSubscriptionUpdated() {
    this.props.onChange();
  }

  @Autobind
  handleDeleteArea() {
    const { area, token } = this.props;
    const toastrConfirmOptions = {
      onOk: () => {
        this.setState({ loading: true });

        // Delete subscription associated to area if there's one
        if (area.subscription) {
          this.userService.deleteSubscription(area.subscription.id, token)
            .then(() => {
              this.userService.deleteArea(area.id, token)
                .then(() => {
                  this.props.onAreaRemoved();
                })
                // Fetch throws an error for some reason but the request is successful...
                .catch(err => this.props.onAreaRemoved()); // eslint-disable-line
            })
            .catch((err) => {
              this.setState({ loading: false });
              toastr.error('Error removing area', err);
            });
        } else {
          this.userService.deleteArea(area.id, token)
            .then(() => {
              this.props.onAreaRemoved();
            })
            // Fetch throws an error for some reason but the request is successful...
            .catch(err => this.props.onAreaRemoved()); // eslint-disable-line
        }
      }
    };
    toastr.confirm(`Are you sure you want to delete the area ${area.attributes.name}?
      Deleting an area will delete all the subscriptions associated to it`, toastrConfirmOptions);
  }

  @Autobind
  handleEdit(event) {
    const position = AreaCard.getClickPosition(event);
    this.props.toggleTooltip(true, {
      follow: false,
      position,
      children: AreaActionsTooltip,
      childrenProps: {
        toggleTooltip: this.props.toggleTooltip,
        onEditArea: this.handleEditArea,
        onEditSubscriptions: this.handleEditSubscription
      }
    });
  }

  render() {
    const { loading, layerGroups } = this.state;
    const { area } = this.props;
    const name = area.attributes.name;
    const subscription = area.subscription;
    const subscriptionConfirmed = area.subscription && area.subscription.attributes.confirmed;

    const borderContainerClassNames = classnames({
      'border-container': true,
      'blue-background': subscription && !subscriptionConfirmed
    });

    return (

            <Map
              LayerManager={LayerManager}
              mapConfig={MAP_CONFIG}
              layerGroups={layerGroups || []}
              interactionEnabled={false}
              useLightBasemap
            />

          <Spinner isLoading={loading} className="-small -light -relative -center" />

{name}

              {subscription &&

                    {subscription.attributes.datasets.map((datasetObj, index) =>
                      (<div
                        className="dataset-element"
                        key={`${datasetObj}-${index}`} // eslint-disable-line
                      >

                          <Link
                            route={'explore_detail'}
                            params={{ id: datasetObj.id }}
                          >

                              {datasetObj.label}

                          </Link>

                          {subscription.attributes.datasetsQuery
                            .find(elem => elem.id === datasetObj.id).type}
                           (≥{subscription.attributes.datasetsQuery
                            .find(elem => elem.id === datasetObj.id).threshold})

)
                    )}

              }
              {subscription &&

                    {!subscriptionConfirmed &&

                      Pending

                    }

              }

              <button
                className="c-btn -b -compressed"
                onClick={this.handleEdit}
              >
                Edit
              </button>

                Delete

    );
  }
}

AreaCard.propTypes = {
  token: PropTypes.string.isRequired,
  area: PropTypes.object.isRequired,
  // Callbacks
  onAreaRemoved: PropTypes.func.isRequired,
  onChange: PropTypes.func.isRequired,
  // Store
  toggleModal: PropTypes.func.isRequired,
  setModalOptions: PropTypes.func.isRequired,
  toggleTooltip: PropTypes.func.isRequired
};

const mapDispatchToProps = dispatch => ({
  toggleModal: (open, opts) => { dispatch(toggleModal(open, opts)); },
  setModalOptions: (options) => { dispatch(setModalOptions(options)); },
  toggleTooltip: (opened, opts) => {
    dispatch(toggleTooltip(opened, opts));
  }
});

export default connect(null, mapDispatchToProps)(AreaCard);
<|endoftext|>


<commit_before>var assert = require('assert');
var util = require('util');

module.exports = Expectation;

/**
 * An Expectation is a wrapper around an assertion that allows it to be written
 * in a more natural style, without the need to remember the order of arguments.
 * This helps prevent you from making mistakes when writing tests. For example,
 * instead of writing:
 *
 *   assert.equal(actual, expected, [message])
 *
 * you can write
 *
 *   expect(actual).toEqual(expected, [message])
 */
function Expectation(actual) {
  if (!(this instanceof Expectation))
    return new Expectation(actual);

  this.actual = actual;
}

var _slice = Array.prototype.slice;
function wrapAssertion(assertion) {
  return function () {
    return assertion.apply(assert, [ this.actual ].concat(_slice.call(arguments, 0)));
  };
}

Expectation.prototype.toBe = wrapAssertion(assert.strictEqual);
Expectation.prototype.toNotBe = wrapAssertion(assert.notStrictEqual);
Expectation.prototype.toEqual = wrapAssertion(assert.deepEqual);
Expectation.prototype.toNotEqual = wrapAssertion(assert.notDeepEqual);
Expectation.prototype.toThrow = wrapAssertion(assert.throws);
Expectation.prototype.toNotThrow = wrapAssertion(assert.doesNotThrow);

Expectation.prototype.toBeA = toBeA;
Expectation.prototype.toBeAn = toBeA;
function toBeA(constructor, message) {
  assert(typeof constructor === 'function', 'The constructor used in toBeA must be a function');

  message = message || util.inspect(this.actual) + ' is not a ' + (constructor.name || constructor.toString());
  assert(this.actual instanceof constructor, message);
}

Expectation.prototype.toMatch = toMatch;
function toMatch(pattern, message) {
  assert(util.isRegExp(pattern), 'The pattern used in toMatch must be a RegExp');

  message = message || util.inspect(this.actual) + ' does not match ' + util.inspect(pattern);
  assert(pattern.test(this.actual), message);
}

Expectation.prototype.toBeLessThan = toBeLessThan;
Expectation.prototype.toBeFewerThan = toBeLessThan;
function toBeLessThan(value, message) {
  message = message || util.inspect(this.actual) + ' is not less than ' + util.inspect(value);
  assert(this.actual < value, message);
}

Expectation.prototype.toBeGreaterThan = toBeGreaterThan;
Expectation.prototype.toBeMoreThan = toBeGreaterThan;
function toBeGreaterThan(value, message) {
  message = message || util.inspect(this.actual) + ' is not greater than ' + util.inspect(value);
  assert(this.actual > value, message);
}

Expectation.prototype.toInclude = toInclude;
Expectation.prototype.toContain = toInclude;
function toInclude(value, comparator, message) {
  assert(Array.isArray(this.actual), 'The actual value used in toContain/toInclude must be an Array');

  message = message || util.inspect(this.actual) + ' does not include ' + util.inspect(value);
  comparator = comparator || assert.deepEqual;
  assert(arrayContains(this.actual, comparator, value), message);
}

Expectation.prototype.toExclude = toExclude;
Expectation.prototype.toNotContain = toExclude;
function toExclude(value, comparator, message) {
  assert(Array.isArray(this.actual), 'The actual value used in toNotContain/toExclude must be an Array');

  message = message || util.inspect(this.actual) + ' includes ' + util.inspect(value);
  comparator = comparator || assert.deepEqual;
  assert(!arrayContains(this.actual, comparator, value), message);
}

/**
 * Returns true if the given array contains the value, false otherwise. The
 * comparator function must return false or throw to indicate a non-match.
 */
function arrayContains(array, comparator, value) {
  return array.some(function (item) {
    try {
      return comparator(item, value) !== false;
    } catch (e) {
      return false;
    }
  });
}
<commit_msg>Make comparator function optional<commit_after>var assert = require('assert');
var util = require('util');
var inspect = util.inspect;

module.exports = Expectation;

/**
 * An Expectation is a wrapper around an assertion that allows it to be written
 * in a more natural style, without the need to remember the order of arguments.
 * This helps prevent you from making mistakes when writing tests. For example,
 * instead of writing:
 *
 *   assert.equal(actual, expected, [message])
 *
 * you can write
 *
 *   expect(actual).toEqual(expected, [message])
 */
function Expectation(actual) {
  if (!(this instanceof Expectation))
    return new Expectation(actual);

  this.actual = actual;
}

var _slice = Array.prototype.slice;
function wrapAssertion(assertion) {
  return function () {
    return assertion.apply(assert, [ this.actual ].concat(_slice.call(arguments, 0)));
  };
}

Expectation.prototype.toBe = wrapAssertion(assert.strictEqual);
Expectation.prototype.toNotBe = wrapAssertion(assert.notStrictEqual);
Expectation.prototype.toEqual = wrapAssertion(assert.deepEqual);
Expectation.prototype.toNotEqual = wrapAssertion(assert.notDeepEqual);
Expectation.prototype.toThrow = wrapAssertion(assert.throws);
Expectation.prototype.toNotThrow = wrapAssertion(assert.doesNotThrow);

Expectation.prototype.toBeA = toBeA;
Expectation.prototype.toBeAn = toBeA;
function toBeA(constructor, message) {
  assert(typeof constructor === 'function', 'The constructor used in toBeA must be a function');
  message = message || inspect(this.actual) + ' is not a ' + (constructor.name || constructor.toString());
  assert(this.actual instanceof constructor, message);
}

Expectation.prototype.toMatch = toMatch;
function toMatch(pattern, message) {
  assert(util.isRegExp(pattern), 'The pattern used in toMatch must be a RegExp');
  message = message || inspect(this.actual) + ' does not match ' + inspect(pattern);
  assert(pattern.test(this.actual), message);
}

Expectation.prototype.toBeLessThan = toBeLessThan;
Expectation.prototype.toBeFewerThan = toBeLessThan;
function toBeLessThan(value, message) {
  message = message || inspect(this.actual) + ' is not less than ' + inspect(value);
  assert(this.actual < value, message);
}

Expectation.prototype.toBeGreaterThan = toBeGreaterThan;
Expectation.prototype.toBeMoreThan = toBeGreaterThan;
function toBeGreaterThan(value, message) {
  message = message || inspect(this.actual) + ' is not greater than ' + inspect(value);
  assert(this.actual > value, message);
}

Expectation.prototype.toInclude = toInclude;
Expectation.prototype.toContain = toInclude;
function toInclude(value, comparator, message) {
  assert(Array.isArray(this.actual), 'The actual value used in toContain/toInclude must be an Array');

  if (typeof comparator === 'string') {
    message = comparator;
    comparator = null;
  }

  message = message || inspect(this.actual) + ' does not include ' + inspect(value);
  assert(arrayContains(this.actual, value, comparator), message);
}

Expectation.prototype.toExclude = toExclude;
Expectation.prototype.toNotContain = toExclude;
function toExclude(value, comparator, message) {
  assert(Array.isArray(this.actual), 'The actual value used in toNotContain/toExclude must be an Array');

  if (typeof comparator === 'string') {
    message = comparator;
    comparator = null;
  }

  message = message || inspect(this.actual) + ' includes ' + inspect(value);
  assert(!arrayContains(this.actual, value, comparator), message);
}

/**
 * Returns true if the given array contains the value, false otherwise. The
 * comparator function must return false or throw to indicate a non-match.
 */
function arrayContains(array, value, comparator) {
  comparator = comparator || assert.deepEqual;

  return array.some(function (item) {
    try {
      return comparator(item, value) !== false;
    } catch (error) {
      return false;
    }
  });
}
<|endoftext|>


<commit_before>var DocsParser = require("../docsparser");
var xregexp = require('../xregexp').XRegExp;
var util = require('util');

function CppParser(settings) {
    //this.setup_settings();
    // call parent constructor
    DocsParser.call(this, settings);
}

CppParser.prototype = Object.create(DocsParser.prototype);

CppParser.prototype.setup_settings = function() {
    var name_token = '[a-zA-Z_][a-zA-Z0-9_]*';
    var identifier = util.format('(%s)(::%s)?', name_token, name_token);
    this.settings = {
        'typeInfo': false,
        'curlyTypes': false,
        'typeTag': 'param',
        'commentCloser': ' */',
        'fnIdentifier': identifier,
        'varIdentifier': '(' + identifier + ')\\s*(?:\\[(?:' + identifier + ')?\\]|\\((?:(?:\\s*,\\s*)?[a-z]+)+\\s*\\))?',
        'fnOpener': identifier + '\\s+' + identifier + '\\s*\\(',
        'bool': 'bool',
        'function': 'function'
    };
};

CppParser.prototype.parse_function = function(line) {
    var regex = xregexp(
        '(?P<retval>' + this.settings.varIdentifier + ')[&*\\s]+' +
        '(?P<name>' + this.settings.varIdentifier + ');?' +
        // void fnName
        // (arg1, arg2)
        '\\s*\\(\\s*(?P<args>.*)\\)'
    );

    var matches = xregexp.exec(line, regex);
    if(matches === null) {
        return null;
    }

    return [matches.name, matches.args, matches.retval];
};

CppParser.prototype.parse_args = function(args) {
    if(args.trim() == 'void')
        return [];
    return DocsParser.prototype.parse_args.call(this, args);
    //return super(JsdocsCPP, self).parseArgs(args)
};

CppParser.prototype.get_arg_type = function(arg) {
    return null;
};

CppParser.prototype.get_arg_name = function(arg) {
    if (arg == "...")  {
        // variable arguments
        return "VARARGS"
    }

    try {
        var regex = new RegExp(this.settings.varIdentifier + '(?:\s*=.*)?$');
        var matches = regex.exec(arg);
        return matches[1];
    }
    catch (ex) {
        // handle possible weird cases .....
    }
    return "???";
};

CppParser.prototype.parse_var = function(line) {
    return null;
};

CppParser.prototype.guess_type_from_value = function(val) {
    return null;
};

CppParser.prototype.get_function_return_type = function(name, retval) {
    return ((retval != 'void') ? retval : null);
};

module.exports = CppParser;
<commit_msg>coding style + remove unecessary try catch block<commit_after>var DocsParser = require("../docsparser");
var xregexp = require('../xregexp').XRegExp;
var util = require('util');

function CppParser(settings) {
    //this.setup_settings();
    // call parent constructor
    DocsParser.call(this, settings);
}

CppParser.prototype = Object.create(DocsParser.prototype);

CppParser.prototype.setup_settings = function() {
    var name_token = '[a-zA-Z_][a-zA-Z0-9_]*';
    var identifier = util.format('(%s)(::%s)?', name_token, name_token);
    this.settings = {
        'typeInfo': false,
        'curlyTypes': false,
        'typeTag': 'param',
        'commentCloser': ' */',
        'fnIdentifier': identifier,
        'varIdentifier': '(' + identifier + ')\\s*(?:\\[(?:' + identifier + ')?\\]|\\((?:(?:\\s*,\\s*)?[a-z]+)+\\s*\\))?',
        'fnOpener': identifier + '\\s+' + identifier + '\\s*\\(',
        'bool': 'bool',
        'function': 'function'
    };
};

CppParser.prototype.parse_function = function(line) {
    var regex = xregexp(
        '(?P<retval>' + this.settings.varIdentifier + ')[&*\\s]+' +
        '(?P<name>' + this.settings.varIdentifier + ');?' +
        // void fnName
        // (arg1, arg2)
        '\\s*\\(\\s*(?P<args>.*)\\)'
    );

    var matches = xregexp.exec(line, regex);
    if(matches === null) {
        return null;
    }

    return [matches.name, matches.args, matches.retval];
};

CppParser.prototype.parse_args = function(args) {
    if(args.trim() === 'void')
        return [];
    return DocsParser.prototype.parse_args.call(this, args);
    //return super(JsdocsCPP, self).parseArgs(args)
};

CppParser.prototype.get_arg_type = function(arg) {
    return null;
};

CppParser.prototype.get_arg_name = function(arg) {
    if(arg === "...") {
        // variable arguments
        return "VARARGS";
    }
    var regex = new RegExp(this.settings.varIdentifier + '(?:\s*=.*)?$');
    var matches = regex.exec(arg);
    return matches[1];
};

CppParser.prototype.parse_var = function(line) {
    return null;
};

CppParser.prototype.guess_type_from_value = function(val) {
    return null;
};

CppParser.prototype.get_function_return_type = function(name, retval) {
    return ((retval != 'void') ? retval : null);
};

module.exports = CppParser;
<|endoftext|>