<commit_before>const esprima = require('esprima');
const escodegen = require('escodegen');
const fs = require("fs");
const path = require("path");

const MACRO = /%inline\s*\(\s*["'](.*?)['"]\s*\)\s*\.\s*(\w+)\s*\((\s*\))?/g;

/**
 * This function walks the given module AST and tries to locate all the
 * functions it exports.
 *
 * @param {Object} ast - The AST as parsed by esprima
 * @returns {Object} Returns a key/value object with the names and the AST of all exported functions
 */
function getExportedFunctions(ast) {
  var functions =  ast.body.reduce(function(scopeFunctions, node) {

    //
    // Look for ES6 `export` functions
    //
    // export function name(a,b,c) {
    //   ...
    // }
    //
    if (node.type === 'ExportNamedDeclaration') {
      if (node.declaration.type === 'FunctionDeclaration') {
        scopeFunctions[node.declaration.id.name] = {
          exported: true,
          ast: node.declaration
        };
      }
      return scopeFunctions;
    }

    //
    // Look for regular function declarations
    //
    // function name(a,b,c) {
    //   ...
    // }
    //
    if (node.type === 'FunctionDeclaration') {
      scopeFunctions[node.id.name] = {
        exported: false,
        ast: node
      };
      return scopeFunctions;
    }

    //
    // Look for variable-defined function declarations
    //
    // var name = function(a,b,c) {
    //   ...
    // }
    //
    if (node.type === 'VariableDeclaration') {
      node.declarations.forEach(function(node) {
        if (node.init.type === 'FunctionExpression') {
          scopeFunctions[node.id.name] = {
            exported: false,
            ast: node.init
          };
        }
      });
      return scopeFunctions;
    }

    //
    // Look for default-class export with static functions
    //
    // export default class {
    //    static name(a,b,c) {
    //       ...
    //    }
    // }
    //
    if ((node.type === 'ExportDefaultDeclaration') &&
        (node.declaration.type === 'ClassDeclaration')) {

      node.declaration.body.body.forEach(function(node) {
        if ((node.type === 'MethodDefinition') && node.static) {
          scopeFunctions[node.key.name] = {
            exported: true,
            ast: node.value
          };
        }
      });

      return scopeFunctions;
    }

    //
    // Look for CommonJs exports
    //
    // module.exports = {
    //    name: function(a,b,c) {
    //      ...
    //    },
    //    name(a,b,c) {
    //      ...
    //    },
    //    reference_to_other_function
    // }
    //
    if ((node.type === 'ExpressionStatement') &&
        (node.expression.left.type === 'MemberExpression') &&
        (node.expression.left.object.name === 'module') &&
        (node.expression.left.property.name === 'exports') &&
        (node.expression.right.type === 'ObjectExpression')) {

      node.expression.right.properties.forEach(function(node) {
        var name = node.key.name;
        var value = node.value;

        // Mark reference to declared functions as exported
        if ((value.type === 'Identifier') && (scopeFunctions[value.name] !== undefined)) {
          if (name === value.name) {
            scopeFunctions[name].exported = true;
          } else {
            scopeFunctions[name] = {
              exported: true,
              ast: scopeFunctions[value.name].ast
            }
          }
          return;
        }

        // Keep reference to in-place defined functions
        if (value.type === 'FunctionExpression') {
          scopeFunctions[name] = {
            exported: true,
            ast: value
          };
        }

      });

      return scopeFunctions;
    }

    return scopeFunctions;
  }, {});

  // Keep only the AST of known functions
  return Object.keys(functions).reduce(function(exportedFunc, name) {
    var fn = functions[name];
    if (fn.exported) {
      exportedFunc[name] = fn.ast;
    }
    return exportedFunc;
  }, {});
}

/**
 * Render the body of the function as a program
 *
 * @param {Object} ast - The function AST
 * @returns {String} Returns the rendered function body
 */
function renderFunction(ast) {

  // Empty functions have empty contents
  if (ast.body.body.length === 0) {
    return '';
  }

  // Functions that have only a return statement, skip the 'return' and
  // render only it's value
  if (ast.body.body[0].type === 'ReturnStatement') {
    return escodegen.generate(ast.body.body[0].argument);
  }

  // Otherwise render the function body as a program fragment
  return escodegen.generate({
    type: 'Program',
    body: ast.body.body,
    sourceType: 'script'
  });

}

/**
 * Replace any identifier AST node found in the tree with a replacement node
 * given in the `withAst` argument.
 *
 * This function also checks if the identifier is shadowed at some particular
 * path of the AST and if yes, it does not replace it.
 *
 * @param {String} name - The name of the identifier
 * @param {Object} withAst - The AST node to replace with
 * @param {Object} inAst - The AST tree to search within
 * @returns {Object} Returns the modified AST.
 */
function replaceIdentifier(name, withAst, inAst) {
  if ((inAst.type === 'Identifier') && (inAst.name === name)) {
    return withAst;
  }

  // If we have a VariableDeclaration that shadows the given identifier
  // in the current body scope, pass the current contents as-is
  if (Array.isArray(inAst.body)) {
    var isShadowed = false;
    inAst.body.forEach(function(node) {

      //
      // Variable declarations can shadow this identifier
      //
      // var name = ...
      //
      if (node.type === 'VariableDeclaration') {
        node.declarations.forEach(function(node) {
          if (node.id.name === name) {
            isShadowed = true;
          }
        });
      }

      //
      // For statements can also shadow this identifier
      //
      // for (var name = ... ; ; ) {
      //
      if (node.type === 'ForStatement') {
        if (node.init && (node.init.type === 'VariableDeclaration')) {
          node.init.declarations.forEach(function(node) {
            if (node.id.name === name) {
              isShadowed = true;
            }
          });
        }
      }

    });

    // If we are shadowed we cannot do more
    if (isShadowed) {
      return inAst;
    }
  }

  // Recursively replace identifiers in the tree
  return Object.keys(inAst).reduce(function(newAst, key) {
    var value = inAst[key];

    if (Array.isArray(value)) {
      newAst[key] = value.map(replaceIdentifier.bind({}, name, withAst));
    } else if ((typeof value === 'object') && (value !== null)) {
      newAst[key] = replaceIdentifier(name, withAst, value);
    } else {
      newAst[key] = value;
    }

    return newAst;
  }, {});
}

/**
 * Compile the ASTs for the specified arguments expression
 *
 * @param {String} expression - The javascript expression for which to compile an AST
 * @returns {Arrays} Returns the array of the arguments as ASTs
 */
function compileArgumentAst(argsExpression) {
  return esprima.parse('X('+argsExpression+')')
    .body[0].expression.arguments;
}

/**
 * Load module contents, trying the various different extensions defined in the
 *
 * @param {String} modulePath - The path to the module
 * @param {Object} options - The webpack options from wihch to extract extensions
 * @returns {String} Returns the file contents
 */
function loadModuleContents(modulePath, options) {
  var extensions = options && options.resolve && options.resolve.extensions || [ '', '.js' ];
  return extensions.reduce(function(payload, ext) {

    // Pass-down payload if found
    if (payload !== null) {
      return payload;
    }

    // Load contents or null on loading error
    try {
      return fs.readFileSync(modulePath + ext);
    } catch(e) {
      return null;
    }

  }, null);
}

/**
 * Return the inline contents of the given function from the given module with
 * the given argument string.
 *
 * @this {loaderAPI} The function should be bound to the webpack loader API
 * @param {String} gModule - The module that contains the actions
 * @param {String} gFunction - The module function to inline
 * @param {String} gArgs - The arguments passed to the inline function
 * @returns {String} Returns the generated code for this inline function
 */
function getFunctionCode(gModule, gFunction, fnArgs) {
  // Resolve filename
  var filePath = path.resolve(this.context, gModule);
  var contents = loadModuleContents(filePath, this.options);
  if (!contents) {
    this.emitError('Could not find module `' + gModule + '`');
    return '/* Missing module ' + gModule + ' */';
  }

  // Load file and extract AST
  var ast;
  try {
    ast = esprima.parse(contents, { sourceType: 'module' })
  } catch (e) {
    this.emitError('%inline("' + gModule + '"): ' + e.toString());
    return '/* Parsing error in module ' + gModule + ' */';
  }
  this.addDependency(filePath);

  // Locate the correct function AST
  var exportedFn = getExportedFunctions(ast);
  var fnAst = exportedFn[gFunction];
  if (!fnAst) {
    this.emitError('%inline("' + gModule + '"): Undefined function `' + gFunction);
    return '/* Unknown inline ' + gFunction + ' */';
  }

  // Replace arguments in the function ast
  for (var i=0; i<fnArgs.length; ++i) {
    fnAst = replaceIdentifier( fnAst.params[i].name, fnArgs[i], fnAst );
  }

  // Render contents
  return renderFunction(fnAst);
}

/**
 * This function walks the AST and returns the node that calls the magic
 * inline function `___js_inline_loader_inline`.
 *
 * @param {Object} ast - The AST to walk
 * @returns {Object} Returns the AST node of the magic function
 */
function findInlineToken(ast) {
  if ((ast.type === 'CallExpression') && (ast.callee.name === '___js_inline_loader_inline')) {
    return ast;
  }

  // Walk object properties
  var keys = Object.keys(ast);
  for (var i=0, l=keys.length; i<l; ++i) {
    var key = keys[i];
    var value = ast[key];

    // Process each item of an array
    if (Array.isArray(value)) {
      for (var j=0, jl=value.length; j<jl; ++j) {
        if (typeof value[j] === 'object') {
          var ans = findInlineToken(value[j]);
          if (ans) return ans;
        }
      }

    // And forward the checks of the objects
    } else if ((typeof value === 'object') && (value !== null)) {
      var ans = findInlineToken(value);
      if (ans) return ans;

    }
  }

  // Nothing found
  return null;
}

/**
 * Correct replacement of an `%inline` macro, using AST processing
 *
 * @param {String} source - The source code to proess
 * @param {Function} callback - The callback to use to get replacements
 * @returns {String} Returns the new source
 */
function replaceInlineFunc(source, callback) {
  while (true) {
    var ast;

    // Parse the current source into the AST
    try {
      ast = esprima.parse(source, {sourceType: 'module', range: true});
    } catch (e) {
      this.emitError('Inline processing failed: SyntaxError: ' + e.toString());
      return source;
    }

    // Find an inline token
    var token = findInlineToken(ast);
    if (!token) {
      return source;
    }

    // Found a token? Callback with details
    var replacement = callback(
      token.arguments[0].value,
      token.arguments[1].name,
      token.arguments.slice(2)
    );

    // Replace that part of the source with the generated code
    source = source.substring(0, token.range[0]) + replacement +
             source.substring(token.range[1]);
  }
}

/**
 * Export the webpack replace function
 */
module.exports = function(source) {
  this.cacheable();

  // Convert the convenient `%macro` to a proper JS expression
  var hasMacros = false;
  var normSource = source.replace(MACRO, function(m, gModule, gFunction, gEmpty) {
    hasMacros = true;
    return '___js_inline_loader_inline(\'' + gModule + '\',' + gFunction + (gEmpty ? ')' : ',');
  });

  // If we don't have macros, don't bother
  if (!hasMacros) {
    return source;
  }

  // Replace all inline functions using the AST
  return replaceInlineFunc.call(this, normSource, getFunctionCode.bind(this));
};
<commit_msg>Updating inline docmentation<commit_after>const esprima = require('esprima');
const escodegen = require('escodegen');
const fs = require("fs");
const path = require("path");

