// The youngisrael-stl.org jquery basic plugins
// uojs for automating unobtrusive javascript
// dom and individual elements for DOM creation

(function($){

/**
uojs:

Implements unobtrusive Javascript unobtrusively. selects all elements 
with a class 'make_foo', applies the foo() plugin to them, then changes 
the class to 'made_foo'.
Options can be added by making the class 'make_foo_bar'; where 
$.fn.foo.bar is assigned (in the javascript code) to the options object.
Assumes all plugins take at most one argument, an object of options. If 
there is no underline after
the class name, looks for a member of the element e.foo and uses that 
as the argument to foo. (e.foo must have been added by one of the 
metadata plugins.)
Thus:
<div class="make_Slider_indicator">
	<div class="indicator" id="indicator1">&nbsp;</div>
</div>
and in a <script> :
$.fn.Slider.indicator = {accept :  '.indicator', opacity:  0.8, values: 
[[290,0]]}

or, using metaobjects:
<div class="make_Slider">
       <object class="metaobject">
            <param name="Slider" value="{accept: '.indicator', opacity: 0.8, values: [[290,0]]}" />
       </object>
	<div class="indicator" id="indicator1">&nbsp;</div>
</div>

or, using metadata:
<div class="make_Slider {Slider: {accept : '.indicator', opacity: 0.8, values: [[290,0]]} }">
	<div class="indicator" id="indicator1">&nbsp;</div>
</div>
*/

$.fn.uojs = function(){
  $('[className*=make_]').each(function(){
    while (m = $.fn.uojs.re.exec(this.className)){
      // m[2] is the whole "class name", m[3] is the plugin name, m[5] is the argument
      var plugin = $.fn[m[3]];
      var options = m[5] && plugin[m[5]] || this[m[3]];
      plugin.call($(this), options);
      this.className = this.className.replace(m[2], 'made_'+m[3]);
     } // for
   }); // each
 }; // uojs
$.fn.uojs.re = /(^|\s)(make_([A-Za-z0-9\$]*)(_([A-Za-z0-9\$]*))?)(\s|$)/;
$(function(){$().uojs()}); // just do it

// DOM creation code, based on http://mg.to/2006/02/27/easy-dom-creation-for-jquery-and-prototype
// and the subsequent comments.
// A simple table would be:
// $.dom (
//   'table',{Class: 'table-class'},['tbody',{}, [
//     'tr',{}, [
//       'td',{}, ['r1c1'],
//       'td',{style: {color: 'red'}}, ['r1c2']
//     ],
//     'tr',{}, [
//       'td',{}, ['r2c2'],
//       'td',{}, ['r1c2: ', 'a', {href: 'whatever.html', title='link'}, ['Link Text']]]
//     ]
//   ]
// );
// You can use already-created HTMLElements and jQuery's in there:
// img = $.dom('img', {src:'foo.gif'});
// div = $.dom('div', {}, [img]);
// creates a div with the image inside. Note that text followed by an object is interpreted as a tagName
// to create, so $.dom('hello', existingObject) gives an error (what you wanted was a textNode 'hello', followed by the
// existing object). You need to put one of them into an array by itself:
// $.dom('hello', [existingObject]);
// and it generates a jQuery object, so it's chainable
$.dom = function(){
  var result = $([]), e;
  for (var i = 0; i < arguments.length; ++i){
    if (typeof arguments[i] == 'string'){
      // a string is either a text literal or a tag name of an element.
      // distinguish by the following argument; a tag name will be followed by an Object
      if (arguments[i+1] && arguments[i+1].constructor == Object){
        e = $(document.createElement(arguments[i])).
          attr (arguments[++i]).css(arguments[i].style || {}); // incorporate the attributes Object
        // append children if the next argument is an array
        if (arguments[i+1] && arguments[i+1].constructor == Array) e.append($.dom.apply(null, arguments[++i]));
      }else{
        e = document.createTextNode(arguments[i]);
      }
    }else if (typeof arguments[i] == 'number'){
      e = document.createTextNode(arguments[i]+'');
    }else if (arguments[i].constructor == Array){
      // process the array
      e = $.dom.apply(null, arguments[i]);
    }else{
      // Something else . Let jQuery deal with it
      e = arguments[i];
    } // if
    result = result.add(e);
  }  // for
  return result;
}; // dom

// predefine some tags, to use as $.P('text') or $.SPAN({Class: 'myclass'}, [child, child])
$.dom.createTag = function(tag){
  $[tag.toUpperCase()] = function(){
    if (arguments.length == 0) return $.dom(tag,{});
    attr = (arguments[0].constructor == Object) ? [].shift.call(arguments) : {};
    return $.dom(tag,attr, [].slice.call(arguments,0));
  }
}; // dom.createTag

$.each(['a', 'br', 'button', 'canvas', 'div', 'fieldset', 'form',
        'h1', 'h2', 'h3', 'hr', 'img', 'input', 'label', 'legend',
        'li', 'ol', 'optgroup', 'option', 'p', 'pre', 'select',
        'span', 'strong', 'table', 'tbody', 'td', 'textarea',
        'tfoot', 'th', 'thead', 'tr', 'tt', 'ul', 'style', 'script' ],
   function (i,e){$.dom.createTag(e)});

// Return a simple image-button, with hover and active (mousedown) image changes
$.imgButton = function (src, hoverSrc, activeSrc){
  hoverSrc = hoverSrc ? hoverSrc : src;
  activeSrc = activeSrc ? activeSrc : hoverSrc;
  return $.dom ('img', {src: src}).
    hover (function(){this.src=hoverSrc}, function(){this.src=src}).
    mousedown (function(){this.src=activeSrc}).
    mouseup (function(){this.src=hoverSrc});    
}; //imgButton

// simple way to encode HTML entities (turn 'a < b' into 'a &lt; b')
$.dom.htmlencode = function(text){
  return $.dom('span',{}, [text]).html();
};

// simple way to decode HTML entities (turn 'a &lt; b' into 'a < b')
$.dom.htmldecode = function(text){
  return $.dom('span',{}).html(text).text();
};

// simple logging, for use with Firebug
$.fn.log = function (brk){
  if (window.console) console.log.apply(console,this.get());;
  if (brk) debugger;
  return this;
};

})(jQuery);
;
// jQuery based CSS parser
// documentation: http://youngisrael-stl.org/wordpress/2009/01/16/jquery-css-parser/
// Version: 1.1
// Copyright (c) 2009 Daniel Wachsstock
// MIT license:
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:

