<commit_before>// Temporary AsterixExpression Placeholder
function AExpression () {
    this._properties = {};
    this._success = function() {};

    return this;
}

AExpression.prototype.bind = function(options) {
    var options = options || {};

    if (options.hasOwnProperty("dataverse")) {
        this._properties["dataverse"] = options["dataverse"];
    }

    if (options.hasOwnProperty("success")) {
        this._success = options["success"];
    }

    if (options.hasOwnProperty("return")) {
        this._properties["return"] = " return " + options["return"].val();
    }
};

AExpression.prototype.run = function() {
    var success_fn = this._success;

    $.ajax({
        type : 'GET',
        url : "http://localhost:19101/query",
        data : {"query" : this.val()},
        dataType : "json",
        success : function(data) {
            success_fn(data);
        }
    });

    return this;
};

AExpression.prototype.val = function() {

    var value = "";

    // If there is a dataverse defined, provide it.
    if (this._properties.hasOwnProperty("dataverse")) {
        value += "use dataverse " + this._properties["dataverse"] + ";\n";
    };

    if (this._properties.hasOwnProperty("value")) {
        value += this._properties["value"];
    }

    return value;
};

// @param expressionValue [String]
AExpression.prototype.set = function(expressionValue) {
    this._properties["value"] = expressionValue;
    return this;
};

AExpression.prototype.error = function(msg) {
    return "Asterix FunctionExpression Error: " + msg;
};

// FunctionExpression
// Parent: AsterixExpression
//
// @param   options [Various],
// @key     function [String], a function to be applid to the expression
// @key     expression [AsterixExpression or AsterixClause] an AsterixExpression/Clause to which the fn will be applied
function FunctionExpression(options) {

    // Initialize superclass
    AExpression.call(this);

    // Possible to initialize a function epxression without inputs, or with them
    this.bind(options);

    // Return object
    return this;
}

FunctionExpression.prototype = Object.create(AExpression.prototype);
FunctionExpression.prototype.constructor = FunctionExpression;

FunctionExpression.prototype.bind = function(options) {

    AExpression.prototype.bind.call(this, options);

    var options = options || {};

    if (options.hasOwnProperty("function")) {
        this._properties["function"] = options["function"];
    }

    if (options.hasOwnProperty("expression")) {
        this._properties["expression"] = options["expression"];
    }

    return this;
};

FunctionExpression.prototype.val = function () {
    return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
};

// FLWOGR         ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
// Clause         ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
//
// WhereClause    ::= "where" Expression
// OrderbyClause  ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
//
// GroupClause    ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
// LimitClause    ::= "limit" Expression ( "offset" Expression )?
// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*

// FLWOGRExpression
//
// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
function FLWOGRExpression (options) {
    // Initialize superclass
    AExpression.call(this);

    this._properties["clauses"] = [];
    this._properties["minSize"] = 0;

    // Bind options and return
    this.bind(options);
    return this;
}

FLWOGRExpression.prototype = Object.create(AExpression.prototype);
FLWOGRExpression.prototype.constructor = FLWOGRExpression;

FLWOGRExpression.prototype.bind = function(options) {
    AExpression.prototype.bind.call(this, options);

    var options = options || {};

    if (options instanceof SetStatement) {
         this._properties["clauses"].push(options);
         this._properties["minSize"] += 1;
    }

    if (this._properties["clauses"].length <= this._properties["minSize"]) {
        // Needs to start with for or let clause
        if (options instanceof ForClause || options instanceof LetClause) {
            this._properties["clauses"].push(options);
        }
    } else {
        if (options instanceof AQLClause) {
            this._properties["clauses"].push(options);
        }
    }

    return this;
};

FLWOGRExpression.prototype.val = function() {
    var value = AExpression.prototype.val.call(this);

    var clauseValues = [];
    for (var c in this._properties["clauses"]) {
        clauseValues.push(this._properties["clauses"][c].val());
    }

    return value + clauseValues.join("\n");// + ";";
};

// AQLClause
//
// Base Clause  ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
function AQLClause() {
    this._properties = {};
    this._properties["clause"] = "";
}

AQLClause.prototype.val = function() {
    var value = this._properties["clause"];

    if (this._properties.hasOwnProperty("return")) {
        value += " return " + this._properties["return"].val();
    }

    return value;
};

AQLClause.prototype.bind = function(options) {
    var options = options || {};

    if (options.hasOwnProperty("return")) {
        this._properties["return"] = options["return"];
    }

    return this;
};

AQLClause.prototype.set = function(value) {
    this._properties["clause"] = value;
    return this;
};

// ForClause
//
// Grammar:
// "for" Variable ( "at" Variable )? "in" ( Expression )
//
// @param for_variable [String], REQUIRED, first variable in clause
// @param at_variable [String], NOT REQUIRED, first variable in clause
// @param expression [AsterixExpression], REQUIRED, expression to evaluate
//
// TODO Error Checking
function ForClause(for_variable, at_variable, expression) {
    AQLClause.call(this);

    // at_variable is optional, check if defined
    var at = typeof at_variable ? at_variable : null;

    // Prepare clause
    this._properties["clause"] = "for $" + for_variable;
    if (at != null) {
        this._properties["clause"] += " at $" + at_variable;
    }
    this._properties["clause"] += " in " + expression.val();
    return this;
}

ForClause.prototype = Object.create(AQLClause.prototype);
ForClause.prototype.constructor = ForClause;

// LetClause
//
// Grammar:
// LetClause      ::= "let" Variable ":=" Expression
//
// @param let_variable [String]
// @param expression [AExpression]
//
// TODO Vigorous error checking
function LetClause(let_variable, expression) {
    AQLClause.call(this);

    this._properties["clause"] = "let $" + let_variable + " := ";
    this._properties["clause"] += expression.val();

    return this;
}

LetClause.prototype = Object.create(AQLClause.prototype);
LetClause.prototype.constructor = LetClause;

// ReturnClause
//
// Grammar:
// return [AQLExpression]
function ReturnClause(expression) {
    AQLClause.call(this);

    this._properties["clause"] = "return ";
    if (expression instanceof AExpression || expression instanceof AQLClause) {
        this._properties["clause"] += expression.val();
    } else if ( Object.getPrototypeOf( expression ) === Object.prototype ) {

        this._properties["clause"] += "{";
        var returnStatements = [];
        for (returnValue in expression) {

            if (expression[returnValue] instanceof AExpression) {
                returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
            } else if (typeof expression[returnValue] == "string") {
                returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
            }
        }
        this._properties["clause"] += returnStatements.join(",\n");
        this._properties["clause"] += "}";

    } else {
        this._properties["clause"] += new AExpression().set(expression).val();
    }

    return this;
}

ReturnClause.prototype = Object.create(AQLClause.prototype);
ReturnClause.prototype.constructor = ReturnClause;

ReturnClause.prototype.val = function () {
    return this._properties["clause"];
};

// WhereClause
//
// Grammar:
// ::= "where" Expression
//
// @param expression [BooleanExpression], pushes this expression onto the stack
function WhereClause(expression) {
    AQLClause.call(this);

    this._properties["stack"] = [];

    this.bind(expression);

    return this;
}

WhereClause.prototype = Object.create(AQLClause.prototype);
WhereClause.prototype.constructor = WhereClause;

WhereClause.prototype.bind = function(expression) {
    if (expression instanceof AExpression) {
        this._properties["stack"].push(expression);
    }
};

WhereClause.prototype.val = function() {
    var value = "where ";

    var count = this._properties["stack"].length - 1;
    while (count >= 0) {
        value += this._properties["stack"][count].val() + " ";
        count -= 1;
    }

    return value;
};

// LimitClause
// Grammar:
// LimitClause    ::= "limit" Expression ( "offset" Expression )?
//
// @param   limitExpression [REQUIRED, AQLExpression]
// @param   offsetExpression [OPTIONAL, AQLExpression]
function LimitClause(limitExpression, offsetExpression) {

    AQLClause.call(this);

    // limitExpression required
    this._properties["clause"] = "limit " + limitExpression.val();

    // Optional: Offset
    var offset = typeof offsetExpression ? offsetExpression : null;
    if (offset != null) {
        this._properties["clause"] += " offset " + offsetExpression.val();
    }

    return this;
}

LimitClause.prototype = Object.create(AQLClause.prototype);
LimitClause.prototype.constructor = LimitClause;

// OrderbyClause
//
// Grammar:
// OrderbyClause  ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
//
// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
function OrderbyClause() {

    AQLClause.call(this);

    // At least one argument expression is required, and first should be expression
    if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
        // TODO Not sure which error to throw for an empty OrderBy but this should fail.
        alert("Order By Error");
        this._properties["clause"] = null;
        return this;
    }

    var expc = 0;
    var expressions = [];

    while (expc < arguments.length) {

        var expression = "";

        if (arguments[expc] instanceof AExpression) {
            expression += arguments[expc].val();
        }

        var next = expc + 1;
        if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
            expc++;
            expression += " " + arguments[expc];
        }

        expressions.push(expression);

        expc++;
    }

    this._properties["clause"] = "order by " + expressions.join(", ");
    return this;
}

OrderbyClause.prototype = Object.create(AQLClause.prototype);
OrderbyClause.prototype.constructor = OrderbyClause;