const MACRO = /%inline\s*\(\s*["'](.*?)['"]\s*\)\s*\.\s*(\w+)\s*\((\s*\))?/g;

/**
 * This function walks the given module AST and tries to locate all the
 * functions it exports.
 *
 * @param {Object} ast - The AST as parsed by esprima
 * @returns {Object} Returns a key/value object with the names and the AST of all exported functions
 */
function getExportedFunctions(ast) {
  var functions =  ast.body.reduce(function(scopeFunctions, node) {

    //
    // Look for ES6 `export` functions
    //
    // export function name(a,b,c) {
    //   ...
    // }
    //
    if (node.type === 'ExportNamedDeclaration') {
      if (node.declaration.type === 'FunctionDeclaration') {
        scopeFunctions[node.declaration.id.name] = {
          exported: true,
          ast: node.declaration
        };
      }
      return scopeFunctions;
    }

    //
    // Look for regular function declarations
    //
    // function name(a,b,c) {
    //   ...
    // }
    //
    if (node.type === 'FunctionDeclaration') {
      scopeFunctions[node.id.name] = {
        exported: false,
        ast: node
      };
      return scopeFunctions;
    }

    //
    // Look for variable-defined function declarations
    //
    // var name = function(a,b,c) {
    //   ...
    // }
    //
    if (node.type === 'VariableDeclaration') {
      node.declarations.forEach(function(node) {
        if (node.init.type === 'FunctionExpression') {
          scopeFunctions[node.id.name] = {
            exported: false,
            ast: node.init
          };
        }
      });
      return scopeFunctions;
    }

    //
    // Look for default-class export with static functions
    //
    // export default class {
    //    static name(a,b,c) {
    //       ...
    //    }
    // }
    //
    if ((node.type === 'ExportDefaultDeclaration') &&
        (node.declaration.type === 'ClassDeclaration')) {

      node.declaration.body.body.forEach(function(node) {
        if ((node.type === 'MethodDefinition') && node.static) {
          scopeFunctions[node.key.name] = {
            exported: true,
            ast: node.value
          };
        }
      });

      return scopeFunctions;
    }

    //
    // Look for CommonJs exports
    //
    // module.exports = {
    //    name: function(a,b,c) {
    //      ...
    //    },
    //    name(a,b,c) {
    //      ...
    //    },
    //    reference_to_other_function
    // }
    //
    if ((node.type === 'ExpressionStatement') &&
        (node.expression.left.type === 'MemberExpression') &&
        (node.expression.left.object.name === 'module') &&
        (node.expression.left.property.name === 'exports') &&
        (node.expression.right.type === 'ObjectExpression')) {

      node.expression.right.properties.forEach(function(node) {
        var name = node.key.name;
        var value = node.value;

        // Mark reference to declared functions as exported
        if ((value.type === 'Identifier') && (scopeFunctions[value.name] !== undefined)) {
          if (name === value.name) {
            scopeFunctions[name].exported = true;
          } else {
            scopeFunctions[name] = {
              exported: true,
              ast: scopeFunctions[value.name].ast
            }
          }
          return;
        }

        // Keep reference to in-place defined functions
        if (value.type === 'FunctionExpression') {
          scopeFunctions[name] = {
            exported: true,
            ast: value
          };
        }

      });

      return scopeFunctions;
    }

    return scopeFunctions;
  }, {});

  // Keep only the AST of known functions
  return Object.keys(functions).reduce(function(exportedFunc, name) {
    var fn = functions[name];
    if (fn.exported) {
      exportedFunc[name] = fn.ast;
    }
    return exportedFunc;
  }, {});
}

/**
 * Render the body of the function as a program
 *
 * @param {Object} ast - The function AST
 * @returns {String} Returns the rendered function body
 */
function renderFunction(ast) {

  // Empty functions have empty contents
  if (ast.body.body.length === 0) {
    return '';
  }

  // Functions that have only a return statement, skip the 'return' and
  // render only it's value
  if (ast.body.body[0].type === 'ReturnStatement') {
    return escodegen.generate(ast.body.body[0].argument);
  }

  // Otherwise render the function body as a program fragment
  return escodegen.generate({
    type: 'Program',
    body: ast.body.body,
    sourceType: 'script'
  });

}

/**
 * Replace any identifier AST node found in the tree with a replacement node
 * given in the `withAst` argument.
 *
 * This function also checks if the identifier is shadowed at some particular
 * path of the AST and if yes, it does not replace it.
 *
 * @param {String} name - The name of the identifier
 * @param {Object} withAst - The AST node to replace with
 * @param {Object} inAst - The AST tree to search within
 * @returns {Object} Returns the modified AST.
 */
function replaceIdentifier(name, withAst, inAst) {
  if ((inAst.type === 'Identifier') && (inAst.name === name)) {
    return withAst;
  }

  // If we have a VariableDeclaration that shadows the given identifier
  // in the current body scope, pass the current contents as-is
  if (Array.isArray(inAst.body)) {
    var isShadowed = false;
    inAst.body.forEach(function(node) {

      //
      // Variable declarations can shadow this identifier
      //
      // var name = ...
      //
      if (node.type === 'VariableDeclaration') {
        node.declarations.forEach(function(node) {
          if (node.id.name === name) {
            isShadowed = true;
          }
        });
      }

      //
      // For statements can also shadow this identifier
      //
      // for (var name = ... ; ; ) {
      //
      if (node.type === 'ForStatement') {
        if (node.init && (node.init.type === 'VariableDeclaration')) {
          node.init.declarations.forEach(function(node) {
            if (node.id.name === name) {
              isShadowed = true;
            }
          });
        }
      }

    });

    // If we are shadowed we cannot do more
    if (isShadowed) {
      return inAst;
    }
  }

  // Recursively replace identifiers in the tree
  return Object.keys(inAst).reduce(function(newAst, key) {
    var value = inAst[key];

    if (Array.isArray(value)) {
      newAst[key] = value.map(replaceIdentifier.bind({}, name, withAst));
    } else if ((typeof value === 'object') && (value !== null)) {
      newAst[key] = replaceIdentifier(name, withAst, value);
    } else {
      newAst[key] = value;
    }

    return newAst;
  }, {});
}

/**
 * Compile the ASTs for the specified arguments expression
 *
 * @param {String} expression - The javascript expression for which to compile an AST
 * @returns {Arrays} Returns the array of the arguments as ASTs
 */
function compileArgumentAst(argsExpression) {
  return esprima.parse('X('+argsExpression+')')
    .body[0].expression.arguments;
}

/**
 * Load module contents, trying the various different extensions defined in the
 *
 * @param {String} modulePath - The path to the module
 * @param {Object} options - The webpack options from wihch to extract extensions
 * @returns {String} Returns the file contents
 */
function loadModuleContents(modulePath, options) {
  var extensions = options && options.resolve && options.resolve.extensions || [ '', '.js' ];
  return extensions.reduce(function(payload, ext) {

    // Pass-down payload if found
    if (payload !== null) {
      return payload;
    }

    // Load contents or null on loading error
    try {
      return fs.readFileSync(modulePath + ext);
    } catch(e) {
      return null;
    }

  }, null);
}

/**
 * Return the inline contents of the given function from the given module with
 * the given argument string.
 *
 * @this {loaderAPI} The function should be bound to the webpack loader API
 * @param {String} gModule - The module that contains the actions
 * @param {String} gFunction - The module function to inline
 * @param {String} gArgs - The arguments passed to the inline function
 * @returns {String} Returns the generated code for this inline function
 */
function getFunctionCode(gModule, gFunction, fnArgs) {
  // Resolve filename
  var filePath = path.resolve(this.context, gModule);
  var contents = loadModuleContents(filePath, this.options);
  if (!contents) {
    this.emitError('Could not find module `' + gModule + '`');
    return '/* Missing module ' + gModule + ' */';
  }

  // Load file and extract AST
  var ast;
  try {
    ast = esprima.parse(contents, { sourceType: 'module' })
  } catch (e) {
    this.emitError('%inline("' + gModule + '"): ' + e.toString());
    return '/* Parsing error in module ' + gModule + ' */';
  }
  this.addDependency(filePath);

  // Locate the correct function AST
  var exportedFn = getExportedFunctions(ast);
  var fnAst = exportedFn[gFunction];
  if (!fnAst) {
    this.emitError('%inline("' + gModule + '"): Undefined function `' + gFunction);
    return '/* Unknown inline ' + gFunction + ' */';
  }

  // Replace arguments in the function ast
  for (var i=0; i<fnArgs.length; ++i) {
    fnAst = replaceIdentifier( fnAst.params[i].name, fnArgs[i], fnAst );
  }

  // Render contents
  return renderFunction(fnAst);
}

/**
 * This function walks the AST and returns the node that calls the magic
 * inline function `___js_inline_loader_inline`.
 *
 * @param {Object} ast - The AST to walk
 * @returns {Object} Returns the AST node of the magic function
 */
function findInlineToken(ast) {
  if ((ast.type === 'CallExpression') && (ast.callee.name === '___js_inline_loader_inline')) {
    return ast;
  }

  // Walk object properties
  var keys = Object.keys(ast);
  for (var i=0, l=keys.length; i<l; ++i) {
    var key = keys[i];
    var value = ast[key];

    // Process each item of an array
    if (Array.isArray(value)) {
      for (var j=0, jl=value.length; j<jl; ++j) {
        if (typeof value[j] === 'object') {
          var ans = findInlineToken(value[j]);
          if (ans) return ans;
        }
      }

    // And forward the checks of the objects
    } else if ((typeof value === 'object') && (value !== null)) {
      var ans = findInlineToken(value);
      if (ans) return ans;

    }
  }

  // Nothing found
  return null;
}

/**
 * Correct replacement of an `%inline` macro, using AST processing
 *
 * This function is rather slow, since we are parsing the entire AST every time
 * we replace something in the source. This way, the resulting source code
 * maintains it's comments and any other information that the esprima parser
 * did not understand.
 *
 * However a much faster alternative would be to parse the AST only once and
 * then replace the ast nodes of the inline functions with the AST nodes
 * from the imported modules.
 *
 * @param {String} source - The source code to proess
 * @param {Function} callback - The callback to use to get replacements
 * @returns {String} Returns the new source
 */
function replaceInlineFunc(source, callback) {
  while (true) {
    var ast;

    // Parse the current source into the AST
    try {
      ast = esprima.parse(source, {sourceType: 'module', range: true});
    } catch (e) {
      this.emitError('Inline processing failed: SyntaxError: ' + e.toString());
      return source;
    }

    // Find an the next inline token to replace
    var token = findInlineToken(ast);
    if (!token) {
      return source;
    }

    // Callback with details and get the replacement
    var replacement = callback(
      token.arguments[0].value, // Module
      token.arguments[1].name,  // Function
      token.arguments.slice(2)  // Arguments as AST nodes
    );

    // Replace that part of the source with the generated one
    source = source.substring(0, token.range[0]) + replacement +
             source.substring(token.range[1]);

  }
}

/**
 * Export the webpack replace function
 */
module.exports = function(source) {
  this.cacheable();

  // Convert the convenient `%inline` macro to a proper JS expression
  var hasMacros = false;
  var normSource = source.replace(MACRO, function(m, gModule, gFunction, gEmpty) {
    hasMacros = true;
    return '___js_inline_loader_inline(\'' + gModule + '\',' + gFunction + (gEmpty ? ')' : ',');
  });

  // If we don't have any macros, don't spend more cycles on processing the code
  if (!hasMacros) {
    return source;
  }

  // Replace all inline functions using the AST
  return replaceInlineFunc.call(this, normSource, getFunctionCode.bind(this));
};
<|endoftext|>


