<commit_before>"use strict";

var SF = SF || {};

if (!SF.Utils) {

SF.Utils = true;
SF.debug = true;

SF.registerModule = (function () {
    var modules = [];

    return function (module, cb) {
        if ($.inArray(module, modules)===-1) {
            modules.push(module);
            cb();
        }
    }
})();

    SF.Loader = (function () {

        var _jsSet = [],
            _jsloaded = [];

        function setLoaded(url, position) {
            _jsloaded[url] = true;
            _jsSet[position].count--;

            if (_jsSet[position].count === 0) {
                _jsSet[position].func && _jsSet[position].func();
                delete _jsSet[position];
            }
        }

        function _loadJs(url, position) {
            if (!_jsloaded[url]) {
                $.getScript(url, function () {
                    setLoaded(url, position);
                });
            } else {
                setLoaded(url, position);
            }
        }

        function loadJs(url, fn) {
            if (typeof url === "object") {  //more than one file
                var position = _jsSet.length;

                _jsSet[position] = {
                    count: url.length,
                    func: fn
                };

                var i;
                for (i = 0; i < url.length; i++) {
                    _loadJs(url[i], position);
                }
            } else {
                $.getScript(url, fn);
            }
        }

        return {
            loadJs: loadJs
};
})();

(function (options) {
    var pendingRequests = 0;

    $.ajaxSetup({
        type: "POST",
        sfCheckRedirection: true,
        sfNotify: true
    });

    var checkRedirection = function (ajaxResult) {
        if (SF.isEmpty(ajaxResult)) {
            return null;
        }
        if (typeof ajaxResult !== "object") {
            return null;
        }
        if (ajaxResult.result == null) {
            return null;
        }
        if (ajaxResult.result == 'url') {
            return ajaxResult.url;
        }
        return null;
    };

    $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
        if (options.dataType == "script" && (typeof originalOptions.type == "undefined")) {
            options.type = "GET";
        }
        if (options.sfNotify) {
            pendingRequests++;
            if (pendingRequests == 1) {
                if (typeof (lang) != "undefined") {
                    SF.Notify.info(lang.signum.loading);
                }
            }
        }
        if (options.sfCheckRedirection) {
            var originalSuccess = options.success;

            options.success = function (result) {
                pendingRequests--;
                if (pendingRequests <= 0) {
                    pendingRequests = 0;
                    SF.Notify.clear();
                }
                if (typeof result === "string") {
                    result = result ? result.trim() : "";
                }
                var url = checkRedirection(result);
                if (!SF.isEmpty(url)) {
                    window.location.href = url;
                }
                else {
                    if (originalSuccess != null) {
                        originalSuccess(result);
                    }
                }
            };
        }
    });

    $(document).ajaxError(function (event, XMLHttpRequest, ajaxOptions, thrownError) {
        //check request status
        //request.abort() has status 0, so we don't show this "error", since we have
        //explicitly aborted the request.
        //this error is documented on http://bugs.jquery.com/ticket/7189
        if (XMLHttpRequest.status !== 0) {
            $("body").trigger("sf-ajax-error", [XMLHttpRequest, ajaxOptions, thrownError]);
            pendingRequests = 0;
        }
    });
})();

SF.stopPropagation = function (event) {
        if (event.stopPropagation) event.stopPropagation();
    else
        event.cancelBubble = true;
}

SF.isFalse = function (value) {
    return value == false || value == "false" || value == "False";
};

SF.isTrue = function (value) {
    return value == true || value == "true" || value == "True";
};

SF.isEmpty = function (value) {
    return (value == undefined || value == null || value === "" || value.toString() == "");
};

    String.prototype.hasText = function () {
        return (this == null || this == undefined || this == '') ? false : true;
    }

String.prototype.startsWith = function (str) {
    return (this.indexOf(str) === 0);
}

String.prototype.format = function (values) {
    var regex = /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g;

    var getValue = function (key) {
            if (values == null || typeof values === 'undefined') return null;

        var value = values[key];
        var type = typeof value;

        return type === 'string' || type === 'number' ? value : null;
    };

    return this.replace(regex, function (match) {
        //match will look like {sample-match}
        //key will be 'sample-match';
        var key = match.substr(1, match.length - 2);

        var value = getValue(key);

        return value != null ? value : match;
    });
};

    String.prototype.replaceAll = function (s1, s2) {
        return this.split(s1).join(s2)
    };

if (typeof String.prototype.trim !== 'function') {
    String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/, '');
    }
}

SF.log = function (s) {
    if (SF.debug) {
            if (typeof console != "undefined" && typeof console.debug != "undefined") console.log(s);
    }
}

/* show messages on top (info, error...) */
SF.Notify = (function () {
    var $messageArea, timer, css;

    var error = function (s, t) {
        info(s, t, 'sf-error');
    };

    var info = function (s, t, cssClass) {
        SF.Notify.clear();
        css = (cssClass != undefined ? cssClass : "sf-info");
        $messageArea = $("#sfMessageArea");
        if ($messageArea.length == 0) {
            $messageArea = $("

").hide().prependTo($("body"));
        }

        $messageArea.find("span").html(s);
        $messageArea.children().first().addClass(css);
        $messageArea.css({
            marginLeft: -parseInt($messageArea.outerWidth() / 2)
        }).show();

        if (t != undefined) {
            timer = setTimeout(clear, t);
        }
    };

    var clear = function () {
        if ($messageArea) {
            $messageArea.hide().children().first().removeClass(css);
            if (timer != null) {
                clearTimeout(timer);
                timer = null;
            }
        }
    }

    return {
        error: error,
        info: info,
        clear: clear
    };
})();

SF.InputValidator = {
    isNumber: function (e) {
        var c = e.keyCode;
            return ((c >= 48 && c <= 57) /*0-9*/ ||
			(c >= 96 && c <= 105) /*NumPad 0-9*/ ||
			(c == 8) /*BackSpace*/ ||
			(c == 9) /*Tab*/ ||
			(c == 12) /*Clear*/ ||
			(c == 27) /*Escape*/ ||
			(c == 37) /*Left*/ ||
			(c == 39) /*Right*/ ||
			(c == 46) /*Delete*/ ||
			(c == 36) /*Home*/ ||
			(c == 35) /*End*/ ||
			(c == 109) /*NumPad -*/ ||
            (c == 189) /*-*/ ||
            (e.ctrlKey && c == 86) /*Ctrl + v*/ ||
            (e.ctrlKey && c == 67) /*Ctrl + v*/
        );
    },

    isDecimal: function (e) {
        var c = e.keyCode;
        return (
            this.isNumber(e) ||
            (c == 110) /*NumPad Decimal*/ ||
            (c == 190) /*.*/ ||
			(c == 188) /*,*/
		);
    }
};

(function ($) {
    $.fn.placeholder = function () {
        if ($.fn.placeholder.supported()) {
            return $(this);
        } else {

            $(this).parent('form').submit(function (e) {
                $('input[placeholder].sf-placeholder, textarea[placeholder].sf-placeholder', this).val('');
            });

            $(this).each(function () {
                $.fn.placeholder.on(this);
            });

            return $(this)

        .focus(function () {
            if ($(this).hasClass('sf-placeholder')) {
                $.fn.placeholder.off(this);
            }
        })

        .blur(function () {
            if ($(this).val() == '') {
                $.fn.placeholder.on(this);
            }
        });
        }
    };

    // Extracted from: http://diveintohtml5.org/detect.html#input-placeholder
    $.fn.placeholder.supported = function () {
        var input = document.createElement('input');
        return !!('placeholder' in input);
    };

    $.fn.placeholder.on = function (el) {
        var $el = $(el);
        if ($el.val() == '') $el.val($el.attr('placeholder')).addClass('sf-placeholder');
    };

    $.fn.placeholder.off = function (el) {
        $(el).val('').removeClass('sf-placeholder');
    };
})(jQuery);

SF.Cookies = {
    read: function (name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
        }
        return null;
    },

    create: function (name, value, days, domain) {
        var expires = null,
                path = "/";

        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            expires = date;
        }

            document.cookie = name + "=" + escape(value) + ((expires) ? ";expires=" + expires.toGMTString() : "") + ((path) ? ";path=" + path : "") + ((domain) ? ";domain=" + domain : "");
    }
};

SF.LocalStorage = (function () {
    var isSupported = typeof (localStorage) != 'undefined';

    var getItem = function (key) {
        if (isSupported) {
                try {
                    return localStorage.getItem(key);
                } catch (e) { }
        }
        return SF.Cookies.read(key);
    };

    var setItem = function (key, value, days) {
        if (isSupported) {
                try {
                    localStorage.setItem(key, value);
                    return true;
                } catch (e) { }
        }
        SF.Cookies.create(key, value, days ? days : 30);
    };

        return {
            getItem: getItem,
            setItem: setItem
        };
    })();

    SF.triggerNewContent = function ($source) {
        $source.trigger("sf-new-content");
    }
}

