<commit_before>"use strict";

const esprima = require("esprima").parse;
const fs = require("fs");
const assert = require("assert");
const is = require("./lib/is");
const fmt = require("./lib/fmt");
const traverse = require("./traverse");
const Scope = require("./scope");
const alter = require("./alter");
const error = require("./error");

if (process.argv.length <= 2) {
    console.log("USAGE: node --harmony blockscope.js file.js");
    process.exit(-1);
}
const filename = process.argv[2];

if (!fs.existsSync(filename)) {
    console.log(fmt("error: file not found <{0}>", filename));
    process.exit(-1);
}

const src = String(fs.readFileSync(filename));
const ast = esprima(src, {
    loc: true,
    range: true,
});

function getline(node) {
    return node.loc.start.line;
}

function isConstLet(kind) {
    return is.someof(kind, ["const", "let"]);
}

function isVarConstLet(kind) {
    return is.someof(kind, ["var", "const", "let"]);
}

function isNonFunctionBlock(node) {
    return node.type === "BlockStatement" && is.noneof(node.$parent.type, ["FunctionDeclaration", "FunctionExpression"]);
}

function isForWithConstLet(node) {
    return node.type === "ForStatement" && node.init && node.init.type === "VariableDeclaration" && isConstLet(node.init.kind);
}

function isForInWithConstLet(node) {
    return node.type === "ForInStatement" && node.left.type === "VariableDeclaration" && isConstLet(node.left.kind);
}

function isFunction(node) {
    return is.someof(node.type, ["FunctionDeclaration", "FunctionExpression"]);
}

function isLoop(node) {
    return is.someof(node.type, ["ForStatement", "ForInStatement", "WhileStatement", "DoWhileStatement"]);
}

function isReference(node) {
    return node.type === "Identifier" &&
        !(node.$parent.type === "VariableDeclarator" && node.$parent.id === node) && // var|let|const $
        !(node.$parent.type === "MemberExpression" && node.$parent.property === node) && // obj.$
        !(node.$parent.type === "Property" && node.$parent.key === node) && // {$: ...}
        !(node.$parent.type === "LabeledStatement" && node.$parent.label === node) && // $: ...
        !(node.$parent.type === "CatchClause" && node.$parent.param === node) && // catch($)
        !(isFunction(node.$parent) && node.$parent.id === node) && // function $(..
        !(isFunction(node.$parent) && is.someof(node, node.$parent.params)) && // function f($)..
        true;
}

function createScopes(node) {
    node.$scope = node.$parent ? node.$parent.$scope : null; // may be overridden

    if (node.type === "Program") {
        // Top-level program is a scope
        // There's no block-scope under it
        node.$scope = new Scope({
            kind: "hoist",
            node: node,
            parent: null,
        });

    } else if (isFunction(node)) {
        // Function is a scope, with params in it
        // There's no block-scope under it
        // Function name goes in parent scope
        if (node.id) {
            assert(node.type === "FunctionDeclaration"); // no support for named function expressions yet
            assert(node.id.type === "Identifier");
            node.$parent.$scope.add(node.id.name, "fun");
        }

        node.$scope = new Scope({
            kind: "hoist",
            node: node,
            parent: node.$parent.$scope,
        });

        node.params.forEach(function(param) {
            node.$scope.add(param.name, "param");
        });

    } else if (node.type === "VariableDeclaration") {
        // Variable declarations names goes in current scope
        assert(isVarConstLet(node.kind));
        node.declarations.forEach(function(declarator) {
            assert(declarator.type === "VariableDeclarator");
            node.$scope.add(declarator.id.name, node.kind);
        });

    } else if (isForWithConstLet(node) || isForInWithConstLet(node)) {
        // For(In) loop with const|let declaration is a scope, with declaration in it
        // There may be a block-scope under it
        node.$scope = new Scope({
            kind: "block",
            node: node,
            parent: node.$parent.$scope,
        });

    } else if (isNonFunctionBlock(node)) {
        // A block node is a scope unless parent is a function
        node.$scope = new Scope({
            kind: "block",
            node: node,
            parent: node.$parent.$scope,
        });

    } else {
        // TODO catch(e)
    }
}

function setupReferences(node) {
    if (!isReference(node)) {
        return;
    }
    node.$references = node.$scope.lookup(node.name);
//    console.log(fmt("line {0}, col {1}: {2} - {3}", node.loc.start.line, node.loc.start.column, node.name, node.$references && node.$references.node.type));
}

// TODO make robust
let cnt = 0;
function unique(name) {
    return name + "$" + String(++cnt);
}

/*
Change all let and const declarations to var
optionally rename:
  if name is already present in hoisted scope
  if name is a reference that would otherwise get shadowed
add name to hoisted scope
remove name from
 */

// TODO for loops init and body props are parallell to each other but init scope is outer that of body
// TODO is this a problem?
const changes = [];
function convertConstLets(node) {
    if (node.type === "VariableDeclaration" && isConstLet(node.kind)) {
        const hoistScope = node.$scope.closestHoistScope();
        const origScope = node.$scope;

        // text change const|let => var
        changes.push({
            start: node.range[0],
            end: node.range[0] + node.kind.length,
            str: "var",
        });

        node.declarations.forEach(function(declaration) {
            assert(declaration.type === "VariableDeclarator");

            const name = declaration.id.name;

            // rename to avoid shadowing existing references to other variable with the same name
            let rename = false;
            traverse(hoistScope.node, {pre: function(node) {
                if (node.$references &&
                    node.name === name &&
                    node.$references !== origScope &&
                    hoistScope.isInnerScopeOf(node.$references)) {
//                        console.log("rename due to shadowing: " + name);
                    rename = true;
                }
            }});

            // rename due to the name being occupied in the hoisted scope (i.e. const|let used to shadow)
            if (origScope !== hoistScope && hoistScope.hasOwn(name)) {
                rename = true;
            }

            origScope.remove(name);
            const newName = (rename ? unique(name) : name);
            hoistScope.add(newName, "var");

            // textchange var x => var x$1
            if (newName !== name) {
                changes.push({
                    start: declaration.id.range[0],
                    end: declaration.id.range[1],
                    str: newName,
                });
            }

            // updated all existing references to the variable
            // TODO is node.$parent sufficient (considering for loop init not parent of body)?
            traverse(node.$parent, {pre: function(node) {
                if (node.$references === origScope && node.name === name) {
//                    console.log(fmt("updated ref for {0} to {1}", node.name, newName));

                    node.$references = hoistScope;

                    // textchange reference x => x$1
                    if (node.name !== newName) {
                        node.name = newName;
                        changes.push({
                            start: node.range[0],
                            end: node.range[1],
                            str: newName,
                        });
                    }
                }
            }});
        });
//        console.log(srcFor(node));
    }
}

let outermostLoop = null;
let functions = [];
function detectLoopClosuresPre(node) {
    if (outermostLoop === null && isLoop(node)) {
        outermostLoop = node;
    }
    if (!outermostLoop) {
        // not inside loop
        return;
    }

    // collect function-chain (as long as we're inside a loop)
    if (isFunction(node)) {
        functions.push(node);
    }
    if (functions.length === 0) {
        // not inside function
        return;
    }

    if (node.$references && isConstLet(node.$references.names.get(node.name))) {
        let n = node.$references.node;

        // node is an identifier
        // scope refers to the scope where the variable is defined
        // loop ..-> function ..-> node

        let ok = true;
        while (n) {
//            n.print();
//            console.log("--");
            if (n === functions[functions.length - 1]) {
                // we're ok (function-local)
                break;
            }
            if (n === outermostLoop) {
                // not ok (between loop and function)
                ok = false;
                break;
            }
//            console.log("# " + scope.node.type);
            n = n.$parent;
//            console.log("# " + scope.node);
        }
        if (ok) {
//            console.log("ok loop + closure: " + node.name);
        } else {
            error(getline(node), "can't transform closure. {0} is defined outside closure, inside loop", node.name);
        }

        /*
        walk the scopes, starting from innermostFunction, ending at outermostLoop
        if the referenced scope is somewhere in-between, then we have an issue
        if the referenced scope is inside innermostFunction, then no problem (function-local const|let)
        if the referenced scope is outside outermostLoop, then no problem (const|let external to the loop)

         */
    }
}

function detectLoopClosuresPost(node) {
    if (outermostLoop === node) {
        outermostLoop = null;
    }
    if (isFunction(node)) {
        functions.pop();
    }
}

traverse(ast, {pre: createScopes});
traverse(ast, {pre: setupReferences});
//ast.$scope.print(); process.exit(-1);
traverse(ast, {pre: detectLoopClosuresPre, post: detectLoopClosuresPost});
if (error.any) {
    process.exit(-1);
}
traverse(ast, {pre: convertConstLets});

