<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    DELEGATED_EVENTS: [
        { type: 'click', useCapture: false },
        { type: 'mouseover', useCapture: false },
        { type: 'mouseout', useCapture: false },
        { type: 'keypress', useCapture: false },
        { type: 'dragstart', useCapture: false },
        { type: 'dragend', useCapture: false },
        { type: 'dragenter', useCapture: false },
        { type: 'dragleave', useCapture: false },
        { type: 'focus', useCapture: true },
        { type: 'blur', useCapture: true }
    ],
    initialize: function (cmp) {
        // Internal variables we use
        cmp._template          = null;
        cmp._virtualItems      = [];
        cmp._ptv               = null;
        cmp._dirtyFlag         = 0;
        cmp.set('v._dirty', 0, true);
    },
    initializeBody: function (cmp) {
        var body = cmp.get('v.body');
        if (!body.length) {
            var bodyCmp = $A.createComponentFromConfig({
                componentDef: {
                    descriptor: 'markup://aura:html'
                },
                attributes: {
                    valueProvider: cmp,
                    values: {
                        tag: 'section'
                    }
                }
            });
            cmp.set('v.body', [bodyCmp]);
        }
    },
    initializeDataModel: function(cmp) {
        var dataModel = cmp.get("v.dataProvider")[0];
        if (dataModel) {
            dataModel.addHandler("onchange", cmp, "c.handleDataChange");
        }
    },
     _createPassthroughValue: function(cmp, itemVar, item) {
        var context = {};
        context[itemVar] = item;
        return $A.expressionService.createPassthroughValue(context, cmp);
    },
    onItemChange: function (cmp, ptv, evt) {
        if (!ptv.ignoreChanges) {
            ptv.dirty = true;
        }

        if (!ptv.sync && cmp.isRendered()) { // Some component has updated asyncronously the item, rerender it

            ptv.sync = true; // at this point the action becomes sync
            var item = evt.getParam('value');
            this._rerenderDirtyElement(cmp, item);
        }
    },
    ignorePTVChanges: function (cmp, ignore) {
        cmp._ptv.sync = ignore;
        cmp._ptv.ignoreChanges = ignore;
    },
    _initializeItemTemplate: function (cmpTemplate) {
        var container = document.createDocumentFragment();
        $A.render(cmpTemplate, container);
        return container;
    },
    initializeTemplate: function (cmp) {
        var tmpl  = cmp.get('v.itemTemplate')[0];
        var ref   = cmp.get('v.itemVar');
        var ptv   = this._createPassthroughValue(cmp, ref);
        tmpl["attributes"]["valueProvider"] = ptv;
        var shape = $A.createComponentFromConfig(tmpl);

        // Initialize internal setup
        cmp._shape             = shape;
        cmp._ptv               = ptv;
        cmp._template          = this._initializeItemTemplate(shape);
        ptv.ignoreChanges      = true;
        ptv.dirty              = false;

        cmp.addValueHandler({
            event  : 'change',
            value  : ref,
            method : this.onItemChange.bind(this, cmp, ptv)
        });
    },

    initializeItems: function (cmp) {
        var dataModel = cmp.get("v.dataProvider")[0],
            model     = dataModel && dataModel.getModel(),
            items     = model && model.get('items');

        if (items) {
            cmp.set("v.items", items, true);
        } else if (dataModel) {
            dataModel.getEvent('provide').fire();
        }
    },
    _attachItemToElement: function (dom, item) {
        dom._data = item;
    },
    _generateVirtualItem: function (cmp, item) {
        var rowTmpl = cmp._template,
            ptv     = cmp._ptv,
            itemVar = cmp.get('v.itemVar'),
            clonedItem;

        // Change the PTV -> dirty whatever is needed
        ptv.set(itemVar, item);

        cmp.markClean('v.items'); // Mark ourselves clean before rerender (avoid calling rerender on ourselves)
        $A.renderingService.rerenderDirty('virtualRendering');

        // Snapshot the DOM
        clonedItem = rowTmpl.firstChild.cloneNode(true);

        // Attach the data to the element
        this._attachItemToElement(clonedItem, item);

        return clonedItem;
    },
    createVirtualList: function (cmp) {
        var items = cmp.get('v.items');
        cmp._virtualItems = [];
        if (items && items.length) {
            for (var i = 0; i < items.length; i++) {
                cmp._virtualItems.push(this._generateVirtualItem(cmp, items[i]));
            }
        }
    },
    getListBody: function (cmp, dom) {
        var node = dom ? dom[0] : cmp.getElement();
        return  node;
    },
    markClean: function (cmp, value) {
        var concreteCmp = cmp.getConcreteComponent();
        concreteCmp.markClean(value);
    },
    markDirty: function (cmp) {
        var concreteCmp = cmp.getConcreteComponent();
        concreteCmp.set('v._dirty', ++cmp._dirtyFlag);
    },
    createEventDelegates: function (cmp, container) {
        var self     = this,
            events   = this.DELEGATED_EVENTS,
            delegate = function (e) {
                self._eventDelegator(cmp, e);
            };

        for (var i = 0; i < events.length; i++) {
            container.addEventListener(events[i].type, delegate, events[i].useCapture);
        }
    },
    appendVirtualRows: function (cmp, items) {
        $A.metricsService.markStart(this.NS, this.NAME + ".appendVirtualRows", {auraid : cmp.getGlobalId()});
        this.ignorePTVChanges(cmp, true);
        var fragment  = document.createDocumentFragment(),
            container = this.getListBody(cmp);

        for (var i = 0; i < items.length; i++) {
            var virtualItem = this._generateVirtualItem(cmp, items[i]);
            cmp._virtualItems.push(virtualItem);
            fragment.appendChild(virtualItem);
        }
        container.appendChild(fragment);
        cmp.set('v.items', (cmp.get('v.items') || []).concat(items), true);
        this.ignorePTVChanges(cmp, false);
        $A.metricsService.markEnd(this.NS, this.NAME + ".appendVirtualRows");
    },
    updateItem: function (cmp, item, index) {
        this._rerenderDirtyElement(cmp, item, null, index);
    },
    getComponentByIndex: function(cmp, index, callback) {
        var items = cmp._virtualItems;
        if (index<0 || index>=items.length) {
            callback(null);
            return;
        }

        var shape  = cmp._shape,
            ptv    = cmp._ptv,
            ref    = cmp.get('v.itemVar'),
            target = cmp._virtualItems[index],
            item   = this._getItemAttached(target);

        // Setting up the component with the current item
        shape.getElement = function () { return target; };
        ptv.sync  = true;
        ptv.set(ref, item, true);
        ptv.ignoreChanges = false;
        ptv.dirty = false;

        callback(shape);
    },
    _findVirtualElementPosition: function (virtualElements, item, element) {
        for (var i = 0; i < virtualElements.length; i++) {
            var ve = virtualElements[i];
            if (element && ve === element || ve._data === item) {
                return i;
            }
        }
    },
    _replaceDOMElement: function (parent, newChild, oldChild) {
        parent.replaceChild(newChild, oldChild);
    },
    // oldElement or index may be null
    _rerenderDirtyElement: function (cmp, item, oldElement, index) {
        var listRoot   = this.getListBody(cmp),
            items      = cmp._virtualItems,
            // if the index is passed in, then we take it, otherwise we try to find it
            position   = (!$A.util.isUndefined(index))?index:this._findVirtualElementPosition(items, item, oldElement),
            newElement = this._generateVirtualItem(cmp, item);

        if (!$A.util.isUndefinedOrNull(listRoot) && !$A.util.isUndefined(position) && position>=0 && position<items.length) {
            if (!oldElement) {
                oldElement = items[position];
            }

            items[position] = newElement;
            this._replaceDOMElement(listRoot, newElement, oldElement);
        }
    },
    _getRenderingComponentForElement: function (domElement) {
        var id  = $A.util.getDataAttribute(domElement, 'auraRenderedBy');
        return id && $A.componentService.get(id);
    },

    // NOTE: Do not rename this function not change its signature(instrumentation reliying on it)
    _dispatchAction: function (action, event /*cmp*/) {
        action.runDeprecated(event);
    },
    _getItemAttached: function (dom) {
        return dom._data;
    },
    _getActionHandler: function (htmlCmp, eventType) {
        var eventTypeAttribute = 'on' + eventType,
            htmlAttr = htmlCmp.isInstanceOf('aura:html') && htmlCmp.get('v.HTMLAttributes');
        return htmlAttr && htmlAttr[eventTypeAttribute];
    },
    _eventDelegator: function (cmp, e) {
        var type     = e.type,
            target    = e.target,
            ref       = cmp.get('v.itemVar'),
            handlers  = [],
            shape     = cmp._shape,
            ptv       = cmp._ptv,
            getElmt   = function (t) { return t; },
            item, targetCmp, actionHandler, actionHandlerScope;

        while (target) {
            targetCmp = this._getRenderingComponentForElement(target);
            // Guard for existance since there are cases like container components
            // that might not have elements associated with them.
            if (targetCmp) {
                actionHandler = this._getActionHandler(targetCmp, type);
                if (actionHandler) {
                    handlers.push({
                        "handler"   : actionHandler,
                        "target"    : target,
                        "targetCmp" : targetCmp
                    });
                }
            }

            if ((item = this._getItemAttached(target))) {
                break;
            }
            target = target.parentElement;
        }

        if (!handlers.length > 0) {
            return;
        }

        if (item) {
            // Seting up the event with some custom properties
            e.templateItem = item;
            e.templateElement = target;
            shape.getElement = getElmt.bind(null, target);

            // Setting up the component with the current item
            ptv.sync  = true;
            ptv.set(ref, item, true);
            ptv.ignoreChanges = false;
            ptv.dirty = false;

            // Execute the collected handlers in order
            while ((actionHandlerScope = handlers.shift())) {
                actionHandler = actionHandlerScope.handler;
                if ($A.util.isExpression(actionHandler)) {
                    actionHandlerScope.targetCmp.getElement = getElmt.bind(null, actionHandlerScope.target);
                    this._dispatchAction(actionHandler.evaluate(), e, actionHandlerScope.targetCmp);
                    delete actionHandlerScope.targetCmp.getElement;
                }
            }

            // TODO: Being smarter when to rerender:
            // If there is an internal change (no ptv),
            // content wont update automatically:
            if (ptv.dirty || cmp.get('v.forceRender')) {
                this._rerenderDirtyElement(cmp, item, target);
            }

            delete shape.getElement;
            ptv.ignoreChanges = true;
            ptv.sync = false;
        }
    },
    _getRootComponent: function (cmp) {
        var superCmp   = cmp.getSuper(),
            isExtended = superCmp.getDef().getDescriptor().getName() !== 'component';

        if (isExtended) {
            cmp = superCmp;
        }
        return cmp;
    }
})// eslint-disable-line semi<commit_msg>Adding afterRender in virtualList<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    DELEGATED_EVENTS: [
        { type: 'click', useCapture: false },
        { type: 'mouseover', useCapture: false },
        { type: 'mouseout', useCapture: false },
        { type: 'keypress', useCapture: false },
        { type: 'dragstart', useCapture: false },
        { type: 'dragend', useCapture: false },
        { type: 'dragenter', useCapture: false },
        { type: 'dragleave', useCapture: false },
        { type: 'focus', useCapture: true },
        { type: 'blur', useCapture: true }
    ],
    initialize: function (cmp) {
        // Internal variables we use
        cmp._template          = null;
        cmp._virtualItems      = [];
        cmp._ptv               = null;
        cmp._dirtyFlag         = 0;
        cmp.set('v._dirty', 0, true);
    },
    initializeBody: function (cmp) {
        var body = cmp.get('v.body');
        if (!body.length) {
            var bodyCmp = $A.createComponentFromConfig({
                componentDef: {
                    descriptor: 'markup://aura:html'
                },
                attributes: {
                    valueProvider: cmp,
                    values: {
                        tag: 'section'
                    }
                }
            });
            cmp.set('v.body', [bodyCmp]);
        }
    },
    initializeDataModel: function(cmp) {
        var dataModel = cmp.get("v.dataProvider")[0];
        if (dataModel) {
            dataModel.addHandler("onchange", cmp, "c.handleDataChange");
        }
    },
     _createPassthroughValue: function(cmp, itemVar, item) {
        var context = {};
        context[itemVar] = item;
        return $A.expressionService.createPassthroughValue(context, cmp);
    },
    onItemChange: function (cmp, ptv, evt) {
        if (!ptv.ignoreChanges) {
            ptv.dirty = true;
        }

        if (!ptv.sync && cmp.isRendered()) { // Some component has updated asyncronously the item, rerender it

            ptv.sync = true; // at this point the action becomes sync
            var item = evt.getParam('value');
            this._rerenderDirtyElement(cmp, item);
        }
    },
    ignorePTVChanges: function (cmp, ignore) {
        cmp._ptv.sync = ignore;
        cmp._ptv.ignoreChanges = ignore;
    },
    _initializeItemTemplate: function (cmpTemplate) {
        var container = document.createDocumentFragment();
        $A.render(cmpTemplate, container);
        $A.afterRender(cmpTemplate);
        return container;
    },
    initializeTemplate: function (cmp) {
        var tmpl  = cmp.get('v.itemTemplate')[0];
        var ref   = cmp.get('v.itemVar');
        var ptv   = this._createPassthroughValue(cmp, ref);
        tmpl["attributes"]["valueProvider"] = ptv;
        var shape = $A.createComponentFromConfig(tmpl);

        // Initialize internal setup
        cmp._shape             = shape;
        cmp._ptv               = ptv;
        cmp._template          = this._initializeItemTemplate(shape);
        ptv.ignoreChanges      = true;
        ptv.dirty              = false;

        cmp.addValueHandler({
            event  : 'change',
            value  : ref,
            method : this.onItemChange.bind(this, cmp, ptv)
        });
    },

    initializeItems: function (cmp) {
        var dataModel = cmp.get("v.dataProvider")[0],
            model     = dataModel && dataModel.getModel(),
            items     = model && model.get('items');

        if (items) {
            cmp.set("v.items", items, true);
        } else if (dataModel) {
            dataModel.getEvent('provide').fire();
        }
    },
    _attachItemToElement: function (dom, item) {
        dom._data = item;
    },
    _generateVirtualItem: function (cmp, item) {
        var rowTmpl = cmp._template,
            ptv     = cmp._ptv,
            itemVar = cmp.get('v.itemVar'),
            clonedItem;

        // Change the PTV -> dirty whatever is needed
        ptv.set(itemVar, item);

        cmp.markClean('v.items'); // Mark ourselves clean before rerender (avoid calling rerender on ourselves)
        $A.renderingService.rerenderDirty('virtualRendering');

        // Snapshot the DOM
        clonedItem = rowTmpl.firstChild.cloneNode(true);

        // Attach the data to the element
        this._attachItemToElement(clonedItem, item);

        return clonedItem;
    },
    createVirtualList: function (cmp) {
        var items = cmp.get('v.items');
        cmp._virtualItems = [];
        if (items && items.length) {
            for (var i = 0; i < items.length; i++) {
                cmp._virtualItems.push(this._generateVirtualItem(cmp, items[i]));
            }
        }
    },
    getListBody: function (cmp, dom) {
        var node = dom ? dom[0] : cmp.getElement();
        return  node;
    },
    markClean: function (cmp, value) {
        var concreteCmp = cmp.getConcreteComponent();
        concreteCmp.markClean(value);
    },
    markDirty: function (cmp) {
        var concreteCmp = cmp.getConcreteComponent();
        concreteCmp.set('v._dirty', ++cmp._dirtyFlag);
    },
    createEventDelegates: function (cmp, container) {
        var self     = this,
            events   = this.DELEGATED_EVENTS,
            delegate = function (e) {
                self._eventDelegator(cmp, e);
            };

        for (var i = 0; i < events.length; i++) {
            container.addEventListener(events[i].type, delegate, events[i].useCapture);
        }
    },
    appendVirtualRows: function (cmp, items) {
        $A.metricsService.markStart(this.NS, this.NAME + ".appendVirtualRows", {auraid : cmp.getGlobalId()});
        this.ignorePTVChanges(cmp, true);
        var fragment  = document.createDocumentFragment(),
            container = this.getListBody(cmp);

        for (var i = 0; i < items.length; i++) {
            var virtualItem = this._generateVirtualItem(cmp, items[i]);
            cmp._virtualItems.push(virtualItem);
            fragment.appendChild(virtualItem);
        }
        container.appendChild(fragment);
        cmp.set('v.items', (cmp.get('v.items') || []).concat(items), true);
        this.ignorePTVChanges(cmp, false);
        $A.metricsService.markEnd(this.NS, this.NAME + ".appendVirtualRows");
    },
    updateItem: function (cmp, item, index) {
        this._rerenderDirtyElement(cmp, item, null, index);
    },
    getComponentByIndex: function(cmp, index, callback) {
        var items = cmp._virtualItems;
        if (index<0 || index>=items.length) {
            callback(null);
            return;
        }

        var shape  = cmp._shape,
            ptv    = cmp._ptv,
            ref    = cmp.get('v.itemVar'),
            target = cmp._virtualItems[index],
            item   = this._getItemAttached(target);

        // Setting up the component with the current item
        shape.getElement = function () { return target; };
        ptv.sync  = true;
        ptv.set(ref, item, true);
        ptv.ignoreChanges = false;
        ptv.dirty = false;

        callback(shape);
    },
    _findVirtualElementPosition: function (virtualElements, item, element) {
        for (var i = 0; i < virtualElements.length; i++) {
            var ve = virtualElements[i];
            if (element && ve === element || ve._data === item) {
                return i;
            }
        }
    },
    _replaceDOMElement: function (parent, newChild, oldChild) {
        parent.replaceChild(newChild, oldChild);
    },
    // oldElement or index may be null
    _rerenderDirtyElement: function (cmp, item, oldElement, index) {
        var listRoot   = this.getListBody(cmp),
            items      = cmp._virtualItems,
            // if the index is passed in, then we take it, otherwise we try to find it
            position   = (!$A.util.isUndefined(index))?index:this._findVirtualElementPosition(items, item, oldElement),
            newElement = this._generateVirtualItem(cmp, item);

        if (!$A.util.isUndefinedOrNull(listRoot) && !$A.util.isUndefined(position) && position>=0 && position<items.length) {
            if (!oldElement) {
                oldElement = items[position];
            }

            items[position] = newElement;
            this._replaceDOMElement(listRoot, newElement, oldElement);
        }
    },
    _getRenderingComponentForElement: function (domElement) {
        var id  = $A.util.getDataAttribute(domElement, 'auraRenderedBy');
        return id && $A.componentService.get(id);
    },

    // NOTE: Do not rename this function not change its signature(instrumentation reliying on it)
    _dispatchAction: function (action, event /*cmp*/) {
        action.runDeprecated(event);
    },
    _getItemAttached: function (dom) {
        return dom._data;
    },
    _getActionHandler: function (htmlCmp, eventType) {
        var eventTypeAttribute = 'on' + eventType,
            htmlAttr = htmlCmp.isInstanceOf('aura:html') && htmlCmp.get('v.HTMLAttributes');
        return htmlAttr && htmlAttr[eventTypeAttribute];
    },
    _eventDelegator: function (cmp, e) {
        var type     = e.type,
            target    = e.target,
            ref       = cmp.get('v.itemVar'),
            handlers  = [],
            shape     = cmp._shape,
            ptv       = cmp._ptv,
            getElmt   = function (t) { return t; },
            item, targetCmp, actionHandler, actionHandlerScope;

        while (target) {
            targetCmp = this._getRenderingComponentForElement(target);
            // Guard for existance since there are cases like container components
            // that might not have elements associated with them.
            if (targetCmp) {
                actionHandler = this._getActionHandler(targetCmp, type);
                if (actionHandler) {
                    handlers.push({
                        "handler"   : actionHandler,
                        "target"    : target,
                        "targetCmp" : targetCmp
                    });
                }
            }

            if ((item = this._getItemAttached(target))) {
                break;
            }
            target = target.parentElement;
        }

        if (!handlers.length > 0) {
            return;
        }

        if (item) {
            // Seting up the event with some custom properties
            e.templateItem = item;
            e.templateElement = target;
            shape.getElement = getElmt.bind(null, target);

            // Setting up the component with the current item
            ptv.sync  = true;
            ptv.set(ref, item, true);
            ptv.ignoreChanges = false;
            ptv.dirty = false;

            // Execute the collected handlers in order
            while ((actionHandlerScope = handlers.shift())) {
                actionHandler = actionHandlerScope.handler;
                if ($A.util.isExpression(actionHandler)) {
                    actionHandlerScope.targetCmp.getElement = getElmt.bind(null, actionHandlerScope.target);
                    this._dispatchAction(actionHandler.evaluate(), e, actionHandlerScope.targetCmp);
                    delete actionHandlerScope.targetCmp.getElement;
                }
            }

            // TODO: Being smarter when to rerender:
            // If there is an internal change (no ptv),
            // content wont update automatically:
            if (ptv.dirty || cmp.get('v.forceRender')) {
                this._rerenderDirtyElement(cmp, item, target);
            }

            delete shape.getElement;
            ptv.ignoreChanges = true;
            ptv.sync = false;
        }
    },
    _getRootComponent: function (cmp) {
        var superCmp   = cmp.getSuper(),
            isExtended = superCmp.getDef().getDescriptor().getName() !== 'component';

        if (isExtended) {
            cmp = superCmp;
        }
        return cmp;
    }
})// eslint-disable-line semi<|endoftext|>