// GroupClause
//
// Grammar:
// GroupClause    ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
function GroupClause() {
    AQLClause.call(this);

    if (arguments.length == 0) {
        // TODO Not sure which error to throw for an empty GroupBy but this should fail.
        alert("Group Error");
        this._properties["clause"] = null;
        return this;
    }

    var expc = 0;
    var expressions = [];
    var variableRefs = [];
    var isDecor = false;

    while (expc < arguments.length) {

        if (arguments[expc] instanceof AExpression) {

            isDecor = false;
            expressions.push(arguments[expc].val());

        } else if (typeof arguments[expc] == "string") {

            // Special keywords, decor & with
            if (arguments[expc] == "decor") {
                isDecor = true;
            } else if (arguments[expc] == "with") {
                isDecor = false;
                expc++;
                while (expc < arguments.length) {
                    variableRefs.push("$" + arguments[expc]);
                    expc++;
                }

            // Variables and variable refs
            } else {

                var nextc = expc + 1;
                var expression = "";

                if (isDecor) {
                    expression += "decor ";
                    isDecor = false;
                }

                expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
                expressions.push(expression);
                expc++;
            }
        }

        expc++;
    }

    this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
    return this;
}

GroupClause.prototype = Object.create(AQLClause.prototype);
GroupClause.prototype.constructor = GroupClause;

// BooleanExpression
//
// TODO
function BooleanExpression(expression) {
    this.value = expression;
    alert("Debugging Bool: " + arguments.length + " " + expression);
}

BooleanExpression.prototype.val = function() {
    return this.value;
}

// SetStatement
//
// Grammar
// "set" Identifier StringLiteral
function SetStatement (identifier, stringLiteral) {
    AExpression.call(this);

    var statement = "set " + identifier + ' "' + stringLiteral + '";';

    AExpression.prototype.set.call(this, statement);

    return this;
}

SetStatement.prototype = Object.create(AExpression.prototype);
SetStatement.prototype.constructor = SetStatement;

// Quantified Expression
//
// Grammar
// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
//
// @param String some/every
// @param [AExpression]
// @param [Aexpression] satisfiesExpression
function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
    AExpression.call(this);

    var expression = keyword + " ";
    var varsInExpressions = [];

    for (var varInExpression in expressions) {
        varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
    }
    expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();

    AExpression.prototype.set.call(this, expression);

    return this;
}

QuantifiedExpression.prototype = Object.create(AExpression.prototype);
QuantifiedExpression.prototype.constructor = QuantifiedExpression;

QuantifiedExpression.prototype.val = function() {
    var value = AExpression.prototype.val.call(this);
    return "(" + value + ")";
};

// Functions that can be used to call core expressions/clauses more cleanly
function AFLWOGR () {

}

function AClause () {

}

function ALetClause () {

}

function AWhereClause () {

}

function AOrderbyClause () {

}

function AGroupClause () {

}

function ALimitClause () {

}

function ADistinctClause () {

}

function AVariable () {

}
<commit_msg>Updates REST API port to 19002<commit_after>// Temporary AsterixExpression Placeholder
function AExpression () {
    this._properties = {};
    this._success = function() {};

    return this;
}

AExpression.prototype.bind = function(options) {
    var options = options || {};

    if (options.hasOwnProperty("dataverse")) {
        this._properties["dataverse"] = options["dataverse"];
    }

    if (options.hasOwnProperty("success")) {
        this._success = options["success"];
    }

    if (options.hasOwnProperty("return")) {
        this._properties["return"] = " return " + options["return"].val();
    }
};

AExpression.prototype.run = function() {
    var success_fn = this._success;

    $.ajax({
        type : 'GET',
        url : "http://localhost:19002/query",
        data : {"query" : this.val()},
        dataType : "json",
        success : function(data) {
            success_fn(data);
        }
    });

    return this;
};

AExpression.prototype.val = function() {

    var value = "";

    // If there is a dataverse defined, provide it.
    if (this._properties.hasOwnProperty("dataverse")) {
        value += "use dataverse " + this._properties["dataverse"] + ";\n";
    };

    if (this._properties.hasOwnProperty("value")) {
        value += this._properties["value"];
    }

    return value;
};

// @param expressionValue [String]
AExpression.prototype.set = function(expressionValue) {
    this._properties["value"] = expressionValue;
    return this;
};

AExpression.prototype.error = function(msg) {
    return "Asterix FunctionExpression Error: " + msg;
};

// FunctionExpression
// Parent: AsterixExpression
//
// @param   options [Various],
// @key     function [String], a function to be applid to the expression
// @key     expression [AsterixExpression or AsterixClause] an AsterixExpression/Clause to which the fn will be applied
function FunctionExpression(options) {

    // Initialize superclass
    AExpression.call(this);

    // Possible to initialize a function epxression without inputs, or with them
    this.bind(options);

    // Return object
    return this;
}

FunctionExpression.prototype = Object.create(AExpression.prototype);
FunctionExpression.prototype.constructor = FunctionExpression;

FunctionExpression.prototype.bind = function(options) {

    AExpression.prototype.bind.call(this, options);

    var options = options || {};

    if (options.hasOwnProperty("function")) {
        this._properties["function"] = options["function"];
    }

    if (options.hasOwnProperty("expression")) {
        this._properties["expression"] = options["expression"];
    }

    return this;
};

FunctionExpression.prototype.val = function () {
    return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
};

// FLWOGR         ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
// Clause         ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
//
// WhereClause    ::= "where" Expression
// OrderbyClause  ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
//
// GroupClause    ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
// LimitClause    ::= "limit" Expression ( "offset" Expression )?
// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*

// FLWOGRExpression
//
// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
function FLWOGRExpression (options) {
    // Initialize superclass
    AExpression.call(this);

    this._properties["clauses"] = [];
    this._properties["minSize"] = 0;

    // Bind options and return
    this.bind(options);
    return this;
}

FLWOGRExpression.prototype = Object.create(AExpression.prototype);
FLWOGRExpression.prototype.constructor = FLWOGRExpression;

FLWOGRExpression.prototype.bind = function(options) {
    AExpression.prototype.bind.call(this, options);

    var options = options || {};

    if (options instanceof SetStatement) {
         this._properties["clauses"].push(options);
         this._properties["minSize"] += 1;
    }

    if (this._properties["clauses"].length <= this._properties["minSize"]) {
        // Needs to start with for or let clause
        if (options instanceof ForClause || options instanceof LetClause) {
            this._properties["clauses"].push(options);
        }
    } else {
        if (options instanceof AQLClause) {
            this._properties["clauses"].push(options);
        }
    }

    return this;
};

FLWOGRExpression.prototype.val = function() {
    var value = AExpression.prototype.val.call(this);

    var clauseValues = [];
    for (var c in this._properties["clauses"]) {
        clauseValues.push(this._properties["clauses"][c].val());
    }

    return value + clauseValues.join("\n");// + ";";
};

// AQLClause
//
// Base Clause  ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
function AQLClause() {
    this._properties = {};
    this._properties["clause"] = "";
}

AQLClause.prototype.val = function() {
    var value = this._properties["clause"];

    if (this._properties.hasOwnProperty("return")) {
        value += " return " + this._properties["return"].val();
    }

    return value;
};

AQLClause.prototype.bind = function(options) {
    var options = options || {};

    if (options.hasOwnProperty("return")) {
        this._properties["return"] = options["return"];
    }

    return this;
};

AQLClause.prototype.set = function(value) {
    this._properties["clause"] = value;
    return this;
};

// ForClause
//
// Grammar:
// "for" Variable ( "at" Variable )? "in" ( Expression )
//
// @param for_variable [String], REQUIRED, first variable in clause
// @param at_variable [String], NOT REQUIRED, first variable in clause
// @param expression [AsterixExpression], REQUIRED, expression to evaluate
//
// TODO Error Checking
function ForClause(for_variable, at_variable, expression) {
    AQLClause.call(this);

    // at_variable is optional, check if defined
    var at = typeof at_variable ? at_variable : null;

    // Prepare clause
    this._properties["clause"] = "for $" + for_variable;
    if (at != null) {
        this._properties["clause"] += " at $" + at_variable;
    }
    this._properties["clause"] += " in " + expression.val();
    return this;
}

ForClause.prototype = Object.create(AQLClause.prototype);
ForClause.prototype.constructor = ForClause;

// LetClause
//
// Grammar:
// LetClause      ::= "let" Variable ":=" Expression
//
// @param let_variable [String]
// @param expression [AExpression]
//
// TODO Vigorous error checking
function LetClause(let_variable, expression) {
    AQLClause.call(this);

    this._properties["clause"] = "let $" + let_variable + " := ";
    this._properties["clause"] += expression.val();

    return this;
}

LetClause.prototype = Object.create(AQLClause.prototype);
LetClause.prototype.constructor = LetClause;

// ReturnClause
//
// Grammar:
// return [AQLExpression]
function ReturnClause(expression) {
    AQLClause.call(this);

    this._properties["clause"] = "return ";
    if (expression instanceof AExpression || expression instanceof AQLClause) {
        this._properties["clause"] += expression.val();
    } else if ( Object.getPrototypeOf( expression ) === Object.prototype ) {

        this._properties["clause"] += "{";
        var returnStatements = [];
        for (returnValue in expression) {

            if (expression[returnValue] instanceof AExpression) {
                returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());
            } else if (typeof expression[returnValue] == "string") {
                returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);
            }
        }
        this._properties["clause"] += returnStatements.join(",\n");
        this._properties["clause"] += "}";

    } else {
        this._properties["clause"] += new AExpression().set(expression).val();
    }

    return this;
}

ReturnClause.prototype = Object.create(AQLClause.prototype);
ReturnClause.prototype.constructor = ReturnClause;