SF.NewContentProcessor = {
    defaultButtons: function ($newContent) {
        $newContent.find(".sf-entity-button, .sf-query-button, .sf-line-button, .sf-chooser-button, .sf-button").each(function (i, val) {
            var $txt = $(val);
            if (!$txt.hasClass("ui-button") && !$txt.closest(".sf-menu-button").length > 0) {
                var data = $txt.data();
                $txt.button({
                    text: (!("text" in data) || SF.isTrue(data.text)),
                    icons: { primary: data.icon, secondary: data.iconSecondary },
                    disabled: $txt.hasClass("sf-disabled")
                });
            }
        });
    },

    defaultDatepicker: function ($newContent) {
        $newContent.find(".sf-datepicker").each(function (i, val) {
            var $txt = $(val);
            $txt.datepicker(jQuery.extend({}, SF.Locale.defaultDatepickerOptions, { dateFormat: $txt.attr("data-format") }));
        });
    },

    defaultDropdown: function ($newContent) {
        $newContent.find(".sf-dropdown .sf-menu-button")
            .addClass("ui-autocomplete ui-menu ui-widget ui-widget-content ui-corner-all")
            .find("li")
            .addClass("ui-menu-item")
            .find("a")
            .addClass("ui-corner-all");
    },

    defaultAutocomplete: function ($newContent) {
        $newContent.find(".sf-entity-autocomplete").each(function (i, val) {
            var $txt = $(val);
            var data = $txt.data();
            $.SF.entityLine.prototype.entityAutocomplete($txt, { delay: 200, types: data.types, url: data.url || SF.Urls.autocomplete, count: 5 });
        });
    },

    defaultPlaceholder: function ($newContent) {
        $newContent.find('input[placeholder], textarea[placeholder]').placeholder();
    },

    defaultTabs: function ($newContent) {
        var $tabContainer = $newContent.find(".sf-tabs:not(.ui-tabs)").prepend($("

"));

        $tabContainer.tabs();

        var $tabs = $tabContainer.children("fieldset");
        $tabs.each(function () {
            var $this = $(this);
            var $legend = $this.children("legend");
            if ($legend.length == 0) {
                $this.prepend("¡¡¡NO LEGEND SPECIFIED!!!");
                throw "No legend specified for tab";
            }
            var legend = $legend.html();

            var id = $this.attr("id");
            if (SF.isEmpty(id)) {
                $legend.html(legend + " ¡¡¡NO TAB ID SET!!!");
                throw "No id set for tab with legend: " + legend;
            }
            else {
                $("
" + legend + "
")
                    .appendTo($tabContainer.find(".ui-tabs-nav"));
                $legend.remove();
            }
        });

        $tabContainer.tabs("refresh");
        $tabContainer.tabs("option", "active", 0);
    },

    defaultSlider: function ($newContent) {
        $newContent.find(".sf-search-results-container").each(function (i, val) {
            new SF.slider(jQuery(val));
        });
    },

    defaultModifiedChecker: function ($newContent) {
        $newContent.find(":input").on("change", function() {
            var $mainControl = $(this).closest(".sf-main-control");
            if ($mainControl.length > 0) {
                $mainControl.addClass("sf-changed");
            }
        });
    }
};<commit_msg>fix String.format<commit_after>"use strict";

var SF = SF || {};

if (!SF.Utils) {

SF.Utils = true;
SF.debug = true;

SF.registerModule = (function () {
    var modules = [];

    return function (module, cb) {
        if ($.inArray(module, modules)===-1) {
            modules.push(module);
            cb();
        }
    }
})();

    SF.Loader = (function () {

        var _jsSet = [],
            _jsloaded = [];

        function setLoaded(url, position) {
            _jsloaded[url] = true;
            _jsSet[position].count--;

            if (_jsSet[position].count === 0) {
                _jsSet[position].func && _jsSet[position].func();
                delete _jsSet[position];
            }
        }

        function _loadJs(url, position) {
            if (!_jsloaded[url]) {
                $.getScript(url, function () {
                    setLoaded(url, position);
                });
            } else {
                setLoaded(url, position);
            }
        }

        function loadJs(url, fn) {
            if (typeof url === "object") {  //more than one file
                var position = _jsSet.length;

                _jsSet[position] = {
                    count: url.length,
                    func: fn
                };

                var i;
                for (i = 0; i < url.length; i++) {
                    _loadJs(url[i], position);
                }
            } else {
                $.getScript(url, fn);
            }
        }

        return {
            loadJs: loadJs
};
})();

(function (options) {
    var pendingRequests = 0;

    $.ajaxSetup({
        type: "POST",
        sfCheckRedirection: true,
        sfNotify: true
    });

    var checkRedirection = function (ajaxResult) {
        if (SF.isEmpty(ajaxResult)) {
            return null;
        }
        if (typeof ajaxResult !== "object") {
            return null;
        }
        if (ajaxResult.result == null) {
            return null;
        }
        if (ajaxResult.result == 'url') {
            return ajaxResult.url;
        }
        return null;
    };

    $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
        if (options.dataType == "script" && (typeof originalOptions.type == "undefined")) {
            options.type = "GET";
        }
        if (options.sfNotify) {
            pendingRequests++;
            if (pendingRequests == 1) {
                if (typeof (lang) != "undefined") {
                    SF.Notify.info(lang.signum.loading);
                }
            }
        }
        if (options.sfCheckRedirection) {
            var originalSuccess = options.success;

            options.success = function (result) {
                pendingRequests--;
                if (pendingRequests <= 0) {
                    pendingRequests = 0;
                    SF.Notify.clear();
                }
                if (typeof result === "string") {
                    result = result ? result.trim() : "";
                }
                var url = checkRedirection(result);
                if (!SF.isEmpty(url)) {
                    window.location.href = url;
                }
                else {
                    if (originalSuccess != null) {
                        originalSuccess(result);
                    }
                }
            };
        }
    });

    $(document).ajaxError(function (event, XMLHttpRequest, ajaxOptions, thrownError) {
        //check request status
        //request.abort() has status 0, so we don't show this "error", since we have
        //explicitly aborted the request.
        //this error is documented on http://bugs.jquery.com/ticket/7189
        if (XMLHttpRequest.status !== 0) {
            $("body").trigger("sf-ajax-error", [XMLHttpRequest, ajaxOptions, thrownError]);
            pendingRequests = 0;
        }
    });
})();

SF.stopPropagation = function (event) {
        if (event.stopPropagation) event.stopPropagation();
    else
        event.cancelBubble = true;
}

SF.isFalse = function (value) {
    return value == false || value == "false" || value == "False";
};

SF.isTrue = function (value) {
    return value == true || value == "true" || value == "True";
};

SF.isEmpty = function (value) {
    return (value == undefined || value == null || value === "" || value.toString() == "");
};

    String.prototype.hasText = function () {
        return (this == null || this == undefined || this == '') ? false : true;
    }

String.prototype.startsWith = function (str) {
    return (this.indexOf(str) === 0);
}

String.prototype.format = function () {
    var regex = /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g;

    var args = arguments;

    var getValue = function (key) {
        if (args == null || typeof args === 'undefined') return null;

        var value = args[key];
        var type = typeof value;

        return type === 'string' || type === 'number' ? value : null;
    };

    return this.replace(regex, function (match) {
        //match will look like {sample-match}
        //key will be 'sample-match';
        var key = match.substr(1, match.length - 2);

        var value = getValue(key);

        return value != null ? value : match;
    });
};

String.prototype.replaceAll = function (s1, s2) {
    return this.split(s1).join(s2)
};

if (typeof String.prototype.trim !== 'function') {
    String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/, '');
    }
}

SF.log = function (s) {
    if (SF.debug) {
            if (typeof console != "undefined" && typeof console.debug != "undefined") console.log(s);
    }
}

/* show messages on top (info, error...) */
SF.Notify = (function () {
    var $messageArea, timer, css;

    var error = function (s, t) {
        info(s, t, 'sf-error');
    };

    var info = function (s, t, cssClass) {
        SF.Notify.clear();
        css = (cssClass != undefined ? cssClass : "sf-info");
        $messageArea = $("#sfMessageArea");
        if ($messageArea.length == 0) {
            $messageArea = $("

").hide().prependTo($("body"));
        }

        $messageArea.find("span").html(s);
        $messageArea.children().first().addClass(css);
        $messageArea.css({
            marginLeft: -parseInt($messageArea.outerWidth() / 2)
        }).show();

        if (t != undefined) {
            timer = setTimeout(clear, t);
        }
    };

    var clear = function () {
        if ($messageArea) {
            $messageArea.hide().children().first().removeClass(css);
            if (timer != null) {
                clearTimeout(timer);
                timer = null;
            }
        }
    }

    return {
        error: error,
        info: info,
        clear: clear
    };
})();

SF.InputValidator = {
    isNumber: function (e) {
        var c = e.keyCode;
            return ((c >= 48 && c <= 57) /*0-9*/ ||
			(c >= 96 && c <= 105) /*NumPad 0-9*/ ||
			(c == 8) /*BackSpace*/ ||
			(c == 9) /*Tab*/ ||
			(c == 12) /*Clear*/ ||
			(c == 27) /*Escape*/ ||
			(c == 37) /*Left*/ ||
			(c == 39) /*Right*/ ||
			(c == 46) /*Delete*/ ||
			(c == 36) /*Home*/ ||
			(c == 35) /*End*/ ||
			(c == 109) /*NumPad -*/ ||
            (c == 189) /*-*/ ||
            (e.ctrlKey && c == 86) /*Ctrl + v*/ ||
            (e.ctrlKey && c == 67) /*Ctrl + v*/
        );
    },

    isDecimal: function (e) {
        var c = e.keyCode;
        return (
            this.isNumber(e) ||
            (c == 110) /*NumPad Decimal*/ ||
            (c == 190) /*.*/ ||
			(c == 188) /*,*/
		);
    }
};

(function ($) {
    $.fn.placeholder = function () {
        if ($.fn.placeholder.supported()) {
            return $(this);
        } else {

            $(this).parent('form').submit(function (e) {
                $('input[placeholder].sf-placeholder, textarea[placeholder].sf-placeholder', this).val('');
            });

            $(this).each(function () {
                $.fn.placeholder.on(this);
            });

            return $(this)

        .focus(function () {
            if ($(this).hasClass('sf-placeholder')) {
                $.fn.placeholder.off(this);
            }
        })

        .blur(function () {
            if ($(this).val() == '') {
                $.fn.placeholder.on(this);
            }
        });
        }
    };

    // Extracted from: http://diveintohtml5.org/detect.html#input-placeholder
    $.fn.placeholder.supported = function () {
        var input = document.createElement('input');
        return !!('placeholder' in input);
    };

    $.fn.placeholder.on = function (el) {
        var $el = $(el);
        if ($el.val() == '') $el.val($el.attr('placeholder')).addClass('sf-placeholder');
    };

    $.fn.placeholder.off = function (el) {
        $(el).val('').removeClass('sf-placeholder');
    };
})(jQuery);

SF.Cookies = {
    read: function (name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
        }
        return null;
    },

    create: function (name, value, days, domain) {
        var expires = null,
                path = "/";

        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
            expires = date;
        }

            document.cookie = name + "=" + escape(value) + ((expires) ? ";expires=" + expires.toGMTString() : "") + ((path) ? ";path=" + path : "") + ((domain) ? ";domain=" + domain : "");
    }
};

SF.LocalStorage = (function () {
    var isSupported = typeof (localStorage) != 'undefined';

    var getItem = function (key) {
        if (isSupported) {
                try {
                    return localStorage.getItem(key);
                } catch (e) { }
        }
        return SF.Cookies.read(key);
    };

    var setItem = function (key, value, days) {
        if (isSupported) {
                try {
                    localStorage.setItem(key, value);
                    return true;
                } catch (e) { }
        }
        SF.Cookies.create(key, value, days ? days : 30);
    };

        return {
            getItem: getItem,
            setItem: setItem
        };
    })();

    SF.triggerNewContent = function ($source) {
        $source.trigger("sf-new-content");
    }
}