<commit_before>var fs = require('fs');
var resolve = require('path').resolve;
var join = require('path').join;
var cp = require('child_process');

// get library path
var lib = resolve(__dirname);

fs.readdirSync(lib).forEach(function(mod) {
  var modPath = join(lib, mod);
  // ensure path has package.json
  if (!fs.existsSync(join(modPath, 'package.json'))) return;

  // Determine OS and set command accordingly
  const cmd = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';

  // install folder
  cp.spawn(cmd, ['install'], { env: process.env, cwd: modPath, stdio: 'inherit' });
});
<commit_msg>Change install to ci to avoid messing with package-lock.json (#3758)<commit_after>var fs = require('fs');
var resolve = require('path').resolve;
var join = require('path').join;
var cp = require('child_process');

// get library path
var lib = resolve(__dirname);

fs.readdirSync(lib).forEach(function(mod) {
  var modPath = join(lib, mod);
  // ensure path has package.json
  if (!fs.existsSync(join(modPath, 'package.json'))) return;

  // Determine OS and set command accordingly
  const cmd = /^win/.test(process.platform) ? 'npm.cmd' : 'npm';

  // install folder
  cp.spawn(cmd, ['ci'], { env: process.env, cwd: modPath, stdio: 'inherit' });
});
<|endoftext|>


<commit_before>// http://dojotoolkit.org/reference-guide/1.9/quickstart/writingWidgets.html

define([
    "dojo/Evented",
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dijit/_WidgetBase",
    "dijit/a11yclick",
    "dijit/_TemplatedMixin",
    "dojo/on",

    // load template
    "dojo/text!./templates/FullScreenMap.html",

    "dojo/dom",
    "dojo/dom-style",
    "dojo/dom-class",
    "dojo/dom-attr",

    "esri/map",

    "dojo/domReady!"
],
function (
    Evented,
    declare, lang,
    _WidgetBase, a11yclick, _TemplatedMixin,
    on,
    dijitTemplate,
    dom, domStyle, domClass, domAttr,
    Map
) {
    return declare([_WidgetBase, _TemplatedMixin, Evented], {

        declaredClass: "modules.FullScreenMap",

        templateString: dijitTemplate,

        options: {
            map: null
        },

        // lifecycle: 1
        constructor: function (options, srcRefNode) {

            // mix in settings and defaults
            var defaults = lang.mixin({}, this.options, options);

            // widget node
            this.domNode = srcRefNode;

            // set map property
            this.set("map", defaults.map);

        },

        // _TemplatedMixin implements buildRendering() for you. Use this to override
        // buildRendering: function() {},

        // called after buildRendering() is finished
        postCreate: function() {
            this.own(on(this.buttonNode, a11yclick, lang.hitch(this, this._toggleFullscreen)));
        },

        // start widget. called by user
        startup: function () {
            // map not defined
            if (!this.get("map")) {
                console.log('map required');
                this.destroy();
                return;
            }

            // map domNode
            this._mapNode = dom.byId(this.map.id);

            // when map is loaded
            if (this.map.loaded) {
                this._init();
            } else {
                on.once(this.map, "load", lang.hitch(this, function () {
                    this._init();
                }));
            }
        },

        // connections/subscriptions will be cleaned up during the destroy() lifecycle phase
        destroy: function () {
            this.inherited(arguments);
        },

        /* ---------------- */
        /* Public Functions */
        /* ---------------- */

        toggle: function () {
            this._toggleFullscreen();
        },

        refresh: function () {
            var w, h;
            var center = this.map.extent.getCenter();

            // determine fullscreen state
            var state;
            if (this._mapNode.requestFullscreen) {
                state = document.fullScreen;
            } else if (this._mapNode.mozRequestFullScreen) {
                state = document.mozFullScreen;
            } else if (this._mapNode.webkitRequestFullScreen) {
                state = document.webkitIsFullScreen;
            }

            // set fullscreen status
            this.set("fullscreen", state);

            if (this.get("fullscreen")) {
                w = "100%";
                h = "100%";
                domClass.add(this.buttonNode, "exit");
                domClass.remove(this.buttonNode, "enter");
                domAttr.set(this.buttonNode, "title", "Exit Fullscreen");
            } else {
                w = '';
                h = '';
                domClass.add(this.buttonNode, "enter");
                domClass.remove(this.buttonNode, "exit");
                domAttr.set(this.buttonNode, "title", "Enter Fullscreen");
            }

            domStyle.set(this._mapNode, {
                width: w,
                height: h
            });

            this.map.resize();

            // re-center map
            setTimeout(lang.hitch(this, function () {
                this.map.centerAt(center);
            }), 500);

        },

        /* ---------------- */
        /* Private Functions */
        /* ---------------- */
        _init: function () {

            // enter/exit fullscreen event
            if (this._mapNode.requestFullscreen) {
                on(document, "fullscreenchange", lang.hitch(this, function () {
                    this.refresh();
                }));
            } else if (this._mapNode.mozRequestFullScreen) {
                on(document, "mozfullscreenchange", lang.hitch(this, function () {
                    this.refresh();
                }));
            } else if (this._mapNode.webkitRequestFullScreen) {
                on(document, "webkitfullscreenchange", lang.hitch(this, function () {
                    this.refresh();
                }));
            }

            this.set("loaded", true);

            // emit event
            this.emit("load", {});

        },

        _toggleFullscreen: function () {
            if (this.get("fullscreen")) {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                } else if (document.webkitCancelFullScreen) {
                    document.webkitCancelFullScreen();
                }
            } else {
                if (this._mapNode.requestFullscreen) {
                    this._mapNode.requestFullscreen();
                } else if (this._mapNode.mozRequestFullScreen) {
                    this._mapNode.mozRequestFullScreen();
                } else if (this._mapNode.webkitRequestFullScreen) {
                    this._mapNode.webkitRequestFullScreen();
                }
            }
        }

    });
});<commit_msg>better sample<commit_after>// http://dojotoolkit.org/reference-guide/1.9/quickstart/writingWidgets.html

define([
    "dojo/Evented",
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dijit/_WidgetBase",
    "dijit/a11yclick",
    "dijit/_TemplatedMixin",
    "dojo/on",

    // load template
    "dojo/text!./templates/FullScreenMap.html",

    "dojo/dom",
    "dojo/dom-style",
    "dojo/dom-class",
    "dojo/dom-attr",

    "esri/map",

    "dojo/domReady!"
],
function (
    Evented,
    declare, lang,
    _WidgetBase, a11yclick, _TemplatedMixin,
    on,
    dijitTemplate,
    dom, domStyle, domClass, domAttr,
    Map
) {
    return declare([_WidgetBase, _TemplatedMixin, Evented], {

        declaredClass: "modules.FullScreenMap",

        templateString: dijitTemplate,

        options: {
            map: null,
            visible: true
        },

        // lifecycle: 1
        constructor: function (options, srcRefNode) {

            // mix in settings and defaults
            var defaults = lang.mixin({}, this.options, options);

            // widget node
            this.domNode = srcRefNode;

            // set map property
            this.set("map", defaults.map);
            this.set("visible", defaults.visible);

            // watch for changes
            this.watch("visible", this._visible);

        },

        // _TemplatedMixin implements buildRendering() for you. Use this to override
        // buildRendering: function() {},

        // called after buildRendering() is finished
        postCreate: function() {
            this.own(on(this.buttonNode, a11yclick, lang.hitch(this, this._toggleFullscreen)));
        },

        // start widget. called by user
        startup: function () {

            this._visible();

            // map not defined
            if (!this.get("map")) {
                console.log('map required');
                this.destroy();
                return;
            }

            // map domNode
            this._mapNode = this.map.container;

            // when map is loaded
            if (this.map.loaded) {
                this._init();
            } else {
                on.once(this.map, "load", lang.hitch(this, function () {
                    this._init();
                }));
            }
        },

        // connections/subscriptions will be cleaned up during the destroy() lifecycle phase
        destroy: function () {
            this.inherited(arguments);
        },

        show: function(){
            this.set("visible", true);
        },
        hide: function(){
            this.set("visible", false);
        },

        /* ---------------- */
        /* Public Functions */
        /* ---------------- */

        toggle: function () {
            this._toggleFullscreen();
        },

        refresh: function () {
            var w, h;
            var center = this.map.extent.getCenter();

            // determine fullscreen state
            var state;
            if (this._mapNode.requestFullscreen) {
                state = document.fullScreen;
            } else if (this._mapNode.mozRequestFullScreen) {
                state = document.mozFullScreen;
            } else if (this._mapNode.webkitRequestFullScreen) {
                state = document.webkitIsFullScreen;
            }

            // set fullscreen status
            this.set("fullscreen", state);

            if (this.get("fullscreen")) {
                w = "100%";
                h = "100%";
                domClass.add(this.buttonNode, "exit");
                domClass.remove(this.buttonNode, "enter");
                domAttr.set(this.buttonNode, "title", "Exit Fullscreen");
            } else {
                w = '';
                h = '';
                domClass.add(this.buttonNode, "enter");
                domClass.remove(this.buttonNode, "exit");
                domAttr.set(this.buttonNode, "title", "Enter Fullscreen");
            }

            domStyle.set(this._mapNode, {
                width: w,
                height: h
            });

            this.map.resize();

            // re-center map
            setTimeout(lang.hitch(this, function () {
                this.map.centerAt(center);
            }), 500);

        },

        /* ---------------- */
        /* Private Functions */
        /* ---------------- */
        _init: function () {

            // enter/exit fullscreen event
            if (this._mapNode.requestFullscreen) {
                on(document, "fullscreenchange", lang.hitch(this, function () {
                    this.refresh();
                }));
            } else if (this._mapNode.mozRequestFullScreen) {
                on(document, "mozfullscreenchange", lang.hitch(this, function () {
                    this.refresh();
                }));
            } else if (this._mapNode.webkitRequestFullScreen) {
                on(document, "webkitfullscreenchange", lang.hitch(this, function () {
                    this.refresh();
                }));
            }

            this.set("loaded", true);

            // emit event
            this.emit("load", {});

        },

        _visible: function(){
            if(this.get("visible")){
                domStyle.set(this.domNode, 'display', 'block');
            }
            else{
                domStyle.set(this.domNode, 'display', 'none');
            }
        },

        _toggleFullscreen: function () {
            if (this.get("fullscreen")) {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                } else if (document.webkitCancelFullScreen) {
                    document.webkitCancelFullScreen();
                }
            } else {
                if (this._mapNode.requestFullscreen) {
                    this._mapNode.requestFullscreen();
                } else if (this._mapNode.mozRequestFullScreen) {
                    this._mapNode.mozRequestFullScreen();
                } else if (this._mapNode.webkitRequestFullScreen) {
                    this._mapNode.webkitRequestFullScreen();
                }
            }
        }

    });
});<|endoftext|>