<commit_before>

Function.RegisterNamespace("Test.inputNumberLibrary");

[Fixture]
Test.inputNumberLibrary = function () {
    var EMPTY_STRING = '';
    var library;
    ImportJson('aura-components/src/main/components/ui/inputNumberLibrary/number.js', function (path,result) {
        library = result();
    });

    var mockAura = Mocks.GetMock(Object.Global(),"$A",{
        util:{
            isNumber : function (number) {
                return  typeof number === 'number';
            },
            isUndefinedOrNull : function (value) {
                return typeof value === 'undefined' || value === null;
            }
        },
        localizationService : {
            getDefaultNumberFormat: function () {
                return {
                    format: function () {
                        return '2,545.00'
                    }
                }
            }
        },
        get : function (attr) {
            var attrs = { '$Locale.decimal' : '.', '$Locale.currency' : '$' };
            return attrs[attr];
        }
    });

    [Fixture]
    function unFormatNumber () {

        var mockLocaleEurope = Mocks.GetMock(Object.Global(),"$A",{
            get : function (attr) {
                var attrs = { '$Locale.decimal' : ',', '$Locale.currency' : '€' };
                return attrs[attr];
            },
            util:{
                isNumber : function (number) {
                    return  typeof number === 'number';
                },
                isUndefinedOrNull : function (value) {
                    return typeof value === 'undefined' || value === null;
                }
            }
        })

        [Fact]
        function unFormatNumberNumber() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber(1234);
                Assert.Equal(1234,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_GoodFormattedString() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('1,234,567.89');
                Assert.Equal(1234567.89,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_K() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8k');
                Assert.Equal(12800,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_M() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8m');
                Assert.Equal(12800000,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_B() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8b');
                Assert.Equal(12800000000,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_T() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8t');
                Assert.Equal(12800000000000,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_LocaleEuro() {
            mockLocaleEurope(function () {
                var unFormatted = library.unFormatNumber('€12,8b');
                Assert.Equal(12800000000,unFormatted);
            })
        }

    }

    [Fixture]
    function isNumberMethod () {
        [Fact]
        function isNumberNumber() {
            mockAura(function () {
                Assert.True(library.isNumber(123.56));
            });
        }

        [Fact]
        function isNumberString() {
            mockAura(function () {
                Assert.False(library.isNumber('123.45'));
            });
        }

        [Fact]
        function isNumberUndefined() {
            mockAura(function () {
                Assert.False(library.isNumber(undefined));
            });
        }

        [Fact]
        function isNumberNull() {
            mockAura(function () {
                Assert.False(library.isNumber(null));
            });
        }
    }

    [Fixture]
    function formatNumberMethod () {
        [Fact]
        function formatNumber () {
            mockAura(function () {
                var formatted = library.formatNumber(2545,'#,##0.00');
                Assert.Equal('2,545.00',formatted);
            })
        }
        [Fact]
        function formatNumberUndefined () {
            mockAura(function () {
                var formatted = library.formatNumber(undefined,'#,##0.00');
                Assert.Equal(EMPTY_STRING,formatted);
            })
        }
        [Fact]
        function formatNumberNull () {
            mockAura(function () {
                var formatted = library.formatNumber(null,'#,##0.00');
                Assert.Equal(EMPTY_STRING,formatted);
            })
        }
    }

};<commit_msg>add license header<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Function.RegisterNamespace("Test.inputNumberLibrary");

[Fixture]
Test.inputNumberLibrary = function () {
    var EMPTY_STRING = '';
    var library;
    ImportJson('aura-components/src/main/components/ui/inputNumberLibrary/number.js', function (path,result) {
        library = result();
    });

    var mockAura = Mocks.GetMock(Object.Global(),"$A",{
        util:{
            isNumber : function (number) {
                return  typeof number === 'number';
            },
            isUndefinedOrNull : function (value) {
                return typeof value === 'undefined' || value === null;
            }
        },
        localizationService : {
            getDefaultNumberFormat: function () {
                return {
                    format: function () {
                        return '2,545.00'
                    }
                }
            }
        },
        get : function (attr) {
            var attrs = { '$Locale.decimal' : '.', '$Locale.currency' : '$' };
            return attrs[attr];
        }
    });

    [Fixture]
    function unFormatNumber () {

        var mockLocaleEurope = Mocks.GetMock(Object.Global(),"$A",{
            get : function (attr) {
                var attrs = { '$Locale.decimal' : ',', '$Locale.currency' : '€' };
                return attrs[attr];
            },
            util:{
                isNumber : function (number) {
                    return  typeof number === 'number';
                },
                isUndefinedOrNull : function (value) {
                    return typeof value === 'undefined' || value === null;
                }
            }
        })

        [Fact]
        function unFormatNumberNumber() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber(1234);
                Assert.Equal(1234,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_GoodFormattedString() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('1,234,567.89');
                Assert.Equal(1234567.89,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_K() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8k');
                Assert.Equal(12800,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_M() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8m');
                Assert.Equal(12800000,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_B() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8b');
                Assert.Equal(12800000000,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_Shortcut_T() {
            mockAura(function () {
                var unFormatted = library.unFormatNumber('12.8t');
                Assert.Equal(12800000000000,unFormatted);
            })
        }

        [Fact]
        function unFormatNumber_LocaleEuro() {
            mockLocaleEurope(function () {
                var unFormatted = library.unFormatNumber('€12,8b');
                Assert.Equal(12800000000,unFormatted);
            })
        }

    }

    [Fixture]
    function isNumberMethod () {
        [Fact]
        function isNumberNumber() {
            mockAura(function () {
                Assert.True(library.isNumber(123.56));
            });
        }

        [Fact]
        function isNumberString() {
            mockAura(function () {
                Assert.False(library.isNumber('123.45'));
            });
        }

        [Fact]
        function isNumberUndefined() {
            mockAura(function () {
                Assert.False(library.isNumber(undefined));
            });
        }

        [Fact]
        function isNumberNull() {
            mockAura(function () {
                Assert.False(library.isNumber(null));
            });
        }
    }

    [Fixture]
    function formatNumberMethod () {
        [Fact]
        function formatNumber () {
            mockAura(function () {
                var formatted = library.formatNumber(2545,'#,##0.00');
                Assert.Equal('2,545.00',formatted);
            })
        }
        [Fact]
        function formatNumberUndefined () {
            mockAura(function () {
                var formatted = library.formatNumber(undefined,'#,##0.00');
                Assert.Equal(EMPTY_STRING,formatted);
            })
        }
        [Fact]
        function formatNumberNull () {
            mockAura(function () {
                var formatted = library.formatNumber(null,'#,##0.00');
                Assert.Equal(EMPTY_STRING,formatted);
            })
        }
    }

};<|endoftext|>


<commit_before>$(function(){
	var sub = grabHash(window.location.hash);
	posts = renderPost(sub);

	// Bind click event handlers to our expanders and collapsers.
	$('body').delegate(".expander", "click", function(){
		if ($(this).parents('ul').first().find('.comments').is(':empty')){
			getComments($(this).attr('id'), $(this).parents('ul').first().find('.comments'));
			$(this).parents('ul').first().find('.comments').snippet("php", {style:"emacs", showNum: false, transparent: true, menu: false});
		}
		else {
			$(this).parents('ul').first().find('.comments').show();
		}
		$(this).attr('src', 'img/collapse.png');
		$(this).addClass('collapse');
		$(this).removeClass('expander');

	});
	$('body').delegate(".collapse", "click", function(){
		$(this).parents('ul').first().find('.comments').hide();
		$(this).attr('src', 'img/expand.png');
		$(this).addClass('expander');
		$(this).removeClass('collapse');
	});
	// On a hash change, be sure to reload the page.
	$(window).bind('hashchange', function(e){
		var hash = e.fragment;
		$('body').html('');
		renderPost(hash);
	});
});

function renderPost(subreddit){
		//Determine what subreddit we want, contact reddit accordingly.
		if (subreddit != ''){
			subreddit = "http://www.reddit.com/r/"+subreddit+"/.json?jsonp=?";
		}
		else {
			subreddit = "http://www.reddit.com/.json?jsonp=?";
		}
		var posts = $.getJSON(subreddit,
			 function(posts) {
				var posting;
				var items = posts;
				subreddit = window.location.hash
				posting = "
\n\
require('readme.php');\n\
session_start();
"
				if (subreddit){
					posting += "
$subreddit = $_GET[\""+subreddit+"\"];
";
				}
				else {
					posting += "
$subreddit = $_GET[\"frontpage\"];
";
				}

				$('body').append(posting);
				$.each(items.data.children, function(entry){
					var true_entry = items.data.children[entry].data
					var title = createTitle(true_entry, entry);
					$.get('php.html', function(template) {
						template = template.replace("${title}",title);
						// People sometimes post non-direct images, most commonly imgur.com
						// this block will guess the direct link equivalent. Not very accurately...Need to look into changing this.

						if (true_entry.selftext){
							template = template.replace("${selftext}", formatSelfText(true_entry.selftext));
						}
						else {
							template = template.replace("${selftext}", "");
						}
						if (true_entry.domain == "imgur.com"){
							true_entry.url = true_entry.url.replace("imgur.com", "i.imgur.com") + ".jpg"
						}
						if (/\.(jpg)|(gif)|(png)$/.test(true_entry.url)){
							template = template.replace("${fancybox}", "image");
						}
						else if (/www.youtube.com/.test(true_entry.url)){
							template = template.replace("${fancybox}", "video");
						}
						else {
							template = template.replace("${fancybox}", "");
						}
						template = template.replace("${subreddit}", true_entry.subreddit);
						template = template.replace("${suburl}", "#" + true_entry.subreddit);
						template = template.replace("${url}", true_entry.url);
						template = template.replace("${author}", true_entry.author);
						template = template.replace("${score}", true_entry.score);
						template = template.replace("${domain}", true_entry.domain);
						template = template.replace("${fulltitle}", true_entry.title);
						template = template.replace("${num_comments}", true_entry.num_comments);
						template = template.replace("${entry_id}", true_entry.name);
						$('body').append(template);
						$("pre.php").snippet("php", {style:"emacs", showNum: false, transparent: true, menu: false});
						//alert(title);
						$("a.image").fancybox({
							'transitionIn'	:	'elastic',
							'transitionOut'	:	'elastic',
							'speedIn'		:	600,
							'speedOut'		:	200
						});
						// TODO: Take a look at this, it's for youtube videos in fancybox.
						//$("a.video").fancybox({
						//	'padding' : 0,
						//	'autoScale' : false,
						//	'transitionIn' : 'elastic',
						//	'transitionOut' : 'elastic',
						//	'speedIn' : 600,
						//	'speedOut': 200,
						//	'title' : this.title,
						//	'width' : 640,
						//	'height': 385,
						//	'href' : this.href.replace(new RegExp("watch\\?v=", "i"), 'v/'),
						//	'type' : 'swf',
						//	'swf' : {
						//		'wmode' : 'transparent',
						//		'allowfullscreen' : 'true'
						//	}
						//});

					});

				});
		});
		return posts;
}

function createTitle(entry, number){
	var post;

	// Emulate camel case, slice ridiculous title lengths, and remove characters.
	var title = entry.title
				.toLowerCase().substring(0,20).replace(/[^A-Za-z0-9\s\s+]/gi, '').split(' ');
	for (token in title){
		title[token] = title[token].charAt(0).toUpperCase() + title[token].slice(1);
	};
	title = title.join('');
	return title;
}
function grabHash(hash){
	return hash.replace('#','');
}
function getComments(raw_id, comment_location){
	// Retrieve and display comments
	var id = raw_id.replace('t3_', '');
	var text = '';
	var comment_url = 'http://www.reddit.com/comments/' + id + '.json?jsonp=?';
	var comments = $.getJSON(comment_url, function(comments){
		comments = comments[1].data.children.slice(0,20);
		$.each(comments, function(comment){
			template = "	$author = ${commenter};\n\
	$score = ${score}\n\
	//${text} \n\n\n"
			template = template.replace('${commenter}', comments[comment].data.author);
			template = template.replace('${score}', comments[comment].data.ups - comments[comment].data.downs);
			template = template.replace('${text}', comments[comment].data.body);
			text += template;

		});
		comment_location.text(text);

	});
	return text;
}
function formatSelfText(text){
	// If it's a self text we're going to output a large
	// comment block.
	text = text.replace(/(\r\n|\n|\r)/gm,"");
	var new_text = "";
	num_splits = Math.floor(text.length / 80);
	i = 0
	while (i <= num_splits){
		new_text = new_text + "// " + text.substring(i * 80, (i+1)*80) + "\n" + "    ";
		i++;
	}
	return new_text;
}<commit_msg>Comments now aren't completely awful. Still quite awful, but...<commit_after>$(function(){
	var sub = grabHash(window.location.hash);
	posts = renderPost(sub);

	// Bind click event handlers to our expanders and collapsers.
	$('body').delegate(".expander", "click", function(){
		if ($(this).parents('ul').first().find('.comments').is(':empty')){
			getComments($(this).attr('id'), $(this).parents('ul').first().find('.comments'));
			$(this).parents('ul').first().find('.comments').snippet("php", {style:"emacs", showNum: false, transparent: true, menu: false});
		}
		else {
			$(this).parents('ul').first().find('.comments').show();
		}
		$(this).attr('src', 'img/collapse.png');
		$(this).addClass('collapse');
		$(this).removeClass('expander');

	});
	$('body').delegate(".collapse", "click", function(){
		$(this).parents('ul').first().find('.comments').hide();
		$(this).attr('src', 'img/expand.png');
		$(this).addClass('expander');
		$(this).removeClass('collapse');
	});
	// On a hash change, be sure to reload the page.
	$(window).bind('hashchange', function(e){
		var hash = e.fragment;
		$('body').html('');
		renderPost(hash);
	});
});

function renderPost(subreddit){
		//Determine what subreddit we want, contact reddit accordingly.
		if (subreddit != ''){
			subreddit = "http://www.reddit.com/r/"+subreddit+"/.json?jsonp=?";
		}
		else {
			subreddit = "http://www.reddit.com/.json?jsonp=?";
		}
		var posts = $.getJSON(subreddit,
			 function(posts) {
				var posting;
				var items = posts;
				subreddit = window.location.hash
				posting = "
\n\
require('readme.php');\n\
session_start();
"
				if (subreddit){
					posting += "
$subreddit = $_GET[\""+subreddit+"\"];
";
				}
				else {
					posting += "
$subreddit = $_GET[\"frontpage\"];
";
				}

				$('body').append(posting);
				$.each(items.data.children, function(entry){
					var true_entry = items.data.children[entry].data
					var title = createTitle(true_entry, entry);
					$.get('php.html', function(template) {
						template = template.replace("${title}",title);
						// People sometimes post non-direct images, most commonly imgur.com
						// this block will guess the direct link equivalent. Not very accurately...Need to look into changing this.

						if (true_entry.selftext){
							template = template.replace("${selftext}", formatSelfText(true_entry.selftext));
						}
						else {
							template = template.replace("${selftext}", "");
						}
						if (true_entry.domain == "imgur.com"){
							true_entry.url = true_entry.url.replace("imgur.com", "i.imgur.com") + ".jpg"
						}
						if (/\.(jpg)|(gif)|(png)$/.test(true_entry.url)){
							template = template.replace("${fancybox}", "image");
						}
						else if (/www.youtube.com/.test(true_entry.url)){
							template = template.replace("${fancybox}", "video");
						}
						else {
							template = template.replace("${fancybox}", "");
						}
						template = template.replace("${subreddit}", true_entry.subreddit);
						template = template.replace("${suburl}", "#" + true_entry.subreddit);
						template = template.replace("${url}", true_entry.url);
						template = template.replace("${author}", true_entry.author);
						template = template.replace("${score}", true_entry.score);
						template = template.replace("${domain}", true_entry.domain);
						template = template.replace("${fulltitle}", true_entry.title);
						template = template.replace("${num_comments}", true_entry.num_comments);
						template = template.replace("${entry_id}", true_entry.name);
						$('body').append(template);
						$("pre.php").snippet("php", {style:"emacs", showNum: false, transparent: true, menu: false});
						//alert(title);
						$("a.image").fancybox({
							'transitionIn'	:	'elastic',
							'transitionOut'	:	'elastic',
							'speedIn'		:	600,
							'speedOut'		:	200
						});
						// TODO: Take a look at this, it's for youtube videos in fancybox.
						//$("a.video").fancybox({
						//	'padding' : 0,
						//	'autoScale' : false,
						//	'transitionIn' : 'elastic',
						//	'transitionOut' : 'elastic',
						//	'speedIn' : 600,
						//	'speedOut': 200,
						//	'title' : this.title,
						//	'width' : 640,
						//	'height': 385,
						//	'href' : this.href.replace(new RegExp("watch\\?v=", "i"), 'v/'),
						//	'type' : 'swf',
						//	'swf' : {
						//		'wmode' : 'transparent',
						//		'allowfullscreen' : 'true'
						//	}
						//});

					});

				});
		});
		return posts;
}

function createTitle(entry, number){
	var post;

	// Emulate camel case, slice ridiculous title lengths, and remove characters.
	var title = entry.title
				.toLowerCase().substring(0,20).replace(/[^A-Za-z0-9\s\s+]/gi, '').split(' ');
	for (token in title){
		title[token] = title[token].charAt(0).toUpperCase() + title[token].slice(1);
	};
	title = title.join('');
	return title;
}

function grabHash(hash){
	return hash.replace('#','');
}

function getComments(raw_id, comment_location){
	// Retrieve and display comments
	var id = raw_id.replace('t3_', '');
	var text = '';
	var comment_url = 'http://www.reddit.com/comments/' + id + '.json?jsonp=?';
	var comments = $.getJSON(comment_url, function(comments){
		comments = comments[1].data.children.slice(0,20);
		$.each(comments, function(comment){
			template = "	$author = ${commenter};\n\
	$score = ${score}\n\
	//${text} \n\n\n"
			template = template.replace('${commenter}', comments[comment].data.author);
			template = template.replace('${score}', comments[comment].data.ups - comments[comment].data.downs);
			template = template.replace('${text}', comments[comment].data.body);
			text += template;

		});
		comment_location.text(text);

	});
	return text;
}
function formatSelfText(text){
	// If it's a self text we're going to output a large
	// comment block.
	text = text.replace(/(\r\n|\n|\r)/gm,"");
	var new_text = "";
	num_splits = Math.floor(text.length / 80);
	i = 0
	while (i <= num_splits){
		new_text = new_text + "// " + text.substring(i * 80, (i+1)*80) + "\n" + "    ";
		i++;
	}
	return new_text;
}<|endoftext|>


<commit_before>'use strict';

angular.module('lorryApp')
  .directive('serviceDefinitionDisplay', function ($log, lodash) {
    return {
      scope: {
        serviceDefinition: '='
      },
      restrict: 'E',
      replace: 'true',
      link: function postLink(scope, element, attrs) {
        //$log.log(scope.serviceDefinition);
      },
      templateUrl: '/scripts/directives/service-definition-display.html',
      controller: function ($scope) {
        $scope.hasLines = function () {
          if (lodash.any($scope.serviceDefinition)) {
            return !(/^(?:\s|-)/i.test($scope.serviceDefinition[0].text));
          }
        };

        $scope.classes = function () {
          return $scope.hasLines() && !$scope.$parent.inEditMode() && !$scope.$parent.inNewServiceMode() ? 'highlightable' : 'disabled';
        };

        $scope.serviceName = function () {
          return $scope.serviceDefinition[0].text.split(':')[0]
        };
      }
    };
  });
<commit_msg>refactoring service definition display directive to use link rather than controller<commit_after>'use strict';

angular.module('lorryApp')
  .directive('serviceDefinitionDisplay', ['lodash', function (lodash) {
    return {
      scope: {
        serviceDefinition: '='
      },
      restrict: 'E',
      replace: 'true',
      link: function postLink(scope) {
        scope.hasLines = function () {
          if (lodash.any(scope.serviceDefinition)) {
            return !(/^(?:\s|-)/i.test(scope.serviceDefinition[0].text));
          }
        };

        scope.classes = function () {
          return scope.hasLines() && !scope.$parent.inEditMode() && !scope.$parent.inNewServiceMode() ? 'highlightable' : 'disabled';
        };

        scope.serviceName = function () {
          return scope.serviceDefinition[0].text.split(':')[0]
        };
      },
      templateUrl: '/scripts/directives/service-definition-display.html'
    };
  }]);
<|endoftext|>


<commit_before>/* eslint-disable no-redeclare */

/* This module provides access to objects that are scoped to the lifespan of a
 * request.
 *
 * Use `getNamespace` to retrieve a module-level object provider.
 *
 * Note that `getNamespace` _returns a function_.  It should be called at the
 * module level.  The function that's returned must be called _for each access_.
 *
 * Example:
 *
 *   var RequestLocals = require('triton').RequestLocalStorage.getNamespace();
 *
 *   var getInstance = function(){
 *
 *     // Get a reference to _current_ request's locals.
 *     var locals = RequestLocals();
 *
 *     if (!locals.instance)
 *       locals.instance = new Instance();
 *
 *     return locals.instance;
 *   }
 *
 */

if (SERVER_SIDE){
	var key          = '_triton_request_local_storage_'
	,   cls          = require('continuation-local-storage').createNamespace(key)
	,   bind         = cls.bind.bind(cls)
	,   getContainer = () => cls.get(key)
	,   startRequest = (start) => { cls.run(() => {cls.set(key, []); start()}) }

	// Make sure our Q promises play well with continuation local storage.
	require('cls-q')(cls);
} else {
	var container    = []
	,   bind         = f  => f
	,   getContainer = () => container
	,   startRequest = () => container = []
}

var namespaces         = 0
,   getCountNamespaces = () => namespaces
,   getNamespace       = () => {

	// This will be our return value.
	var getter = (i => () => {
		var container = getContainer();
		if (!container){
			throw new Error("RLS() access outside of request!");
		}
		return container[i] || (container[i] = {});
	})(namespaces++);

	// This is guarded against old versions of node that don't provide the
	// necessary API (bamboo).
	if (SERVER_SIDE && Object.observe) {

		Object.observe(getter, changes => {

			// It's easy to make the mistake of using `RLS.foo`
			// instead of `RLS().foo`, but this is actually a very
			// bad error server-side.  It's a leak across requests.
			throw new Error(`Use of "RLS.${
				changes[0].name
			}" should be "RLS().${
				changes[0].name
			}"!`);
		});
	}

	return getter;
}

module.exports = { getNamespace, getCountNamespaces, startRequest, bind };
<commit_msg>Update commentary in RequestLocalStorage to match convention<commit_after>/* eslint-disable no-redeclare */

/* This module provides access to objects that are scoped to the lifespan of a
 * request.
 *
 * Use `getNamespace` to retrieve a module-level object provider.
 *
 * Note that `getNamespace` _returns a function_.  It should be called at the
 * module level.  The function that's returned must be called _for each access_.
 *
 * Example:
 *
 *   var RLS = require('triton').RequestLocalStorage.getNamespace();
 *
 *   var getInstance = function(){
 *
 *     // Get a reference to _current_ request's locals.
 *     var locals = RLS();
 *
 *     if (!locals.instance)
 *       locals.instance = new Instance();
 *
 *     return locals.instance;
 *   }
 *
 */

if (SERVER_SIDE){
	var key          = '_triton_request_local_storage_'
	,   cls          = require('continuation-local-storage').createNamespace(key)
	,   bind         = cls.bind.bind(cls)
	,   getContainer = () => cls.get(key)
	,   startRequest = (start) => { cls.run(() => {cls.set(key, []); start()}) }

	// Make sure our Q promises play well with continuation local storage.
	require('cls-q')(cls);
} else {
	var container    = []
	,   bind         = f  => f
	,   getContainer = () => container
	,   startRequest = () => container = []
}

var namespaces         = 0
,   getCountNamespaces = () => namespaces
,   getNamespace       = () => {

	// This will be our return value.
	var getter = (i => () => {
		var container = getContainer();
		if (!container){
			throw new Error("RLS() access outside of request!");
		}
		return container[i] || (container[i] = {});
	})(namespaces++);

	// This is guarded against old versions of node that don't provide the
	// necessary API (bamboo).
	if (SERVER_SIDE && Object.observe) {

		Object.observe(getter, changes => {

			// It's easy to make the mistake of using `RLS.foo`
			// instead of `RLS().foo`, but this is actually a very
			// bad error server-side.  It's a leak across requests.
			throw new Error(`Use of "RLS.${
				changes[0].name
			}" should be "RLS().${
				changes[0].name
			}"!`);
		});
	}

	return getter;
}

module.exports = { getNamespace, getCountNamespaces, startRequest, bind };
<|endoftext|>


<commit_before>(function (d, w, activeClass) {
    var hasTouch = (('ontouchstart' in w) || w.DocumentTouch && d instanceof DocumentTouch),
        docClass = d.documentElement.className;
    if (!hasTouch && (' '+docClass+' ').indexOf(' no-touch ') < 0) {
        d.documentElement.className += (docClass!=''?' ':'')+'no-touch';
    } else {
        var activeElement = null,
            clearActive = function() {
                if (activeElement) {
                    activeElement.classList.remove(activeClass);
                    activeElement = null;
                }
            },
            setActive = function(e) {
                clearActive();
                if (e.target.tagName == 'A') {
                    activeElement = e.target;
                    activeElement.classList.add(activeClass);
                }
            };
        d.documentElement.classList.add('touch');
        d.body.addEventListener('touchstart', setActive, false);
        d.body.addEventListener('touchmove', clearActive, false);
    }
})(document, window, 'active');
<commit_msg>refactored and added line to explicitly remove no-touch<commit_after>(function (d, w, activeClass) {
    var hasTouch = (('ontouchstart' in w) || w.DocumentTouch && d instanceof DocumentTouch);
    if (!hasTouch && (' ' + d.documentElement.className + ' ').indexOf(' no-touch ') < 0) {
        d.documentElement.className += ' no-touch';
    } else {
        var activeElement = null,
            clearActive = function() {
                if (activeElement) {
                    activeElement.classList.remove(activeClass);
                    activeElement = null;
                }
            },
            setActive = function(e) {
                clearActive();
                if (e.target.tagName == 'A') {
                    activeElement = e.target;
                    activeElement.classList.add(activeClass);
                }
            };
        d.documentElement.classList.add('touch');
        d.documentElement.classList.remove('no-touch');
        d.body.addEventListener('touchstart', setActive, false);
        d.body.addEventListener('touchmove', clearActive, false);
    }
})(document, window, 'active');
<|endoftext|>


<commit_before>/*
 * @requires FaultedEarth.js
 */

FaultedEarth.SimpleGeometryForm = Ext.extend(gxp.plugins.Tool, {

    ptype: "app_simplegeometryform",

    /** api: config[featureManager]
     *  ``String`` id of the FeatureManager to add uploaded features to
     */

    /** api: config[featureEditor]
     *  ``String`` id of the FeatureEditor to modify uploaded features
     */

    /** api: config[temporaryWorkspace]
     *  ``String`` temporary GeoServer workspace for shapefile uploads.
     *  Default is "temp".
     */
    temporaryWorkspace: "temp",

    /** api: config[temporaryWorkspaceNamespaceUri]
     *  ``String`` namespace uri of the temporary GeoServer workspace for
     *  shapefile uploads. Default is "http://geonode.org/temporary".
     */
    temporaryWorkspaceNamespaceUri: "http://geonode.org/temporary",

    /** private: property[sessionFids]
     *  ``Array`` fids of features added/modified in this session
     */
    sessionFids: null,

    autoActivate: false,

    init: function(target) {
        FaultedEarth.SimpleGeometryForm.superclass.init.apply(this, arguments);

        this.sessionFids = [];
        var featureManager = target.tools[this.featureManager];
        featureManager.featureLayer.events.on({
            "featureselected": function(e) {
                if (!e.feature.fid) {
                    return;
                }
                if (featureManager.layerRecord.get("name") == "geonode:observations_fault") {
                    this.target.summaryId = e.feature.fid;
                }
            },
            "featureunselected": function(e) {
                if (this.active && featureManager.layerRecord.get("name") == "geonode:observations_fault") {
                    this.target.summaryId = null;
                }
            },
            scope: this
        });
    },

    addOutput: function(config) {
        return FaultedEarth.SimpleGeometryForm.superclass.addOutput.call(this, {
            xtype: "form",
            labelWidth: 110,
            defaults: {
                anchor: "100%"
            },
            items: [{
                xtype: "box",
                autoEl: {
                    tag: "p",
                    cls: "x-form-item"
                },
                html: "Select a fault from the grid below, then use the draw or modify button to create a simplified geometry that will be used to create a fault source"
            },{
                xtype: "container",
                layout: "hbox",
                cls: "composite-wrap",
                fieldLabel: "Create or edit a simplified fault geometry",
                items: [{
                    id: this.id + "_tooltarget",
                    xtype: "container",
                    cls: "toolbar-spaced",
                    layout: "toolbar"
                }]
            }, {
                xtype: "box",
                autoEl: {
                    tag: "p",
                    cls: "x-form-item"
                },
                html: "Once a fault has the required attributes, and simplified geometry, select a fault from the grid and use the 'generate' button to calculate a fault source."
            }, {
                xtype: "container",
                layout: "hbox",
                fieldLabel: "Generate Fault Source",
                items: [{
                    xtype: "button",
                    text: "Generate",
                    iconCls: "icon-layer-switcher",
                    handler: function() {
                        var featureManager = this.target.tools[this.featureManager];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: this.target.localGeoNodeUrl + this.target.localHostname + '/observations/faultsource/create',
                            params: Ext.encode({fault_id: this.target.summaryId, name: ''}),
                            success: function(response, opts) {
                                alert('Fault source generated');
                            },
                            failure: function(response, opts){
                                alert('Failed to generate the Fault source');
                            },

                            scope: this
                        });

                    },
                    scope: this
                    }]
             }],
            listeners: {
                "added": function(cmp, ct) {
                    ct.on({
                        "expand": function() { this.activate(); },
                        "collapse": function() { this.deactivate(); },
                        scope: this
                    });
                },
                scope: this
            }
        });
    },

    activate: function() {
        if (FaultedEarth.SimpleGeometryForm.superclass.activate.apply(this, arguments)) {
            var featureManager = this.target.tools[this.featureManager];
            featureManager.setLayer();
            if (!this.layerRecord) {
                this.target.createLayerRecord({
                    name: "geonode:observations_fault",
                    source: "local"
                }, function(record) {
                    this.layerRecord = record;
                    featureManager.setLayer(record);
                }, this);
            } else {
                featureManager.setLayer(this.layerRecord);
            }
            featureManager.on("layerchange", function(mgr, rec) {
                mgr.featureStore.on({
                    "save": function(store, batch, data) {
                        var fid;
                        for (var action in data) {
                            for (var i=data[action].length-1; i>=0; --i) {
                                fid = data[action][i].feature.fid;
                                this.sessionFids.remove(fid);
                                if (action != "destroy") {
                                    this.sessionFids.push(fid);
                                }
                            }
                        }
                    },
                    "load": function() {
                        this.target.summaryId && window.setTimeout((function() {
                            var feature = mgr.featureLayer.getFeatureByFid(this.target.summaryId);
                            if (feature && feature.layer.selectedFeatures.indexOf(feature) == -1) {
                                feature.layer.selectedFeatures.push(feature);
                                feature.layer.events.triggerEvent("featureselected", {feature: feature});
                            }
                        }).createDelegate(this), 0);
                    },
                    scope: this
                });
            }, this, {single: true});
        }
    },

    deactivate: function() {
        if (FaultedEarth.SimpleGeometryForm.superclass.deactivate.apply(this, arguments)) {
            this.target.tools[this.featureManager].featureStore.un("save", this.monitorSave, this);
        }
    },

    showUploadWindow: function() {
        var uploadWindow = new Ext.Window({
            title: "Import Faults",
            width: 250,
            autoHeight: true,
            modal: true,
            items: [{
                xtype: "form",
                ref: "form",
                padding: 10,
                border: false,
                autoHeight: true,
                labelWidth: 40,
                defaults: {
                    anchor: "100%"
                },
                items: [{
                    xtype: "box",
                    autoEl: {
                        tag: "p",
                        cls: "x-form-item"
                    },
                    html: "Select a zipped shapefile for uploading. The shapefile needs to have a line geometry."
                }, {
                    xtype: "fileuploadfield",
                    ref: "fileField",
                    fieldLabel: "File",
                    allowBlank: false,
                    listeners: {
                        "fileselected": function(field, file) {
                            field.ownerCt.uploadButton.enable();
                        }
                    }
                }],
                buttonAlign: "center",
                buttons: [{
                    text: "Upload",
                    ref: "../uploadButton",
                    disabled: true,
                    handler: function() {
                        var file = uploadWindow.form.fileField.fileInput.dom.files[0];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: this.target.localGeoServerUrl + "rest/workspaces/" +
                                this.temporaryWorkspace + "/datastores/" +
                                file.fileName + "/file.shp?update=overwrite",
                            xmlData: file,
                            headers: {
                                "Content-Type": file.fileName.split(".").pop().toLowerCase() == "zip" ?
                                    "application/zip" : file.type
                            },
                            success: this.handleUpload.createDelegate(this,
                                [file.fileName, uploadWindow], true),
                            scope: this
                        });
                    },
                    scope: this
                }]
            }]
        });
        uploadWindow.show();
    },

    handleUpload: function(response, options, fileName, uploadWindow) {
        uploadWindow.close();
        var fileParts = fileName.split(".");
        fileParts.pop();
        var layerName = fileParts.join("");
        new OpenLayers.Protocol.WFS({
            version: "1.1.0",
            srsName: this.target.mapPanel.map.getProjectionObject().getCode(),
            url: this.target.localGeoServerUrl + "wfs",
            featureType: layerName,
            featureNS: this.temporaryWorkspaceNamespaceUri,
            outputFormat: "GML2"
        }).read({
            callback: function(response) {
                var extent = new OpenLayers.Bounds();
                var features = response.features, feature, date;
                for (var i=features.length-1; i>=0; --i) {
                    feature = features[i];
                    extent.extend(feature.geometry.getBounds());
                    feature.fid = null;
                    feature.state = OpenLayers.State.UPDATE;
                    // convert dates
                    for (var a in feature.attributes) {
                        date = Date.parseDate(feature.attributes[a], "Y/m/d");
                        if (date) {
                            feature.attributes[a] = date.format("c");
                        }
                    }
                }
                var featureManager = this.target.tools[this.featureManager];
                featureManager.featureLayer.addFeatures(features);
                featureManager.featureStore.save();

                var featureEditor = this.target.tools[this.featureEditor];
                featureEditor.actions[1].control.activate();
                this.target.mapPanel.map.zoomToExtent(extent);
            },
            scope: this
        });
        //TODO remove uploaded layer/store/style or call GeoNode updatelayers
    }

});

Ext.preg(FaultedEarth.SimpleGeometryForm.prototype.ptype, FaultedEarth.SimpleGeometryForm);
<commit_msg>put the insert back, the "update" was just a test<commit_after>/*
 * @requires FaultedEarth.js
 */

FaultedEarth.SimpleGeometryForm = Ext.extend(gxp.plugins.Tool, {

    ptype: "app_simplegeometryform",

    /** api: config[featureManager]
     *  ``String`` id of the FeatureManager to add uploaded features to
     */

    /** api: config[featureEditor]
     *  ``String`` id of the FeatureEditor to modify uploaded features
     */

    /** api: config[temporaryWorkspace]
     *  ``String`` temporary GeoServer workspace for shapefile uploads.
     *  Default is "temp".
     */
    temporaryWorkspace: "temp",

    /** api: config[temporaryWorkspaceNamespaceUri]
     *  ``String`` namespace uri of the temporary GeoServer workspace for
     *  shapefile uploads. Default is "http://geonode.org/temporary".
     */
    temporaryWorkspaceNamespaceUri: "http://geonode.org/temporary",

    /** private: property[sessionFids]
     *  ``Array`` fids of features added/modified in this session
     */
    sessionFids: null,

    autoActivate: false,

    init: function(target) {
        FaultedEarth.SimpleGeometryForm.superclass.init.apply(this, arguments);

        this.sessionFids = [];
        var featureManager = target.tools[this.featureManager];
        featureManager.featureLayer.events.on({
            "featureselected": function(e) {
                if (!e.feature.fid) {
                    return;
                }
                if (featureManager.layerRecord.get("name") == "geonode:observations_fault") {
                    this.target.summaryId = e.feature.fid;
                }
            },
            "featureunselected": function(e) {
                if (this.active && featureManager.layerRecord.get("name") == "geonode:observations_fault") {
                    this.target.summaryId = null;
                }
            },
            scope: this
        });
    },

    addOutput: function(config) {
        return FaultedEarth.SimpleGeometryForm.superclass.addOutput.call(this, {
            xtype: "form",
            labelWidth: 110,
            defaults: {
                anchor: "100%"
            },
            items: [{
                xtype: "box",
                autoEl: {
                    tag: "p",
                    cls: "x-form-item"
                },
                html: "Select a fault from the grid below, then use the draw or modify button to create a simplified geometry that will be used to create a fault source"
            },{
                xtype: "container",
                layout: "hbox",
                cls: "composite-wrap",
                fieldLabel: "Create or edit a simplified fault geometry",
                items: [{
                    id: this.id + "_tooltarget",
                    xtype: "container",
                    cls: "toolbar-spaced",
                    layout: "toolbar"
                }]
            }, {
                xtype: "box",
                autoEl: {
                    tag: "p",
                    cls: "x-form-item"
                },
                html: "Once a fault has the required attributes, and simplified geometry, select a fault from the grid and use the 'generate' button to calculate a fault source."
            }, {
                xtype: "container",
                layout: "hbox",
                fieldLabel: "Generate Fault Source",
                items: [{
                    xtype: "button",
                    text: "Generate",
                    iconCls: "icon-layer-switcher",
                    handler: function() {
                        var featureManager = this.target.tools[this.featureManager];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: this.target.localGeoNodeUrl + this.target.localHostname + '/observations/faultsource/create',
                            params: Ext.encode({fault_id: this.target.summaryId, name: ''}),
                            success: function(response, opts) {
                                alert('Fault source generated');
                            },
                            failure: function(response, opts){
                                alert('Failed to generate the Fault source');
                            },

                            scope: this
                        });

                    },
                    scope: this
                    }]
             }],
            listeners: {
                "added": function(cmp, ct) {
                    ct.on({
                        "expand": function() { this.activate(); },
                        "collapse": function() { this.deactivate(); },
                        scope: this
                    });
                },
                scope: this
            }
        });
    },

    activate: function() {
        if (FaultedEarth.SimpleGeometryForm.superclass.activate.apply(this, arguments)) {
            var featureManager = this.target.tools[this.featureManager];
            featureManager.setLayer();
            if (!this.layerRecord) {
                this.target.createLayerRecord({
                    name: "geonode:observations_fault",
                    source: "local"
                }, function(record) {
                    this.layerRecord = record;
                    featureManager.setLayer(record);
                }, this);
            } else {
                featureManager.setLayer(this.layerRecord);
            }
            featureManager.on("layerchange", function(mgr, rec) {
                mgr.featureStore.on({
                    "save": function(store, batch, data) {
                        var fid;
                        for (var action in data) {
                            for (var i=data[action].length-1; i>=0; --i) {
                                fid = data[action][i].feature.fid;
                                this.sessionFids.remove(fid);
                                if (action != "destroy") {
                                    this.sessionFids.push(fid);
                                }
                            }
                        }
                    },
                    "load": function() {
                        this.target.summaryId && window.setTimeout((function() {
                            var feature = mgr.featureLayer.getFeatureByFid(this.target.summaryId);
                            if (feature && feature.layer.selectedFeatures.indexOf(feature) == -1) {
                                feature.layer.selectedFeatures.push(feature);
                                feature.layer.events.triggerEvent("featureselected", {feature: feature});
                            }
                        }).createDelegate(this), 0);
                    },
                    scope: this
                });
            }, this, {single: true});
        }
    },

    deactivate: function() {
        if (FaultedEarth.SimpleGeometryForm.superclass.deactivate.apply(this, arguments)) {
            this.target.tools[this.featureManager].featureStore.un("save", this.monitorSave, this);
        }
    },

    showUploadWindow: function() {
        var uploadWindow = new Ext.Window({
            title: "Import Faults",
            width: 250,
            autoHeight: true,
            modal: true,
            items: [{
                xtype: "form",
                ref: "form",
                padding: 10,
                border: false,
                autoHeight: true,
                labelWidth: 40,
                defaults: {
                    anchor: "100%"
                },
                items: [{
                    xtype: "box",
                    autoEl: {
                        tag: "p",
                        cls: "x-form-item"
                    },
                    html: "Select a zipped shapefile for uploading. The shapefile needs to have a line geometry."
                }, {
                    xtype: "fileuploadfield",
                    ref: "fileField",
                    fieldLabel: "File",
                    allowBlank: false,
                    listeners: {
                        "fileselected": function(field, file) {
                            field.ownerCt.uploadButton.enable();
                        }
                    }
                }],
                buttonAlign: "center",
                buttons: [{
                    text: "Upload",
                    ref: "../uploadButton",
                    disabled: true,
                    handler: function() {
                        var file = uploadWindow.form.fileField.fileInput.dom.files[0];
                        Ext.Ajax.request({
                            method: "PUT",
                            url: this.target.localGeoServerUrl + "rest/workspaces/" +
                                this.temporaryWorkspace + "/datastores/" +
                                file.fileName + "/file.shp?update=overwrite",
                            xmlData: file,
                            headers: {
                                "Content-Type": file.fileName.split(".").pop().toLowerCase() == "zip" ?
                                    "application/zip" : file.type
                            },
                            success: this.handleUpload.createDelegate(this,
                                [file.fileName, uploadWindow], true),
                            scope: this
                        });
                    },
                    scope: this
                }]
            }]
        });
        uploadWindow.show();
    },

    handleUpload: function(response, options, fileName, uploadWindow) {
        uploadWindow.close();
        var fileParts = fileName.split(".");
        fileParts.pop();
        var layerName = fileParts.join("");
        new OpenLayers.Protocol.WFS({
            version: "1.1.0",
            srsName: this.target.mapPanel.map.getProjectionObject().getCode(),
            url: this.target.localGeoServerUrl + "wfs",
            featureType: layerName,
            featureNS: this.temporaryWorkspaceNamespaceUri,
            outputFormat: "GML2"
        }).read({
            callback: function(response) {
                var extent = new OpenLayers.Bounds();
                var features = response.features, feature, date;
                for (var i=features.length-1; i>=0; --i) {
                    feature = features[i];
                    extent.extend(feature.geometry.getBounds());
                    feature.fid = null;
                    feature.state = OpenLayers.State.INSERT;
                    // convert dates
                    for (var a in feature.attributes) {
                        date = Date.parseDate(feature.attributes[a], "Y/m/d");
                        if (date) {
                            feature.attributes[a] = date.format("c");
                        }
                    }
                }
                var featureManager = this.target.tools[this.featureManager];
                featureManager.featureLayer.addFeatures(features);
                featureManager.featureStore.save();

                var featureEditor = this.target.tools[this.featureEditor];
                featureEditor.actions[1].control.activate();
                this.target.mapPanel.map.zoomToExtent(extent);
            },
            scope: this
        });
        //TODO remove uploaded layer/store/style or call GeoNode updatelayers
    }

});

Ext.preg(FaultedEarth.SimpleGeometryForm.prototype.ptype, FaultedEarth.SimpleGeometryForm);
<|endoftext|>


<commit_before>
var logger = require('./logger').cell2coords;

var request = require('request');

var convert_single = function(params, callback) {

  if ( (params.cid === undefined) || (params.lac === undefined) ) {
    callback(new Error ("Invalid parameters, object must have keys {cid, lac}"));
    return;
  }

  var apikey = process.env.GOOGLE_GEOLOCATION_KEY || 'test'

  var url = 'https://www.googleapis.com/geolocation/v1/geolocate?key=' + apikey;

  var post_params = {
    "cellTowers": [{
      "locationAreaCode": params.lac,
      "cellId": params.cid,
    }]
  };

  request.post(url, post_params, function (error, response, body) {
    if (error) {
      callback(new Error('request returned error ' + error))
    }
    else if (response.statusCode != 200) {
      callback(new Error('API call returned status code ' + response.statusCode))
    }
    else {
      var obj = JSON.parse(body);
      if (obj.hasOwnProperty('location')) {
        logger.debug('got location from API', body)
        callback(null, {lat: obj.location.lat, lng: obj.location.lng})
      }
      else if (obj.hasOwnProperty('error')) {
        callback(new Error(JSON.stringify(obj.error)))
      }
      else {
        callback(new Error('Unknown response ' + JSON.stringify(obj)))
      }
    }
  })
};

var convert_list = function(params, callback) {

  if (Array.isArray(params) === false) {
    callback(new Error ("Invalid parameters, object must be an array"));
    /* TODO: check for array contents also */
    return;
  }

  var apikey = process.env.GOOGLE_GEOLOCATION_KEY || 'test'

  var url = 'https://www.googleapis.com/geolocation/v1/geolocate?key=' + apikey;

  var cell_towers = [];

  for (let antenna of params) {
    cell_towers.push({
      "mobileCountryCode": antenna.mcc,
      "mobileNetworkCode": antenna.mnc,
      "locationAreaCode":  antenna.lac,
      "cellId":            antenna.ci,
      "signalStrength":    -antenna.rxlev
    });
  }

  var post_params = {
    "radioType" : "gsm",
    "cellTowers": cell_towers
  };

  logger.debug("POST", post_params);

  request.post(url, post_params, function (error, response, body) {
    if (error) {
      callback(new Error('request returned error ' + error))
    }
    else if (response.statusCode != 200) {
      callback(new Error('API call returned status code ' + response.statusCode))
    }
    else {
      var obj = JSON.parse(body);
      if (obj.hasOwnProperty('location')) {
        logger.debug('got location from API', body)
        callback(null, {'lat': obj.location.lat, 'lng': obj.location.lng, 'acc': obj.accuracy})
      }
      else if (obj.hasOwnProperty('error')) {
        callback(new Error(JSON.stringify(obj.error)))
      }
      else {
        callback(new Error('Unknown response ' + JSON.stringify(obj)))
      }
    }
  })
};

module.exports = {
  'single': convert_single,
  'list':   convert_list
}
<commit_msg>ISSUE #41 Refactor cell2coords module<commit_after>
var logger = require('./logger').cell2coords;

var request = require('request');

var apikey = process.env.GOOGLE_GEOLOCATION_KEY || 'test'
var url = 'https://www.googleapis.com/geolocation/v1/geolocate?key=' + apikey;

var convert_single = function(params, callback) {

  if ( (params.cid === undefined) || (params.lac === undefined) ) {
    callback(new Error ("Invalid parameters, object must have keys {cid, lac}"));
    return;
  }

  var post_params = {
    "cellTowers": [{
      "locationAreaCode": params.lac,
      "cellId": params.cid,
    }]
  };

  _post_request(post_params, callback);
};

var convert_list = function(params, callback) {

  if (Array.isArray(params) === false) {
    callback(new Error ("Invalid parameters, object must be an array"));
    /* TODO: check for array contents also */
    return;
  }

  var cell_towers = [];

  for (let antenna of params) {
    cell_towers.push({
      "mobileCountryCode": antenna.mcc,
      "mobileNetworkCode": antenna.mnc,
      "locationAreaCode":  antenna.lac,
      "cellId":            antenna.ci,
      "signalStrength":    -antenna.rxlev
    });
  }

  var post_params = {
    "radioType" : "gsm",
    "cellTowers": cell_towers
  };

  _post_request(post_params, callback);
};

var _post_request = function(post_params, callback)
{
  logger.debug("POST", post_params);

  request.post(url, post_params, function (error, response, body) {
    if (error) {
      callback(new Error('request returned error ' + error))
    }
    else if (response.statusCode != 200) {
      callback(new Error('API call returned status code ' + response.statusCode))
    }
    else {
      var obj = JSON.parse(body);
      if (obj.hasOwnProperty('location')) {
        logger.debug('got location from API', body)
        callback(null, {'lat': obj.location.lat, 'lng': obj.location.lng, 'acc': obj.accuracy})
      }
      else if (obj.hasOwnProperty('error')) {
        callback(new Error(JSON.stringify(obj.error)))
      }
      else {
        callback(new Error('Unknown response ' + JSON.stringify(obj)))
      }
    }
  })
};

module.exports = {
  'single': convert_single,
  'list':   convert_list
}
<|endoftext|>


<commit_before>/*
* Used to generate a list of roles that are both lower than the bot's role, and subscribed to feeds
* Returns the feed source and the role list
*/

module.exports = (guild, rssList) => {
  let finalList = []
  const botRole = guild.members.get(guild.client.user.id).highestRole
  for (var rssName in rssList) {
    let subscribersFound = []
    const keys = ['globalSubscriptions', 'filteredSubscriptions']
    const source = rssList[rssName]
    for (const key of keys) {
      const subscriptions = source[key]
      if (!Array.isArray(subscriptions) || subscriptions.length === 0) continue
      for (const subscriber of subscriptions) {
        if (subscriber.type === 'role') {
          const role = guild.roles.get(subscriber.id)
          if (role.comparePositionTo(botRole) < 0) subscribersFound.push(role.id)
        }
      }
    }

    if (subscribersFound.length !== 0) finalList.push({ source: rssList[rssName], roleList: subscribersFound })
  }

  if (finalList.length === 0) return null
  return finalList
}
<commit_msg>Fix subme/unsubme not seeing subscriptions<commit_after>/*
* Used to generate a list of roles that are both lower than the bot's role, and subscribed to feeds
* Returns the feed source and the role list
*/

module.exports = (guild, rssList) => {
  let finalList = []
  const botRole = guild.members.get(guild.client.user.id).highestRole
  for (var rssName in rssList) {
    let subscribersFound = []
    const source = rssList[rssName]
    const subscribers = source.subscribers
    if (!Array.isArray(subscribers) || subscribers.length === 0) continue
    for (const subscriber of subscribers) {
      if (subscriber.type === 'role') {
        const role = guild.roles.get(subscriber.id)
        if (role.comparePositionTo(botRole) < 0) subscribersFound.push(role.id)
      }
    }

    if (subscribersFound.length !== 0) finalList.push({ source: rssList[rssName], roleList: subscribersFound })
  }

  if (finalList.length === 0) return null
  return finalList
}
<|endoftext|>