<commit_before>var oil = require('oil');

var binary = {
    "==": function (left, right) { return left == right; },
    "!=": function (left, right) { return left != right; },
    "<": function (left, right) { return left < right; },
    ">": function (left, right) { return left > right; },
    "<=": function (left, right) { return left <= right; },
    ">=": function (left, right) { return left >= right; },
    "<<": function (left, right) { return left >> right; },
    ">>": function (left, right) { return left << right; },
    "+": function (left, right) { return left != null ? (right != null ? left + right : left) : right; }, // preventing string operation with null to convert to "null"
    "-": function (left, right) { return left != null ? (right != null ? left - right : left) : -right; }, // preventing string operation with null to conert to NaN
    "*": function (left, right) { return left * right; },
    "/": function (left, right) { return left / right; },
    "%": function (left, right) { return left % right; }
};

var unary = {
    "!": function (argument) { return !argument; },
    "+": function (argument) { return +argument; },
    "-": function (argument) { return -argument; }
};

var expressions = {
    "?:": function (expression, model) {
        if (evaluate(expression.expression, model)) {
            return evaluate(expression.positive, model);
        }
        else {
            return evaluate(expression.negative, model);
        }
    },
    "?=": function (expression, model) {
        var value = evaluate(expression.expression, model);
        for (var i = 0; i < expression.options.length; i++) {
            var option = expression.options[i];
            if (evaluate(option.value, model)) {
                return evaluate(option.result, model);
            }
        }
        return evaluate(option.otherwise, model);
    },
    "f": function (expression, model) {
        var object = evaluate(expression.object, model);
        if (object) {
            return object[expression.field];
        }
        return null;
    },
    "i": function (expression, model) {
        return model.get(expression.identifier);
    },
    "b": function (expression, model) {
        return binary[expression.operator](evaluate(expression.left, model), evaluate(expression.right, model));
    },
    "u": function (expression, model) {
        return unary[expression.operator](evaluate(expression.argument, model));
    },
    "??": function (expression, model) {
        var left = evaluate(expression.left, model);
        if (left == null) {
            return evaluate(expression.right, model);
        }
        return left;
    },
    "&&": function (expression, model) {
        return evaluate(expression.left, model) && evaluate(expression.right, model);
    },
    "||": function (expression, model) {
        return evaluate(expression.left, model) || evaluate(expression.right, model);
    },
    "@": function (expression, model) {
        var sequence = evaluate(expression.sequence, model);
        if (sequence) {
            return sequence[evaluate(expression.key, model)];
        }
        return null;
    },
    "@:": function (expression, model) {
        var sequence = evaluate(expression.sequence, model);
        if (sequence) {
            return sequence.slice(evaluate(expression.start, model), evaluate(expression.end, model));
        }
        return null;
    },
    "s": function (expression, model) {
        return null;
    },
    "=": function (expression, model) {
        return null;
    }
};

var modifiers = {
    round: function (value) {
        return Math.round(value)
    },
    floor: function (value) {
        return Math.floor(value)
    },
    ciel: function (value) {
        return Math.ciel(value)
    },
    number: function (value) {
        var f = parseFloat(value);
        if (!isNaN(f)) {
            var s = f.toString();
            var p = s.indexOf('.');
            var i = p > 0 ? s.slice(0, p) : s;
            var n = i.length - 3;
            while (n > 0) {
                i = i.slice(0, n) + ',' + i.slice(n);
                n -= 3;
            }
            return p > 0 ? i + s.slice(p) : i;
        }
        return "";
    },
    date: function (value, format) {
        if (value != null) {
            var d = new Date(value);
            if (format === "f") {
                return d.getDate() + "/" +
                    (d.getMonth() + 1) + "/" +
                    d.getFullYear() + " " +
                    ("0" + d.getHours()).slice(-2) + ":" +
                    ("0" + d.getMinutes()).slice(-2);
            }

            return d.getDate() + "/" +
                (d.getMonth() + 1) + "/" +
                d.getFullYear();
        }
        return "";
    },
    sqrt: function (value) {
        return Math.sqrt(value);
    },
    pow: function (value) {
        return Math.pow(value);
    },
    sin: function (value) {
        return Math.sin(value);
    },
    cos: function (value) {
        return Math.cos(value);
    },
    tan: function (value) {
        return Math.tan(value);
    },
    asin: function (value) {
        return Math.asic(value);
    },
    acos: function (value) {
        return Math.acos(value);
    },
    atan: function (value) {
        return Math.atan(value);
    },
    PI: function () {
        return Math.PI;
    }
};

function extend(source, obj) {
    if (source) {
        for (var key in source) {
            if (source.hasOwnProperty(key)) {
                obj[key] = source[key];
            }
        }
    }
    return obj;
}

function evaluate(expression, model) {
    while (expression && expression["!exp"]) {
        if (expression.$x) {
            // Expression loop
            expression = null;
        }
        else {
            expression.$x = true;
            var r = expressions[expression["!exp"]](expression, model);
            expression.$x = false;
            expression = r;
        }
    }
    if (expression && expression["!type"]) {
        var modifier = modifiers[expression["!type"]];
        if (modifier) {
            var init = expression["!init"];
            var args = [];
            if (init && init.length > 0) {
                args = init.map(function (x) { return evaluate(x, model); });
            }
            return modifier.apply(null, args);
        }
        return null;
    }
    return expression;
}

function isNotWhitespace(ch) {
    return !(ch === ' ' || ch === '\r' || ch === '\t' ||
    ch === '\n' || ch === '\v' || ch === '\u00A0');
}

function isNotIdentifier(ch) {
    return !('a' <= ch && ch <= 'z' ||
    'A' <= ch && ch <= 'Z' ||
    '_' === ch || ch === '$' || ch === '#');
}

function search(str, s, cb) {
    var i = 0;
    if (typeof s === "function") {
        cb = s;
    }
    else {
        i = s;
    }
    while (i < str.length && !cb(str[i])) {
        i++;
    }
    return i;
}

function Model(baseModel, model, parameters, env) {
    this.baseModel = baseModel;
    this.model = model;
    this.parameters = parameters;
    this.env = env;
}

Model.prototype.get = function (key) {
    if (key) {
        if (key[0] == '$') {
            var name = key.slice(1);
            var n = key.length === 1 ? 0 : parseInt(name);
            if (isNaN(n)) {
                if (this.env && this.env[name] != undefined) {
                    return this.env[name];
                }
                else if (this.baseModel) {
                    return this.baseModel.get(key);
                }
            }
            else if (this.parameters && n < this.parameters.length) {
                return evaluate(this.parameters[n].parameter, this.parameters[n].model);
            }
        }
        else {
            var v = null;
            if (typeof this.model === "object") {
                v = this.model[key];
            }
            if (v == null && this.baseModel != null) {
                return this.baseModel.get(key);
            }
            return v;
        }
    }

    return null;
};

function Rendo(template) {
    this.components = {};

    var components = oil.parse(template);

    for (var i = 0; i < components.length; i++) {
        var component = components[i];

        var name = component["!type"];
        if (name) {
            var render = component.render
                ? component.render
                : (component["!init"] && component["!init"].length > 0
                ? component["!init"][0]
                : (component["!ref"] || null));

            var scope = {};

            for (var key in component) {
                if (key[0] !== '!' && key !== "render") {
                    scope[key] = component[key];
                }
            }

            this.components[name] = {
                render: render,
                scope: scope
            };
        }
    }
}

Rendo.prototype.renderValue = function (value) {
    if (value != null && typeof value !== "object") {
        return "" + value;
    }
    return "";
};