ReturnClause.prototype.val = function () {
    return this._properties["clause"];
};

// WhereClause
//
// Grammar:
// ::= "where" Expression
//
// @param expression [BooleanExpression], pushes this expression onto the stack
function WhereClause(expression) {
    AQLClause.call(this);

    this._properties["stack"] = [];

    this.bind(expression);

    return this;
}

WhereClause.prototype = Object.create(AQLClause.prototype);
WhereClause.prototype.constructor = WhereClause;

WhereClause.prototype.bind = function(expression) {
    if (expression instanceof AExpression) {
        this._properties["stack"].push(expression);
    }
};

WhereClause.prototype.val = function() {
    var value = "where ";

    var count = this._properties["stack"].length - 1;
    while (count >= 0) {
        value += this._properties["stack"][count].val() + " ";
        count -= 1;
    }

    return value;
};

// LimitClause
// Grammar:
// LimitClause    ::= "limit" Expression ( "offset" Expression )?
//
// @param   limitExpression [REQUIRED, AQLExpression]
// @param   offsetExpression [OPTIONAL, AQLExpression]
function LimitClause(limitExpression, offsetExpression) {

    AQLClause.call(this);

    // limitExpression required
    this._properties["clause"] = "limit " + limitExpression.val();

    // Optional: Offset
    var offset = typeof offsetExpression ? offsetExpression : null;
    if (offset != null) {
        this._properties["clause"] += " offset " + offsetExpression.val();
    }

    return this;
}

LimitClause.prototype = Object.create(AQLClause.prototype);
LimitClause.prototype.constructor = LimitClause;

// OrderbyClause
//
// Grammar:
// OrderbyClause  ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
//
// @params AQLExpressions and asc/desc strings, in any quantity. At least one required.
function OrderbyClause() {

    AQLClause.call(this);

    // At least one argument expression is required, and first should be expression
    if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
        // TODO Not sure which error to throw for an empty OrderBy but this should fail.
        alert("Order By Error");
        this._properties["clause"] = null;
        return this;
    }

    var expc = 0;
    var expressions = [];

    while (expc < arguments.length) {

        var expression = "";

        if (arguments[expc] instanceof AExpression) {
            expression += arguments[expc].val();
        }

        var next = expc + 1;
        if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
            expc++;
            expression += " " + arguments[expc];
        }

        expressions.push(expression);

        expc++;
    }

    this._properties["clause"] = "order by " + expressions.join(", ");
    return this;
}

OrderbyClause.prototype = Object.create(AQLClause.prototype);
OrderbyClause.prototype.constructor = OrderbyClause;

// GroupClause
//
// Grammar:
// GroupClause    ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
function GroupClause() {
    AQLClause.call(this);

    if (arguments.length == 0) {
        // TODO Not sure which error to throw for an empty GroupBy but this should fail.
        alert("Group Error");
        this._properties["clause"] = null;
        return this;
    }

    var expc = 0;
    var expressions = [];
    var variableRefs = [];
    var isDecor = false;

    while (expc < arguments.length) {

        if (arguments[expc] instanceof AExpression) {

            isDecor = false;
            expressions.push(arguments[expc].val());

        } else if (typeof arguments[expc] == "string") {

            // Special keywords, decor & with
            if (arguments[expc] == "decor") {
                isDecor = true;
            } else if (arguments[expc] == "with") {
                isDecor = false;
                expc++;
                while (expc < arguments.length) {
                    variableRefs.push("$" + arguments[expc]);
                    expc++;
                }

            // Variables and variable refs
            } else {

                var nextc = expc + 1;
                var expression = "";

                if (isDecor) {
                    expression += "decor ";
                    isDecor = false;
                }

                expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
                expressions.push(expression);
                expc++;
            }
        }

        expc++;
    }

    this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
    return this;
}

GroupClause.prototype = Object.create(AQLClause.prototype);
GroupClause.prototype.constructor = GroupClause;

// BooleanExpression
//
// TODO
function BooleanExpression(expression) {
    this.value = expression;
    alert("Debugging Bool: " + arguments.length + " " + expression);
}

BooleanExpression.prototype.val = function() {
    return this.value;
}

// SetStatement
//
// Grammar
// "set" Identifier StringLiteral
function SetStatement (identifier, stringLiteral) {
    AExpression.call(this);

    var statement = "set " + identifier + ' "' + stringLiteral + '";';

    AExpression.prototype.set.call(this, statement);

    return this;
}

SetStatement.prototype = Object.create(AExpression.prototype);
SetStatement.prototype.constructor = SetStatement;

// Quantified Expression
//
// Grammar
// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
//
// @param String some/every
// @param [AExpression]
// @param [Aexpression] satisfiesExpression
function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
    AExpression.call(this);

    var expression = keyword + " ";
    var varsInExpressions = [];

    for (var varInExpression in expressions) {
        varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val());
    }
    expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();

    AExpression.prototype.set.call(this, expression);

    return this;
}

QuantifiedExpression.prototype = Object.create(AExpression.prototype);
QuantifiedExpression.prototype.constructor = QuantifiedExpression;

QuantifiedExpression.prototype.val = function() {
    var value = AExpression.prototype.val.call(this);
    return "(" + value + ")";
};

// Functions that can be used to call core expressions/clauses more cleanly
function AFLWOGR () {

}

function AClause () {

}

function ALetClause () {

}

function AWhereClause () {

}

function AOrderbyClause () {

}

function AGroupClause () {

}

function ALimitClause () {

}

function ADistinctClause () {

}

function AVariable () {

}
<|endoftext|>


<commit_before>/* GET 'homelist' page */
module.exports.homelist = function(req, res) {
    res.render('locations-list', {
        title: 'Loc8r - find a place to work with wifi',
        pageHeader: {
            title: 'Loc8r',
            strapline: 'Find places to work with wifi near you!'
        },
        locations: [{
            name: 'Starcups',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 3,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            distance: '100m'
        }, {
            name: 'Cafe Hero',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 4,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            distance: '200m'
        }, {
            name: 'Burger Queen',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 2,
            facilities: ['Food', 'Premium wifi'],
            distance: '250m'
        }],
		sidebar: 'Looking for coffee and a seat? Loc8r helps you find places to work when out and about. Perharps with coffe, cake or a pint? Let Loc8r help you find the place you\'re looking for.'
    });
};

/* GET 'Location info' page */
module.exports.locationInfo = function(req, res) {
    res.render('location-info', {
        title: 'Starcups',
        pageHeader: {
            title: 'Starcups'
        },
        sidebar: {
            context: 'is on Loc8r because it has accessible wifi and space to sit down with your laptop and get some work done.',
            callToAction: 'If you\'ve been and you like it - or if you don\'t - please leave a review to help other people just like you.'
        },
        location: {
            name: 'Starcups',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 3,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            coords: {
                lat: 51.455041,
                lng: -0.9690884
            },
            openingTimes: [{
                days: 'Monday - Friday',
                opening: '7:00am',
                closing: '7:00pm',
                closed: false
            }, {
                days: 'Saturday',
                opening: '8:00am',
                closing: '5:00pm',
                closed: false
            }, {
                days: 'Sunday',
                closed: true
            }],
            reviews: [{
                author: 'Simon Holmes',
                rating: 5,
                timestamp: '16 July 2013',
                reviewText: 'What a great place. I can\'t say enough good things about it.'
            }, {
                author: 'Charlie Chaplin',
                rating: 3,
                timestamp: '16 June 2013',
                reviewText: 'It was okay. Coffee wasn\'t great, but the wifi was fast.'
            }]
        }
    });
};/* GET 'home' page */
module.exports.homelist = function(req, res) {
    res.render('locations-list', {
        title: 'Loc8r - find a place to work with wifi',
        pageHeader: {
            title: 'Loc8r',
            strapline: 'Find places to work with wifi near you!'
        },
        sidebar: "Looking for wifi and a seat? Loc8r helps you find places to work when out and about. Perhaps with coffee, cake or a pint? Let Loc8r help you find the place you're looking for.",
        locations: [{
            name: 'Starcups',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 3,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            distance: '100m'
        }, {
            name: 'Cafe Hero',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 4,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            distance: '200m'
        }, {
            name: 'Burger Queen',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 2,
            facilities: ['Food', 'Premium wifi'],
            distance: '250m'
        }]
    });
};

/* GET 'Location info' page */
module.exports.locationInfo = function(req, res) {
    res.render('location-info', {
        title: 'Starcups',
        pageHeader: {
            title: 'Starcups'
        },
        sidebar: {
            context: 'is on Loc8r because it has accessible wifi and space to sit down with your laptop and get some work done.',
            callToAction: 'If you\'ve been and you like it - or if you don\'t - please leave a review to help other people just like you.'
        },
        location: {
            name: 'Starcups',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 3,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            coords: {
                lat: 51.455041,
                lng: -0.9690884
            },
            openingTimes: [{
                days: 'Monday - Friday',
                opening: '7:00am',
                closing: '7:00pm',
                closed: false
            }, {
                days: 'Saturday',
                opening: '8:00am',
                closing: '5:00pm',
                closed: false
            }, {
                days: 'Sunday',
                closed: true
            }],
            reviews: [{
                author: 'Simon Holmes',
                rating: 5,
                timestamp: '16 July 2013',
                reviewText: 'What a great place. I can\'t say enough good things about it.'
            }, {
                author: 'Charlie Chaplin',
                rating: 3,
                timestamp: '16 June 2013',
                reviewText: 'It was okay. Coffee wasn\'t great, but the wifi was fast.'
            }]
        }
    });
};

