master a33bf5aa794c cached
8 files
29.7 KB
8.4k tokens
1 requests
Download .txt
Repository: phiggins42/bloody-jquery-plugins
Branch: master
Commit: a33bf5aa794c
Files: 8
Total size: 29.7 KB

Directory structure:
gitextract_b3to4grb/

├── README.md
├── Stateful.js
├── date.js
├── format.js
├── hitch.js
├── pubsub.js
└── tests/
    ├── Stateful.html
    └── format.html

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Bloody jQuery Plugins 

A small collection of useful functionality available by default in Dojo, though useful in plain-ole-JavaScript context.

## hitch.js

Advanced scope manipulation in jQuery. For jQuery 1.3 and before, as 1.4 the official "way" to accomplish this is via $.proxy ... New versions of this module _may_ curry arguments, giving it an advantage over proxy. The Dojo version currently curries arguments.

## pubsub.js

Ambiguous communication plugin. Small API surface. Publish some message to listeners.

## date.js

Date functionality for jQuery, living in the $.date namespace. Provides date.add, date.compare, date.difference, and a few other small utility functions. Ignore the word `dojo` in the source. By way of JavaScript _magic_ it is actually a _jQuery_ plugin. I promise.

## format.js

Port of some random MIT/GPL Number formatting plugin to allow "plain ole' Number formatting" without requirement of the number being formatted be in the DOM. Retains API of original plugin, though exposes the formatter and parser publicly.

# License

Being stolen directly from the Dojo Toolkit source, these plugins are released under a dual AFL/BSD license identical to Dojo proper. See http://dojotoolkit.org/license for more information.


================================================
FILE: Stateful.js
================================================
(function($){

	$.Stateful = function(args){
		$.extend(this, args);
	}
	
	$.extend($.Stateful.prototype, {

		get: function(/*String*/name){
			// summary:
			//		Get a property on a Stateful instance.
			//	name:
			//		The property to get.
			// description:
			//		Get a named property on a Stateful object. The property may
			//		potentially be retrieved via a getter method in subclasses. In the base class
			//		this just retrieves the object's property. 
			//		For example:
			//	|	stateful = new dojo.Stateful({foo: 3});
			//	|	stateful.get("foo") // returns 3
			//	|	stateful.foo // returns 3
		
			return this[name];
		},

		set: function(/*String*/name, /*Object*/value){
			// summary:
			//		Set a property on a Stateful instance
			//	name:
			//		The property to set. 
			//	value:
			//		The value to set in the property.
			// description:
			//		Sets named properties on a stateful object and notifies any watchers of 
			//		the property. A programmatic setter may be defined in subclasses.
			//		For example:
			//	|	stateful = new dojo.Stateful();
			//	|	stateful.watch(function(name, oldValue, value){
			//	|		// this will be called on the set below
			//	|	}
			//	|	stateful.set(foo, 5);
			//
			//	set() may also be called with a hash of name/value pairs, ex:
			//	|	myObj.set({
			//	|		foo: "Howdy",
			//	|		bar: 3
			//	|	})
			//	This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
			if(typeof name === "object"){
				for(var x in name){
					this.set(x, name[x]); 
				}
				return this;
			}
			var oldValue = this[name];
			this[name] = value;
			if(this._watchCallbacks){
				this._watchCallbacks(name, oldValue, value);
			}
			return this;
		},

		watch: function(/*String?*/name, /*Function*/callback){
			// summary:
			//		Watches a property for changes
			//	name:
			//		Indicates the property to watch. This is optional (the callback may be the 
			//		only parameter), and if omitted, all the properties will be watched
			// returns:
			//		An object handle for the watch. The unwatch method of this object 
			//		can be used to discontinue watching this property:
			//		|	var watchHandle = obj.watch("foo", callback);
			//		|	watchHandle.unwatch(); // callback won't be called now
			//	callback:
			//		The function to execute when the property changes. This will be called after
			//		the property has been changed. The callback will be called with the |this|
			//		set to the instance, the first argument as the name of the property, the 
			//		second argument as the old value and the third argument as the new value.
		
			var callbacks = this._watchCallbacks;
			if(!callbacks){
				var self = this;
				callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
					var notify = function(propertyCallbacks){
						for(var i = 0, l = propertyCallbacks && propertyCallbacks.length; i < l; i++){
							try{
								propertyCallbacks[i].call(self, name, oldValue, value);
							}catch(e){
								console.error(e);
							}
						}
					};
					notify(callbacks[name]);
					if(!ignoreCatchall){
						notify(callbacks["*"]); // the catch-all
					}
				}; // we use a function instead of an object so it will be ignored by JSON conversion
			}
			if(!callback && typeof name === "function"){
				callback = name;
				name = "*";
			}
			var propertyCallbacks = callbacks[name];
			if(typeof propertyCallbacks !== "object"){
				propertyCallbacks = callbacks[name] = [];
			}
			propertyCallbacks.push(callback);
			return {
				unwatch: function(){
					propertyCallbacks.splice($.inArray(propertyCallbacks, callback), 1);
				}
			};
		}
	
	});

})(jQuery);

