<commit_before>'use strict';

var util = require('../util/util');
var async = require('async');
var _ = require('lodash');
var debug = require('debug')('formio:permissions');

module.exports = function(router) {
  var hook = require('../util/hook')(router.formio);

  // Add this access handlers for all to use.
  router.formio.access = {

    /**
     * Get the access for all defined entities.
     *
     * @param req {Object}
     *   The Express request Object.
     * @param res {Object}
     *   The Express request Object.
     * @param done
     *   The callback function to invoke after completion.
     *
     * @return
     *   The access object for the given form/sub id.
     */
    getAccess: function(req, res, done) {
      var access = {};
      async.series(hook.alter('getAccess', [
        // Get the permissions for a Form and Submissions with the given ObjectId.
        function getFormAccess(callback) {
          access.form = access.form || {};
          access.submission = access.submission || {};

          // Skip form access if no formId was given.
          if (!req.formId) {
            return callback(null);
          }

          // Load the form, and get its roles/permissions data.
          router.formio.cache.loadForm(req, null, req.formId, function(err, item) {
            if (err) {
              return callback(err);
            }
            if (!item) {
              return callback('No Form found with formId: ' + req.formId);
            }

            // Add the defined access types for the form.
            if (item.access) {
              // Add the submission owners UserId to the access list.
              access.form.owner = item.owner
                ? item.owner.toString()
                : null;

              item.access.forEach(function(permission) {
                // Define this access type.
                access.form[permission.type] = access.form[permission.type] || [];

                permission.roles.forEach(function(id) {
                  // Add each roleId to the role array for this access type.
                  access.form[permission.type].push(id.toString());
                });
              });
            }

            // Add the defined access types for the form submissions.
            if (item.submissionAccess) {
              item.submissionAccess.forEach(function(permission) {
                // Define this access type.
                access.submission[permission.type] = access.submission[permission.type] || [];

                permission.roles.forEach(function(id) {
                  // Add each roleId to the role array for this access type.
                  access.submission[permission.type].push(id.toString());
                });
              });
            }

            // Return the updated access list.
            return callback(null);
          });
        },

        // Get the permissions for a Submission with the given ObjectId.
        function getSubmissionAccess(callback) {
          access.submission = access.submission || {};

          // Skip submission access if no subId was given.
          if (!req.subId) {
            debug('Skipping submission access, no req.subId found.');
            return callback(null);
          }

          // Get the submission by request id and query its access.
          router.formio.cache.loadSubmission(req, req.formId, req.subId, function(err, submission) {
            if (err) {
              debug(err);
              return callback(400);
            }

            // No submission exists.
            if (!submission) {
              debug('No submission found w/ _id: ' + req.subId);
              return callback(404);
            }

            // Add the submission owners UserId to the access list.
            access.submission.owner = submission.owner
              ? submission.owner.toString()
              : null;

            // Return the updated access list.
            return callback(null);
          });
        }
      ], req, res, access), function(err) {
        if (err) {
          debug(err);
          return done(err);
        }

        // Load a specific role.
        var loadRole = function(name, query, done) {
          // Load the default role.
          access[name] = hook.alter(name, null, access);
          if (access[name]) {
            done(null, access);
          }
          else {

            // Load the default role.
            router.formio.resources.role.model.findOne(hook.alter('roleQuery', query, req), function(err, role) {
              if (err) {
                return done(err);
              }

              if (role) {
                access[name] = role._id.toString();
              }

              done(null, access);
            });
          }
        };

        // Load all of the applicable roles.
        async.series([
          async.apply(loadRole, 'defaultRole', {default: true}),
          async.apply(loadRole, 'adminRole', {admin: true})
        ], function(err) {
          if (err) {
            debug(err);
            return done(err);
          }

          done(null, access);
        });
      });
    },

    /**
     * Checks if the given set of roles has the permissions to perform the given method.
     *
     * @param req {Object}
     *   The Express request Object.
     * @param access {Object}
     *   An object of access with the associated roles.
     * @param entity {Object}
     *   The entity within the permissions object to use.
     *
     * @returns boolean
     *   If the user has access to this method, with their given roles.
     */
    hasAccess: function(req, access, entity) {
      var method = req.method.toUpperCase();

      // Determine the roles and user based on the available token.
      var roles = [access.defaultRole];
      var user = null;
      if(req.user) {
        user = req.user._id;

        // Get the roles for the permission checks.
        req.user.roles = req.user.roles || [];
        if(req.user.roles.length > 0) {
          debug('User Roles: ' + JSON.stringify(req.user.roles));

          // Ensure that all roles are strings to be compatible for comparison.
          roles = _.uniq(_.map(_.filter(req.user.roles), util.idToString));
        }
      }

      // Setup some flags for other handlers.
      req.isAdmin = false;

      // Check to see if this user has an admin role.
      var hasAdminRole = access.adminRole ? (_.indexOf(roles, access.adminRole) !== -1) : false;
      if (hasAdminRole || hook.alter('isAdmin', req.isAdmin, req)) {
        req.isAdmin = true;
        return true;
      }

      debug('Checking access for roles: ' + JSON.stringify(roles));
      debug('Checking access for access: ' + JSON.stringify(access));
      debug('Checking access for entity: ' + JSON.stringify(entity));
      debug('Checking access for method: ' + method);
      debug('Checking access for user: ' + user);

      // There should be an entity at this point.
      if (!entity) {
        return false;
      }

      // The return value of user access.
      var _hasAccess = false;

      // Allow anyone to hook and change the access entity.
      entity = hook.alter('accessEntity', entity, req);

      // Determine access based on the given access method.
      var methods = {
        'POST': ['create_all', 'create_own'],
        'GET': ['read_all', 'read_own'],
        'PUT': ['update_all', 'update_own'],
        'DELETE': ['delete_all', 'delete_own']
      };

      // Check if the user making the request owns the entity being requested.
      if (
        user
        && access.hasOwnProperty(entity.type)
        && access[entity.type].hasOwnProperty('owner')
        && req.token.user._id === access[entity.type].owner
      ) {
        _hasAccess = true;
      }

      // Using the given method, iterate the 8 available entity access. Compare the given roles with the roles
      // defined by the entity to have access. If this roleId is found within the defined roles, grant access.
      var search = methods[method];

      if (!search || typeof search === 'undefined') {
        console.error({
          method: req.method,
          _method: method
        });
      }

      search.forEach(function(type) {
        // Check if the given roles are contained within the allowed roles for our
        roles.forEach(function(role) {
          // Grant access if the role was found in the access for this resource.
          if (
            access.hasOwnProperty(entity.type)
            && access[entity.type].hasOwnProperty(type)
            && access[entity.type][type] instanceof Array
            && access[entity.type][type].indexOf(role) !== -1
          ) {
            // Allow anonymous users to create a submission for themselves if defined.
            if (type === 'create_own') {
              _hasAccess = true;
            }
            else if (type.toString().indexOf('_own') !== -1) {
              // Entity has an owner, Request is from a User, and the User is the Owner.
              if (access[entity.type].hasOwnProperty('owner') && user && access[entity.type].owner === user) {
                _hasAccess = true;
              }
              // Exception for Index endpoint, the
              else if (type === 'read_own' && !Boolean(entity.id) && entity.id === '') {
                // The user has access to this endpoint, however the results will need to be filtered by the
                // ownerFilter middleware.
                _hasAccess = true;
              }
            }
            else {
              // Only allow the the bootstrapEntityOwner middleware to assign an owner if defined in the payload.
              if (
                (type === 'create_all' || type === 'update_all')
                && req.body
                && req.body.hasOwnProperty('owner')
                && req.body.owner
              ) {
                req.assignOwner = true;
              }

              // No ownership requirements here.
              req.skipOwnerFilter = true;
              _hasAccess = true;
            }
          }
        });
      });

      // No prior access was granted, the given role does not have access to this resource using the given method.
      debug('assignOwner: ' + req.assignOwner);
      debug('hasAccess: ' + _hasAccess);
      return hook.alter('hasAccess', _hasAccess, req, access, entity);
    }
  };

  /**
   * The Form.io permissions middleware.
   *
   * This middleware will confirm that the request has permissions to perform its request.
   *
   * @param req {Object}
   *   The Express request Object.
   * @param res {Object}
   *   The Express request Object.
   * @param next {Function}
   *   The callback function to invoke after completion.
   */
  return function permissionHandler(req, res, next) {
    // Check for whitelisted paths.
    var whitelist = ['/health', '/current', '/logout'];
    var skip = _.any(whitelist, function(path) {
      if ((req.url === path) || (req.url === hook.alter('url', path, req))) return true;
      return false;
    });

    debug(req.url);

    // If there is a whitelist match, then move onto the next middleware.
    if (skip) {
      debug('Skipping');
      return next();
    }

    // Determine if we are trying to access and entity of the form or submission.
    router.formio.access.getAccess(req, res, function(err, access) {
      if (err) {
        debug(err);
        return res.status(400).send(err.message || err);
      }

      // Check for permissions starting at micro -> macro level.
      var entity = null;
      if (req.hasOwnProperty('subId') && ((req.subId !== null) && (req.subId !== undefined))) {
        debug('Checking access for the Submission.');
        entity = {
          type: 'submission',
          id: req.subId
        };
      }
      else if (req.hasOwnProperty('formId') && ((req.formId !== null) && (req.formId !== undefined))) {
        debug('Checking access for the Form.');
        entity = {
          type: 'form',
          id: req.formId
        };
      }

      // Check for access.
      if (
        (router.formio.access.hasAccess(req, access, entity)) ||
        (hook.alter('access', false, req, access))
      ) {
        debug('Access Granted!');
        return next();
      }

      // If someone else before this sent the status, then go to the next middleware.
      debug('Access Denied!');
      return res.headersSent ? next() : res.sendStatus(401);
    });
  };
};
<commit_msg>Adding namespaced debugging to access middleware.<commit_after>'use strict';

var util = require('../util/util');
var async = require('async');
var _ = require('lodash');
var debug = require('debug')('formio:permissions');