Rendo.prototype.renderContents = function (contents, model) {
    var result = "";

    var s = 0;
    var o = contents.indexOf("{{");
    while (o >= s) {
        result += contents.slice(s, o);
        o += 2;

        var component = null;
        var fromModel = false;
        var i = search(contents, o, isNotWhitespace);

        if (contents[i] === ':' || contents[i] === '+') {
            fromModel = contents[i] == '+';
            o = i + 1;
            i = search(contents, o, isNotIdentifier);
            component = contents.slice(o, i);
        }

        // Reading to closing '}'
        var c = i;
        var count = 0;
        while (c < contents.length) {
            if (contents[c] === '{') {
                count++;
            }
            else if (contents[c] === '}') {
                if (count === 0) {
                    break;
                }
                count--;
            }
            c++;
        }

        var expressions = oil.parse(contents.slice(i, c));
        if (expressions.length > 0) {
            var models = evaluate(expressions[0], model);
            var parameters = expressions.slice(1).map(function (x) { return { model: model, parameter: x }; });

            var isArray = false;
            if (!models || models.constructor !== Array) {
                models = [models];
            }
            else {
                isArray = true;
            }

            for (var m = 0; m < models.length; m++) {
                var env = isArray ? {
                    index: m,
                    first: m === 0,
                    last: m === models.length - 1
                } : null;
                if (component) {
                    if (fromModel) {
                        var renderContents = model.get(component);
                        if (renderContents) {
                            result += this.renderContents(renderContents, new Model(model, models[m], [{model: model, parameter: models[m]}].concat(parameters), env));
                        }
                    }
                    else {
                        result += this.render(component, new Model(model, models[m], null, env), [{model: model, parameter: models[m]}].concat(parameters));
                    }
                }
                else {
                    result += this.renderValue(models[m]);
                }
            }
        }
        else if (component) {
            // Render same model
            if (fromModel) {
                var renderContents = model.get(component);
                if (renderContents) {
                    result += this.renderContents(renderContents, model);
                }
            }
            else {
                result += this.render(component, model);
            }
        }

        if (c === contents.length || contents[c + 1] != "}") {
            return result;
        }

        s = c + 2;
        o = contents.indexOf("{{", s);
    }

    if (s < contents.length) {
        result += contents.slice(s);
    }

    return result;
};

Rendo.prototype.render = function (componentName, model, parameters) {
    if (componentName == null) {
        return this.renderValue(model);
    }

    var component = this.components[componentName];
    if (!component) {
        return "";
    }

    var contents = component.render;
    if (!contents) {
        return "";
    }

    var isArray = false;
    var models;
    if (model) {
        if (model.constructor === Array) {
            models = model;
            isArray = true;
        }
        else {
            models = [model];
        }
    }
    else {
        models = [null];
    }

    var result = "";
    for (var m = 0; m < models.length; m++) {
        var model = models[m];
        var env = isArray ? {
            index: m,
            first: m === 0,
            last: m === models.length - 1
        } : null;
        if (!model || model.constructor !== Model) {
            model = new Model(null, model, null, env);
        }

        result += this.renderContents(contents, new Model(model, component.scope, parameters, env));
    }
    return result;
};

Rendo.render = function (template, component, model) {
    return new Rendo(template).render(component, model);
};

module.exports = Rendo;<commit_msg>Fix switch expression<commit_after>var oil = require('oil');

var binary = {
    "==": function (left, right) { return left == right; },
    "!=": function (left, right) { return left != right; },
    "<": function (left, right) { return left < right; },
    ">": function (left, right) { return left > right; },
    "<=": function (left, right) { return left <= right; },
    ">=": function (left, right) { return left >= right; },
    "<<": function (left, right) { return left >> right; },
    ">>": function (left, right) { return left << right; },
    "+": function (left, right) { return left != null ? (right != null ? left + right : left) : right; }, // preventing string operation with null to convert to "null"
    "-": function (left, right) { return left != null ? (right != null ? left - right : left) : -right; }, // preventing string operation with null to conert to NaN
    "*": function (left, right) { return left * right; },
    "/": function (left, right) { return left / right; },
    "%": function (left, right) { return left % right; }
};

var unary = {
    "!": function (argument) { return !argument; },
    "+": function (argument) { return +argument; },
    "-": function (argument) { return -argument; }
};

var expressions = {
    "?:": function (expression, model) {
        if (evaluate(expression.expression, model)) {
            return evaluate(expression.positive, model);
        }
        else {
            return evaluate(expression.negative, model);
        }
    },
    "?=": function (expression, model) {
        var value = evaluate(expression.expression, model);
        for (var i = 0; i < expression.options.length; i++) {
            var option = expression.options[i];
            if (evaluate(option.value, model) == value) {
                return evaluate(option.result, model);
            }
        }
        return evaluate(expression.otherwise, model);
    },
    "f": function (expression, model) {
        var object = evaluate(expression.object, model);
        if (object) {
            return object[expression.field];
        }
        return null;
    },
    "i": function (expression, model) {
        return model.get(expression.identifier);
    },
    "b": function (expression, model) {
        return binary[expression.operator](evaluate(expression.left, model), evaluate(expression.right, model));
    },
    "u": function (expression, model) {
        return unary[expression.operator](evaluate(expression.argument, model));
    },
    "??": function (expression, model) {
        var left = evaluate(expression.left, model);
        if (left == null) {
            return evaluate(expression.right, model);
        }
        return left;
    },
    "&&": function (expression, model) {
        return evaluate(expression.left, model) && evaluate(expression.right, model);
    },
    "||": function (expression, model) {
        return evaluate(expression.left, model) || evaluate(expression.right, model);
    },
    "@": function (expression, model) {
        var sequence = evaluate(expression.sequence, model);
        if (sequence) {
            return sequence[evaluate(expression.key, model)];
        }
        return null;
    },
    "@:": function (expression, model) {
        var sequence = evaluate(expression.sequence, model);
        if (sequence) {
            return sequence.slice(evaluate(expression.start, model), evaluate(expression.end, model));
        }
        return null;
    },
    "s": function (expression, model) {
        return null;
    },
    "=": function (expression, model) {
        return null;
    }
};

var modifiers = {
    round: function (value) {
        return Math.round(value)
    },
    floor: function (value) {
        return Math.floor(value)
    },
    ciel: function (value) {
        return Math.ciel(value)
    },
    number: function (value) {
        var f = parseFloat(value);
        if (!isNaN(f)) {
            var s = f.toString();
            var p = s.indexOf('.');
            var i = p > 0 ? s.slice(0, p) : s;
            var n = i.length - 3;
            while (n > 0) {
                i = i.slice(0, n) + ',' + i.slice(n);
                n -= 3;
            }
            return p > 0 ? i + s.slice(p) : i;
        }
        return "";
    },
    date: function (value, format) {
        if (value != null) {
            var d = new Date(value);
            if (format === "f") {
                return d.getDate() + "/" +
                    (d.getMonth() + 1) + "/" +
                    d.getFullYear() + " " +
                    ("0" + d.getHours()).slice(-2) + ":" +
                    ("0" + d.getMinutes()).slice(-2);
            }

            return d.getDate() + "/" +
                (d.getMonth() + 1) + "/" +
                d.getFullYear();
        }
        return "";
    },
    sqrt: function (value) {
        return Math.sqrt(value);
    },
    pow: function (value) {
        return Math.pow(value);
    },
    sin: function (value) {
        return Math.sin(value);
    },
    cos: function (value) {
        return Math.cos(value);
    },
    tan: function (value) {
        return Math.tan(value);
    },
    asin: function (value) {
        return Math.asic(value);
    },
    acos: function (value) {
        return Math.acos(value);
    },
    atan: function (value) {
        return Math.atan(value);
    },
    PI: function () {
        return Math.PI;
    }
};

function extend(source, obj) {
    if (source) {
        for (var key in source) {
            if (source.hasOwnProperty(key)) {
                obj[key] = source[key];
            }
        }
    }
    return obj;
}

function evaluate(expression, model) {
    while (expression && expression["!exp"]) {
        if (expression.$x) {
            // Expression loop
            expression = null;
        }
        else {
            expression.$x = true;
            var r = expressions[expression["!exp"]](expression, model);
            expression.$x = false;
            expression = r;
        }
    }
    if (expression && expression["!type"]) {
        var modifier = modifiers[expression["!type"]];
        if (modifier) {
            var init = expression["!init"];
            var args = [];
            if (init && init.length > 0) {
                args = init.map(function (x) { return evaluate(x, model); });
            }
            return modifier.apply(null, args);
        }
        return null;
    }
    return expression;
}

function isNotWhitespace(ch) {
    return !(ch === ' ' || ch === '\r' || ch === '\t' ||
    ch === '\n' || ch === '\v' || ch === '\u00A0');
}