================================================
FILE: date.js
================================================
/*	

	jQuery Date utility plugin by Peter Higgins (dante@dojotoolkit.org)

	Based on (actually, diretly ported from) Dojo date.js

	Original is (c) Dojo Foundation 2004-2010. Released under either AFL or new BSD, see:
	http://dojofoundation.org/license for more information.

*/
(function(dojo){

	dojo.date = {
		// summary: Date manipulation utilities
	};
	
	dojo.date.getDaysInMonth = function(/*Date*/dateObject){
		//	summary:
		//		Returns the number of days in the month used by dateObject
		var month = dateObject.getMonth();
		var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
		return days[month]; // Number
	}

	dojo.date.isLeapYear = function(/*Date*/dateObject){
		//	summary:
		//		Determines if the year of the dateObject is a leap year
		//	description:
		//		Leap years are years with an additional day YYYY-02-29, where the
		//		year number is a multiple of four with the following exception: If
		//		a year is a multiple of 100, then it is only a leap year if it is
		//		also a multiple of 400. For example, 1900 was not a leap year, but
		//		2000 is one.

		var year = dateObject.getFullYear();
		return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
	}

	// FIXME: This is not localized
	dojo.date.getTimezoneName = function(/*Date*/dateObject){
		//	summary:
		//		Get the user's time zone as provided by the browser
		// dateObject:
		//		Needed because the timezone may vary with time (daylight savings)
		//	description:
		//		Try to get time zone info from toString or toLocaleString method of
		//		the Date object -- UTC offset is not a time zone.  See
		//		http://www.twinsun.com/tz/tz-link.htm Note: results may be
		//		inconsistent across browsers.

		var str = dateObject.toString(); // Start looking in toString
		var tz = ''; // The result -- return empty string if nothing found
		var match;

		// First look for something in parentheses -- fast lookup, no regex
		var pos = str.indexOf('(');
		if(pos > -1){
			tz = str.substring(++pos, str.indexOf(')'));
		}else{
			// If at first you don't succeed ...
			// If IE knows about the TZ, it appears before the year
			// Capital letters or slash before a 4-digit year 
			// at the end of string
			var pat = /([A-Z\/]+) \d{4}$/;
			if((match = str.match(pat))){
				tz = match[1];
			}else{
			// Some browsers (e.g. Safari) glue the TZ on the end
			// of toLocaleString instead of putting it in toString
				str = dateObject.toLocaleString();
				// Capital letters or slash -- end of string, 
				// after space
				pat = / ([A-Z\/]+)$/;
				if((match = str.match(pat))){
					tz = match[1];
				}
			}
		}

		// Make sure it doesn't somehow end up return AM or PM
		return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
	}

	// Utility methods to do arithmetic calculations with Dates

	dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
		//	summary:
		//		Compare two date objects by date, time, or both.
		//	description:
		//		Returns 0 if equal, positive if a > b, else negative.
		//	date1:
		//		Date object
		//	date2:
		//		Date object.  If not specified, the current Date is used.
		//	portion:
		//		A string indicating the "date" or "time" portion of a Date object.
		//		Compares both "date" and "time" by default.	 One of the following:
		//		"date", "time", "datetime"

		// Extra step required in copy for IE - see #3112
		date1 = new Date(+date1);
		date2 = new Date(+(date2 || new Date()));

		if(portion == "date"){
			// Ignore times and compare dates.
			date1.setHours(0, 0, 0, 0);
			date2.setHours(0, 0, 0, 0);
		}else if(portion == "time"){
			// Ignore dates and compare times.
			date1.setFullYear(0, 0, 0);
			date2.setFullYear(0, 0, 0);
		}
	
		if(date1 > date2){ return 1; } // int
		if(date1 < date2){ return -1; } // int
		return 0; // int
	};

	dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
		//	summary:
		//		Add to a Date in intervals of different size, from milliseconds to years
		//	date: Date
		//		Date object to start with
		//	interval:
		//		A string representing the interval.	 One of the following:
		//			"year", "month", "day", "hour", "minute", "second",
		//			"millisecond", "quarter", "week", "weekday"
		//	amount:
		//		How much to add to the date.

		var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112)
		var fixOvershoot = false;
		var property = "Date";

		switch(interval){
			case "day":
				break;
			case "weekday":
				//i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true.	 see dojo.cldr.supplemental

				// Divide the increment time span into weekspans plus leftover days
				// e.g., 8 days is one 5-day weekspan / and two leftover days
				// Can't have zero leftover days, so numbers divisible by 5 get
				// a days value of 5, and the remaining days make up the number of weeks
				var days, weeks;
				var mod = amount % 5;
				if(!mod){
					days = (amount > 0) ? 5 : -5;
					weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
				}else{
					days = mod;
					weeks = parseInt(amount/5);
				}
				// Get weekday value for orig date param
				var strt = date.getDay();
				// Orig date is Sat / positive incrementer
				// Jump over Sun
				var adj = 0;
				if(strt == 6 && amount > 0){
					adj = 1;
				}else if(strt == 0 && amount < 0){
				// Orig date is Sun / negative incrementer
				// Jump back over Sat
					adj = -1;
				}
				// Get weekday val for the new date
				var trgt = strt + days;
				// New date is on Sat or Sun
				if(trgt == 0 || trgt == 6){
					adj = (amount > 0) ? 2 : -2;
				}
				// Increment by number of weeks plus leftover days plus
				// weekend adjustments
				amount = (7 * weeks) + days + adj;
				break;
			case "year":
				property = "FullYear";
				// Keep increment/decrement from 2/29 out of March
				fixOvershoot = true;
				break;
			case "week":
				amount *= 7;
				break;
			case "quarter":
				// Naive quarter is just three months
				amount *= 3;
				// fallthrough...
			case "month":
				// Reset to last day of month if you overshoot
				fixOvershoot = true;
				property = "Month";
				break;
	//		case "hour":
	//		case "minute":
	//		case "second":
	//		case "millisecond":
			default:
				property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
		}

		if(property){
			sum["set"+property](sum["get"+property]()+amount);
		}

		if(fixOvershoot && (sum.getDate() < date.getDate())){
			sum.setDate(0);
		}

		return sum; // Date
	};

	dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
		//	summary:
		//		Get the difference in a specific unit of time (e.g., number of
		//		months, weeks, days, etc.) between two dates, rounded to the
		//		nearest integer.
		//	date1:
		//		Date object
		//	date2:
		//		Date object.  If not specified, the current Date is used.
		//	interval:
		//		A string representing the interval.	 One of the following:
		//			"year", "month", "day", "hour", "minute", "second",
		//			"millisecond", "quarter", "week", "weekday"
		//		Defaults to "day".

		date2 = date2 || new Date();
		interval = interval || "day";
		var yearDiff = date2.getFullYear() - date1.getFullYear();
		var delta = 1; // Integer return value

		switch(interval){
			case "quarter":
				var m1 = date1.getMonth();
				var m2 = date2.getMonth();
				// Figure out which quarter the months are in
				var q1 = Math.floor(m1/3) + 1;
				var q2 = Math.floor(m2/3) + 1;
				// Add quarters for any year difference between the dates
				q2 += (yearDiff * 4);
				delta = q2 - q1;
				break;
			case "weekday":
				var days = Math.round(dojo.date.difference(date1, date2, "day"));
				var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
				var mod = days % 7;

				// Even number of weeks
				if(mod == 0){
					days = weeks*5;
				}else{
					// Weeks plus spare change (< 7 days)
					var adj = 0;
					var aDay = date1.getDay();
					var bDay = date2.getDay();

					weeks = parseInt(days/7);
					mod = days % 7;
					// Mark the date advanced by the number of
					// round weeks (may be zero)
					var dtMark = new Date(date1);
					dtMark.setDate(dtMark.getDate()+(weeks*7));
					var dayMark = dtMark.getDay();

					// Spare change days -- 6 or less
					if(days > 0){
						switch(true){
							// Range starts on Sat
							case aDay == 6:
								adj = -1;
								break;
							// Range starts on Sun
							case aDay == 0:
								adj = 0;
								break;
							// Range ends on Sat
							case bDay == 6:
								adj = -1;
								break;
							// Range ends on Sun
							case bDay == 0:
								adj = -2;
								break;
							// Range contains weekend
							case (dayMark + mod) > 5:
								adj = -2;
						}
					}else if(days < 0){
						switch(true){
							// Range starts on Sat
							case aDay == 6:
								adj = 0;
								break;
							// Range starts on Sun
							case aDay == 0:
								adj = 1;
								break;
							// Range ends on Sat
							case bDay == 6:
								adj = 2;
								break;
							// Range ends on Sun
							case bDay == 0:
								adj = 1;
								break;
							// Range contains weekend
							case (dayMark + mod) < 0:
								adj = 2;
						}
					}
					days += adj;
					days -= (weeks*2);
				}
				delta = days;
				break;
			case "year":
				delta = yearDiff;
				break;
			case "month":
				delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
				break;
			case "week":
				// Truncate instead of rounding
				// Don't use Math.floor -- value may be negative
				delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
				break;
			case "day":
				delta /= 24;
				// fallthrough
			case "hour":
				delta /= 60;
				// fallthrough
			case "minute":
				delta /= 60;
				// fallthrough
			case "second":
				delta /= 1000;
				// fallthrough
			case "millisecond":
				delta *= date2.getTime() - date1.getTime();
		}

		// Round for fractional values and DST leaps
		return Math.round(delta); // Number (integer)
	};

})(jQuery);