SF.NewContentProcessor = {
    defaultButtons: function ($newContent) {
        $newContent.find(".sf-entity-button, .sf-query-button, .sf-line-button, .sf-chooser-button, .sf-button").each(function (i, val) {
            var $txt = $(val);
            if (!$txt.hasClass("ui-button") && !$txt.closest(".sf-menu-button").length > 0) {
                var data = $txt.data();
                $txt.button({
                    text: (!("text" in data) || SF.isTrue(data.text)),
                    icons: { primary: data.icon, secondary: data.iconSecondary },
                    disabled: $txt.hasClass("sf-disabled")
                });
            }
        });
    },

    defaultDatepicker: function ($newContent) {
        $newContent.find(".sf-datepicker").each(function (i, val) {
            var $txt = $(val);
            $txt.datepicker(jQuery.extend({}, SF.Locale.defaultDatepickerOptions, { dateFormat: $txt.attr("data-format") }));
        });
    },

    defaultDropdown: function ($newContent) {
        $newContent.find(".sf-dropdown .sf-menu-button")
            .addClass("ui-autocomplete ui-menu ui-widget ui-widget-content ui-corner-all")
            .find("li")
            .addClass("ui-menu-item")
            .find("a")
            .addClass("ui-corner-all");
    },

    defaultAutocomplete: function ($newContent) {
        $newContent.find(".sf-entity-autocomplete").each(function (i, val) {
            var $txt = $(val);
            var data = $txt.data();
            $.SF.entityLine.prototype.entityAutocomplete($txt, { delay: 200, types: data.types, url: data.url || SF.Urls.autocomplete, count: 5 });
        });
    },

    defaultPlaceholder: function ($newContent) {
        $newContent.find('input[placeholder], textarea[placeholder]').placeholder();
    },

    defaultTabs: function ($newContent) {
        var $tabContainer = $newContent.find(".sf-tabs:not(.ui-tabs)").prepend($("

"));

        $tabContainer.tabs();

        var $tabs = $tabContainer.children("fieldset");
        $tabs.each(function () {
            var $this = $(this);
            var $legend = $this.children("legend");
            if ($legend.length == 0) {
                $this.prepend("¡¡¡NO LEGEND SPECIFIED!!!");
                throw "No legend specified for tab";
            }
            var legend = $legend.html();

            var id = $this.attr("id");
            if (SF.isEmpty(id)) {
                $legend.html(legend + " ¡¡¡NO TAB ID SET!!!");
                throw "No id set for tab with legend: " + legend;
            }
            else {
                $("
" + legend + "
")
                    .appendTo($tabContainer.find(".ui-tabs-nav"));
                $legend.remove();
            }
        });

        $tabContainer.tabs("refresh");
        $tabContainer.tabs("option", "active", 0);
    },

    defaultSlider: function ($newContent) {
        $newContent.find(".sf-search-results-container").each(function (i, val) {
            new SF.slider(jQuery(val));
        });
    },

    defaultModifiedChecker: function ($newContent) {
        $newContent.find(":input").on("change", function() {
            var $mainControl = $(this).closest(".sf-main-control");
            if ($mainControl.length > 0) {
                $mainControl.addClass("sf-changed");
            }
        });
    }
};<|endoftext|>


<commit_before>//= require folio/webp
//= require photoswipe/dist/photoswipe
//= require photoswipe/dist/photoswipe-ui-default

window.Folio = window.Folio || {}
window.Folio.Lightbox = {}

window.Folio.Lightbox.calls = []

window.Folio.Lightbox.instances = []

window.Folio.Lightbox.bind = (selector, options) => {
  options = options || {}

  window.Folio.Lightbox.calls.push([selector, options])

  const init = () => {
    const $items = $(selector)

    if ($items.length === 0) return

    if (options.individual) {
      $items.each(function () {
        let subSelector = `.${this.className.replace(/\s+/g, '.')}`

        if (options.itemSelector) {
          subSelector = `${subSelector} ${options.itemSelector}`
        }

        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, subSelector, options }))
      })
    } else if (options.fromData) {
      $items.each((i, el) => {
        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options, data: $(el).data('lightbox-image-data') }))
      })
    } else {
      window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options }))
    }
  }

  if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
    $(document)
      .on('turbolinks:load', init)
      .on('turbolinks:before-render', function () {
        if (window.Folio.Lightbox.instances.length === 0) return

        window.Folio.Lightbox.instances.forEach((instance) => {
          instance.destroy()
        })

        window.Folio.Lightbox.instances = []
      })
  } else {
    $(() => setTimeout(init, 0))
  }
}

window.Folio.Lightbox.updateAll = () => {
  window.Folio.Lightbox.instances.forEach((instance) => instance.destroy())

  window.Folio.Lightbox.instances = []

  window.Folio.Lightbox.calls.forEach((call) => window.Folio.Lightbox.bind(call[0], call[1]))
}

window.Folio.Lightbox.Lightbox = class FolioLightbox {
  constructor (attrs) {
    this.selector = attrs.selector
    this.options = attrs.options

    if (attrs.additionalSelector) {
      this.fullSelector = `${this.selector}, ${attrs.additionalSelector}`
    } else {
      this.fullSelector = this.selector
    }

    this.eventIdentifier = 'folioLightbox'
    this.$html = $(document.documentElement)

    this.bind(attrs.data)
  }

  pswp () {
    this.$pswp || (this.$pswp = $('.pswp'))
    return this.$pswp
  }

  bind (data) {
    this.unbind()
    const that = this

    $(document).on(`click.${this.eventIdentifier}`, this.fullSelector, function (e) {
      e.preventDefault()

      const items = data || that.items()
      let index = 0

      if (typeof that.options.forceIndex !== 'undefined') {
        index = that.options.forceIndex
      } else {
        items.forEach((item, i) => {
          if (item.el === this) {
            index = i
          }
        })
      }

      that.photoSwipe = new PhotoSwipe(that.pswp()[0], PhotoSwipeUI_Default, items, {
        index: index,
        bgOpacity: 0.7,
        showHideOpacity: true,
        history: false,
        errorMsg: that.pswp().data('error-msg')
      })

      that.photoSwipe.init()
    })
  }

  items () {
    const items = []

    $(this.selector).each((i, el) => {
      const item = this.item(i, el)

      if (item) items.push(item)
    })

    return items
  }

  item (index, el) {
    let $el = $(el)

    if ($el.hasClass('f-image--sensitive-content')) {
      if (!this.$html.hasClass('f-html--show-sensitive-content')) return
    }

    if (!$el.data('lightbox-src')) {
      $el = $(el).find('[data-lightbox-src]')
    }

    if (!$el.length) return null

    return {
      w: parseInt($el.data('lightbox-width')),
      h: parseInt($el.data('lightbox-height')),
      title: $el.data('lightbox-title') || $el.next('figcaption').text(),
      src: window.Folio.Webp.supported ? $el.data('lightbox-webp-src') : $el.data('lightbox-src'),
      el: el
    }
  }

  unbind () {
    $(document).off(`click.${this.eventIdentifier}`, this.fullSelector)
  }

  destroy () {
    try {
      this.photoSwipe.close()
      this.photoSwipe.destroy()
    } catch (_error) {
    }

    this.photoSwipe = null
    this.unbind()
    this.$pswp = null
  }
}
<commit_msg>add itemsCallback to folio/lightbox<commit_after>//= require folio/webp
//= require photoswipe/dist/photoswipe
//= require photoswipe/dist/photoswipe-ui-default

window.Folio = window.Folio || {}
window.Folio.Lightbox = {}

window.Folio.Lightbox.calls = []

window.Folio.Lightbox.instances = []

window.Folio.Lightbox.bind = (selector, options) => {
  options = options || {}

  window.Folio.Lightbox.calls.push([selector, options])

  const init = () => {
    const $items = $(selector)

    if ($items.length === 0) return

    if (options.individual) {
      $items.each(function () {
        let subSelector = `.${this.className.replace(/\s+/g, '.')}`

        if (options.itemSelector) {
          subSelector = `${subSelector} ${options.itemSelector}`
        }

        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, subSelector, options }))
      })
    } else if (options.fromData) {
      $items.each((i, el) => {
        window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options, data: $(el).data('lightbox-image-data') }))
      })
    } else {
      window.Folio.Lightbox.instances.push(new window.Folio.Lightbox.Lightbox({ selector, options }))
    }
  }

  if (typeof Turbolinks !== 'undefined' && Turbolinks !== null) {
    $(document)
      .on('turbolinks:load', init)
      .on('turbolinks:before-render', function () {
        if (window.Folio.Lightbox.instances.length === 0) return

        window.Folio.Lightbox.instances.forEach((instance) => {
          instance.destroy()
        })

        window.Folio.Lightbox.instances = []
      })
  } else {
    $(() => setTimeout(init, 0))
  }
}

window.Folio.Lightbox.updateAll = () => {
  window.Folio.Lightbox.instances.forEach((instance) => instance.destroy())

  window.Folio.Lightbox.instances = []

  window.Folio.Lightbox.calls.forEach((call) => window.Folio.Lightbox.bind(call[0], call[1]))
}