module.exports = function(router) {
  var hook = require('../util/hook')(router.formio);

  // Add this access handlers for all to use.
  router.formio.access = {

    /**
     * Get the access for all defined entities.
     *
     * @param req {Object}
     *   The Express request Object.
     * @param res {Object}
     *   The Express request Object.
     * @param done
     *   The callback function to invoke after completion.
     *
     * @return
     *   The access object for the given form/sub id.
     */
    getAccess: function(req, res, done) {
      var access = {};
      async.series(hook.alter('getAccess', [
        // Get the permissions for a Form and Submissions with the given ObjectId.
        function getFormAccess(callback) {
          var _debug = require('debug')('formio:permissions:getAccess#getFormAccess');

          access.form = access.form || {};
          access.submission = access.submission || {};

          // Skip form access if no formId was given.
          if (!req.formId) {
            _debug('Skipping, no req.formId');
            return callback(null);
          }

          // Load the form, and get its roles/permissions data.
          router.formio.cache.loadForm(req, null, req.formId, function(err, item) {
            if (err) {
              _debug(err);
              return callback(err);
            }
            if (!item) {
              _debug('No Form found with formId: ' + req.formId)
              return callback('No Form found with formId: ' + req.formId);
            }

            // Add the defined access types for the form.
            if (item.access) {
              // Add the submission owners UserId to the access list.
              access.form.owner = item.owner
                ? item.owner.toString()
                : null;

              item.access.forEach(function(permission) {
                // Define this access type.
                access.form[permission.type] = access.form[permission.type] || [];

                permission.roles.forEach(function(id) {
                  // Add each roleId to the role array for this access type.
                  access.form[permission.type].push(id.toString());
                });
              });
            }

            // Add the defined access types for the form submissions.
            if (item.submissionAccess) {
              item.submissionAccess.forEach(function(permission) {
                // Define this access type.
                access.submission[permission.type] = access.submission[permission.type] || [];

                permission.roles.forEach(function(id) {
                  // Add each roleId to the role array for this access type.
                  access.submission[permission.type].push(id.toString());
                });
              });
            }

            // Return the updated access list.
            _debug(JSON.stringify(access));
            return callback(null);
          });
        },

        // Get the permissions for a Submission with the given ObjectId.
        function getSubmissionAccess(callback) {
          var _debug = require('debug')('formio:permissions:getAccess#getSubmissionAccess');
          access.submission = access.submission || {};

          // Skip submission access if no subId was given.
          if (!req.subId) {
            _debug('Skipping, no req.subId');
            return callback(null);
          }

          // Get the submission by request id and query its access.
          router.formio.cache.loadSubmission(req, req.formId, req.subId, function(err, submission) {
            if (err) {
              _debug(err);
              return callback(400);
            }

            // No submission exists.
            if (!submission) {
              _debug('No submission found w/ _id: ' + req.subId);
              return callback(404);
            }

            // Add the submission owners UserId to the access list.
            access.submission.owner = submission.owner
              ? submission.owner.toString()
              : null;

            // Return the updated access list.
            _debug(JSON.stringify(access));
            return callback(null);
          });
        }
      ], req, res, access), function(err) {
        if (err) {
          debug(err);
          return done(err);
        }

        // Load a specific role.
        var loadRole = function(name, query, done) {
          // Load the default role.
          access[name] = hook.alter(name, null, access);
          if (access[name]) {
            done(null, access);
          }
          else {

            // Load the default role.
            router.formio.resources.role.model.findOne(hook.alter('roleQuery', query, req), function(err, role) {
              if (err) {
                return done(err);
              }

              if (role) {
                access[name] = role._id.toString();
              }

              done(null, access);
            });
          }
        };

        // Load all of the applicable roles.
        async.series([
          async.apply(loadRole, 'defaultRole', {default: true}),
          async.apply(loadRole, 'adminRole', {admin: true})
        ], function(err) {
          if (err) {
            debug(err);
            return done(err);
          }

          done(null, access);
        });
      });
    },

    /**
     * Checks if the given set of roles has the permissions to perform the given method.
     *
     * @param req {Object}
     *   The Express request Object.
     * @param access {Object}
     *   An object of access with the associated roles.
     * @param entity {Object}
     *   The entity within the permissions object to use.
     *
     * @returns boolean
     *   If the user has access to this method, with their given roles.
     */
    hasAccess: function(req, access, entity) {
      var method = req.method.toUpperCase();

      // Determine the roles and user based on the available token.
      var roles = [access.defaultRole];
      var user = null;
      if(req.user) {
        user = req.user._id;

        // Get the roles for the permission checks.
        req.user.roles = req.user.roles || [];
        if(req.user.roles.length > 0) {
          debug('User Roles: ' + JSON.stringify(req.user.roles));

          // Ensure that all roles are strings to be compatible for comparison.
          roles = _.uniq(_.map(_.filter(req.user.roles), util.idToString));
        }
      }

      // Setup some flags for other handlers.
      req.isAdmin = false;

      // Check to see if this user has an admin role.
      var hasAdminRole = access.adminRole ? (_.indexOf(roles, access.adminRole) !== -1) : false;
      if (hasAdminRole || hook.alter('isAdmin', req.isAdmin, req)) {
        req.isAdmin = true;
        return true;
      }

      debug('Checking access for roles: ' + JSON.stringify(roles));
      debug('Checking access for access: ' + JSON.stringify(access));
      debug('Checking access for entity: ' + JSON.stringify(entity));
      debug('Checking access for method: ' + method);
      debug('Checking access for user: ' + user);

      // There should be an entity at this point.
      if (!entity) {
        return false;
      }

      // The return value of user access.
      var _hasAccess = false;

      // Allow anyone to hook and change the access entity.
      entity = hook.alter('accessEntity', entity, req);

      // Determine access based on the given access method.
      var methods = {
        'POST': ['create_all', 'create_own'],
        'GET': ['read_all', 'read_own'],
        'PUT': ['update_all', 'update_own'],
        'DELETE': ['delete_all', 'delete_own']
      };

      // Check if the user making the request owns the entity being requested.
      if (
        user
        && access.hasOwnProperty(entity.type)
        && access[entity.type].hasOwnProperty('owner')
        && req.token.user._id === access[entity.type].owner
      ) {
        _hasAccess = true;
      }

      // Using the given method, iterate the 8 available entity access. Compare the given roles with the roles
      // defined by the entity to have access. If this roleId is found within the defined roles, grant access.
      var search = methods[method];

      if (!search || typeof search === 'undefined') {
        console.error({
          method: req.method,
          _method: method
        });
      }

      search.forEach(function(type) {
        // Check if the given roles are contained within the allowed roles for our
        roles.forEach(function(role) {
          // Grant access if the role was found in the access for this resource.
          if (
            access.hasOwnProperty(entity.type)
            && access[entity.type].hasOwnProperty(type)
            && access[entity.type][type] instanceof Array
            && access[entity.type][type].indexOf(role) !== -1
          ) {
            // Allow anonymous users to create a submission for themselves if defined.
            if (type === 'create_own') {
              _hasAccess = true;
            }
            else if (type.toString().indexOf('_own') !== -1) {
              // Entity has an owner, Request is from a User, and the User is the Owner.
              if (access[entity.type].hasOwnProperty('owner') && user && access[entity.type].owner === user) {
                _hasAccess = true;
              }
              // Exception for Index endpoint, the
              else if (type === 'read_own' && !Boolean(entity.id) && entity.id === '') {
                // The user has access to this endpoint, however the results will need to be filtered by the
                // ownerFilter middleware.
                _hasAccess = true;
              }
            }
            else {
              // Only allow the the bootstrapEntityOwner middleware to assign an owner if defined in the payload.
              if (
                (type === 'create_all' || type === 'update_all')
                && req.body
                && req.body.hasOwnProperty('owner')
                && req.body.owner
              ) {
                req.assignOwner = true;
              }

              // No ownership requirements here.
              req.skipOwnerFilter = true;
              _hasAccess = true;
            }
          }
        });
      });

      // No prior access was granted, the given role does not have access to this resource using the given method.
      debug('assignOwner: ' + req.assignOwner);
      debug('hasAccess: ' + _hasAccess);
      return hook.alter('hasAccess', _hasAccess, req, access, entity);
    }
  };

  /**
   * The Form.io permissions middleware.
   *
   * This middleware will confirm that the request has permissions to perform its request.
   *
   * @param req {Object}
   *   The Express request Object.
   * @param res {Object}
   *   The Express request Object.
   * @param next {Function}
   *   The callback function to invoke after completion.
   */
  return function permissionHandler(req, res, next) {
    // Check for whitelisted paths.
    var whitelist = ['/health', '/current', '/logout'];
    var skip = _.any(whitelist, function(path) {
      if ((req.url === path) || (req.url === hook.alter('url', path, req))) return true;
      return false;
    });

    debug(req.url);

    // If there is a whitelist match, then move onto the next middleware.
    if (skip) {
      debug('Skipping');
      return next();
    }

    // Determine if we are trying to access and entity of the form or submission.
    router.formio.access.getAccess(req, res, function(err, access) {
      if (err) {
        debug(err);
        return res.status(400).send(err.message || err);
      }

      // Check for permissions starting at micro -> macro level.
      var entity = null;
      if (req.hasOwnProperty('subId') && ((req.subId !== null) && (req.subId !== undefined))) {
        debug('Checking access for the Submission.');
        entity = {
          type: 'submission',
          id: req.subId
        };
      }
      else if (req.hasOwnProperty('formId') && ((req.formId !== null) && (req.formId !== undefined))) {
        debug('Checking access for the Form.');
        entity = {
          type: 'form',
          id: req.formId
        };
      }

      // Check for access.
      if (
        (router.formio.access.hasAccess(req, access, entity)) ||
        (hook.alter('access', false, req, access))
      ) {
        debug('Access Granted!');
        return next();
      }

      // If someone else before this sent the status, then go to the next middleware.
      debug('Access Denied!');
      return res.headersSent ? next() : res.sendStatus(401);
    });
  };
};
<|endoftext|>


<commit_before>//  1. Enter sheet name where data is to be written below
var SHEET_NAME = "Sheet1";

//  2. Run > setup
//
//  3. Publish > Deploy as web app
//    - enter Project Version name and click 'Save New Version'
//    - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously)
//
//  4. Copy the 'Current web app URL' and post this in your form/script action
//
//  5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)

var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service

// If you don't want to expose either GET or POST methods you can comment out the appropriate function
function doGet(e) {
  return handleResponse(e, "get", e.queryString);
}

function doPost(e) {
  return handleResponse(e, "post");
}

