<commit_before>'use strict';

/**
 * Module dependencies.
 */
var path = require('path'),
  mongoose = require('mongoose'),
  Poll = mongoose.model('Poll'),
  Opt = mongoose.model('Opt'),
  Vote = mongoose.model('Vote'),
  Voteopt = mongoose.model('Voteopt'),
  Polltag = mongoose.model('Polltag'),
  Pollreport = mongoose.model('Pollreport'),
  Polluser = mongoose.model('Polluser'),
  Report = mongoose.model('Report'),
  Bookmark = mongoose.model('Bookmark'),
  Like = mongoose.model('Like'),
  errorHandler = require(path.resolve(
    './modules/core/server/controllers/errors.server.controller'
  )),
  _ = require('lodash');
/**
 * Create a Poll
 */
exports.create = function(req, res) {
  var poll = new Poll(req.body);
  poll.user = req.user;

  var tags = req.body.tags || [];
  var opts = req.body.opts || [];
  var promises = [];

  poll
    .save()
    .then(_poll => {
      poll = _poll;
      // Tạo report cho poll
      var report = new Pollreport({ poll: poll._id });
      return report.save();
    }, handleError)
    .then(_report => {
      // Lưu tag vào db
      tags.forEach(tag => {
        var polltag = new Polltag({ tag: tag, poll: poll._id });
        promises.push(polltag.save());
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      // Lưu options vào db
      promises = [];
      opts.forEach(opt => {
        var _opt = new Opt(opt);
        _opt.user = req.user;
        _opt.poll = poll._id;
        promises.push(_opt.save());
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      // Tạo biến follow mới
      promises = [];
      var _polluser = new Polluser({ poll: poll._id, user: req.user._id });
      return _polluser.save();
    }, handleError)
    .then(_polluser => {
      res.jsonp(poll);
    }, handleError);

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Show the current Poll
 */
exports.read = function(req, res) {
  // convert mongoose document to JSON
  var poll = req.poll ? req.poll.toJSON() : {};

  // Add a custom field to the Article, for determining if the current User is the "owner".
  // NOTE: This field is NOT persisted to the database, since it doesn't exist in the Article model.
  poll.isCurrentUserOwner =
    req.user &&
    poll.user &&
    poll.user._id.toString() === req.user._id.toString();
  poll.canEdit =
    req.user &&
    req.user.roles &&
    req.user.roles.length &&
    req.user.roles.indexOf('admin') > -1;

  res.jsonp(poll);
};

/**
 * Update a Poll
 */
exports.update = function(req, res) {
  var poll = req.poll;
  poll = _.extend(poll, req.body);
  var tags = req.body.tags || [];
  var opts = req.body.opts || [];
  var promises = [];
  poll
    .save()
    .then(_poll => {
      poll = _poll;
      return Polltag.remove({ poll: _poll._id });
    }, handleError)
    .then(() => {
      tags.forEach(tag => {
        var polltag = new Polltag({ tag: tag, poll: poll._id });
        promises.push(polltag.save());
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      promises = [];
      opts.forEach(opt => {
        if (opt._id) {
          promises.push(
            Opt.update(
              {
                _id: opt._id
              },
              {
                $set: {
                  title: opt.title,
                  color: opt.color,
                  body: opt.body
                }
              }
            ).exec()
          );
        } else {
          var _opt = new Opt(opt);
          _opt.user = req.user;
          _opt.poll = poll;
          promises.push(_opt.save());
        }
      });
      return Promise.all(promises);
    }, handleError)
    .then(_opts => {
      promises = [];
      res.jsonp(poll);
    }, handleError);

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Delete an Poll
 */
exports.delete = function(req, res) {
  var poll = req.poll;
  poll
    .remove()
    .then(() => {
      return Opt.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      var promises = [];
      Vote.find({ poll: poll._id }).exec((err, votes) => {
        votes.forEach(vote => {
          promises.push(Voteopt.remove({ vote: vote._id }));
        });
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      return Vote.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Pollreport.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Polltag.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Report.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Bookmark.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Like.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      res.jsonp(poll);
    }, handleError);

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * List of Polls
 */
exports.list = function(req, res) {
  Poll.find()
    .sort('-created')
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .exec(function(err, polls) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(polls);
      }
    });
};

/**
 * List of Offset
 */
exports.findPolls = function(req, res) {
  var page = req.params.page || 0;
  Poll.find({ isPublic: true })
    .sort('-created')
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .skip(10 * page)
    .limit(10)
    .exec(function(err, polls) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(polls);
      }
    });
};

/**
 * List of Hot
 */
exports.findHotPolls = function(req, res) {
  var page = req.params.page || 0;
  Poll.find({ isPublic: true })
    .sort('-likeCnt')
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .skip(10 * page)
    .limit(10)
    .exec(function(err, polls) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(polls);
      }
    });
};

/**
 * List of Opts in poll
 */
exports.findOpts = function(req, res) {
  Poll.findOpts(req.poll._id)
    .populate('user', 'displayName')
    .exec(function(err, opts) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(opts);
      }
    });
};

/**
 * List of Cmts in poll
 */
exports.findCmts = function(req, res) {
  var page = req.params.page || 0;
  Poll.findCmts(req.poll._id)
    .sort('-created')
    .populate('user', 'displayName profileImageURL')
    .skip(10 * page)
    .limit(10)
    .exec(function(err, cmts) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(cmts);
      }
    });
};

/**
 * List of Tags in poll
 */
exports.findTags = function(req, res) {
  Poll.findTags(req.poll._id).populate('tag').exec(function(err, polltags) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.jsonp(polltags);
    }
  });
};

/**
 * List of Votes in poll
 */
exports.findVotes = function(req, res) {
  Poll.findVotes(req.poll._id).exec(function(err, votes) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.jsonp(votes);
    }
  });
};

/**
 * Vote in poll of user
 */
exports.findOwnerVote = function(req, res) {
  var condition = {};
  condition.poll = req.poll._id;
  if (req.user) {
    condition.user = req.user._id;
    condition.guest = false;
  } else {
    condition.ip =
      req.headers['X-Forwarded-For'] ||
      req.headers['x-forwarded-for'] ||
      req.client.remoteAddress;
    condition.guest = true;
  }
  Poll.findOwnerVote(condition).exec(function(err, vote) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.jsonp(vote);
    }
  });
};

/**
 * Get all info of vote in poll
 */