window.Folio.Lightbox.Lightbox = class FolioLightbox {
  constructor (attrs) {
    this.selector = attrs.selector
    this.options = attrs.options

    if (attrs.additionalSelector) {
      this.fullSelector = `${this.selector}, ${attrs.additionalSelector}`
    } else {
      this.fullSelector = this.selector
    }

    this.eventIdentifier = 'folioLightbox'
    this.$html = $(document.documentElement)

    this.bind(attrs.data)
  }

  pswp () {
    this.$pswp || (this.$pswp = $('.pswp'))
    return this.$pswp
  }

  bind (data) {
    this.unbind()
    const that = this

    $(document).on(`click.${this.eventIdentifier}`, this.fullSelector, function (e) {
      e.preventDefault()

      let items = data || that.items()

      if (that.options.itemsCallback) {
        items = that.options.itemsCallback(items)
      }

      let index = 0

      if (typeof that.options.forceIndex !== 'undefined') {
        index = that.options.forceIndex
      } else {
        items.forEach((item, i) => {
          if (item.el === this) {
            index = i
          }
        })
      }

      that.photoSwipe = new PhotoSwipe(that.pswp()[0], PhotoSwipeUI_Default, items, {
        index: index,
        bgOpacity: 0.7,
        showHideOpacity: true,
        history: false,
        errorMsg: that.pswp().data('error-msg')
      })

      that.photoSwipe.init()
    })
  }

  items () {
    const items = []

    $(this.selector).each((i, el) => {
      const item = this.item(i, el)

      if (item) items.push(item)
    })

    return items
  }

  item (index, el) {
    let $el = $(el)

    if ($el.hasClass('f-image--sensitive-content')) {
      if (!this.$html.hasClass('f-html--show-sensitive-content')) return
    }

    if (!$el.data('lightbox-src')) {
      $el = $(el).find('[data-lightbox-src]')
    }

    if (!$el.length) return null

    return {
      w: parseInt($el.data('lightbox-width')),
      h: parseInt($el.data('lightbox-height')),
      title: $el.data('lightbox-title') || $el.next('figcaption').text(),
      src: window.Folio.Webp.supported ? $el.data('lightbox-webp-src') : $el.data('lightbox-src'),
      el: el
    }
  }

  unbind () {
    $(document).off(`click.${this.eventIdentifier}`, this.fullSelector)
  }

  destroy () {
    try {
      this.photoSwipe.close()
      this.photoSwipe.destroy()
    } catch (_error) {
    }

    this.photoSwipe = null
    this.unbind()
    this.$pswp = null
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var exec = require('child_process').exec;
exec("npm install xml2js@0.4.x");<commit_msg>Transform npminstall hook<commit_after>#!/usr/bin/env node
"use strict";

var exec = require("child_process").exec;
exec("npm install xml2js@0.4.x");<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');

App.MainAdminServiceAutoStartController = Em.Controller.extend({
  name: 'mainAdminServiceAutoStartController',

  /**
   * @type {?object}
   * @default null
   */
  clusterConfigs: null,

  /**
   * @type {Array}
   */
  componentsConfigsCached: [],

  /**
   * @type {object}
   */
  componentsConfigsCachedMap: function() {
    const map = {};
    this.get('componentsConfigsCached').mapProperty('ServiceComponentInfo').forEach((component) => {
      map[component.component_name] = component.recovery_enabled === 'true'
    });
    return map;
  }.property('componentsConfigsCached.@each.ServiceComponentInfo.recovery_enabled'),

  /**
   * @type {Array}
   */
  componentsConfigsGrouped: [],

  /**
   * @type {boolean}
   */
  isLoaded: false,

  /**
   * @type {boolean}
   */
  isGeneralRecoveryEnabled: false,

  /**
   * @type {boolean}
   */
  isGeneralRecoveryEnabledCached: false,

  /**
   * @type {boolean}
   */
  saveInProgress: false,

  /**
   * @type {boolean}
   */
  isModified: function() {
    return this.get('isGeneralModified') || this.get('isComponentModified');
  }.property('isGeneralModified', 'isComponentModified'),

  /**
   * @type {boolean}
   */
  isGeneralModified: function() {
    return this.get('isGeneralRecoveryEnabled') !== this.get('isGeneralRecoveryEnabledCached')
  }.property('isGeneralRecoveryEnabled', 'isGeneralRecoveryEnabledCached'),

  /**
   * @type {boolean}
   */
  isComponentModified: function() {
    const componentsConfigsCachedMap = this.get('componentsConfigsCachedMap');

    return this.get('componentsConfigsGrouped').some((component) => {
      return component.get('recoveryEnabled') !== componentsConfigsCachedMap[component.get('componentName')];
    });
  }.property('componentsConfigsGrouped.@each.recoveryEnabled', 'componentsConfigsCachedMap'),

  parseComponentConfigs: function(componentsConfigsCached) {
    const componentsConfigsGrouped = [];
    const servicesMap = componentsConfigsCached
      .mapProperty('ServiceComponentInfo.service_name').uniq().toWickMap();

    componentsConfigsCached.mapProperty('ServiceComponentInfo').forEach((component) => {
      componentsConfigsGrouped.push(Em.Object.create({
        serviceDisplayName: App.format.role(component.service_name, true),
        isFirst: servicesMap[component.service_name],
        componentName: component.component_name,
        displayName: App.format.role(component.component_name, false),
        recoveryEnabled: component.recovery_enabled === 'true'
      }));
      servicesMap[component.service_name] = false;
    });
    return componentsConfigsGrouped;
  },

  load: function() {
    App.router.get('configurationController').getCurrentConfigsBySites(['cluster-env']).done((data) => {
      this.set('clusterConfigs', data[0].properties);
      this.set('isGeneralRecoveryEnabled', data[0].properties.recovery_enabled === 'true');
      this.set('isGeneralRecoveryEnabledCached', this.get('isGeneralRecoveryEnabled'));
      this.loadComponentsConfigs().then(() => {
        this.set('isLoaded', true);
      });
    });
  },

  loadComponentsConfigs: function () {
    return App.ajax.send({
      name: 'components.get_category',
      sender: this,
      success: 'loadComponentsConfigsSuccess'
    });
  },

  loadComponentsConfigsSuccess: function (data) {
    this.set('componentsConfigsCached', data.items);
    this.set('componentsConfigsGrouped', this.parseComponentConfigs(data.items));
  },

  saveClusterConfigs: function (clusterConfigs, recoveryEnabled) {
    clusterConfigs.recovery_enabled = String(recoveryEnabled);
    return App.ajax.send({
      name: 'admin.save_configs',
      sender: this,
      data: {
        siteName: 'cluster-env',
        properties: clusterConfigs
      }
    });
  },

  saveComponentSettingsCall: function(recoveryEnabled, components) {
    return App.ajax.send({
      name: 'components.update',
      sender: this,
      data: {
        ServiceComponentInfo: {
          recovery_enabled: recoveryEnabled
        },
        query: 'ServiceComponentInfo/component_name.in(' + components.join(',') + ')'
      }
    });
  },

  syncStatus: function () {
    const componentsConfigsGrouped = this.get('componentsConfigsGrouped');
    this.set('isGeneralRecoveryEnabledCached', this.get('isGeneralRecoveryEnabled'));
    this.get('componentsConfigsCached').mapProperty('ServiceComponentInfo').forEach((component) => {
      const actualComponent = componentsConfigsGrouped.findProperty('componentName', component.component_name);
      component.recovery_enabled = String(actualComponent.get('recoveryEnabled'));
    });
    this.propertyDidChange('componentsConfigsCached');
  },

  restoreCachedValues: function () {
    this.set('isGeneralRecoveryEnabled', this.get('isGeneralRecoveryEnabledCached'));
    this.set('componentsConfigsGrouped', this.parseComponentConfigs(this.get('componentsConfigsCached')));
  },

  filterComponentsByChange: function(components, value) {
    const map = this.get('componentsConfigsCachedMap');

    return components.filter((component) => {
      return component.get('recoveryEnabled') !== map[component.get('componentName')]
          && component.get('recoveryEnabled') === value;
    }).mapProperty('componentName');
  },

  /**
   * If some configs are changed and user navigates away or select another config-group, show this popup with propose to save changes
   * @param {object} transitionCallback - callback with action to change configs view
   * @return {App.ModalPopup}
   * @method showSavePopup
   */
  showSavePopup: function (transitionCallback) {
    var self = this;
    var title = '';
    var body = '';
    if (typeof transitionCallback === 'function') {
      title = Em.I18n.t('admin.serviceAutoStart.save.popup.transition.title');
      body = Em.I18n.t('admin.serviceAutoStart.save.popup.transition.body');
    } else {
      title = Em.I18n.t('admin.serviceAutoStart.save.popup.title');
      body = Em.I18n.t('admin.serviceAutoStart.save.popup.body');
    }
    return App.ModalPopup.show({
      header: title,
      bodyClass: Ember.View.extend({
        template: Ember.Handlebars.compile(body)
      }),
      footerClass: Em.View.extend({
        templateName: require('templates/main/service/info/save_popup_footer')
      }),
      primary: Em.I18n.t('common.save'),
      secondary: Em.I18n.t('common.cancel'),
      onSave: function () {
        let clusterConfigsCall, enabledComponentsCall, disabledComponentsCall;

        if (self.get('isGeneralModified')) {
          clusterConfigsCall = self.saveClusterConfigs(self.get('clusterConfigs'), self.get('isGeneralRecoveryEnabled'));
        }

        const enabledComponents = self.filterComponentsByChange(self.get('componentsConfigsGrouped'), true);
        const disabledComponents = self.filterComponentsByChange(self.get('componentsConfigsGrouped'), false);

        if (enabledComponents.length) {
          enabledComponentsCall = self.saveComponentSettingsCall('true', enabledComponents);
        }
        if (disabledComponents.length) {
          disabledComponentsCall = self.saveComponentSettingsCall('false', disabledComponents);
        }
        self.set('saveInProgress', true);
        $.when(clusterConfigsCall, enabledComponentsCall, disabledComponentsCall).done(function () {
          if (typeof transitionCallback === 'function') {
            transitionCallback();
          }
          self.syncStatus();
        }).always(function() {
          self.set('saveInProgress', false);
        });
        this.hide();
      },
      onDiscard: function () {
        self.restoreCachedValues();
        if (typeof transitionCallback === 'function') {
          transitionCallback();
        }
        this.hide();
      },
      onCancel: function () {
        this.hide();
      }
    });
  }
});
<commit_msg>AMBARI-23669 issue with service auto restart service categorization (atkach)<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var App = require('app');

App.MainAdminServiceAutoStartController = Em.Controller.extend({
  name: 'mainAdminServiceAutoStartController',

  /**
   * @type {?object}
   * @default null
   */
  clusterConfigs: null,

  /**
   * @type {Array}
   */
  componentsConfigsCached: [],

  /**
   * @type {object}
   */
  componentsConfigsCachedMap: function() {
    const map = {};
    this.get('componentsConfigsCached').mapProperty('ServiceComponentInfo').forEach((component) => {
      map[component.component_name] = component.recovery_enabled === 'true'
    });
    return map;
  }.property('componentsConfigsCached.@each.ServiceComponentInfo.recovery_enabled'),

  /**
   * @type {Array}
   */
  componentsConfigsGrouped: [],

  /**
   * @type {boolean}
   */
  isLoaded: false,

  /**
   * @type {boolean}
   */
  isGeneralRecoveryEnabled: false,

  /**
   * @type {boolean}
   */
  isGeneralRecoveryEnabledCached: false,

  /**
   * @type {boolean}
   */
  saveInProgress: false,

  /**
   * @type {boolean}
   */
  isModified: function() {
    return this.get('isGeneralModified') || this.get('isComponentModified');
  }.property('isGeneralModified', 'isComponentModified'),

  /**
   * @type {boolean}
   */
  isGeneralModified: function() {
    return this.get('isGeneralRecoveryEnabled') !== this.get('isGeneralRecoveryEnabledCached')
  }.property('isGeneralRecoveryEnabled', 'isGeneralRecoveryEnabledCached'),

  /**
   * @type {boolean}
   */
  isComponentModified: function() {
    const componentsConfigsCachedMap = this.get('componentsConfigsCachedMap');

    return this.get('componentsConfigsGrouped').some((component) => {
      return component.get('recoveryEnabled') !== componentsConfigsCachedMap[component.get('componentName')];
    });
  }.property('componentsConfigsGrouped.@each.recoveryEnabled', 'componentsConfigsCachedMap'),

  parseComponentConfigs: function(componentsConfigsCached) {
    componentsConfigsCached.sortPropertyLight('ServiceComponentInfo.service_name');
    const componentsConfigsGrouped = [];
    const servicesMap = componentsConfigsCached
      .mapProperty('ServiceComponentInfo.service_name').uniq().toWickMap();

    componentsConfigsCached.mapProperty('ServiceComponentInfo').forEach((component) => {
      componentsConfigsGrouped.push(Em.Object.create({
        serviceDisplayName: App.format.role(component.service_name, true),
        isFirst: servicesMap[component.service_name],
        componentName: component.component_name,
        displayName: App.format.role(component.component_name, false),
        recoveryEnabled: component.recovery_enabled === 'true'
      }));
      servicesMap[component.service_name] = false;
    });
    return componentsConfigsGrouped;
  },

  load: function() {
    App.router.get('configurationController').getCurrentConfigsBySites(['cluster-env']).done((data) => {
      this.set('clusterConfigs', data[0].properties);
      this.set('isGeneralRecoveryEnabled', data[0].properties.recovery_enabled === 'true');
      this.set('isGeneralRecoveryEnabledCached', this.get('isGeneralRecoveryEnabled'));
      this.loadComponentsConfigs().then(() => {
        this.set('isLoaded', true);
      });
    });
  },

  loadComponentsConfigs: function () {
    return App.ajax.send({
      name: 'components.get_category',
      sender: this,
      success: 'loadComponentsConfigsSuccess'
    });
  },

  loadComponentsConfigsSuccess: function (data) {
    this.set('componentsConfigsCached', data.items);
    this.set('componentsConfigsGrouped', this.parseComponentConfigs(data.items));
  },

  saveClusterConfigs: function (clusterConfigs, recoveryEnabled) {
    clusterConfigs.recovery_enabled = String(recoveryEnabled);
    return App.ajax.send({
      name: 'admin.save_configs',
      sender: this,
      data: {
        siteName: 'cluster-env',
        properties: clusterConfigs
      }
    });
  },

  saveComponentSettingsCall: function(recoveryEnabled, components) {
    return App.ajax.send({
      name: 'components.update',
      sender: this,
      data: {
        ServiceComponentInfo: {
          recovery_enabled: recoveryEnabled
        },
        query: 'ServiceComponentInfo/component_name.in(' + components.join(',') + ')'
      }
    });
  },

  syncStatus: function () {
    const componentsConfigsGrouped = this.get('componentsConfigsGrouped');
    this.set('isGeneralRecoveryEnabledCached', this.get('isGeneralRecoveryEnabled'));
    this.get('componentsConfigsCached').mapProperty('ServiceComponentInfo').forEach((component) => {
      const actualComponent = componentsConfigsGrouped.findProperty('componentName', component.component_name);
      component.recovery_enabled = String(actualComponent.get('recoveryEnabled'));
    });
    this.propertyDidChange('componentsConfigsCached');
  },

  restoreCachedValues: function () {
    this.set('isGeneralRecoveryEnabled', this.get('isGeneralRecoveryEnabledCached'));
    this.set('componentsConfigsGrouped', this.parseComponentConfigs(this.get('componentsConfigsCached')));
  },

  filterComponentsByChange: function(components, value) {
    const map = this.get('componentsConfigsCachedMap');

    return components.filter((component) => {
      return component.get('recoveryEnabled') !== map[component.get('componentName')]
          && component.get('recoveryEnabled') === value;
    }).mapProperty('componentName');
  },

  /**
   * If some configs are changed and user navigates away or select another config-group, show this popup with propose to save changes
   * @param {object} transitionCallback - callback with action to change configs view
   * @return {App.ModalPopup}
   * @method showSavePopup
   */
  showSavePopup: function (transitionCallback) {
    var self = this;
    var title = '';
    var body = '';
    if (typeof transitionCallback === 'function') {
      title = Em.I18n.t('admin.serviceAutoStart.save.popup.transition.title');
      body = Em.I18n.t('admin.serviceAutoStart.save.popup.transition.body');
    } else {
      title = Em.I18n.t('admin.serviceAutoStart.save.popup.title');
      body = Em.I18n.t('admin.serviceAutoStart.save.popup.body');
    }
    return App.ModalPopup.show({
      header: title,
      bodyClass: Ember.View.extend({
        template: Ember.Handlebars.compile(body)
      }),
      footerClass: Em.View.extend({
        templateName: require('templates/main/service/info/save_popup_footer')
      }),
      primary: Em.I18n.t('common.save'),
      secondary: Em.I18n.t('common.cancel'),
      onSave: function () {
        let clusterConfigsCall, enabledComponentsCall, disabledComponentsCall;

        if (self.get('isGeneralModified')) {
          clusterConfigsCall = self.saveClusterConfigs(self.get('clusterConfigs'), self.get('isGeneralRecoveryEnabled'));
        }

        const enabledComponents = self.filterComponentsByChange(self.get('componentsConfigsGrouped'), true);
        const disabledComponents = self.filterComponentsByChange(self.get('componentsConfigsGrouped'), false);

        if (enabledComponents.length) {
          enabledComponentsCall = self.saveComponentSettingsCall('true', enabledComponents);
        }
        if (disabledComponents.length) {
          disabledComponentsCall = self.saveComponentSettingsCall('false', disabledComponents);
        }
        self.set('saveInProgress', true);
        $.when(clusterConfigsCall, enabledComponentsCall, disabledComponentsCall).done(function () {
          if (typeof transitionCallback === 'function') {
            transitionCallback();
          }
          self.syncStatus();
        }).always(function() {
          self.set('saveInProgress', false);
        });
        this.hide();
      },
      onDiscard: function () {
        self.restoreCachedValues();
        if (typeof transitionCallback === 'function') {
          transitionCallback();
        }
        this.hide();
      },
      onCancel: function () {
        this.hide();
      }
    });
  }
});
<|endoftext|>


<commit_before>/* Tests ColorMapService, which has functions:
    tempColor(index, min, max, name)
    mapColor(index, count)
    mapColorMonochrome(min, max, value, color)
    generateColorMap(results)

*/

describe('Color Map Service Testing', function() {
    var mockColorService, mockResults, society;

    beforeEach(function() {
        module('dplaceServices');
    });

    beforeEach(inject(function(colorMapService) {
        mockColorService = colorMapService;
        mockResults = {
            'societies': [],
            'environmental_variables': [],
            'geographic_regions': [],
            'languages': [],
            'variable_descriptions': []
        }; //used to store the mock results for the test

        society = {
            'society': { 'id': 11264 },
            'environmental_values': [],
            'geographic_regions': [],
            'languages': [],
            'variable_coded_values': []
        };

    }));

    it('geographic region color map', function() {

        var geographic_region = {
            'continent': "AFRICA",
            'count': 71,
            'id': 7398,
            'level_2_re': 24,
            'region_nam': "Northeastern Africa",
            'tdwg_code': 24
        };

       society.geographic_regions.push(geographic_region);
       mockResults.geographic_regions.push(geographic_region);
        mockResults.societies.push(society);
        var map = mockColorService.generateColorMap(mockResults);
        expect(map[society.society.id]).toBe('rgb(255,0,0)');
    });

    it('environmental color map', function() {
        var environmental_variable = {
            'id': 317,
            'max': 29,
            'min': -17,
            'name': "Temperature",
            'range': 46
        };

        var environmental_value = {
            'value': 18.25,
            'variable': 317,
        };
        mockResults.environmental_variables.push(environmental_variable);
        society.environmental_values.push(environmental_value);
        mockResults.societies.push(society);
        var map = mockColorService.generateColorMap(mockResults);
        expect(map[society.society.id]).toBe('rgb(255,238,0)');

    });

    it('cultural variable map', function() {
        var variable_description = {
            'codes': [
                {'code': 'NA', 'description': 'Missing data'},
                {'code': '1', 'description': 'Absence of slavery'},
                {'code': '2', 'description': 'Incipient or nonhereditary slavery, i.e., where slave status is temporary and not transmitted to the children of slaves'},
                {'code': '3', 'description': "Slavery reported but not identified as hereditary or nonhereditary"},
                {'code': '4', 'description': "Hereditary slavery present and of at least modest social significance"},
            ],
            'variable': {
                'id': 1628,
                'data_type': 'Categorical'
            }
        };

        var coded_value = {
            'coded_value': '1',
            'variable': 1628,
            'code_description': variable_description.codes[1]
        };

        mockResults.variable_descriptions.push(variable_description);
        society.variable_coded_values.push(coded_value);
        mockResults.societies.push(society);
        var map = mockColorService.generateColorMap(mockResults);
        expect(map[society.society.id]).toBe('rgb(228,26,28)');

    });

});<commit_msg>Adding language family map marker test<commit_after>/* Tests ColorMapService, which has functions:
    tempColor(index, min, max, name)
    mapColor(index, count)
    mapColorMonochrome(min, max, value, color)
    generateColorMap(results)

*/

describe('Color Map Service Testing', function() {
    var mockColorService, mockResults, society, society2, society3;

    beforeEach(function() {
        module('dplaceServices');
    });

    beforeEach(inject(function(colorMapService) {
        mockColorService = colorMapService;
        mockResults = {
            'societies': [],
            'environmental_variables': [],
            'geographic_regions': [],
            'languages': [],
            'variable_descriptions': []
        }; //used to store the mock results for the test

        society = {
            'society': { 'id': 11264 },
            'environmental_values': [],
            'geographic_regions': [],
            'variable_coded_values': []
        };

        society2 = {
            'society': { 'id': 16 },
            'environmental_values': [],
            'geographic_regions': [],
            'variable_coded_values': []
        };

        society3 = {
            'society': { 'id': 46 },
            'environmental_values': [],
            'geographic_regions': [],
            'variable_coded_values': []
        };

    }));

    it('geographic region color map', function() {

        var geographic_region = {
            'continent': "AFRICA",
            'count': 71,
            'id': 7398,
            'level_2_re': 24,
            'region_nam': "Northeastern Africa",
            'tdwg_code': 24
        };

       society.geographic_regions.push(geographic_region);
       mockResults.geographic_regions.push(geographic_region);
        mockResults.societies.push(society);
        var map = mockColorService.generateColorMap(mockResults);
        expect(map[society.society.id]).toBe('rgb(255,0,0)');
    });

    it('environmental color map', function() {
        var environmental_variable = {
            'id': 317,
            'max': 29,
            'min': -17,
            'name': "Temperature",
            'range': 46
        };

        var environmental_value = {
            'value': 18.25,
            'variable': 317,
        };
        mockResults.environmental_variables.push(environmental_variable);
        society.environmental_values.push(environmental_value);
        mockResults.societies.push(society);
        var map = mockColorService.generateColorMap(mockResults);
        expect(map[society.society.id]).toBe('rgb(255,238,0)');

    });

    it('cultural variable map', function() {
        var variable_description = {
            'codes': [
                {'code': 'NA', 'description': 'Missing data'},
                {'code': '1', 'description': 'Absence of slavery'},
                {'code': '2', 'description': 'Incipient or nonhereditary slavery, i.e., where slave status is temporary and not transmitted to the children of slaves'},
                {'code': '3', 'description': "Slavery reported but not identified as hereditary or nonhereditary"},
                {'code': '4', 'description': "Hereditary slavery present and of at least modest social significance"},
            ],
            'variable': {
                'id': 1628,
                'data_type': 'Categorical'
            }
        };

        var coded_value = {
            'coded_value': '1',
            'variable': 1628,
            'code_description': variable_description.codes[1]
        };

        mockResults.variable_descriptions.push(variable_description);
        society.variable_coded_values.push(coded_value);
        mockResults.societies.push(society);
        var map = mockColorService.generateColorMap(mockResults);
        expect(map[society.society.id]).toBe('rgb(228,26,28)');

    });

    it('language family map', function() {
        var language1 = {
            'family': {
                'id': 11,
                'language_count': 11,
                'name': 'Family 1',
                'scheme': 'G'
            },
            'glotto_code': "abcd1234",
            'id': 1100,
            'iso_code': "abc",
            'name': "ABCD"

        };
        var language2 = {
            'family': {
                'id': 58,
                'name': 'Austronesian',
                'scheme': 'G'
            },
            'glotto_code': "efgh1234",
            'id': 1110,
            'iso_code': "efg",
            'name': "SFGH"

        };

        var language3 = {
            'family': {
                'id': 58,
                'name': 'Austronesian',
                'scheme': 'G'
            },
            'glotto_code': "lmno1234",
            'id': 1110,
            'iso_code': "lmn",
            'name': "LMNO"

        };

        society.society.language = language1;
        society2.society.language = language2;
        society3.society.language = language3;
        mockResults.societies.push(society);

        //societies 2 and 3 have the same language family
        mockResults.societies.push(society2);
        mockResults.societies.push(society3);
        mockResults.languages = mockResults.languages.concat([language1, language2, language3]);
        mockResults.classifications = [
            {
                'id': 11,
                'name': 'Family 1',
                'scheme': 'G'
            },
            {
                'id': 58,
                'name': "Austronesian",
                'scheme': 'G'
            }
        ];

        var map = mockColorService.generateColorMap(mockResults);
       expect(map[society.society.id]).toBe("rgb(0,0,255)");
       expect(map[society2.society.id]).toBe("rgb(0,255,0)");
       expect(map[society2.society.id]).toEqual(map[society3.society.id]);
    });

});<|endoftext|>


<commit_before>import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
	container: {
		flex: 1,
		paddingTop: 20,
		paddingBottom: 25
	},
	noContentContainer: {
		alignItems: 'center',
		marginTop: 50
	},
	noContentText: {
		color: '#3c3c3c'
	}
});