const transformedSrc = alter(src, changes)
process.stdout.write(transformedSrc);

//console.dir(ast);

function srcFor(node) {
    return src.slice(node.range[0], node.range[1]);
}
<commit_msg>node.$references -> node.$refToScope<commit_after>"use strict";

const esprima = require("esprima").parse;
const fs = require("fs");
const assert = require("assert");
const is = require("./lib/is");
const fmt = require("./lib/fmt");
const traverse = require("./traverse");
const Scope = require("./scope");
const alter = require("./alter");
const error = require("./error");

if (process.argv.length <= 2) {
    console.log("USAGE: node --harmony blockscope.js file.js");
    process.exit(-1);
}
const filename = process.argv[2];

if (!fs.existsSync(filename)) {
    console.log(fmt("error: file not found <{0}>", filename));
    process.exit(-1);
}

const src = String(fs.readFileSync(filename));
const ast = esprima(src, {
    loc: true,
    range: true,
});

function getline(node) {
    return node.loc.start.line;
}

function isConstLet(kind) {
    return is.someof(kind, ["const", "let"]);
}

function isVarConstLet(kind) {
    return is.someof(kind, ["var", "const", "let"]);
}

function isNonFunctionBlock(node) {
    return node.type === "BlockStatement" && is.noneof(node.$parent.type, ["FunctionDeclaration", "FunctionExpression"]);
}

function isForWithConstLet(node) {
    return node.type === "ForStatement" && node.init && node.init.type === "VariableDeclaration" && isConstLet(node.init.kind);
}

function isForInWithConstLet(node) {
    return node.type === "ForInStatement" && node.left.type === "VariableDeclaration" && isConstLet(node.left.kind);
}

function isFunction(node) {
    return is.someof(node.type, ["FunctionDeclaration", "FunctionExpression"]);
}

function isLoop(node) {
    return is.someof(node.type, ["ForStatement", "ForInStatement", "WhileStatement", "DoWhileStatement"]);
}

function isReference(node) {
    return node.type === "Identifier" &&
        !(node.$parent.type === "VariableDeclarator" && node.$parent.id === node) && // var|let|const $
        !(node.$parent.type === "MemberExpression" && node.$parent.property === node) && // obj.$
        !(node.$parent.type === "Property" && node.$parent.key === node) && // {$: ...}
        !(node.$parent.type === "LabeledStatement" && node.$parent.label === node) && // $: ...
        !(node.$parent.type === "CatchClause" && node.$parent.param === node) && // catch($)
        !(isFunction(node.$parent) && node.$parent.id === node) && // function $(..
        !(isFunction(node.$parent) && is.someof(node, node.$parent.params)) && // function f($)..
        true;
}

function createScopes(node) {
    node.$scope = node.$parent ? node.$parent.$scope : null; // may be overridden

    if (node.type === "Program") {
        // Top-level program is a scope
        // There's no block-scope under it
        node.$scope = new Scope({
            kind: "hoist",
            node: node,
            parent: null,
        });

    } else if (isFunction(node)) {
        // Function is a scope, with params in it
        // There's no block-scope under it
        // Function name goes in parent scope
        if (node.id) {
            assert(node.type === "FunctionDeclaration"); // no support for named function expressions yet
            assert(node.id.type === "Identifier");
            node.$parent.$scope.add(node.id.name, "fun");
        }

        node.$scope = new Scope({
            kind: "hoist",
            node: node,
            parent: node.$parent.$scope,
        });

        node.params.forEach(function(param) {
            node.$scope.add(param.name, "param");
        });

    } else if (node.type === "VariableDeclaration") {
        // Variable declarations names goes in current scope
        assert(isVarConstLet(node.kind));
        node.declarations.forEach(function(declarator) {
            assert(declarator.type === "VariableDeclarator");
            node.$scope.add(declarator.id.name, node.kind);
        });

    } else if (isForWithConstLet(node) || isForInWithConstLet(node)) {
        // For(In) loop with const|let declaration is a scope, with declaration in it
        // There may be a block-scope under it
        node.$scope = new Scope({
            kind: "block",
            node: node,
            parent: node.$parent.$scope,
        });

    } else if (isNonFunctionBlock(node)) {
        // A block node is a scope unless parent is a function
        node.$scope = new Scope({
            kind: "block",
            node: node,
            parent: node.$parent.$scope,
        });

    } else {
        // TODO catch(e)
    }
}

function setupReferences(node) {
    if (!isReference(node)) {
        return;
    }
    const scope = node.$scope.lookup(node.name);
    node.$refToScope = scope;
}

// TODO make robust
let cnt = 0;
function unique(name) {
    return name + "$" + String(++cnt);
}

/*
Change all let and const declarations to var
optionally rename:
  if name is already present in hoisted scope
  if name is a reference that would otherwise get shadowed
add name to hoisted scope
remove name from
 */

// TODO for loops init and body props are parallell to each other but init scope is outer that of body
// TODO is this a problem?
const changes = [];
function convertConstLets(node) {
    if (node.type === "VariableDeclaration" && isConstLet(node.kind)) {
        const hoistScope = node.$scope.closestHoistScope();
        const origScope = node.$scope;

        // text change const|let => var
        changes.push({
            start: node.range[0],
            end: node.range[0] + node.kind.length,
            str: "var",
        });

        node.declarations.forEach(function(declaration) {
            assert(declaration.type === "VariableDeclarator");

            const name = declaration.id.name;

            // rename to avoid shadowing existing references to other variable with the same name
            let rename = false;
            traverse(hoistScope.node, {pre: function(node) {
                if (node.$refToScope &&
                    node.$refToScope !== origScope &&
                    node.name === name &&
                    hoistScope.isInnerScopeOf(node.$refToScope)) {
//                        console.log("rename due to shadowing: " + name);
                    rename = true;
                }
            }});

            // rename due to the name being occupied in the hoisted scope (i.e. const|let used to shadow)
            if (origScope !== hoistScope && hoistScope.hasOwn(name)) {
                rename = true;
            }

            origScope.remove(name);
            const newName = (rename ? unique(name) : name);
            hoistScope.add(newName, "var");

            // textchange var x => var x$1
            if (newName !== name) {
                changes.push({
                    start: declaration.id.range[0],
                    end: declaration.id.range[1],
                    str: newName,
                });
            }

            // updated all existing references to the variable
            // TODO is node.$parent sufficient (considering for loop init not parent of body)?
            traverse(node.$parent, {pre: function(node) {
                if (node.$refToScope === origScope && node.name === name) {
//                    console.log(fmt("updated ref for {0} to {1}", node.name, newName));

                    node.$refToScope = hoistScope;

                    // textchange reference x => x$1
                    if (node.name !== newName) {
                        node.name = newName;
                        changes.push({
                            start: node.range[0],
                            end: node.range[1],
                            str: newName,
                        });
                    }
                }
            }});
        });
//        console.log(srcFor(node));
    }
}

let outermostLoop = null;
let functions = [];
function detectLoopClosuresPre(node) {
    if (outermostLoop === null && isLoop(node)) {
        outermostLoop = node;
    }
    if (!outermostLoop) {
        // not inside loop
        return;
    }

    // collect function-chain (as long as we're inside a loop)
    if (isFunction(node)) {
        functions.push(node);
    }
    if (functions.length === 0) {
        // not inside function
        return;
    }

    if (node.$refToScope && isConstLet(node.$refToScope.names.get(node.name))) {
        let n = node.$refToScope.node;

        // node is an identifier
        // scope refers to the scope where the variable is defined
        // loop ..-> function ..-> node

        let ok = true;
        while (n) {
//            n.print();
//            console.log("--");
            if (n === functions[functions.length - 1]) {
                // we're ok (function-local)
                break;
            }
            if (n === outermostLoop) {
                // not ok (between loop and function)
                ok = false;
                break;
            }
//            console.log("# " + scope.node.type);
            n = n.$parent;
//            console.log("# " + scope.node);
        }
        if (ok) {
//            console.log("ok loop + closure: " + node.name);
        } else {
            error(getline(node), "can't transform closure. {0} is defined outside closure, inside loop", node.name);
        }

        /*
        walk the scopes, starting from innermostFunction, ending at outermostLoop
        if the referenced scope is somewhere in-between, then we have an issue
        if the referenced scope is inside innermostFunction, then no problem (function-local const|let)
        if the referenced scope is outside outermostLoop, then no problem (const|let external to the loop)

         */
    }
}

function detectLoopClosuresPost(node) {
    if (outermostLoop === node) {
        outermostLoop = null;
    }
    if (isFunction(node)) {
        functions.pop();
    }
}