================================================
FILE: format.js
================================================
/**
 *       jquery.numberformatter - Formatting/Parsing Numbers in jQuery
 *       Completely changed by Peter Higgins (dante@dojotoolkit.org)
 *       Originally written by Michael Abernethy (mike@abernethysoft.com)
 *
 *       This plugin can be used to format numbers as text and parse text as Numbers
 *       Because we live in an international world, we cannot assume that everyone
 *       uses "," to divide thousands, and "." as a decimal point.
 *      
 *       The format() function will take the text within any selector by calling
 *       text() or val() on them, getting the String, and applying the specified format to it.
 *       It will return the jQuery object
 *      
 *       The parse() function will take the text within any selector by calling text()
 *       or val() on them, turning the String into a Number, and returning these
 *       values in a Number array.
 *       It WILL BREAK the jQuery chain, and return an Array of Numbers.
 *      
 *       Because there is limited use in a plugin that is unable to simply parse strings and numbers
 *       The parsing and formatting section has been broken out into $.formatNumber and $.parseNumber
 *      
 *       The syntax for the formatting is:
 *       0 = Digit
 *       # = Digit, zero shows as absent
 *       . = Decimal separator
 *       - = Negative sign
 *       , = Grouping Separator
 *       % = Percent (multiplies the number by 100)
 *       For example, a format of "#,###.00" and text of 4500.20 will
 *       display as "4.500,20" with a locale of "de", and "4,500.20" with a locale of "us"
 *      
 *      
 *       As of now, the only acceptable locales are 
 *       United States -> "us"
 *       Arab Emirates -> "ae"
 *       Egypt -> "eg"
 *       Israel -> "il"
 *       Japan -> "jp"
 *       South Korea -> "kr"
 *       Thailand -> "th"
 *       China -> "cn"
 *       Hong Kong -> "hk"
 *       Taiwan -> "tw"
 *       Australia -> "au"
 *       Canada -> "ca"
 *       Great Britain -> "gb"
 *       India -> "in"
 *       Germany -> "de"
 *       Vietnam -> "vn"
 *       Spain -> "es"
 *       Denmark -> "dk"
 *       Austria -> "at"
 *       Greece -> "gr"
 *       Brazil -> "br"
 *       Czech -> "cz"
 *       France  -> "fr"
 *       Finland -> "fi"
 *       Russia -> "ru"
 *       Sweden -> "se"
 *       Switzerland -> "ch"
 *       
 *       TODO
 *       Separate positive and negative patterns separated by a ":" (e.g. use (#,###) for accounting)
 *       More options may come in the future (currency)
 **/