function isNotIdentifier(ch) {
    return !('a' <= ch && ch <= 'z' ||
    'A' <= ch && ch <= 'Z' ||
    '_' === ch || ch === '$' || ch === '#');
}

function search(str, s, cb) {
    var i = 0;
    if (typeof s === "function") {
        cb = s;
    }
    else {
        i = s;
    }
    while (i < str.length && !cb(str[i])) {
        i++;
    }
    return i;
}

function Model(baseModel, model, parameters, env) {
    this.baseModel = baseModel;
    this.model = model;
    this.parameters = parameters;
    this.env = env;
}

Model.prototype.get = function (key) {
    if (key) {
        if (key[0] == '$') {
            var name = key.slice(1);
            var n = key.length === 1 ? 0 : parseInt(name);
            if (isNaN(n)) {
                if (this.env && this.env[name] != undefined) {
                    return this.env[name];
                }
                else if (this.baseModel) {
                    return this.baseModel.get(key);
                }
            }
            else if (this.parameters && n < this.parameters.length) {
                return evaluate(this.parameters[n].parameter, this.parameters[n].model);
            }
        }
        else {
            var v = null;
            if (typeof this.model === "object") {
                v = this.model[key];
            }
            if (v == null && this.baseModel != null) {
                return this.baseModel.get(key);
            }
            return v;
        }
    }

    return null;
};

function Rendo(template) {
    this.components = {};

    var components = oil.parse(template);

    for (var i = 0; i < components.length; i++) {
        var component = components[i];

        var name = component["!type"];
        if (name) {
            var render = component.render
                ? component.render
                : (component["!init"] && component["!init"].length > 0
                ? component["!init"][0]
                : (component["!ref"] || null));

            var scope = {};

            for (var key in component) {
                if (key[0] !== '!' && key !== "render") {
                    scope[key] = component[key];
                }
            }

            this.components[name] = {
                render: render,
                scope: scope
            };
        }
    }
}

Rendo.prototype.renderValue = function (value) {
    if (value != null && typeof value !== "object") {
        return "" + value;
    }
    return "";
};

Rendo.prototype.renderContents = function (contents, model) {
    var result = "";

    var s = 0;
    var o = contents.indexOf("{{");
    while (o >= s) {
        result += contents.slice(s, o);
        o += 2;

        var component = null;
        var fromModel = false;
        var i = search(contents, o, isNotWhitespace);

        if (contents[i] === ':' || contents[i] === '+') {
            fromModel = contents[i] == '+';
            o = i + 1;
            i = search(contents, o, isNotIdentifier);
            component = contents.slice(o, i);
        }

        // Reading to closing '}'
        var c = i;
        var count = 0;
        while (c < contents.length) {
            if (contents[c] === '{') {
                count++;
            }
            else if (contents[c] === '}') {
                if (count === 0) {
                    break;
                }
                count--;
            }
            c++;
        }

        var expressions = oil.parse(contents.slice(i, c));
        if (expressions.length > 0) {
            var models = evaluate(expressions[0], model);
            var parameters = expressions.slice(1).map(function (x) { return { model: model, parameter: x }; });

            var isArray = false;
            if (!models || models.constructor !== Array) {
                models = [models];
            }
            else {
                isArray = true;
            }

            for (var m = 0; m < models.length; m++) {
                var env = isArray ? {
                    index: m,
                    first: m === 0,
                    last: m === models.length - 1
                } : null;
                if (component) {
                    if (fromModel) {
                        var renderContents = model.get(component);
                        if (renderContents) {
                            result += this.renderContents(renderContents, new Model(model, models[m], [{model: model, parameter: models[m]}].concat(parameters), env));
                        }
                    }
                    else {
                        result += this.render(component, new Model(model, models[m], null, env), [{model: model, parameter: models[m]}].concat(parameters));
                    }
                }
                else {
                    result += this.renderValue(models[m]);
                }
            }
        }
        else if (component) {
            // Render same model
            if (fromModel) {
                var renderContents = model.get(component);
                if (renderContents) {
                    result += this.renderContents(renderContents, model);
                }
            }
            else {
                result += this.render(component, model);
            }
        }

        if (c === contents.length || contents[c + 1] != "}") {
            return result;
        }

        s = c + 2;
        o = contents.indexOf("{{", s);
    }

    if (s < contents.length) {
        result += contents.slice(s);
    }

    return result;
};

Rendo.prototype.render = function (componentName, model, parameters) {
    if (componentName == null) {
        return this.renderValue(model);
    }

    var component = this.components[componentName];
    if (!component) {
        return "";
    }

    var contents = component.render;
    if (!contents) {
        return "";
    }

    var isArray = false;
    var models;
    if (model) {
        if (model.constructor === Array) {
            models = model;
            isArray = true;
        }
        else {
            models = [model];
        }
    }
    else {
        models = [null];
    }

    var result = "";
    for (var m = 0; m < models.length; m++) {
        var model = models[m];
        var env = isArray ? {
            index: m,
            first: m === 0,
            last: m === models.length - 1
        } : null;
        if (!model || model.constructor !== Model) {
            model = new Model(null, model, null, env);
        }

        result += this.renderContents(contents, new Model(model, component.scope, parameters, env));
    }
    return result;
};

Rendo.render = function (template, component, model) {
    return new Rendo(template).render(component, model);
};

module.exports = Rendo;<|endoftext|>


<commit_before>'use strict'

let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js')
let { dirname, resolve, relative, sep } = require('path')
let { pathToFileURL } = require('url')

let Input = require('./input')

let sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator)
let pathAvailable = Boolean(dirname && resolve && relative && sep)

class MapGenerator {
  constructor(stringify, root, opts, cssString) {
    this.stringify = stringify
    this.mapOpts = opts.map || {}
    this.root = root
    this.opts = opts
    this.css = cssString
    this.fileUrls = !this.mapOpts.from && this.mapOpts.absolute
  }

  isMap() {
    if (typeof this.opts.map !== 'undefined') {
      return !!this.opts.map
    }
    return this.previous().length > 0
  }

  previous() {
    if (!this.previousMaps) {
      this.previousMaps = []
      if (this.root) {
        this.root.walk(node => {
          if (node.source && node.source.input.map) {
            let map = node.source.input.map
            if (!this.previousMaps.includes(map)) {
              this.previousMaps.push(map)
            }
          }
        })
      } else {
        let input = new Input(this.css, this.opts)
        if (input.map) this.previousMaps.push(input.map)
      }
    }

    return this.previousMaps
  }

  isInline() {
    if (typeof this.mapOpts.inline !== 'undefined') {
      return this.mapOpts.inline
    }

    let annotation = this.mapOpts.annotation
    if (typeof annotation !== 'undefined' && annotation !== true) {
      return false
    }

    if (this.previous().length) {
      return this.previous().some(i => i.inline)
    }
    return true
  }

  isSourcesContent() {
    if (typeof this.mapOpts.sourcesContent !== 'undefined') {
      return this.mapOpts.sourcesContent
    }
    if (this.previous().length) {
      return this.previous().some(i => i.withContent())
    }
    return true
  }