export default styles;<commit_msg>Remove “Similar” styles from dev<commit_after><|endoftext|>


<commit_before>/*global Ajv, JsonRefs, Promise, module*/
/*exported textbrowserTests, bahaiwritingsTests*/

var textbrowserTests, bahaiwritingsTests;
(function () {

/* eslint-disable indent*/
'use strict';

var appBase = '/';
var schemaBase = appBase + 'general-schemas/';
var localesBase = appBase + 'locales/';
var appdataBase = appBase + 'appdata/';

/**
* @param {object} schema Schema object
* @param {any} data Data object
* @returns {boolean} Whether validation succeeded
*/
function validate (schema, data) {
    var ajv = Ajv(); // eslint-disable-line new-cap
    var valid;
    try {
        valid = ajv.validate(schema, data);
    }
    catch (e) {
        console.log(e); // eslint-disable-line no-console
    }
    finally {
        if (!valid) {console.log(JSON.stringify(ajv.errors));} // eslint-disable-line no-console
    }
    return valid;
}

textbrowserTests = {
    'locales tests': function (test) {
        test.expect(4); // eslint-disable-line no-magic-numbers
        Promise.all([
            JsonRefs.resolveRefsAt('locale.jsonschema', {relativeBase: schemaBase}),
            JsonRefs.resolveRefsAt('en-US.json', {relativeBase: localesBase}),
            JsonRefs.resolveRefsAt('ar.json', {relativeBase: localesBase}),
            JsonRefs.resolveRefsAt('fa.json', {relativeBase: localesBase}),
            JsonRefs.resolveRefsAt('ru.json', {relativeBase: localesBase})
        ]).then(function ([{resolved: schema}, ...locales]) {
            locales.forEach(function ({resolved: locale}) {
                var valid = validate(schema, locale);
                test.strictEqual(valid, true);
            });
            test.done();
        });
    },
    'languages.json test': function (test) { // See TextBrowser to-dos on what must be fixed for this to work
        Promise.all([
            JsonRefs.resolveRefsAt('languages.jsonschema', {relativeBase: schemaBase}),
            JsonRefs.resolveRefsAt('languages.json', {relativeBase: appdataBase})
        ]).then(function ([{resolved: schema}, {resolved: data}]) {
            var valid = validate(schema, data);
            test.strictEqual(valid, true);
            test.done();
        });
    }
};

if (typeof exports !== 'undefined') {
    module.exports = bahaiwritingsTests;
}

}());
<commit_msg>Report failing test name<commit_after>/*global Ajv, JsonRefs, Promise, module*/
/*exported textbrowserTests, bahaiwritingsTests*/