(function($){
    
    var defaults = {
        parse:{
            locale: "us",
            decimalSeparatorAlwaysShown: false
        },
        format:{
            format: "#,###.00",
            locale: "us",
            decimalSeparatorAlwaysShown: false
        }
    }
    
    var formatCodes = function(locale) {

        var dec = ".", group = ",", neg = "-";
        switch(locale.toLowerCase()){
            case "de": case "vn": case "es": case "dk": case "at": case "gr": case "br":
                dec = ","; group = ".";
                break;
            case "cz": case "fr": case "fi": case "ru": case "se":
                group = " "; dec = ",";
                break;
            case "ch":
                group = "'";
                break;
        }

        return { group: group, dec: dec, neg: neg }
        
    };

    var formatNumber = function(text, options, dontmix){
        // summary: Format some plain number to a localized printable version
        
        var opts = dontmix ? (options || defaults.format) : $.extend({}, defaults.format, options),
            d = dontmix || formatCodes(opts.locale),
            dec = d.dec, group = d.group, neg = d.neg,
            validFormat = "0#-,.", returnString = ""
        ;

        // strip all the invalid characters at the beginning and the end
        // of the format, and we'll stick them back on at the end
        // make a special case for the negative sign "-" though, so 
        // we can have formats like -$23.32
        var prefix = "", negativeInFront = false;
        for (var i = 0, l = opts.format.length; i < l; i++) {
            if (validFormat.indexOf(opts.format.charAt(i)) == -1) {
                prefix = prefix + opts.format.charAt(i);
            } else if (i == 0 && opts.format.charAt(i) == '-'){
                negativeInFront = true;
                continue;                
            } else {
                break;
            }
        }

        var suffix = "";
        for (var i = opts.format.length - 1; i >= 0; i--) {
            if (validFormat.indexOf(opts.format.charAt(i)) == -1){
                suffix = opts.format.charAt(i) + suffix;
            } else {
                break;
            }

        }

        opts.format = opts.format.substring(prefix.length);
        opts.format = opts.format.substring(0, opts.format.length - suffix.length);

        // now we need to convert it into a number
        while (text.indexOf(group) > -1){
            text = text.replace(group,'');
        }
           
        var number = new Number(text.replace(dec,".").replace(neg,"-"));

        // special case for percentages
        if (suffix == "%") { number *= 100; }

        var decimalValue = number % 1;
        
        if (opts.format.indexOf(".") > -1) {
            var decimalPortion = dec;
            var decimalFormat = opts.format.substring(opts.format.lastIndexOf(".") + 1);
            var decimalString = new String(decimalValue.toFixed(decimalFormat.length));
            decimalString = decimalString.substring(decimalString.lastIndexOf(".") + 1);
            for (var i=0, l = decimalFormat.length; i < l; i++){
                if (decimalFormat.charAt(i) == '#' && decimalString.charAt(i) != '0') {
                    decimalPortion += decimalString.charAt(i);
                    continue;
                } else if (decimalFormat.charAt(i) == '#' && decimalString.charAt(i) == '0') {
                    var notParsed = decimalString.substring(i);
                    if (notParsed.match('[1-9]')) {
                        decimalPortion += decimalString.charAt(i);
                        continue;
                    } else {
                        break;
                    }
                } else if (decimalFormat.charAt(i) == "0") {
                    decimalPortion += decimalString.charAt(i);
                }
            }
            
            returnString += decimalPortion;

        } else {
            number = Math.round(number);
        }
           
        var ones = Math.floor(number);
        if (number < 0){
            ones = Math.ceil(number);
        }

        var onePortion = "";
        if (ones == 0) {
            onePortion = "0";
        } else {
            // find how many digits are in the group
            var onesFormat = "";
            if (opts.format.indexOf(".") == -1){
                onesFormat = opts.format;
            } else {
                onesFormat = opts.format.substring(0, opts.format.indexOf("."));
            }

            var oneText = new String(Math.abs(ones));
            var groupLength = 9999;
            if (onesFormat.lastIndexOf(",") != -1) {
                groupLength = onesFormat.length - onesFormat.lastIndexOf(",") - 1;
            }

            var groupCount = 0;
            for (var i = oneText.length - 1; i >- 1; i--) {
                onePortion = oneText.charAt(i) + onePortion;
                groupCount++;
                if (groupCount == groupLength && i!=0) {
                    onePortion = group + onePortion;
                    groupCount = 0;
                }

            }
        }
        
        returnString = onePortion + returnString;

        // handle special case where negative is in front of the invalid
        // characters
        if (number < 0 && negativeInFront && prefix.length > 0) {
            prefix = neg + prefix;
        } else if (number < 0) {
            returnString = neg + returnString;
        }

        if (!opts.decimalSeparatorAlwaysShown && returnString.lastIndexOf(dec) == returnString.length - 1) {
            returnString = returnString.substring(0, returnString.length - 1);
        }
        
        returnString = prefix + returnString + suffix;
        return returnString;

    };
    
    var parseNumber = function(text, options, dontmix){
        
        var opts = dontmix ? (options || defaults.parse) : $.extend({}, defaults.parse, options),   
            formatData = dontmix || formatCodes(opts.locale),
            dec = formatData.dec, group = formatData.group, neg = formatData.neg,
            valid = "1234567890.-"
        ;

        // now we need to convert it into a number
        while (text.indexOf(group) > -1){
            text = text.replace(group,'');
        }
        
        text = text.replace(dec,".").replace(neg,"-");
        
        var validText = "", hasPercent = false;
        
        if (text.charAt(text.length-1) == "%") { hasPercent = true }
        for (var i = 0, l = text.length; i < l; i++) {
            if (valid.indexOf(text.charAt(i)) > -1) {
                validText += text.charAt(i);
            }
        }
        
        var number = new Number(validText);
        if (hasPercent) {
            number = number / 100;
            number = number.toFixed(validText.length - 1);
        }

        return number;
        
    }
    
    // expose this in public:
    $.parseNumber = parseNumber;
    $.fn.parse = function(opts){
        var o = $.extend({}, defaults.parse, opts), codez = formatCodes(o.locale);
        return $.map(this, function(item){
            var me = $(item), val = me[me.is(":input") ? "val" : "text"]();
            return parseNumber(val, o, codez);
        });
    }
    $.fn.parse.defaults = defaults.parse;
    
    $.formatNumber = formatNumber;
    $.fn.format = function(opts){
        var o = $.extend({}, defaults.format, opts), codez = formatCodes(o.locale);
        return this.each(function(){
            var me = $(this);
            me[me.is(":input") ? "val" : "text" ](function(_, v){
                return formatNumber(v, o, codez);
            }); 
        });
    }
    $.fn.format.defaults = defaults.format;
    
})(jQuery);