<commit_before>(function() {
  $(function() {
    var printNodeStatus = function(chord, html) {
      var statuses = chord.getStatuses();

      statuses = _.chain(statuses)
        .map(function(str, key) {
          return [key, str.replace(/[\r\n]/g, "
")];
        })
        .object()
        .value();

      html.find("#successors-container").html(statuses.successors);
      html.find("#predecessor-container").html(statuses.predecessor);
      html.find("#finger-table-container").html(statuses.fingerTable);
      html.find("#entries-container").html(statuses.entries);
    };

    $("#btn-create-node").click(function() {
      var chord = new Chord({
        peer: {
          options: {
            key: 'lwjd5qra8257b9',
          }
        }
      });

      var html = $(_.template($("#node-template").html())());
      var timer;
      html.find("#btn-create").click(function() {
        chord.create(function(peerId) {
          if (_.isNull(peerId)) {
            console.log("Failed to create network.");
            return;
          }
          html.find("#peer-id").text("Peer ID: " + peerId);

          timer = setInterval(function() {
            printNodeStatus(chord, html);
          }, 5000);
        });
      });

      html.find("#btn-join").click(function() {
        var id = html.find("#text-id-to-join").val();
        chord.join(id, function(peerId) {
          if (_.isNull(peerId)) {
            console.log("Failed to join network.");
            return;
          }
          html.find("#peer-id").text("Peer ID: " + peerId);

          timer = setInterval(function() {
            printNodeStatus(chord, html);
          }, 5000);
        });
      });

      html.find("#btn-leave").click(function() {
        chord.leave();
        clearInterval(timer);
      });

      html.find("#btn-insert-entry").click(function() {
        var key = html.find("#text-insert-entry-key").val();
        var value = html.find("#text-insert-entry-value").val();
        chord.insert(key, JSON.parse(value), function(inserted) {
          if (!inserted) {
            console.log("Failed to insert entry.");
          }
        });
      });

      html.find("#btn-retrieve-entry").click(function() {
        var key = html.find("#text-retrieve-entry-key").val();
        chord.retrieve(key, function(value) {
          if (_.isNull(value)) {
            console.log("Failed to retrieve entries.");
            return;
          }
          html.find("#p-retrieve-entry-value").text(JSON.stringify(value));
        });
      });

      html.find("#btn-remove-entry").click(function() {
        var key = html.find("#text-remove-entry-key").val();
        var value = html.find("#text-remove-entry-value").val();
        chord.remove(key, JSON.parse(value), function(removed) {
          if (!removed) {
            console.log("Failed to remove entry.");
          }
        });
      });

      $("#node-list-container").append(html);
    });
  });
})();
<commit_msg>Modify chord-monitor to accept non-json formatted string for entry values.<commit_after>(function() {
  $(function() {
    var printNodeStatus = function(chord, html) {
      var statuses = chord.getStatuses();

      statuses = _.chain(statuses)
        .map(function(str, key) {
          return [key, str.replace(/[\r\n]/g, "
")];
        })
        .object()
        .value();

      html.find("#successors-container").html(statuses.successors);
      html.find("#predecessor-container").html(statuses.predecessor);
      html.find("#finger-table-container").html(statuses.fingerTable);
      html.find("#entries-container").html(statuses.entries);
    };

    $("#btn-create-node").click(function() {
      var chord = new Chord({
        peer: {
          options: {
            key: 'lwjd5qra8257b9',
          }
        }
      });

      var html = $(_.template($("#node-template").html())());
      var timer;
      html.find("#btn-create").click(function() {
        chord.create(function(peerId) {
          if (_.isNull(peerId)) {
            console.log("Failed to create network.");
            return;
          }
          html.find("#peer-id").text("Peer ID: " + peerId);

          timer = setInterval(function() {
            printNodeStatus(chord, html);
          }, 5000);
        });
      });

      html.find("#btn-join").click(function() {
        var id = html.find("#text-id-to-join").val();
        chord.join(id, function(peerId) {
          if (_.isNull(peerId)) {
            console.log("Failed to join network.");
            return;
          }
          html.find("#peer-id").text("Peer ID: " + peerId);

          timer = setInterval(function() {
            printNodeStatus(chord, html);
          }, 5000);
        });
      });

      html.find("#btn-leave").click(function() {
        chord.leave();
        clearInterval(timer);
      });

      html.find("#btn-insert-entry").click(function() {
        var key = html.find("#text-insert-entry-key").val();
        var value = html.find("#text-insert-entry-value").val();
        try {
          value = JSON.parse(value);
        } catch (e) {
        }
        chord.insert(key, value, function(inserted) {
          if (!inserted) {
            console.log("Failed to insert entry.");
          }
        });
      });

      html.find("#btn-retrieve-entry").click(function() {
        var key = html.find("#text-retrieve-entry-key").val();
        chord.retrieve(key, function(value) {
          if (_.isNull(value)) {
            console.log("Failed to retrieve entries.");
            return;
          }
          html.find("#p-retrieve-entry-value").text(JSON.stringify(value));
        });
      });

      html.find("#btn-remove-entry").click(function() {
        var key = html.find("#text-remove-entry-key").val();
        var value = html.find("#text-remove-entry-value").val();
        try {
          value = JSON.parse(value);
        } catch (e) {
        }
        chord.remove(key, value, function(removed) {
          if (!removed) {
            console.log("Failed to remove entry.");
          }
        });
      });

      $("#node-list-container").append(html);
    });
  });
})();
<|endoftext|>


<commit_before>
/****
 * Grapnel.js
 * https://github.com/gregsabia/Grapnel.js
 *
 * @author Greg Sabia
 * @link http://gregsabia.com
 * @version 0.1.2
 *
 * Released under MIT License. See LICENSE.txt or http://opensource.org/licenses/MIT
*/

var Grapnel = function(hook){
    "use strict";
    // Scope reference
    var self = this;
    // Current action if matched (default: null)
    this.action = null;
    // Hook (default: ":")
    this.hook = hook || ':';
    // Current value if matched (default: null)
    this.value = null;
    // Actions
    this.actionsMatching = [];
    // Listeners
    this.listeners = [];
    // Version
    this.version = '0.1.2';
    /**
     * Map Array workaround for compatibility issues with archaic browsers
     *
     * @param {Array} to iterate
     * @param {Function} callback
    */
    this.mapArray = function(a, callback){
        if(typeof Array.prototype.map === 'function') return Array.prototype.map.call(a, callback);
        // Replicate map()
        return function(c, next){
            var other = new Array(this.length);
            for(var i=0, n=this.length; i<n; i++){
                if(i in this) other[i] = c.call(next, this[i], i, this);
            }

            return other;
        }.call(a, callback);
    }
    /**
     * Add an event listener
     *
     * @param {String|Array} event
     * @param {Function} callback
     * @return self
    */
    this.on = function(event, handler){
        var events = (typeof event === 'string') ? event.split() : event;
        // Add listeners
        this.mapArray(events, function(event){
            self.listeners.push({ event : event, handler : handler });
        });

        return this;
    }
    /**
     * Add an action and handler
     *
     * @param {String|RegExp} action name
     * @param {Function} callback
     * @return self
    */
    this.add = function(name, handler){
        var invoke = function(){
            // If action is instance of RegEx, match the action
            var regex = (self.action && name instanceof RegExp && self.action.match(name));
            // Test matches against current action
            if(regex || name === self.action){
                // Match found
                handler.call(self, self.value, self.action);
                // Push self to actions
                self.actionsMatching.push({ name : name, handler : handler });
            }
            // Return self to force context
            return self;
        }
        // Invoke itself and add listeners
        return invoke().on(['ready', 'hashchange'], invoke);
    }
    /**
     * Fire an event listener
     *
     * @param {String} event
     * @return self
    */
    this._trigger = function(event){
        var params = Array.prototype.slice.call(arguments, 1);
        // Call matching events
        this.mapArray(this.listeners, function(listener){
            // Apply special state (ready) to future events
            if(listener.event == event) listener.handler.apply(self, params);
        });

        return this;
    }
    // Get anchor
    this.getAnchor = function(){
        return (window.location.hash) ? window.location.hash.split('#')[1] : '';
    }
    // Change anchor
    this.setAnchor = function(anchor){
        window.location.hash = (!anchor) ? '' : anchor;
        return this;
    }
    // Reset anchor
    this.clearAnchor = function(){
        return this.setAnchor(false);
    }
    // Parse hook
    this.parse = function(){
        var action, value;

        if(this.getAnchor().match(this.hook)){
            // Found a hook!
            value = this.getAnchor().split(this.hook)[1];
            action = this.getAnchor().split(this.hook)[0];
        }

        return {
            value : value,
            action : action
        };
    }
    // Return matched actions
    this.matches = function(){
        var matches = [];

        this.mapArray(this.actionsMatching, function(action){
            // If action is instance of RegEx, match the action
            var regex = (action.name instanceof RegExp && self.action.match(action.name));
            // Test matches against current action
            if(regex || action.name === self.action){
                // Match found
                matches.push(action);
            }
        });

        return matches;
    }
    // Run hook action
    this.on(['ready', 'hashchange'], function(){
        // Parse Hashtag in URL
        this.action = this.parse().action;
        this.value = this.parse().value;
        // Reset actions
        this.actionsMatching = [];
        // If a match is found, trigger event
        if(this.matches().length > 0) this._trigger('match', this.value, this.action);
    });
    // Check current hash change event
    if(typeof window.onhashchange === 'function') this.on('hashchange', window.onhashchange);
    /**
     * Hash change event
     * TODO: increase browser compatibility. "window.onhashchange" can be supplemented in older browsers with setInterval()
    */
    window.onhashchange = function(){
        self._trigger('hashchange');
    }

    return this._trigger('ready');
}
<commit_msg>Move default event triggering into invoke<commit_after>
/****
 * Grapnel.js
 * https://github.com/gregsabia/Grapnel.js
 *
 * @author Greg Sabia
 * @link http://gregsabia.com
 * @version 0.1.2
 *
 * Released under MIT License. See LICENSE.txt or http://opensource.org/licenses/MIT
*/

var Grapnel = function(hook){
    "use strict";
    // Scope reference
    var self = this;
    // Current action if matched (default: null)
    this.action = null;
    // Hook (default: ":")
    this.hook = hook || ':';
    // Current value if matched (default: null)
    this.value = null;
    // Actions
    this.actionsMatching = [];
    // Listeners
    this.listeners = [];
    // Version
    this.version = '0.1.2';
    /**
     * Map Array workaround for compatibility issues with archaic browsers
     *
     * @param {Array} to iterate
     * @param {Function} callback
    */
    this.mapArray = function(a, callback){
        if(typeof Array.prototype.map === 'function') return Array.prototype.map.call(a, callback);
        // Replicate map()
        return function(c, next){
            var other = new Array(this.length);
            for(var i=0, n=this.length; i<n; i++){
                if(i in this) other[i] = c.call(next, this[i], i, this);
            }

            return other;
        }.call(a, callback);
    }
    /**
     * Add an event listener
     *
     * @param {String|Array} event
     * @param {Function} callback
     * @return self
    */
    this.on = function(event, handler){
        var events = (typeof event === 'string') ? event.split() : event;
        // Add listeners
        this.mapArray(events, function(event){
            self.listeners.push({ event : event, handler : handler });
        });

        return this;
    }
    /**
     * Add an action and handler
     *
     * @param {String|RegExp} action name
     * @param {Function} callback
     * @return self
    */
    this.add = function(name, handler){
        var invoke = function(){
            // If action is instance of RegEx, match the action
            var regex = (self.action && name instanceof RegExp && self.action.match(name));
            // Test matches against current action
            if(regex || name === self.action){
                // Match found
                self._trigger('match', self.value, self.action);
                // Callback
                handler.call(self, self.value, self.action);
                // Push self to actions
                self.actionsMatching.push({ name : name, handler : handler });
            }
            // Return self to force context
            return self;
        }
        // Invoke itself and add listeners
        return invoke().on(['ready', 'hashchange'], invoke);
    }
    /**
     * Fire an event listener
     *
     * @param {String} event
     * @return self
    */
    this._trigger = function(event){
        var params = Array.prototype.slice.call(arguments, 1);
        // Call matching events
        this.mapArray(this.listeners, function(listener){
            // Apply special state (ready) to future events
            if(listener.event == event) listener.handler.apply(self, params);
        });

        return this;
    }
    // Get anchor
    this.getAnchor = function(){
        return (window.location.hash) ? window.location.hash.split('#')[1] : '';
    }
    // Change anchor
    this.setAnchor = function(anchor){
        window.location.hash = (!anchor) ? '' : anchor;
        return this;
    }
    // Reset anchor
    this.clearAnchor = function(){
        return this.setAnchor(false);
    }
    // Parse hook
    this.parse = function(){
        var action, value;

        if(this.getAnchor().match(this.hook)){
            // Found a hook!
            value = this.getAnchor().split(this.hook)[1];
            action = this.getAnchor().split(this.hook)[0];
        }

        return {
            value : value,
            action : action
        };
    }
    // Return matched actions
    this.matches = function(){
        var matches = [];

        this.mapArray(this.actionsMatching, function(action){
            // If action is instance of RegEx, match the action
            var regex = (action.name instanceof RegExp && self.action.match(action.name));
            // Test matches against current action
            if(regex || action.name === self.action){
                // Match found
                matches.push(action);
            }
        });

        return matches;
    }
    // Run hook action
    this.on(['ready', 'hashchange'], function(){
        // Parse Hashtag in URL
        this.action = this.parse().action;
        this.value = this.parse().value;
        // Reset actions
        this.actionsMatching = [];
    });
    // Check current hash change event
    if(typeof window.onhashchange === 'function') this.on('hashchange', window.onhashchange);
    /**
     * Hash change event
     * TODO: increase browser compatibility. "window.onhashchange" can be supplemented in older browsers with setInterval()
    */
    window.onhashchange = function(){
        self._trigger('hashchange');
    }

    return this._trigger('ready');
}
<|endoftext|>


<commit_before>var db = require('./db')
var co = require('co');
var auth = require('./auth');
module.exports = {};

module.exports.addCalendarEvent = co.wrap(function*(username, event){
  var client = db();
  var a = yield auth.isAdmin(username);
  client.query('INSERT INTO calendar("user", "time", room, duration, title)VALUES ($1, $2, $3, $4, $5);', [username, event.time, event.room, event.duration, event.title]);

  return yield Promise.resolve(true);
});

module.exports.deleteCalendarEvent = co.wrap(function*(username, event){
  var client = db();
  var a = yield auth.isAdmin(username);
  if(a) {
    client.query('DELETE FROM calendar WHERE room=$1 AND "time"=$2;', [event.room, event.time]);
    return yield Promise.resolve(true);
  }

  return yield Promise.reject(new Error("Nice try."));
});
<commit_msg>Undoing changes to cal.js app_module.<commit_after>var db = require('./db')
var co = require('co');
var auth = require('./auth');
module.exports = {};

module.exports.addCalendarEvent = co.wrap(function*(username, event, reply){
  var client = db();
  var a = yield auth.isAdmin(username);
  var user = a ? event.user : reply;
  client.query('INSERT INTO calendar("user", "time", room, duration, title)VALUES ($1, $2, $3, $4, $5);', [user, event.time, event.room, event.duration, event.title]);

  return yield Promise.resolve(true);
});

module.exports.deleteCalendarEvent = co.wrap(function*(username, event){
  var client = db();
  var a = yield auth.isAdmin(username);
  if(event.user == username || a) {
    client.query('DELETE FROM calendar WHERE room=$1 AND "time"=$2;', [event.room, event.time]);
    return yield Promise.resolve(true);
  }

  return yield Promise.reject(new Error("Nice try."));
});<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * MultiLine plain text, with alignment.
 * The line break character is '\n'.
 * Specify alignment via the 'align' option.
 * Text node options can be specified to style the text.
 *

 * Example: new MultiLineText( 'Hello\nWorld', { align: 'left', font: new PhetFont(20), fill: 'red' } );
 *
 * @author Sam Reid
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Text = require( 'SCENERY/nodes/Text' );
  var VBox = require( 'SCENERY/nodes/VBox' );

  function MultiLineText( text, options ) {

    var thisNode = this;

    thisNode._options = options = _.extend( {
      align: 'center' // 'center', 'left' or 'right' (as supported by VBox)
    }, options );

    Node.call( thisNode );
    thisNode.text = text;
    thisNode.mutate( _.omit( options, 'align' ) ); // mutate after removing options that are specific to this subtype
  }

  inherit( Node, MultiLineText, {
      get text() {
        return this._text;
      },
      set text( string ) {
        var thisNode = this;
        thisNode._text = string;
        thisNode.children = [ new VBox( {
          children: string.split( '\n' ).map( function( line ) {
            if ( line.length === 0 ) { line = ' '; }  // creates a blank line between consecutive line breaks
            return new Text( line, _.omit( thisNode._options, 'align' ) );
          } ),
          align: thisNode._options.align
        } ) ];
      }
    }
  );

  return MultiLineText;
} );
<commit_msg>Fixes for the Adapted from PhET text fill<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * MultiLine plain text, with alignment.
 * The line break character is '\n'.
 * Specify alignment via the 'align' option.
 * Text node options can be specified to style the text.
 *

 * Example: new MultiLineText( 'Hello\nWorld', { align: 'left', font: new PhetFont(20), fill: 'red' } );
 *
 * @author Sam Reid
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Text = require( 'SCENERY/nodes/Text' );
  var VBox = require( 'SCENERY/nodes/VBox' );

  function MultiLineText( text, options ) {

    var thisNode = this;

    thisNode._options = options = _.extend( {
      align: 'center' // 'center', 'left' or 'right' (as supported by VBox)
    }, options );

    Node.call( thisNode );
    thisNode.text = text;
    thisNode.mutate( _.omit( options, 'align' ) ); // mutate after removing options that are specific to this subtype
  }

  inherit( Node, MultiLineText, {
      get text() {
        return this._text;
      },
      set text( string ) {
        var thisNode = this;
        thisNode._text = string;
        thisNode.children = [ new VBox( {
          children: string.split( '\n' ).map( function( line ) {
            if ( line.length === 0 ) { line = ' '; }  // creates a blank line between consecutive line breaks
            return new Text( line, _.omit( thisNode._options, 'align' ) );
          } ),
          align: thisNode._options.align
        } ) ];
      },
      /**
       * Returns an Array of the text nodes that comprise this multi line text, in case they need to be modified.
       * @private
       * @returns {Array[Text]}
       */
      getTextNodes: function() {
        var vbox = this.children[ 0 ];
        return vbox.getChildren();
      },

      /**
       * Sets the fill for all Text nodes.
       */
      setFill: function( fill ) {
        var children = this.getTextNodes();
        for ( var i = 0; i < children.length; i++ ) {
          children[ i ].setFill( fill );
        }
      }
    }
  );

  return MultiLineText;
} );
<|endoftext|>