/* GET 'Add review' page */
module.exports.addReview = function(req, res) {
    res.render('location-review-form', {
        title: 'Review Starcups on Loc8r',
        pageHeader: {
            title: 'Review Starcups'
        }
    });
};
<commit_msg>Update locations.js<commit_after>/* GET 'home' page */
module.exports.homelist = function(req, res) {
    res.render('locations-list', {
        title: 'Loc8r - find a place to work with wifi',
        pageHeader: {
            title: 'Loc8r',
            strapline: 'Find places to work with wifi near you!'
        },
        sidebar: "Looking for wifi and a seat? Loc8r helps you find places to work when out and about. Perhaps with coffee, cake or a pint? Let Loc8r help you find the place you're looking for.",
        locations: [{
            name: 'Starcups',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 3,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            distance: '100m'
        }, {
            name: 'Cafe Hero',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 4,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            distance: '200m'
        }, {
            name: 'Burger Queen',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 2,
            facilities: ['Food', 'Premium wifi'],
            distance: '250m'
        }]
    });
};

/* GET 'Location info' page */
module.exports.locationInfo = function(req, res) {
    res.render('location-info', {
        title: 'Starcups',
        pageHeader: {
            title: 'Starcups'
        },
        sidebar: {
            context: 'is on Loc8r because it has accessible wifi and space to sit down with your laptop and get some work done.',
            callToAction: 'If you\'ve been and you like it - or if you don\'t - please leave a review to help other people just like you.'
        },
        location: {
            name: 'Starcups',
            address: '125 High Street, Reading, RG6 1PS',
            rating: 3,
            facilities: ['Hot drinks', 'Food', 'Premium wifi'],
            coords: {
                lat: 51.455041,
                lng: -0.9690884
            },
            openingTimes: [{
                days: 'Monday - Friday',
                opening: '7:00am',
                closing: '7:00pm',
                closed: false
            }, {
                days: 'Saturday',
                opening: '8:00am',
                closing: '5:00pm',
                closed: false
            }, {
                days: 'Sunday',
                closed: true
            }],
            reviews: [{
                author: 'Simon Holmes',
                rating: 5,
                timestamp: '16 July 2013',
                reviewText: 'What a great place. I can\'t say enough good things about it.'
            }, {
                author: 'Charlie Chaplin',
                rating: 3,
                timestamp: '16 June 2013',
                reviewText: 'It was okay. Coffee wasn\'t great, but the wifi was fast.'
            }]
        }
    });
};

/* GET 'Add review' page */
module.exports.addReview = function(req, res) {
    res.render('location-review-form', {
        title: 'Review Starcups on Loc8r',
        pageHeader: {
            title: 'Review Starcups'
        }
    });
};
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular
        .module('app')
        .controller('HomeController', HomeController);

    HomeController.$inject = ['UserService', '$rootScope'];
    function HomeController(UserService, $rootScope) {
        var vm = this;

        vm.user = null;

        vm.allUsers = [];
        vm.deleteUser = deleteUser;

        initController();

        function initController() {
            loadCurrentUser();
           loadAllUsers();
        }

        function loadCurrentUser() {
            UserService.GetByUsername($rootScope.globals.currentUser.username)
                .then(function (user) {
                    vm.user = user;
                });
        }

   function loadAllUsers() {
            UserService.GetAll()
                .then(function (users) {
                    vm.allUsers = users;
                });
        }

       /* function deleteUser(id) {
            UserService.Delete(id)
            .then(function () {
                loadAllUsers();
            });
        }*/

        function deleteUser(id) {
            UserService.Delete(id)
            .then(function () {
                loadCurrentUser();
            });
        }
    }

})();
<commit_msg>Create home.controller.js<commit_after>(function () {
    'use strict';

    angular
        .module('app')
        .controller('HomeController', HomeController);

    HomeController.$inject = ['UserService', '$rootScope'];
    function HomeController(UserService, $rootScope) {
        var vm = this;

        vm.user = null;

        vm.allUsers = [];
        vm.deleteUser = deleteUser;

        initController();

        function initController() {
            loadCurrentUser();
           loadAllUsers();
        }

        function loadCurrentUser() {
            UserService.GetByUsername($rootScope.globals.currentUser.username)
                .then(function (user) {
                    vm.user = user;
                });
        }

   function loadAllUsers() {
            UserService.GetAll()
                .then(function (users) {
                    vm.allUsers = users;
                });
        }

     function deleteUser(id) {
            UserService.Delete(id)
            .then(function () {
                loadAllUsers();
            });
        }

       /* function deleteUser(id) {
            UserService.Delete(id)
            .then(function () {
                loadCurrentUser();
            });
        }*/
    }

})();
<|endoftext|>


<commit_before>
var fs = require("fs");
var path = require("path");
var utilities = require("./utilities");

/**
 * This is used as the display text for the build phase block in XCode as well as the
 * inline comments inside of the .pbxproj file for the build script phase block.
 */
var comment = "\"Fabric.io: Crashlytics\"";