function handleResponse(e, type, check) {
  // shortly after my original solution Google announced the LockService[1]
  // this prevents concurrent access overwritting data
  // [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
  // we want a public lock, one that locks for all invocations
  var lock = LockService.getPublicLock();
  lock.waitLock(30000);  // wait 30 seconds before conceding defeat.
  type = type || "none";
  check = check || "bad";
  try {
    // next set where we write the data - you could write to multiple/alternate destinations
    var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
    var sheet = doc.getSheetByName(SHEET_NAME);

    // we'll assume header is in row 1 but you can override with header_row in GET/POST data
    var start_row = e.parameter.start_row || 2; // if data has header, 2; if not, set 1.

    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    var nextRow = sheet.getLastRow() + 1; // get next row
    var ret = [];

    if (type == "get" && check != "bad") {
      var row = sheet.getRange(start_row, 1, sheet.getLastRow() - 1, headers.length).getValues();
      row.forEach(function(column) {
        var temp = {};
        column.forEach(function(element, index) {
          temp[headers[index]] = element
        })
        ret.push(temp);
      })

      // return json success results
      return (
        ContentService.createTextOutput(JSON.stringify({"result":"success", "type": type, "row": nextRow, "output": ret}))
        .setMimeType(ContentService.MimeType.JSON)
      );
    }
    else if (type == "post") {
      // loop through the header columns
      headers.forEach(function(header) {
        if (header == "Timestamp"){ // special case if you include a 'Timestamp' column
          ret.push(new Date());
        } else { // else use header name to get data
          ret.push(e.parameter[header]);
        }
      })
      // more efficient to set values as [][] array than individually
      sheet.getRange(nextRow, 1, 1, ret.length).setValues([ret]); // insert the data
      // return json success results
      return (
        ContentService.createTextOutput(JSON.stringify({"result":"success", "type": type, "row": nextRow, "insert": ret}))
        .setMimeType(ContentService.MimeType.JSON)
      );
    }
    else {
      return (
        ContentService.createTextOutput(JSON.stringify({"result":"error", "type": type, "reason": "no authority"}))
        .setMimeType(ContentService.MimeType.JSON)
      );
    }
  } catch(e){
    // if error return this
    return ContentService
          .createTextOutput(JSON.stringify({"result":"error", "error": e}))
          .setMimeType(ContentService.MimeType.JSON);
  } finally { //release lock
    lock.releaseLock();
  }
}

function setup() {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  SCRIPT_PROP.setProperty("key", doc.getId());
}<commit_msg>增加身份驗證、修改資料功能(限人名皆不同)<commit_after>//  1. Enter sheet name where data is to be written below
var SHEET_NAME = "Sheet1";

//  2. Run > setup
//
//  3. Publish > Deploy as web app
//    - enter Project Version name and click 'Save New Version'
//    - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously)
//
//  4. Copy the 'Current web app URL' and post this in your form/script action
//
//  5. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)

var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service

// If you don't want to expose either GET or POST methods you can comment out the appropriate function
function doGet(e) {
  return handleResponse(e, "get", e.queryString);
}

function doPost(e) {
  return handleResponse(e, "post");
}

function handleResponse(e, type, check) {
  /*e = {
    姓名: "崔家華",
    信箱: "st880221@gmail.com",
  Avatar: 123,
  Github: 321,
  Demopage: 123,
  Info: "test"
  };*/
  // shortly after my original solution Google announced the LockService[1]
  // this prevents concurrent access overwritting data
  // [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
  // we want a public lock, one that locks for all invocations
  var lock = LockService.getPublicLock();
  lock.waitLock(30000);  // wait 30 seconds before conceding defeat.
  type = type || "none";
  check = check || "bad";
  try {
    // next set where we write the data - you could write to multiple/alternate destinations
    var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
    var sheet = doc.getSheetByName(SHEET_NAME);

    // we'll assume header is in row 1 but you can override with header_row in GET/POST data
    var start_row = e.parameter.start_row || 2; // if data has header, 2; if not, set 1.

    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    var nextRow = sheet.getLastRow() + 1; // get next row
    var ret = [];

    if (type == "get" && check != "bad") {
      var row = sheet.getRange(start_row, 1, sheet.getLastRow() - 1, headers.length).getValues();
      row.forEach(function(column) {
        var temp = {};
        column.forEach(function(element, index) {
          temp[headers[index]] = element
        })
        ret.push(temp);
      })
      return (
        ContentService.createTextOutput(JSON.stringify({"result":"success", "type": type, "row": nextRow, "output": ret}))
        .setMimeType(ContentService.MimeType.JSON)
      );
    }
    else if (type == "post") {
      var obj = e.parameter;
      var arr = [];
      if (CheckPostIsActualModify(obj) != -1) {
        var ret_row = CheckPostIsActualModify(obj);
        var email_column = getEmailColumn();
        if (checkInfoCorrespond(ret_row, email_column, obj["信箱"])) {
          for(var key in obj) {
            for(var i = 0; i < headers.length; i++) {
              if (key == headers[i]) {
                arr.push(i + 1);
                break;
              }
            }
          }
          var keys = Object.keys(obj);
          for(var i = 0; i < keys.length; i++) {
            var key = keys[i];
            sheet.getRange(temp_row, arr[i], 1, 1).setValue(obj[key]);
          }
          return (
            ContentService.createTextOutput(JSON.stringify({"result":"success", "type": "modify"}))
            .setMimeType(ContentService.MimeType.JSON)
          );
        }
        else {
          return (
            ContentService.createTextOutput(JSON.stringify({"result":"error", "type": "modify", "reason": "Authentication failed"}))
            .setMimeType(ContentService.MimeType.JSON)
          );
        }
      }
      else {
        // loop through the header columns
        headers.forEach(function(header) {
          if (header == "Timestamp"){ // special case if you include a 'Timestamp' column
            ret.push(new Date());
          } else { // else use header name to get data
            ret.push(e.parameter[header]);
          }
        })
        // more efficient to set values as [][] array than individually
        sheet.getRange(nextRow, 1, 1, ret.length).setValues([ret]); // insert the data
        // return json success results
        return (
          ContentService.createTextOutput(JSON.stringify({"result":"success", "type": type, "row": nextRow, "insert": ret}))
          .setMimeType(ContentService.MimeType.JSON)
        );
      }
    }
    else {
      return (
        ContentService.createTextOutput(JSON.stringify({"result":"error", "type": type, "reason": "Permission denied"}))
        .setMimeType(ContentService.MimeType.JSON)
      );
    }
  } catch(e){
    // if error return this
    return ContentService
          .createTextOutput(JSON.stringify({"result":"error", "error": e}))
          .setMimeType(ContentService.MimeType.JSON);
  } finally { //release lock
    lock.releaseLock();
  }
}

function setup() {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  SCRIPT_PROP.setProperty("key", doc.getId());
}

function CheckPostIsActualModify(obj) {
  /*obj = {
    姓名: "崔家華",
    信箱: "st880221@gmail.com",
  Avatar: 123,
  Github: 321,
  Demopage: 123,
  Info: "test"
  };*/
  var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
  var sheet = doc.getSheetByName(SHEET_NAME);
  var rows = sheet.getLastRow();
  var columns = sheet.getLastColumn();
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  var name_column = getNameColumn();

  for(var i = 2; i <= rows; i++) {
    var value = sheet.getRange(i, name_column, 1, 1).getValue();
    if (value == obj["姓名"]) {
      return i;
    }
  }
  return -1; // 找不到
}

function checkInfoCorrespond(row, email_column, email) {
  var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
  var sheet = doc.getSheetByName(SHEET_NAME);
  var true_email = sheet.getRange(row, email_column, 1, 1).getValue();
  if (true_email == email)
    return true;
  else
    return false;
}

function getNameColumn() {
  var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
  var sheet = doc.getSheetByName(SHEET_NAME);
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  for(var i = 0; i < headers.length; i++) {
    if (headers[i] == "姓名") return i + 1;
  }
  return -1;
}

function getEmailColumn() {
   var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
  var sheet = doc.getSheetByName(SHEET_NAME);
  var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  for(var i = 0; i < headers.length; i++) {
    if (headers[i] == "信箱") return i + 1;
  }
  return -1;
}<|endoftext|>


<commit_before>casper.test.comment('Widget - File preview');

/**
 * Verifies that the default preview is shown for content items without preview
 */
var verifyDefaultPreview = function() {
    casper.waitForSelector('#filepreview-container', function() {
        casper.test.assertExists('#filepreview-container', 'The file preview container is present');
        casper.test.assertExists('#filepreview-container #filepreview-default-container', 'The default container is present');
        casper.test.assertExists('#filepreview-container #filepreview-default-container #filepreview-default-download', 'The download button is showing in the default preview');
    });
};

/**
 * Verifies that a file preview is shown on the content profile page
 */
var verifyFilePreview = function() {
    casper.waitForSelector('#filepreview-container', function() {
        casper.test.assertExists('#filepreview-container', 'The file preview container is present');
        casper.test.assertExists('#filepreview-container #filepreview-image-container', 'The image container is present');
        casper.test.assertExists('#filepreview-container #filepreview-image-container img', 'The image is shown on the content profile page');
    });
};

/**
 * Verifies that a video preview is shown on the content profile page
 */
var verifyVideoPreview = function() {
    casper.waitForSelector('#filepreview-container', function() {
        casper.test.assertExists('#filepreview-container', 'The file preview container is present');
        casper.test.assertExists('#filepreview-container #filepreview-video-container', 'The video container is present');
        casper.test.assertExists('#filepreview-container #filepreview-video-container #filepreview-video', 'The video is shown on the content profile page');
    });
};

/**
 * Verifies that the etherpad document is shown on the content profile page and that viewers cannot edit the document
 */
var verifyCollabDocPreview = function(username, documentURL) {
    casper.waitForSelector('#etherpad-container', function() {
        casper.test.assertExists('#etherpad-container', 'The etherpad container is present');
        casper.test.assertExists('#etherpad-container #etherpad-edit-mode', 'The etherpad edit mode is present for other manager');
        casper.test.assertExists('#etherpad-container iframe#etherpad-editor', 'The etherpad iframe is present');
        userUtil().doLogOut();
        userUtil().doLogIn(username, 'password');
        casper.thenOpen(documentURL, function() {
            casper.waitForSelector('#etherpad-container', function() {
                casper.test.assertExists('#etherpad-container', 'The etherpad container is present for viewer');
                casper.test.assertExists('#etherpad-container #etherpad-view-mode', 'The etherpad view mode is present for viewer');
                casper.test.assertDoesntExist('#etherpad-container iframe#etherpad-editor', 'The etherpad edit iframe is not present for viewer');
            });
        });
    });
};