var textbrowserTests, bahaiwritingsTests;
(function () {

/* eslint-disable indent*/
'use strict';

var appBase = '/';
var schemaBase = appBase + 'general-schemas/';
var localesBase = appBase + 'locales/';
var appdataBase = appBase + 'appdata/';

/**
* @param {object} schema Schema object
* @param {any} data Data object
* @param {string} testName Name of the current test
* @returns {boolean} Whether validation succeeded
*/
function validate (schema, data, testName) {
    var ajv = Ajv(); // eslint-disable-line new-cap
    var valid;
    try {
        valid = ajv.validate(schema, data);
    }
    catch (e) {
        console.log('(' + testName + ') ' + e); // eslint-disable-line no-console
    }
    finally {
        if (!valid) {console.log(JSON.stringify(ajv.errors));} // eslint-disable-line no-console
    }
    return valid;
}

textbrowserTests = {
    'locales tests': function (test) {
        test.expect(4); // eslint-disable-line no-magic-numbers
        Promise.all([
            JsonRefs.resolveRefsAt('locale.jsonschema', {relativeBase: schemaBase}),
            JsonRefs.resolveRefsAt('en-US.json', {relativeBase: localesBase}),
            JsonRefs.resolveRefsAt('ar.json', {relativeBase: localesBase}),
            JsonRefs.resolveRefsAt('fa.json', {relativeBase: localesBase}),
            JsonRefs.resolveRefsAt('ru.json', {relativeBase: localesBase})
        ]).then(function ([{resolved: schema}, ...locales]) {
            locales.forEach(function ({resolved: locale}) {
                var valid = validate(schema, locale, 'locales tests');
                test.strictEqual(valid, true);
            });
            test.done();
        });
    },
    'languages.json test': function (test) { // See TextBrowser to-dos on what must be fixed for this to work
        Promise.all([
            JsonRefs.resolveRefsAt('languages.jsonschema', {relativeBase: schemaBase}),
            JsonRefs.resolveRefsAt('languages.json', {relativeBase: appdataBase})
        ]).then(function ([{resolved: schema}, {resolved: data}]) {
            var valid = validate(schema, data, 'languages.json test');
            test.strictEqual(valid, true);
            test.done();
        });
    }
};

if (typeof exports !== 'undefined') {
    module.exports = bahaiwritingsTests;
}

}());
<|endoftext|>


<commit_before>/**
	_moon.Dialog_ is a [moon.Popup](#moon.Popup) with a title, a subtitle, a
	message, and an area for additional controls.
*/
enyo.kind({
	name: "moon.Dialog",
	kind: moon.Popup,
	//* @protected
	classes: "moon-dialog",
	//* @public
	published: {
		//* The title string for the dialog
		title: "",
		//* The subtitle string for the dialog
		subTitle: "",
		//* The message for the dialog
		message: ""
	},
	//* @protected
	tools: [
		{
			layoutKind: "FittableColumnsLayout",
			components: [
				{fit: true, components: [
					{name: "title", classes: "moon-header-font moon-popup-header-text moon-dialog-title"},
					{name: "subTitle", classes: "moon-dialog-sub-title"}
				]},
				{name: "client", classes: "moon-dialog-client"}
			]
		},
		{kind: "moon.Divider", classes: "moon-dialog-divider"},
		{name: "message", kind:"moon.BodyText", classes: "moon-dialog-content"}
	],
	create: function() {
		this.inherited(arguments);
		this.titleChanged();
		this.subTitleChanged();
		this.messageChanged();
	},
	titleChanged: function() {
		this.$.title.setContent(this.title);
	},
	subTitleChanged: function() {
		this.$.subTitle.setContent(this.subTitle);
	},
	messageChanged: function() {
		this.$.message.setContent(this.message);
	}
});<commit_msg>Adding spotlightDummy control to moon.Dialog so that it properly inherits spotlight behavior from moon.Popup.<commit_after>/**
	_moon.Dialog_ is a [moon.Popup](#moon.Popup) with a title, a subtitle, a
	message, and an area for additional controls.
*/
enyo.kind({
	name: "moon.Dialog",
	kind: moon.Popup,
	//* @protected
	classes: "moon-dialog",
	//* @public
	published: {
		//* The title string for the dialog
		title: "",
		//* The subtitle string for the dialog
		subTitle: "",
		//* The message for the dialog
		message: ""
	},
	//* @protected
	tools: [
		{
			layoutKind: "FittableColumnsLayout",
			components: [
				{fit: true, components: [
					{name: "title", classes: "moon-header-font moon-popup-header-text moon-dialog-title"},
					{name: "subTitle", classes: "moon-dialog-sub-title"}
				]},
				{name: "client", classes: "moon-dialog-client"}
			]
		},
		{kind: "moon.Divider", classes: "moon-dialog-divider"},
		{name: "message", kind:"moon.BodyText", classes: "moon-dialog-content"},
		{name: "spotlightDummy", spotlight:false}
	],
	create: function() {
		this.inherited(arguments);
		this.titleChanged();
		this.subTitleChanged();
		this.messageChanged();
	},
	titleChanged: function() {
		this.$.title.setContent(this.title);
	},
	subTitleChanged: function() {
		this.$.subTitle.setContent(this.subTitle);
	},
	messageChanged: function() {
		this.$.message.setContent(this.message);
	}
});<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

"use strict";

const SERVER_ADDR = window.location.host;

// Shorthand for document.querySelectorAll that returns one element
// for NodeLists of length == 1, or a NodeList.
function $(selector) {
  var els = document.querySelectorAll(String(selector));
  return els.length > 1 ? els : els[0];
};

// Extension of HTMLElement's prototype to allow adding a single CSS
// class to its @class attribute.
HTMLElement.prototype.addClass = function(newClass) {
  var oldClasses = this.className;
  this.className = String(this.className + " " + newClass).trim();
};

// Extension of HTMLElement's prototype to allow removing a single CSS
// class from its @class attribute.
HTMLElement.prototype.removeClass = function(toRemove) {
  var oldClasses = this.className.split(" ");
  var newClasses = "";
  oldClasses.map(function(klass) {
    if (klass == toRemove)
      return;
    newClasses += klass + " ";
  });
  this.className = newClasses.trim();
};

// Represents tests in a table in the document.
function TestListView(el, tests) {
  this.el = el;
  this.tests = tests;
}

TestListView.prototype = {
  // have a reusable function if we want a 'Re-run tests' option
  resetTable: function() {
    for (var index in this.tests) {
      var test = this.tests[index];
      var rowNode = this.el.insertRow(-1);
      rowNode.id = "test" + test.id;
      var descriptionNode = rowNode.insertCell(0);
      var resultNode = rowNode.insertCell(1);
      descriptionNode.innerHTML = test.description;
      resultNode.addClass("result");
      resultNode.innerHTML = "";
    }
  },

  setTestState: function(testId, outcome, result) {
    var el = $("#test" + testId);
    el.className = outcome;
    if (result) {
      var resultCell = el.getElementsByClassName("result")[0];
      resultCell.innerHTML = result;
    }
  },

  updateTest: function(data) {
    var testData = data.testData;
    switch (testData.event) {
      case "testStart":
        this.setTestState(testData.id, "start");
        break;
      case "success":
        this.setTestState(testData.id, "success", "Pass");
        break;
      case "expectedFailure":
        this.setTestState(testData.id, "success", "Expected failure");
        break;
      case "skip":
        this.setTestState(testData.id, "success", testData.reason);
        break;
      case "error":
        this.setTestState(testData.id, "fail", testData.error);
        break;
      case "failure":
        this.setTestState(testData.id, "fail", testData.error);
        break;
      case "expectedSuccess":
        this.setTestState(testData.id, "fail", "Unexpected success");
        break;
    }
  }
};