  clearAnnotation() {
    if (this.mapOpts.annotation === false) return

    if (this.root) {
      let node
      for (let i = this.root.nodes.length - 1; i >= 0; i--) {
        node = this.root.nodes[i]
        if (node.type !== 'comment') continue
        if (node.text.indexOf('# sourceMappingURL=') === 0) {
          this.root.removeChild(i)
        }
      }
    } else if (this.css) {
      this.css = this.css.replace(/(\n)?\/\*#[\S\s]*?\*\/$/gm, '')
    }
  }

  setSourcesContent() {
    let already = {}
    if (this.root) {
      this.root.walk(node => {
        if (node.source) {
          let from = node.source.input.from
          if (from && !already[from]) {
            already[from] = true
            let fromUrl = this.toUrl(this.path(from))
            if (this.fileUrls) {
              if (pathToFileURL) {
                fromUrl = pathToFileURL(from).toString()
              } else {
                throw new Error(
                  '`map.absolute` option is not available in this PostCSS build'
                )
              }
            }
            this.map.setSourceContent(fromUrl, node.source.input.css)
          }
        }
      })
    } else if (this.css) {
      let from = this.opts.from
        ? this.toUrl(this.path(this.opts.from))
        : '<no source>'
      this.map.setSourceContent(from, this.css)
    }
  }

  applyPrevMaps() {
    for (let prev of this.previous()) {
      let from = this.toUrl(this.path(prev.file))
      let root = prev.root || dirname(prev.file)
      let map

      if (this.mapOpts.sourcesContent === false) {
        map = new SourceMapConsumer(prev.text)
        if (map.sourcesContent) {
          map.sourcesContent = map.sourcesContent.map(() => null)
        }
      } else {
        map = prev.consumer()
      }

      this.map.applySourceMap(map, from, this.toUrl(this.path(root)))
    }
  }

  isAnnotation() {
    if (this.isInline()) {
      return true
    }
    if (typeof this.mapOpts.annotation !== 'undefined') {
      return this.mapOpts.annotation
    }
    if (this.previous().length) {
      return this.previous().some(i => i.annotation)
    }
    return true
  }

  toBase64(str) {
    if (Buffer) {
      return Buffer.from(str).toString('base64')
    } else {
      return window.btoa(unescape(encodeURIComponent(str)))
    }
  }

  addAnnotation() {
    let content

    if (this.isInline()) {
      content =
        'data:application/json;base64,' + this.toBase64(this.map.toString())
    } else if (typeof this.mapOpts.annotation === 'string') {
      content = this.mapOpts.annotation
    } else if (typeof this.mapOpts.annotation === 'function') {
      content = this.mapOpts.annotation(this.opts.to, this.root)
    } else {
      content = this.outputFile() + '.map'
    }
    let eol = '\n'
    if (this.css.includes('\r\n')) eol = '\r\n'

    this.css += eol + '/*# sourceMappingURL=' + content + ' */'
  }

  outputFile() {
    if (this.opts.to) {
      return this.path(this.opts.to)
    } else if (this.opts.from) {
      return this.path(this.opts.from)
    } else {
      return 'to.css'
    }
  }

  generateMap() {
    if (this.root) {
      this.generateString()
    } else if (this.previous().length === 1) {
      let prev = this.previous()[0].consumer()
      prev.file = this.outputFile()
      this.map = SourceMapGenerator.fromSourceMap(prev)
    } else {
      this.map = new SourceMapGenerator({ file: this.outputFile() })
      this.map.addMapping({
        source: this.opts.from
          ? this.toUrl(this.path(this.opts.from))
          : '<no source>',
        generated: { line: 1, column: 0 },
        original: { line: 1, column: 0 }
      })
    }

    if (this.isSourcesContent()) this.setSourcesContent()
    if (this.root && this.previous().length > 0) this.applyPrevMaps()
    if (this.isAnnotation()) this.addAnnotation()

    if (this.isInline()) {
      return [this.css]
    } else {
      return [this.css, this.map]
    }
  }

  path(file) {
    if (file.indexOf('<') === 0) return file
    if (/^\w+:\/\//.test(file)) return file
    if (this.mapOpts.absolute) return file

    let from = this.opts.to ? dirname(this.opts.to) : '.'

    if (typeof this.mapOpts.annotation === 'string') {
      from = dirname(resolve(from, this.mapOpts.annotation))
    }

    file = relative(from, file)
    return file
  }

  toUrl(path) {
    if (sep === '\\') {
      path = path.replace(/\\/g, '/')
    }
    return encodeURI(path).replace(/[#?]/g, encodeURIComponent)
  }

  sourcePath(node) {
    if (this.mapOpts.from) {
      return this.toUrl(this.mapOpts.from)
    } else if (this.fileUrls) {
      if (pathToFileURL) {
        return pathToFileURL(node.source.input.from).toString()
      } else {
        throw new Error(
          '`map.absolute` option is not available in this PostCSS build'
        )
      }
    } else {
      return this.toUrl(this.path(node.source.input.from))
    }
  }

  generateString() {
    this.css = ''
    this.map = new SourceMapGenerator({ file: this.outputFile() })

    let line = 1
    let column = 1

    let noSource = '<no source>'
    let mapping = {
      source: '',
      generated: { line: 0, column: 0 },
      original: { line: 0, column: 0 }
    }

    let lines, last
    this.stringify(this.root, (str, node, type) => {
      this.css += str

      if (node && type !== 'end') {
        mapping.generated.line = line
        mapping.generated.column = column - 1
        if (node.source && node.source.start) {
          mapping.source = this.sourcePath(node)
          mapping.original.line = node.source.start.line
          mapping.original.column = node.source.start.column - 1
          this.map.addMapping(mapping)
        } else {
          mapping.source = noSource
          mapping.original.line = 1
          mapping.original.column = 0
          this.map.addMapping(mapping)
        }
      }

      lines = str.match(/\n/g)
      if (lines) {
        line += lines.length
        last = str.lastIndexOf('\n')
        column = str.length - last
      } else {
        column += str.length
      }

      if (node && type !== 'start') {
        let p = node.parent || { raws: {} }
        if (node.type !== 'decl' || node !== p.last || p.raws.semicolon) {
          if (node.source && node.source.end) {
            mapping.source = this.sourcePath(node)
            mapping.original.line = node.source.end.line
            mapping.original.column = node.source.end.column - 1
            mapping.generated.line = line
            mapping.generated.column = column - 2
            this.map.addMapping(mapping)
          } else {
            mapping.source = noSource
            mapping.original.line = 1
            mapping.original.column = 0
            mapping.generated.line = line
            mapping.generated.column = column - 1
            this.map.addMapping(mapping)
          }
        }
      }
    })
  }

  generate() {
    this.clearAnnotation()
    if (pathAvailable && sourceMapAvailable && this.isMap()) {
      return this.generateMap()
    } else {
      let result = ''
      this.stringify(this.root, i => {
        result += i
      })
      return [result]
    }
  }
}

module.exports = MapGenerator
<commit_msg>add toFileUrl function<commit_after>'use strict'

let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js')
let { dirname, resolve, relative, sep } = require('path')
let { pathToFileURL } = require('url')

let Input = require('./input')

let sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator)
let pathAvailable = Boolean(dirname && resolve && relative && sep)

class MapGenerator {
  constructor(stringify, root, opts, cssString) {
    this.stringify = stringify
    this.mapOpts = opts.map || {}
    this.root = root
    this.opts = opts
    this.css = cssString
    this.usesFileUrls = !this.mapOpts.from && this.mapOpts.absolute
  }

  isMap() {
    if (typeof this.opts.map !== 'undefined') {
      return !!this.opts.map
    }
    return this.previous().length > 0
  }

  previous() {
    if (!this.previousMaps) {
      this.previousMaps = []
      if (this.root) {
        this.root.walk(node => {
          if (node.source && node.source.input.map) {
            let map = node.source.input.map
            if (!this.previousMaps.includes(map)) {
              this.previousMaps.push(map)
            }
          }
        })
      } else {
        let input = new Input(this.css, this.opts)
        if (input.map) this.previousMaps.push(input.map)
      }
    }

    return this.previousMaps
  }

  isInline() {
    if (typeof this.mapOpts.inline !== 'undefined') {
      return this.mapOpts.inline
    }

    let annotation = this.mapOpts.annotation
    if (typeof annotation !== 'undefined' && annotation !== true) {
      return false
    }

    if (this.previous().length) {
      return this.previous().some(i => i.inline)
    }
    return true
  }

  isSourcesContent() {
    if (typeof this.mapOpts.sourcesContent !== 'undefined') {
      return this.mapOpts.sourcesContent
    }
    if (this.previous().length) {
      return this.previous().some(i => i.withContent())
    }
    return true
  }

  clearAnnotation() {
    if (this.mapOpts.annotation === false) return

    if (this.root) {
      let node
      for (let i = this.root.nodes.length - 1; i >= 0; i--) {
        node = this.root.nodes[i]
        if (node.type !== 'comment') continue
        if (node.text.indexOf('# sourceMappingURL=') === 0) {
          this.root.removeChild(i)
        }
      }
    } else if (this.css) {
      this.css = this.css.replace(/(\n)?\/\*#[\S\s]*?\*\/$/gm, '')
    }
  }

  setSourcesContent() {
    let already = {}
    if (this.root) {
      this.root.walk(node => {
        if (node.source) {
          let from = node.source.input.from
          if (from && !already[from]) {
            already[from] = true
            let fromUrl = this.usesFileUrls
              ? this.toFileUrl(from)
              : this.toUrl(this.path(from))
            this.map.setSourceContent(fromUrl, node.source.input.css)
          }
        }
      })
    } else if (this.css) {
      let from = this.opts.from
        ? this.toUrl(this.path(this.opts.from))
        : '<no source>'
      this.map.setSourceContent(from, this.css)
    }
  }

  applyPrevMaps() {
    for (let prev of this.previous()) {
      let from = this.toUrl(this.path(prev.file))
      let root = prev.root || dirname(prev.file)
      let map

      if (this.mapOpts.sourcesContent === false) {
        map = new SourceMapConsumer(prev.text)
        if (map.sourcesContent) {
          map.sourcesContent = map.sourcesContent.map(() => null)
        }
      } else {
        map = prev.consumer()
      }

      this.map.applySourceMap(map, from, this.toUrl(this.path(root)))
    }
  }

  isAnnotation() {
    if (this.isInline()) {
      return true
    }
    if (typeof this.mapOpts.annotation !== 'undefined') {
      return this.mapOpts.annotation
    }
    if (this.previous().length) {
      return this.previous().some(i => i.annotation)
    }
    return true
  }

  toBase64(str) {
    if (Buffer) {
      return Buffer.from(str).toString('base64')
    } else {
      return window.btoa(unescape(encodeURIComponent(str)))
    }
  }

  addAnnotation() {
    let content

    if (this.isInline()) {
      content =
        'data:application/json;base64,' + this.toBase64(this.map.toString())
    } else if (typeof this.mapOpts.annotation === 'string') {
      content = this.mapOpts.annotation
    } else if (typeof this.mapOpts.annotation === 'function') {
      content = this.mapOpts.annotation(this.opts.to, this.root)
    } else {
      content = this.outputFile() + '.map'
    }
    let eol = '\n'
    if (this.css.includes('\r\n')) eol = '\r\n'

    this.css += eol + '/*# sourceMappingURL=' + content + ' */'
  }

  outputFile() {
    if (this.opts.to) {
      return this.path(this.opts.to)
    } else if (this.opts.from) {
      return this.path(this.opts.from)
    } else {
      return 'to.css'
    }
  }

  generateMap() {
    if (this.root) {
      this.generateString()
    } else if (this.previous().length === 1) {
      let prev = this.previous()[0].consumer()
      prev.file = this.outputFile()
      this.map = SourceMapGenerator.fromSourceMap(prev)
    } else {
      this.map = new SourceMapGenerator({ file: this.outputFile() })
      this.map.addMapping({
        source: this.opts.from
          ? this.toUrl(this.path(this.opts.from))
          : '<no source>',
        generated: { line: 1, column: 0 },
        original: { line: 1, column: 0 }
      })
    }

    if (this.isSourcesContent()) this.setSourcesContent()
    if (this.root && this.previous().length > 0) this.applyPrevMaps()
    if (this.isAnnotation()) this.addAnnotation()

    if (this.isInline()) {
      return [this.css]
    } else {
      return [this.css, this.map]
    }
  }

  path(file) {
    if (file.indexOf('<') === 0) return file
    if (/^\w+:\/\//.test(file)) return file
    if (this.mapOpts.absolute) return file

    let from = this.opts.to ? dirname(this.opts.to) : '.'

    if (typeof this.mapOpts.annotation === 'string') {
      from = dirname(resolve(from, this.mapOpts.annotation))
    }

    file = relative(from, file)
    return file
  }

  toUrl(path) {
    if (sep === '\\') {
      path = path.replace(/\\/g, '/')
    }
    return encodeURI(path).replace(/[#?]/g, encodeURIComponent)
  }

  toFileUrl(path) {
    if (pathToFileURL) {
      return pathToFileURL(path).toString()
    } else {
      throw new Error(
        '`map.absolute` option is not available in this PostCSS build'
      )
    }
  }

  sourcePath(node) {
    if (this.mapOpts.from) {
      return this.toUrl(this.mapOpts.from)
    } else if (this.usesFileUrls) {
      return this.toFileUrl(node.source.input.from)
    } else {
      return this.toUrl(this.path(node.source.input.from))
    }
  }

  generateString() {
    this.css = ''
    this.map = new SourceMapGenerator({ file: this.outputFile() })

    let line = 1
    let column = 1

    let noSource = '<no source>'
    let mapping = {
      source: '',
      generated: { line: 0, column: 0 },
      original: { line: 0, column: 0 }
    }

    let lines, last
    this.stringify(this.root, (str, node, type) => {
      this.css += str

      if (node && type !== 'end') {
        mapping.generated.line = line
        mapping.generated.column = column - 1
        if (node.source && node.source.start) {
          mapping.source = this.sourcePath(node)
          mapping.original.line = node.source.start.line
          mapping.original.column = node.source.start.column - 1
          this.map.addMapping(mapping)
        } else {
          mapping.source = noSource
          mapping.original.line = 1
          mapping.original.column = 0
          this.map.addMapping(mapping)
        }
      }

      lines = str.match(/\n/g)
      if (lines) {
        line += lines.length
        last = str.lastIndexOf('\n')
        column = str.length - last
      } else {
        column += str.length
      }

      if (node && type !== 'start') {
        let p = node.parent || { raws: {} }
        if (node.type !== 'decl' || node !== p.last || p.raws.semicolon) {
          if (node.source && node.source.end) {
            mapping.source = this.sourcePath(node)
            mapping.original.line = node.source.end.line
            mapping.original.column = node.source.end.column - 1
            mapping.generated.line = line
            mapping.generated.column = column - 2
            this.map.addMapping(mapping)
          } else {
            mapping.source = noSource
            mapping.original.line = 1
            mapping.original.column = 0
            mapping.generated.line = line
            mapping.generated.column = column - 1
            this.map.addMapping(mapping)
          }
        }
      }
    })
  }

  generate() {
    this.clearAnnotation()
    if (pathAvailable && sourceMapAvailable && this.isMap()) {
      return this.generateMap()
    } else {
      let result = ''
      this.stringify(this.root, i => {
        result += i
      })
      return [result]
    }
  }
}

module.exports = MapGenerator
<|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');
var date = require('utils/date/date');

App.MainAdminStackUpgradeHistoryView = App.TableView.extend(App.TableServerViewMixin, {

  controllerBinding: 'App.router.mainAdminStackUpgradeHistoryController',

  templateName: require('templates/main/admin/stack_upgrade/upgrade_history'),

  summary: [],

  isReady: false,

  categories: [
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.all',
      value: 'ALL',
      isSelected: true
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.upgrade',
      value: 'UPGRADE',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.downgrade',
      value: 'DOWNGRADE',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.successful.upgrade',
      value: 'UPGRADE_COMPLETED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.aborted.upgrade',
      value: 'UPGRADE_ABORTED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.failed.upgrade',
      value: 'UPGRADE_FAILED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.successful.downgrade',
      value: 'DOWNGRADE_COMPLETED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.aborted.downgrade',
      value: 'DOWNGRADE_ABORTED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.failed.downgrade',
      value: 'DOWNGRADE_FAILED',
      isSelected: false
    })
  ],
  upgradeMethods: [
    Em.Object.create({
      displayName: Em.I18n.t('common.rolling'),
      type: 'ROLLING'
    }),
    Em.Object.create({
      displayName: Em.I18n.t('common.express'),
      type: 'NON_ROLLING'
    }),
    Em.Object.create({
      displayName: Em.I18n.t('common.hostOrdered'),
      type: 'HOST_ORDERED'
    })
  ],

  /**
   * @type {object}
   */
  selectedCategory: Em.computed.findBy('categories', 'isSelected', true),

  filteredCount: function () {
    var filteredContent = this.get('filteredContent').toArray();
    return filteredContent.length;
  }.property('filteredContent'),

  /**
   * displaying content filtered by upgrade type and upgrade status.
   */
  filteredContent: function () {
    var filterValue = 'ALL';
    var category = this.get('selectedCategory');
    if (category) {
      filterValue = category.get('value');
    }
    return this.filterBy(filterValue).reverse();
  }.property('selectedCategory'),

  /**
   * sort and slice recieved content by pagination parameters
   */
  pageContent: function () {
    var content = this.get('filteredContent').toArray();
    content = this.processForDisplay(content);
    content = content.slice(this.get('startIndex') - 1, this.get('endIndex'));
    return content;
  }.property('filteredContent', 'startIndex', 'endIndex'),

  processForDisplay: function (content) {
    var processedContent = [];

    content.forEach(function (item) {
      var direction = item.get('direction') === 'UPGRADE' ? Em.I18n.t('common.upgrade') : Em.I18n.t('common.downgrade');
      var method = this.get('upgradeMethods').findProperty('type', item.get('upgradeType'));
      item.setProperties({
        directionLabel: direction,
        upgradeTypeLabel: method ? method.get('displayName') : method,
        startTimeLabel: date.startTime(item.get('startTime')),
        endTimeLabel: date.startTime(item.get('endTime')),
        duration: date.durationSummary(item.get('startTime'), item.get('endTime'))
      });
      processedContent.push(item);
    }, this);
    return processedContent;
  },

  paginationLeftClass: function () {
    if (this.get("startIndex") > 1) {
      return "paginate_previous";
    }
    return "paginate_disabled_previous";
  }.property("startIndex", 'filteredCount'),

  /**
   * Determines how display "next"-link - as link or text
   * @type {string}
   */
  paginationRightClass: function () {
    if (this.get("endIndex") < this.get("filteredCount")) {
      return "paginate_next";
    }
    return "paginate_disabled_next";
  }.property("endIndex", 'filteredCount'),

  /**
   * Show previous-page if user not in the first page
   * @method previousPage
   */
  previousPage: function () {
    if (this.get('paginationLeftClass') === 'paginate_previous') {
      this._super();
    }
  },

  /**
   * Show next-page if user not in the last page
   * @method nextPage
   */
  nextPage: function () {
    if (this.get('paginationRightClass') === 'paginate_next') {
      this._super();
    }
  },

  willInsertElement: function () {
    var self = this;
    this.get('controller').loadStackUpgradeHistoryToModel().done(function () {
      self.populateUpgradeHistorySummary();
    });
  },

  didInsertElement: function () {
    this.observesCategories();
  },

  observesCategories: function () {
    this.get('categories').forEach(function (category) {
      var label = Em.I18n.t(category.labelKey).format(this.filterBy(category.value).length);
      category.set('label', label)
    }, this);
  }.observes('isReady'),

  filterBy: function (filterValue) {
    if ('ALL' == filterValue) {
      var all_records = App.StackUpgradeHistory.find();
      return all_records.toArray();
    } else {
      var tokens = filterValue.split('_');
      var direction_token = null;
      var status_token = null;

      if (tokens.length == 1) {
        direction_token = tokens[0]
      } else if (tokens.length > 1) {
        direction_token = tokens[0];
        status_token = tokens[1];
      }

      var result = [];
      App.StackUpgradeHistory.find().forEach(function (item) {
        var direction = item.get('direction');
        if (direction == direction_token) {
          if (status_token != null) {
            //only for the given status
            var status = item.get('requestStatus');
            if (status == status_token) {
              result.push(item)
            }
          } else {
            //regardless status
            result.push(item)
          }
        }
      }, this);
      return result
    }
  },

  selectCategory: function (event) {
    this.get('categories').filterProperty('isSelected').setEach('isSelected', false);
    event.context.set('isSelected', true);
  },

  populateUpgradeHistorySummary: function () {
    this.set('isReady', false);
    var result = [
      Em.Object.create({
        direction: 'UPGRADE',
        label: Em.I18n.t('common.upgrade'),
        hasSuccess: false,
        success: 0,
        hasAbort: false,
        abort: 0
      }),
      Em.Object.create({
        direction: 'DOWNGRADE',
        label: Em.I18n.t('common.downgrade'),
        hasSuccess: false,
        success: 0,
        hasAbort: false,
        abort: 0
      })
    ];

    App.StackUpgradeHistory.find().forEach(function (item) {
      var direction = item.get('direction');
      var status = item.get('requestStatus');
      if ('UPGRADE' == direction) {
        if ('COMPLETED' == status) {
          result[0].set('success', result[0].get('success') + 1);
        } else if ('ABORTED' == status) {
          result[0].set('abort', result[0].get('abort') + 1);
        }
      } else if ('DOWNGRADE' == direction) {
        if ('COMPLETED' == status) {
          result[1].set('success', result[1].get('success') + 1);
        } else if ('ABORTED' == status) {
          result[1].set('abort', result[1].get('abort') + 1);
        }
      }
    }, this);

    result[0].set('hasSuccess', result[0].get('success') > 0);
    result[1].set('hasSuccess', result[1].get('success') > 0);
    result[0].set('hasAbort', result[0].get('abort') > 0);
    result[1].set('hasAbort', result[1].get('abort') > 0);

    this.set('summary', result);
    this.set('isReady', true);
  },

  showUpgradeHistoryRecord: function (event) {
    var record = event.context;
    var direction = App.format.normalizeName(record.get('direction'));
    var toVersion = record.get('toVersion');
    var type = this.get('upgradeMethods').findProperty('type', record.get('upgradeType'));
    var displayName = type ? type.get('displayName') : record.get('upgradeType');

    this.get('controller').set('currentUpgradeRecord', record);

    App.ModalPopup.show({
      classNames: ['wizard-modal-wrapper'],
      modalDialogClasses: ['modal-xlg'],
      header: Em.I18n.t('admin.stackVersions.upgradeHistory.record.title').format(displayName, direction, toVersion),
      bodyClass: App.MainAdminStackUpgradeHistoryDetailsView,
      primary: Em.I18n.t('common.dismiss'),
      secondary: null,
      didInsertElement: function () {
        this._super();
        this.fitHeight();
        this.fitInnerHeight();
      },
      fitInnerHeight: function () {
        var block = this.$().find('#modal > .modal-body');
        var scrollable = this.$().find('#modal .scrollable-block');
        scrollable.css('max-height', Number(block.css('max-height').slice(0, -2)) - block.height());
        block.css('max-height', 'none');
      },
    });
  },
});
<commit_msg>AMBARI-19560. Timezone for timestamps in Upgrade History not consistent with Background Operations (onechiporenko)<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');
var date = require('utils/date/date');

App.MainAdminStackUpgradeHistoryView = App.TableView.extend(App.TableServerViewMixin, {

  controllerBinding: 'App.router.mainAdminStackUpgradeHistoryController',

  templateName: require('templates/main/admin/stack_upgrade/upgrade_history'),

  summary: [],

  isReady: false,

  categories: [
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.all',
      value: 'ALL',
      isSelected: true
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.upgrade',
      value: 'UPGRADE',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.downgrade',
      value: 'DOWNGRADE',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.successful.upgrade',
      value: 'UPGRADE_COMPLETED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.aborted.upgrade',
      value: 'UPGRADE_ABORTED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.failed.upgrade',
      value: 'UPGRADE_FAILED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.successful.downgrade',
      value: 'DOWNGRADE_COMPLETED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.aborted.downgrade',
      value: 'DOWNGRADE_ABORTED',
      isSelected: false
    }),
    Em.Object.create({
      labelKey: 'admin.stackVersions.upgradeHistory.filter.failed.downgrade',
      value: 'DOWNGRADE_FAILED',
      isSelected: false
    })
  ],
  upgradeMethods: [
    Em.Object.create({
      displayName: Em.I18n.t('common.rolling'),
      type: 'ROLLING'
    }),
    Em.Object.create({
      displayName: Em.I18n.t('common.express'),
      type: 'NON_ROLLING'
    }),
    Em.Object.create({
      displayName: Em.I18n.t('common.hostOrdered'),
      type: 'HOST_ORDERED'
    })
  ],

  /**
   * @type {object}
   */
  selectedCategory: Em.computed.findBy('categories', 'isSelected', true),

  filteredCount: function () {
    var filteredContent = this.get('filteredContent').toArray();
    return filteredContent.length;
  }.property('filteredContent'),

  /**
   * displaying content filtered by upgrade type and upgrade status.
   */
  filteredContent: function () {
    var filterValue = 'ALL';
    var category = this.get('selectedCategory');
    if (category) {
      filterValue = category.get('value');
    }
    return this.filterBy(filterValue).reverse();
  }.property('selectedCategory'),

  /**
   * sort and slice recieved content by pagination parameters
   */
  pageContent: function () {
    var content = this.get('filteredContent').toArray();
    content = this.processForDisplay(content);
    content = content.slice(this.get('startIndex') - 1, this.get('endIndex'));
    return content;
  }.property('filteredContent', 'startIndex', 'endIndex'),

  processForDisplay: function (content) {
    var processedContent = [];

    content.forEach(function (item) {
      var direction = item.get('direction') === 'UPGRADE' ? Em.I18n.t('common.upgrade') : Em.I18n.t('common.downgrade');
      var method = this.get('upgradeMethods').findProperty('type', item.get('upgradeType'));
      item.setProperties({
        directionLabel: direction,
        upgradeTypeLabel: method ? method.get('displayName') : method,
        startTimeLabel: App.dateTimeWithTimeZone(item.get('startTime')),
        endTimeLabel: App.dateTimeWithTimeZone(item.get('endTime')),
        duration: date.durationSummary(item.get('startTime'), item.get('endTime'))
      });
      processedContent.push(item);
    }, this);
    return processedContent;
  },

  paginationLeftClass: function () {
    if (this.get("startIndex") > 1) {
      return "paginate_previous";
    }
    return "paginate_disabled_previous";
  }.property("startIndex", 'filteredCount'),

  /**
   * Determines how display "next"-link - as link or text
   * @type {string}
   */
  paginationRightClass: function () {
    if (this.get("endIndex") < this.get("filteredCount")) {
      return "paginate_next";
    }
    return "paginate_disabled_next";
  }.property("endIndex", 'filteredCount'),

  /**
   * Show previous-page if user not in the first page
   * @method previousPage
   */
  previousPage: function () {
    if (this.get('paginationLeftClass') === 'paginate_previous') {
      this._super();
    }
  },

  /**
   * Show next-page if user not in the last page
   * @method nextPage
   */
  nextPage: function () {
    if (this.get('paginationRightClass') === 'paginate_next') {
      this._super();
    }
  },

  willInsertElement: function () {
    var self = this;
    this.get('controller').loadStackUpgradeHistoryToModel().done(function () {
      self.populateUpgradeHistorySummary();
    });
  },

  didInsertElement: function () {
    this.observesCategories();
  },

  observesCategories: function () {
    this.get('categories').forEach(function (category) {
      var label = Em.I18n.t(category.labelKey).format(this.filterBy(category.value).length);
      category.set('label', label)
    }, this);
  }.observes('isReady'),

  filterBy: function (filterValue) {
    if ('ALL' == filterValue) {
      var all_records = App.StackUpgradeHistory.find();
      return all_records.toArray();
    } else {
      var tokens = filterValue.split('_');
      var direction_token = null;
      var status_token = null;

      if (tokens.length == 1) {
        direction_token = tokens[0]
      } else if (tokens.length > 1) {
        direction_token = tokens[0];
        status_token = tokens[1];
      }

      var result = [];
      App.StackUpgradeHistory.find().forEach(function (item) {
        var direction = item.get('direction');
        if (direction == direction_token) {
          if (status_token != null) {
            //only for the given status
            var status = item.get('requestStatus');
            if (status == status_token) {
              result.push(item)
            }
          } else {
            //regardless status
            result.push(item)
          }
        }
      }, this);
      return result
    }
  },

  selectCategory: function (event) {
    this.get('categories').filterProperty('isSelected').setEach('isSelected', false);
    event.context.set('isSelected', true);
  },

  populateUpgradeHistorySummary: function () {
    this.set('isReady', false);
    var result = [
      Em.Object.create({
        direction: 'UPGRADE',
        label: Em.I18n.t('common.upgrade'),
        hasSuccess: false,
        success: 0,
        hasAbort: false,
        abort: 0
      }),
      Em.Object.create({
        direction: 'DOWNGRADE',
        label: Em.I18n.t('common.downgrade'),
        hasSuccess: false,
        success: 0,
        hasAbort: false,
        abort: 0
      })
    ];

    App.StackUpgradeHistory.find().forEach(function (item) {
      var direction = item.get('direction');
      var status = item.get('requestStatus');
      if ('UPGRADE' == direction) {
        if ('COMPLETED' == status) {
          result[0].set('success', result[0].get('success') + 1);
        } else if ('ABORTED' == status) {
          result[0].set('abort', result[0].get('abort') + 1);
        }
      } else if ('DOWNGRADE' == direction) {
        if ('COMPLETED' == status) {
          result[1].set('success', result[1].get('success') + 1);
        } else if ('ABORTED' == status) {
          result[1].set('abort', result[1].get('abort') + 1);
        }
      }
    }, this);

    result[0].set('hasSuccess', result[0].get('success') > 0);
    result[1].set('hasSuccess', result[1].get('success') > 0);
    result[0].set('hasAbort', result[0].get('abort') > 0);
    result[1].set('hasAbort', result[1].get('abort') > 0);

    this.set('summary', result);
    this.set('isReady', true);
  },

  showUpgradeHistoryRecord: function (event) {
    var record = event.context;
    var direction = App.format.normalizeName(record.get('direction'));
    var toVersion = record.get('toVersion');
    var type = this.get('upgradeMethods').findProperty('type', record.get('upgradeType'));
    var displayName = type ? type.get('displayName') : record.get('upgradeType');

    this.get('controller').set('currentUpgradeRecord', record);

    App.ModalPopup.show({
      classNames: ['wizard-modal-wrapper'],
      modalDialogClasses: ['modal-xlg'],
      header: Em.I18n.t('admin.stackVersions.upgradeHistory.record.title').format(displayName, direction, toVersion),
      bodyClass: App.MainAdminStackUpgradeHistoryDetailsView,
      primary: Em.I18n.t('common.dismiss'),
      secondary: null,
      didInsertElement: function () {
        this._super();
        this.fitHeight();
        this.fitInnerHeight();
      },
      fitInnerHeight: function () {
        var block = this.$().find('#modal > .modal-body');
        var scrollable = this.$().find('#modal .scrollable-block');
        scrollable.css('max-height', Number(block.css('max-height').slice(0, -2)) - block.height());
        block.css('max-height', 'none');
      },
    });
  },
});
<|endoftext|>


<commit_before>/** @flow */
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import ReactDOMServer from 'react-dom/server'

/**
 * Measures a Grid cell's contents by rendering them in a way that is not visible to the user.
 * Either a fixed width or height may be provided if it is desirable to measure only in one direction.
 */
export default class CellMeasurer extends Component {

  static propTypes = {
    /**
     * Renders a cell given its indices.
     * Should implement the following interface: ({ columnIndex: number, rowIndex: number }): PropTypes.node
     */
    cellRenderer: PropTypes.func.isRequired,

    /**
     * Function respondible for rendering a virtualized component.
     * This function should implement the following signature:
     * ({ getColumnWidth, getRowHeight, resetMeasurements }) => PropTypes.element
     */
    children: PropTypes.func.isRequired,

    /**
     * Number of columns in grid.
     */
    columnCount: PropTypes.number.isRequired,

    /**
     * A Node, Component instance, or function that returns either.
     * If this property is not specified the document body will be used.
     */
    container: React.PropTypes.oneOfType([
      React.PropTypes.func,
      React.PropTypes.node
    ]),

    /**
     * Assign a fixed :height in order to measure dynamic text :width only.
     */
    height: PropTypes.number,

    /**
     * Number of rows in grid.
     */
    rowCount: PropTypes.number.isRequired,

    /**
     * Assign a fixed :width in order to measure dynamic text :height only.
     */
    width: PropTypes.number
  };

  constructor (props, state) {
    super(props, state)

    this._cachedColumnWidths = {}
    this._cachedRowHeights = {}

    this.getColumnWidth = this.getColumnWidth.bind(this)
    this.getRowHeight = this.getRowHeight.bind(this)
    this.resetMeasurements = this.resetMeasurements.bind(this)
  }

  getColumnWidth ({ index }) {
    if (this._cachedColumnWidths[index]) {
      return this._cachedColumnWidths[index]
    }

    const { rowCount } = this.props

    let maxWidth = 0

    for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
      let { width } = this._measureCell({
        columnIndex: index,
        rowIndex
      })

      maxWidth = Math.max(maxWidth, width)
    }

    this._cachedColumnWidths[index] = maxWidth

    return maxWidth
  }

  getRowHeight ({ index }) {
    if (this._cachedRowHeights[index]) {
      return this._cachedRowHeights[index]
    }

    const { columnCount } = this.props

    let maxHeight = 0

    for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
      let { height } = this._measureCell({
        columnIndex,
        rowIndex: index
      })

      maxHeight = Math.max(maxHeight, height)
    }

    this._cachedRowHeights[index] = maxHeight

    return maxHeight
  }

  resetMeasurements () {
    this._cachedColumnWidths = {}
    this._cachedRowHeights = {}
  }

  componentDidMount () {
    this._renderAndMount()
  }

  componentWillReceiveProps (nextProps) {
    this._updateDivDimensions(nextProps)
  }

  componentWillUnmount () {
    this._unmountContainer()
  }

  render () {
    const { children } = this.props

    return children({
      getColumnWidth: this.getColumnWidth,
      getRowHeight: this.getRowHeight,
      resetMeasurements: this.resetMeasurements
    })
  }

  _getContainerNode (props) {
    const { container } = props

    if (container) {
      return ReactDOM.findDOMNode(
        typeof container === 'function'
          ? container()
          : container
      )
    } else {
      const node = ReactDOM.findDOMNode(this)

      return node.ownerDocument.body
    }
  }

  _measureCell ({
    columnIndex,
    rowIndex
  }) {
    const { cellRenderer } = this.props

    const rendered = cellRenderer({
      columnIndex,
      rowIndex
    })

    this._div.innerHTML = ReactDOMServer.renderToString(rendered)

    const height = this._div.clientHeight
    const width = this._div.clientWidth

    return {
      height,
      width
    }
  }

  _renderAndMount () {
    if (!this._div) {
      this._div = document.createElement('div')
      this._div.style.display = 'inline-block'
      this._div.style.position = 'absolute'
      this._div.style.visibility = 'hidden'
      this._div.style.zIndex = -1

      this._updateDivDimensions(this.props)

      this._containerNode = this._getContainerNode(this.props)
      this._containerNode.appendChild(this._div)
    }
  }

  _unmountContainer () {
    if (this._div) {
      this._containerNode.removeChild(this._div)

      this._div = null
    }

    this._containerNode = null
  }

  _updateDivDimensions (props) {
    const { height, width } = props

    if (
      height &&
      height !== this._divHeight
    ) {
      this._divHeight = height
      this._div.style.height = `${height}px`
    }

    if (
      width &&
      width !== this._divWidth
    ) {
      this._divWidth = width
      this._div.style.width = `${width}px`
    }
  }
}
<commit_msg>Avoid querying cell for :clientWidth or :clientHeight unless needed<commit_after>/** @flow */
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import ReactDOMServer from 'react-dom/server'

/**
 * Measures a Grid cell's contents by rendering them in a way that is not visible to the user.
 * Either a fixed width or height may be provided if it is desirable to measure only in one direction.
 */
export default class CellMeasurer extends Component {