traverse(ast, {pre: createScopes});
traverse(ast, {pre: setupReferences});
//ast.$scope.print(); process.exit(-1);
traverse(ast, {pre: detectLoopClosuresPre, post: detectLoopClosuresPost});
if (error.any) {
    process.exit(-1);
}
traverse(ast, {pre: convertConstLets});

const transformedSrc = alter(src, changes)
process.stdout.write(transformedSrc);

//console.dir(ast);

function srcFor(node) {
    return src.slice(node.range[0], node.range[1]);
}
<|endoftext|>


<commit_before>// Standard AMD RequireJS define
define(function(){
    // Fill this with your database information.

    // Configure which version of backbone-couchdb we are using
    var mode = 'backbone-couchdb' // Jan Monschke's original backbone-couch.js
    //var mode = 'backbone.couch' // backbone.couch.js. Andrzej Sliwa's old rewrite of JM's backbone-couch.
    //var mode = 'backbone.couchdb' // Thomas Rampelberg's backbone.couchdb.js
    if (mode == 'backbone-couchdb'){
        // `ddoc_name` is the name of your couchapp project.
        Backbone.couch_connector.config.db_name = "rcl";
        Backbone.couch_connector.config.ddoc_name = "rcl";

        // If set to true, the connector will listen to the changes feed
        // and will provide your models with real time remote updates.
        // But in this case we enable the changes feed for each Collection on our own.
        // TODO: Get this to work
        Backbone.couch_connector.config.global_changes = true;
        // TODO: Replicate ddocChange() window.location.reload() functionality (see below)
        //  available in backbone.couch.js for use here in backbone-couchdb.js
    }else if (mode=='backbone.couch'){
       Backbone.couch.databaseName = "rcl";
       Backbone.couch.ddocName = "rcl";
       // TODO: Replicate this functionality for backbone-couchdb above
       Backbone.couch.ddocChange(function(ddocName){
         if (console && console.log) {
           console.log("current ddoc: '" + ddocName + "' changed");
           console.log("restarting...");
         }
         window.location.reload();
      });
       // TODO: Does this auto-update models in browser with changes on server?
      Backbone.couch.enableChangesFeed = true;
    }

    // set your models here

    // A link object between 'CGroup' and 'Cong', to achieve many-to-many relations.
    CGroup_Cong = Backbone.RelationalModel.extend({})
    CGroup = Backbone.RelationalModel.extend({
        collection:'cgroup',
        urlRoot:'/cgroup',
        defaults:{
            name: '',
            abbreviaton: '',
            website: ''
        },
        relations:[
                   {
                       type:'HasMany',
                       key: 'congregations',
                       relatedModel: 'CGroup_Cong',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'cgroup',
                           // TODO: Is this needed?
                           includeInJSON:'_id'
                       }
                   },
                   {
                       type:'HasMany',
                       key: 'people',
                       relatedModel: 'CGroup_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'cgroup',
                           includeInJSON:'_id'
                       }
                   },
                   {
                       type:'HasMany',
                       key: 'roles',
                       relatedModel: 'CGroup_Role',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'cgroup',
                           includeInJSON:'_id'
                       }
                   },
                   {
                       type:'HasMany',
                       key: 'directories',
                       relatedModel: 'Directory',
                       includeInJSON:'_id',
                       // TODO: Should we include this collectionType attribute in the other relations?
                       collectionType:'DirectoryList',
                       reverseRelation: {
                           key: 'cgroup',
                           includeInJSON:'_id'
                       }
                   }
                   ]
      })
    Cong = Backbone.RelationalModel.extend({
      urlRoot:'/cong',
      collection:'cong',
      defaults:{
          name : '',
          meeting_address1 : '',
          meeting_address2:'',
          meeting_city:'',
          meeting_state:'',
          meeting_zip:'',
          meeting_country:'',
          lat:'',
          lng:'',
          mailing_address1:'',
          mailing_address2:'',
          mailing_city:'',
          mailing_state:'',
          mailing_zip:'',
          mailing_country:'',
          phone:'',
          fax:'',
          email:'',
          website:'',
          service_info:'',
          date_founded:'', // date
          number_of_members:'', // integer
          range_of_number_of_members:'', // textual range, like '20-30' members, where estimates are
                                         //   permitted/preferred or the only available data
          organized:'', // boolean, defines whether this is a mission work or an organized congregation
          source:'', // Foreign key:  Which source this cong's data came from
          source_cong_id:'', // The ID of this cong in the source's database
      },
      relations:[
                 {
                     type:'HasMany',
                     key: 'cgroups',
                     relatedModel: 'CGroup_Cong',
                     includeInJSON:'_id',
                     reverseRelation: {
                         key: 'congregation',
                         includeInJSON:'_id'
                     }
                 },
                 {
                     type:'HasMany',
                     key: 'people',
                     relatedModel: 'Cong_Person',
                     includeInJSON:'_id',
                     reverseRelation: {
                         key: 'congregation',
                         includeInJSON:'_id'
                     }
                 }
                 ]
    })
    // A link object between 'Cong' and 'Person', to achieve many-to-many relations.
    Cong_Person = Backbone.RelationalModel.extend({})
    Person = Backbone.RelationalModel.extend({
        urlRoot:'/person',
        collection:'person',
        defaults: {
                    prefix:'',
                    firstname:'',
                    lastname:'',
                    suffix:'',
                    phone:'',
                    email:''
        },
        relations:[
                   {
                       type:'HasMany',
                       key: 'congregations',
                       relatedModel: 'Cong_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   },
                   // TODO: create link object
                   {
                       type:'HasMany',
                       key: 'groups',
                       relatedModel: 'CGroup_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   },
                   // TODO: create link object
                   {
                       type:'HasMany',
                       key: 'roles',
                       relatedModel: 'Person_Role',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   },
                   // TODO: create link object
                   {
                       type:'HasMany',
                       key: 'offices',
                       relatedModel: 'Office_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   }
                   ]
    })

    return {
        CGroup_Cong: CGroup_Cong,
        CGroup: CGroup,
        Cong: Cong,
        Cong_Person: Cong_Person,
        Person: Person
    }
})
<commit_msg>Adding more model objects<commit_after>// Standard AMD RequireJS define
define(function(){
    // Fill this with your database information.

    // Configure which version of backbone-couchdb we are using
    var mode = 'backbone-couchdb' // Jan Monschke's original backbone-couch.js
    //var mode = 'backbone.couch' // backbone.couch.js. Andrzej Sliwa's old rewrite of JM's backbone-couch.
    //var mode = 'backbone.couchdb' // Thomas Rampelberg's backbone.couchdb.js
    if (mode == 'backbone-couchdb'){
        // `ddoc_name` is the name of your couchapp project.
        Backbone.couch_connector.config.db_name = "rcl";
        Backbone.couch_connector.config.ddoc_name = "rcl";

        // If set to true, the connector will listen to the changes feed
        // and will provide your models with real time remote updates.
        // But in this case we enable the changes feed for each Collection on our own.
        // TODO: Get this to work
        Backbone.couch_connector.config.global_changes = true;
        // TODO: Replicate ddocChange() window.location.reload() functionality (see below)
        //  available in backbone.couch.js for use here in backbone-couchdb.js
    }else if (mode=='backbone.couch'){
       Backbone.couch.databaseName = "rcl";
       Backbone.couch.ddocName = "rcl";
       // TODO: Replicate this functionality for backbone-couchdb above
       Backbone.couch.ddocChange(function(ddocName){
         if (console && console.log) {
           console.log("current ddoc: '" + ddocName + "' changed");
           console.log("restarting...");
         }
         window.location.reload();
      });
       // TODO: Does this auto-update models in browser with changes on server?
      Backbone.couch.enableChangesFeed = true;
    }

    // set your models here

    // A link object between 'CGroup' and 'Cong', to achieve many-to-many relations.
    CGroup_Cong = Backbone.RelationalModel.extend({})
    CGroup = Backbone.RelationalModel.extend({
        collection:'cgroup',
        urlRoot:'/cgroup',
        defaults:{
            name: '',
            abbreviaton: '',
            website: ''
        },
        relations:[
                   {
                       type:'HasMany', // many-to-many
                       key: 'congregations',
                       relatedModel: 'CGroup_Cong',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'cgroup',
                           // TODO: Is this needed?
                           includeInJSON:'_id'
                       }
                   },
                   {
                       type:'HasMany',
                       key: 'people',
                       relatedModel: 'CGroup_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'cgroup',
                           includeInJSON:'_id'
                       }
                   },
                   {
                       type:'HasMany',
                       key: 'roles',
                       relatedModel: 'CGroup_Role',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'cgroup',
                           includeInJSON:'_id'
                       }
                   },
                   {
                       type:'HasMany',
                       key: 'directories',
                       relatedModel: 'Directory',
                       includeInJSON:'_id',
                       // TODO: Should we include this collectionType attribute in the other relations?
                       collectionType:'DirectoryList',
                       reverseRelation: {
                           key: 'cgroup',
                           includeInJSON:'_id'
                       }
                   }
                   ]
      })
    Cong = Backbone.RelationalModel.extend({
      urlRoot:'/cong',
      collection:'cong',
      defaults:{
          name : '',
          meeting_address1 : '',
          meeting_address2:'',
          meeting_city:'',
          meeting_state:'',
          meeting_zip:'',
          meeting_country:'',
          lat:'',
          lng:'',
          mailing_address1:'',
          mailing_address2:'',
          mailing_city:'',
          mailing_state:'',
          mailing_zip:'',
          mailing_country:'',
          phone:'',
          fax:'',
          email:'',
          website:'',
          service_info:'',
          date_founded:'', // date
          number_of_members:'', // integer
          range_of_number_of_members:'', // textual range, like '20-30' members, where estimates are
                                         //   permitted/preferred or the only available data
          organized:'', // boolean, defines whether this is a mission work or an organized congregation
          source:'', // Foreign key:  Which source this cong's data came from
          source_cong_id:'', // The ID of this cong in the source's database
      },
      relations:[
                 {
                     type:'HasMany',
                     key: 'cgroups',
                     relatedModel: 'CGroup_Cong',
                     includeInJSON:'_id',
                     reverseRelation: {
                         key: 'congregation',
                         includeInJSON:'_id'
                     }
                 },
                 {
                     type:'HasMany',
                     key: 'people',
                     relatedModel: 'Cong_Person',
                     includeInJSON:'_id',
                     reverseRelation: {
                         key: 'congregation',
                         includeInJSON:'_id'
                     }
                 }
                 ]
    })
    // A link object between 'Cong' and 'Person', to achieve many-to-many relations.
    Cong_Person = Backbone.RelationalModel.extend({})
    Person = Backbone.RelationalModel.extend({
        urlRoot:'/person',
        collection:'person',
        defaults: {
                    prefix:'',
                    firstname:'',
                    lastname:'',
                    suffix:'',
                    phone:'',
                    email:''
        },
        relations:[
                   {
                       type:'HasMany',
                       key: 'congregations',
                       relatedModel: 'Cong_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   },
                   // TODO: create link object
                   {
                       type:'HasMany',
                       key: 'groups',
                       relatedModel: 'CGroup_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   },
                   // TODO: create link object
                   {
                       type:'HasMany',
                       key: 'roles',
                       relatedModel: 'Person_Role',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   },
                   // TODO: create link object
                   {
                       type:'HasMany',
                       key: 'offices',
                       relatedModel: 'Office_Person',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'person',
                           includeInJSON:'_id'
                       }
                   }
                   ]
    })
    Directory = Backbone.RelationalModel.extend({
        collection:'directory',
        urlRoot:'/directory',
        defaults:{
            get_url_contents:'', // true or false
            pagetype:'', // html or rss
            url:'', // url of directory's main page
            url_html:'', // HTML of directory's main page
            state_url:'', // URL of state page
            state_url_html:'', // HTML of state page
            state_page_values:[] // list of select box options for this directory's states
        },
        relations:[
                   {
                       type:'HasOne', // many-to-one
                       key: 'cgroup',
                       relatedModel: 'CGroup_Directory',
                       includeInJSON:'_id',
                       reverseRelation: {
                           key: 'directories',
                           // TODO: Is this needed?
                           includeInJSON:'_id'
                       }
                   }
                   ]
    })

    return {
        CGroup_Cong: CGroup_Cong,
        CGroup: CGroup,
        Cong: Cong,
        Cong_Person: Cong_Person,
        Person: Person
    }
})
<|endoftext|>


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