exports.findVoteopts = function(req, res) {
  var rs = {}, ids;
  Poll.findVotes(req.poll._id).exec(function(err, _votes) {
    if (err) {
      handleError(err);
    } else {
      rs.votes = _votes;
      rs.voteopts = [];
      ids = _.pluck(_votes, '_id');
      Voteopt.find({ vote: { $in: ids } }).exec(function(err, opts) {
        if (err) {
          handleError(err);
        } else {
          rs.voteopts = opts;
          res.jsonp(rs);
        }
      });
    }
  });

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Get Like of user on this poll
 */
exports.findPollLike = function(req, res) {
  var condition = { poll: req.poll._id, user: req.user._id };
  Like.findOne(condition).exec(function(err, like) {
    if (err) {
      handleError(err);
    } else {
      res.jsonp(like);
    }
  });

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find pollusers
 */
exports.findPolluser = function(req, res) {
  Polluser.findOne({
    poll: req.poll._id,
    user: req.user._id
  }).exec((err, _polluser) => {
    if (err) {
      handleError(err);
    } else {
      res.jsonp(_polluser);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find report
 */
exports.findReport = function(req, res) {
  Report.findOne({
    poll: req.poll._id,
    user: req.user._id
  }).exec((err, _report) => {
    if (err) {
      handleError(err);
    } else {
      var result = _report ? true : false;
      res.jsonp(result);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find report
 */
exports.findBookmark = function(req, res) {
  Bookmark.findOne({
    poll: req.poll._id,
    user: req.user._id
  }).exec((err, _bookmark) => {
    if (err) {
      handleError(err);
    } else {
      var result = _bookmark ? true : false;
      res.jsonp(result);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find report
 */
exports.findPollreport = function(req, res) {
  Pollreport.findOne({ poll: req.poll._id }).exec((err, _report) => {
    if (err) {
      handleError(err);
    } else {
      res.jsonp(_report);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Poll middleware
 */
exports.pollByID = function(req, res, next, id) {
  if (!mongoose.Types.ObjectId.isValid(id)) {
    return res.status(400).send({
      message: 'Poll is invalid'
    });
  }

  Poll.findById(id)
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .exec(function(err, poll) {
      if (err) {
        return next(err);
      } else if (!poll) {
        return res.status(404).send({
          message: 'No Poll with that identifier has been found'
        });
      }
      req.poll = poll;
      next();
    });
};
<commit_msg>Commited from lenh at Thu, Jul 06, 2017 11:05:54 AM<commit_after>'use strict';

/**
 * Module dependencies.
 */
var path = require('path'),
  mongoose = require('mongoose'),
  Poll = mongoose.model('Poll'),
  Opt = mongoose.model('Opt'),
  Vote = mongoose.model('Vote'),
  Voteopt = mongoose.model('Voteopt'),
  Polltag = mongoose.model('Polltag'),
  Pollreport = mongoose.model('Pollreport'),
  Polluser = mongoose.model('Polluser'),
  Report = mongoose.model('Report'),
  Bookmark = mongoose.model('Bookmark'),
  Like = mongoose.model('Like'),
  errorHandler = require(path.resolve(
    './modules/core/server/controllers/errors.server.controller'
  )),
  _ = require('lodash');
/**
 * Create a Poll
 */
exports.create = function(req, res) {
  var poll = new Poll(req.body);
  poll.user = req.user;

  var tags = req.body.tags || [];
  var opts = req.body.opts || [];
  var promises = [];

  poll
    .save()
    .then(_poll => {
      poll = _poll;
      // Tạo report cho poll
      var report = new Pollreport({ poll: poll._id });
      return report.save();
    }, handleError)
    .then(_report => {
      // Lưu tag vào db
      tags.forEach(tag => {
        var polltag = new Polltag({ tag: tag, poll: poll._id });
        promises.push(polltag.save());
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      // Lưu options vào db
      promises = [];
      opts.forEach(opt => {
        var _opt = new Opt(opt);
        _opt.user = req.user;
        _opt.poll = poll._id;
        promises.push(_opt.save());
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      // Tạo biến follow mới
      promises = [];
      var _polluser = new Polluser({ poll: poll._id, user: req.user._id });
      return _polluser.save();
    }, handleError)
    .then(_polluser => {
      res.jsonp(poll);
    }, handleError);

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Show the current Poll
 */
exports.read = function(req, res) {
  // convert mongoose document to JSON
  var poll = req.poll ? req.poll.toJSON() : {};

  // Add a custom field to the Article, for determining if the current User is the "owner".
  // NOTE: This field is NOT persisted to the database, since it doesn't exist in the Article model.
  poll.isCurrentUserOwner =
    req.user &&
    poll.user &&
    poll.user._id.toString() === req.user._id.toString();
  poll.canEdit =
    req.user &&
    req.user.roles &&
    req.user.roles.length &&
    req.user.roles.indexOf('admin') > -1;

  res.jsonp(poll);
};

/**
 * Update a Poll
 */
exports.update = function(req, res) {
  var poll = req.poll;
  poll = _.extend(poll, req.body);
  var tags = req.body.tags || [];
  var opts = req.body.opts || [];
  var promises = [];
  poll
    .save()
    .then(_poll => {
      poll = _poll;
      return Polltag.remove({ poll: _poll._id });
    }, handleError)
    .then(() => {
      tags.forEach(tag => {
        var polltag = new Polltag({ tag: tag, poll: poll._id });
        promises.push(polltag.save());
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      promises = [];
      opts.forEach(opt => {
        if (opt._id) {
          promises.push(
            Opt.update(
              {
                _id: opt._id
              },
              {
                $set: {
                  title: opt.title,
                  color: opt.color,
                  body: opt.body
                }
              }
            ).exec()
          );
        } else {
          var _opt = new Opt(opt);
          _opt.user = req.user;
          _opt.poll = poll;
          promises.push(_opt.save());
        }
      });
      return Promise.all(promises);
    }, handleError)
    .then(_opts => {
      promises = [];
      res.jsonp(poll);
    }, handleError);

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Delete an Poll
 */
exports.delete = function(req, res) {
  var poll = req.poll;
  poll
    .remove()
    .then(() => {
      return Opt.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      var promises = [];
      Vote.find({ poll: poll._id }).exec((err, votes) => {
        votes.forEach(vote => {
          promises.push(Voteopt.remove({ vote: vote._id }));
        });
      });
      return Promise.all(promises);
    }, handleError)
    .then(() => {
      return Vote.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Pollreport.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Polltag.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Report.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Bookmark.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Like.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      return Polluser.remove({ poll: poll._id });
    }, handleError)
    .then(() => {
      res.jsonp(poll);
    }, handleError);

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * List of Polls
 */
exports.list = function(req, res) {
  Poll.find()
    .sort('-created')
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .exec(function(err, polls) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(polls);
      }
    });
};

/**
 * List of Offset
 */
exports.findPolls = function(req, res) {
  var page = req.params.page || 0;
  Poll.find({ isPublic: true })
    .sort('-created')
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .skip(10 * page)
    .limit(10)
    .exec(function(err, polls) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(polls);
      }
    });
};

/**
 * List of Hot
 */
exports.findHotPolls = function(req, res) {
  var page = req.params.page || 0;
  Poll.find({ isPublic: true })
    .sort('-likeCnt')
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .skip(10 * page)
    .limit(10)
    .exec(function(err, polls) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(polls);
      }
    });
};

/**
 * List of Opts in poll
 */
exports.findOpts = function(req, res) {
  Poll.findOpts(req.poll._id)
    .populate('user', 'displayName')
    .exec(function(err, opts) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(opts);
      }
    });
};

/**
 * List of Cmts in poll
 */
exports.findCmts = function(req, res) {
  var page = req.params.page || 0;
  Poll.findCmts(req.poll._id)
    .sort('-created')
    .populate('user', 'displayName profileImageURL')
    .skip(10 * page)
    .limit(10)
    .exec(function(err, cmts) {
      if (err) {
        return res.status(400).send({
          message: errorHandler.getErrorMessage(err)
        });
      } else {
        res.jsonp(cmts);
      }
    });
};

/**
 * List of Tags in poll
 */
exports.findTags = function(req, res) {
  Poll.findTags(req.poll._id).populate('tag').exec(function(err, polltags) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.jsonp(polltags);
    }
  });
};

/**
 * List of Votes in poll
 */
exports.findVotes = function(req, res) {
  Poll.findVotes(req.poll._id).exec(function(err, votes) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.jsonp(votes);
    }
  });
};

/**
 * Vote in poll of user
 */
exports.findOwnerVote = function(req, res) {
  var condition = {};
  condition.poll = req.poll._id;
  if (req.user) {
    condition.user = req.user._id;
    condition.guest = false;
  } else {
    condition.ip =
      req.headers['X-Forwarded-For'] ||
      req.headers['x-forwarded-for'] ||
      req.client.remoteAddress;
    condition.guest = true;
  }
  Poll.findOwnerVote(condition).exec(function(err, vote) {
    if (err) {
      return res.status(400).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.jsonp(vote);
    }
  });
};

/**
 * Get all info of vote in poll
 */
exports.findVoteopts = function(req, res) {
  var rs = {}, ids;
  Poll.findVotes(req.poll._id).exec(function(err, _votes) {
    if (err) {
      handleError(err);
    } else {
      rs.votes = _votes;
      rs.voteopts = [];
      ids = _.pluck(_votes, '_id');
      Voteopt.find({ vote: { $in: ids } }).exec(function(err, opts) {
        if (err) {
          handleError(err);
        } else {
          rs.voteopts = opts;
          res.jsonp(rs);
        }
      });
    }
  });

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Get Like of user on this poll
 */
exports.findPollLike = function(req, res) {
  var condition = { poll: req.poll._id, user: req.user._id };
  Like.findOne(condition).exec(function(err, like) {
    if (err) {
      handleError(err);
    } else {
      res.jsonp(like);
    }
  });

  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find pollusers
 */
exports.findPolluser = function(req, res) {
  Polluser.findOne({
    poll: req.poll._id,
    user: req.user._id
  }).exec((err, _polluser) => {
    if (err) {
      handleError(err);
    } else {
      res.jsonp(_polluser);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find report
 */
exports.findReport = function(req, res) {
  Report.findOne({
    poll: req.poll._id,
    user: req.user._id
  }).exec((err, _report) => {
    if (err) {
      handleError(err);
    } else {
      var result = _report ? true : false;
      res.jsonp(result);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find report
 */
exports.findBookmark = function(req, res) {
  Bookmark.findOne({
    poll: req.poll._id,
    user: req.user._id
  }).exec((err, _bookmark) => {
    if (err) {
      handleError(err);
    } else {
      var result = _bookmark ? true : false;
      res.jsonp(result);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Find report
 */
exports.findPollreport = function(req, res) {
  Pollreport.findOne({ poll: req.poll._id }).exec((err, _report) => {
    if (err) {
      handleError(err);
    } else {
      res.jsonp(_report);
    }
  });
  function handleError(err) {
    return res.status(400).send({
      message: errorHandler.getErrorMessage(err)
    });
  }
};

/**
 * Poll middleware
 */
exports.pollByID = function(req, res, next, id) {
  if (!mongoose.Types.ObjectId.isValid(id)) {
    return res.status(400).send({
      message: 'Poll is invalid'
    });
  }

  Poll.findById(id)
    .populate('category', 'name icon')
    .populate('user', 'displayName profileImageURL')
    .exec(function(err, poll) {
      if (err) {
        return next(err);
      } else if (!poll) {
        return res.status(404).send({
          message: 'No Poll with that identifier has been found'
        });
      }
      req.poll = poll;
      next();
    });
};
<|endoftext|>


<commit_before>/* global describe */
/* global it */

const should = require('should')
const sw = require('../lib/stopword.js')

describe('general stopwordiness:', function () {
  it('should remove stopwords, should default to english, should preserve case', function () {
    const oldString = 'a really Interesting string with some words'.split(' ')
    const newString = sw.removeStopwords(oldString)
    should.exist(sw.removeStopwords(oldString))
    newString.should.eql([ 'really', 'Interesting', 'string', 'words' ])
  })

  it('should remove custom stopwords', function () {
    const oldString = 'a really interesting string with some words'.split(' ')
    const newString = sw.removeStopwords(oldString, ['interesting'])
    newString.should.eql([ 'a', 'really', 'string', 'with', 'some', 'words' ])
  })

  it('should not remove any stopwords', function () {
    const oldString = 'a really interesting string with some words'.split(' ')
    const newString = sw.removeStopwords(oldString, [])
    newString.should.eql([ 'a', 'really', 'interesting', 'string', 'with', 'some', 'words' ])
  })

  it('should remove stopwords that have a non standard separator', function () {
    const oldString = 'a.really,interesting string.with,some.words'.split(/[\\., ]+/)
    const newString = sw.removeStopwords(oldString)
    newString.should.eql([ 'really', 'interesting', 'string', 'words' ])
  })

  it('should specify a custom input separator', function () {
    const oldString = 'a-really-interesting-string-with-some words'.split('-')
    const newString = sw.removeStopwords(oldString)
    newString.should.eql([ 'really', 'interesting', 'string', 'some words' ])
  })

  it('should remove norwegian stopwords', function () {
    const oldString = 'dette er en tekst som har nørske tegn øæåø øæåø æææ'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.no)
    newString.should.eql([ 'tekst', 'nørske', 'tegn', 'øæåø', 'øæåø', 'æææ' ])
  })

  it('should remove swedish stopwords and preserve case', function () {
    const oldString = 'Trädgårdsägare är beredda att pröva vad som helst för att bli av med de hatade mördarsniglarna åäö'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.sv)
    newString.should.eql([ 'Trädgårdsägare', 'beredda', 'pröva', 'helst', 'hatade', 'mördarsniglarna', 'åäö' ])
  })

  it('should remove danish stopwords', function () {
    const oldString = 'gæsterne i musikhuset i aarhus bør fremover sende en venlig tanke til den afdøde købmand herman salling når de skal til koncert eller se teater i det aarhusianske kulturhus æøå'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.da)
    newString.should.eql([ 'gæsterne', 'musikhuset', 'aarhus', 'bør', 'fremover', 'sende', 'venlig', 'tanke', 'afdøde', 'købmand', 'herman', 'salling', 'koncert', 'teater', 'aarhusianske', 'kulturhus', 'æøå' ])
  })

  it('should remove hindu stopwords', function () {
    const oldString = 'केंद्र सरकार पर्यावरण के माकूल घरों ग्रीन होम्स को बढ़ावा देने की दिशा में गंभीरता से सोच रही है। ग्रीन हाउसिंग सोसायटी डिवेलप करने के लिए सरकार सस्ते लोन और कम रजिस्ट्रेशन फीस जैसी सुविधाएं देगी। क्लाइमेट चेंज से लड़ने की दिशा में केंद्र इस तरह की रिहायशी कॉलोनियां विकसित करने की दिशा में सोच रही है। बता दें कि ग्रीन होम्स वे घर हैं, जो पर्यावरण को ध्यान में रखकर विकसित किए जाते हैं। इनमें पर्यावरण के नजरिए से एनर्जी जल संसाधन और बिल्डिंग मटीरियल्स का प्रभावशाली इस्तेमाल किया जाता है। सरकारी सूत्रों ने बताया कि ग्रीन होम्स को बढ़ावा देने के लिए ही इससे जुड़े नियम-कायदे यानी एनर्जी कंजर्वेशन बिल्डिंग कोड फॉर रेजिडेंशल सेक्टर तैयार किया जा चुका है। ये नियम में सरकारी और कमर्शल इमारतों से संबंधित कोड की तर्ज पर ही हैं। ऊर्जा मंत्री पीयूष गोयल सोमवार को पेश कर सकते हैं। इसे भारतीय रीयल्टी सेक्टर में इको फ्रेंडली निर्माण की दिशा में बड़ा कदम माना जा सकता है। सूत्रों ने बताया कि ऊर्जा मंत्रालय के अंतर्गत काम करने वाले ब्यूरो ऑफ एनर्जी एफ़िशंसी एक योजना पर काम कर रहा है। मकसद ऐसे घरों को बढ़ावा देना है जहां ऊर्जा का प्रभावशाली इस्तेमाल हो सके। यानी यहां रोशनी या कूलिंग के लिए संसाधनों की कम डिमांड विकसित की जा सके। इसी कोशिश के तहत वर्तमान रेजिडेंशल इमारतों में भी नए उपकरणों का इस्तेमाल करके ऊर्जा के कम और प्रभावशाली इस्तेमाल को बढ़ावा देना है।'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.hi)
    newString.should.eql([ 'है।' ])
  })

})

describe('error handling', function () {
  it('should return throw an error if specified language is not supported', function () {
    (function () {
      sw.getStopwords('xx')
    }).should.throw()
  })
})
<commit_msg>Update test.js<commit_after>/* global describe */
/* global it */

const should = require('should')
const sw = require('../lib/stopword.js')

describe('general stopwordiness:', function () {
  it('should remove stopwords, should default to english, should preserve case', function () {
    const oldString = 'a really Interesting string with some words'.split(' ')
    const newString = sw.removeStopwords(oldString)
    should.exist(sw.removeStopwords(oldString))
    newString.should.eql([ 'really', 'Interesting', 'string', 'words' ])
  })

  it('should remove custom stopwords', function () {
    const oldString = 'a really interesting string with some words'.split(' ')
    const newString = sw.removeStopwords(oldString, ['interesting'])
    newString.should.eql([ 'a', 'really', 'string', 'with', 'some', 'words' ])
  })

  it('should not remove any stopwords', function () {
    const oldString = 'a really interesting string with some words'.split(' ')
    const newString = sw.removeStopwords(oldString, [])
    newString.should.eql([ 'a', 'really', 'interesting', 'string', 'with', 'some', 'words' ])
  })

  it('should remove stopwords that have a non standard separator', function () {
    const oldString = 'a.really,interesting string.with,some.words'.split(/[\\., ]+/)
    const newString = sw.removeStopwords(oldString)
    newString.should.eql([ 'really', 'interesting', 'string', 'words' ])
  })

  it('should specify a custom input separator', function () {
    const oldString = 'a-really-interesting-string-with-some words'.split('-')
    const newString = sw.removeStopwords(oldString)
    newString.should.eql([ 'really', 'interesting', 'string', 'some words' ])
  })

  it('should remove norwegian stopwords', function () {
    const oldString = 'dette er en tekst som har nørske tegn øæåø øæåø æææ'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.no)
    newString.should.eql([ 'tekst', 'nørske', 'tegn', 'øæåø', 'øæåø', 'æææ' ])
  })

  it('should remove swedish stopwords and preserve case', function () {
    const oldString = 'Trädgårdsägare är beredda att pröva vad som helst för att bli av med de hatade mördarsniglarna åäö'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.sv)
    newString.should.eql([ 'Trädgårdsägare', 'beredda', 'pröva', 'helst', 'hatade', 'mördarsniglarna', 'åäö' ])
  })

  it('should remove danish stopwords', function () {
    const oldString = 'gæsterne i musikhuset i aarhus bør fremover sende en venlig tanke til den afdøde købmand herman salling når de skal til koncert eller se teater i det aarhusianske kulturhus æøå'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.da)
    newString.should.eql([ 'gæsterne', 'musikhuset', 'aarhus', 'bør', 'fremover', 'sende', 'venlig', 'tanke', 'afdøde', 'købmand', 'herman', 'salling', 'koncert', 'teater', 'aarhusianske', 'kulturhus', 'æøå' ])
  })

  it('should remove hindu stopwords', function () {
    const oldString = 'केंद्र सरकार पर्यावरण के माकूल घरों ग्रीन होम्स को बढ़ावा देने की दिशा में गंभीरता से सोच रही है। ग्रीन हाउसिंग सोसायटी डिवेलप करने के लिए सरकार सस्ते लोन और कम रजिस्ट्रेशन फीस जैसी सुविधाएं देगी। क्लाइमेट चेंज से लड़ने की दिशा में केंद्र इस तरह की रिहायशी कॉलोनियां विकसित करने की दिशा में सोच रही है। बता दें कि ग्रीन होम्स वे घर हैं, जो पर्यावरण को ध्यान में रखकर विकसित किए जाते हैं। इनमें पर्यावरण के नजरिए से एनर्जी जल संसाधन और बिल्डिंग मटीरियल्स का प्रभावशाली इस्तेमाल किया जाता है। सरकारी सूत्रों ने बताया कि ग्रीन होम्स को बढ़ावा देने के लिए ही इससे जुड़े नियम-कायदे यानी एनर्जी कंजर्वेशन बिल्डिंग कोड फॉर रेजिडेंशल सेक्टर तैयार किया जा चुका है। ये नियम में सरकारी और कमर्शल इमारतों से संबंधित कोड की तर्ज पर ही हैं। ऊर्जा मंत्री पीयूष गोयल सोमवार को पेश कर सकते हैं। इसे भारतीय रीयल्टी सेक्टर में इको फ्रेंडली निर्माण की दिशा में बड़ा कदम माना जा सकता है। सूत्रों ने बताया कि ऊर्जा मंत्रालय के अंतर्गत काम करने वाले ब्यूरो ऑफ एनर्जी एफ़िशंसी एक योजना पर काम कर रहा है। मकसद ऐसे घरों को बढ़ावा देना है जहां ऊर्जा का प्रभावशाली इस्तेमाल हो सके। यानी यहां रोशनी या कूलिंग के लिए संसाधनों की कम डिमांड विकसित की जा सके। इसी कोशिश के तहत वर्तमान रेजिडेंशल इमारतों में भी नए उपकरणों का इस्तेमाल करके ऊर्जा के कम और प्रभावशाली इस्तेमाल को बढ़ावा देना है।'.split(' ')
    const newString = sw.removeStopwords(oldString, sw.hi)
    newString.should.eql([ 'केंद्र', 'सरकार', 'पर्यावरण', 'के', 'माकूल', 'घरों', 'ग्रीन', 'होम्स', 'को', 'बढ़ावा', 'देने', 'की', 'दिशा', 'में', 'गंभीरता', 'से', 'सोच', 'रही', 'है।', 'ग्रीन', 'हाउसिंग', 'सोसायटी', 'डिवेलप', 'करने', 'के', 'लिए', 'सरकार', 'सस्ते', 'लोन', 'और', 'कम', 'रजिस्ट्रेशन', 'फीस', 'जैसी', 'सुविधाएं', 'देगी।', 'क्लाइमेट', 'चेंज', 'से', 'लड़ने', 'की', 'दिशा', 'में', 'केंद्र', 'इस', 'तरह', 'की', 'रिहायशी', 'कॉलोनियां', 'विकसित', 'करने', 'की', 'दिशा', 'में', 'सोच', 'रही', 'है।', 'बता', 'दें', 'कि', 'ग्रीन', 'होम्स', 'वे', 'घर', 'हैं,', 'जो', 'पर्यावरण', 'को', 'ध्यान', 'में', 'रखकर', 'विकसित', 'किए', 'जाते', 'हैं।', 'इनमें', 'पर्यावरण', 'के', 'नजरिए', 'से', 'एनर्जी', 'जल', 'संसाधन', 'और', 'बिल्डिंग', 'मटीरियल्स', 'का', 'प्रभावशाली', 'इस्तेमाल', 'किया', 'जाता', 'है।', 'सरकारी', 'सूत्रों', 'ने', 'बताया', 'कि', 'ग्रीन', 'होम्स', 'को', 'बढ़ावा', 'देने', 'के', 'लिए', 'ही', 'इससे', 'जुड़े', 'नियम-कायदे', 'यानी', 'एनर्जी', 'कंजर्वेशन', 'बिल्डिंग', 'कोड', 'फॉर', 'रेजिडेंशल', 'सेक्टर', 'तैयार', 'किया', 'जा', 'चुका', 'है।', 'ये', 'नियम', 'में', 'सरकारी', 'और', 'कमर्शल', 'इमारतों', 'से', 'संबंधित', 'कोड', 'की', 'तर्ज', 'पर', 'ही', 'हैं।', 'ऊर्जा', 'मंत्री', 'पीयूष', 'गोयल', 'सोमवार', 'को', 'पेश', 'कर', 'सकते', 'हैं।', 'इसे', 'भारतीय', 'रीयल्टी', 'सेक्टर', 'में', 'इको', 'फ्रेंडली', 'निर्माण', 'की', 'दिशा', 'में', 'बड़ा', 'कदम', 'माना', 'जा', 'सकता', 'है।', 'सूत्रों', 'ने', 'बताया', 'कि', 'ऊर्जा', 'मंत्रालय', 'के', 'अंतर्गत', 'काम', 'करने', 'वाले', 'ब्यूरो', 'ऑफ', 'एनर्जी', 'एफ़िशंसी', 'एक', 'योजना', 'पर', 'काम', 'कर', 'रहा', 'है।', 'मकसद', 'ऐसे', 'घरों', 'को', 'बढ़ावा', 'देना', 'है', 'जहां', 'ऊर्जा', 'का', 'प्रभावशाली', 'इस्तेमाल', 'हो', 'सके।', 'यानी', 'यहां', 'रोशनी', 'या', 'कूलिंग', 'के', 'लिए', 'संसाधनों', 'की', 'कम', 'डिमांड', 'विकसित', 'की', 'जा', 'सके।', 'इसी', 'कोशिश', 'के', 'तहत', 'वर्तमान', 'रेजिडेंशल', 'इमारतों', 'में', 'भी', 'नए', 'उपकरणों', 'का', 'इस्तेमाल', 'करके', 'ऊर्जा', 'के', 'कम', 'और', 'प्रभावशाली', 'इस्तेमाल', 'को', 'बढ़ावा', 'देना', 'है।' ])
  })

})

describe('error handling', function () {
  it('should return throw an error if specified language is not supported', function () {
    (function () {
      sw.getStopwords('xx')
    }).should.throw()
  })
})
<|endoftext|>


<commit_before>//function ready(fn) {
//  if (document.readyState != 'loading'){
//    fn();
//  } else {
//    document.addEventListener('DOMContentLoaded', fn);
//  }
//}
//
//function loadReusableComponents() {

  //insert elements, even before Polymer is loaded

  //first element of the original document
  var firstElement = document.body.children[0];

  // insert header after body-tag
  var header = document.createElement('uq-minimal-header');
  document.body.insertBefore(header, firstElement);

  // insert menu after header
  var menu = document.createElement('uql-menu');
  //header.appendChild(menu);
  document.body.insertBefore(menu, firstElement);

  // insert sub footer before body-tag
  var subFooter = document.createElement('uql-connect-footer');
  document.body.appendChild(subFooter);

  // insert footer before body-tag
  var footer = document.createElement('uq-minimal-footer');
  document.body.appendChild(footer);

  window.addEventListener('WebComponentsReady', function() {
    // when polymer is ready - configure elements
    header.showIAButton = (document.cookie.indexOf("iabutton") >= 0);
    header.showMenuButton = true;
    header.showSearchButton = true;

    menu.menuJson = '../uql-menu/demo/menu.json';

    header.addEventListener("menu-clicked", function(event) {
      menu.toggleMenu();
    });

    subFooter.mainDomain = 'https://www.library.uq.edu.au';
  });
//}
//
//ready(loadReusableComponents);

<commit_msg>optimized loading for drupal<commit_after>//function ready(fn) {
//  if (document.readyState != 'loading'){
//    fn();
//  } else {
//    document.addEventListener('DOMContentLoaded', fn);
//  }
//}
//
//function loadReusableComponents() {

  //insert elements, even before Polymer is loaded

  //first element of the original document
  //var firstElement = document.body.children[0];
  //
  //// insert header after body-tag
  //var header = document.createElement('uq-minimal-header');
  //document.body.insertBefore(header, firstElement);
  //
  //// insert menu after header
  //var menu = document.createElement('uql-menu');
  ////header.appendChild(menu);
  //document.body.insertBefore(menu, firstElement);
  //
  //// insert sub footer before body-tag
  //var subFooter = document.createElement('uql-connect-footer');
  //document.body.appendChild(subFooter);
  //
  //// insert footer before body-tag
  //var footer = document.createElement('uq-minimal-footer');
  //document.body.appendChild(footer);

  //window.addEventListener('WebComponentsReady', function() {
  //  // when polymer is ready - configure elements
  //  header.showIAButton = (document.cookie.indexOf("iabutton") >= 0);
  //  header.showMenuButton = true;
  //  header.showSearchButton = true;
  //
  //  menu.menuJson = '../uql-menu/demo/menu.json';
  //
  //  header.addEventListener("menu-clicked", function(event) {
  //    menu.toggleMenu();
  //  });
  //
  //  subFooter.mainDomain = 'https://www.library.uq.edu.au';
  //});
//}
//
//ready(loadReusableComponents);

window.addEventListener('WebComponentsReady', function() {
  var header = document.querySelector('uq-minimal-header');

  // when polymer is ready - configure elements
  header.showIAButton = (document.cookie.indexOf("iabutton") >= 0);
  header.showMenuButton = true;
  header.showSearchButton = true;

  var menu = document.querySelector('uql-menu');
  //menu.menuJson = '../uql-menu/demo/menu.json';

  header.addEventListener("menu-clicked", function(event) {
    menu.toggleMenu();
  });

  var subFooter = document.querySelector('uql-connect-footer');
  subFooter.mainDomain = 'https://www.library.uq.edu.au';
});

<|endoftext|>


<commit_before>/*
 * Chat Window Class
 */

/*
 * Ext JS Library 2.0.2
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 *
 * http://extjs.com/license
 */

/**
  * Ext.ux.fbk.sonet.ChatWindow Extension Class
  *
  * @author  Marco Frassoni and Davide Setti and Yakalope
  * @class Ext.ux.fbk.sonet.ChatWindow
  *
This window chat

  *

    This is a example of the json

*/

ChatWindow = Ext.extend(Ext.Window, {

    /* Construction Time Variables */

    width: 250,
    height: 250,
    iconCls: "comment-icon",
    //constrain: true,
    border:false,
    collapsible:true,
    draggable:false,
    resizable:false,
    animCollapse:false,
    constrain:true,
    closeAction: 'hide',
    layout:'anchor',
    bodyStyle:'background:#fff;',
    cls:'chat-window',

    /* Runtime Variables */

    focus: function() {
        /* focus the area where the user write instead of the entire window*/
        jabberui.focused = this.getId();
        Ext.getCmp('msgarea'+this.getId()).focus('', 5);
    },

    sendHandler: function(key,event) {
        var msgArea = this.items.items[1];
        var chatMessage = msgArea.getValue();
        if (chatMessage !== '' && chatMessage !== '\n') {
            this.addMsg(this.user, chatMessage);
            msgArea.setValue('');
            //Send Message to Jabber Connection
            jabber.sendMsg(this.getId(), chatMessage);
            this.composing = false;
        }
        msgArea.focus();
        event.stopEvent();
    },
    initComponent: function() {
        Ext.apply(this, {
            composing: false,
            setComposing: function(status) {
                if ((!status) || (!this.composing)) {
                    this.composing = status;
                    jabber.sendComposing(this.getId(), status);
                }
            },
            items: [{
                id:'msgarea'+this.getId(),
                layout:'fit',
                split:true,
                hideBorders:false,
                border:false,
                xtype:'textarea',
                hideLabel:true,
                maxLength:4000,
                maxLengthText:'The maximum length text for this field is 4000',
                anchor:'100% 20%',
                enableKeyEvents:true,
                listeners: {
                    keyup: {
                        fn: function(t, e) {
                            var kc = e.keyCode;

                            //TODO: write this better
                            // these keys don't trigger any change: if the key pressed was one of them, stop here
                            if ((kc == e.ALT) || (kc == e.CTRL) || (kc == e.SHIFT) || (kc == 15) || (kc == e.UP) || (kc == e.DOWN) || (kc == e.LEFT) || (kc == e.RIGHT) || (kc == e.CAPS_LOCK) || (kc == e.HOME) || (kc == e.END) || (kc === 0) || (kc == e.ENTER))
                                return;

                            this.setComposing(true);
                            t.dTask.delay(3000);
                        }
                        ,scope:this
                    },
                    beforerender: {
                        fn: function(t) {
                            t.dTask = new Ext.util.DelayedTask(
                                this.setComposing, this, [false]
                            );
                        }
                        ,scope:this
                    },
                    focus: function(t) {
                        Ext.getCmp(t.getId().substring(7)).setActive(true);
                    },
                    blur: function(t) {
                        Ext.getCmp(t.getId().substring(7)).setActive();
                    }
                }
            },{
                html:'Show chat history'
                ,anchor: '100% 10%'
                ,border: false
                ,style:'padding: 5px 0 0 5px;'
            }],
            keys: [{
                key:13,
                fn:this.sendHandler,
                scope:this
            },{
                key:Ext.EventObject.TAB,
                fn:jabberui.focusNext,
                scope:jabberui
            }
            ]
        });
        ChatWindow.superclass.initComponent.apply(this, arguments);
        //jabberui.addChatToList(this.getId());
    },
    render: function() {
        /*
         * Set up chat, chatStore, and dataview
         * objects for use in the window
         */
        var id = this.getId()
            ,chatId = 'chat' + id
            ,chatStoreId = 'chatStore' + id
            ,chat =  {
            id:chatId,
            msgs:[],
                update: function(msg, scope) {
                    this.msgs.push(msg);
                    scope.chatStore.load();
                },
                clear: function(scope) {
                    this.msgs = new Array();
                    scope.chatStore.load();
                }
            }
            ,chatStore = new Ext.data.Store({
                id:chatStoreId,
                proxy: new Ext.data.MemoryProxy(chat),
                reader: new Ext.data.JsonReader({
                    root:'msgs'},
                [
                   {name: 'username'},
                   {name: 'time'},
                   {name: 'msg'}
                ]),
                listeners: {
                    loadexception: function (o, responce, e, exception) {
                        Ext.MessageBox.alert('Error', exception);
                    }
                }
            });

        var dataview = new Ext.DataView({
            id:'chatview' + this.getId()
            ,store:chatStore
            ,tpl: new Ext.XTemplate(
                '<tpl for=".">',
                '
{username} ({time}): {msg}
',
                '</tpl>',
                '{[this.info]}'
                ,{
                    compiled:true
                    ,info:''
                }
            )
            ,itemSelector:'div.msg'
        });

        var panel = new Ext.Panel({
            id:'chatpanel' + this.getId()
            ,items: dataview
            ,anchor:'100% 70%'
            ,autoScroll: true
            ,border: false
        });

        this.chat = chat;
        this.chatStore = chatStore;
        this.items.insert(0, panel.id, panel);

        ChatWindow.superclass.render.apply(this, arguments);
    },
    addMsg:function(userName, msg, timestamp) {
        var chat = Ext.getCmp(this.getId()).chat;

        msg = Ext.util.Format.htmlEncode(msg).urlize().smilize().replace(/\n/g,"
");
        if (userName !== this.user) {
            userName = userName.toString().split('@')[0];
        }
        if (!timestamp) {
            timestamp = new Date();
        }

        var sTime; //string containg formatted time
        //show day and month only if day != today
        if (timestamp.format('jmY') == (new Date()).format('jmY')){
            sTime = timestamp.format('G:i');
        } else {
            sTime = timestamp.format('G:i, M j');
        }

        var lMsg = {
            username: userName,
            time: sTime,
            msg: msg
        };
        chat.update(lMsg, this);
        var panel = Ext.getCmp('chatpanel'+this.getId());
        panel.body.scroll('down', 5000, true);

        // play sounds
        var tm = msg.trim();
        if ((soundManager.enabled) && (tm.split(' ', 1)[0] == '/play')){
            var i = tm.indexOf(' ');
            var sound = tm.substring(i).trim();

            if (sound == 'trombone') {
                soundManager.play('trombone', 'sound/sad_trombone.mp3');
            }
            else if (sound == 'moo') {
                soundManager.play('moo', 'sound/cow.mp3');
            }
            else if (sound == 'cheer') {
                soundManager.play('cheer', 'sound/cheer.mp3');
            }
            else if (sound == 'fart') {
                soundManager.play('fart', 'sound/fartus_tubartus.mp3');
            }
        }

        /* now do show signals if the message comes from another user */
        if (userName == this.user) return;

        // check also for document.hasFocus existence: WebKit has not yet implemented it
        if ((!this.isActive) || (typeof document.hasFocus == 'undefined') || (!document.hasFocus())) {
            this.visualBeep = true;
        }
    },
    listeners: {
        beforehide: function(t) {
            jabberui.removeChat(t.getId());
            jabberui.refreshChats();
        },
        beforeshow: function(t){
            jabberui.addChat(t.getId());
            jabberui.refreshChats();
        },
        collapse: function(panel){
            jabberui.refreshChats();
        },
        expand: function(panel){
            jabberui.refreshChats();
        },
        activate: function(t){
            t.isActive = true;
            t.visualBeep = false;
        },
        deactivate: function(t){
            t.isActive = false;
        }
    }
 });

 Ext.reg('chatwindow', ChatWindow);
<commit_msg>Sizing text area for ChatWindow<commit_after>/*
 * Chat Window Class
 */

/*
 * Ext JS Library 2.0.2
 * Copyright(c) 2006-2008, Ext JS, LLC.
 * licensing@extjs.com
 *
 * http://extjs.com/license
 */

/**
  * Ext.ux.fbk.sonet.ChatWindow Extension Class
  *
  * @author  Marco Frassoni and Davide Setti and Yakalope
  * @class Ext.ux.fbk.sonet.ChatWindow
  *
This window chat

  *

    This is a example of the json

*/

ChatWindow = Ext.extend(Ext.Window, {

    /* Construction Time Variables */

    width: 250,
    height: 250,
    iconCls: "comment-icon",
    //constrain: true,
    border:false,
    collapsible:true,
    draggable:false,
    resizable:false,
    animCollapse:false,
    constrain:true,
    closeAction: 'hide',
    layout:'anchor',
    bodyStyle:'background:#fff;',
    cls:'chat-window',

    /* Runtime Variables */

    focus: function() {
        /* focus the area where the user write instead of the entire window*/
        jabberui.focused = this.getId();
        Ext.getCmp('msgarea'+this.getId()).focus('', 5);
    },

    sendHandler: function(key,event) {
        var msgArea = this.items.items[1];
        var chatMessage = msgArea.getValue();
        if (chatMessage !== '' && chatMessage !== '\n') {
            this.addMsg(this.user, chatMessage);
            msgArea.setValue('');
            //Send Message to Jabber Connection
            jabber.sendMsg(this.getId(), chatMessage);
            this.composing = false;
        }
        msgArea.focus();
        event.stopEvent();
    },
    initComponent: function() {
        Ext.apply(this, {
            composing: false,
            setComposing: function(status) {
                if ((!status) || (!this.composing)) {
                    this.composing = status;
                    jabber.sendComposing(this.getId(), status);
                }
            },
            items: [{
                id:'msgarea'+this.getId(),
                layout:'fit',
                split:true,
                hideBorders:false,
                border:false,
                xtype:'textarea',
                hideLabel:true,
                maxLength:4000,
                maxLengthText:'The maximum length text for this field is 4000',
                anchor:'100% 25%',
                enableKeyEvents:true,
                listeners: {
                    keyup: {
                        fn: function(t, e) {
                            var kc = e.keyCode;

                            //TODO: write this better
                            // these keys don't trigger any change: if the key pressed was one of them, stop here
                            if ((kc == e.ALT) || (kc == e.CTRL) || (kc == e.SHIFT) || (kc == 15) || (kc == e.UP) || (kc == e.DOWN) || (kc == e.LEFT) || (kc == e.RIGHT) || (kc == e.CAPS_LOCK) || (kc == e.HOME) || (kc == e.END) || (kc === 0) || (kc == e.ENTER))
                                return;

                            this.setComposing(true);
                            t.dTask.delay(3000);
                        }
                        ,scope:this
                    },
                    beforerender: {
                        fn: function(t) {
                            t.dTask = new Ext.util.DelayedTask(
                                this.setComposing, this, [false]
                            );
                        }
                        ,scope:this
                    },
                    focus: function(t) {
                        Ext.getCmp(t.getId().substring(7)).setActive(true);
                    },
                    blur: function(t) {
                        Ext.getCmp(t.getId().substring(7)).setActive();
                    }
                }
            },{
                html:'Show chat history'
                ,anchor: '100% 10%'
                ,border: false
                ,style:'padding: 5px 0 0 5px;'
            }],
            keys: [{
                key:13,
                fn:this.sendHandler,
                scope:this
            },{
                key:Ext.EventObject.TAB,
                fn:jabberui.focusNext,
                scope:jabberui
            }
            ]
        });
        ChatWindow.superclass.initComponent.apply(this, arguments);
        //jabberui.addChatToList(this.getId());
    },
    render: function() {
        /*
         * Set up chat, chatStore, and dataview
         * objects for use in the window
         */
        var id = this.getId()
            ,chatId = 'chat' + id
            ,chatStoreId = 'chatStore' + id
            ,chat =  {
            id:chatId,
            msgs:[],
                update: function(msg, scope) {
                    this.msgs.push(msg);
                    scope.chatStore.load();
                },
                clear: function(scope) {
                    this.msgs = new Array();
                    scope.chatStore.load();
                }
            }
            ,chatStore = new Ext.data.Store({
                id:chatStoreId,
                proxy: new Ext.data.MemoryProxy(chat),
                reader: new Ext.data.JsonReader({
                    root:'msgs'},
                [
                   {name: 'username'},
                   {name: 'time'},
                   {name: 'msg'}
                ]),
                listeners: {
                    loadexception: function (o, responce, e, exception) {
                        Ext.MessageBox.alert('Error', exception);
                    }
                }
            });

        var dataview = new Ext.DataView({
            id:'chatview' + this.getId()
            ,store:chatStore
            ,tpl: new Ext.XTemplate(
                '<tpl for=".">',
                '
{username} ({time}): {msg}
',
                '</tpl>',
                '{[this.info]}'
                ,{
                    compiled:true
                    ,info:''
                }
            )
            ,itemSelector:'div.msg'
        });

        var panel = new Ext.Panel({
            id:'chatpanel' + this.getId()
            ,items: dataview
            ,anchor:'100% 65%'
            ,autoScroll: true
            ,border: false
        });

        this.chat = chat;
        this.chatStore = chatStore;
        this.items.insert(0, panel.id, panel);

        ChatWindow.superclass.render.apply(this, arguments);
    },
    addMsg:function(userName, msg, timestamp) {
        var chat = Ext.getCmp(this.getId()).chat;

        msg = Ext.util.Format.htmlEncode(msg).urlize().smilize().replace(/\n/g,"
");
        if (userName !== this.user) {
            userName = userName.toString().split('@')[0];
        }
        if (!timestamp) {
            timestamp = new Date();
        }

        var sTime; //string containg formatted time
        //show day and month only if day != today
        if (timestamp.format('jmY') == (new Date()).format('jmY')){
            sTime = timestamp.format('G:i');
        } else {
            sTime = timestamp.format('G:i, M j');
        }

        var lMsg = {
            username: userName,
            time: sTime,
            msg: msg
        };
        chat.update(lMsg, this);
        var panel = Ext.getCmp('chatpanel'+this.getId());
        panel.body.scroll('down', 5000, true);

        // play sounds
        var tm = msg.trim();
        if ((soundManager.enabled) && (tm.split(' ', 1)[0] == '/play')){
            var i = tm.indexOf(' ');
            var sound = tm.substring(i).trim();

            if (sound == 'trombone') {
                soundManager.play('trombone', 'sound/sad_trombone.mp3');
            }
            else if (sound == 'moo') {
                soundManager.play('moo', 'sound/cow.mp3');
            }
            else if (sound == 'cheer') {
                soundManager.play('cheer', 'sound/cheer.mp3');
            }
            else if (sound == 'fart') {
                soundManager.play('fart', 'sound/fartus_tubartus.mp3');
            }
        }

        /* now do show signals if the message comes from another user */
        if (userName == this.user) return;

        // check also for document.hasFocus existence: WebKit has not yet implemented it
        if ((!this.isActive) || (typeof document.hasFocus == 'undefined') || (!document.hasFocus())) {
            this.visualBeep = true;
        }
    },
    listeners: {
        beforehide: function(t) {
            jabberui.removeChat(t.getId());
            jabberui.refreshChats();
        },
        beforeshow: function(t){
            jabberui.addChat(t.getId());
            jabberui.refreshChats();
        },
        collapse: function(panel){
            jabberui.refreshChats();
        },
        expand: function(panel){
            jabberui.refreshChats();
        },
        activate: function(t){
            t.isActive = true;
            t.visualBeep = false;
        },
        deactivate: function(t){
            t.isActive = false;
        }
    }
 });

 Ext.reg('chatwindow', ChatWindow);
<|endoftext|>


<commit_before>
<commit_msg>Update PostgresInitOptions.spec.js<commit_after>const Parse = require('parse/node').Parse;
const PostgresStorageAdapter = require('../src/Adapters/Storage/Postgres/PostgresStorageAdapter');
const postgresURI = 'postgres://username:password@localhost:5432/db-name';

//public schema
const databaseOptions1 = {
	initOptions: {
		connect: function (client, dc, isFresh) {
			if (isFresh) {
				client.query('SET search_path = public');
			}
		}
	}
};

//not exists schema
const databaseOptions2 = {
	initOptions: {
		connect: function (client, dc, isFresh) {
			if (isFresh) {
				client.query('SET search_path = not_exists_schema');
			}
		}
	}
};

const GameScore = Parse.Object.extend({
	className: "GameScore"
});

describe('Postgres database init options', () => {
	it('create server with public schema databaseOptions,shoud be ok', (done) => {
		reconfigureServer({
			databaseAdapter: new PostgresStorageAdapter({
				uri: postgresURI, collectionPrefix: 'test_',
				databaseOptions: databaseOptions1
			})
		}).then(done, fail);
	});

	it("save new GameScore in public schema", function (done) {
		var score = new GameScore({ "score": 1337, "playerName": "Sean Plott", "cheatMode": false });
		score.save().then(done, fail);
	});

	it('create server with not exists schema databaseOptions,shoud be fail', (done) => {
		reconfigureServer({
			databaseAdapter: new PostgresStorageAdapter({
				uri: postgresURI, collectionPrefix: 'test_',
				databaseOptions: databaseOptions2
			})
		}).catch(error => {
			expect(error.code).toEqual('3F000');
			done();
		});
	});
});
<|endoftext|>


<commit_before>'use strict';

var dispatchGridEvent = require('../../lib/dispatchGridEvent.js');

/**
 * @namespace dataModelEventHandlers
 * @desc These handlers are called by {@link module:decorators.dispatchDataModelEvent dataModel.dispatchEvent}.
 *
 * (Hypergrid registers itself with the data model by calling `dataModel.addListener`. Both `addListener` and `dispatchEvent` are optional API. If the data model lacks `addListener`, Hypergrid inserts a bound version of `dispatchEvent` directly into the data model.)
 *
 * They perform some Hypergrid housekeeping chores before (and possibly after) optionally re-emiting the event as a standard
 * Hypergrid event (to the `<canvas>` element).
 *
 * All the built-in data model events re-emit their events (all non-cancelable).
 *
 * #### Coding patterns
 * These handlers should return a boolean if they re-emit the event as a grid event themselves (via `dispatchGridEvent`), when they have chores to perform post-re-emission. If they don't, they should return `undefined` which signals the caller (`dataModel.dispatchEvent`) to re-emit it as a grid event as a final step for the handler.
 *
 * Given the above, there are four typical coding patterns for these handlers:
 * 1. Perform chores with no event re-emission:
 * ```
 * Chores();
 * return true; // (or any defined value) signals caller not to re-emit the event
 * ```
 * 2. First perform chores; then re-emit the event as a grid event:
 * ```
 * Chores();
 * return undefined; // (or omit) signals caller to re-emit the event for us
 * ```
 * 3. First perform some pre-re-emit chores (optional); then re-emit the event as a _non-cancelable_ grid event; then perform remaining chores:
 * ```
 * optionalPreReemitChores();
 * dispatchGridEvent.call(this, event.type, event); // non-cancelable
 * remainingChores();
 * return true; // signals caller that we've already re-emitted the event and it was not canceled
 * ```
 * 3. First perform some pre-re-emit chores (optional); then re-emit the event as a _cancelable_ grid event; then perform remaining chores conditionally [iff](https://en.wikipedia.org/wiki/If_and_only_if) not canceled (_important:_ note the `true` in the following):
 * ```
 * optionalPreReemitChores();
 * if (dispatchGridEvent.call(this, event.type, true, event)) { // `true` here means cancelable
 *     conditionalChores();
 *     return true; // signals caller that we've already re-emitted the event (which was not canceled)
 * } else {
 *     return false; // signals caller that we've already re-emitted the event (which was canceled)
 * }
 * ```
 */
module.exports = {
    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-schema-loaded}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-schema-loaded': function(event) {
        dispatchGridEvent.call(this, event.type, event);
        this.behavior.createColumns();
        return true;
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-loaded}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-loaded': function(event) {
        this.repaint();
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-shape-changed}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-shape-changed': function(event) {
        this.behaviorShapeChanged();
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-prereindex}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-prereindex': function(event) {
        saveSelectedRowsAndColumns.call(this);
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {{type}} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-postreindex}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-postreindex': function(event) {
        reselectRowsAndColumns.call(this);
        this.behaviorShapeChanged();
    }
};

function saveSelectedRowsAndColumns() {
    saveSelectedDataRowIndexes.call(this);
    saveSelectedColumnNames.call(this);
}

function reselectRowsAndColumns() {
    this.selectionModel.reset();
    reselectRowsByDataRowIndexes.call(this);
    reselectColumnsByNames.call(this);
}

/**
 * Save underlying data row indexes backing current grid row selections in `grid.selectedDataRowIndexes`.
 *
 * This call should be paired with a subsequent call to `reselectRowsByUnderlyingIndexes`.
 * @private
 * @this {Hypergrid}
 * @returns {number|undefined} Number of selected rows or `undefined` if `restoreRowSelections` is falsy.
 */
function saveSelectedDataRowIndexes() {
    if (this.properties.restoreRowSelections) {
        var dataModel = this.behavior.dataModel;

        this.selectedDataRowIndexes = this.getSelectedRows().map(function(selectedRowIndex) {
            return dataModel.getRowIndex(selectedRowIndex);
        });

        return this.selectedDataRowIndexes.length;
    }
}

/**
 * Re-establish grid row selections based on underlying data row indexes saved by `getSelectedDataRowIndexes` which should be called first.
 *
 * Note that not all previously selected rows will necessarily be available after a data transformation. Even if they appear to be available, if they are not from the same data set, restoring the selections may not make sense. When this is the case, the application should set the `restoreRowSelections` property to `false`.
 * @private
 * @this {Hypergrid}
 * @returns {number|undefined} Number of rows reselected or `undefined` if there were no previously selected rows.
 */
function reselectRowsByDataRowIndexes() {
    var dataRowIndexes = this.selectedDataRowIndexes;
    if (dataRowIndexes) {
        delete this.selectedDataRowIndexes;

        var i, r,
            dataModel = this.behavior.dataModel,
            rowCount = this.getRowCount(),
            selectedRowCount = dataRowIndexes.length,
            gridRowIndexes = [],
            selectionModel = this.selectionModel;

        for (r = 0; selectedRowCount && r < rowCount; ++r) {
            i = dataRowIndexes.indexOf(dataModel.getRowIndex(r));
            if (i >= 0) {
                gridRowIndexes.push(r);
                delete dataRowIndexes[i]; // might make indexOf increasingly faster as deleted elements are not enumerable
                selectedRowCount--; // count down so we can bail early if all found
            }
        }

        gridRowIndexes.forEach(function(gridRowIndex) {
            selectionModel.selectRow(gridRowIndex);
        });

        return gridRowIndexes.length;
    }
}

/**
 * Save data column names of currently column selections in `grid.selectedColumnNames`.
 *
 * This call should be paired with a subsequent call to `reselectColumnsByNames`.
 * @private
 * @this {Hypergrid}
 * @param sourceColumnNames
 * @returns {number|undefined} Number of selected columns or `undefined` if `restoreColumnSelections` is falsy.
 */
function saveSelectedColumnNames() {
    if (this.properties.restoreColumnSelections) {
        var behavior = this.behavior;

        this.selectedColumnNames = this.getSelectedColumns().map(function(selectedColumnIndex) {
            return behavior.getActiveColumn(selectedColumnIndex).name;
        });

        return this.selectedColumnNames.length;
    }
}

/**
 * Re-establish columns selections based on column names saved by `getSelectedColumnNames` which should be called first.
 *
 * Note that not all preveiously selected columns wil necessarily be available after a data transformation. Even if they appear to be available, if they are not from the same data set, restoring the selections may not make sense. When this is the case, the application should set the `restoreRowSelections` property to `false`.
 * @private
 * @this {Hypergrid}
 * @param sourceColumnNames
 * @returns {number|undefined} Number of rows reselected or `undefined` if there were no previously selected columns.
 */
function reselectColumnsByNames(sourceColumnNames) {
    var selectedColumnNames = this.selectedColumnNames;
    if (selectedColumnNames) {
        delete this.selectedColumnNames;

        var behavior = this.behavior,
            selectionModel = this.selectionModel;

        return selectedColumnNames.reduce(function(reselectedCount, columnName) {
            var activeColumnIndex = behavior.getActiveColumnIndex(columnName);
            if (activeColumnIndex) {
                selectionModel.selectColumn(activeColumnIndex);
                reselectedCount++;
            }
            return reselectedCount;
        }, 0);
    }
}
<commit_msg>decorate schema *before* dispatching schema-loaded event<commit_after>'use strict';

/**
 * @namespace dataModelEventHandlers
 * @desc These handlers are called by {@link module:decorators.dispatchDataModelEvent dataModel.dispatchEvent}.
 *
 * (Hypergrid registers itself with the data model by calling `dataModel.addListener`. Both `addListener` and `dispatchEvent` are optional API. If the data model lacks `addListener`, Hypergrid inserts a bound version of `dispatchEvent` directly into the data model.)
 *
 * They perform some Hypergrid housekeeping chores before (and possibly after) optionally re-emiting the event as a standard
 * Hypergrid event (to the `<canvas>` element).
 *
 * All the built-in data model events re-emit their events (all non-cancelable).
 *
 * #### Coding patterns
 * These handlers should return a boolean if they re-emit the event as a grid event themselves, when they have chores to perform post-re-emission. If they don't, they should return `undefined` which signals the caller (`dataModel.dispatchEvent`) to re-emit it as a grid event as a final step for the handler.
 *
 * Given the above, there are four typical coding patterns for these handlers:
 * 1. Perform chores with no event re-emission:
 * ```
 * Chores();
 * return true; // (or any defined value) signals caller not to re-emit the event
 * ```
 * 2. First perform chores; then re-emit the event as a grid event:
 * ```
 * Chores();
 * return undefined; // (or omit) signals caller to re-emit the event for us
 * ```
 * 3. First perform some pre-re-emit chores (optional); then re-emit the event as a _non-cancelable_ grid event; then perform remaining chores:
 * ```
 * optionalPreReemitChores();
 * var dispatchGridEvent = require('../../lib/dispatchGridEvent.js');
 * dispatchGridEvent.call(this, event.type, event); // non-cancelable
 * remainingChores();
 * return true; // signals caller that we've already re-emitted the event and it was not canceled
 * ```
 * 3. First perform some pre-re-emit chores (optional); then re-emit the event as a _cancelable_ grid event; then perform remaining chores conditionally [iff](https://en.wikipedia.org/wiki/If_and_only_if) not canceled (_important:_ note the `true` in the following):
 * ```
 * optionalPreReemitChores();
 * if (dispatchGridEvent.call(this, event.type, true, event)) { // `true` here means cancelable
 *     conditionalChores();
 *     return true; // signals caller that we've already re-emitted the event (which was not canceled)
 * } else {
 *     return false; // signals caller that we've already re-emitted the event (which was canceled)
 * }
 * ```
 */
module.exports = {
    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-schema-loaded}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-schema-loaded': function(event) {
        this.behavior.createColumns();
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-loaded}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-loaded': function(event) {
        this.repaint();
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-shape-changed}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-shape-changed': function(event) {
        this.behaviorShapeChanged();
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {NormalizedDataModelEvent} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-prereindex}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-prereindex': function(event) {
        saveSelectedRowsAndColumns.call(this);
    },

    /**
     * _See the data model API page for event semantics (link below)._
     * @param {{type}} event
     * @returns {undefined|boolean} Result of re-emitted event or `undefined` if event not re-emitted.
     * @see {@link DataModel#event:fin-hypergrid-data-postreindex}
     * @memberOf dataModelEventHandlers
     */
    'fin-hypergrid-data-postreindex': function(event) {
        reselectRowsAndColumns.call(this);
        this.behaviorShapeChanged();
    }
};

function saveSelectedRowsAndColumns() {
    saveSelectedDataRowIndexes.call(this);
    saveSelectedColumnNames.call(this);
}

function reselectRowsAndColumns() {
    this.selectionModel.reset();
    reselectRowsByDataRowIndexes.call(this);
    reselectColumnsByNames.call(this);
}

/**
 * Save underlying data row indexes backing current grid row selections in `grid.selectedDataRowIndexes`.
 *
 * This call should be paired with a subsequent call to `reselectRowsByUnderlyingIndexes`.
 * @private
 * @this {Hypergrid}
 * @returns {number|undefined} Number of selected rows or `undefined` if `restoreRowSelections` is falsy.
 */
function saveSelectedDataRowIndexes() {
    if (this.properties.restoreRowSelections) {
        var dataModel = this.behavior.dataModel;

        this.selectedDataRowIndexes = this.getSelectedRows().map(function(selectedRowIndex) {
            return dataModel.getRowIndex(selectedRowIndex);
        });

        return this.selectedDataRowIndexes.length;
    }
}

/**
 * Re-establish grid row selections based on underlying data row indexes saved by `getSelectedDataRowIndexes` which should be called first.
 *
 * Note that not all previously selected rows will necessarily be available after a data transformation. Even if they appear to be available, if they are not from the same data set, restoring the selections may not make sense. When this is the case, the application should set the `restoreRowSelections` property to `false`.
 * @private
 * @this {Hypergrid}
 * @returns {number|undefined} Number of rows reselected or `undefined` if there were no previously selected rows.
 */
function reselectRowsByDataRowIndexes() {
    var dataRowIndexes = this.selectedDataRowIndexes;
    if (dataRowIndexes) {
        delete this.selectedDataRowIndexes;

        var i, r,
            dataModel = this.behavior.dataModel,
            rowCount = this.getRowCount(),
            selectedRowCount = dataRowIndexes.length,
            gridRowIndexes = [],
            selectionModel = this.selectionModel;

        for (r = 0; selectedRowCount && r < rowCount; ++r) {
            i = dataRowIndexes.indexOf(dataModel.getRowIndex(r));
            if (i >= 0) {
                gridRowIndexes.push(r);
                delete dataRowIndexes[i]; // might make indexOf increasingly faster as deleted elements are not enumerable
                selectedRowCount--; // count down so we can bail early if all found
            }
        }

        gridRowIndexes.forEach(function(gridRowIndex) {
            selectionModel.selectRow(gridRowIndex);
        });

        return gridRowIndexes.length;
    }
}

/**
 * Save data column names of currently column selections in `grid.selectedColumnNames`.
 *
 * This call should be paired with a subsequent call to `reselectColumnsByNames`.
 * @private
 * @this {Hypergrid}
 * @param sourceColumnNames
 * @returns {number|undefined} Number of selected columns or `undefined` if `restoreColumnSelections` is falsy.
 */
function saveSelectedColumnNames() {
    if (this.properties.restoreColumnSelections) {
        var behavior = this.behavior;

        this.selectedColumnNames = this.getSelectedColumns().map(function(selectedColumnIndex) {
            return behavior.getActiveColumn(selectedColumnIndex).name;
        });

        return this.selectedColumnNames.length;
    }
}

/**
 * Re-establish columns selections based on column names saved by `getSelectedColumnNames` which should be called first.
 *
 * Note that not all preveiously selected columns wil necessarily be available after a data transformation. Even if they appear to be available, if they are not from the same data set, restoring the selections may not make sense. When this is the case, the application should set the `restoreRowSelections` property to `false`.
 * @private
 * @this {Hypergrid}
 * @param sourceColumnNames
 * @returns {number|undefined} Number of rows reselected or `undefined` if there were no previously selected columns.
 */
function reselectColumnsByNames(sourceColumnNames) {
    var selectedColumnNames = this.selectedColumnNames;
    if (selectedColumnNames) {
        delete this.selectedColumnNames;

        var behavior = this.behavior,
            selectionModel = this.selectionModel;

        return selectedColumnNames.reduce(function(reselectedCount, columnName) {
            var activeColumnIndex = behavior.getActiveColumnIndex(columnName);
            if (activeColumnIndex) {
                selectionModel.selectColumn(activeColumnIndex);
                reselectedCount++;
            }
            return reselectedCount;
        }, 0);
    }
}
<|endoftext|>


<commit_before>'use strict';

import test from 'tape';
import postcss from 'postcss';
import atImport from 'postcss-import';
import nested from 'postcss-nested';
import reference from '../../index.js';
import {name} from '../../package.json';

let tests = [{
    message: 'should match requested selector',
    fixture: '@reference { header { color: blue; display: block; } } header { @references header; display: block; margin: 1em; }',
    expected: 'header { color: blue; display: block; margin: 1em; }'
}, {
    message: "should merge duplicate selectors' declarations into single rule",
    fixture: '@reference { header { color: blue; display: block; } header { border: 1px solid black; } } header { @references header; display: block; margin: 1em; }',
    expected: 'header { color: blue; border: 1px solid black; display: block; margin: 1em; }'
}, {
    message: 'non-matching selectors in selector list get discarded',
    fixture: '@reference { header, section { padding: 0; } } header { @references header; display: block; margin: 1em; }',
    expected: 'header { padding: 0; display: block; margin: 1em; }'
}, {
    message: '@import files into the @reference block and reference them',
    fixture: '@reference { @import "test/imports/header.css" } header { @references header; display: block; margin: 1em; }',
    expected: 'header { color: blue; padding: 0; box-sizing: border-box; width: 100%; display: block; margin: 1em; }'
}, {
  message: 'pseudo-classed references like "selector:references(.another-selector)" will be treated like an @references atrule prepended above any existing declarations',
  fixture: '@reference { .uppercase { text-transform: uppercase; } } header h1:references(.uppercase) { display: inline-block; }',
  expected: 'header h1 { text-transform: uppercase; display: inline-block; }'
}, {
    message: 'referenced selectors which are related to the requested selectors and have the "all" flag set, will have their related rules inserted after the requesting rule',
    fixture: '@reference { header { color: blue; display: block; } header aside { width: 25%; } } header { @references header all; display: block; margin: 1em; }',
    expected: 'header { color: blue; display: block; margin: 1em; }\nheader aside { width: 25%; }'
}, {
    message: 'referenced selectors which contain nested selectors (using postcss-nested) and have the "all" flag set, will have their nested rules inserted after the requesting rule',
    fixture: '@reference { header { color: blue; display: block; aside { width: 25%; } } } header { @references header all; display: block; margin: 1em; }',
    expected: 'header { color: blue; display: block; margin: 1em; }\nheader aside { width: 25%; }'
}, {
    message: "referencing rules where the requesting rule's selector is different from the referenced rule's, the referenced rule's selector will get remapped to the requesting rule's selector",
    fixture: '@reference { header { color: blue; display: block; aside { width: 25%; } } } footer { @references header all; display: block; margin: 1em; }',
    expected: 'footer { color: blue; display: block; margin: 1em; }\nfooter aside { width: 25%; }'
}, {
    message: "referenced rules which contain 'before' raws (like '-' or '*'; often used in CSS hacks) will have those before raws preserved.",
    fixture: "@reference { h1 { display: block; font-size: 2.2em; font-weight: bold; } .pure-u-1-2, .pure-u-12-24 { width: 50%; *width: 49.9690%; } } .document-title { @references h1, .pure-u-1-2; text-align: center; }",
    expected: ".document-title { display: block; font-size: 2.2em; font-weight: bold; width: 50%; *width: 49.9690%; text-align: center; }"
}, {
    message: "multiple requested selectors which match multiple reference selectors will merge declarations into requesting rule",
    fixture: "@reference { h1 { display: block; font-size: 2.2em; font-weight: bold; } .pure-u-1-2, .pure-u-12-24 { width: 50%; *width: 49.9690%; } } .document-title { @references h1, .pure-u-1-2; text-align: center; }",
    expected: ".document-title { display: block; font-size: 2.2em; font-weight: bold; width: 50%; *width: 49.9690%; text-align: center; }"
}, {
    message: "referencing a rule with the all flag will also match hover, focus, or other pseudo-classes or -elements",
    fixture: "@reference { a:hover { text-decoration: underline; } } a { display: block; @references a all; }",
    expected: "a { display: block; }\na:hover { text-decoration: underline; }"
}, {
    message: 'With no params declared, a referencing rule not wrapped in a @references-media query will only match selectors also not wrapped in a media query',
    fixture: '@reference { article { width: 100%;} @media (min-width: 900px) { article { width: 75%; } } } article { display: block; @references article; }',
    expected: 'article { display: block; width: 100%; }'
}, {
    message: 'If both the reference rule and the requesting declaration are wrapped in matching media queries, the media query and referenced rule will be merged into the requesting rule',
    fixture: '@reference { article { width: 100%;} @media (min-width: 900px) { article { width: 75%; } } } @media (min-width: 900px) { article { display: block; @references article; } }',
    expected: '@media (min-width: 900px) { article { display: block; width: 75%; } }'
}, {
    message: 'If the requesting rule has no media query, but has the all flag set, reference rules which match the selector should return rules from all media-queries',
    fixture: '@reference { article { width: 100%;} @media (min-width: 900px) { article { width: 75%; } } } article { display: block; @references article all; }',
    expected: 'article { display: block; width: 100%; }\n@media (min-width: 900px) {\n article { width: 75%; } }'
}];

function process (css, options) {
    return postcss().use(atImport()).use(nested()).use(reference()).process(css).css;
}

test(name, t => {
    t.plan(tests.length);

    tests.forEach(test => {
        let options = test.options || {};
        t.equal(process(test.fixture, options), test.expected, test.message);
    });
});

test('should use the postcss plugin api', t => {
    t.plan(2);
    t.ok(reference().postcssVersion, 'should be able to access version');
    t.equal(reference().postcssPlugin, name, 'should be able to access name');
});
<commit_msg>converted tests to 2-space tabs<commit_after>'use strict';

import test from 'tape';
import postcss from 'postcss';
import atImport from 'postcss-import';
import nested from 'postcss-nested';
import reference from '../../index.js';
import {name} from '../../package.json';

let tests = [{
  message: 'should match requested selector',
  fixture: '@reference { header { color: blue; display: block; } } header { @references header; display: block; margin: 1em; }',
  expected: 'header { color: blue; display: block; margin: 1em; }'
}, {
  message: "should merge duplicate selectors' declarations into single rule",
  fixture: '@reference { header { color: blue; display: block; } header { border: 1px solid black; } } header { @references header; display: block; margin: 1em; }',
  expected: 'header { color: blue; border: 1px solid black; display: block; margin: 1em; }'
}, {
  message: 'non-matching selectors in selector list get discarded',
  fixture: '@reference { header, section { padding: 0; } } header { @references header; display: block; margin: 1em; }',
  expected: 'header { padding: 0; display: block; margin: 1em; }'
}, {
  message: '@import files into the @reference block and reference them',
  fixture: '@reference { @import "test/imports/header.css" } header { @references header; display: block; margin: 1em; }',
  expected: 'header { color: blue; padding: 0; box-sizing: border-box; width: 100%; display: block; margin: 1em; }'
}, {
  message: 'pseudo-classed references like "selector:references(.another-selector)" will be treated like an @references atrule prepended above any existing declarations',
  fixture: '@reference { .uppercase { text-transform: uppercase; } } header h1:references(.uppercase) { display: inline-block; }',
  expected: 'header h1 { text-transform: uppercase; display: inline-block; }'
}, {
  message: 'referenced selectors which are related to the requested selectors and have the "all" flag set, will have their related rules inserted after the requesting rule',
  fixture: '@reference { header { color: blue; display: block; } header aside { width: 25%; } } header { @references header all; display: block; margin: 1em; }',
  expected: 'header { color: blue; display: block; margin: 1em; }\nheader aside { width: 25%; }'
}, {
  message: 'referenced selectors which contain nested selectors (using postcss-nested) and have the "all" flag set, will have their nested rules inserted after the requesting rule',
  fixture: '@reference { header { color: blue; display: block; aside { width: 25%; } } } header { @references header all; display: block; margin: 1em; }',
  expected: 'header { color: blue; display: block; margin: 1em; }\nheader aside { width: 25%; }'
}, {
  message: "referencing rules where the requesting rule's selector is different from the referenced rule's, the referenced rule's selector will get remapped to the requesting rule's selector",
  fixture: '@reference { header { color: blue; display: block; aside { width: 25%; } } } footer { @references header all; display: block; margin: 1em; }',
  expected: 'footer { color: blue; display: block; margin: 1em; }\nfooter aside { width: 25%; }'
}, {
  message: "referenced rules which contain 'before' raws (like '-' or '*'; often used in CSS hacks) will have those before raws preserved.",
  fixture: "@reference { h1 { display: block; font-size: 2.2em; font-weight: bold; } .pure-u-1-2, .pure-u-12-24 { width: 50%; *width: 49.9690%; } } .document-title { @references h1, .pure-u-1-2; text-align: center; }",
  expected: ".document-title { display: block; font-size: 2.2em; font-weight: bold; width: 50%; *width: 49.9690%; text-align: center; }"
}, {
  message: "multiple requested selectors which match multiple reference selectors will merge declarations into requesting rule",
  fixture: "@reference { h1 { display: block; font-size: 2.2em; font-weight: bold; } .pure-u-1-2, .pure-u-12-24 { width: 50%; *width: 49.9690%; } } .document-title { @references h1, .pure-u-1-2; text-align: center; }",
  expected: ".document-title { display: block; font-size: 2.2em; font-weight: bold; width: 50%; *width: 49.9690%; text-align: center; }"
}, {
  message: "referencing a rule with the all flag will also match hover, focus, or other pseudo-classes or -elements",
  fixture: "@reference { a:hover { text-decoration: underline; } } a { display: block; @references a all; }",
  expected: "a { display: block; }\na:hover { text-decoration: underline; }"
}, {
  message: 'With no params declared, a referencing rule not wrapped in a @references-media query will only match selectors also not wrapped in a media query',
  fixture: '@reference { article { width: 100%;} @media (min-width: 900px) { article { width: 75%; } } } article { display: block; @references article; }',
  expected: 'article { display: block; width: 100%; }'
}, {
  message: 'If both the reference rule and the requesting declaration are wrapped in matching media queries, the media query and referenced rule will be merged into the requesting rule',
  fixture: '@reference { article { width: 100%;} @media (min-width: 900px) { article { width: 75%; } } } @media (min-width: 900px) { article { display: block; @references article; } }',
  expected: '@media (min-width: 900px) { article { display: block; width: 75%; } }'
}, {
  message: 'If the requesting rule has no media query, but has the all flag set, reference rules which match the selector should return rules from all media-queries',
  fixture: '@reference { article { width: 100%;} @media (min-width: 900px) { article { width: 75%; } } } article { display: block; @references article all; }',
  expected: 'article { display: block; width: 100%; }\n@media (min-width: 900px) {\n article { width: 75%; } }'
}];

function process (css, options) {
    return postcss().use(atImport()).use(nested()).use(reference()).process(css).css;
}

test(name, t => {
    t.plan(tests.length);

    tests.forEach(test => {
        let options = test.options || {};
        t.equal(process(test.fixture, options), test.expected, test.message);
    });
});

test('should use the postcss plugin api', t => {
    t.plan(2);
    t.ok(reference().postcssVersion, 'should be able to access version');
    t.equal(reference().postcssPlugin, name, 'should be able to access name');
});
<|endoftext|>