casper.start('http://test.oae.com', function() {
    // Create a couple of users to test with
    var user1 = null;
    var user2 = null;
    userUtil().createUsers(2, function(users) {
        user1 = users[0];
        user2 = users[1];
    });

    // Log in with that user
    casper.then(function() {
        userUtil().doLogIn(user1.username, 'password');
    });

    // Verify default previews
    casper.then(function() {
        casper.echo('Verify default preview elements present', 'INFO');
        contentUtil().createFile('tests/casperjs/data/apereo.zip', function(contentURL) {
            casper.thenOpen('http://test.oae.com' + contentURL);

            casper.then(function() {
                verifyDefaultPreview();
            });
        });
    });

    // Verify image previews
    casper.then(function() {
        casper.echo('Verify image preview elements present', 'INFO');
        contentUtil().createFile(null, function(contentURL) {
            casper.thenOpen('http://test.oae.com' + contentURL);

            casper.then(function() {
                verifyFilePreview();
            });
        });
    });

    // Verify video previews
    casper.then(function() {
        casper.echo('Verify video preview elements present', 'INFO');
        contentUtil().createFile('tests/casperjs/data/sample-video.mp4', function(contentURL) {
            casper.thenOpen('http://test.oae.com' + contentURL);

            casper.then(function() {
                verifyVideoPreview();
            });
        });
    });

    // Verify collaborative document previews
    casper.then(function() {
        casper.echo('Verify collaborative document preview elements present', 'INFO');
        collabDocUtil().createCollabDoc(function(collabDoc) {
            casper.thenOpen('http://test.oae.com' + collabDoc.profilePath);

            casper.then(function() {
                verifyCollabDocPreview(user2.username, 'http://test.oae.com' + collabDoc.profilePath);
            });
        });
    });

    // Log out at the end of the test
    casper.then(function() {
        userUtil().doLogOut();
    });
});

casper.run(function() {
    this.test.done();
});
<commit_msg>Fix failing filepreview test<commit_after>casper.test.comment('Widget - File preview');

/**
 * Verifies that a file preview is shown on the content profile page
 */
var verifyFilePreview = function() {
    casper.waitForSelector('#filepreview-container', function() {
        casper.test.assertExists('#filepreview-container', 'The file preview container is present');
        casper.test.assertExists('#filepreview-container #filepreview-image-container', 'The image container is present');
        casper.test.assertExists('#filepreview-container #filepreview-image-container img', 'The image is shown on the content profile page');
    });
};

/**
 * Verifies that a video preview is shown on the content profile page
 */
var verifyVideoPreview = function() {
    casper.waitForSelector('#filepreview-container', function() {
        casper.test.assertExists('#filepreview-container', 'The file preview container is present');
        casper.test.assertExists('#filepreview-container #filepreview-video-container', 'The video container is present');
        casper.test.assertExists('#filepreview-container #filepreview-video-container #filepreview-video', 'The video is shown on the content profile page');
    });
};

/**
 * Verifies that the etherpad document is shown on the content profile page and that viewers cannot edit the document
 */
var verifyCollabDocPreview = function(username, documentURL) {
    casper.waitForSelector('#etherpad-container', function() {
        casper.test.assertExists('#etherpad-container', 'The etherpad container is present');
        casper.test.assertExists('#etherpad-container #etherpad-edit-mode', 'The etherpad edit mode is present for other manager');
        casper.test.assertExists('#etherpad-container iframe#etherpad-editor', 'The etherpad iframe is present');
        userUtil().doLogOut();
        userUtil().doLogIn(username, 'password');
        casper.thenOpen(documentURL, function() {
            casper.waitForSelector('#etherpad-container', function() {
                casper.test.assertExists('#etherpad-container', 'The etherpad container is present for viewer');
                casper.test.assertExists('#etherpad-container #etherpad-view-mode', 'The etherpad view mode is present for viewer');
                casper.test.assertDoesntExist('#etherpad-container iframe#etherpad-editor', 'The etherpad edit iframe is not present for viewer');
            });
        });
    });
};

casper.start('http://test.oae.com', function() {
    // Create a couple of users to test with
    var user1 = null;
    var user2 = null;
    userUtil().createUsers(2, function(users) {
        user1 = users[0];
        user2 = users[1];
    });

    // Log in with that user
    casper.then(function() {
        userUtil().doLogIn(user1.username, 'password');
    });

    // Verify image previews
    casper.then(function() {
        casper.echo('Verify image preview elements present', 'INFO');
        contentUtil().createFile(null, function(contentURL) {
            casper.thenOpen('http://test.oae.com' + contentURL);

            casper.then(function() {
                verifyFilePreview();
            });
        });
    });

    // Verify video previews
    casper.then(function() {
        casper.echo('Verify video preview elements present', 'INFO');
        contentUtil().createFile('tests/casperjs/data/sample-video.mp4', function(contentURL) {
            casper.thenOpen('http://test.oae.com' + contentURL);

            casper.then(function() {
                verifyVideoPreview();
            });
        });
    });

    // Verify collaborative document previews
    casper.then(function() {
        casper.echo('Verify collaborative document preview elements present', 'INFO');
        collabDocUtil().createCollabDoc(function(collabDoc) {
            casper.thenOpen('http://test.oae.com' + collabDoc.profilePath);

            casper.then(function() {
                verifyCollabDocPreview(user2.username, 'http://test.oae.com' + collabDoc.profilePath);
            });
        });
    });

    // Log out at the end of the test
    casper.then(function() {
        userUtil().doLogOut();
    });
});

casper.run(function() {
    this.test.done();
});
<|endoftext|>


<commit_before>/**
 * Created by cbrownroberts on 9/13/16.
 */