// Represents a dialogue overlay.  Type can either be "prompt",
// "instruct", "confirm".  Message is the question or confirmation to
// pose to the user.
//
// A prompt will show a dialogue with a question, text input, and two
// buttons: "OK" and "Cancel".  An instruction will show a dialogue
// with an instruction, and two buttons: "OK" and "Cancel".  A
// confirmation will show a dialogue with a question, and two buttons:
// "Yes" and "No".
function Dialog(msg, type) {
  this.overlayEl = $("#overlay");
  this.textEl = $("#dialog_text");
  this.responseEl = $("#dialog_response");
  this.okEl = $("#ok");
  this.cancelEl = $("#cancel");

  this.okEl.onclick = function() { this.onok(); this.close(); }.bind(this);
  this.cancelEl.onclick = function() { this.oncancel(); this.close(); }.bind(this);

  this.message = msg || "";
  this.type = type || "prompt";
  //this.value = this.responseEl.value;

  // Assume prompt is default
  switch (this.type) {
  case "instruct":
    this.responseEl.addClass("hidden");
    break;
  case "confirm":
    this.responseEl.addClass("hidden");
    this.okEl.value = "Yes";
    this.cancelEl.value = "No";
    break;
  }
}

Dialog.prototype = {
  show: function() {
    this.textEl.innerHTML = this.message;
    this.overlayEl.removeClass("hidden");
  },

  close: function() {
    this.overlayEl.addClass("hidden");
    this.reset();
  },

  value: function() {
    return this.responseEl.value;
  },

  // TODO(ato): Because we're reusing the same Dialog construct, we
  // have to reset it.
  reset: function() {
    this.responseEl.removeClass("hidden");
    this.okEl.value = "OK";
    this.cancelEl.value = "Cancel";
  },

  onok: function() {},
  oncancel: function() {}
};

function Client(addr) {
  this.addr = addr;
  this.ws, this.testList = null;
  this.notificationEl = $("#notification");
}

Client.prototype = {
  sendResponse: function(payload) {
    var respWs = new WebSocket("ws://" + this.addr + "/resp");
    respWs.onopen = function(e) {
      respWs.send(payload);
      console.log("sent: " + payload);
      respWs.close();
    };
  },

  sendUserData: function() {
    var dialogResponse = $("#dialog_response");
    var payload = JSON.stringify({"prompt": dialogResponse.value});
    this.sendResponse(payload);
  },

  // Prompt the user for a response.  Return input to server.
  //
  // This will present the user with an overlay and the ability to
  // enter a text string which will be returned to the server.
  promptUser: function(text) {
    var dialog = new Dialog(text);
    dialog.onok = function() { this.emit("prompt", dialog.value()); }.bind(this);
    dialog.oncancel = function() { this.emit("promptCancel"); }.bind(this);
    dialog.show();
  },

  // Instruct the user perform an action, such as rotating the phone.
  //
  // This will present the user with an ok/cancel dialogue to indicate
  // whether she was successful in carrying out the instruction.
  instructUser: function(text) {
    var dialog = new Dialog(text, "instruct");
    dialog.onok = function() { this.emit("instructPromptOk"); }.bind(this);
    dialog.oncancel = function() { this.emit("instructPromptCancel"); }.bind(this);
    dialog.show();
  },

  // Ask user to confirm a physical aspect about the device or the
  // testing environment that cannot be checked by the test.
  //
  // This will present the user with an ok/cancel dialogue to indicate
  // whether the question posed was true or false.
  confirmPrompt: function(question) {
    var dialog = new Dialog(question, "confirm");
    dialog.onok = function() { this.emit("confirmPromptOk"); }.bind(this);
    dialog.oncancel = function() { this.emit("confirmPromptCancel"); }.bind(this);
    dialog.show();
  },

  connect: function() {
    this.ws = new WebSocket("ws://" + this.addr + "/tests");

    this.ws.onopen = function(e) { console.log("open", e); }.bind(this);
    this.ws.onclose = function(e) { console.log("close", e); }.bind(this);

    this.ws.onmessage = function(e) {
      var data = JSON.parse(e.data);
      var command = Object.keys(data)[0];
      console.log("recv", data);

      switch (command) {
      case "testList":
        // set up the test_list table
        this.testList = new TestListView($("#test_list"), data.testList);
        this.testList.resetTable();
        break;

      case "testRunStart":
        this.notificationEl.innerHTML = "Running tests";
        break;

      case "testRunStop":
        this.notificationEl.innerHTML = "Done";
        break;

      case "prompt":
        this.promptUser(data.prompt);
        break;

      case "instructPrompt":
        this.instructUser(data.instructPrompt);
        break;

      case "confirmPrompt":
        this.confirmPrompt(data.confirmPrompt);
        break;

      case "updateTest":
        // TODO: this assumes any other request will be to update the table
        this.testList.updateTest(data.updateTest);
        break;

      default:
        console.log("unkwn", data);
        this.ws.close();
        this.notificationEl.innerHTML = "Received unknown command from server";
        break;
      }
    }.bind(this);
  },

  emit: function(event, data) {
    var command = {};
    command[event] = data || null;
    var payload = JSON.stringify(command);
    console.log("send", command);
    this.ws.send(payload);
  }
};

function App(server) {
  this.addr = server;
  this.client = new Client(this.addr);
}

App.prototype = {
  start: function() {
    this.client.connect();
  }
};

function init() {
  var app = new App(SERVER_ADDR);
  app.start();
}

document.addEventListener("DOMContentLoaded", init, false);
<commit_msg>Remove second WS connection for prompt responses<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

"use strict";

const SERVER_ADDR = window.location.host;

// Shorthand for document.querySelectorAll that returns one element
// for NodeLists of length == 1, or a NodeList.
function $(selector) {
  var els = document.querySelectorAll(String(selector));
  return els.length > 1 ? els : els[0];
};

// Extension of HTMLElement's prototype to allow adding a single CSS
// class to its @class attribute.
HTMLElement.prototype.addClass = function(newClass) {
  var oldClasses = this.className;
  this.className = String(this.className + " " + newClass).trim();
};

// Extension of HTMLElement's prototype to allow removing a single CSS
// class from its @class attribute.
HTMLElement.prototype.removeClass = function(toRemove) {
  var oldClasses = this.className.split(" ");
  var newClasses = "";
  oldClasses.map(function(klass) {
    if (klass == toRemove)
      return;
    newClasses += klass + " ";
  });
  this.className = newClasses.trim();
};

// Represents tests in a table in the document.
function TestListView(el, tests) {
  this.el = el;
  this.tests = tests;
}

TestListView.prototype = {
  // have a reusable function if we want a 'Re-run tests' option
  resetTable: function() {
    for (var index in this.tests) {
      var test = this.tests[index];
      var rowNode = this.el.insertRow(-1);
      rowNode.id = "test" + test.id;
      var descriptionNode = rowNode.insertCell(0);
      var resultNode = rowNode.insertCell(1);
      descriptionNode.innerHTML = test.description;
      resultNode.addClass("result");
      resultNode.innerHTML = "";
    }
  },

  setTestState: function(testId, outcome, result) {
    var el = $("#test" + testId);
    el.className = outcome;
    if (result) {
      var resultCell = el.getElementsByClassName("result")[0];
      resultCell.innerHTML = result;
    }
  },

  updateTest: function(data) {
    var testData = data.testData;
    switch (testData.event) {
      case "testStart":
        this.setTestState(testData.id, "start");
        break;
      case "success":
        this.setTestState(testData.id, "success", "Pass");
        break;
      case "expectedFailure":
        this.setTestState(testData.id, "success", "Expected failure");
        break;
      case "skip":
        this.setTestState(testData.id, "success", testData.reason);
        break;
      case "error":
        this.setTestState(testData.id, "fail", testData.error);
        break;
      case "failure":
        this.setTestState(testData.id, "fail", testData.error);
        break;
      case "expectedSuccess":
        this.setTestState(testData.id, "fail", "Unexpected success");
        break;
    }
  }
};

// Represents a dialogue overlay.  Type can either be "prompt",
// "instruct", "confirm".  Message is the question or confirmation to
// pose to the user.
//
// A prompt will show a dialogue with a question, text input, and two
// buttons: "OK" and "Cancel".  An instruction will show a dialogue
// with an instruction, and two buttons: "OK" and "Cancel".  A
// confirmation will show a dialogue with a question, and two buttons:
// "Yes" and "No".
function Dialog(msg, type) {
  this.overlayEl = $("#overlay");
  this.textEl = $("#dialog_text");
  this.responseEl = $("#dialog_response");
  this.okEl = $("#ok");
  this.cancelEl = $("#cancel");

  this.okEl.onclick = function() { this.onok(); this.close(); }.bind(this);
  this.cancelEl.onclick = function() { this.oncancel(); this.close(); }.bind(this);

  this.message = msg || "";
  this.type = type || "prompt";
  //this.value = this.responseEl.value;

  // Assume prompt is default
  switch (this.type) {
  case "instruct":
    this.responseEl.addClass("hidden");
    break;
  case "confirm":
    this.responseEl.addClass("hidden");
    this.okEl.value = "Yes";
    this.cancelEl.value = "No";
    break;
  }
}

Dialog.prototype = {
  show: function() {
    this.textEl.innerHTML = this.message;
    this.overlayEl.removeClass("hidden");
  },

  close: function() {
    this.overlayEl.addClass("hidden");
    this.reset();
  },

  value: function() {
    return this.responseEl.value;
  },

  // TODO(ato): Because we're reusing the same Dialog construct, we
  // have to reset it.
  reset: function() {
    this.responseEl.removeClass("hidden");
    this.okEl.value = "OK";
    this.cancelEl.value = "Cancel";
  },

  onok: function() {},
  oncancel: function() {}
};

function Client(addr) {
  this.addr = addr;
  this.ws, this.testList = null;
  this.notificationEl = $("#notification");
}

