﻿/*
Performer JavaScript library
Created by Chris Taylor (http://www.stillbreathing.co.uk)
Additional work by kourge
Based on the Prototype framework (http://www.prototypejs.org)

This work is released under a Creative Commons Attribution-ShareAlike 3.0 licence

You are free:

* to Share — to copy, distribute and transmit the work
* to Remix — to adapt the work

Under the following conditions:

* Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
* Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.
* For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
* Any of the above conditions can be waived if you get permission from the copyright holder.
* Nothing in this license impairs or restricts the author's moral rights.
*/
var Performer =
{
    Performer: function()
    {
        // set debugging
        Performer.Debugging = false;
        Performer.Debug('Performer.Performer', 'function');
        // set up global variables
        Performer.Reloaders = new Array();
        // initialise the app
        Performer.Init();
    },
	Init: function()
	{
	    Performer.Debug('Performer.Init', 'function');
	    // set up global variables
		Performer.FillerElement;
		Performer.TextValue;
		Performer.FadeSteps = 8;
		Performer.CurrentFadeStep = 0;
		// do the transformations
		Performer.DoTransformers();
		// set up listeners
		Performer.DoListeners();
	},
	ReInit: function(el)
	{
	    Performer.Debug('Performer.ReInit', 'function');
		// do the transformations
		Performer.DoTransformers(el);
		// set up listeners
		Performer.DoListeners(el);
	},
	DoListeners: function(el)
	{
	    Performer.Debug('Performer.DoListeners', 'function');
	    if (el == undefined) el = '';
		Performer.Listeners(el,'toggler','Toggle','click');
		Performer.Listeners(el,'switcher','Switch','click');
		Performer.Listeners(el,'loader','Load','click');
		Performer.Listeners(el,'toggleloader','ToggleLoad','click');
		Performer.Listeners(el,'sizer','Size','click');
		Performer.Listeners(el,'tabber','Tab','click');
		Performer.Listeners(el,'selector','Select','change,keyup');
		Performer.Listeners(el,'limiter','Limit','keyup');
		Performer.Listeners(el,'editor','Edit','click,keyup');
		Performer.Listeners(el,'uneditor','UnEdit','click,keyup');
		Performer.Listeners(el,'prompter','RemovePrompt','focus');
		Performer.Listeners(el,'prompter','CheckPrompt','blur');
		Performer.Listeners(el,'popper','Pop','click,keyup');
		Performer.Listeners(el,'passwordchecker','CheckPassword','keyup');
		Performer.Listeners(el,'matcher','Match','keyup');
	},
	DoTransformers: function(el)
	{
	    if (el == undefined) el = '';
	    Performer.Debug('Performer.DoTransformers', 'function');
		Performer.Transformers(el,'hider','Hide');
		Performer.Transformers(el,'shower','Show');
		Performer.Transformers(el,'focusser','Focus');
		Performer.Transformers(el,'limiter','LimitNotifier');
		Performer.Transformers(el,'reloader','Reload');
		Performer.Transformers(el,'preloader', 'Preload');
		Performer.Transformers(el,'prompter','SetPrompt');
		// fader requires scriptaculous
		Performer.Transformers(el,'fader','Fader');
	},
    // listen for the required classnames
    Listeners: function(el,className,f,event)
    {
        if (el != undefined) el = el + ' ';
        Performer.Debug('- Performer.Listeners(' + el + '.' + className + ')', 'subfunction');
        $$(el + '.' + className).each(function(element)
        {
            event.split(',').each(function(event)
            {
                Event.observe(element, event, Performer[f], false);
            });
        });
    },
    // transform the required classnames
    Transformers: function(el,className,f)
    {
        Performer.Debug('- Performer.Transformers(' + el + '.' + className + ')', 'subfunction');
        if (el != undefined) el = el + ' ';
        $$(el + '.' + className).each(function(element)
        {
            Performer[f](element);
        });
    },
    // send a list selection to a remote page
    Select: function(e)
    {
      Performer.Debug('Performer.Select', 'function');
      var el = Event.element(e);
      // check the element has the required attributes
      if (el.readAttribute && el.readAttribute('id') && el.readAttribute('name') && el.readAttribute('class'))
      {
        // get the classes
        var classes = el.readAttribute('class').split(' ');
        // loop the classes, trying to get the rev and rel
        for (var i=0; i<classes.length; i++)
        {
          // targetEl
          if (classes[i].match(/^targetEl-/)){ var targetEl = classes[i].replace('targetEl-', ''); }
          // targetPage
          if (classes[i].match(/^targetPage-/)){ var targetPage = classes[i].replace('targetPage-', ''); }
          // targetValue
          if (classes[i].match(/^targetValue-/)){ var targetValue = classes[i].replace('targetValue-', ''); }
        }
        // check we have a targetPage and targetEl
        if (targetPage && targetEl)
        {
           // check the target element can be found
           if ($(targetEl))
           {
             Performer.FillerElement = targetEl;
             if (targetValue == 'true')
             {
                Performer.DoLoad(targetPage + '?selection=' + el.getValue(), 'post', Performer.SetValueAndInit);
             } else {
                Performer.DoLoad(targetPage + '?selection=' + el.getValue(), 'post', Performer.FillAndInit);
             }
           }
        }
      }
    },
    // check the strength of a password
    CheckPassword: function(e)
    {
        Performer.Debug('Performer.CheckPassword', 'function');
        var el = Event.element(e);
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('id') && el.readAttribute('name') && el.readAttribute('class'))
        {
          // get the classes
          var classes = el.readAttribute('class').split(' ');
          // loop the classes, trying to get the rev and rel
          for (var i=0; i<classes.length; i++)
          {
            // notifyEl
            if (classes[i].match(/^notifyEl-/)){ var notifyEl = classes[i].replace('notifyEl-', ''); }
          }
          // check we have a notification element
          if (notifyEl && $(notifyEl))
          {
            var val = el.value;
            // if the password is shorter than 6 characters
            if (val.length < 6)
            {
                $(notifyEl).innerHTML = 'Your password must be at least 6 characters long';
                $(notifyEl).className = 'password-fail';
            // if the password has only letters
            } else {
                $(notifyEl).innerHTML = '';
                $(notifyEl).className = '';
                // if the password is just letters or just numbers less than 10 characters
                if (val.match(/^([a-zA-Z]{6,10})$/) || val.match(/^([0-9]{6,10})$/)) {
                    $(notifyEl).innerHTML = 'Weak password';
                    $(notifyEl).className = 'password-weak';
                // if the password is just letters or just numbers more than 10 characters
                } else if (val.match(/^([a-zA-Z]{10,})$/) || val.match(/^([0-9]{10,})$/)) {
                    $(notifyEl).innerHTML = 'Acceptable password';
                    $(notifyEl).className = 'password-ok';
                // if the password contains letters, numbers and characters it is strong
                } else if (val.match(/^.*(?=.{6,})(?=.*\d)(?=.*[a-z])(?=.*[^0-9a-zA-Z]).*$/)) {
                    $(notifyEl).innerHTML = 'Strong password';
                    $(notifyEl).className = 'password-strong';
                // if the password has just letters and numbers, or just letters and characters, or just numbers and characters
                } else if (val.match(/^.*(?=.{6,})(?=.*\d)(?=.*[a-z]).*$/) || val.match(/^.*(?=.{6,})(?=.*[^0-9a-zA-Z])(?=.*[a-z]).*$/) || val.match(/^.*(?=.{6,})(?=.*[^0-9a-zA-Z])(?=.*\d).*$/)) {
                    $(notifyEl).innerHTML = 'Acceptable password';
                    $(notifyEl).className = 'password-ok';
                }
             }
          }
        }
    },
    // match the values of two input boxes
    Match: function(e)
    {
        Performer.Debug('Performer.Match', 'function');
        var el = Event.element(e);
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('id') && el.readAttribute('name') && el.readAttribute('class'))
        {
          // get the classes
          var classes = el.readAttribute('class').split(' ');
          // loop the classes, trying to get the rev and rel
          for (var i=0; i<classes.length; i++)
          {
            // notifyEl
            if (classes[i].match(/^notifyEl-/)){ var notifyEl = classes[i].replace('notifyEl-', ''); }
            // matchEl
            if (classes[i].match(/^matchEl-/)){ var matchEl = classes[i].replace('matchEl-', ''); }
          }
          // check we have a match element and a notification element
          if (notifyEl && $(notifyEl) && matchEl && $(matchEl))
          {
            // show the notifyEl
            $(notifyEl).show();
            // get the value
            var val1 = el.value;
            // get the value to be matched
            var val2 = $(matchEl).value;
            // if the values match
            if (val1 == val2)
            {
                // hide the notifyEl
                $(notifyEl).hide();
            }
          }
        }
    },
    // toggle element
    Toggle: function(e,c)
    {
        Performer.Debug('Performer.Toggle', 'function');
	    r = false;
	    var el = Event.findElement(e, 'A');
        // check the element has the required attribute
        if (el.readAttribute && el.readAttribute('rel'))
        {
            var targetEl = el.readAttribute('rel');
            // check the target element can be found
            if ($(targetEl))
            {
		        // toggle the visibility
                if (!$(targetEl).visible())
                {
		            el.addClassName('toggleropen');
		            $(targetEl).removeClassName('hider');
                    $(targetEl).show();
                    r = true;
                } else {
		            el.removeClassName('toggleropen');
		            $(targetEl).addClassName('hider');
                    $(targetEl).hide();
                    r = false;
                }
            }
        }
        if (!c) Event.stop(e);
        return r;
    },
    // switch visibility of two element
    Switch: function(e,c)
    {
        Performer.Debug('Performer.Switch', 'function');
	    r = false;
        //var el = Event.element(e);
	    var el = Event.findElement(e, 'A');
        // check the element has the required attribute
        if (el.readAttribute && el.readAttribute('rel') && el.readAttribute('rev'))
        {
            var targetEl1 = el.readAttribute('rel');
	        var targetEl2 = el.readAttribute('rev');
            // check the target elements can be found
            if ($(targetEl1) && $(targetEl2))
            {
		        // toggle the visibility
                if (!$(targetEl1).visible())
                {
                    $(targetEl1).show();
		            $(targetEl2).hide();
                    r = true;
                } else {
                    $(targetEl2).show();
		            $(targetEl1).hide();
                    r = false;
                }
            }
        }
        if (!c) Event.stop(e);
        return r;
    },
    // focus the element
    Focus: function(e)
    {
        Performer.Debug('Performer.Focus', 'function');
        var el = $(e);
        if (el)
        {
            $(el).focus();
        }        
    },
    // resize the element
    Size: function(e)
    {
        Performer.Debug('Performer.Size', 'function');
        var el = Event.findElement(e, 'A');
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('rel') && el.readAttribute('rev'))
        {
            var targetEl = el.readAttribute('rel');
            // check the target element can be found
            if ($(targetEl))
            {
                // get the new size
                var sizes = el.readAttribute('rev');
                // get the height/width values
                if (sizes.indexOf(',')>=0)
                {
                  var sizeParts = sizes.split(',');
                  var height = sizeParts[0];
                  var width = sizeParts[1];
                } else {
                  var height = sizes;
                  var width = 0;
                }
                if (height==''){ height = 0; }
                if (width==''){ width = 0; }
                // get current dimensions
                var dimensions = $(targetEl).getDimensions();
                var currentHeight = dimensions.height;
                var currentWidth = dimensions.width;
                // calculate the new dimensions and resize the element
                if (height != 0){
                    var newHeight = (parseFloat(height) + parseFloat(currentHeight)) + 'px';
                    $(targetEl).setStyle({ height: newHeight });
                }
                if (width != 0)
                {
                    var newWidth = (parseFloat(width) + parseFloat(currentWidth)) + 'px';
                    $(targetEl).setStyle({ width: newWidth });
                }
            }
        }
        Event.stop(e);
        Performer.DoTransformers();
    },
    // toggle an element and load data
    ToggleLoad: function(e)
    {
        Performer.Debug('Performer.ToggleLoad', 'function');
	    var el = Event.element(e);
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('rel') && el.readAttribute('rev'))
        { 
           var targetEl = el.getAttribute('rel');
           // check the target element can be found
           if ($(targetEl))
           {
             if (Performer.Toggle(e,true))
             {
               Performer.Load(e,true,false);
             }
           }
        }
        Event.stop(e);
    },
    // toggle tabs
    Tab: function(e)
    {
        Performer.Debug('Performer.Tab', 'function');
        var el = Event.findElement(e, 'A');
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('rel') && el.readAttribute('rev'))
        {
            var tabGroup = el.readAttribute('rel');
            var openTab = el.readAttribute('rev');
	    var tablinks = $$(' .tabber');
	    for (var i=0; i<tablinks.length; i++)
	    {
		if ($(tablinks[i]).readAttribute && $(tablinks[i]).readAttribute('rel') == tabGroup)
		{
			$(tablinks[i]).removeClassName('tabbercurrent');
		}
	    }
            // check the tabgroup can be found
            if ($(tabGroup))
            {
                // hide all the tabs
                var tabs = $$('#' + tabGroup + ' .tab');
                for (var i=0; i<tabs.length; i++)
                {
                    $(tabs[i]).hide();
                }
		        el.addClassName('tabbercurrent');
                // show the required tab
                $(openTab).show();
                Performer.Debug('-> Showing tab ' + openTab, 'success'); 
            }
        }
        Event.stop(e);
    },
    // load data into an element
    Load: function(e,c,s)
    {
        Performer.Debug('Performer.Load', 'function');
        var el = Event.findElement(e, 'A');
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('rel') && el.readAttribute('rev'))
        {
            var targetEl = el.readAttribute('rel');
            var targetPage = el.readAttribute('rev');
            // check the target element can be found
            if ($(targetEl))
            {
                Performer.FillerElement = targetEl;
		        if(!s)
		        {
			        Performer.DoLoad(targetPage, 'get', Performer.FillAndInit);
		        } else {
			        Performer.DoLoad(targetPage, 'get', Performer.Fill);
		        }
            }
        }
        if (!c) Event.stop(e);
    },
    // load some data
    DoLoad: function(targetPage, requestMethod, onCompleteFunction)
    {
        Performer.Debug('Performer.DoLoad(' + targetPage + ')', 'function');
        $(Performer.FillerElement).addClassName('loaderloading');
        new Ajax.Request(targetPage, {method: requestMethod, onComplete: onCompleteFunction});
    },
    // load data into an element on a regular basis
    Reload: function(e)
    {
        Performer.Debug('Performer.Reload');
        var el = $(e);
        // check this reloader isn't already initialised
        Performer.Debug('\'' + el.id + '\' exists in Performer.Reloaders = ' + Performer.Reloaders.indexOf(el.id));
        if (Performer.Reloaders.indexOf(el.id) == -1)
        {
            var delay;
            var targetPage;
            // loop the classes, trying to get the delay and and targetPage
            el.classNames().each(function(cls)
            {
                // targetEl
                if (cls.match(/^delay-/)){ delay = cls.replace('delay-', ''); } else { delay = '15'; }
                // targetPage
                if (cls.match(/^targetPage-/)){ targetPage = cls.replace('targetPage-', ''); 
            }});
            // check the element has the required attributes
            if (el && delay && targetPage)
            {
                Performer.Reloaders[Performer.Reloaders.length] = el.id;
                Performer.Debug('Added \'' + el.id + '\' to Performer.Reloaders (now ' + Performer.Reloaders.length + ' items)');
                Performer.FillerElement = el;
			    Performer.DoLoad(targetPage, 'get', Performer.FillAndInit);
                var ex = new PeriodicalExecuter(function(){
				    var d = new Date();
				    var t = d.getTime();
				    Performer.DoLoad(targetPage + '?&' + t, 'get', Performer.FillAndInit);
			    }, delay);
            }
        }
    },
    // load data into an element when the page loads
    Preload: function(e)
    {
        Performer.Debug('Performer.Preload', 'function');
        var el = $(e);
        var targetPage;
        // loop the classes, trying to get the targetPage
        el.classNames().each(function(cls)
        {
            // targetPage
            if (cls.match(/^targetPage-/)){ targetPage = cls.replace('targetPage-', ''); 
        }});
	    // check the element has the required attributes
	    if (el && targetPage)
        {
	        Performer.FillerElement = e;
	        $Loader = new Ajax.Request(targetPage, {method: 'get', onComplete: Performer.FillAndInit});
	        Performer.Debug('-> Preloading from ' + targetPage, 'success'); 
	    }
    },
    // fill an element with data
    Fill: function(request)
    {
        Performer.Debug('Performer.Fill', 'function');
        var text = request.responseText;
        // check the target element can be found
        if ($(Performer.FillerElement))
        {
            $(Performer.FillerElement).innerHTML = text;
	        $(Performer.FillerElement).removeClassName('loaderloading');
	        Performer.Debug('-> Filled \'' + Performer.FillerElement.id + '\'', 'success');
        }
    },
    // set the value of an element with data
    SetValue: function(request)
    {
        Performer.Debug('Performer.SetValue', 'function');
        var text = request.responseText;
        // check the target element can be found
        if ($(Performer.FillerElement))
        {
            $(Performer.FillerElement).value = text;
	        $(Performer.FillerElement).removeClassName('loaderloading');
	        Performer.Debug('-> Value set \'' + Performer.FillerElement.id + '\'', 'success');
        }
    },
    // fill an element with data then initialise the Performer functions
    FillAndInit: function(request)
    {
        Performer.Debug('Performer.FillAndInit', 'function');
        var text = request.responseText;
        // check the target element can be found
        if ($(Performer.FillerElement))
        {
            $(Performer.FillerElement).innerHTML = text;
	        $(Performer.FillerElement).removeClassName('loaderloading');
	        Performer.Debug('-> Filled \'' + Performer.FillerElement.id + '\'', 'success');
        }
	    Performer.ReInit('#' + Performer.FillerElement.id);
    },
    // set the value of an element with data then initialise the Performer functions
    SetValueAndInit: function(request)
    {
        Performer.Debug('Performer.SetValueAndInit', 'function');
        var text = request.responseText;
        // check the target element can be found
        if ($(Performer.FillerElement))
        {
            $(Performer.FillerElement).value = text;
	        $(Performer.FillerElement).removeClassName('loaderloading');
	        Performer.Debug('-> Set value \'' + Performer.FillerElement.id + '\'', 'success');
        }
	    Performer.ReInit('#' + Performer.FillerElement.id);
    },
    // hide a hider element
    Hide: function(e)
    {
        Performer.Debug('Performer.Hide', 'function');
        var el = $(e);
        if (el)
        {
            el.hide();
        }
    },
    // show a shower element
    Show: function(e)
    {
        Performer.Debug('Performer.Show', 'function');
        var el = $(e);
        if (el)
        {
            el.removeClassName('shower', 'function');
        }
    },
    // get the parameters for a limiter
    GetLimitParams: function(el)
    {
        Performer.Debug('Performer.GetLimitParams');
        // check the element has the required attributes and is an input or textarea
        if (el.readAttribute && el.readAttribute('id') && el.classNames() && (el.type == 'textarea' || el.type == 'text'))
        {
            var targetEl;
            var lengthLimit;
            // loop the classes, trying to get the rev and rel
            el.classNames().each(function(cls)
            {
                // targetEl
                if (cls.match(/^targetEl-/)){ targetEl = cls.replace('targetEl-', ''); }
                // targetPage
                if (cls.match(/^lengthLimit-/)){ lengthLimit = cls.replace('lengthLimit-', ''); } else { lengthLimit = 255; }
            })
            // check the target element can be found
            if (targetEl && $(targetEl))
            {
                var params = new Array();
                params["lengthLimit"] = lengthLimit;
                params["targetEl"] = targetEl;
                return params;
            } else {
                return false;
            }
        } else {
            return false;
        }
    },
    // limit the amount of text in an input box or textarea
    Limit: function(e)
    {
        Performer.Debug('Performer.Limit', 'function');
        var el = Event.element(e);
        // get the parameters
        var params = Performer.GetLimitParams(el);
        if (params && params["lengthLimit"] && params["targetEl"])
        {
            var lengthLimit = params["lengthLimit"];
            var targetEl = params["targetEl"];
            var currentLength = $F(el).length;
            // limit the length
            if (parseFloat(currentLength) >= parseFloat(lengthLimit))
            {
                $(el).value = $F(el).substr(0,lengthLimit);
                $(targetEl).update("Limit reached");
            } else {
                $(targetEl).update((lengthLimit-currentLength) + " characters left");
                
            }
        }
    },
    // show the length limit notification
    LimitNotifier: function(e)
    {
        Performer.Debug('Performer.LimitNotifier', 'function');
        var el = $(e);
        // get the parameters
        var params = Performer.GetLimitParams(el);
        // check this doesn't have prompt text in
        if (!el.hasClassName('prompter'))
        {
            if (params && params["lengthLimit"] && params["targetEl"])
            {
                var currentLength = $F(el).length;
                $(params["targetEl"]).update((params["lengthLimit"]-currentLength) + " characters left");
            }
        } else {
            $(params["targetEl"]).update(params["lengthLimit"] + " characters left");
        }
    },
    // edit the contents of an element and send the results to a processing page
    Edit: function(e)
    {
        Performer.Debug('Performer.Edit', 'function');
        var el = Event.element(e);
        if (el.readAttribute && el.readAttribute('id') && el.classNames())
        {
            var targetPage;
            var inputType;
            // loop the classes
            el.classNames().each(function(cls)
            {
                // targetPage
                if (cls.match(/^targetPage-/)){ targetPage = cls.replace('targetPage-', ''); }
            })
            if (targetPage)
            {
                // build the editing form
		        Performer.TextValue = $(el).innerHTML;
                el.innerHTML = Performer.BuildEditForm(el,targetPage);
                Performer.Init();
            }
        }
    },
    // build the element editing form
    BuildEditForm: function(el,targetPage)
    {
        Performer.Debug('Performer.BuildEditForm(' + targetPage + ')', 'function');
        if (el && $(el) && targetPage)
        {
            var value = $(el).innerHTML;
            var editForm;
            editForm = '<form id="' + $(el).id + '-editor" class="performer-editor" action="' + targetPage + '" method="post">\n';
            editForm += '<fieldset>\n';
	    editForm += '<input type="text" id="' + $(el).id + '-value" name="' + $(el).id + '" value="' + value + '" />\n';
            editForm += '<input type="submit" id="' + $(el).id + '-save" name="' + $(el).id + '-save" value="Save" />\n';
            editForm += '<a href=\"#\" class="uneditor" rel="' + $(el).id + '">Cancel</a>\n';
            editForm += '</fieldset>\n';
            editForm += '</form>\n';
            Performer.Debug('-> Built form with action: ' + targetPage, 'function'); 
            return editForm;
        }
    },
    // cancel a Performer.Edit command and return the element to normal
    UnEdit: function(e)
    {
        Performer.Debug('Performer.UnEdit', 'function');
        var el = Event.element(e);
        if (el.readAttribute && el.readAttribute('rel'))
        {
            var targetEl = el.readAttribute('rel');
            $(targetEl).innerHTML = Performer.TextValue;
        }
	    Event.stop(e);
        },
    // checks if the element has focus and if so removes the content from it
    // when the element loses focus it checks if the element has no contents and adds the prompt back in
    SetPrompt: function(el)
    {
        Performer.Debug('Performer.SetPrompt', 'function');
	    if (el.readAttribute && el.readAttribute('id') && el.readAttribute('title') && el.value == "" && (el.type == 'textarea' || el.type == 'text'))
	    {
	        Performer.Debug('-> Setting prompt: ' + el.readAttribute('title'), 'function'); 
		    el.addClassName("performer-prompter");
		    el.value = el.readAttribute('title');
	    }
    },
    // remove a prompt
    RemovePrompt: function(e)
    {
        Performer.Debug('Performer.RemovePrompt', 'function');
	    var el = Event.element(e);
        if (el.readAttribute && el.readAttribute('id') && el.readAttribute("title")&& (el.value == el.readAttribute("title")) && (el.type == 'textarea' || el.type == 'text'))
        {
		    el.value = "";
		    el.removeClassName("performer-prompter");
	    }
    },
    // check a prompt is present
    CheckPrompt: function(e)
    {
        Performer.Debug('Performer.CheckPrompt', 'function');
	    var el = Event.element(e);
	    if (el.readAttribute && el.readAttribute('id') && el.readAttribute("title")&& (el.value == "") && (el.type == 'textarea' || el.type == 'text'))
	    {
		    Performer.SetPrompt(el);
	    }
    },
    // open a popup window
    Pop: function(e)
    {
        Performer.Debug('Performer.Pop', 'function');
        var el = Event.element(e);
        // check the element has the required attributes
        if (el.readAttribute && el.readAttribute('href') && el.readAttribute('rel') && el.readAttribute('rev'))
        {
            var targetURL = el.readAttribute('href');
			var targetName = el.readAttribute('rel');
            var pageOptions = el.readAttribute('rev');
            Performer.Debug('-> Opening: ' + targetURL + ' with ' + pageOptions, 'function'); 
			var win = window.open(targetURL,targetName,pageOptions);
			if (window.focus) {win.focus()}
			Event.stop(e);
		}
	},
	// fade from one color to another - this relies on scriptaculous being used
	Fader: function(e)
	{
	    Performer.Debug('Performer.Fader', 'function');
        var el = $(e);
        if (Effect.Highlight && el)
        {
            // get the end color
            var end_bg = Performer.GetColor(el.getStyle('backgroundColor'));
            var bg = '#FFEB8F';
            var dur = '3';
            var del = '1';
            // loop the classes
            el.classNames().each(function(cls)
            {
                // get the bg
                if (cls.match(/^bg-/)){ bg = cls.replace('bg-', ''); }
                // get the duration
                if (cls.match(/^duration-/)){ dur = cls.replace('duration-', ''); }
                // get the delay
                if (cls.match(/^delay-/)){ del = cls.replace('delay-', ''); }
            })
            // get the initial fade color
            var start_bg = Performer.GetColor(bg);
            // set the initial color
            el.setStyle({ backgroundColor: start_bg });
            // start the fade
            Performer.Debug('Fader background color: ' + start_bg + ' -> ' + end_bg + '', 'function');
            new Effect.Highlight(el, { startcolor: start_bg, endcolor: end_bg, restorecolor: end_bg, duration: dur, delay: del });
        } 
	},
	// get HEX from color, either HEX or RGB string
	GetColor: function(val)
	{
	    Performer.Debug('Performer.GetColor(' + val + ')', 'function');
	    if (val && val.length != 0)
	    {
            val = val.toUpperCase();
            val = val.toLowerCase().replace(/#/g,'');
            if (val.length == 6)
            {
                color = '#' + val;
            }
            else if (val.length == 3)
            {
                color = val.substring(0, 1) + val.substring(0, 1);
                color = color + val.substring(1, 2) + val.substring(1, 2);
                color = color + val.substring(2, 3) + val.substring(2, 3);
                color = '#' + color;
            }
	        else if (val.substring(0, 3) == 'rgb' && val.indexOf(',') != -1)
	        {
	            var vals = val.replace(/rgb\(|\)/g, "").split(",");
	            r = parseInt(vals[0].replace(/ /g,''), 10).toString(16).toLowerCase();
	            g = parseInt(vals[1].replace(/ /g,''), 10).toString(16).toLowerCase();
	            b = parseInt(vals[2].replace(/ /g,''), 10).toString(16).toLowerCase();
	            color = '#' + r + g + b;  
	        } else {
	            color = '#FFFFFF';
	        }
	        Performer.Debug('-> Color: ' + color.toUpperCase(), 'function'); 
	    }
	    return color.toUpperCase();
	    //Array(color["red"], color["green"], color["blue"]);
	},
	// debug Performer
	Debug: function(str, status)
	{
	    if (Performer.Debugging)
	    {
	        if ($('performerjsoutput') == null)
	        {
	            document.getElementsByTagName('body')[0].innerHTML += '<div style="background:#333;"><h3 style="font-family:Arial,sans-serif;padding:0.3em;margin:0;color:#FFF;">Performer Debug Output</h3><div id="performerjsoutput" style="padding:0.3em;margin:0.4em;height:24em;overflow:auto;background:#FFF;></div></div>';
	        }
	        var col = '#000';
	        if (status == 'function')
	        {
	            col = '#333';
	        } else if (status == 'subfunction')
	        {
	            col = '#AAA';
	        } else if (status == 'error')
	        {
	            col = '#900';
	        } else if (status == 'success')
	        {
	            col = '#090';
	        } else if (status == 'warning')
	        {
	            col = '#FFA800';
	        }
	        $('performerjsoutput').innerHTML += '<p style="margin:0.1em 0;padding:0;color:' + col + '">' + str + '</p>';
	    }
	}
}
// load Performer
Event.observe(window, 'load', Performer.Performer, false);