function bookList() {

    "use strict";

    var myBookList = {

        settings: {},
        strings: {},
        bindUiActions: function () {
            myBookList.iterateUrls();
        },
            init: function () {
                myBookList.bindUiActions();

                var isotopeScript = "http://unpkg.com/isotope-layout@3.0.1/dist/isotope.pkgd.min.js";

                //get script
                $.getScript(isotopeScript, function(){
                    $("head").append("


<commit_before>function nl2br (str, is_xhtml) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Philip Peterson
    // +   improved by: Onno Marsman
    // +   improved by: Atli Þór
    // +   bugfixed by: Onno Marsman
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Maximusya
    // *     example 1: nl2br('Kevin\nvan\nZonneveld');
    // *     returns 1: 'Kevin
\nvan
\nZonneveld'
    // *     example 2: nl2br("\nOne\nTwo\n\nThree\n", false);
    // *     returns 2: '
\nOne
\nTwo
\n
\nThree
\n'
    // *     example 3: nl2br("\nOne\nTwo\n\nThree\n", true);
    // *     returns 3: '
\nOne
\nTwo
\n
\nThree
\n'
    var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '
' : '
';

    return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
}
<commit_msg>Slight formatting change for sake of website display<commit_after>function nl2br (str, is_xhtml) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Philip Peterson
    // +   improved by: Onno Marsman
    // +   improved by: Atli Þór
    // +   bugfixed by: Onno Marsman
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Maximusya
    // *     example 1: nl2br('Kevin\nvan\nZonneveld');
    // *     returns 1: 'Kevin
\nvan
\nZonneveld'
    // *     example 2: nl2br("\nOne\nTwo\n\nThree\n", false);
    // *     returns 2: '
\nOne
\nTwo
\n
\nThree
\n'
    // *     example 3: nl2br("\nOne\nTwo\n\nThree\n", true);
    // *     returns 3: '
\nOne
\nTwo
\n
\nThree
\n'
    var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '
' : '
'; // Adjust comment to avoid issue on phpjs.org display

    return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
}
<|endoftext|>


<commit_before>// @flow

import React from 'react'
import type {CourseType} from '../../../../lib/course-search'
import glamorous from 'glamorous-native'
import {Badge} from '../../../building-hours/detail/badge'
import {TableView, Section, Cell} from 'react-native-tableview-simple'
import {convertTimeStringsToOfferings} from 'sto-sis-time-parser'
import moment from 'moment-timezone'
import {formatDay} from '../lib/format-day'
import {MultiLineDetailCell} from '../../components/multi-line-cell'
import type {TopLevelViewPropsType} from '../../../types'

const Container = glamorous.scrollView({
	paddingVertical: 6,
})

const Header = glamorous.text({
	fontSize: 36,
	textAlign: 'center',
	marginTop: 20,
	marginHorizontal: 10,
})

const SubHeader = glamorous.text({
	fontSize: 21,
	textAlign: 'center',
	marginTop: 5,
})

const CellText = glamorous.text({
	padding: 5,
})

function Information({course}: {course: CourseType}) {
	const profs = course.instructors ? course.instructors.join(', ') : null
	const instructors = course.instructors ? (
		<Cell cellStyle="LeftDetail" detail="Instructor(s)" title={profs} />
	) : null
	const gereqs = course.gereqs ? course.gereqs.join(', ') : null
	const ges = course.gereqs ? (
		<Cell cellStyle="LeftDetail" detail="GEs" title={gereqs} />
	) : null
	const credits = course.credits ? (
		<Cell cellStyle="LeftDetail" detail="Credits" title={course.credits} />
	) : null
	const type = <Cell cellStyle="LeftDetail" detail="Type" title={course.type} />
	const passFail = course.pn ? 'Yes' : 'No'
	const pn = <Cell cellStyle="LeftDetail" detail="Pass/Fail" title={passFail} />
	const prerequisites = course.prerequisites ?
		course.prerequisites.replace("Prerequisite: ", "") : 'None'

	const prereqs = <Cell cellStyle="LeftDetail" detail="Prerequisites" title={prerequisites} />
	return (

			{instructors}
			{type}
			{ges}
			{pn}
			{prereqs}
			{credits}

	)
}

function Schedule({course}: {course: CourseType}) {
	if (!course.times) {
		return null
	}
	const times = convertTimeStringsToOfferings({times: course.times})
	const schedule = times.map(time => {
		const hours = time.times.map(time => {
			const start = moment(time.start, 'hmm').format('h:mm A')
			const end = moment(time.end, 'hmm').format('h:mm A')
			return `${start} - ${end}`
		})
		const allHours = hours.join('\n')
		const day = formatDay(time.day)
		return <MultiLineDetailCell key={time.day} detail={allHours} title={day} />
	})

	return
{schedule}

}

function Description({course}: {course: CourseType}) {
	return course.description ? (

			<Cell cellContentView={<CellText>{course.description[0]}</CellText>} />

	) : null
}

type Props = TopLevelViewPropsType & {
	navigation: {state: {params: {course: CourseType}}},
}

export class CourseDetailView extends React.PureComponent<Props> {
	static navigationOptions = ({navigation}: any) => {
		const course = navigation.state.params.course
		return {
			title: course.name,
		}
	}

	render() {
		const course = this.props.navigation.state.params.course
		const status = course.status === 'O' ? 'Open' : 'Closed'
		return (
			<Container>
				{course.name}
				<SubHeader>
					{course.departments[0]} {course.number}
					{course.section}
				</SubHeader>
				<Badge status={status} />
				<TableView>
					<Information course={course} />
					<Schedule course={course} />
					<Description course={course} />
				</TableView>
			</Container>
		)
	}
}
<commit_msg>prettier<commit_after>// @flow

import React from 'react'
import type {CourseType} from '../../../../lib/course-search'
import glamorous from 'glamorous-native'
import {Badge} from '../../../building-hours/detail/badge'
import {TableView, Section, Cell} from 'react-native-tableview-simple'
import {convertTimeStringsToOfferings} from 'sto-sis-time-parser'
import moment from 'moment-timezone'
import {formatDay} from '../lib/format-day'
import {MultiLineDetailCell} from '../../components/multi-line-cell'
import type {TopLevelViewPropsType} from '../../../types'

const Container = glamorous.scrollView({
	paddingVertical: 6,
})

const Header = glamorous.text({
	fontSize: 36,
	textAlign: 'center',
	marginTop: 20,
	marginHorizontal: 10,
})

const SubHeader = glamorous.text({
	fontSize: 21,
	textAlign: 'center',
	marginTop: 5,
})

const CellText = glamorous.text({
	padding: 5,
})

function Information({course}: {course: CourseType}) {
	const profs = course.instructors ? course.instructors.join(', ') : null
	const instructors = course.instructors ? (
		<Cell cellStyle="LeftDetail" detail="Instructor(s)" title={profs} />
	) : null
	const gereqs = course.gereqs ? course.gereqs.join(', ') : null
	const ges = course.gereqs ? (
		<Cell cellStyle="LeftDetail" detail="GEs" title={gereqs} />
	) : null
	const credits = course.credits ? (
		<Cell cellStyle="LeftDetail" detail="Credits" title={course.credits} />
	) : null
	const type = <Cell cellStyle="LeftDetail" detail="Type" title={course.type} />
	const passFail = course.pn ? 'Yes' : 'No'
	const pn = <Cell cellStyle="LeftDetail" detail="Pass/Fail" title={passFail} />
	const prerequisites = course.prerequisites
		? course.prerequisites.replace('Prerequisite: ', '')
		: 'None'

	const prereqs = (
		<Cell cellStyle="LeftDetail" detail="Prerequisites" title={prerequisites} />
	)
	return (

			{instructors}
			{type}
			{ges}
			{pn}
			{prereqs}
			{credits}

	)
}

function Schedule({course}: {course: CourseType}) {
	if (!course.times) {
		return null
	}
	const times = convertTimeStringsToOfferings({times: course.times})
	const schedule = times.map(time => {
		const hours = time.times.map(time => {
			const start = moment(time.start, 'hmm').format('h:mm A')
			const end = moment(time.end, 'hmm').format('h:mm A')
			return `${start} - ${end}`
		})
		const allHours = hours.join('\n')
		const day = formatDay(time.day)
		return <MultiLineDetailCell key={time.day} detail={allHours} title={day} />
	})

	return
{schedule}

}

function Description({course}: {course: CourseType}) {
	return course.description ? (

			<Cell cellContentView={<CellText>{course.description[0]}</CellText>} />

	) : null
}

type Props = TopLevelViewPropsType & {
	navigation: {state: {params: {course: CourseType}}},
}

export class CourseDetailView extends React.PureComponent<Props> {
	static navigationOptions = ({navigation}: any) => {
		const course = navigation.state.params.course
		return {
			title: course.name,
		}
	}

	render() {
		const course = this.props.navigation.state.params.course
		const status = course.status === 'O' ? 'Open' : 'Closed'
		return (
			<Container>
				{course.name}
				<SubHeader>
					{course.departments[0]} {course.number}
					{course.section}
				</SubHeader>
				<Badge status={status} />
				<TableView>
					<Information course={course} />
					<Schedule course={course} />
					<Description course={course} />
				</TableView>
			</Container>
		)
	}
}
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.SVGRenderer = function () {

	console.log( 'THREE.SVGRenderer', THREE.REVISION );

	var _this = this,
	_renderData, _elements, _lights,
	_projector = new THREE.Projector(),
	_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
	_svgWidth, _svgHeight, _svgWidthHalf, _svgHeightHalf,

	_v1, _v2, _v3, _v4,

	_clipBox = new THREE.Box2(),
	_elemBox = new THREE.Box2(),

	_color = new THREE.Color(),
	_diffuseColor = new THREE.Color(),
	_ambientLight = new THREE.Color(),
	_directionalLights = new THREE.Color(),
	_pointLights = new THREE.Color(),
	_clearColor = new THREE.Color(),

	_w, // z-buffer to w-buffer
	_vector3 = new THREE.Vector3(), // Needed for PointLight
	_centroid = new THREE.Vector3(),

	_svgPathPool = [], _svgLinePool = [], _svgRectPool = [],
	_svgNode, _pathCount = 0, _lineCount = 0, _rectCount = 0,
	_quality = 1;

	this.domElement = _svg;

	this.autoClear = true;
	this.sortObjects = true;
	this.sortElements = true;

	this.info = {

		render: {

			vertices: 0,
			faces: 0

		}

	}

	this.setQuality = function( quality ) {

		switch(quality) {

			case "high": _quality = 1; break;
			case "low": _quality = 0; break;

		}

	};

	// WebGLRenderer compatibility

	this.supportsVertexTextures = function () {};
	this.setFaceCulling = function () {};

	this.setClearColor = function ( color, alpha ) {

		_clearColor.set(color);

	};

	this.setSize = function( width, height ) {

		_svgWidth = width; _svgHeight = height;
		_svgWidthHalf = _svgWidth / 2; _svgHeightHalf = _svgHeight / 2;

		_svg.setAttribute( 'viewBox', ( - _svgWidthHalf ) + ' ' + ( - _svgHeightHalf ) + ' ' + _svgWidth + ' ' + _svgHeight );
		_svg.setAttribute( 'width', _svgWidth );
		_svg.setAttribute( 'height', _svgHeight );

		_clipBox.min.set( - _svgWidthHalf, - _svgHeightHalf );
		_clipBox.max.set( _svgWidthHalf, _svgHeightHalf );

	};

	this.clear = function () {

		_pathCount = 0;
		_lineCount = 0;
		_rectCount = 0;

		while ( _svg.childNodes.length > 0 ) {

			_svg.removeChild( _svg.childNodes[ 0 ] );

		}

		_svg.style.backgroundColor = _clearColor.getStyle();

	};

	this.render = function ( scene, camera ) {

		if ( camera instanceof THREE.Camera === false ) {

			console.error( 'THREE.SVGRenderer.render: camera is not an instance of THREE.Camera.' );
			return;

		}

		if ( this.autoClear === true ) this.clear();

		_this.info.render.vertices = 0;
		_this.info.render.faces = 0;

		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
		_elements = _renderData.elements;
		_lights = _renderData.lights;

		calculateLights( _lights );

		for ( var e = 0, el = _elements.length; e < el; e ++ ) {

			var element = _elements[ e ];
			var material = element.material;

			if ( material === undefined || material.opacity === 0 ) continue;

			_elemBox.makeEmpty();

			if ( element instanceof THREE.RenderableSprite ) {

				_v1 = element;
				_v1.x *= _svgWidthHalf; _v1.y *= - _svgHeightHalf;

				renderSprite( _v1, element, material );

			} else if ( element instanceof THREE.RenderableLine ) {

				_v1 = element.v1; _v2 = element.v2;

				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;

				_elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] );

				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {

					renderLine( _v1, _v2, element, material );

				}

			} else if ( element instanceof THREE.RenderableFace ) {

				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;

				if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue;
				if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue;
				if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue;

				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
				_v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= - _svgHeightHalf;

				_elemBox.setFromPoints( [
					_v1.positionScreen,
					_v2.positionScreen,
					_v3.positionScreen
				] );

				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {

					renderFace3( _v1, _v2, _v3, element, material );

				}

			}

		}

	};

	function calculateLights( lights ) {

		_ambientLight.setRGB( 0, 0, 0 );
		_directionalLights.setRGB( 0, 0, 0 );
		_pointLights.setRGB( 0, 0, 0 );

		for ( var l = 0, ll = lights.length; l < ll; l++ ) {

			var light = lights[ l ];
			var lightColor = light.color;

			if ( light instanceof THREE.AmbientLight ) {

				_ambientLight.r += lightColor.r;
				_ambientLight.g += lightColor.g;
				_ambientLight.b += lightColor.b;

			} else if ( light instanceof THREE.DirectionalLight ) {

				_directionalLights.r += lightColor.r;
				_directionalLights.g += lightColor.g;
				_directionalLights.b += lightColor.b;

			} else if ( light instanceof THREE.PointLight ) {

				_pointLights.r += lightColor.r;
				_pointLights.g += lightColor.g;
				_pointLights.b += lightColor.b;

			}

		}

	}

	function calculateLight( lights, position, normal, color ) {

		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {

			var light = lights[ l ];
			var lightColor = light.color;

			if ( light instanceof THREE.DirectionalLight ) {

				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();

				var amount = normal.dot( lightPosition );

				if ( amount <= 0 ) continue;

				amount *= light.intensity;

				color.r += lightColor.r * amount;
				color.g += lightColor.g * amount;
				color.b += lightColor.b * amount;

			} else if ( light instanceof THREE.PointLight ) {

				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );

				var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );

				if ( amount <= 0 ) continue;

				amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );

				if ( amount == 0 ) continue;

				amount *= light.intensity;

				color.r += lightColor.r * amount;
				color.g += lightColor.g * amount;
				color.b += lightColor.b * amount;

			}

		}

	}

	function renderSprite( v1, element, material ) {

		var scaleX = element.scale.x * _svgWidthHalf;
		var scaleY = element.scale.y * _svgHeightHalf;

		_svgNode = getRectNode( _rectCount ++ );

		_svgNode.setAttribute( 'x', v1.x - ( scaleX * 0.5 ) );
		_svgNode.setAttribute( 'y', v1.y - ( scaleY * 0.5 ) );
		_svgNode.setAttribute( 'width', scaleX );
		_svgNode.setAttribute( 'height', scaleY );

		if ( material instanceof THREE.SpriteMaterial ) {

			_svgNode.setAttribute( 'style', 'fill: ' + material.color.getStyle() );

		}

		_svg.appendChild( _svgNode );

	}

	function renderLine( v1, v2, element, material ) {

		_svgNode = getLineNode( _lineCount ++ );

		_svgNode.setAttribute( 'x1', v1.positionScreen.x );
		_svgNode.setAttribute( 'y1', v1.positionScreen.y );
		_svgNode.setAttribute( 'x2', v2.positionScreen.x );
		_svgNode.setAttribute( 'y2', v2.positionScreen.y );

		if ( material instanceof THREE.LineBasicMaterial ) {

			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin );

			_svg.appendChild( _svgNode );

		}

	}

	function renderFace3( v1, v2, v3, element, material ) {

		_this.info.render.vertices += 3;
		_this.info.render.faces ++;

		_svgNode = getPathNode( _pathCount ++ );
		_svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' );

		if ( material instanceof THREE.MeshBasicMaterial ) {

			_color.copy( material.color );

			if ( material.vertexColors === THREE.FaceColors ) {

				_color.multiply( element.color );

			}

		} else if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {

			_diffuseColor.copy( material.color );

			if ( material.vertexColors === THREE.FaceColors ) {

				_diffuseColor.multiply( element.color );

			}

			_color.copy( _ambientLight );

			_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );

			calculateLight( _lights, _centroid, element.normalModel, _color );

			_color.multiply( _diffuseColor ).add( material.emissive );

		} else if ( material instanceof THREE.MeshDepthMaterial ) {

			_w = 1 - ( material.__2near / (material.__farPlusNear - element.z * material.__farMinusNear) );
			_color.setRGB( _w, _w, _w );

		} else if ( material instanceof THREE.MeshNormalMaterial ) {

			var normal = element.normalModelView;

			_color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );

		}

		if ( material.wireframe ) {

			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );

		} else {

			_svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );

		}

		_svg.appendChild( _svgNode );

	}

	function getLineNode( id ) {

		if ( _svgLinePool[ id ] == null ) {

			_svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' );

			if ( _quality == 0 ) {

				_svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

			}

			return _svgLinePool[ id ];

		}

		return _svgLinePool[ id ];

	}

	function getPathNode( id ) {

		if ( _svgPathPool[ id ] == null ) {

			_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );

			if ( _quality == 0 ) {

				_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

			}

			return _svgPathPool[ id ];

		}

		return _svgPathPool[ id ];

	}

	function getRectNode( id ) {

		if ( _svgRectPool[ id ] == null ) {

			_svgRectPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );

			if ( _quality == 0 ) {

				_svgRectPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

			}

			return _svgRectPool[ id ];

		}

		return _svgRectPool[ id ];

	}

};
<commit_msg>SVGRenderer: Implemented @srifqi clearAlpha code. Fixes #4898.<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.SVGRenderer = function () {

	console.log( 'THREE.SVGRenderer', THREE.REVISION );

	var _this = this,
	_renderData, _elements, _lights,
	_projector = new THREE.Projector(),
	_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
	_svgWidth, _svgHeight, _svgWidthHalf, _svgHeightHalf,

	_v1, _v2, _v3, _v4,

	_clipBox = new THREE.Box2(),
	_elemBox = new THREE.Box2(),

	_color = new THREE.Color(),
	_diffuseColor = new THREE.Color(),
	_ambientLight = new THREE.Color(),
	_directionalLights = new THREE.Color(),
	_pointLights = new THREE.Color(),
	_clearColor = new THREE.Color(),
	_clearAlpha = 1,

	_w, // z-buffer to w-buffer
	_vector3 = new THREE.Vector3(), // Needed for PointLight
	_centroid = new THREE.Vector3(),

	_svgPathPool = [], _svgLinePool = [], _svgRectPool = [],
	_svgNode, _pathCount = 0, _lineCount = 0, _rectCount = 0,
	_quality = 1;

	this.domElement = _svg;

	this.autoClear = true;
	this.sortObjects = true;
	this.sortElements = true;

	this.info = {

		render: {

			vertices: 0,
			faces: 0

		}

	}

	this.setQuality = function( quality ) {

		switch(quality) {

			case "high": _quality = 1; break;
			case "low": _quality = 0; break;

		}

	};

	// WebGLRenderer compatibility

	this.supportsVertexTextures = function () {};
	this.setFaceCulling = function () {};

	this.setClearColor = function ( color, alpha ) {

		_clearColor.set( color );
		_clearAlpha = alpha !== undefined ? alpha : 1;

	};

	this.setSize = function( width, height ) {

		_svgWidth = width; _svgHeight = height;
		_svgWidthHalf = _svgWidth / 2; _svgHeightHalf = _svgHeight / 2;

		_svg.setAttribute( 'viewBox', ( - _svgWidthHalf ) + ' ' + ( - _svgHeightHalf ) + ' ' + _svgWidth + ' ' + _svgHeight );
		_svg.setAttribute( 'width', _svgWidth );
		_svg.setAttribute( 'height', _svgHeight );

		_clipBox.min.set( - _svgWidthHalf, - _svgHeightHalf );
		_clipBox.max.set( _svgWidthHalf, _svgHeightHalf );

	};

	this.clear = function () {

		_pathCount = 0;
		_lineCount = 0;
		_rectCount = 0;

		while ( _svg.childNodes.length > 0 ) {

			_svg.removeChild( _svg.childNodes[ 0 ] );

		}

		_svg.style.backgroundColor = 'rgba(' + ( ( _clearColor.r * 255 ) | 0 ) + ',' + ( ( _clearColor.g * 255 ) | 0 ) + ',' + ( ( _clearColor.b * 255 ) | 0 ) + ',' + _clearAlpha + ')';

	};

	this.render = function ( scene, camera ) {

		if ( camera instanceof THREE.Camera === false ) {

			console.error( 'THREE.SVGRenderer.render: camera is not an instance of THREE.Camera.' );
			return;

		}

		if ( this.autoClear === true ) this.clear();

		_this.info.render.vertices = 0;
		_this.info.render.faces = 0;

		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
		_elements = _renderData.elements;
		_lights = _renderData.lights;

		calculateLights( _lights );

		for ( var e = 0, el = _elements.length; e < el; e ++ ) {

			var element = _elements[ e ];
			var material = element.material;

			if ( material === undefined || material.opacity === 0 ) continue;

			_elemBox.makeEmpty();

			if ( element instanceof THREE.RenderableSprite ) {

				_v1 = element;
				_v1.x *= _svgWidthHalf; _v1.y *= - _svgHeightHalf;

				renderSprite( _v1, element, material );

			} else if ( element instanceof THREE.RenderableLine ) {

				_v1 = element.v1; _v2 = element.v2;

				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;

				_elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] );

				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {

					renderLine( _v1, _v2, element, material );

				}

			} else if ( element instanceof THREE.RenderableFace ) {

				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;

				if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue;
				if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue;
				if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue;

				_v1.positionScreen.x *= _svgWidthHalf; _v1.positionScreen.y *= - _svgHeightHalf;
				_v2.positionScreen.x *= _svgWidthHalf; _v2.positionScreen.y *= - _svgHeightHalf;
				_v3.positionScreen.x *= _svgWidthHalf; _v3.positionScreen.y *= - _svgHeightHalf;

				_elemBox.setFromPoints( [
					_v1.positionScreen,
					_v2.positionScreen,
					_v3.positionScreen
				] );

				if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {

					renderFace3( _v1, _v2, _v3, element, material );

				}

			}

		}

	};

	function calculateLights( lights ) {

		_ambientLight.setRGB( 0, 0, 0 );
		_directionalLights.setRGB( 0, 0, 0 );
		_pointLights.setRGB( 0, 0, 0 );

		for ( var l = 0, ll = lights.length; l < ll; l++ ) {

			var light = lights[ l ];
			var lightColor = light.color;

			if ( light instanceof THREE.AmbientLight ) {

				_ambientLight.r += lightColor.r;
				_ambientLight.g += lightColor.g;
				_ambientLight.b += lightColor.b;

			} else if ( light instanceof THREE.DirectionalLight ) {

				_directionalLights.r += lightColor.r;
				_directionalLights.g += lightColor.g;
				_directionalLights.b += lightColor.b;

			} else if ( light instanceof THREE.PointLight ) {

				_pointLights.r += lightColor.r;
				_pointLights.g += lightColor.g;
				_pointLights.b += lightColor.b;

			}

		}

	}

	function calculateLight( lights, position, normal, color ) {

		for ( var l = 0, ll = lights.length; l < ll; l ++ ) {

			var light = lights[ l ];
			var lightColor = light.color;

			if ( light instanceof THREE.DirectionalLight ) {

				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();

				var amount = normal.dot( lightPosition );

				if ( amount <= 0 ) continue;

				amount *= light.intensity;

				color.r += lightColor.r * amount;
				color.g += lightColor.g * amount;
				color.b += lightColor.b * amount;

			} else if ( light instanceof THREE.PointLight ) {

				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );

				var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );

				if ( amount <= 0 ) continue;

				amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );

				if ( amount == 0 ) continue;

				amount *= light.intensity;

				color.r += lightColor.r * amount;
				color.g += lightColor.g * amount;
				color.b += lightColor.b * amount;

			}

		}

	}

	function renderSprite( v1, element, material ) {

		var scaleX = element.scale.x * _svgWidthHalf;
		var scaleY = element.scale.y * _svgHeightHalf;

		_svgNode = getRectNode( _rectCount ++ );

		_svgNode.setAttribute( 'x', v1.x - ( scaleX * 0.5 ) );
		_svgNode.setAttribute( 'y', v1.y - ( scaleY * 0.5 ) );
		_svgNode.setAttribute( 'width', scaleX );
		_svgNode.setAttribute( 'height', scaleY );

		if ( material instanceof THREE.SpriteMaterial ) {

			_svgNode.setAttribute( 'style', 'fill: ' + material.color.getStyle() );

		}

		_svg.appendChild( _svgNode );

	}

	function renderLine( v1, v2, element, material ) {

		_svgNode = getLineNode( _lineCount ++ );

		_svgNode.setAttribute( 'x1', v1.positionScreen.x );
		_svgNode.setAttribute( 'y1', v1.positionScreen.y );
		_svgNode.setAttribute( 'x2', v2.positionScreen.x );
		_svgNode.setAttribute( 'y2', v2.positionScreen.y );

		if ( material instanceof THREE.LineBasicMaterial ) {

			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin );

			_svg.appendChild( _svgNode );

		}

	}

	function renderFace3( v1, v2, v3, element, material ) {

		_this.info.render.vertices += 3;
		_this.info.render.faces ++;

		_svgNode = getPathNode( _pathCount ++ );
		_svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' );

		if ( material instanceof THREE.MeshBasicMaterial ) {

			_color.copy( material.color );

			if ( material.vertexColors === THREE.FaceColors ) {

				_color.multiply( element.color );

			}

		} else if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {

			_diffuseColor.copy( material.color );

			if ( material.vertexColors === THREE.FaceColors ) {

				_diffuseColor.multiply( element.color );

			}

			_color.copy( _ambientLight );

			_centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );

			calculateLight( _lights, _centroid, element.normalModel, _color );

			_color.multiply( _diffuseColor ).add( material.emissive );

		} else if ( material instanceof THREE.MeshDepthMaterial ) {

			_w = 1 - ( material.__2near / (material.__farPlusNear - element.z * material.__farMinusNear) );
			_color.setRGB( _w, _w, _w );

		} else if ( material instanceof THREE.MeshNormalMaterial ) {

			var normal = element.normalModelView;

			_color.setRGB( normal.x, normal.y, normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );

		}

		if ( material.wireframe ) {

			_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );

		} else {

			_svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );

		}

		_svg.appendChild( _svgNode );

	}

	function getLineNode( id ) {

		if ( _svgLinePool[ id ] == null ) {

			_svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' );

			if ( _quality == 0 ) {

				_svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

			}

			return _svgLinePool[ id ];

		}

		return _svgLinePool[ id ];

	}

	function getPathNode( id ) {

		if ( _svgPathPool[ id ] == null ) {

			_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );

			if ( _quality == 0 ) {

				_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

			}

			return _svgPathPool[ id ];

		}

		return _svgPathPool[ id ];

	}

	function getRectNode( id ) {

		if ( _svgRectPool[ id ] == null ) {

			_svgRectPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );

			if ( _quality == 0 ) {

				_svgRectPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

			}

			return _svgRectPool[ id ];

		}

		return _svgRectPool[ id ];

	}

};
<|endoftext|>