// The above 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.


(function($){
	// utility function, since we want to allow $('style') and $(document), so we need to look for elements in the jQuery object ($.fn.filter) and elements that are children of the jQuery object ($.fn.find)
	$.fn.findandfilter = function(selector){
		var ret = this.filter(selector).add(this.find(selector));
		ret.prevObject = ret.prevObject.prevObject; // maintain the filter/end chain correctly (the filter and the find both push onto the chain). 
		return ret;
	};
	
  $.fn.parsecss = function(callback, parseAttributes){
		var parse = function(str) { $.parsecss(str, callback) }; // bind the callback
    this
    .findandfilter ('style').each (function(){
      parse(this.innerHTML);
    })
    .end()
    .findandfilter ('link[type="text/css"]').each (function(){
			// only get the stylesheet if it's not disabled, it won't trigger cross-site security (doesn't start with anything like http:) and it uses the appropriate media)
			if (!this.disabled && !/\w+:/.test($(this).attr('href')) && $.parsecss.mediumApplies(this.media)) $.get(this.href, parse);
    })
    .end();
		
		if (parseAttributes){
			$.get(location.pathname+location.search, 'text', function(HTMLtext) {
				styleAttributes(HTMLtext, callback);
			});
		}
		
		return this;
	};

  $.parsecss = function(str, callback){
    var ret = {};
		str = munge(str).replace(/@(([^;`]|`[^b]|`b[^%])*(`b%)?);?/g, function(s,rule){
			// @rules end with ; or a block, with the semicolon not being part of the rule but the closing brace (represented by `b%) is
			processAtRule($.trim(rule), callback);
			return '';
		});

    $.each (str.split('`b%'), function(i,css){ // split on the end of a block 
			css = css.split('%b`'); // css[0] is the selector; css[1] is the index in munged for the cssText
			if (css.length < 2) return; // invalid css
			css[0] = restore(css[0]);
			ret[css[0]] = $.extend(ret[css[0]] || {}, parsedeclarations(css[1]));
    });
		callback(ret);
  };
	// explanation of the above: munge(str) strips comments and encodes strings and brace-delimited blocks, so that
	// %b` corresponds to { and `b% corresponds to }
	// munge(str) replaces blocks with %b`1`b% (for example)
	// 
	// str.split('`b%') splits the text by '}' (which ends every CSS statement) 
	// Each so the each(munge(str... function(i,css)
	// is called with css being empty (the string after the last delimiter), an @rule, or a css statement of the form
	// selector %b`n where n is a number (the block was turned into %b`n`b% by munge). Splitting on %b` gives the selector and the
	// number corresponding to the declaration block. parsedeclarations will do restore('%b`'+n+'`b%') to get it back.

	// if anyone ever implements http://www.w3.org/TR/cssom-view/#the-media-interface, we're ready
  $.parsecss.mediumApplies = (window.media && window.media.query) || function(str){
    if (!str) return true; // if no descriptor, everything applies
    if (str in media) return media[str];
		var style = $('<style media="'+str+'">body {position: relative; z-index: 1;}</style>').appendTo('head');
		return media[str] = [$('body').css('z-index')==1, style.remove()][0]; // the [x,y][0] is a silly hack to evaluate two expressions and return the first
  };

  $.parsecss.isValidSelector = function(str){
		var s = $('<style>'+str+'{}</style>').appendTo('head')[0];
		// s.styleSheet is IE; it accepts illegal selectors but converts them to UNKNOWN. Standards-based (s.shee.cssRules) just reject the rule
		return [s.styleSheet ? !/UNKNOWN/i.test(s.styleSheet.cssText) : !!s.sheet.cssRules.length, $(s).remove()][0]; // the [x,y][0] is a silly hack to evaluate two expressions and return the first
  };
	
	$.parsecss.parseArguments = function(str){
		if (!str) return [];
		var ret = [], mungedArguments = munge(str, true).split(/\s+/); // can't use $.map because it flattens arrays !
		for (var i = 0; i < mungedArguments.length; ++i) {
			var a = restore(mungedArguments[i]);
			try{
				ret.push(eval('('+a+')'));
			}catch(err){
				ret.push(a);
			}
		}
		return ret;
	};

	// uses the parsed css to apply useful jQuery functions
	$.parsecss.jquery = function(css){
		for (var selector in css){
			for (var property in css[selector]){
				var match = /^-jquery(-(.*))?/.exec(property);
				if (!match) continue;
				var value = munge(css[selector][property]).split('!'); // exclamation point separates the parts of livequery actions
				var which = match[2];
				dojQuery(selector, which, restore(value[0]), restore(value[1]));
			}
		}
	};

	// expose the styleAttributes function
	$.parsecss.styleAttributes = styleAttributes;
	
  // caches
  var media = {}; // media description strings
  var munged = {}; // strings that were removed by the parser so they don't mess up searching for specific characters

  // private functions

  function parsedeclarations(index){ // take a string from the munged array and parse it into an object of property: value pairs
		var str = munged[index].replace(/^{|}$/g, ''); // find the string and remove the surrounding braces
		str = munge(str); // make sure any internal braces or strings are escaped
    var parsed = {};
    $.each (str.split(';'), function (i, decl){
      decl = decl.split(':');
      if (decl.length < 2) return;
      parsed[restore(decl[0])] = restore(decl[1]);
    });
    return parsed;
  }

  // replace strings and brace-surrounded blocks with %s`number`s% and %b`number`b%. By successively taking out the innermost
  // blocks, we ensure that we're matching braces. No way to do this with just regular expressions. Obviously, this assumes no one
  // would use %s` in the real world.
	// Turns out this is similar to the method that Dean Edwards used for his CSS parser in IE7.js (http://code.google.com/p/ie7-js/)
  var REbraces = /{[^{}]*}/;
	var REfull = /\[[^\[\]]*\]|{[^{}]*}|\([^()]*\)|function(\s+\w+)?(\s*%b`\d+`b%){2}/; // match pairs of parentheses, brackets, and braces and function definitions.
	var REatcomment = /\/\*@((?:[^\*]|\*[^\/])*)\*\//g; // comments of the form /*@ text */ have text parsed 
	// we have to combine the comments and the strings because comments can contain string delimiters and strings can contain comment delimiters
	// var REcomment = /\/\*(?:[^\*]|\*[^\/])*\*\/|<!--|-->/g; // other comments are stripped. (this is a simplification of real SGML comments (see http://htmlhelp.com/reference/wilbur/misc/comment.html) , but it's what real browsers use)
	// var REstring = /\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*'/g; //  match escaped characters and strings
	var REcomment_string =
		/(?:\/\*(?:[^\*]|\*[^\/])*\*\/)|(\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*')/g;
  var REmunged = /%\w`(\d+)`\w%/;
  var uid = 0; // unique id number
  function munge(str, full){
    str = str
    .replace(REatcomment,'$1') // strip /*@ comments but leave the text (to let invalid CSS through)
    .replace(REcomment_string, function (s, string){ // strip strings and escaped characters, leaving munged markers, and strip comments
			if (!string) return '';
      var replacement = '%s`'+(++uid)+'`s%';
      munged[uid] = string.replace(/^\\/,''); // strip the backslash now
      return replacement;      
    })
		;    
    // need a loop here rather than .replace since we need to replace nested braces
		var RE = full ? REfull : REbraces;
    while (match = RE.exec(str)){
      replacement = '%b`'+(++uid)+'`b%';
      munged[uid] = match[0];
      str = str.replace(RE, replacement);
    }
    return str;
  }

  function restore(str){
		if (str === undefined) return str;
    while (match = REmunged.exec(str)){
      str = str.replace(REmunged, munged[match[1]]);
    }
    return $.trim(str);
  }

  function processAtRule (rule, callback){
    var split = rule.split(/\s+/); // split on whitespace
    var type = split.shift(); // first word
    if (type=='media'){
      var css = restore(split.pop()).slice(1,-1); // last word is the rule; need to strip the outermost braces
      if ($.parsecss.mediumApplies(split.join(' '))){
        $.parsecss(css, callback);
      }
    }else if (type='import'){
      var url = restore(split.shift());
      if ($.parsecss.mediumApplies(split.join(' '))){
        url = url.replace(/^url\(|\)$/gi, '').replace(/^["']|["']$/g, ''); // remove the url('...') wrapper
        $.get(url, function(str) { $.parsecss(str, callback) });
      }
    }
  }
		
	function dojQuery (selector, which, value, value2){ // value2 is the value for the livequery no longer match
		if (/show|hide/.test(which)) which +=  'Default'; // -jquery-show is a shortcut for -jquery-showDefault
		if (value2 !== undefined && $.livequery){
			// mode is 0 for a static value (can be evaluated when parsed); 
			// 1 for delayed (refers to "this" which means it needs to be evaluated separately for each element matched), and
			// 2 for livequery; evaluated whenever elments change
			var mode = 2;
		}else{
			mode = /\bthis\b/.test(value) ? 1 : 0;
		}
		if (which && $.fn[which]){
			// a plugin
			// late bind parseArguments so "this" is defined correctly
			function p (str) { return function() { return $.fn[which].apply($(this), $.parsecss.parseArguments.call(this, str)) } };
			switch (mode){
				case 0: return $.fn[which].apply($(selector), $.parsecss.parseArguments(value));
				case 1: return $(selector).each(p(value));
				case 2: return (new $.livequery(selector, document, undefined, p(value), value2 === '' ? undefined : p(value2))).run();
			}
		}else if (which){
			// a plugin but one that was not defined
			return undefined;
		}else{
			// straight javascript
			switch (mode){
				case 0: return eval(value);
				case 1: return $(selector).each(Function(value));
				case 2: return (new $.livequery(selector, document, undefined, Function(value), value2 === '' ? undefined : Function(value2))).run();
			}
		}
	}

	// override show and hide. $.data(el, 'showDefault') is a function that is to be used for show if no arguments are passed in (if there are arguments, they override the stored function)
	// Many of the effects call the native show/hide() with no arguments, resulting in an infinite loop.
	var _show = {show: $.fn.show, hide: $.fn.hide}; // save the originals
	$.each(['show','hide'], function(){
		var which = this, show = _show[which], plugin = which+'Default';
		$.fn[which] = function(){
			if (arguments.length > 0) return show.apply(this, arguments);
			return this.each(function(){
				var fn = $.data(this, plugin), $this = $(this);
				if (fn){
					$.removeData(this, plugin); // prevent the infinite loop
					fn.call($this);
					$this.queue(function(){$this.data(plugin, fn).dequeue()}); // put the function back at the end of the animation
				}else{
					show.call($this);
				}
			});
		};
		$.fn[plugin] = function(){
			var args = $.makeArray(arguments), name = args[0];
			if ($.fn[name]){ // a plugin
				args.shift();
				var fn = $.fn[name];
			}else if ($.effects && $.effects[name]){ // a jQuery UI effect. They require an options object as the second argument
				if (typeof args[1] != 'object') args.splice(1,0,{});
				fn = _show[which];
			}else{ // regular show/hide
				fn = _show[which];
			}
			return this.data(plugin, function(){fn.apply(this,args)});
		};
	});
		
	// experimental: find unrecognized style attributes in elements by reloading the code as text
	var RESGMLcomment = /<!--([^-]|-[^-])*-->/g; // as above, a simplification of real comments. Don't put -- in your HTML comments!
	var REnotATag = /(>)[^<]*/g;
	var REtag = /<(\w+)([^>]*)>/g;

	function styleAttributes (HTMLtext, callback) {
		var ret = '', style, tags = {}; //  keep track of tags so we can identify elements unambiguously
		HTMLtext = HTMLtext.replace(RESGMLcomment, '').replace(REnotATag, '$1');
		munge(HTMLtext).replace(REtag, function(s, tag, attrs){
			tag = tag.toLowerCase();
			if (tags[tag]) ++tags[tag]; else tags[tag] = 1;
			if (style = /\bstyle\s*=\s*(%s`\d+`s%)/i.exec(attrs)){ // style attributes must be of the form style = "a: bc" ; they must be in quotes. After munging, they are marked with numbers. Grab that number
				var id = /\bid\s*=\s*(\S+)/i.exec(attrs); // find the id if there is one.
				if (id) id = '#'+restore(id[1]).replace(/^['"]|['"]$/g,''); else id = tag + ':eq(' + (tags[tag]-1) + ')';
				ret += [id, '{', restore(style[1]).replace(/^['"]|['"]$/g,''),'}'].join('');
			}
		});
		$.parsecss(ret, callback);
	}
})(jQuery);
;