  static propTypes = {
    /**
     * Renders a cell given its indices.
     * Should implement the following interface: ({ columnIndex: number, rowIndex: number }): PropTypes.node
     */
    cellRenderer: PropTypes.func.isRequired,

    /**
     * Function respondible for rendering a virtualized component.
     * This function should implement the following signature:
     * ({ getColumnWidth, getRowHeight, resetMeasurements }) => PropTypes.element
     */
    children: PropTypes.func.isRequired,

    /**
     * Number of columns in grid.
     */
    columnCount: PropTypes.number.isRequired,

    /**
     * A Node, Component instance, or function that returns either.
     * If this property is not specified the document body will be used.
     */
    container: React.PropTypes.oneOfType([
      React.PropTypes.func,
      React.PropTypes.node
    ]),

    /**
     * Assign a fixed :height in order to measure dynamic text :width only.
     */
    height: PropTypes.number,

    /**
     * Number of rows in grid.
     */
    rowCount: PropTypes.number.isRequired,

    /**
     * Assign a fixed :width in order to measure dynamic text :height only.
     */
    width: PropTypes.number
  };

  constructor (props, state) {
    super(props, state)

    this._cachedColumnWidths = {}
    this._cachedRowHeights = {}

    this.getColumnWidth = this.getColumnWidth.bind(this)
    this.getRowHeight = this.getRowHeight.bind(this)
    this.resetMeasurements = this.resetMeasurements.bind(this)
  }