module.exports = {

    /**
     * This helper is used to add a build phase to the XCode project which runs a shell
     * script during the build process. The script executes Crashlytics run command line
     * tool with the API and Secret keys. This tool is used to upload the debug symbols
     * (dSYMs) so that Crashlytics can display stack trace information in it's web console.
     */
    addShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var pluginConfig = utilities.getPluginConfig("ios");
        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        // Build the body of the script to be executed during the build phase.
        // ../../plugins/plugin-id/lib/ios/Crashlytics.framework/run API_KEY SECRET_KEY
//         var script = [
//             "\"",
//             "\\\"",
//             utilities.getAppName(context),
//             "/Plugins/",
//             utilities.getPluginId(),
//             "/./Fabric.framework/run",
//             "\\\"",
//             " ",
//             pluginConfig.apiKey,
//             " ",
//             pluginConfig.apiSecret,
//             "\""
//         ].join("");
//         // "${PODS_ROOT}"
//         var script = '"' + "./Fabric.framework/run " + pluginConfig.apiKey + " " + pluginConfig.apiSecret + '"';
//         var script = '"' + "./Fabric.framework/run " + pluginConfig.apiKey + " " + pluginConfig.apiSecret + '"';
        var script ='"' + ' "${SRCROOT}"/ ' + utilities.getAppName(context) + "/Plugins/cordova-fabric-plugin/Fabric.framework/run" +  pluginConfig.apiKey + " " + pluginConfig.apiSecret + '"';

        // Generate a unique ID for our new build phase.
        var id = xcodeProject.generateUuid();
        // Create the build phase.
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id] = {
            isa: "PBXShellScriptBuildPhase",
            buildActionMask: 2147483647,
            files: [],
            inputPaths: [],
            name: comment,
            outputPaths: [],
            runOnlyForDeploymentPostprocessing: 0,
            shellPath: "/bin/sh",
            shellScript: script,
            showEnvVarsInLog: 0
        };

        // Add a comment to the block (viewable in the source of the pbxproj file).
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id + "_comment"] = comment;

        // Add this new shell script build phase block to the targets.
        for (var nativeTargetId in xcodeProject.hash.project.objects.PBXNativeTarget) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = xcodeProject.hash.project.objects.PBXNativeTarget[nativeTargetId];

            nativeTarget.buildPhases.push({
                value: id,
                comment: comment
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    },

    /**
     * This helper is used to remove the build phase from the XCode project that was added
     * by the addShellScriptBuildPhase() helper method.
     */
    removeShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        // First, we want to delete the build phase block itself.

        var buildPhases = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase;

        for (var buildPhaseId in buildPhases) {

            var buildPhase = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[buildPhaseId];
            var shouldDelete = false;

            if (buildPhaseId.indexOf("_comment") === -1) {
                // Dealing with a build phase block.

                // If the name of this block matches ours, then we want to delete it.
                shouldDelete = buildPhase.name && buildPhase.name.indexOf(comment) !== -1;
            }
            else {
                // Dealing with a comment block.

                // If this is a comment block that matches ours, then we want to delete it.
                shouldDelete = buildPhaseId === comment;
            }

            if (shouldDelete) {
                delete buildPhases[buildPhaseId];
            }
        }

        // Second, we want to delete the native target reference to the block.

        var nativeTargets = xcodeProject.hash.project.objects.PBXNativeTarget;

        for (var nativeTargetId in nativeTargets) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = nativeTargets[nativeTargetId];

            // We remove the reference to the block by filtering out the the ones that match.
            nativeTarget.buildPhases = nativeTarget.buildPhases.filter(function (buildPhase) {
                return buildPhase.comment !== comment;
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    }
};
<commit_msg>Update ios-helper.js<commit_after>
var fs = require("fs");
var path = require("path");
var utilities = require("./utilities");

/**
 * This is used as the display text for the build phase block in XCode as well as the
 * inline comments inside of the .pbxproj file for the build script phase block.
 */
var comment = "\"Fabric.io: Crashlytics\"";

module.exports = {

    /**
     * This helper is used to add a build phase to the XCode project which runs a shell
     * script during the build process. The script executes Crashlytics run command line
     * tool with the API and Secret keys. This tool is used to upload the debug symbols
     * (dSYMs) so that Crashlytics can display stack trace information in it's web console.
     */
    addShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var pluginConfig = utilities.getPluginConfig("ios");
        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        // Build the body of the script to be executed during the build phase.
        // ../../plugins/plugin-id/lib/ios/Crashlytics.framework/run API_KEY SECRET_KEY
//         var script = [
//             "\"",
//             "\\\"",
//             utilities.getAppName(context),
//             "/Plugins/",
//             utilities.getPluginId(),
//             "/./Fabric.framework/run",
//             "\\\"",
//             " ",
//             pluginConfig.apiKey,
//             " ",
//             pluginConfig.apiSecret,
//             "\""
//         ].join("");
//         // "${PODS_ROOT}"
//         var script = '"' + "./Fabric.framework/run " + pluginConfig.apiKey + " " + pluginConfig.apiSecret + '"';
//         var script = '"' + "./Fabric.framework/run " + pluginConfig.apiKey + " " + pluginConfig.apiSecret + '"';
        var script ='"' + '${SRCROOT}' + utilities.getAppName(context) + "/Plugins/cordova-fabric-plugin/Fabric.framework/run" +  pluginConfig.apiKey + " " + pluginConfig.apiSecret + '"';

        // Generate a unique ID for our new build phase.
        var id = xcodeProject.generateUuid();
        // Create the build phase.
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id] = {
            isa: "PBXShellScriptBuildPhase",
            buildActionMask: 2147483647,
            files: [],
            inputPaths: [],
            name: comment,
            outputPaths: [],
            runOnlyForDeploymentPostprocessing: 0,
            shellPath: "/bin/sh",
            shellScript: script,
            showEnvVarsInLog: 0
        };

        // Add a comment to the block (viewable in the source of the pbxproj file).
        xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[id + "_comment"] = comment;

        // Add this new shell script build phase block to the targets.
        for (var nativeTargetId in xcodeProject.hash.project.objects.PBXNativeTarget) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = xcodeProject.hash.project.objects.PBXNativeTarget[nativeTargetId];

            nativeTarget.buildPhases.push({
                value: id,
                comment: comment
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    },

    /**
     * This helper is used to remove the build phase from the XCode project that was added
     * by the addShellScriptBuildPhase() helper method.
     */
    removeShellScriptBuildPhase: function(context, xcodeProjectPath) {

        var xcode = context.requireCordovaModule("xcode");

        // Read and parse the XCode project (.pxbproj) from disk.
        // File format information: http://www.monobjc.net/xcode-project-file-format.html
        var xcodeProject = xcode.project(xcodeProjectPath);
        xcodeProject.parseSync();

        // First, we want to delete the build phase block itself.

        var buildPhases = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase;

        for (var buildPhaseId in buildPhases) {

            var buildPhase = xcodeProject.hash.project.objects.PBXShellScriptBuildPhase[buildPhaseId];
            var shouldDelete = false;

            if (buildPhaseId.indexOf("_comment") === -1) {
                // Dealing with a build phase block.

                // If the name of this block matches ours, then we want to delete it.
                shouldDelete = buildPhase.name && buildPhase.name.indexOf(comment) !== -1;
            }
            else {
                // Dealing with a comment block.

                // If this is a comment block that matches ours, then we want to delete it.
                shouldDelete = buildPhaseId === comment;
            }

            if (shouldDelete) {
                delete buildPhases[buildPhaseId];
            }
        }

        // Second, we want to delete the native target reference to the block.

        var nativeTargets = xcodeProject.hash.project.objects.PBXNativeTarget;

        for (var nativeTargetId in nativeTargets) {

            // Skip over the comment blocks.
            if (nativeTargetId.indexOf("_comment") !== -1) {
                continue;
            }

            var nativeTarget = nativeTargets[nativeTargetId];

            // We remove the reference to the block by filtering out the the ones that match.
            nativeTarget.buildPhases = nativeTarget.buildPhases.filter(function (buildPhase) {
                return buildPhase.comment !== comment;
            });
        }

        // Finally, write the .pbxproj back out to disk.
        fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
    }
};
<|endoftext|>


<commit_before>/*
    here's function lifecycle
    [displaying div table]
     \ 1. extractFromDisplay
     \ 2. renderEditModal
    [edit/add modal]
     | 3. extractFromModal  4. extractToBackend
    [executeUpdateWithUI] ----------------------[backend]
     | 4. convertToInternals
    [genBodyRows]
*/
var CrudManager = Class.extend({
    panel: null,
    panelBody: null,
    addModal: null,
    editModal: null,
    editingCallback: function () {},
    template_id: '',
    getNextRowId: function () {
        return this.panelBody.find('.crud-row').length - 1;
    },

    init: function (config) {
        this.panel = $(config.containerSelector).addClass('crud-table');
        this.panel.css('position', 'relative'); // avoid leak of absolute children
        this.editingCallback = config.editingCallback || this.editingCallback;
        this.template_id = config.template_id || '';
    },
    render: function () {
        this.panel.append(this.genHead());
        this.panel.append(this.genBody());
    },
    renderAddModal: function (containerSelector) {
        this.addModal = $(containerSelector);
        this.addModal.html('').append(this.genAdd());
    },
    renderEditModal: function (containerSelector, $row) {
        this.editModal = $(containerSelector);
        var data = this.convertToInternal(this.extractFromDisplay($row));
        this.editModal.html('').append(this.genEdit(data));
    },
    executeAddWithUI: function (dpd) {
        var self = this;
        var dict = this.extractFromModal(this.addModal, 'add');
        var params = this.extractToBackend(dict);
        dpd.post(params, function (r) {
            self.editingCallback();

            try {
                r = eval('(' + r +')');
            } catch (e) {
                de.assert(false, "dpd post failed. ", r);
                // TODO show err msg
                return;
            }
            dict = $.extend(dict, {id: r['$id']}); // this is a trick for make guarantee the order of key
            var idx = self.panelBody.find('.crud-row').length - 1;
            var data = self.convertToInternal(dict);
            ////de.log(data, 'genBodyRow');
            self.panelBody.append(self.genBodyRow(self, idx, data));
        });
    },
    executeUpdateWithUI: function (dpd, $row) {
        var self = this;
        var dict = this.extractFromModal(this.editModal, 'edit');
        var params = this.extractToBackend(dict);
        dpd.put(dict['id'], params, function (r) {
            self.editingCallback();

            try {
                r = eval('(' + r +')');
            } catch (e) {
                de.assert(false, "dpd post failed. ", r);
                // TODO show err msg
                return;
            }

            var data = self.convertToInternal(dict);
            var $updatedRow = self.genBodyRow(self, parseInt($row.attr('data-id')), data);
            replaceDom($updatedRow, $row);
        });
    },
    executeRemoveWithUI: function (dpd, $row) {
        var self = this;
        var id = $row.find('.id').text().trim();
        dpd.del(id, function (r) {
            self.editingCallback();

            $row.remove();
        });
    },
    // -------------------------------------------------------------------------
    genDefaultRow: function () {
        return $('
');
    },
    genDefaultColumn: function (info) {
        return $('
').attr('name', info.k).addClass(info.k).text(info.v);
    },
    genDefaultColumns: function (data) {
        var self = this;
        return data.map(function (info) {
            return self.genDefaultColumn(info);
        });
    },
    genDefaultInputColumns: function (data) {
        return data.map(function (info) {
            var $label = $('').addClass('k').text(info.kDisp);
            var $input = $('<input>').addClass('v').attr('name', info.k);
            var $wrap = $('
').addClass(info.k);
            if (info.v) {
                $input.val(info.v);
            }
            return $wrap.append($label).append($input);
        });
    },
    genGivenColumn: function ($templ, info) {
        var $more_fine_templ = (this.template_id !== '') ? $templ.filter('.' + info.k+'.'+this.template_id) : [];
        var $fine_templ = $templ.filter('.' + info.k);
        if ($more_fine_templ.length > 0) {
            return $more_fine_templ.tmpl(info);
        } else if ($fine_templ.length > 0) {
            try {
                return $fine_templ.tmpl(info);
            } catch (e) {
                console.error('can not render template with given data. please check whether there is an exception happened in js templateHelper.', $fine_templ.get(0), info);
            }
        } else {
            return $templ.tmpl(info);
        }
    },
    genGivenColumns: function (selector, data) {
        var self = this;
        var $templ = $(selector);
        if ($templ.length === 0) {
            return false;
        }
        return data.map(function (info) {
            return self.genGivenColumn($templ, info);
        });
    },
    // -------------------------------------------------------------------------
    getHeads: function () {
        // data loader for head
        return [{k: 'title', kDisp: '標題'},
            {k: 'content',  kDisp:'內容'},
            {k: 'comment',  kDisp:'註解'}
        ];
    },
    getBodies: function () {
        // data loader for body
        return [
            [
                {k: 'title', v: 'title 1'},
                {k: 'content',  v:'content 1'},
                {k: 'comment',  v:'comment 1'}
            ],
            [
                {k: 'title', v: 'title 2'},
                {k: 'content',  v:'content 2'},
                {k: 'comment',  v:''}
            ]
        ]
    },
    getHeadKeys: function () {
        var headKeys = [];
        $.each(this.getHeads(), function(idx, head) {
            headKeys.push(head['k']);
        });
        return headKeys;
    },
    // -------------------------------------------------------------------------
    genHead: function () {
        var tmplHead = $('.crud_head_row'); // user-defined
        var $head = (tmplHead.length === 0)
            ? this.genDefaultRow() // default
            : tmplHead.tmpl({});
        $head.addClass('crud-head');

        var data = this.getHeads(); // [{k:, kDisp:}, {}, ...]
        var $columns = this.genGivenColumns('.crud_head_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-column');
        });

        $head.append($columns);
        return $head;
    },
    genBodyRow:function (self, idx, data) {
        var tmplRow = $('.crud_body_row'); // user-defined
        if (tmplRow.length > 1) { // always get latter one for overriding
            tmplRow = $(tmplRow.get(tmplRow.length - 1));
        }
        var $row = (tmplRow.length === 0)
            ? self.genDefaultRow() // default
            : tmplRow.tmpl({});
        $row.addClass('crud-row').attr('data-id', idx);

        var $columns = this.genGivenColumns('.crud_body_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-column');
        });

        var $mostInner = $row.find(' *:not(:has("*"))'); // http://stackoverflow.com/questions/4250893/find-the-inner-most-text-with-javascript-jquery-regardless-of-number-of-nested
        if ($mostInner.length !== 0) {
            // multiple wrapper
            if ($row.find('.crud_body_column_placeholder')) {
                $row.find('.crud_body_column_placeholder').append($columns);
            } else {
                $($mostInner.get(0)).append($columns);
            }
        } else {
            // single wrapper
            $row.append($columns);
        }

        var $control = $('#crud_control').tmpl({});
        $row.append($control);

        return $row;
    },
    genBody: function () {
        var self = this; // make this accessible in closure
        var tmplBody = $('.crud_body'); // user-defined
        var $body = (tmplBody.length === 0)
            ? this.genDefaultRow() // default
            : tmplBody.tmpl({});
        $body.addClass('crud-body');

        var dataSets = this.getBodies();
        $.each(dataSets, function (idx, data) {
            $body.append(self.genBodyRow(self, idx, data));
        });

        this.panelBody = $body;
        return $body;
    },
    // -------------------------------------------------------------------------
    genAdd: function () {
        // generate input list for adding
        var tmplAdd = $('.crud_add'); // user-defined
        var $add = (tmplAdd.length === 0)
            ? this.genDefaultRow() // default
            : tmplAdd.tmpl({});
        $add.addClass('crud-add table');

        var data = this.getHeads(); // [{k:, kDisp:}, {}, ...]

        var $columns = this.genGivenColumns('.crud_add_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultInputColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-modal-column pair');
        });

        $add.append($columns);
        return $add;
    },
    // -------------------------------------------------------------------------
    genEdit: function (data) {
        // generate input list for editing
        var tmplEdit = $('.crud_edit'); // user-defined
        var $edit = (tmplEdit.length === 0)
            ? this.genDefaultRow() // default
            : tmplEdit.tmpl({});
        $edit.addClass('crud-edit table');

        var heads = this.getHeads(); // [{k:, kDisp:}, {}, ...]
        $.each(data, function (i, row) {
            row = $.extend(row, heads[i]);
        });

        var $columns = this.genGivenColumns('.crud_edit_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultInputColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-modal-column pair');
        });

        $edit.append($columns);
        return $edit;
    },
    // -------------------------------------------------------------------------
    getDisplayColumnByName: function ($row, name) {
        var $field = $row.find('.crud-column[name="'+name+'"]');
        if ($field.length === 0) {
            console.error('can not get column, '+name+', from $row', $row);
            return false;
        }
        return $field;
    },
    getModalColumnByClass: function ($row, clazz) {
        var $field = $row.find('.crud-modal-column.'+clazz+'');
        if ($field.length === 0) {
            console.error('can not get column, '+clazz+', from $row', $row);
            return false;
        }
        return $field;
    },
    extractFromDisplay: function ($row) {
        /*
a

            -> {content: "a", ...}
         */
        var dict = {};
        $row.find('.crud-column').each(function (idx, column) {
            var $column = $(column);
            var k = $column.attr('name');
            de.assert(k, 'can not extract name attribute from  ... must set it while creating', column);
            dict[k] = $column.text(); // do i need to trim this?
        });
        return dict;
    },
    extractFromModal: function (modal, source) {
        var data = {};
        if (!modal) {
            console.warn('undefined modal object found while extractFromModal');
            return data;
        }

        modal.find('.crud-modal-column').each(function (idx, column) {
            var $column = $(column);
            var $input = $column.find('input');
            if ($input.length === 0) {
                $input = $column.find('textarea');
            }
            de.assert($input.length !== 0, 'can not find input/textarea from column ... must set it while editing', column);
            var k = $input.attr('name');
            de.assert(k, 'input/textarea must be bound with name attribute', $input);
            data[k] = $input.val(); // do i need to trim this?
        });
        return data;
    },
    extractToBackend: function (dict) {
        var params =  $.extend({}, dict);
        delete params['id'];
        return params;
    },
    convertToInternal: function (dict) {
        /* {x:1,y:1}
         -> [{k:x,v:1}, {k:y,v:1}]
            NOTE that 1) keys does not existed in HEAD will be ignored!
                      2) missing value of existing key will be set as default
         */
        var info = [], head = this.getHeadKeys(), self = this;
        $.each(head, function (idx, field) {
            if (field in dict) {
                info.push({k: field, v: dict[field]});
            } else {
                info.push({k: field, v: ''});
            }
        });
        return info;
    },
    convertToInternals: function (dicts) {
        /* [{x:1,y:1}]
            -> [{k:x,v:1}, {k:y,v:1}]
         */
        var data = [];
        $.each(dicts, function (idx, dict) {
            $.each(dict, function (k, v) {
                data.push({k: k, v: v});
            });
        });
        return data;
    }
 });