<commit_before>import ColorHash from 'color-hash';
import Color from 'color';
import L from 'leaflet';
import createSVGPie from 'create-svg-pie';
import createElement from 'svg-create-element';
import SVGInjector from 'svg-injector';
import { Base64 } from 'js-base64';
import poiColors from '../constants/poiColors.js';

export const featureStyler = (feature) => {
    var color = Color(getColorForProperties(feature.properties));
    let radius = 10;
    let selectionBox = 30;
    let weight = 2;
    let svgSize = radius * 2 + weight * 2;
    if (feature.selected) {
        svgSize = 36;
    }

    let badge=feature.properties.svgBadge || `<image x="${(svgSize - 20) / 2}" y="${(svgSize - 20) / 2}" width="20" height="20" xlink:href="/pois/signaturen/`+getSignatur(feature.properties)+`" />`;

    let svg = `<svg id="badgefor_${feature.id}" height="${svgSize}" width="${svgSize}">

               <svg x="2" y="2"  width="20" height="20" viewBox="0 0 `+feature.properties.svgBadgeDimension.width+` `+feature.properties.svgBadgeDimension.height+`">
               `+badge+`
               </svg>
               </svg>  `

    if (feature.selected) {
        svg = `<svg id="badgefor_${feature.id}" height="${svgSize}" width="${svgSize}">

              <rect visible="false" x="${ (svgSize - selectionBox) / 2}" y="${ (svgSize - selectionBox) / 2}" rx="8" ry="8" width="${selectionBox}" height="${selectionBox}" fill="rgba(67, 149, 254, 0.8)" stroke-width="0"/>
              <svg x="8" y="8"  width="20" height="20" viewBox="0 0 `+feature.properties.svgBadgeDimension.width+` `+feature.properties.svgBadgeDimension.height+`">
              `+badge+`
              </svg>
              </svg>  `
            //   console.log(svg)
            }

    const style = {
        radius,
        fillColor: color,
        color: color.darken(0.5),
        weight,
        opacity: 1,
        fillOpacity: 0.8,
        svg,
        svgSize
    };
    return style;
};

export const poiClusterIconCreator = (cluster) => {
    var childCount = cluster.getChildCount();
    const color="#A83F6A";
    const values = [];
    const colors = [];
    const r = 16;

    // Pie with default colors
    let childMarkers=cluster.getAllChildMarkers();

    let containsSelection=false;
    let inCart=false;
    for (let marker of childMarkers) {
        values.push(1);
        colors.push(Color(getColorForProperties(marker.feature.properties)));
        if (marker.feature.selected===true){
            containsSelection=true;
        }
        if (marker.feature.inCart){
            inCart=true;
        }
    }
    const pie = createSVGPie(values, r, colors);

    let background=createElement('svg', {
        width:40,
         height:40,
         viewBox:"0 0 40 40"
    });

    //Kleiner Kreis in der Mitte
    // (blau wenn selektion)
    let innerCircleColor="#ffffff";
    if (containsSelection) {
        innerCircleColor="rgb(67, 149, 254)";
    }
    pie.appendChild(createElement('circle', {
        cx:r,
        cy:r,
        r:8,
        "stroke-width":0,
        "opacity": "0.5",
        fill: innerCircleColor
    }));

    background.appendChild(pie);

    background.appendChild(createElement('circle', {
        cx:20,
        cy:20,
        r:r,
        "stroke-width":2,
        stroke: "#000000",
        opacity: "0.5",
        fill: "none"

    }));

    if (inCart) {
        background.appendChild(createElement('text', {
            x:"50%",
            y:"50%",
            "text-anchor":"middle",
            "font-family":"FontAwesome",
            "fill":"#fff",
            "font-size":"26",
            "dy":".4em",
            opacity: "0.5",
        })).appendChild(document.createTextNode("\uf005"));
    }

    background.appendChild(createElement('text', {
        x:"50%",
        y:"50%",
        "text-anchor":"middle",
        "dy":".3em",
    })).appendChild(document.createTextNode(childCount));

    pie.setAttribute("x",4);
    pie.setAttribute("y",4);

    var divIcon = L.divIcon({
            className: "leaflet-data-marker",
            html: background.outerHTML || new XMLSerializer().serializeToString(background), //IE11 Compatibility
            iconAnchor: [
                20 ,
                20
            ],
            iconSize: [40, 40]
        });
        //console.log(background.outerHtml)
        return divIcon;
};

export const getColorForProperties = (properties) => {
    let {mainlocationtype}=properties;
    let ll=mainlocationtype.lebenslagen;
    //console.log(colorHash.hex("" + JSON.stringify({ll})));
    return getColorFromLebenslagenCombination(ll.join(", "));
    //return "#A83F6A";
};
export const getColorFromLebenslagenCombination = (combination) => {
    const colorCandidate=poiColors[combination]
    if (colorCandidate) {
        return colorCandidate;
    } else {
        let colorHash = new ColorHash({saturation: 0.3});
        const c=colorHash.hex(combination);
        console.log("Keine vordefinierte Farbe für '"+combination+"' vorhanden. (Ersatz wird automatisch erstellt) --> "+c);
        return c;
    }
    //return "#A83F6A";
};