================================================
FILE: hitch.js
================================================
/*
	jQuery.hitch() -  Advanced scope manipulation for jQuery 
	version: 0.1, Peter Higgins (dante at dojotoolkit.org)

	(c) 2004-2010 The Dojo Foundation - adapted from `dojo.hitch`
	Either AFL/New BSD license, see: http://dojotoolkit.org/license 

	usage 1:
	
		var obj = {
			attr: "blah",
			func: function(){
				console.log(this.attr);
			}
		}
		
		// most useful example out of context, with setTimeout/Interval:
		setInterval($.hitch(obj, "func"), 2100) // call obj.func() in scope of obj
		setTimeout($.hitch(obj, function(){
			this.attr = "blargh";
			this.func();
		}), 2100);
	
	usage 2:
		
		// pseudo-class
		var Thinger = function(){
			this.foo = "bar";
			this.bar = function(event){
				// super generic function to reuse lots
				this.foo = $(event.target).attr("id");
			}
		}
		
		var mine = new Thinger();
		var yours = new Thinger();
		
		$(".foo").click($.hitch(mine, "bar"));
		$(mine).bind("bar", $.hitch(yours, "bar"));
		
*/
;(function($){

	$.hitch = function(scope, method){
		// summary: Create a function that will only ever execute in a given scope
		if(!method){ method = scope; scope = null; }
		if(typeof method == "string"){
			scope = scope || window;
			if(!scope[method]){ throw(['method not found']); }
			return function(){ return scope[method].apply(scope, arguments || []); };
		}
		return !scope ? method : function(){ return method.apply(scope, arguments || []); };
	}

})(jQuery);