<commit_msg>add callback to modal rendering method<commit_after>/*
    here's function lifecycle
    [displaying div table]
     \ 1. extractFromDisplay
     \ 2. renderEditModal
    [edit/add modal]
     | 3. extractFromModal  4. extractToBackend
    [executeUpdateWithUI] ----------------------[backend]
     | 4. convertToInternals
    [genBodyRows]
*/
var CrudManager = Class.extend({
    panel: null,
    panelBody: null,
    addModal: null,
    editModal: null,
    editingCallback: function () {},
    template_id: '',
    getNextRowId: function () {
        return this.panelBody.find('.crud-row').length - 1;
    },

    init: function (config) {
        this.panel = $(config.containerSelector).addClass('crud-table');
        this.panel.css('position', 'relative'); // avoid leak of absolute children
        this.editingCallback = config.editingCallback || this.editingCallback;
        this.template_id = config.template_id || '';
    },
    render: function () {
        this.panel.append(this.genHead());
        this.panel.append(this.genBody());
    },
    renderAddModal: function (containerSelector, callback) {
        this.addModal = $(containerSelector);
        this.addModal.html('').append(this.genAdd());
        if (callback) {
            callback();
        }
    },
    renderEditModal: function (containerSelector, $row, callback) {
        this.editModal = $(containerSelector);
        var data = this.convertToInternal(this.extractFromDisplay($row));
        this.editModal.html('').append(this.genEdit(data));
        if (callback) {
            callback();
        }
    },
    executeAddWithUI: function (dpd) {
        var self = this;
        var dict = this.extractFromModal(this.addModal, 'add');
        var params = this.extractToBackend(dict);
        dpd.post(params, function (r) {
            self.editingCallback();

            try {
                r = eval('(' + r +')');
            } catch (e) {
                de.assert(false, "dpd post failed. ", r);
                // TODO show err msg
                return;
            }
            dict = $.extend(dict, {id: r['$id']}); // this is a trick for make guarantee the order of key
            var idx = self.panelBody.find('.crud-row').length - 1;
            var data = self.convertToInternal(dict);
            ////de.log(data, 'genBodyRow');
            self.panelBody.append(self.genBodyRow(self, idx, data));
        });
    },
    executeUpdateWithUI: function (dpd, $row) {
        var self = this;
        var dict = this.extractFromModal(this.editModal, 'edit');
        var params = this.extractToBackend(dict);
        dpd.put(dict['id'], params, function (r) {
            self.editingCallback();

            try {
                r = eval('(' + r +')');
            } catch (e) {
                de.assert(false, "dpd post failed. ", r);
                // TODO show err msg
                return;
            }

            var data = self.convertToInternal(dict);
            var $updatedRow = self.genBodyRow(self, parseInt($row.attr('data-id')), data);
            replaceDom($updatedRow, $row);
        });
    },
    executeRemoveWithUI: function (dpd, $row) {
        var self = this;
        var id = $row.find('.id').text().trim();
        dpd.del(id, function (r) {
            self.editingCallback();

            $row.remove();
        });
    },
    // -------------------------------------------------------------------------
    genDefaultRow: function () {
        return $('
');
    },
    genDefaultColumn: function (info) {
        return $('
').attr('name', info.k).addClass(info.k).text(info.v);
    },
    genDefaultColumns: function (data) {
        var self = this;
        return data.map(function (info) {
            return self.genDefaultColumn(info);
        });
    },
    genDefaultInputColumns: function (data) {
        return data.map(function (info) {
            var $label = $('').addClass('k').text(info.kDisp);
            var $input = $('<input>').addClass('v').attr('name', info.k);
            var $wrap = $('
').addClass(info.k);
            if (info.v) {
                $input.val(info.v);
            }
            return $wrap.append($label).append($input);
        });
    },
    genGivenColumn: function ($templ, info) {
        var $more_fine_templ = (this.template_id !== '') ? $templ.filter('.' + info.k+'.'+this.template_id) : [];
        var $fine_templ = $templ.filter('.' + info.k);
        if ($more_fine_templ.length > 0) {
            return $more_fine_templ.tmpl(info);
        } else if ($fine_templ.length > 0) {
            try {
                return $fine_templ.tmpl(info);
            } catch (e) {
                console.error('can not render template with given data. please check whether there is an exception happened in js templateHelper.', $fine_templ.get(0), info);
            }
        } else {
            return $templ.tmpl(info);
        }
    },
    genGivenColumns: function (selector, data) {
        var self = this;
        var $templ = $(selector);
        if ($templ.length === 0) {
            return false;
        }
        return data.map(function (info) {
            return self.genGivenColumn($templ, info);
        });
    },
    // -------------------------------------------------------------------------
    getHeads: function () {
        // data loader for head
        return [{k: 'title', kDisp: '標題'},
            {k: 'content',  kDisp:'內容'},
            {k: 'comment',  kDisp:'註解'}
        ];
    },
    getBodies: function () {
        // data loader for body
        return [
            [
                {k: 'title', v: 'title 1'},
                {k: 'content',  v:'content 1'},
                {k: 'comment',  v:'comment 1'}
            ],
            [
                {k: 'title', v: 'title 2'},
                {k: 'content',  v:'content 2'},
                {k: 'comment',  v:''}
            ]
        ]
    },
    getHeadKeys: function () {
        var headKeys = [];
        $.each(this.getHeads(), function(idx, head) {
            headKeys.push(head['k']);
        });
        return headKeys;
    },
    // -------------------------------------------------------------------------
    genHead: function () {
        var tmplHead = $('.crud_head_row'); // user-defined
        var $head = (tmplHead.length === 0)
            ? this.genDefaultRow() // default
            : tmplHead.tmpl({});
        $head.addClass('crud-head');

        var data = this.getHeads(); // [{k:, kDisp:}, {}, ...]
        var $columns = this.genGivenColumns('.crud_head_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-column');
        });

        $head.append($columns);
        return $head;
    },
    genBodyRow:function (self, idx, data) {
        var tmplRow = $('.crud_body_row'); // user-defined
        if (tmplRow.length > 1) { // always get latter one for overriding
            tmplRow = $(tmplRow.get(tmplRow.length - 1));
        }
        var $row = (tmplRow.length === 0)
            ? self.genDefaultRow() // default
            : tmplRow.tmpl({});
        $row.addClass('crud-row').attr('data-id', idx);

        var $columns = this.genGivenColumns('.crud_body_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-column');
        });

        var $mostInner = $row.find(' *:not(:has("*"))'); // http://stackoverflow.com/questions/4250893/find-the-inner-most-text-with-javascript-jquery-regardless-of-number-of-nested
        if ($mostInner.length !== 0) {
            // multiple wrapper
            if ($row.find('.crud_body_column_placeholder')) {
                $row.find('.crud_body_column_placeholder').append($columns);
            } else {
                $($mostInner.get(0)).append($columns);
            }
        } else {
            // single wrapper
            $row.append($columns);
        }

        var $tmplControl = $('.crud_control');
        if ($tmplControl.length > 1) { // always get latter one for overriding
            $tmplControl = $($tmplControl.get($tmplControl.length - 1));
        }
        var $control = $tmplControl.tmpl({});
        $row.append($control);

        return $row;
    },
    genBody: function () {
        var self = this; // make this accessible in closure
        var tmplBody = $('.crud_body'); // user-defined
        var $body = (tmplBody.length === 0)
            ? this.genDefaultRow() // default
            : tmplBody.tmpl({});
        $body.addClass('crud-body');

        var dataSets = this.getBodies();
        $.each(dataSets, function (idx, data) {
            $body.append(self.genBodyRow(self, idx, data));
        });

        this.panelBody = $body;
        return $body;
    },
    // -------------------------------------------------------------------------
    genAdd: function () {
        // generate input list for adding
        var tmplAdd = $('.crud_add'); // user-defined
        var $add = (tmplAdd.length === 0)
            ? this.genDefaultRow() // default
            : tmplAdd.tmpl({});
        $add.addClass('crud-add table');

        var data = this.getHeads(); // [{k:, kDisp:}, {}, ...]

        var $columns = this.genGivenColumns('.crud_add_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultInputColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-modal-column pair');
        });

        $add.append($columns);
        return $add;
    },
    // -------------------------------------------------------------------------
    genEdit: function (data) {
        // generate input list for editing
        var tmplEdit = $('.crud_edit'); // user-defined
        var $edit = (tmplEdit.length === 0)
            ? this.genDefaultRow() // default
            : tmplEdit.tmpl({});
        $edit.addClass('crud-edit table');

        var heads = this.getHeads(); // [{k:, kDisp:}, {}, ...]
        $.each(data, function (i, row) {
            row = $.extend(row, heads[i]);
        });

        var $columns = this.genGivenColumns('.crud_edit_column', data); // user-defined
        $columns = ($columns === false) ? this.genDefaultInputColumns(data) : $columns; // default
        // template-generated result does not have addClass method
        $.each($columns, function (idx, column) {
            $(column).addClass('crud-modal-column pair');
        });

        $edit.append($columns);
        return $edit;
    },
    // -------------------------------------------------------------------------
    getDisplayColumnByName: function ($row, name) {
        var $field = $row.find('.crud-column[name="'+name+'"]');
        if ($field.length === 0) {
            console.error('can not get column, '+name+', from $row', $row);
            return false;
        }
        return $field;
    },
    getModalColumnByClass: function ($row, clazz) {
        var $field = $row.find('.crud-modal-column.'+clazz+'');
        if ($field.length === 0) {
            console.error('can not get column, '+clazz+', from $row', $row);
            return false;
        }
        return $field;
    },
    extractFromDisplay: function ($row) {
        /*
a

            -> {content: "a", ...}
         */
        var dict = {};
        $row.find('.crud-column').each(function (idx, column) {
            var $column = $(column);
            var k = $column.attr('name');
            de.assert(k, 'can not extract name attribute from  ... must set it while creating', column);
            dict[k] = $column.text(); // do i need to trim this?
        });
        return dict;
    },
    extractFromModal: function (modal, source) {
        var data = {};
        if (!modal) {
            console.warn('undefined modal object found while extractFromModal');
            return data;
        }

        modal.find('.crud-modal-column').each(function (idx, column) {
            var $column = $(column);
            var $input = $column.find('input');
            if ($input.length === 0) {
                $input = $column.find('textarea');
            }
            de.assert($input.length !== 0, 'can not find input/textarea from column ... must set it while editing', column);
            var k = $input.attr('name');
            de.assert(k, 'input/textarea must be bound with name attribute', $input);
            data[k] = $input.val(); // do i need to trim this?
        });
        return data;
    },
    extractToBackend: function (dict) {
        var params =  $.extend({}, dict);
        delete params['id'];
        return params;
    },
    convertToInternal: function (dict) {
        /* {x:1,y:1}
         -> [{k:x,v:1}, {k:y,v:1}]
            NOTE that 1) keys does not existed in HEAD will be ignored!
                      2) missing value of existing key will be set as default
         */
        var info = [], head = this.getHeadKeys(), self = this;
        $.each(head, function (idx, field) {
            if (field in dict) {
                info.push({k: field, v: dict[field]});
            } else {
                info.push({k: field, v: ''});
            }
        });
        return info;
    },
    convertToInternals: function (dicts) {
        /* [{x:1,y:1}]
            -> [{k:x,v:1}, {k:y,v:1}]
         */
        var data = [];
        $.each(dicts, function (idx, dict) {
            $.each(dict, function (k, v) {
                data.push({k: k, v: v});
            });
        });
        return data;
    }
 });