<commit_before>"use strict";
/*
 * ooiui/static/js/views/science/PlottingSelection.js
 * Builds a list of the arrays subsequent items
 *
 * Dependencies
 * CSS:
 * - ooiui/static/css/common/PlottingSelection.css
 * Partials:
 * - ooiui/static/js/partials/PlottingSelection.html
 * Libs
 * - ooiui/static/lib/underscore/underscore.js
 * - ooiui/static/lib/backbone/backbone.js
 * - ooiui/static/js/ooi.js
 * Usage
 */

var PlottingSelectionView = Backbone.View.extend({
  filterSubviews:[],
  dataCollection: {},
  parentChild : {
                 "arrays":{"parent":null,"child":"moorings"},
                 "moorings":{"parent":"arrays","child":"platforms"},
                 "platforms":{"parent":"platforms","child":"instruments"},
                 "instruments":{"parent":"platforms","child":"streams"},
                 "streams":{"parent":"streams","child":"instruments"},
                 "parameters":{"parent":"instruments","child":"parameters"}
                 },
  initialize: function() {
    _.bindAll(this, "render");
  },
  getSelectedVars: function(filterModel,filterCollection){
    var selectedParam = this.$el.find( "#parameters_id option:selected").val()
    return selectedParam;
  },
  addFilter: function(filterModel,filterCollection){
    if (filterModel.get('labelText') == "arrays"){
      var subview = new FilterSelectionView({
        model: filterModel,
        collection: filterCollection
      });
      subview.initallyDisabled = ""
    }else if(filterModel.get('labelText') == "parameters"){
      var subview = new FilterSelectionView({
        model: filterModel,
        collection: filterCollection
      });
      subview.numberSelectable = 6
    }else{
      var subview = new FilterSelectionView({
        model: filterModel,
        collection: filterCollection
      });
    }
    subview.render();
    this.filterSubviews.push(subview);

    this.$el.find('.filter-selection-body').append(subview.el);
  },
  template: JST['ooiui/static/js/partials/PlottingSelection.html'],
  render: function() {
    console.log("render called");
    var self = this;
    this.$el.html(this.template({}));

    var filterItems = Object.keys(self.dataCollection)

    for (var i = 0; i < filterItems.length; i++) {
      var filterModel = new FilterSelectionModel({
        labelText : filterItems[i],
        parentItem : self.parentChild[filterItems[i]]['parent'],
        childItem : self.parentChild[filterItems[i]]['child']
      });
      //add the sub here
      this.addFilter(filterModel,self.dataCollection[filterItems[i]])
    };

    this.$el.find('#parameters_id .dropdown-menu').addClass("pull-right")

  },
  unFilterItems: function(options) {
    var self = this;
    var childItem = options.model.get("childItem") ;
    var currentItem =  options.model.get("labelText") ;
    var filterItem =  options.filter ;
    var filterVal = options.filterValue;

    if (currentItem == "streams" || currentItem == "parameters"){
      //no more need to filter
      console.log("no more filter");
    }else if (childItem == "streams" || childItem == "parameters"){

    }else{

      //unfilter items
      this.$el.find( "#"+childItem+"_id option" ).each(function( index, obj ) {
        $( this ).removeAttr("disabled");
      });
      //add disabled back
      this.$el.find( "#"+childItem+"_id" ).attr("disabled", true);

      //refresh
      $('.selectpicker').selectpicker('refresh');
      console.log("un:filter called, refresh");
    }
  },
  filterItems: function(options) {
    var self = this;
    var childItem = options.model.get("childItem") ;
    var currentItem =  options.model.get("labelText") ;
    var filterItem =  options.filter ;
    var filterVal = options.filterValue;

    if (currentItem == "streams" || currentItem == "parameters"){
      //no more need to filter
      if (currentItem == "parameters"){
        var selectedStream = this.$el.find( "#streams_id option:selected")
        var selectedParam = this.$el.find( "#parameters_id option:selected")

        var selected = [];
        $(selectedParam).each(function(index){
            selected.push([$(this).val()]);
        });

        var streamModel = new StreamModel({preferred_timestamp : "internal_timestamp",
                                           start : selectedStream.attr('start'),
                                           end : selectedStream.attr('end'),
                                           stream_name : selectedStream.attr("stream_type") + "_" + selectedStream.text(),
                                           display_name : "",
                                           xvariable : ["time"],
                                           yvariable : selected,
                                           variables_shape : {filterVal:"float"},
                                           reference_designator:  selectedStream.attr("sensor"),
                                       })

        ooi.trigger('FilterSelectionView:onParameterSelection', {model: streamModel});
      }else if (currentItem == "streams"){
        /*
        var selectedStream = this.$el.find( "#streams_id option:selected")
        var streamModel = new StreamModel({preferred_timestamp : "internal_timestamp",
                                           start : selectedStream.attr('start'),
                                           end : selectedStream.attr('end'),
                                           stream_name : selectedStream.attr("stream_type") + "_" + selectedStream.text(),
                                           reference_designator:  selectedStream.attr("sensor"),
        })
        ooi.trigger('FilterSelectionView:onStreamSelection', {model: streamModel});
        */
      }
      console.log("no more filter");
    }else if (childItem == "streams" || childItem == "parameters"){
      //this.$el.find( "#"+currentItem+"_id option").each(function(){$( this ).remove()});
      this.$el.find( "#streams_id").html("")
      this.$el.find( "#parameters_id").html("")

      var param_list = []

      options.collection.each(function(model) {
        if (model.get('reference_designator') == filterVal){
          //reset then build html
          var streamhtml = ""
          for (var i = 0; i < model.get(childItem).length; i++) {
            //add the contents for the stream info
            var streamTextValue = model.get('streams')[i]['stream']
            var streamSubText = model.get('streams')[i]['method']
            var start = model.get('streams')[i]['beginTime']
            var end = model.get('streams')[i]['endTime']
            var sensor = model.get('streams')[i]['sensor']

            streamhtml+= "<option sensor='"+sensor+"' stream_type='"+streamSubText+"' start='"+start+"' end='"+end+"' data-subtext='"+streamSubText+"' >"+streamTextValue+"</option>"
          };

          //params
          var parameterhtml = ""
          for (var i = 0; i < model.get('instrument_parameters').length; i++) {
            var parameterTextValue = model.get('instrument_parameters')[i]
            var parameterSubText = ""
            if (param_list.indexOf(parameterTextValue) == -1){
              parameterhtml+= "<option data-subtext='"+streamSubText+"' >"+parameterTextValue+"</option>"
              param_list.push(parameterTextValue);
            }
          };
          //set them
          self.$el.find( "#streams_id").html(streamhtml)
          self.$el.find( "#parameters_id").html(parameterhtml)
        }
      });
      //remove disabled
      this.$el.find( "#streams_id" ).removeAttr("disabled");
      this.$el.find( "#parameters_id" ).removeAttr("disabled");
      //refresh
      $('.selectpicker').selectpicker('refresh');
    }else{
      this.unFilterItems(options)
      //filter items
      this.$el.find( "#"+childItem+"_id option" ).each(function( index, obj ) {
        var childValue = $( this ).attr("filter").trim();
        var childCode = $( this ).attr(currentItem+"-code");
        if (filterVal == childCode){
          //ITS GOOD!
          var newText = childValue.split(filterItem)[1].trim();
          newText = newText.replace("-","")
          newText = newText.trim();

          $( this ).text(newText)
          console.log(newText)
          //self.$el.find( "#"+childItem+"_id").text(newText)
        }
        else{
          $( this ).attr("disabled", true);
        }
      });

      //remove disabled
      this.$el.find( "#"+childItem+"_id" ).removeAttr("disabled");

      //refresh
      console.log("filter called, refresh",childItem);
      $('.selectpicker').selectpicker('refresh');
    }
  },
});