================================================
FILE: pubsub.js
================================================
/*	

	jQuery pub/sub plugin by Peter Higgins (dante@dojotoolkit.org)

	Loosely based on Dojo publish/subscribe API, limited in scope. Rewritten blindly.

	Original is (c) Dojo Foundation 2004-2010. Released under either AFL or new BSD, see:
	http://dojofoundation.org/license for more information.

*/	

;(function(d){

	// the topic/subscription hash
	var cache = {};

	d.publish = function(/* String */topic, /* Array? */args){
		// summary: 
		//		Publish some data on a named topic.
		// topic: String
		//		The channel to publish on
		// args: Array?
		//		The data to publish. Each array item is converted into an ordered
		//		arguments on the subscribed functions. 
		//
		// example:
		//		Publish stuff on '/some/topic'. Anything subscribed will be called
		//		with a function signature like: function(a,b,c){ ... }
		//
		//	|		$.publish("/some/topic", ["a","b","c"]);
		cache[topic] && d.each(cache[topic], function(){
			this.apply(d, args || []);
		});
	};

	d.subscribe = function(/* String */topic, /* Function */callback){
		// summary:
		//		Register a callback on a named topic.
		// topic: String
		//		The channel to subscribe to
		// callback: Function
		//		The handler event. Anytime something is $.publish'ed on a 
		//		subscribed channel, the callback will be called with the
		//		published array as ordered arguments.
		//
		// returns: Array
		//		A handle which can be used to unsubscribe this particular subscription.
		//	
		// example:
		//	|	$.subscribe("/some/topic", function(a, b, c){ /* handle data */ });
		//
		if(!cache[topic]){
			cache[topic] = [];
		}
		cache[topic].push(callback);
		return [topic, callback]; // Array
	};

	d.unsubscribe = function(/* Array */handle){
		// summary:
		//		Disconnect a subscribed function for a topic.
		// handle: Array
		//		The return value from a $.subscribe call.
		// example:
		//	|	var handle = $.subscribe("/something", function(){});
		//	|	$.unsubscribe(handle);
		
		var t = handle[0];
		cache[t] && d.each(cache[t], function(idx){
			if(this == handle[1]){
				cache[t].splice(idx, 1);
			}
		});
	};

})(jQuery);



