jsbeans

jsbeans  1.0.0

jsbeans > jsbeans > Validator.wordCount.js (source view)
Search:
 
Filters
/*!
 * Copyright (c) 2009 Francesco Mele jsbeans@francescomele.com
 *
 * This Software is licenced under the LGPL Licence (GNU Lesser General 
 * Public License).
 * In addition to the LGPL Licence the Software is subject to the 
 * following conditions:
 * 
 * 	i	every modification must be public and comunicated to the Author
 * 	ii	every "jsbean" added to this library must be self consistent 
 * 		except for the dependence from jsbeans-x.x.x.js
 * 	iii	copyright notice and this permission notice shall be included 
 * 		in all copies or substantial portions of the Software
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
 
/**
 * Validator extensions for counting words in inputs.
 * @for Validator
 * @namespace jsbeans
 * @static
 * */
jsbeans.Validator.wordCount = {
	/**
	 * Default messages for Validator.wordCount extension
	 * @property wordCount.messages
	 * @type JSON
	 * @static
	 * */
	messages: {
		en: "exceedes the maximum number of words allowed for the field",
		it: "supera il numero di parole massimo consentito per il campo"
	},
	/**
	 * Core counter. It takes same arguments (and it is used by) as {@method} <code class="methd">assertWordCount</code>.<br/>
	 * It may be useful to display current number of words. Beware of firing with <code>onkeyup</code> event.
	 * @method wordCount.getCount
	 * @param input {DOM} input to check
	 * @param params {Integer | JSON} limit for number of words OR a JSON with <code>limit</code> (Integer, required), <code>skip</code> (Integer, optional) and <code>excludes</code> (Array, optional).
	 * @return {Integer} the current number of words in <code class="param">input</code>; default <code>0</code>
	 * @static
	 */
	getCount: function(input, params) {
		if (input == null || input.value == null || input.value == "") {
			return 0;
		}
		// see jsbeans.string.trim
		var trim = function(str) {
			return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
		}
		var ps = {};
		try {
//			if (skipParsing) {
//				ps = params;
//				// limit is required
//				if (typeof ps.limit == "undefined") {
//					return Number.MAX_VALUE;
//				}
//				// defaults
//				if (typeof ps.skip == "undefined") {
//					ps.skip = -1;
//				}
//				if (typeof ps.excludes == "undefined") {
//					ps.excludes = jsbeans.Validator.wordCount.EXCLUDES;
//				}
//			}
//			else {
				ps = jsbeans.Validator.wordCount._parseParams(params);
//			}
		}
		catch(err) {
			return Number.MAX_VALUE;
		}
		// core validation

		// trimming value
		var str = trim(input.value);
		// try to check email to count as one word
		var sp = str.split(" ");
		var res = [];
		var s;
		var email = /^[^\s()<>@,;:\/]+@\w[\w\.-]+\.[a-z]{2,}$/i;
		var http = /((http:\/\/)|(www\.))+(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(\/[a-zA-Z0-9\&amp;%_\.\/-~-]*)?/;
		var https = /((https:\/\/)|(www\.))+(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(\/[a-zA-Z0-9\&amp;%_\.\/-~-]*)?/;
		for (var i = 0; i < sp.length; i++) {
			s = trim(sp[i]);
			if (email.test(s) || http.test(s) || https.test(s)) {
				var t = "";
				for (var j = 0; j < s.length; j++) {
					t += "a";
				}
				// now word has as many "a" as original length (supposing "a" isn't in the excludes)
				s = t;
			}
			// it's a Number
			else if (!isNaN(parseFloat(s))) {
				// replacing with a word longer than 'skip' (as it has -1 as default we always use skip+2)
				var t = "";
				for (var j = 0; j < (ps.skip + 2); j++) {
					t += "a";
				}
				s = t;
			}
			res.push(s);
		}
		str = res.join(" ");
		// skipping excludes
		for (var i = 0; i < ps.excludes.length; i++) {
			var s = str;
			str = trim(str.split(new RegExp(ps.excludes[i], 'gi')).join(" "));
		}
		// skipping words shorter than 'skip'
		if (ps.skip != -1) {
			var sp = str.split(" ");
			var res = [];
			for (var i = 0; i < sp.length; i++) {
				if (sp[i].length > ps.skip) {
					res.push(sp[i]);
				}
			}
			str = res.join(" ");
		}
		// removes two or more spaces
		while (str.indexOf("  ") != -1) {
			str = str.split("  ").join(" ");
		}
		return str.split(" ").length;
	},
	/**
	 * List of words and marks excluded from counting. It has punctation marks, brackets, arithmetics marks, ...<br/>
	 * It may be modified according to yours needs (just remember it's static) or use the optional <code>excludes</code> parameter invoking the validation method.
	 * See <a href="http://brajeshwar.github.io/entities/">here<a> and <a href="http://www.w3.org/TR/html4/sgml/entities.html">here</a> for a list of HTML/javascript entities.
	 * @property wordCount.EXCLUDES
	 * @type Array
	 * @static
	 */
	EXCLUDES: [
       // marks
       "\\.", ",", ";", ":", "!", "\\?",  
       // brackets
       "\\(", "\\)", "\\[", "\\]", "\\{", "\\}", 
       // arithmetics
       "\\-", "\\+", "\\/",  "\\*", "=", "\\^",
       // others
       "#", "@", '"', '~', '`', '\n', '\t', '\\\\', '_',
       '\u0022',
       '\42',
       '\u0026',
       '\u003c',
       '\u003e',
       '\u00a5',
       '\241',
       '\243',
       '\245',
       '\246',
       '\247',
       '\251',
       '\253',
       '\256',
       '\260',
       '\261',
       '\262',
       '\263',
       '\264',
       '\265',
       '\271',
       '\272',
       '\273',
       '\277',
       '\327',
       '\367',
       '\u02c6',
       '\u02dc',
       '\u2018',
       '\u2019',
       '\u201a',
       '\u201c',
       '\u201d',
       '\u201e',
       '\u2039',
       '\u203a',
       '\u2026',
       '\u2032',
       '\u2033',
       '\u8260',
       '\u2122',
       '\u2212',
       '\u2217',
       '\u223c',
       '\u22c5',
       '\u2329',
       '\u232a',
       '\74',
       '\76',
       '\u20ac',
       '\u2227', 
       '\u2228',
       '\u2122'
	],
	/**
	 * Checks if {@param} <code class="param">input</code>'s value contains not more than a given number of words.<br/>
	 * This method does NOT take into account some characters as defined by <code>jsbeans.Validator.wordCount.EXLUDES</code> array.<br/>
	 * It also try to intercept email and web (http|https) addresses counting them as one word (each).<br/>
	 * Numbers are parsed as floats and <strong>always</strong> counted, regardless of their length as strings.<br/>
	 * {@param} <code class="param">params</code> may be an just Integer to check the maximum mumber of words or a JSON in the following form:
	 * <ul>
	 * <li><code>limit</code> &lt;Integer> (<strong>required</strong>): maximum number of words aspected</li>
	 * <li><code>skip</code> &lt;Integer>: skips words shorter than {@param} <code class="param">skip</code>. Default: no skip</li>
	 * <li><code>excludes</code> &lt;Array>: if provided this array overrides <code>jsbeans.Validator.wordCount.EXCLUDES</code></li>
	 * </ul>
	 * {@param} <code class="param">excludes</code> items are checked using regular expression: <code>new RegExp(ps.excludes[i], 'gi')</code>.
	 * <br/>Samples:
	 * <ol>
	 * <li><code>["wordCount=10"]</code>: returns false if {@param} <code class="param">input</code>'s value contains 11 or more words</li>
	 * <li><code>["wordCount={limit:10,skip:3}"]</code>: returns false if {@param} <code class="param">input</code>'s value contains 11 or more words longer than 3 characters</li>
	 * </ol>
	 * @method assertWordCount
	 * @param input {DOM} input to check
	 * @param params {Integer | JSON} limit for number of words OR a JSON with <code>limit</code> (Integer, required), <code>skip</code> (Integer, optional) and <code>excludes</code> (Array, optional). 
	 * @return {boolean} true if <code class="param">input</code>'s value has less than specified rules (see description).
	 * @static
	 * */
	assertWordCount: function(input, params) {
		var ps = {};
		try {
			ps = jsbeans.Validator.wordCount._parseParams(params);
		}
		catch(err) {
			return false;
		}
		return jsbeans.Validator.wordCount.getCount(input, ps) <= ps.limit;
	},
	/**
	 * Utility method. It parses parameters for <code class="methd">getCount</code> and <code class="methd">assertWordCount</code> methods.<br/>
	 * Method intended to be private.
	 * @method wordCount._parseParams
	 * @param params {Integer | JSON} limit for number of words OR a JSON with <code>limit</code> (Integer, required), <code>skip</code> (Integer, optional) and <code>excludes</code> (Array, optional).
	 * @return {JSON} a JSON with parsed parameters as passed and/or with default values. It throws <code>Error</code>s as validation issue.
	 * @private
	 * @static
	 */
	_parseParams: function(params) {
		// defaults
		var ps = {
			limit: -1,
			skip: -1,
			excludes: jsbeans.Validator.wordCount.EXCLUDES
		};
		// checks for params
		var test = parseInt(params);
		if (isNaN(test)) {
			// presuming a JSON has been passed
			if (params.limit) {
				test = params;
			} 
			else {
				test = eval("(" + params + ")");
			}
			// if params is a JSON it MUST have the 'limit' property
			if (!test.limit) {
				throw new Error('limit');
			}
			else {
				var n = parseInt(test.limit);
				// 'limit' MUST be an Integer
				if (isNaN(n)) {
					throw new Error('limit');
				}
				ps.limit = test.limit;
			}
			if (!!test.skip) {
				var n = parseInt(test.skip);
				// 'skip' MUST be an Integer
				if (isNaN(n)) {
					throw new Error('skip');
				}
				else {
					ps.skip = n;
				}
			}
			if (!!test.excludes) {
				// see jsbeans.Array
				var ex = (typeof(test.excludes) === "object" && (test.excludes).constructor == Array);
				// 'excludes' MUST be an Array
				if (ex == false) {
					throw new Error('excludes');
				}
				else {
					// overrride default jsbeans.Validator.wordCount.EXCLUDES
					ps.excludes = test.excludes;
				}
			}
		}
		// just passed an Integer
		else {
			ps.limit = test;
		}
		return ps;
	}
};

Copyright © 2016 Francesco Mele. All rights reserved.