export const featureHoverer = (feature) => {
    return "
" + feature.text + "
";
};

const getSignatur = (properties) => {
    if (properties.signatur){
        return properties.signatur;
    }
    else if (properties.mainlocationtype.signatur){
        return properties.mainlocationtype.signatur;
    }
    else {
        for (let type of properties.locationtypes){
            if (type.signatur) {
                return type.signatur;
            }
        }
    }
    return "burg.svg"; //TODO sinnvoller default
}

export const addSVGToPOI = (poi) => {
    return new Promise(function (fulfilled,rejected) {
        var color = Color(getColorForProperties(poi));
        let radius = 10;
        let selectionBox = 30;
        let weight = 2;
        let svgSize = radius * 2 + weight * 2;
        let test=createElement('svg', {
            width:svgSize,
            height:svgSize,
        });
        test.appendChild(createElement('image', {
            x:(svgSize - 20) / 2,
            y:(svgSize - 20) / 2,
            width:20,
            height:20,
            "xlink:href":"/pois/signaturen/"+getSignatur(poi)
        }));
        let d=document.createElement("div");

        test= document.createElement("image");
        test.setAttribute("data-src", "/poi-signaturen/"+getSignatur(poi));
        test.setAttribute("height", "30");
        test.setAttribute("width", "30");
        d.appendChild(test);

        var mySVGsToInject=[test];
        var injectorOptions = {
            evalScripts: 'once',
            each: function (xsvg) {
                try {
                    poi.svgBadge=xsvg.outerHTML || new XMLSerializer().serializeToString(xsvg)
                    poi.svgBadgeDimension={
                        width: xsvg.width.baseVal.valueAsString,
                        height: xsvg.height.baseVal.valueAsString
                    }
                    fulfilled(poi);
                }
                catch (error) {
                    console.error("Problem bei "+"/pois/signaturen/"+getSignatur(poi));
                    console.error(error);
                    rejected(error);
                }

            }
          };
        SVGInjector(mySVGsToInject, injectorOptions);
    });
}<commit_msg>:sparkles: #18: added a (temporary) solution to provide own poiColorMaps<commit_after>import ColorHash from 'color-hash';
import Color from 'color';
import L from 'leaflet';
import createSVGPie from 'create-svg-pie';
import createElement from 'svg-create-element';
import SVGInjector from 'svg-injector';
import { Base64 } from 'js-base64';
import poiColors from '../constants/poiColors.js';
import store from '../redux/store';
import queryString from 'query-string';

export const featureStyler = (feature) => {
    var color = Color(getColorForProperties(feature.properties));
    let radius = 10;
    let selectionBox = 30;
    let weight = 2;
    let svgSize = radius * 2 + weight * 2;
    if (feature.selected) {
        svgSize = 36;
    }

    let badge=feature.properties.svgBadge || `<image x="${(svgSize - 20) / 2}" y="${(svgSize - 20) / 2}" width="20" height="20" xlink:href="/pois/signaturen/`+getSignatur(feature.properties)+`" />`;

    let svg = `<svg id="badgefor_${feature.id}" height="${svgSize}" width="${svgSize}">

               <svg x="2" y="2"  width="20" height="20" viewBox="0 0 `+feature.properties.svgBadgeDimension.width+` `+feature.properties.svgBadgeDimension.height+`">
               `+badge+`
               </svg>
               </svg>  `

    if (feature.selected) {
        svg = `<svg id="badgefor_${feature.id}" height="${svgSize}" width="${svgSize}">

              <rect visible="false" x="${ (svgSize - selectionBox) / 2}" y="${ (svgSize - selectionBox) / 2}" rx="8" ry="8" width="${selectionBox}" height="${selectionBox}" fill="rgba(67, 149, 254, 0.8)" stroke-width="0"/>
              <svg x="8" y="8"  width="20" height="20" viewBox="0 0 `+feature.properties.svgBadgeDimension.width+` `+feature.properties.svgBadgeDimension.height+`">
              `+badge+`
              </svg>
              </svg>  `
            //   console.log(svg)
            }

    const style = {
        radius,
        fillColor: color,
        color: color.darken(0.5),
        weight,
        opacity: 1,
        fillOpacity: 0.8,
        svg,
        svgSize
    };
    return style;
};

export const poiClusterIconCreator = (cluster) => {
    var childCount = cluster.getChildCount();
    const color="#A83F6A";
    const values = [];
    const colors = [];
    const r = 16;

    // Pie with default colors
    let childMarkers=cluster.getAllChildMarkers();

    let containsSelection=false;
    let inCart=false;
    for (let marker of childMarkers) {
        values.push(1);
        colors.push(Color(getColorForProperties(marker.feature.properties)));
        if (marker.feature.selected===true){
            containsSelection=true;
        }
        if (marker.feature.inCart){
            inCart=true;
        }
    }
    const pie = createSVGPie(values, r, colors);

    let background=createElement('svg', {
        width:40,
         height:40,
         viewBox:"0 0 40 40"
    });

    //Kleiner Kreis in der Mitte
    // (blau wenn selektion)
    let innerCircleColor="#ffffff";
    if (containsSelection) {
        innerCircleColor="rgb(67, 149, 254)";
    }
    pie.appendChild(createElement('circle', {
        cx:r,
        cy:r,
        r:8,
        "stroke-width":0,
        "opacity": "0.5",
        fill: innerCircleColor
    }));

    background.appendChild(pie);

    background.appendChild(createElement('circle', {
        cx:20,
        cy:20,
        r:r,
        "stroke-width":2,
        stroke: "#000000",
        opacity: "0.5",
        fill: "none"

    }));

    if (inCart) {
        background.appendChild(createElement('text', {
            x:"50%",
            y:"50%",
            "text-anchor":"middle",
            "font-family":"FontAwesome",
            "fill":"#fff",
            "font-size":"26",
            "dy":".4em",
            opacity: "0.5",
        })).appendChild(document.createTextNode("\uf005"));
    }

    background.appendChild(createElement('text', {
        x:"50%",
        y:"50%",
        "text-anchor":"middle",
        "dy":".3em",
    })).appendChild(document.createTextNode(childCount));

    pie.setAttribute("x",4);
    pie.setAttribute("y",4);

    var divIcon = L.divIcon({
            className: "leaflet-data-marker",
            html: background.outerHTML || new XMLSerializer().serializeToString(background), //IE11 Compatibility
            iconAnchor: [
                20 ,
                20
            ],
            iconSize: [40, 40]
        });
        //console.log(background.outerHtml)
        return divIcon;
};

export const getColorForProperties = (properties) => {
    let {mainlocationtype}=properties;
    let ll=mainlocationtype.lebenslagen;
    //console.log(colorHash.hex("" + JSON.stringify({ll})));
    return getColorFromLebenslagenCombination(ll.join(", "));
    //return "#A83F6A";
};
export const getColorFromLebenslagenCombination = (combination) => {
    let qColorRules=queryString.parse(store.getState().routing.location.search).colorRules;
    let colorCandidate;
    let lookup=null;
    try {
        lookup=JSON.parse(qColorRules);
    }
    catch (error){
        console.error(error);
    }
    if (lookup===null){
        lookup=poiColors;
    }

    colorCandidate=lookup[combination]
    if (colorCandidate) {
        return colorCandidate;
    } else {
        let colorHash = new ColorHash({saturation: 0.3});
        const c=colorHash.hex(combination);
        console.log("Keine vordefinierte Farbe für '"+combination+"' vorhanden. (Ersatz wird automatisch erstellt) --> "+c);
        return c;
    }
    //return "#A83F6A";
};

export const featureHoverer = (feature) => {
    return "
" + feature.text + "
";
};

const getSignatur = (properties) => {
    if (properties.signatur){
        return properties.signatur;
    }
    else if (properties.mainlocationtype.signatur){
        return properties.mainlocationtype.signatur;
    }
    else {
        for (let type of properties.locationtypes){
            if (type.signatur) {
                return type.signatur;
            }
        }
    }
    return "burg.svg"; //TODO sinnvoller default
}

export const addSVGToPOI = (poi) => {
    return new Promise(function (fulfilled,rejected) {
        var color = Color(getColorForProperties(poi));
        let radius = 10;
        let selectionBox = 30;
        let weight = 2;
        let svgSize = radius * 2 + weight * 2;
        let test=createElement('svg', {
            width:svgSize,
            height:svgSize,
        });
        test.appendChild(createElement('image', {
            x:(svgSize - 20) / 2,
            y:(svgSize - 20) / 2,
            width:20,
            height:20,
            "xlink:href":"/pois/signaturen/"+getSignatur(poi)
        }));
        let d=document.createElement("div");

        test= document.createElement("image");
        test.setAttribute("data-src", "/poi-signaturen/"+getSignatur(poi));
        test.setAttribute("height", "30");
        test.setAttribute("width", "30");
        d.appendChild(test);

        var mySVGsToInject=[test];
        var injectorOptions = {
            evalScripts: 'once',
            each: function (xsvg) {
                try {
                    poi.svgBadge=xsvg.outerHTML || new XMLSerializer().serializeToString(xsvg)
                    poi.svgBadgeDimension={
                        width: xsvg.width.baseVal.valueAsString,
                        height: xsvg.height.baseVal.valueAsString
                    }
                    fulfilled(poi);
                }
                catch (error) {
                    console.error("Problem bei "+"/pois/signaturen/"+getSignatur(poi));
                    console.error(error);
                    rejected(error);
                }

            }
          };
        SVGInjector(mySVGsToInject, injectorOptions);
    });
}<|endoftext|>


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

exports.get = function (req, res){
    models.Repo.findOne({
        where: {
            repoName: req.params.account+'/'+req.params.repo,
        },
        order: [['updatedAt', 'DESC']]
    }).then(function (repo) {
        models.Commit.findAll({
            where: {
                repo: repo.repo
            }
        }).then(function (commits) {
            res.send({results: commits});
        });
    });
};<commit_msg>improve api responses<commit_after>var models = require('../models');

exports.get = function (req, res){
    models.Repo.findOne({
        where: {
            repoName: req.params.account+'/'+req.params.repo,
        },
        order: [['updatedAt', 'DESC']]
    }).then(function (repo) {
        if (repo) {
            models.Commit.findAll({
                where: {
                    repo: repo.repo
                }
            }).then(function (commits) {
                res.send({
                    status: 'success',
                    results: commits
                });
            });
        } else {
            res.send({
                status: 'error',
                error: 'no such repo'
            });
        }
    });
};<|endoftext|>


<commit_before>/**
 * This file is intended for non module enviorements
 * Works like JQuery or legacy angular
 * Note the parent can be within a clousure or be self(window or worker)
 */
((parent) => {
	include "_core.js"
	self.Trocha = Trocha//fucking babel
	parent.Trocha = Trocha
})(this)
<commit_msg>remove babel kick fix<commit_after>/**
 * This file is intended for non module enviorements
 * Works like JQuery or legacy angular
 * Note the parent can be within a clousure or be self(window or worker)
 */
((parent) => {
	include "_core.js"
	parent.Trocha = Trocha
})(this)
<|endoftext|>