================================================
FILE: tests/Stateful.html
================================================
<!DOCTYPE html>
<html>
    <head>
        
        <title>Number Format Tests</title>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script src="../Stateful.js"></script>
        <script>
        
            $(function(){

                var thing = new $.Stateful();
                thing.watch("bar", function(){
                    console.log("bar changed to", this.get("bar"));
                });
                thing.set("bar", "baz");

            });
        
        </script>
        
    </head>
    <body>
    </body>
</html>

================================================
FILE: tests/format.html
================================================
<!DOCTYPE html>
<html>
    <head>
        
        <title>Number Format Tests</title>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script src="../format.js"></script>
        <script>
        
            $(function(){
                
                $("#foo, #bar").format();

                var o = $("#baz");

                var x = "1234567";
                var xx = $.formatNumber(x);
                
                var y = "1,234,567";
                var yy = $.parseNumber(y);
                
                o.append("<li>" + xx + "</li>").append("<li>" + yy + "</li>");
            });
        
        </script>
        
    </head>
    <body>
        
        <input id="foo" value="1234567">
        
        <div id="bar">1234567</div>
        
        <ul id="baz">
            <li>outputs:</li>
        </ul>
        
    </body>
</html>
Download .txt
gitextract_b3to4grb/

├── README.md
├── Stateful.js
├── date.js
├── format.js
├── hitch.js
├── pubsub.js
└── tests/
    ├── Stateful.html
    └── format.html
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (34K chars).
[
  {
    "path": "README.md",
    "chars": 1260,
    "preview": "# Bloody jQuery Plugins \n\nA small collection of useful functionality available by default in Dojo, though useful in plai"
  },
  {
    "path": "Stateful.js",
    "chars": 3665,
    "preview": "(function($){\n\n\t$.Stateful = function(args){\n\t\t$.extend(this, args);\n\t}\n\t\n\t$.extend($.Stateful.prototype, {\n\n\t\tget: func"
  },
  {
    "path": "date.js",
    "chars": 10128,
    "preview": "/*\t\n\n\tjQuery Date utility plugin by Peter Higgins (dante@dojotoolkit.org)\n\n\tBased on (actually, diretly ported from) Doj"
  },
  {
    "path": "format.js",
    "chars": 10300,
    "preview": "/**\n *       jquery.numberformatter - Formatting/Parsing Numbers in jQuery\n *       Completely changed by Peter Higgins "
  },
  {
    "path": "hitch.js",
    "chars": 1430,
    "preview": "/*\n\tjQuery.hitch() -  Advanced scope manipulation for jQuery \n\tversion: 0.1, Peter Higgins (dante at dojotoolkit.org)\n\n\t"
  },
  {
    "path": "pubsub.js",
    "chars": 2109,
    "preview": "/*\t\n\n\tjQuery pub/sub plugin by Peter Higgins (dante@dojotoolkit.org)\n\n\tLoosely based on Dojo publish/subscribe API, limi"
  },
  {
    "path": "tests/Stateful.html",
    "chars": 599,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        \n        <title>Number Format Tests</title>\n        <script src=\"http://ajax.g"
  },
  {
    "path": "tests/format.html",
    "chars": 920,
    "preview": "<!DOCTYPE html>\n<html>\n    <head>\n        \n        <title>Number Format Tests</title>\n        <script src=\"http://ajax.g"
  }
]

About this extraction

This page contains the full source code of the phiggins42/bloody-jquery-plugins GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (29.7 KB), approximately 8.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!