// @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp

'use strict';

// IMPORTANT: Avoid adding any initialization tasks here, if you need to do
// something before add-on is loaded consider addon/runner module instead!

const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu,
        results: Cr, manager: Cm } = Components;
const ioService = Cc['@mozilla.org/network/io-service;1'].
                  getService(Ci.nsIIOService);
const resourceHandler = ioService.getProtocolHandler('resource').
                        QueryInterface(Ci.nsIResProtocolHandler);
const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
                     getService(Ci.mozIJSSubScriptLoader);
const prefService = Cc['@mozilla.org/preferences-service;1'].
                    getService(Ci.nsIPrefService).
                    QueryInterface(Ci.nsIPrefBranch);
const { get, exists } = Cc['@mozilla.org/process/environment;1'].
                        getService(Ci.nsIEnvironment);

const prefSvc = Cc["@mozilla.org/preferences-service;1"].
                getService(Ci.nsIPrefService).getBranch(null);

const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const { Promise: { defer } } = Cu.import("resource://gre/modules/Promise.jsm", {});
const { Task: { spawn } } = Cu.import("resource://gre/modules/Task.jsm", {});
// load below now, so that it can be used by sdk/addon/runner
// see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1042239
const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;

const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
                 'install', 'uninstall', 'upgrade', 'downgrade' ];

const bind = Function.call.bind(Function.bind);

let loader = null;
let unload = null;
let loaderSandbox = null;
let nukeTimer = null;

function getPref(name, defaultValue) {
  defaultValue = defaultValue || null;
  switch (prefSvc.getPrefType(name)) {
  case Ci.nsIPrefBranch.PREF_STRING:
    return prefSvc.getComplexValue(name, Ci.nsISupportsString).data;

  case Ci.nsIPrefBranch.PREF_INT:
    return prefSvc.getIntPref(name);

  case Ci.nsIPrefBranch.PREF_BOOL:
    return prefSvc.getBoolPref(name);

  default:
    return defaultValue;
  }
}

// Utility function reads URI async. Returns promise for the read
// content.
const readURI = (uri, charset="utf-8") => {
  const channel = NetUtil.newChannel(uri, charset, null);
  const { promise, resolve, reject } = defer();

  try {
    NetUtil.asyncFetch(channel, (stream, result) => {
      if (Components.isSuccessCode(result)) {
        const count = stream.available();
        const data = NetUtil.readInputStreamToString(stream, count, {charset : charset});

        resolve(data);
      } else {
        reject(Error("Failed to read: '" + uri + "' (Error Code: " + result + ")"));
      }
    });
  }
  catch ({message}) {
    reject(Error("Failed to read: '" + uri + "' (Error: " + message + ")"));
  }

  return promise;
}

// We don't do anything on install & uninstall yet, but in a future
// we should allow add-ons to cleanup after uninstall.
const install = (data, reason) => {}
const uninstall = (data, reason) => {}

// Reads run configuration asynchronously, returns promise
// for the config JSON.
const readConfig = (rootURI) => {
  const { resolve, reject, promise } = defer();
  spawn(function () {
    let config = null;
    try {
      const options = JSON.parse(yield (readURI(rootURI + "./harness-options.json")));
      config = {
        options: options,
        metadata: options.metadata[options.name],
        isNative: false
      };
    }
    catch (_) {
      try {
        config = {
          isNative: true,
          options: {},
          metadata: JSON.parse(yield readURI(rootURI + './package.json'))
        };
      }
      catch(_) {}
    }
    resolve(config);
  });

  return promise;
}