  getColumnWidth ({ index }) {
    if (this._cachedColumnWidths[index]) {
      return this._cachedColumnWidths[index]
    }

    const { rowCount } = this.props

    let maxWidth = 0

    for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
      let { width } = this._measureCell({
        clientWidth: true,
        columnIndex: index,
        rowIndex
      })

      maxWidth = Math.max(maxWidth, width)
    }

    this._cachedColumnWidths[index] = maxWidth

    return maxWidth
  }

  getRowHeight ({ index }) {
    if (this._cachedRowHeights[index]) {
      return this._cachedRowHeights[index]
    }

    const { columnCount } = this.props

    let maxHeight = 0

    for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
      let { height } = this._measureCell({
        clientHeight: true,
        columnIndex,
        rowIndex: index
      })

      maxHeight = Math.max(maxHeight, height)
    }

    this._cachedRowHeights[index] = maxHeight

    return maxHeight
  }

  resetMeasurements () {
    this._cachedColumnWidths = {}
    this._cachedRowHeights = {}
  }

  componentDidMount () {
    this._renderAndMount()
  }

  componentWillReceiveProps (nextProps) {
    this._updateDivDimensions(nextProps)
  }

  componentWillUnmount () {
    this._unmountContainer()
  }

  render () {
    const { children } = this.props

    return children({
      getColumnWidth: this.getColumnWidth,
      getRowHeight: this.getRowHeight,
      resetMeasurements: this.resetMeasurements
    })
  }

  _getContainerNode (props) {
    const { container } = props

    if (container) {
      return ReactDOM.findDOMNode(
        typeof container === 'function'
          ? container()
          : container
      )
    } else {
      const node = ReactDOM.findDOMNode(this)

      return node.ownerDocument.body
    }
  }

  _measureCell ({
    clientHeight = false,
    clientWidth = true,
    columnIndex,
    rowIndex
  }) {
    const { cellRenderer } = this.props

    const rendered = cellRenderer({
      columnIndex,
      rowIndex
    })

    this._div.innerHTML = ReactDOMServer.renderToString(rendered)

    return {
      height: clientHeight && this._div.clientHeight,
      width: clientWidth && this._div.clientWidth
    }
  }

  _renderAndMount () {
    if (!this._div) {
      this._div = document.createElement('div')
      this._div.style.display = 'inline-block'
      this._div.style.position = 'absolute'
      this._div.style.visibility = 'hidden'
      this._div.style.zIndex = -1

      this._updateDivDimensions(this.props)

      this._containerNode = this._getContainerNode(this.props)
      this._containerNode.appendChild(this._div)
    }
  }

  _unmountContainer () {
    if (this._div) {
      this._containerNode.removeChild(this._div)

      this._div = null
    }

    this._containerNode = null
  }

  _updateDivDimensions (props) {
    const { height, width } = props

    if (
      height &&
      height !== this._divHeight
    ) {
      this._divHeight = height
      this._div.style.height = `${height}px`
    }

    if (
      width &&
      width !== this._divWidth
    ) {
      this._divWidth = width
      this._div.style.width = `${width}px`
    }
  }
}
<|endoftext|>