Client.prototype = {
  // Prompt the user for a response.  Return input to server.
  //
  // This will present the user with an overlay and the ability to
  // enter a text string which will be returned to the server.
  promptUser: function(text) {
    var dialog = new Dialog(text);
    dialog.onok = function() { this.emit("prompt", dialog.value()); }.bind(this);
    dialog.oncancel = function() { this.emit("promptCancel"); }.bind(this);
    dialog.show();
  },

  // Instruct the user perform an action, such as rotating the phone.
  //
  // This will present the user with an ok/cancel dialogue to indicate
  // whether she was successful in carrying out the instruction.
  instructUser: function(text) {
    var dialog = new Dialog(text, "instruct");
    dialog.onok = function() { this.emit("instructPromptOk"); }.bind(this);
    dialog.oncancel = function() { this.emit("instructPromptCancel"); }.bind(this);
    dialog.show();
  },

  // Ask user to confirm a physical aspect about the device or the
  // testing environment that cannot be checked by the test.
  //
  // This will present the user with an ok/cancel dialogue to indicate
  // whether the question posed was true or false.
  confirmPrompt: function(question) {
    var dialog = new Dialog(question, "confirm");
    dialog.onok = function() { this.emit("confirmPromptOk"); }.bind(this);
    dialog.oncancel = function() { this.emit("confirmPromptCancel"); }.bind(this);
    dialog.show();
  },

  connect: function() {
    this.ws = new WebSocket("ws://" + this.addr + "/tests");

    this.ws.onopen = function(e) { console.log("open", e); }.bind(this);
    this.ws.onclose = function(e) { console.log("close", e); }.bind(this);

    this.ws.onmessage = function(e) {
      var data = JSON.parse(e.data);
      var command = Object.keys(data)[0];
      console.log("recv", data);

      switch (command) {
      case "testList":
        // set up the test_list table
        this.testList = new TestListView($("#test_list"), data.testList);
        this.testList.resetTable();
        break;

      case "testRunStart":
        this.notificationEl.innerHTML = "Running tests";
        break;

      case "testRunStop":
        this.notificationEl.innerHTML = "Done";
        break;

      case "prompt":
        this.promptUser(data.prompt);
        break;

      case "instructPrompt":
        this.instructUser(data.instructPrompt);
        break;

      case "confirmPrompt":
        this.confirmPrompt(data.confirmPrompt);
        break;

      case "updateTest":
        // TODO: this assumes any other request will be to update the table
        this.testList.updateTest(data.updateTest);
        break;

      default:
        console.log("unkwn", data);
        this.ws.close();
        this.notificationEl.innerHTML = "Received unknown command from server";
        break;
      }
    }.bind(this);
  },

  emit: function(event, data) {
    var command = {};
    command[event] = data || null;
    var payload = JSON.stringify(command);
    console.log("send", command);
    this.ws.send(payload);
  }
};

function App(server) {
  this.addr = server;
  this.client = new Client(this.addr);
}

App.prototype = {
  start: function() {
    this.client.connect();
  }
};

function init() {
  var app = new App(SERVER_ADDR);
  app.start();
}

document.addEventListener("DOMContentLoaded", init, false);
<|endoftext|>


<commit_before>function expandSidebar(){
  var sidebar = $(".sidebar-container")[0];
  if(sidebar) {
    var page_content = $(".page-content-container")[0];
    if(page_content.offsetHeight > sidebar.offsetHeight) {
      sidebar.style.height = page_content.offsetHeight + 'px';
    }
  }
}

function adjustProgress(percent) {
  $('.ai-progressbar').width(percent + '%');
}

function adjustText(percent) {
  var ai_red    = '#FF4E48';           // source: _variables.scss
  var ai_white  = '#FFFFFF';
  var screen_width = $(window).width();
  if(screen_width < 690) {
    $('.ai-progress-text').css('visibility','hidden');
  } else {
    if(percent < 30) {
      $('.ai-progress-text').css({'color': ai_red, 'width': '10%', 'left': '50%'});
    }
    if(percent >= 30 && percent < 65) {
      $('.ai-progress-text').css({'color': ai_red, 'width': '10%', 'left': percent + 5 + '%'});
    }
    if(percent >= 65) {
      $('.ai-progress-text').css({'color': ai_white, 'width': percent + '%'});
    }
  }
}
<commit_msg>fixed corner rounding for 100% completed challenges<commit_after>function expandSidebar(){
  var sidebar = $(".sidebar-container")[0];
  if(sidebar) {
    var page_content = $(".page-content-container")[0];
    if(page_content.offsetHeight > sidebar.offsetHeight) {
      sidebar.style.height = page_content.offsetHeight + 'px';
    }
  }
}

function adjustProgress(percent) {
  $('.ai-progressbar').width(percent + '%');
}

function adjustText(percent) {
  var ai_red    = '#FF4E48';           // source: _variables.scss
  var ai_white  = '#FFFFFF';
  var screen_width = $(window).width();
  if(screen_width < 690) {
    $('.ai-progress-text').css('visibility','hidden');
  } else {
    if(percent < 30) {
      $('.ai-progress-text').css({'color': ai_red, 'width': '10%', 'left': '50%'});
    }
    if(percent >= 30 && percent < 65) {
      $('.ai-progress-text').css({'color': ai_red, 'width': '10%', 'left': percent + 5 + '%'});
    }
    if(percent >= 65) {
      $('.ai-progress-text').css({'color': ai_white, 'width': percent + '%'});
    }
    if(percent === 100) {
      $('.ai-progressbar').css({'border-radius': '0.3em'});
    }
  }
}
<|endoftext|>


<commit_before>var moment = require("moment");
var parseDate = require("helper").parseDate;

var supportedByAllFormats = {
  "2019-01-01T00:00:00Z": ["2019"],
  "2017-02-14T00:00:00Z": ["2017-02-14"],
  "2018-01-15T00:00:00Z": ["January 15th, 2018"],
  "2017-05-15T00:00:00Z": ['"2017-05-15"'], // surrounded by quote marks
  "2019-04-03T12:33:15Z": ["2019-04-03 12:33:15"],
  "2018-12-17T17:29:00Z": ["2018-12-17 17:29"],
  "2018-03-29T00:00:00Z": ["March 29, 2018"],
  "2015-02-10T07:26:00Z": ["February 10th, 2015 07:26"],
  "2019-01-18T00:00:00Z": ["18 january, 2019"], // lowercase month name
  "2018-04-18T00:00:00Z": ["Apr 18, 2018"],
  "2019-04-16T14:50:00Z": ["2019-04-16 02:50 PM"], // AM/PM
  "2018-06-24T14:59:27Z": ["June 24th 2018, 2:59:27 pm"], // am/pm
  "2015-01-04T05:08:00Z": ["January 4th, 2015 05:08"],
  "2015-02-04T21:14:18Z": ["Wed Feb  4 21:14:18 EST 2015"], // timezone ignored
  "2012-05-30T14:45:44Z": ["Wed May 30 2012 14:45:44 GMT+0000 (UTC)"], // timezone ignored
};

var supportedBySpecficFormat = {
  "D/M/YYYY": {
    "2016-04-18T00:00:00Z": ["18/04/2016"],
    "2018-07-19T00:00:00Z": ["19-07-2018"],
    "2019-02-05T00:00:00Z": ["5.2.2019"]
  },
  "M/D/YYYY": {},
  "YYYY/M/D": {}
};

describe("date metadata", function() {
  Object.keys(supportedByAllFormats).forEach(function(result) {
    supportedByAllFormats[result].forEach(function(metadata) {
      Object.keys(supportedBySpecficFormat).forEach(function(format) {
        it('parses "' + metadata + '" using date format ' + format, function() {
          expect(moment.utc(parseDate(metadata, format)).format()).toEqual(
            result
          );
        });
      });
    });
  });

  Object.keys(supportedBySpecficFormat).forEach(function(format) {
    Object.keys(supportedBySpecficFormat[format]).forEach(function(result) {
      supportedBySpecficFormat[format][result].forEach(function(metadata) {
        it('parses "' + metadata + '" using date format ' + format, function() {
          expect(moment.utc(parseDate(metadata, format)).format()).toEqual(
            result
          );
        });
      });
    });
  });
});
<commit_msg>Adds comments<commit_after>var moment = require("moment");
var parseDate = require("helper").parseDate;

// Blot parses dates according to the 'dateFormat' of the blog.
// This allows Blot to determine what 5.1.2019 means: either
// May 1st or 5th of January. The dateFormat is either:
// - "D/M/YYYY" Day, Month, Year
// - "M/D/YYYY" Month, Day, Year
// - "YYYY/M/D" Year, Month, Day

// The following date strings can be parsed from each of the
// metadata inputs, regardless of the blog's dateFormat.
// For example, the date "2019-01-01T00:00:00Z"
// should be parsed from "2019", "2019-01-01" etc...
var supportedByAllFormats = {
  "2019-01-01T00:00:00Z": ["2019", "2019-01-01", "2019 01 01"],
  "2017-02-14T00:00:00Z": ["2017-02-14", "2017/02/14"],
  "2018-01-15T00:00:00Z": ["January 15th, 2018", "JANUARY 15th 2018"],
  "2017-05-15T00:00:00Z": ['"2017-05-15"'], // surrounded by quote marks
  "2019-04-03T12:33:15Z": ["2019-04-03 12:33:15"],
  "2018-12-17T17:29:00Z": ["2018-12-17 17:29"],
  "2018-03-29T00:00:00Z": ["March 29, 2018", "March.29.2018"],
  "2015-02-10T07:26:00Z": ["February 10th, 2015 07:26"],
  "2019-01-18T00:00:00Z": ["18 january, 2019"], // lowercase month name
  "2018-04-18T00:00:00Z": ["Apr 18, 2018"],
  "2019-04-16T14:50:00Z": ["2019-04-16 02:50 PM"], // AM/PM
  "2018-06-24T14:59:27Z": ["June 24th 2018, 2:59:27 pm"], // am/pm
  "2015-01-04T05:08:00Z": ["January 4th, 2015 05:08"],
  "2015-02-04T21:14:18Z": ["Wed Feb  4 21:14:18 EST 2015"], // timezone ignored
  "2012-05-30T14:45:44Z": ["Wed May 30 2012 14:45:44 GMT+0000 (UTC)"] // timezone ignored
};

// The following date strings can only be parsed from blogs
// with specific date formats. This is neccessary due to ambiguity
// in the ordering of month and day in the date metadata.
var supportedBySpecficFormat = {
  "D/M/YYYY": {
    "2016-04-18T00:00:00Z": ["18/04/2016"],
    "2018-07-19T00:00:00Z": ["19-07-2018"],
    "2019-02-05T00:00:00Z": ["5.2.2019"]
  },
  "M/D/YYYY": {},
  "YYYY/M/D": {}
};

describe("date metadata", function() {
  // Test the metadata which should be parsed correctly
  // regardless of the dateFormat (e.g. M/D/YYYY) of the blog
  Object.keys(supportedByAllFormats).forEach(function(result) {
    supportedByAllFormats[result].forEach(function(metadata) {
      Object.keys(supportedBySpecficFormat).forEach(function(format) {
        it('parses "' + metadata + '" using date format ' + format, function() {
          expect(moment.utc(parseDate(metadata, format)).format()).toEqual(
            result
          );
        });
      });
    });
  });

  // Test the metadata which can only be parsed correctly
  // using a specific dateFormat (e.g. M/D/YYYY) of the blog
  Object.keys(supportedBySpecficFormat).forEach(function(format) {
    Object.keys(supportedBySpecficFormat[format]).forEach(function(result) {
      supportedBySpecficFormat[format][result].forEach(function(metadata) {
        it('parses "' + metadata + '" using date format ' + format, function() {
          expect(moment.utc(parseDate(metadata, format)).format()).toEqual(
            result
          );
        });
      });
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Fixed #2894.<commit_after><|endoftext|>