<|endoftext|>


<commit_before>$(function () {
	$('a[data-type=comments]').click(function(){
		$('#tab-reviews').css({position:'static', visibility:'visible'});
	});

    if (isSocial) {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = 'https://localhost:9443/social/export-js/social.js';
        document.body.appendChild(script);
    } else {
        var comments = {
                interval: 5 * 1000,
                commentsUrl: caramel.context + '/apis/comments?asset=' + $('#assetp-tabs').data('aid') + '&page=',
                pagingUrl: '/apis/comments/paging?page=',
                partial: '/themes/store/partials/comments.hbs'
            },
            paging = {
                current: 1,
                partial: '/themes/store/partials/pagination.hbs'
            };

        $('#tab-reviews').on('click', '.pagination a', function (e) {
            e.preventDefault();
            var page,
                thiz = $(this),
                str = thiz.text(),
                url = thiz.attr('href');
            if (url === '#') {
                return;
            }
            if (str.indexOf('Next') !== -1) {
                page = paging.current + 1;
            } else if (str.indexOf('Prev') !== -1) {
                page = paging.current - 1
            } else {
                page = parseInt(str, 10);
            }
            loadReviews(url, page);
        });

        var loadReviews = function (url, page) {
            var iframe, iframeHeight,
                el = $('#tab-reviews').find('.content');
            comments.updated = new Date().getTime();
            async.parallel({
                comments: function (callback) {
                    $.get(url, function (data) {
                        callback(null, data);
                    }, 'json');
                },
                paging: function (callback) {
                    caramel.post(comments.pagingUrl + page, {
                        asset: $('#assetp-tabs').data('aid')
                    }, function (data) {
                        paging.current = data.current;
                        callback(null, data);
                    }, 'json');
                }
            }, function (error, result) {
                if (error) {
                    theme.loaded(el, '
Error while retrieving data.
')
                } else {
                    async.parallel({
                        comments: function (callback) {
                            var i, comment,
                                comments = result.comments,
                                length = comments.length;
                            for (i = 0; i < length; i++) {
                                comment = comments[i];
                                comment.created.time = moment(comment.created.time).format('LL');
                            }
                            caramel.render('comments', {
                                user: store.user,
                                comments: comments
                            }, callback);
                        },
                        paging: function (callback) {
                            caramel.render('pagination', result.paging, callback);
                        }
                    }, function (err, result) {
                        theme.loaded(el, result.comments);
                        el.append(result.paging);

                        iframe = $('#tab-reviews').find('iframe');
                        iframeHeight = iframe.contents().height();
                        iframe.height(iframeHeight);
                    });
                }
                $('#assetp-tabs').tab();
            });
            theme.loading(el);
        };

        $('#assetp-tabs').on('click', 'a[href="#tab-reviews"]',function (e) {
            var thiz = $(this),
                current = new Date().getTime();
            e.preventDefault();
            if (!comments.interval || (current - (comments.updated || 0) < comments.interval)) {
                thiz.tab('show');
                return;
            }
            loadReviews(comments.commentsUrl + paging.current, paging.current);
            thiz.tab('show');
        }).on('click', 'a[href="#tab-properties"]', function (e) {

            });

        $('#tab-review-box').find('.btn-primary').live('click', function (e) {
            if (!$("#form-review").valid()) return;
            caramel.post('/apis/comment', {
                asset: $('#assetp-tabs').data('aid'),
                content: $('#tab-review-box').find('.content').val()
            }, function (data) {
                loadReviews(comments.commentsUrl + paging.current, paging.current);
            }, 'json');
        });

        $('.text-review-box').live('keyup focus', function (e) {
            if ($('#comment-content').hasClass('user-review')) {
                $(".btn-review").removeClass("btn-primary");
                $(".btn-review").addClass("disabled");
                $('.text-review-box-charCount-msg').hide();
                $('.error-text').show();
                return false;
            }
            var chars = this.value.length;
            $('.text-review-box-charCount-msg').show();
            var limit = 490;
            if (chars > limit) {
                src.value = src.value.substr(0, limit);
                chars = limit;
            }
            $("#charCount").html(limit - chars);
            return false;

        });

        /*    $('#btn-copy-gadget-code').click(function(){
         var script = $('#modal-add-gadget code').html().trim();
         localStorage['gadget-code'] = script;
         $(this).fadeOut("fast", function(){
         $(this).attr('id', 'btn-open-editor').text('Open Editor').fadeIn("fast", function(){
         $('.copy-status').html('Code copied to clipboard').delay(1000).fadeIn();
         });

         })

         })
         $('#btn-open-editor').live('click', function(){
         location.href = '/portal/dashboard.jag';
         })*/
        /*
         $(document).scroll(function(){
         var h = $(this).scrollTop();
         if(h>19){
         $('.asset-description-header').addClass('asset-description-header-scroll');
         } else {
         $('.asset-description-header').removeClass('asset-description-header-scroll');
         }
         })*/
    }
    $('#btn-add-gadget').click(function () {
        var elem = $(this);
        asset.process(elem.data('type'), elem.data('aid'), location.href);
    });

    $("a[data-toggle='tooltip']").tooltip();

    $('.embed-snippet').hide();

    $('.btn-embed').click(function () {
        $('.embed-snippet').toggle(400);
        return false;
    });

    var el = $('.user-rating'),
        rating = el.data('rating');
    $($('input', el)[rating - 1]).attr('checked', 'checked');

    $('.auto-submit-star').rating({
        callback: function (value, link) {
            if (value == undefined) {
                value = 0;
            }
            $('.rate-num-assert').html('(' + value + ')');
            caramel.post('/apis/rate', {
                asset: $('#assetp-tabs').data('aid'),
                value: value || 0
            }, function (data) {

            });
        }
    });

});
<commit_msg>fixing STORE-331.<commit_after>$(function () {
    var $tab = $('#tab-reviews');
    $('a').click(function(){
        var tab = $(this).data("type");
        if(tab=="basic"){
            $tab.css({position:'static', visibility:'hidden'});
        }else if(tab=="comments"){
            $tab.css({position:'static', visibility:'visible'});

        }
    });

    if (isSocial) {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = 'https://localhost:9443/social/export-js/social.js';
        document.body.appendChild(script);
    } else {
        var comments = {
                interval: 5 * 1000,
                commentsUrl: caramel.context + '/apis/comments?asset=' + $('#assetp-tabs').data('aid') + '&page=',
                pagingUrl: '/apis/comments/paging?page=',
                partial: '/themes/store/partials/comments.hbs'
            },
            paging = {
                current: 1,
                partial: '/themes/store/partials/pagination.hbs'
            };

        $tab.on('click', '.pagination a', function (e) {
            e.preventDefault();
            var page,
                thiz = $(this),
                str = thiz.text(),
                url = thiz.attr('href');
            if (url === '#') {
                return;
            }
            if (str.indexOf('Next') !== -1) {
                page = paging.current + 1;
            } else if (str.indexOf('Prev') !== -1) {
                page = paging.current - 1
            } else {
                page = parseInt(str, 10);
            }
            loadReviews(url, page);
        });

        var loadReviews = function (url, page) {
            var iframe, iframeHeight,
                el = $('#tab-reviews').find('.content');
            comments.updated = new Date().getTime();
            async.parallel({
                comments: function (callback) {
                    $.get(url, function (data) {
                        callback(null, data);
                    }, 'json');
                },
                paging: function (callback) {
                    caramel.post(comments.pagingUrl + page, {
                        asset: $('#assetp-tabs').data('aid')
                    }, function (data) {
                        paging.current = data.current;
                        callback(null, data);
                    }, 'json');
                }
            }, function (error, result) {
                if (error) {
                    theme.loaded(el, '
Error while retrieving data.
')
                } else {
                    async.parallel({
                        comments: function (callback) {
                            var i, comment,
                                comments = result.comments,
                                length = comments.length;
                            for (i = 0; i < length; i++) {
                                comment = comments[i];
                                comment.created.time = moment(comment.created.time).format('LL');
                            }
                            caramel.render('comments', {
                                user: store.user,
                                comments: comments
                            }, callback);
                        },
                        paging: function (callback) {
                            caramel.render('pagination', result.paging, callback);
                        }
                    }, function (err, result) {
                        theme.loaded(el, result.comments);
                        el.append(result.paging);

                        iframe = $('#tab-reviews').find('iframe');
                        iframeHeight = iframe.contents().height();
                        iframe.height(iframeHeight);
                    });
                }
                $('#assetp-tabs').tab();
            });
            theme.loading(el);
        };

        $('#assetp-tabs').on('click', 'a[href="#tab-reviews"]',function (e) {
            var thiz = $(this),
                current = new Date().getTime();
            e.preventDefault();
            if (!comments.interval || (current - (comments.updated || 0) < comments.interval)) {
                thiz.tab('show');
                return;
            }
            loadReviews(comments.commentsUrl + paging.current, paging.current);
            thiz.tab('show');
        }).on('click', 'a[href="#tab-properties"]', function (e) {

            });

        $('#tab-review-box').find('.btn-primary').live('click', function (e) {
            if (!$("#form-review").valid()) return;
            caramel.post('/apis/comment', {
                asset: $('#assetp-tabs').data('aid'),
                content: $('#tab-review-box').find('.content').val()
            }, function (data) {
                loadReviews(comments.commentsUrl + paging.current, paging.current);
            }, 'json');
        });

        $('.text-review-box').live('keyup focus', function (e) {
            if ($('#comment-content').hasClass('user-review')) {
                $(".btn-review").removeClass("btn-primary");
                $(".btn-review").addClass("disabled");
                $('.text-review-box-charCount-msg').hide();
                $('.error-text').show();
                return false;
            }
            var chars = this.value.length;
            $('.text-review-box-charCount-msg').show();
            var limit = 490;
            if (chars > limit) {
                src.value = src.value.substr(0, limit);
                chars = limit;
            }
            $("#charCount").html(limit - chars);
            return false;

        });

        /*    $('#btn-copy-gadget-code').click(function(){
         var script = $('#modal-add-gadget code').html().trim();
         localStorage['gadget-code'] = script;
         $(this).fadeOut("fast", function(){
         $(this).attr('id', 'btn-open-editor').text('Open Editor').fadeIn("fast", function(){
         $('.copy-status').html('Code copied to clipboard').delay(1000).fadeIn();
         });

         })

         })
         $('#btn-open-editor').live('click', function(){
         location.href = '/portal/dashboard.jag';
         })*/
        /*
         $(document).scroll(function(){
         var h = $(this).scrollTop();
         if(h>19){
         $('.asset-description-header').addClass('asset-description-header-scroll');
         } else {
         $('.asset-description-header').removeClass('asset-description-header-scroll');
         }
         })*/
    }
    $('#btn-add-gadget').click(function () {
        var elem = $(this);
        asset.process(elem.data('type'), elem.data('aid'), location.href);
    });

    $("a[data-toggle='tooltip']").tooltip();

    $('.embed-snippet').hide();

    $('.btn-embed').click(function () {
        $('.embed-snippet').toggle(400);
        return false;
    });

    var el = $('.user-rating'),
        rating = el.data('rating');
    $($('input', el)[rating - 1]).attr('checked', 'checked');

    $('.auto-submit-star').rating({
        callback: function (value, link) {
            if (value == undefined) {
                value = 0;
            }
            $('.rate-num-assert').html('(' + value + ')');
            caramel.post('/apis/rate', {
                asset: $('#assetp-tabs').data('aid'),
                value: value || 0
            }, function (data) {

            });
        }
    });

});
<|endoftext|>