const UUID_PATTERN = /^\{([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\}$/;
// Takes add-on ID and normalizes it to a domain name so that add-on
// can be mapped to resource://domain/
const readDomain = id =>
  // If only `@` character is the first one, than just substract it,
  // otherwise fallback to legacy normalization code path. Note: `.`
  // is valid character for resource substitutaiton & we intend to
  // make add-on URIs intuitive, so it's best to just stick to an
  // add-on author typed input.
  id.lastIndexOf("@") === 0 ? id.substr(1).toLowerCase() :
  id.toLowerCase().
     replace(/@/g, "-at-").
     replace(/\./g, "-dot-").
     replace(UUID_PATTERN, "$1");

const readPaths = (options, id, name, domain, baseURI, isNative=false) => {
  let paths = {
    "": "resource://gre/modules/commonjs/",
    "./": isNative ? baseURI : baseURI + name + '/lib/',
    "./tests/": (isNative ? baseURI : baseURI + name + '/') + 'tests/'
  };

  Object.keys(options.manifest || {}).reduce((paths, prefix) => {
    paths[prefix + "/"] = baseURI + prefix + "/lib/";
    paths[prefix + "tests/"] = baseURI + prefix + "/tests/";
    return paths;
  }, paths);

  if (name == "addon-sdk")
    paths["tests/"] = baseURI + "addon-sdk/tests/";

  // If SDK is bundled and it is required to use bundled version
  // of the SDK setup paths to do so.
  const isSDKBundled = options["is-sdk-bundled"];
  const useBundledSDK = options["force-use-bundled-sdk"] ||
                        getPref("extensions.addon-sdk.useBundledSDK");

  if (isSDKBundled && useBundledSDK) {
    paths[""] = baseURI + "addon-sdk/lib/";
    paths["test"] = baseURI + "addon-sdk/lib/sdk/test.js";
  }

  const branch = prefService.getBranch("extensions.modules." + id + ".path");
  branch.getChildList("", {}).reduce((paths, name) => {
    const path = name.substr(1).split(".").join("/");
    const prefix = path.length ? path + "/" : path;
    const value = branch.getCharPref(name);
    const fileURI = value[value.length - 1] === "/" ? value :
                    value + "/";
    const key = "extensions.modules." + domain + ".commonjs.path" + name;
    const uri = ioService.newURI(fileURI, null, null);
    resourceHandler.setSubstitution(key, uri);

    paths[prefix] = "resource://" + key + "/";
    return paths;
  }, paths);

  return paths;
}

// Takes JSON `options` and sets prefs for each key under
// the given `root`. Given `options` may contain nested
// objects.
const setPrefs = (root, options) =>
  void Object.keys(options).forEach(id => {
    const key = root + "." + id;
    const value = options[id]
    const type = typeof(value);

    value === null ? void(0) :
    value === undefined ? void(0) :
    type === "boolean" ? prefService.setBoolPref(key, value) :
    type === "string" ? prefService.setCharPref(key, value) :
    type === "number" ? prefService.setIntPref(key, parseInt(value)) :
    type === "object" ? setPrefs(key, value) :
    void(0);
  });

const startup = (addon, reasonCode) => {
  const reason = REASON[reasonCode];
  const { id, version, resourceURI: { spec: rootURI } } = addon;
  const loadCommand = exists("CFX_COMMAND") ?
                        get("CFX_COMMAND") :
                        getPref("extensions." + id + ".sdk.load.command", undefined);

  spawn(function() {
    try {
      const config = readConfig(rootURI);
      const { metadata, options, isNative } = (yield config);
      const permissions = Object.freeze(metadata.permissions || {});
      const domain = readDomain(id);
      const name = metadata.name;

      const baseURI = "resource://" + domain + "/";

      const prefsURI = baseURI + "defaults/preferences/prefs.js";

      const mappedURI = isNative ? rootURI + '/' : rootURI + '/resources/';
      resourceHandler.setSubstitution(domain, ioService.newURI(mappedURI, null, null));

      const paths = readPaths(options, id, name, domain, baseURI, isNative);

      const loaderID = isNative ? "toolkit/loader" : "sdk/loader/cuddlefish";
      const loaderURI = paths[""] + loaderID + ".js";

      loaderSandbox = loadSandbox(loaderURI);

      const loaderModule = loaderSandbox.exports;

      unload = loaderModule.unload;

      setPrefs("extensions." + id + ".sdk", {
        id: id,
        version: version,
        domain: domain,
        mainPath: options.mainPath,
        baseURI: baseURI,
        rootURI: rootURI,
        load: {
          reason: reason,
          command: loadCommand
        },
        input: {
          staticArgs: JSON.stringify(options.staticArgs)
        },
        output: {
          resultFile: options.resultFile,
          style: options.parseable ? "tbpl" : null,
          logLevel: options.verbose ? "verbose" : null,
        },
        test: {
          stop: options.stopOnError ? 1 : null,
          filter: options.filter,
          iterations: options.iterations,
        },
        profile: {
          memory: options.profileMemory,
          leaks: options.check_memory ? "refcount" : null
        }
      });

      const modules = {};

      // Manually set the loader's module cache to include itself;
      // which otherwise fails due to lack of `Components`.
      modules[loaderID] = loaderModule;
      modules["@test/options"] = Object.freeze({});

      loader = loaderModule.Loader({
        id: id,
        isNative: isNative,
        prefixURI: baseURI,
        rootURI: baseURI,
        name: name,
        paths: paths,
        manifest: options.manifest || metadata,
        metadata: metadata,
        modules: modules,
        noQuit: getPref("extensions." + id + ".sdk.test.no-quit", false)
      });

      const module = loaderModule.Module(loaderID, loaderURI);
      const require = loaderModule.Require(loader, module);
      const mainPath = (loadCommand == "test") ? "sdk/test/runner" : options.mainPath;

      require("sdk/addon/runner").startup(reason, {
        loader: loader,
        prefsURI: prefsURI,
        main: mainPath
      });
    }
    catch (error) {
      console.error("Failed to bootstrap addon: ", id, error);
      throw error;
    }
  });
};

const loadSandbox = (uri) => {
  let proto = {
    sandboxPrototype: {
      loadSandbox: loadSandbox,
      ChromeWorker: ChromeWorker
    }
  };
  let sandbox = Cu.Sandbox(systemPrincipal, proto);
  // Create a fake commonjs environnement just to enable loading loader.js
  // correctly
  sandbox.exports = {};
  sandbox.module = { uri: uri, exports: sandbox.exports };
  sandbox.require = function (id) {
    if (id !== "chrome")
      throw new Error("Bootstrap sandbox `require` method isn't implemented.");

    return Object.freeze({ Cc: Cc, Ci: Ci, Cu: Cu, Cr: Cr, Cm: Cm,
      CC: bind(CC, Components), components: Components,
      ChromeWorker: ChromeWorker });
  };
  scriptLoader.loadSubScript(uri, sandbox, 'UTF-8');
  return sandbox;
}

const unloadSandbox = sandbox =>
  Cu.nukeSandbox && sandbox && Cu.nukeSandbox(sandbox);

const setTimeout = (callback, delay=0) => {
  const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  timer.initWithCallback({ notify: callback },
                         delay,
                         Ci.nsITimer.TYPE_ONE_SHOT);
  return timer;
}

const shutdown = (data, reasonCode) => {
  let reason = REASON[reasonCode];
  if (loader) {
    unload(loader, reason);
    unload = null;

    // Don't waste time cleaning up if the application is shutting down
    if (reason != "shutdown") {
      // Avoid leaking all modules when something goes wrong with one particular
      // module. Do not clean it up immediatly in order to allow executing some
      // actions on addon disabling.
      // We need to keep a reference to the timer, otherwise it is collected
      // and won't ever fire.
      nukeTimer = setTimeout(nukeModules, 1000);
    }
  }
};

function nukeModules() {
  nukeTimer = null;
  // module objects store `exports` which comes from sandboxes
  // We should avoid keeping link to these object to avoid leaking sandboxes
  for (let id in loader.modules) {
    delete loader.modules[id];
  }

  // Direct links to sandboxes should be removed too
  for (let id in loader.sandboxes) {
    let sandbox = loader.sandboxes[id];
    delete loader.sandboxes[id];
    // Bug 775067: From FF17 we can kill all CCW from a given sandbox
    unloadSandbox(sandbox);
  }
  loader = null;

  // both `toolkit/loader` and `system/xul-app` are loaded as JSM's via
  // `cuddlefish.js`, and needs to be unloaded to avoid memory leaks, when
  // the addon is unload.

  unloadSandbox(loaderSandbox.loaderSandbox);
  unloadSandbox(loaderSandbox.xulappSandbox);

  // Bug 764840: We need to unload cuddlefish otherwise it will stay alive
  // and keep a reference to this compartment.
  unloadSandbox(loaderSandbox);
  loaderSandbox = null;
}
<commit_msg>Using the new sdk/addon/bootstrap.js<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

const { utils: Cu } = Components;
const rootURI = __SCRIPT_URI_SPEC__.replace("bootstrap.js", "");
const COMMONJS_URI = "resource://gre/modules/commonjs";
const { require } = Cu.import(`${COMMONJS_URI}/toolkit/require.js`, {});
const { Bootstrap } = require(`${COMMONJS_URI}/sdk/addon/bootstrap.js`);
const { startup, shutdown, install, uninstall } = new Bootstrap(rootURI);
<|endoftext|>


<commit_before>function getIdInClasses(el)
{
    var classes = $(el).attr("class").split(" ");
    for ( var i = 0; i < classes.length; i++ )
    {
        exp = new RegExp(".*id_([-]?[0-9]+)",'gi');
        var result = exp.exec(classes[i]) ;
        if ( result )
        {
            return result[1];
        }
    }
}

function check_screen_size()
{
  if($(window).width() < 1100)
    $('link:last').append('<link rel="stylesheet" id="tiny" type="text/css" href="/css/tiny.css">') ;
  else
    $('#tiny').remove() ;
}

function getElInClasses(element,prefix)
{
    var classes = $(element).attr("class").split(" ");
    for ( var i = 0; i < classes.length; i++ )
    {
        exp = new RegExp(prefix+"(.*)",'gi');
        var result = exp.exec(classes[i]) ;
        if ( result )
        {
            return result[1];
        }
    }
}

function removeAllQtip()
{
    var i = $.fn.qtip.interfaces.length; while(i--)
    {
            // Access current elements API
        var api = $.fn.qtip.interfaces[i];
            // Queue the animation so positions are updated correctly
        if(api && api.status.rendered && !api.status.hidden && !api.elements.target.is('.button'))
            api.destroy();
    };
}

function addBlackScreen()
{
    $(document).ready(function()
    {
        $('
')
            .css({
                top: $(document).scrollTop(), // Use document scrollTop so it's on-screen even if the window is scrolled
                left: 0,
                height: $(document).height() // Span the full document height...
            })
            .appendTo(document.body) // Append to the document body
            .hide(); // Hide it initially
    });
}

function hideForRefresh(el)
{
  $(el).css({position: 'relative'})
  $(el).append('
')
}

function showAfterRefresh(el)
{
  $(el).children('#loading_screen').remove();
}

function trim(myString)
{
  return jQuery.trim(myString);
}

function showValues()
{
  $(this).parent().find('ul').slideDown();
  $(this).parent().find('.hide_value').show();
  $(this).hide();
  return false;
};

function hideValues()
{
  $(this).parent().find('ul').slideUp();
  $(this).parent().find('.display_value').show();
  $(this).hide();
  return false;
};

function clearPropertyValue()
{
  parent = $(this).closest('tr');
  $(parent).find('input').val('');
  $(parent).hide();
}

$(document).ready(function()
{
  $(this).ajaxStart(function(){
    $('#load_indicator').fadeIn();
  });

  $(this).ajaxComplete(function(){
    $('#load_indicator').fadeOut();
  });
});

function returnText(object)
{
  var obj = object.jquery ? object[0] : object;
  if(typeof obj.selectionStart == 'number')
  {
    return obj.value.substring(obj.selectionStart, obj.selectionEnd);
  }
  else if(document.selection)
  {
    // Internet Explorer
    obj.focus();
    var range = document.selection.createRange();
    if(range.parentElement() != obj) return false;

    if(typeof range.text == 'string')
    {
      return range.text;
    }
  }
  else
    return false;
}

function clearSelection(el)
{
  t = el.val();
  el.val('');
  el.val(t);
}

function result_choose ()
{
        el = $(this).closest('tr');
        ref_element_id = getIdInClasses(el);
        ref_element_name = el.find('span.item_name').text();
        $('.result_choose').die('click');
        $('.qtip-button').click();
}

function objectsAreSame(x, y) {
   var objectsAreSame = true;
   for(var propertyName in x) {
      if(x[propertyName] !== y[propertyName]) {
         objectsAreSame = false;
         break;
      }
   }
   return objectsAreSame;
}

function attachHelpQtip(element)
{
        $(element).find(".help_ico").qtip({
          style: {
              width: 200,
              padding: 5,
              background: '#95bd4c',
              color: 'black',
              border: {
                  width: 7,
                  radius: 5,
                  color: '#95bd4c'
              },
              tip: 'bottomLeft',
              name: 'dark', // Inherit the rest of the attributes from the preset dark style
          },
          position: {
              corner: {
                  target: 'topRight',
                  tooltip: 'bottomLeft'
              }
          },
      });
}

function postToUrl(url, params, newWindow)
{
    var form = $('<form>');
    form.attr('action', url);
    form.attr('method', 'POST');
    if(newWindow){ form.attr('target', '_blank'); }

    var addParam = function(paramName, paramValue){
        var input = $('<input type="hidden">');
        input.attr({ 'id':     paramName,
                     'name':   paramName,
                     'value':  paramValue });
        form.append(input);
    };

    // Params is an Array.
    if(params instanceof Array){
        for(var i=0; i<params.length; i++){
            addParam(i, params[i]);
        }
    }

    // Params is an Associative array or Object.
    if(params instanceof Object){
        for(var key in params){
            addParam(key, params[key]);
        }
    }

    // Submit the form, then remove it from the page
    form.appendTo(document.body);
    form.submit();
    form.remove();
}
<commit_msg>Correct sign for ie<commit_after>function getIdInClasses(el)
{
    var classes = $(el).attr("class").split(" ");
    for ( var i = 0; i < classes.length; i++ )
    {
        exp = new RegExp(".*id_([-]?[0-9]+)",'gi');
        var result = exp.exec(classes[i]) ;
        if ( result )
        {
            return result[1];
        }
    }
}

function check_screen_size()
{
  if($(window).width() < 1100)
    $('link:last').append('<link rel="stylesheet" id="tiny" type="text/css" href="/css/tiny.css">') ;
  else
    $('#tiny').remove() ;
}

function getElInClasses(element,prefix)
{
    var classes = $(element).attr("class").split(" ");
    for ( var i = 0; i < classes.length; i++ )
    {
        exp = new RegExp(prefix+"(.*)",'gi');
        var result = exp.exec(classes[i]) ;
        if ( result )
        {
            return result[1];
        }
    }
}

function removeAllQtip()
{
    var i = $.fn.qtip.interfaces.length; while(i--)
    {
            // Access current elements API
        var api = $.fn.qtip.interfaces[i];
            // Queue the animation so positions are updated correctly
        if(api && api.status.rendered && !api.status.hidden && !api.elements.target.is('.button'))
            api.destroy();
    };
}

function addBlackScreen()
{
    $(document).ready(function()
    {
        $('
')
            .css({
                top: $(document).scrollTop(), // Use document scrollTop so it's on-screen even if the window is scrolled
                left: 0,
                height: $(document).height() // Span the full document height...
            })
            .appendTo(document.body) // Append to the document body
            .hide(); // Hide it initially
    });
}

function hideForRefresh(el)
{
  $(el).css({position: 'relative'})
  $(el).append('
')
}

function showAfterRefresh(el)
{
  $(el).children('#loading_screen').remove();
}

function trim(myString)
{
  return jQuery.trim(myString);
}

function showValues()
{
  $(this).parent().find('ul').slideDown();
  $(this).parent().find('.hide_value').show();
  $(this).hide();
  return false;
};

function hideValues()
{
  $(this).parent().find('ul').slideUp();
  $(this).parent().find('.display_value').show();
  $(this).hide();
  return false;
};

function clearPropertyValue()
{
  parent = $(this).closest('tr');
  $(parent).find('input').val('');
  $(parent).hide();
}

$(document).ready(function()
{
  $(this).ajaxStart(function(){
    $('#load_indicator').fadeIn();
  });

  $(this).ajaxComplete(function(){
    $('#load_indicator').fadeOut();
  });
});

function returnText(object)
{
  var obj = object.jquery ? object[0] : object;
  if(typeof obj.selectionStart == 'number')
  {
    return obj.value.substring(obj.selectionStart, obj.selectionEnd);
  }
  else if(document.selection)
  {
    // Internet Explorer
    obj.focus();
    var range = document.selection.createRange();
    if(range.parentElement() != obj) return false;

    if(typeof range.text == 'string')
    {
      return range.text;
    }
  }
  else
    return false;
}

function clearSelection(el)
{
  t = el.val();
  el.val('');
  el.val(t);
}

function result_choose ()
{
        el = $(this).closest('tr');
        ref_element_id = getIdInClasses(el);
        ref_element_name = el.find('span.item_name').text();
        $('.result_choose').die('click');
        $('.qtip-button').click();
}

function objectsAreSame(x, y) {
   var objectsAreSame = true;
   for(var propertyName in x) {
      if(x[propertyName] !== y[propertyName]) {
         objectsAreSame = false;
         break;
      }
   }
   return objectsAreSame;
}

function attachHelpQtip(element)
{
        $(element).find(".help_ico").qtip({
          style: {
              width: 200,
              padding: 5,
              background: '#95bd4c',
              color: 'black',
              border: {
                  width: 7,
                  radius: 5,
                  color: '#95bd4c'
              },
              tip: 'bottomLeft',
              name: 'dark', // Inherit the rest of the attributes from the preset dark style
          },
          position: {
              corner: {
                  target: 'topRight',
                  tooltip: 'bottomLeft'
              }
          }
      });
}

function postToUrl(url, params, newWindow)
{
    var form = $('<form>');
    form.attr('action', url);
    form.attr('method', 'POST');
    if(newWindow){ form.attr('target', '_blank'); }

    var addParam = function(paramName, paramValue){
        var input = $('<input type="hidden">');
        input.attr({ 'id':     paramName,
                     'name':   paramName,
                     'value':  paramValue });
        form.append(input);
    };

    // Params is an Array.
    if(params instanceof Array){
        for(var i=0; i<params.length; i++){
            addParam(i, params[i]);
        }
    }

    // Params is an Associative array or Object.
    if(params instanceof Object){
        for(var key in params){
            addParam(key, params[key]);
        }
    }

    // Submit the form, then remove it from the page
    form.appendTo(document.body);
    form.submit();
    form.remove();
}
<|endoftext|>


<commit_before>/*
 * This file is part of EMCOO TEAM PROJECT.
 *
 *  (c) EMCOO TEAM
 *  (c) DevMark <mark@emcoo.com>
 *
 *  For the full copyright and license information, please view http://emcoo.com/
 *
 *
 */

(function () {
    'use strict';

    angular.module('backend', [

        'authModule',
        'userModule',
        'postModule',
        'mediaModule',
        'mediaCategoryModule',
        'postCategoryModule',
        'settingModule',
        'languageModule',

        'theme.directives',
        'theme.services',
        'global.filter',
        'global.service',
        'global.directive',

        //UI Plugin
        'angular-spinkit',
        'smart-table',
        'ui.router',
        'ui.bootstrap',
        'ui.bootstrap.datetimepicker',
        'ui.tree',
        'ui.select',
        'checklist-model',
        'textAngular',
        'toaster', //notification plugin

        //Plugin
        'angular.filter',
        'pascalprecht.translate', //Multi Language plugin
        'angularMoment', //moment plugin, date plugin
        'restangular',
        'LocalStorageModule', // local storage module
        'tmh.dynamicLocale',

        'ngAnimate',
        'ngCookies',
        'ngTouch',
        'ngRoute',
        'ngSanitize'

    ])
        //================================================
        // Check isLogin when run system
        //================================================
        .run(function ($rootScope, $location, authenticationService, localStorageService, amMoment, tmhDynamicLocale, settingService, $translate, $timeout) {
            var routesThatRequireAuth = ['/auth/login', '/auth/logout'];

            //================================================
            // page route event
            //================================================
            $rootScope.pageViewLoading = false;

            $rootScope.$on('$stateChangeStart', function (event, next, current) {
                if (!_(routesThatRequireAuth).contains($location.path()) && !authenticationService.check()) {
                    console.log('Oops! please login!');
                    $location.path('auth/login');
                }
                $rootScope.pageViewLoading = true;
            });
            $rootScope.$on('$stateChangeSuccess', function () {
                $timeout(function () {
                    $rootScope.pageViewLoading = false;
                }, 500);
            });

            //================================================
            // page title init
            //================================================
            $translate('panel.name').then(function (translation) {
                $rootScope.siteTitle = translation;
            });
            $rootScope.meta = {
                pageTitle: ''
            };

            //================================================
            // global variable init
            //================================================
            $rootScope.$location = $location;

            //================================================
            // timezone init
            //================================================
            amMoment.changeTimezone(settingService.find('timezone'));

        })
        .run(function ($location, authenticationService, localStorageService, $timeout, Restangular, $http, $q, $state) {

            var refreshAccessToken = function () {
                var deferred = $q.defer();
                console.log('start get refresh token');

                $http({
                    method: 'POST', url: 'http://cms.dev/api/admin/auth/refresh-token', headers: {
                        'Authorization': authenticationService.getToken()
                    }
                }).success(function (data, status, headers, config) {
                    console.log('set token');
                    localStorageService.set('token', data.result.token);
                    deferred.resolve(data.result.token);
                }).error(function (data, status, headers, config) {
                    console.log('Oops! Expired Token, please login again! ');
                    $location.path('auth/login');
                    deferred.reject(data);
                });

                return deferred.promise;
            };

            Restangular.setErrorInterceptor(function (response, deferred, responseHandler) {
                if (response.data.message === 'token_invalid') {
                    localStorageService.remove('token');
                    $state.go('fullscreen.login');
                    return false;
                }

                if (response.data.message === 'token_expired') {
                    return refreshAccessToken().then(function () {
                        response.config.headers.Authorization = authenticationService.getToken();
                        // Repeat the request and then call the handlers the usual way.
                        $http(response.config).then(responseHandler, deferred.reject);
                        return false;
                        // Be aware that no request interceptors are called this way.
                    });
                    return false;
                }
                console.log('error not handled');
                return true; // error not handled
            });

            //Restangular.setErrorInterceptor(function (response, deferred, responseHandler) {
            //    if (response.status === 401 || response.message === 'token_expired') {
            //        refreshAccessToken().then(function () {
            //            response.config.headers.Authorization = authenticationService.getToken();
            //            // Repeat the request and then call the handlers the usual way.
            //            $http(response.config).then(responseHandler, deferred.reject)
            //                .then(function (httpResponse) {
            //                    deferred.resolve(httpResponse);
            //                });
            //
            //            // Be aware that no request interceptors are called this way.
            //        });
            //        return false; // error handled
            //    }
            //    return true; // error not handled
            //});

            Restangular.addFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) {
                //================================================
                // Token setup when load each request
                //================================================
                headers.Authorization = authenticationService.getToken();

                return {
                    element: element,
                    headers: headers,
                    params: params,
                    httpConfig: httpConfig
                };
            });
        })
        //================================================
        // UI router Config
        //================================================
        .config(function ($provide) {
            $provide.decorator('$state', function ($delegate, $rootScope) {
                $rootScope.$on('$stateChangeStart', function (event, state, params) {
                    $delegate.next = state;
                    $delegate.toParams = params;
                });
                return $delegate;
            });
        })
        //================================================
        // Local storage module init
        //================================================
        .config(function ($httpProvider, localStorageServiceProvider) {
            $httpProvider.defaults.useXDomain = true;
            delete $httpProvider.defaults.headers.common['X-Requested-With'];

            localStorageServiceProvider
                .setPrefix('emcoocms')
                .setStorageType('localStorage')
                .setNotify(true, true);
        })
        //================================================
        // Translate Config
        //================================================
        .config(function ($translateProvider) {
            $translateProvider.useStaticFilesLoader({
                prefix: 'app/languages/locale-',
                suffix: '.json'
            });

            $translateProvider.useCookieStorage();
            $translateProvider.useSanitizeValueStrategy('sanitize');
            $translateProvider.preferredLanguage('en-us');
            $translateProvider.fallbackLanguage(['en-us', 'zh-hk', 'zh-cn']);

        })
        //================================================
        // UI select Config
        //================================================
        .config(function (uiSelectConfig) {
            uiSelectConfig.theme = 'bootstrap';
            uiSelectConfig.resetSearchInput = true;
        })

        //================================================
        // Plugin: Smart-table init
        //================================================
        .config(function (stConfig) {
            stConfig.select.mode = 'multiple';
        })

        //================================================
        // Plugin: Restangular init
        //================================================
        .config(function (RestangularProvider) {
            RestangularProvider.setBaseUrl('http://cms.dev/api/admin');
            RestangularProvider.setRestangularFields({
                ids: "_ids"
            });

            RestangularProvider.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
                var extractedData;
                if (operation === 'getList') {
                    // handle the data and meta data
                    extractedData = data.result;
                    if (!_.isUndefined(data.meta)) {
                        extractedData.meta = data.meta;
                    }
                } else {
                    extractedData = data.result;
                }

                return extractedData;
            });

            RestangularProvider.setDefaultHttpFields({
                cache: true
            });

        })
        .config(function ($locationProvider, $stateProvider, $urlRouterProvider) {
            $locationProvider.html5Mode(true);
            $stateProvider
                .state('main', {
                    url: '/',
                    abstract: true,
                    templateUrl: 'app/main/main.html'
                })
                .state('fullscreen', {
                    url: '/',
                    abstract: true,
                    templateUrl: 'app/main/fullscreen.html'
                })
                .state('main.index', {
                    url: '',
                    templateUrl: 'app/main/dashboard.html',
                    resolve: {
                        meta: function ($rootScope, $translate, $q) {
                            var deferred = $q.defer();
                            $translate('panel.dashboard').then(function (translation) {
                                $rootScope.meta.pageTitle = translation;
                                deferred.resolve(true);
                            }, function () {
                                deferred.reject();
                            });
                            return deferred.promise;
                        }
                    }
                })
                .state('main.not-found', {
                    url: '404',
                    templateUrl: 'app/template/404.html',
                    resolve: {
                        meta: function ($rootScope, $translate, $q) {
                            var deferred = $q.defer();
                            $translate('panel.dashboard').then(function (translation) {
                                $rootScope.meta.pageTitle = translation;
                                deferred.resolve(true);
                            }, function () {
                                deferred.reject();
                            });
                            return deferred.promise;
                        }
                    }
                });

            $urlRouterProvider.otherwise('/');
        });

})();
<commit_msg>remove cache when changed page<commit_after>/*
 * This file is part of EMCOO TEAM PROJECT.
 *
 *  (c) EMCOO TEAM
 *  (c) DevMark <mark@emcoo.com>
 *
 *  For the full copyright and license information, please view http://emcoo.com/
 *
 *
 */

(function () {
    'use strict';

    angular.module('backend', [

        'authModule',
        'userModule',
        'postModule',
        'mediaModule',
        'mediaCategoryModule',
        'postCategoryModule',
        'settingModule',
        'languageModule',

        'theme.directives',
        'theme.services',
        'global.filter',
        'global.service',
        'global.directive',

        //UI Plugin
        'angular-spinkit',
        'smart-table',
        'ui.router',
        'ui.bootstrap',
        'ui.bootstrap.datetimepicker',
        'ui.tree',
        'ui.select',
        'checklist-model',
        'textAngular',
        'toaster', //notification plugin

        //Plugin
        'angular.filter',
        'pascalprecht.translate', //Multi Language plugin
        'angularMoment', //moment plugin, date plugin
        'restangular',
        'LocalStorageModule', // local storage module
        'tmh.dynamicLocale',

        'ngAnimate',
        'ngCookies',
        'ngTouch',
        'ngRoute',
        'ngSanitize'

    ])
        //================================================
        // Check isLogin when run system
        //================================================
        .run(function ($rootScope, $location, authenticationService, localStorageService, amMoment, tmhDynamicLocale, settingService, $translate, $timeout, $cacheFactory) {
            var routesThatRequireAuth = ['/auth/login', '/auth/logout'];

            //================================================
            // page route event
            //================================================
            $rootScope.pageViewLoading = false;

            $rootScope.$on('$stateChangeStart', function (event, next, current) {
                if (!_(routesThatRequireAuth).contains($location.path()) && !authenticationService.check()) {
                    console.log('Oops! please login!');
                    $location.path('auth/login');
                }
                $rootScope.pageViewLoading = true;
            });
            $rootScope.$on('$stateChangeSuccess', function () {
                $timeout(function () {
                    $rootScope.pageViewLoading = false;
                }, 500);
                $cacheFactory.get('$http').removeAll();
            });

            //================================================
            // page title init
            //================================================
            $translate('panel.name').then(function (translation) {
                $rootScope.siteTitle = translation;
            });
            $rootScope.meta = {
                pageTitle: ''
            };

            //================================================
            // global variable init
            //================================================
            $rootScope.$location = $location;

            //================================================
            // timezone init
            //================================================
            amMoment.changeTimezone(settingService.find('timezone'));

        })
        .run(function ($location, authenticationService, localStorageService, $timeout, Restangular, $http, $q, $state) {

            var refreshAccessToken = function () {
                var deferred = $q.defer();
                console.log('start get refresh token');

                $http({
                    method: 'POST', url: 'http://cms.dev/api/admin/auth/refresh-token', headers: {
                        'Authorization': authenticationService.getToken()
                    }
                }).success(function (data, status, headers, config) {
                    console.log('set token');
                    localStorageService.set('token', data.result.token);
                    deferred.resolve(data.result.token);
                }).error(function (data, status, headers, config) {
                    console.log('Oops! Expired Token, please login again! ');
                    $location.path('auth/login');
                    deferred.reject(data);
                });

                return deferred.promise;
            };

            Restangular.setErrorInterceptor(function (response, deferred, responseHandler) {
                if (response.data.message === 'token_invalid') {
                    localStorageService.remove('token');
                    $state.go('fullscreen.login');
                    return false;
                }

                if (response.data.message === 'token_expired') {
                    return refreshAccessToken().then(function () {
                        response.config.headers.Authorization = authenticationService.getToken();
                        // Repeat the request and then call the handlers the usual way.
                        $http(response.config).then(responseHandler, deferred.reject);
                        return false;
                        // Be aware that no request interceptors are called this way.
                    });
                    return false;
                }
                console.log('error not handled');
                return true; // error not handled
            });

            //Restangular.setErrorInterceptor(function (response, deferred, responseHandler) {
            //    if (response.status === 401 || response.message === 'token_expired') {
            //        refreshAccessToken().then(function () {
            //            response.config.headers.Authorization = authenticationService.getToken();
            //            // Repeat the request and then call the handlers the usual way.
            //            $http(response.config).then(responseHandler, deferred.reject)
            //                .then(function (httpResponse) {
            //                    deferred.resolve(httpResponse);
            //                });
            //
            //            // Be aware that no request interceptors are called this way.
            //        });
            //        return false; // error handled
            //    }
            //    return true; // error not handled
            //});

            Restangular.addFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) {
                //================================================
                // Token setup when load each request
                //================================================
                headers.Authorization = authenticationService.getToken();

                return {
                    element: element,
                    headers: headers,
                    params: params,
                    httpConfig: httpConfig
                };
            });
        })
        //================================================
        // UI router Config
        //================================================
        .config(function($provide) {
            $provide.decorator('$state', function($delegate, $rootScope) {
                $rootScope.$on('$stateChangeStart', function(event, state, params) {
                    $delegate.next = state;
                    $delegate.toParams = params;
                });
                return $delegate;
            });
        })
        //================================================
        // Local storage module init
        //================================================
        .config(function ($httpProvider, localStorageServiceProvider) {
            $httpProvider.defaults.useXDomain = true;
            delete $httpProvider.defaults.headers.common['X-Requested-With'];

            localStorageServiceProvider
                .setPrefix('emcoocms')
                .setStorageType('localStorage')
                .setNotify(true, true);
        })
        //================================================
        // Translate Config
        //================================================
        .config(function ($translateProvider) {
            $translateProvider.useStaticFilesLoader({
                prefix: 'app/languages/locale-',
                suffix: '.json'
            });

            $translateProvider.useCookieStorage();
            $translateProvider.useSanitizeValueStrategy('sanitize');
            $translateProvider.preferredLanguage('en-us');
            $translateProvider.fallbackLanguage(['en-us', 'zh-hk', 'zh-cn']);

        })
        //================================================
        // UI select Config
        //================================================
        .config(function (uiSelectConfig) {
            uiSelectConfig.theme = 'bootstrap';
            uiSelectConfig.resetSearchInput = true;
        })

        //================================================
        // Plugin: Smart-table init
        //================================================
        .config(function (stConfig) {
            stConfig.select.mode = 'multiple';
        })

        //================================================
        // Plugin: Restangular init
        //================================================
        .config(function (RestangularProvider) {
            RestangularProvider.setBaseUrl('http://cms.dev/api/admin');
            RestangularProvider.setRestangularFields({
                ids: "_ids"
            });

            RestangularProvider.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
                var extractedData;
                if (operation === 'getList') {
                    // handle the data and meta data
                    extractedData = data.result;
                    if (!_.isUndefined(data.meta)) {
                        extractedData.meta = data.meta;
                    }
                } else {
                    extractedData = data.result;
                }

                return extractedData;
            });

            RestangularProvider.setDefaultHttpFields({
                cache: true
            });

        })
        .config(function ($locationProvider, $stateProvider, $urlRouterProvider) {
            $locationProvider.html5Mode(true);
            $stateProvider
                .state('main', {
                    url: '/',
                    abstract: true,
                    templateUrl: 'app/main/main.html'
                })
                .state('fullscreen', {
                    url: '/',
                    abstract: true,
                    templateUrl: 'app/main/fullscreen.html'
                })
                .state('main.index', {
                    url: '',
                    templateUrl: 'app/main/dashboard.html',
                    resolve: {
                        meta: function ($rootScope, $translate, $q) {
                            var deferred = $q.defer();
                            $translate('panel.dashboard').then(function (translation) {
                                $rootScope.meta.pageTitle = translation;
                                deferred.resolve(true);
                            }, function () {
                                deferred.reject();
                            });
                            return deferred.promise;
                        }
                    }
                })
                .state('main.not-found', {
                    url: '404',
                    templateUrl: 'app/template/404.html',
                    resolve: {
                        meta: function ($rootScope, $translate, $q) {
                            var deferred = $q.defer();
                            $translate('panel.dashboard').then(function (translation) {
                                $rootScope.meta.pageTitle = translation;
                                deferred.resolve(true);
                            }, function () {
                                deferred.reject();
                            });
                            return deferred.promise;
                        }
                    }
                });

            $urlRouterProvider.otherwise('/');
        });

})();
<|endoftext|>