<commit_before>/**
 * The tab navigation bar at the bottom of the screen.
 * For a single-tabbed sim, it shows the name of the sim at the left and the PhET Logo and options menu at the right.
 * For a multi-tabbed sim, it shows icons for all of the other tabs, with the tab name at the left and the PhET Logo and options menu at the right.
 */
define( function( require ) {
  "use strict";

  var Node = require( 'SCENERY/nodes/Node' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var Text = require( 'SCENERY/nodes/Text' );
  var FontAwesomeNode = require( 'SUN/FontAwesomeNode' );
  var Layout = require( 'SCENERY_PHET/Layout' );
  var inherit = require( 'PHET_CORE/inherit' );

  function NavigationBar( tabs, model ) {
    var navigationBar = this;
    Node.call( this );

    //Space between the icons and the bottom of the play area
    var verticalPadding = 2;

    //Vertical height of the nav bar
    var height = Layout.navBarHeight;

    var fontSize = 36;

    //Create the text labels once because in this version of Scenery (4/18/2013) they are expensive to create because they must be accurately sized.
    this.textLabel = new Node();
    this.phetLabel = new Text( "PhET", {fontSize: fontSize, fill: 'yellow', centerY: height / 2, right: Layout.width - 5} );
    this.addChild( this.textLabel );
    this.addChild( this.phetLabel );

    //Create the nodes to be used for the tab icons
    var index = 0;
    var tabChildren = _.map( tabs, function( tab ) {
      tab.index = index++;
      var child = new Node( {children: [tab.icon], cursor: 'pointer'} );
      child.tab = tab;
      child.scale( (height - verticalPadding * 2) / child.tab.icon.height );
      child.largeTextLabel = new Text( tab.name, {fontSize: fontSize, fill: 'white', centerY: height / 2} );
      child.addInputListener( { down: function() {
        model.tab = tab.index;
        model.home = false;
      }} );
      return child;
    } );

    //Add everything to the scene
    for ( var i = 0; i < tabChildren.length; i++ ) {
      this.addChild( tabChildren[i] );
      this.addChild( tabChildren[i].largeTextLabel );
    }

    //add the home icon
    this.homeIcon = new FontAwesomeNode( 'home', {cursor: 'pointer', fill: '#fff', centerY: height / 2} );
    this.homeIcon.addInputListener( {down: function() { model.home = true; }} );
    this.addChild( this.homeIcon );

    //On initialization and when the tab changes, update the size of the icons and the layout of the icons and text
    model.link( 'tab', function( tab ) {

      //Update size and opacity of each icon
      var selectedChild = null;
      for ( var i = 0; i < tabChildren.length; i++ ) {
        var child = tabChildren[i];
        child.invalidateBounds();
        var selected = tab === child.tab.index;
        child.selected = selected;
        child.opacity = selected ? 1 : 0.5;
        child.resetTransform();
        child.scale( selected ? (height - verticalPadding * 2) / child.tab.icon.height : (height - verticalPadding * 2) / child.tab.icon.height * 0.75 );
        child.largeTextLabel.visible = selected;
        if ( selected ) {
          selectedChild = child;
        }
      }

      //Compute layout bounds
      var width = 0;
      for ( var i = 0; i < tabChildren.length; i++ ) {
        var child = tabChildren[i];
        width = width + child.width;
      }
      var spacing = 10;
      width = width + spacing * (tabChildren.length - 1);

      //Lay out the components from left to right
      var x = Layout.width / 2 - width / 2;
      selectedChild.largeTextLabel.right = x - 25;
      for ( var i = 0; i < tabChildren.length; i++ ) {
        var child = tabChildren[i];
        child.x = x;
        child.y = verticalPadding;
        x += child.width + spacing;
      }
      navigationBar.homeIcon.left = x + 15;
    } );
  }

  inherit( NavigationBar, Node );

  return NavigationBar;
} );<commit_msg>added white border around the tab title text<commit_after>/**
 * The tab navigation bar at the bottom of the screen.
 * For a single-tabbed sim, it shows the name of the sim at the left and the PhET Logo and options menu at the right.
 * For a multi-tabbed sim, it shows icons for all of the other tabs, with the tab name at the left and the PhET Logo and options menu at the right.
 */
define( function( require ) {
  "use strict";

  var Node = require( 'SCENERY/nodes/Node' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var Text = require( 'SCENERY/nodes/Text' );
  var FontAwesomeNode = require( 'SUN/FontAwesomeNode' );
  var Layout = require( 'SCENERY_PHET/Layout' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var inherit = require( 'PHET_CORE/inherit' );

  function NavigationBar( tabs, model ) {
    var navigationBar = this;
    Node.call( this );

    //Space between the icons and the bottom of the play area
    var verticalPadding = 2;

    //Vertical height of the nav bar
    var height = Layout.navBarHeight;

    var fontSize = 36;

    //Create the text labels once because in this version of Scenery (4/18/2013) they are expensive to create because they must be accurately sized.
    this.textLabel = new Node();
    this.phetLabel = new Text( "PhET", {fontSize: fontSize, fill: 'yellow', centerY: height / 2, right: Layout.width - 5} );
    this.addChild( this.textLabel );
    this.addChild( this.phetLabel );

    //Create the nodes to be used for the tab icons
    var index = 0;
    var tabChildren = _.map( tabs, function( tab ) {
      tab.index = index++;
      var child = new Node( {children: [tab.icon], cursor: 'pointer'} );
      child.tab = tab;
      child.scale( (height - verticalPadding * 2) / child.tab.icon.height );

      var textLabel = new Text( tab.name, {fontSize: 32, fill: 'black'} );
      var outline = new Rectangle( 0, 0, textLabel.width + 10, textLabel.height + 10, 10, 10, {fill: 'white'} );
      textLabel.centerX = outline.width / 2;
      textLabel.centerY = outline.height / 2;
      outline.addChild( textLabel );

      child.largeTextLabel = outline;
      child.addInputListener( { down: function() {
        model.tab = tab.index;
        model.home = false;
      }} );
      return child;
    } );

    //Add everything to the scene
    for ( var i = 0; i < tabChildren.length; i++ ) {
      this.addChild( tabChildren[i] );
      this.addChild( tabChildren[i].largeTextLabel );
    }

    //add the home icon
    this.homeIcon = new FontAwesomeNode( 'home', {cursor: 'pointer', fill: '#fff', centerY: height / 2} );
    this.homeIcon.addInputListener( {down: function() { model.home = true; }} );
    this.addChild( this.homeIcon );

    //On initialization and when the tab changes, update the size of the icons and the layout of the icons and text
    model.link( 'tab', function( tab ) {

      //Update size and opacity of each icon
      var selectedChild = null;
      for ( var i = 0; i < tabChildren.length; i++ ) {
        var child = tabChildren[i];
        child.invalidateBounds();
        var selected = tab === child.tab.index;
        child.selected = selected;
        child.opacity = selected ? 1 : 0.5;
        child.resetTransform();
        child.scale( selected ? (height - verticalPadding * 2) / child.tab.icon.height : (height - verticalPadding * 2) / child.tab.icon.height * 0.75 );
        child.largeTextLabel.visible = selected;
        if ( selected ) {
          selectedChild = child;
        }
      }

      //Compute layout bounds
      var width = 0;
      for ( var i = 0; i < tabChildren.length; i++ ) {
        var child = tabChildren[i];
        width = width + child.width;
      }
      var spacing = 10;
      width = width + spacing * (tabChildren.length - 1);

      //Lay out the components from left to right
      var x = Layout.width / 2 - width / 2;
      selectedChild.largeTextLabel.right = x - 25;
      selectedChild.largeTextLabel.centerY = height / 2;
      for ( var i = 0; i < tabChildren.length; i++ ) {
        var child = tabChildren[i];
        child.x = x;
        child.y = verticalPadding;
        x += child.width + spacing;
      }
      navigationBar.homeIcon.left = x + 15;
    } );
  }

  inherit( NavigationBar, Node );

  return NavigationBar;
} );<|endoftext|>


<commit_before>const Lang = imports.lang;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Util = Me.imports.util;

function LOG(message) {
	// log("[pixel-saver]: " + message);
}

function WARN(message) {
	log("[pixel-saver]: " + message);
}

let appMenu = null;

/*
 * AppMenu synchronization
 */
function updateAppMenu() {
	let win = global.display.focus_window;

	if(!win) {
		return false;
	}

	let title = win.title;

	// Not the topmost maximized window.
	if(win !== Util.getWindow()) {
		let app = Shell.WindowTracker.get_default().get_window_app(win);
		title = app.get_name();
	}

	LOG('Override title ' + title);
	appMenu._label.setText(title);
	tooltip.text = title;

	return false;
}

/*
 * Track the focused window's title
 */
let activeWindow = null;
let awCallbackID = 0;
function changeActiveWindow(win) {
	if(win === activeWindow) {
		return;
	}

	if(activeWindow) {
		activeWindow.disconnect(awCallbackID);
	}

	activeWindow = win;

	if(win) {
		awCallbackID = win.connect('notify::title', updateAppMenu);
		updateAppMenu();
	}
}

/*
 * Focus change
 */
function onFocusChange() {
	if (!Shell.WindowTracker.get_default().focus_app &&
		global.stage_input_mode == Shell.StageInputMode.FOCUSED) {
		// If the app has just lost focus to the panel, pretend
		// nothing happened; otherwise you can't keynav to the
		// app menu.
		return false;
	}

	changeActiveWindow(global.display.focus_window);
	return false;
}

/*
 * tooltip
 */
let tooltip = null;
let showTooltip = false;

let SHOW_DELAY = 350;
let SHOW_DURATION = 0.15;
let HIDE_DURATION = 0.1;

let tooltipDelayCallbackID = 0;
let menuCallbackID = 0;

function onHover(actor) {
	let hover = actor.get_hover();
	if(showTooltip === hover) {
		return false;
	}

	// We are not in the right state, let's fix that.
	showTooltip = hover;

	if (showTooltip) {
		tooltipDelayCallbackID = Mainloop.timeout_add(SHOW_DELAY, function() {
			if (!showTooltip) {
				WARN('showTooltip is false and delay callback ran.');
			}

			let label = appMenu._label._label;

			if(!label.get_clutter_text().get_layout().is_ellipsized()) {
				// Do not need to hide.
				tooltipDelayCallbackID = 0;
				return false;
			}

			Main.uiGroup.add_actor(tooltip);
			menuCallbackID = appMenu.menu.connect('open-state-changed', function(menu, open) {
				if(open) {
					Main.uiGroup.remove_actor(tooltip);
				} else {
					Main.uiGroup.add_actor(tooltip);
				}
			});

			[bx, by] = label.get_transformed_position();
			[w, h] = label.get_transformed_size();

			let y = by + h + 5;
			let x = bx - Math.round((tooltip.get_width() - w)/2);
			tooltip.opacity = 0;
			tooltip.set_position(x, y);

			LOG('show title tooltip');
			Tweener.removeTweens(tooltip);
			Tweener.addTween(tooltip, {
				opacity: 255,
				time: SHOW_DURATION,
				transition: 'easeOutQuad',
			});

			return false;
		});
	} else if(tooltipDelayCallbackID > 0) {
		if(!Mainloop.source_remove(tooltipDelayCallbackID)) {
			// If the event ran, then we hide.
			LOG('hide title tooltip');

			if(menuCallbackID) {
				appMenu.menu.disconnect(menuCallbackID);
				menuCallbackID = 0;
			}

			Tweener.removeTweens(tooltip);
			Tweener.addTween(tooltip, {
				opacity: 0,
				time: HIDE_DURATION,
				transition: 'easeOutQuad',
				onComplete: function() {
					Main.uiGroup.remove_actor(tooltip);
				}
			});
		}

		tooltipDelayCallbackID = 0;
	}

	return false;
}

/*
 * Subextension hooks
 */
function init() {
	tooltip = new St.Label({
		style_class: 'tooltip dash-label',
		text: ''
	});
}

let wmCallbackIDs = [];
let focusCallbackID = 0;
let tooltipCallbackID = 0;
function enable() {
	tooltip.opacity = 0;

	if(Main.panel.statusArea && Main.panel.statusArea["appMenu"]) {
		appMenu = Main.panel.statusArea["appMenu"];
    } else if(Main.panel._appMenu) {
        appMenu = Main.panel._appMenu;
    } else if(Main.panel.statusArea["appMenu"]) {
        appMenu = Main.panel.statusArea["appMenu"];
	} else {
		appMenu = Main.panel.statusArea.appMenu;
	}

	focusCallbackID = Shell.WindowTracker.get_default().connect('notify::focus-app', onFocusChange);

	wmCallbackIDs.push(global.window_manager.connect('maximize', updateAppMenu));
	wmCallbackIDs.push(global.window_manager.connect('unmaximize', updateAppMenu));

	// note: 'destroy' needs a delay for .list_windows() report correctly
	wmCallbackIDs.push(global.window_manager.connect('destroy', function () {
		Mainloop.idle_add(updateAppMenu);
	}));

	tooltipCallbackID = appMenu.actor.connect('notify::hover', onHover);
}

function disable() {
	appMenu.actor.disconnect(tooltipCallbackID);

	Shell.WindowTracker.get_default().disconnect(focusCallbackID);
	focusCallbackID = 0;

	for (let i = 0; i < wmCallbackIDs.length; ++i) {
		global.window_manager.disconnect(wmCallbackIDs[i]);
	}

	wmCallbackIDs = [];

	if(activeWindow) {
		activeWindow.disconnect(awCallbackID);
		awCallbackID = 0;
		activeWindow = null;
	}

	if(tooltipDelayCallbackID) {
		Mainloop.source_remove(tooltipDelayCallbackID);
		tooltipDelayCallbackID = 0;
	}

	if(menuCallbackID) {
		appMenu.menu.disconnect(menuCallbackID);
		menuCallbackID = 0;
	}

	Main.uiGroup.remove_actor(tooltip);
}

<commit_msg>Fix indentation<commit_after>const Lang = imports.lang;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Util = Me.imports.util;

function LOG(message) {
	// log("[pixel-saver]: " + message);
}

function WARN(message) {
	log("[pixel-saver]: " + message);
}

let appMenu = null;

/*
 * AppMenu synchronization
 */
function updateAppMenu() {
	let win = global.display.focus_window;

	if(!win) {
		return false;
	}

	let title = win.title;

	// Not the topmost maximized window.
	if(win !== Util.getWindow()) {
		let app = Shell.WindowTracker.get_default().get_window_app(win);
		title = app.get_name();
	}

	LOG('Override title ' + title);
	appMenu._label.setText(title);
	tooltip.text = title;

	return false;
}

/*
 * Track the focused window's title
 */
let activeWindow = null;
let awCallbackID = 0;
function changeActiveWindow(win) {
	if(win === activeWindow) {
		return;
	}

	if(activeWindow) {
		activeWindow.disconnect(awCallbackID);
	}

	activeWindow = win;

	if(win) {
		awCallbackID = win.connect('notify::title', updateAppMenu);
		updateAppMenu();
	}
}

/*
 * Focus change
 */
function onFocusChange() {
	if (!Shell.WindowTracker.get_default().focus_app &&
		global.stage_input_mode == Shell.StageInputMode.FOCUSED) {
		// If the app has just lost focus to the panel, pretend
		// nothing happened; otherwise you can't keynav to the
		// app menu.
		return false;
	}

	changeActiveWindow(global.display.focus_window);
	return false;
}

/*
 * tooltip
 */
let tooltip = null;
let showTooltip = false;

let SHOW_DELAY = 350;
let SHOW_DURATION = 0.15;
let HIDE_DURATION = 0.1;

let tooltipDelayCallbackID = 0;
let menuCallbackID = 0;

function onHover(actor) {
	let hover = actor.get_hover();
	if(showTooltip === hover) {
		return false;
	}

	// We are not in the right state, let's fix that.
	showTooltip = hover;

	if (showTooltip) {
		tooltipDelayCallbackID = Mainloop.timeout_add(SHOW_DELAY, function() {
			if (!showTooltip) {
				WARN('showTooltip is false and delay callback ran.');
			}

			let label = appMenu._label._label;

			if(!label.get_clutter_text().get_layout().is_ellipsized()) {
				// Do not need to hide.
				tooltipDelayCallbackID = 0;
				return false;
			}

			Main.uiGroup.add_actor(tooltip);
			menuCallbackID = appMenu.menu.connect('open-state-changed', function(menu, open) {
				if(open) {
					Main.uiGroup.remove_actor(tooltip);
				} else {
					Main.uiGroup.add_actor(tooltip);
				}
			});

			[bx, by] = label.get_transformed_position();
			[w, h] = label.get_transformed_size();

			let y = by + h + 5;
			let x = bx - Math.round((tooltip.get_width() - w)/2);
			tooltip.opacity = 0;
			tooltip.set_position(x, y);

			LOG('show title tooltip');
			Tweener.removeTweens(tooltip);
			Tweener.addTween(tooltip, {
				opacity: 255,
				time: SHOW_DURATION,
				transition: 'easeOutQuad',
			});

			return false;
		});
	} else if(tooltipDelayCallbackID > 0) {
		if(!Mainloop.source_remove(tooltipDelayCallbackID)) {
			// If the event ran, then we hide.
			LOG('hide title tooltip');

			if(menuCallbackID) {
				appMenu.menu.disconnect(menuCallbackID);
				menuCallbackID = 0;
			}

			Tweener.removeTweens(tooltip);
			Tweener.addTween(tooltip, {
				opacity: 0,
				time: HIDE_DURATION,
				transition: 'easeOutQuad',
				onComplete: function() {
					Main.uiGroup.remove_actor(tooltip);
				}
			});
		}

		tooltipDelayCallbackID = 0;
	}

	return false;
}

/*
 * Subextension hooks
 */
function init() {
	tooltip = new St.Label({
		style_class: 'tooltip dash-label',
		text: ''
	});
}

let wmCallbackIDs = [];
let focusCallbackID = 0;
let tooltipCallbackID = 0;
function enable() {
	tooltip.opacity = 0;

	if(Main.panel.statusArea && Main.panel.statusArea["appMenu"]) {
		appMenu = Main.panel.statusArea["appMenu"];
	} else if(Main.panel._appMenu) {
		appMenu = Main.panel._appMenu;
	} else if(Main.panel.statusArea["appMenu"]) {
		appMenu = Main.panel.statusArea["appMenu"];
	} else {
		appMenu = Main.panel.statusArea.appMenu;
	}

	focusCallbackID = Shell.WindowTracker.get_default().connect('notify::focus-app', onFocusChange);

	wmCallbackIDs.push(global.window_manager.connect('maximize', updateAppMenu));
	wmCallbackIDs.push(global.window_manager.connect('unmaximize', updateAppMenu));

	// note: 'destroy' needs a delay for .list_windows() report correctly
	wmCallbackIDs.push(global.window_manager.connect('destroy', function () {
		Mainloop.idle_add(updateAppMenu);
	}));

	tooltipCallbackID = appMenu.actor.connect('notify::hover', onHover);
}

function disable() {
	appMenu.actor.disconnect(tooltipCallbackID);

	Shell.WindowTracker.get_default().disconnect(focusCallbackID);
	focusCallbackID = 0;

	for (let i = 0; i < wmCallbackIDs.length; ++i) {
		global.window_manager.disconnect(wmCallbackIDs[i]);
	}

	wmCallbackIDs = [];

	if(activeWindow) {
		activeWindow.disconnect(awCallbackID);
		awCallbackID = 0;
		activeWindow = null;
	}

	if(tooltipDelayCallbackID) {
		Mainloop.source_remove(tooltipDelayCallbackID);
		tooltipDelayCallbackID = 0;
	}

	if(menuCallbackID) {
		appMenu.menu.disconnect(menuCallbackID);
		menuCallbackID = 0;
	}

	Main.uiGroup.remove_actor(tooltip);
}

<|endoftext|>


<commit_before>'use strict';
var db = require("./auth.js");

var slugExists = function(slug, callable){
  db.url.findOne({"slug": slug}, function(error, doc){
    if (error) throw error;
    if(doc){
      generateSlug(callable);
    } else {
      callable(slug);
    }
  });
};

var findExistingUrl = function(url, callable){
  db.url.findOne({"url": url}, function(error, doc){
    if (error) throw error;
    if(doc){
      callable(doc.slug);
    }else {
      callable(false);
    }
  });
};

var generateSlug = function(callable){
  var lib = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  var slug = "";

  for(var i=0; i < Math.floor((Math.random() * 8)+1); i++)
    slug += lib.charAt(Math.floor(Math.random() * lib.length));

  slugExists(slug, callable);
};

exports.getUrl = function(request, response){
  db.url.findOne({"slug": request.params.id}, function(error, url){
    if(error){
      response.json(error);
    } else {
      response.json(url);
    }
  });
};

exports.addUrl = function(request, response){
  var urlRegex = /(http(s?)):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
  var urlLoopProtection = /\b(http(s?)):(\/\/|\/\/www.)tau\.pe\b/;
  var url = request.body.url;

  if(urlRegex.test(url) && false === urlLoopProtection.test(url)){
    findExistingUrl(url, function(existingSlug){
       if(existingSlug){
         response.json({"slug": existingSlug});
       } else {
         generateSlug(function(slug){
           db.url.insert({
             "url": url,
             "slug": slug,
             "date": Date.now()
           });
           response.json({"slug": slug});
         });
       }
    });
  }
};
<commit_msg>Update api.js<commit_after>'use strict';
var db = require("./auth.js");

var slugExists = function(slug, callable){
  db.url.findOne({"slug": slug}, function(error, doc){
    if (error) throw error;
    if(doc){
      generateSlug(callable);
    } else {
      callable(slug);
    }
  });
};

var findExistingUrl = function(url, callable){
  db.url.findOne({"url": url}, function(error, doc){
    if (error) throw error;
    if (doc) {
      callable(doc.slug);
    } else {
      callable(false);
    }
  });
};

var generateSlug = function(callable){
  var lib = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  var slug = "";

  for(var i=0; i < Math.floor((Math.random() * 8)+1); i++)
    slug += lib.charAt(Math.floor(Math.random() * lib.length));

  slugExists(slug, callable);
};

exports.getUrl = function(request, response){
  db.url.findOne({"slug": request.params.id}, function(error, url){
    if(error){
      response.json(error);
    } else {
      response.json(url);
    }
  });
};

exports.addUrl = function(request, response){
  var urlRegex = /(http(s?)):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
  var urlLoopProtection = /\b(http(s?)):(\/\/|\/\/www.)tau\.pe\b/;
  var url = request.body.url;

  if(urlRegex.test(url) && false === urlLoopProtection.test(url)){
    findExistingUrl(url, function(existingSlug){
       if(existingSlug){
         response.json({"slug": existingSlug});
       } else {
         generateSlug(function(slug){
           db.url.insert({
             "url": url,
             "slug": slug,
             "date": Date.now()
           });
           response.json({"slug": slug});
         });
       }
    });
  }
};
<|endoftext|>