var FilterSelectionView = Backbone.View.extend({
  collection: null,
  initallyDisabled: "disabled",
  tagName: "div",
  numberSelectable: 1,
  className:"col-sm-2",
  events: {
    'change .selectpicker' : 'onChange'
  },
  initialize: function(options) {
    _.bindAll(this, "render");
  },
  template: JST['ooiui/static/js/partials/FilterPlottingSelection.html'],
  render: function() {
    console.log("render called");
    var self = this;

    this.$el.html(this.template({numberSelectable: self.numberSelectable,
                                 isDisabled:self.initallyDisabled,
                                 labelText:self.model.get('labelText'),
                                 model:self.model,
                                 collection:self.collection}));
    //setup the picker
    this.$el.find('.selectpicker').selectpicker();
  },
  onChange: function() {
    var self = this;
    var val = this.$el.find("option:selected").val();
    var text = this.$el.find("option:selected").text();
    var parent_item = self.model.get('parentItem');
    var child_item = self.model.get('childItem');
    //fire when the options is selected or unselected
    if (val === undefined){
      ooi.trigger('FilterSelectionView:onUnSelect', {model: this.model});
    }else{
      ooi.trigger('FilterSelectionView:onSelect', {model: this.model, filter:text.trim(),filterValue:val, collection: this.collection});
    }

  }
});<commit_msg>add pull right to the view for params<commit_after>"use strict";
/*
 * ooiui/static/js/views/science/PlottingSelection.js
 * Builds a list of the arrays subsequent items
 *
 * Dependencies
 * CSS:
 * - ooiui/static/css/common/PlottingSelection.css
 * Partials:
 * - ooiui/static/js/partials/PlottingSelection.html
 * Libs
 * - ooiui/static/lib/underscore/underscore.js
 * - ooiui/static/lib/backbone/backbone.js
 * - ooiui/static/js/ooi.js
 * Usage
 */

