PageSourceSearch

https://selfservice.foxborough.k12.ma.us/ess/js/jquery.calculation.js

js foxborough.k12.ma.us collected 2026-09-26 01:08:21 UTC 12,871 bytes, 390 lines download raw bytes

1/*
2 * jQuery Calculation Plug-in
3 *
4 * Copyright (c) 2007 Dan G. Switzer, II
5 *
6 * Dual licensed under the MIT and GPL licenses:
7 *   http://www.opensource.org/licenses/mit-license.php
8 *   http://www.gnu.org/licenses/gpl.html
9 *
10 * Revision: 11
11 * Version: 0.4.07
12 *
13 * Revision History
14 * v0.4.07
15 * - Added trim to parseNumber to fix issue with whitespace in elements
16 * 
17 * v0.4.06
18 * - Added support for calc() "format" callback so that if return value
19 *   is null, then value is not updated
20 * - Added jQuery.isFunction() check for calc() callbacks
21 * 
22 * v0.4.05
23 * - Added support to the sum() & calc() method for automatically fixing precision
24 *   issues (will detect the max decimal spot in the number and fix to that
25 *   depth)
26 * 
27 * v0.4.04
28 * - Fixed bug #5420 by adding the defaults.cleanseNumber handler; you can
29 *   override this function to handle stripping number of extra digits
30 * 
31 * v0.4.02
32 * - Fixed bug where bind parameter was not being detecting if you specified
33 *   a string in method like sum(), avg(), etc.
34 * 
35 * v0.4a
36 * - Fixed bug in aggregate functions so that a string is passed to jQuery's
37 *   text() method (since numeric zero is interpetted as false)
38 * 
39 * v0.4
40 * - Added support for -$.99 values
41 * - Fixed regex so that decimal values without leading zeros are correctly
42 *   parsed
43 * - Removed defaults.comma setting
44 * - Changed secondary regex that cleans additional formatting from parsed
45 *   number
46 * 
47 * v0.3
48 * - Refactored the aggregate methods (since they all use the same core logic)
49 *   to use the $.extend() method
50 * - Added support for negative numbers in the regex)
51 * - Added min/max aggregate methods
52 * - Added defaults.onParseError and defaults.onParseClear methods to add logic for
53 *   parsing errors
54 * 
55 * v0.2
56 * - Fixed bug in sMethod in calc() (was using getValue, should have been setValue)
57 * - Added arguments for sum() to allow auto-binding with callbacks
58 * - Added arguments for avg() to allow auto-binding with callbacks
59 * 
60 * v0.1a
61 * - Added semi-colons after object declaration (for min protection)
62 * 
63 * v0.1
64 * - First public release
65 *
66*/
67(function($){
68
69	// set the defaults
70	var defaults = {
71		// regular expression used to detect numbers, if you want to force the field to contain
72		// numbers, you can add a ^ to the beginning or $ to the end of the regex to force the
73		// the regex to match the entire string: /^(-|-\$)?(\d+(,\d{3})*(\.\d{1,})?|\.\d{1,})$/g
74		reNumbers: /(-|-\$)?(\d+(,\d{3})*(\.\d{1,})?|\.\d{1,})/g
75		// this function is used in the parseNumber() to cleanse up any found numbers
76		// the function is intended to remove extra information found in a number such
77		// as extra commas and dollar signs. override this function to strip European values
78		, cleanseNumber: function (v){
79			// cleanse the number one more time to remove extra data (like commas and dollar signs)
80			// use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
81			return v.replace(/[^0-9.\-]/g, "");
82		}
83		// should the Field plug-in be used for getting values of :input elements?
84		, useFieldPlugin: (!!$.fn.getValue)
85		// a callback function to run when an parsing error occurs
86		, onParseError: null
87		// a callback function to run once a parsing error has cleared
88		, onParseClear: null
89	};
90	
91	// set default options
92	$.Calculation = {
93		version: "0.4.07",
94		setDefaults: function(options){
95			$.extend(defaults, options);
96		}
97	};
98
99
100	/*
101	 * jQuery.fn.parseNumber()
102	 *
103	 * returns Array - detects the DOM element and returns it's value. input
104	 *                 elements return the field value, other DOM objects
105	 *                 return their text node
106	 *
107	 * NOTE: Breaks the jQuery chain, since it returns a Number.
108	 *
109	 * Examples:
110	 * $("input[name^='price']").parseNumber();
111	 * > This would return an array of potential number for every match in the selector
112	 *
113	 */
114	// the parseNumber() method -- break the chain
115	$.fn.parseNumber = function(options){
116		var aValues = [];
117		options = $.extend(options, defaults);
118		
119		this.each(
120			function (){
121				var
122					// get a pointer to the current element
123					$el = $(this),
124					// determine what method to get it's value
125					sMethod = ($el.is(":input") ? (defaults.useFieldPlugin ? "getValue" : "val") : "text"),
126					// parse the string and get the first number we find
127					v = $.trim($el[sMethod]()).match(defaults.reNumbers, "");
128					
129				// if the value is null, use 0
130				if( v == null ){
131					v = 0; // update value
132					// if there's a error callback, execute it
133					if( jQuery.isFunction(options.onParseError) ) options.onParseError.apply($el, [sMethod]);
134					$.data($el[0], "calcParseError", true);
135				// otherwise we take the number we found and remove any commas
136				} else {
137					// clense the number one more time to remove extra data (like commas and dollar signs)
138					v = options.cleanseNumber.apply(this, [v[0]]);
139					// if there's a clear callback, execute it
140					if( $.data($el[0], "calcParseError") && jQuery.isFunction(options.onParseClear) ){
141						options.onParseClear.apply($el, [sMethod]);
142						// clear the error flag
143						$.data($el[0], "calcParseError", false);
144					} 
145				}
146				aValues.push(parseFloat(v, 10));
147			}
148		);
149
150		// return an array of values
151		return aValues;
152	};
153
154	/*
155	 * jQuery.fn.calc()
156	 *
157	 * returns Number - performance a calculation and updates the field
158	 *
159	 * Examples:
160	 * $("input[name='price']").calc();
161	 * > This would return the sum of all the fields named price
162	 *
163	 */
164	// the calc() method
165	$.fn.calc = function(expr, vars, cbFormat, cbDone){
166		var
167			// create a pointer to the jQuery object
168			$this = this
169			// the value determine from the expression
170			, exprValue = ""
171			// track the precision to use
172			, precision = 0
173			// a pointer to the current jQuery element
174			, $el
175			// store an altered copy of the vars
176			, parsedVars = {}
177			// temp variable
178			, tmp
179			// the current method to use for updating the value
180			, sMethod
181			// a hash to store the local variables
182			, _
183			// track whether an error occured in the calculation
184			, bIsError = false;
185
186		// look for any jQuery objects and parse the results into numbers			
187		for( var k in vars ){
188			// replace the keys in the expression
189			expr = expr.replace( (new RegExp("(" + k + ")", "g")), "_.$1");
190			if( !!vars[k] && !!vars[k].jquery ){
191				parsedVars[k] = vars[k].parseNumber();
192			} else {
193				parsedVars[k] = vars[k];
194			}
195		}
196		
197		this.each(
198			function (i, el){
199				var p, len;
200				// get a pointer to the current element
201				$el = $(this);
202				// determine what method to get it's value
203				sMethod = ($el.is(":input") ? (defaults.useFieldPlugin ? "setValue" : "val") : "text");
204
205				// initialize the hash vars
206				_ = {};
207				for( var k in parsedVars ){
208					if( typeof parsedVars[k] == "number" ){
209						_[k] = parsedVars[k];
210					} else if( typeof parsedVars[k] == "string" ){
211						_[k] = parseFloat(parsedVars[k], 10);
212					} else if( !!parsedVars[k] && (parsedVars[k] instanceof Array) ) {
213						// if the length of the array is the same as number of objects in the jQuery
214						// object we're attaching to, use the matching array value, otherwise use the
215						// value from the first array item
216						tmp = (parsedVars[k].length == $this.length) ? i : 0;
217						_[k] = parsedVars[k][tmp];
218					}
219
220					// if we're not a number, make it 0
221					if( isNaN(_[k]) ) _[k] = 0;
222
223					// check for decimals and check the precision
224					p = _[k].toString().match(/\.\d+$/gi);
225					len = (p) ? p[0].length-1 : 0;
226
227					// track the highest level of precision
228					if( len > precision ) precision = len; 
229				}
230
231
232				// try the calculation
233				try {
234					exprValue = eval( expr );
235					
236					// fix any the precision errors
237					if( precision ) exprValue = Number(exprValue.toFixed(Math.max(precision, 4)));
238
239					// if there's a format callback, call it now
240					if( jQuery.isFunction(cbFormat) ){
241						// get return value
242						var tmp = cbFormat.apply(this, [exprValue])
243						// if we have a returned value (it's null null) use it
244						if( !!tmp ) exprValue = tmp;
245					}
246		
247				// if there's an error, capture the error output
248				} catch(e){
249					exprValue = e;
250					bIsError = true;
251				}
252				
253				// update the value
254				$el[sMethod](exprValue.toString());
255			}
256		);
257		
258		// if there's a format callback, call it now
259		if( jQuery.isFunction(cbDone) ) cbDone.apply(this, [this]);
260
261		return this;
262	};
263
264	/*
265	 * Define all the core aggregate functions. All of the following methods
266	 * have the same functionality, but they perform different aggregate 
267	 * functions.
268	 * 
269	 * If this methods are called without any arguments, they will simple
270	 * perform the specified aggregate function and return the value. This
271	 * will break the jQuery chain. 
272	 * 
273	 * However, if you invoke the method with any arguments then a jQuery
274	 * object is returned, which leaves the chain intact.
275	 * 
276	 * 
277	 * jQuery.fn.sum()
278	 * returns Number - the sum of all fields
279	 *
280	 * jQuery.fn.avg()
281	 * returns Number - the avg of all fields
282	 *
283	 * jQuery.fn.min()
284	 * returns Number - the minimum value in the field
285	 *
286	 * jQuery.fn.max()
287	 * returns Number - the maximum value in the field
288	 * 
289	 * Examples:
290	 * $("input[name='price']").sum();
291	 * > This would return the sum of all the fields named price
292	 *
293	 * $("input[name='price1'], input[name='price2'], input[name='price3']").sum();
294	 * > This would return the sum of all the fields named price1, price2 or price3
295	 *
296	 * $("input[name^=sum]").sum("keyup", "#totalSum");
297	 * > This would update the element with the id "totalSum" with the sum of all the 
298	 * > fields whose name started with "sum" anytime the keyup event is triggered on
299	 * > those field.
300	 *
301	 * NOTE: The syntax above is valid for any of the aggregate functions
302	 *
303	 */
304	$.each(["sum", "avg", "min", "max"], function (i, method){
305		$.fn[method] = function (bind, selector){
306			// if no arguments, then return the result of the aggregate function
307			if( arguments.length == 0 )
308				return math[method](this.parseNumber());
309
310			// if the selector is an options object, get the options
311			var bSelOpt = selector && (selector.constructor == Object) && !(selector instanceof jQuery);
312
313			// configure the options for this method
314			var opt = bind && bind.constructor == Object ? bind : {
315				  bind: bind || "keyup"
316				, selector: (!bSelOpt) ? selector : null
317				, oncalc: null
318			};
319			
320			// if the selector is an options object, extend	the options
321			if( bSelOpt ) opt = jQuery.extend(opt, selector);
322	
323			// if the selector exists, make sure it's a jQuery object
324			if( !!opt.selector ) opt.selector = $(opt.selector);
325			
326			var self = this
327				, sMethod
328				, doCalc = function (){
329					// preform the aggregate function
330					var value = math[method](self.parseNumber(opt));
331					// check to make sure we have a selector				
332					if( !!opt.selector ){
333						// determine how to set the value for the selector
334						sMethod = (opt.selector.is(":input") ? (defaults.useFieldPlugin ? "setValue" : "val") : "text");
335						// update the value
336						opt.selector[sMethod](value.toString());
337					}
338					// if there's a callback, run it now
339					if( jQuery.isFunction(opt.oncalc) ) opt.oncalc.apply(self, [value, opt]);
340				};
341			
342			// perform the aggregate function now, to ensure init values are updated
343			doCalc();
344			
345			// bind the doCalc function to run each time a key is pressed
346			return self.bind(opt.bind, doCalc);
347		}
348	});
349	
350	/*
351	 * Mathmatical functions
352	 */
353	var math = {
354		// sum an array
355		sum: function (a){
356			var total = 0, precision = 0;
357			
358			// loop through the value and total them
359			$.each(a, function (i, v){
360				// check for decimals and check the precision
361				var p = v.toString().match(/\.\d+$/gi), len = (p) ? p[0].length-1 : 0;
362				// track the highest level of precision
363				if( len > precision ) precision = len; 
364				// we add 0 to the value to ensure we get a numberic value
365				total += v;
366			});
367
368			// fix any the precision errors
369			if( precision ) total = Number(total.toFixed(precision));
370	
371			// return the values as a comma-delimited string
372			return total;
373		},
374		// average an array
375		avg: function (a){
376			// return the values as a comma-delimited string
377			return math.sum(a)/a.length;
378		},
379		// lowest number in array
380		min: function (a){
381			return Math.min.apply(Math, a);
382		},
383		// highest number in array
384		max: function (a){
385			return Math.max.apply(Math, a);
386		}
387	};
388	
389
390})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.