var PlottingSelectionView = Backbone.View.extend({
  filterSubviews:[],
  dataCollection: {},
  parentChild : {
                 "arrays":{"parent":null,"child":"moorings"},
                 "moorings":{"parent":"arrays","child":"platforms"},
                 "platforms":{"parent":"platforms","child":"instruments"},
                 "instruments":{"parent":"platforms","child":"streams"},
                 "streams":{"parent":"streams","child":"instruments"},
                 "parameters":{"parent":"instruments","child":"parameters"}
                 },
  initialize: function() {
    _.bindAll(this, "render");
  },
  getSelectedVars: function(filterModel,filterCollection){
    var selectedParam = this.$el.find( "#parameters_id option:selected").val()
    return selectedParam;
  },
  addFilter: function(filterModel,filterCollection){
    if (filterModel.get('labelText') == "arrays"){
      var subview = new FilterSelectionView({
        model: filterModel,
        collection: filterCollection
      });
      subview.initallyDisabled = ""
    }else if(filterModel.get('labelText') == "parameters"){
      var subview = new FilterSelectionView({
        model: filterModel,
        collection: filterCollection
      });
      subview.numberSelectable = 6
    }else{
      var subview = new FilterSelectionView({
        model: filterModel,
        collection: filterCollection
      });
    }
    subview.render();
    this.filterSubviews.push(subview);

    this.$el.find('.filter-selection-body').append(subview.el);
  },
  template: JST['ooiui/static/js/partials/PlottingSelection.html'],
  render: function() {
    console.log("render called");
    var self = this;
    this.$el.html(this.template({}));

    var filterItems = Object.keys(self.dataCollection)

    for (var i = 0; i < filterItems.length; i++) {
      var filterModel = new FilterSelectionModel({
        labelText : filterItems[i],
        parentItem : self.parentChild[filterItems[i]]['parent'],
        childItem : self.parentChild[filterItems[i]]['child']
      });
      //add the sub here
      this.addFilter(filterModel,self.dataCollection[filterItems[i]])
    };

    this.$el.find('#parameters_id').parent().find('.dropdown-menu').addClass("pull-right")

  },
  unFilterItems: function(options) {
    var self = this;
    var childItem = options.model.get("childItem") ;
    var currentItem =  options.model.get("labelText") ;
    var filterItem =  options.filter ;
    var filterVal = options.filterValue;

    if (currentItem == "streams" || currentItem == "parameters"){
      //no more need to filter
      console.log("no more filter");
    }else if (childItem == "streams" || childItem == "parameters"){

    }else{

      //unfilter items
      this.$el.find( "#"+childItem+"_id option" ).each(function( index, obj ) {
        $( this ).removeAttr("disabled");
      });
      //add disabled back
      this.$el.find( "#"+childItem+"_id" ).attr("disabled", true);

      //refresh
      $('.selectpicker').selectpicker('refresh');
      console.log("un:filter called, refresh");
    }
  },
  filterItems: function(options) {
    var self = this;
    var childItem = options.model.get("childItem") ;
    var currentItem =  options.model.get("labelText") ;
    var filterItem =  options.filter ;
    var filterVal = options.filterValue;

    if (currentItem == "streams" || currentItem == "parameters"){
      //no more need to filter
      if (currentItem == "parameters"){
        var selectedStream = this.$el.find( "#streams_id option:selected")
        var selectedParam = this.$el.find( "#parameters_id option:selected")

        var selected = [];
        $(selectedParam).each(function(index){
            selected.push([$(this).val()]);
        });

        var streamModel = new StreamModel({preferred_timestamp : "internal_timestamp",
                                           start : selectedStream.attr('start'),
                                           end : selectedStream.attr('end'),
                                           stream_name : selectedStream.attr("stream_type") + "_" + selectedStream.text(),
                                           display_name : "",
                                           xvariable : ["time"],
                                           yvariable : selected,
                                           variables_shape : {filterVal:"float"},
                                           reference_designator:  selectedStream.attr("sensor"),
                                       })

        ooi.trigger('FilterSelectionView:onParameterSelection', {model: streamModel});
      }else if (currentItem == "streams"){
        /*
        var selectedStream = this.$el.find( "#streams_id option:selected")
        var streamModel = new StreamModel({preferred_timestamp : "internal_timestamp",
                                           start : selectedStream.attr('start'),
                                           end : selectedStream.attr('end'),
                                           stream_name : selectedStream.attr("stream_type") + "_" + selectedStream.text(),
                                           reference_designator:  selectedStream.attr("sensor"),
        })
        ooi.trigger('FilterSelectionView:onStreamSelection', {model: streamModel});
        */
      }
      console.log("no more filter");
    }else if (childItem == "streams" || childItem == "parameters"){
      //this.$el.find( "#"+currentItem+"_id option").each(function(){$( this ).remove()});
      this.$el.find( "#streams_id").html("")
      this.$el.find( "#parameters_id").html("")

      var param_list = []

      options.collection.each(function(model) {
        if (model.get('reference_designator') == filterVal){
          //reset then build html
          var streamhtml = ""
          for (var i = 0; i < model.get(childItem).length; i++) {
            //add the contents for the stream info
            var streamTextValue = model.get('streams')[i]['stream']
            var streamSubText = model.get('streams')[i]['method']
            var start = model.get('streams')[i]['beginTime']
            var end = model.get('streams')[i]['endTime']
            var sensor = model.get('streams')[i]['sensor']

            streamhtml+= "<option sensor='"+sensor+"' stream_type='"+streamSubText+"' start='"+start+"' end='"+end+"' data-subtext='"+streamSubText+"' >"+streamTextValue+"</option>"
          };

          //params
          var parameterhtml = ""
          for (var i = 0; i < model.get('instrument_parameters').length; i++) {
            var parameterTextValue = model.get('instrument_parameters')[i]
            var parameterSubText = ""
            if (param_list.indexOf(parameterTextValue) == -1){
              parameterhtml+= "<option data-subtext='"+streamSubText+"' >"+parameterTextValue+"</option>"
              param_list.push(parameterTextValue);
            }
          };
          //set them
          self.$el.find( "#streams_id").html(streamhtml)
          self.$el.find( "#parameters_id").html(parameterhtml)
        }
      });
      //remove disabled
      this.$el.find( "#streams_id" ).removeAttr("disabled");
      this.$el.find( "#parameters_id" ).removeAttr("disabled");
      //refresh
      $('.selectpicker').selectpicker('refresh');
    }else{
      this.unFilterItems(options)
      //filter items
      this.$el.find( "#"+childItem+"_id option" ).each(function( index, obj ) {
        var childValue = $( this ).attr("filter").trim();
        var childCode = $( this ).attr(currentItem+"-code");
        if (filterVal == childCode){
          //ITS GOOD!
          var newText = childValue.split(filterItem)[1].trim();
          newText = newText.replace("-","")
          newText = newText.trim();

          $( this ).text(newText)
          console.log(newText)
          //self.$el.find( "#"+childItem+"_id").text(newText)
        }
        else{
          $( this ).attr("disabled", true);
        }
      });

      //remove disabled
      this.$el.find( "#"+childItem+"_id" ).removeAttr("disabled");

      //refresh
      console.log("filter called, refresh",childItem);
      $('.selectpicker').selectpicker('refresh');
    }
  },
});

var FilterSelectionView = Backbone.View.extend({
  collection: null,
  initallyDisabled: "disabled",
  tagName: "div",
  numberSelectable: 1,
  className:"col-sm-2",
  events: {
    'change .selectpicker' : 'onChange'
  },
  initialize: function(options) {
    _.bindAll(this, "render");
  },
  template: JST['ooiui/static/js/partials/FilterPlottingSelection.html'],
  render: function() {
    console.log("render called");
    var self = this;

    this.$el.html(this.template({numberSelectable: self.numberSelectable,
                                 isDisabled:self.initallyDisabled,
                                 labelText:self.model.get('labelText'),
                                 model:self.model,
                                 collection:self.collection}));
    //setup the picker
    this.$el.find('.selectpicker').selectpicker();
  },
  onChange: function() {
    var self = this;
    var val = this.$el.find("option:selected").val();
    var text = this.$el.find("option:selected").text();
    var parent_item = self.model.get('parentItem');
    var child_item = self.model.get('childItem');
    //fire when the options is selected or unselected
    if (val === undefined){
      ooi.trigger('FilterSelectionView:onUnSelect', {model: this.model});
    }else{
      ooi.trigger('FilterSelectionView:onSelect', {model: this.model, filter:text.trim(),filterValue:val, collection: this.collection});
    }

  }
});<|endoftext|>