/* This file has the following sections: - The MD Global Object - Establishing/Extending - Extending Global Objects - Global Utility Functions */ /* /////////////////////////////////////////////////////////////// The MD Global Object - Establishing/Extending *///////////////////////////////////////////////////////////////// var MD = MD || {}; // Global toggle system for debug console messaging... MD.Debug = true; // Prevent evil browsers that don't support 'console' from bombing... if (typeof console === 'undefined' || MD.Debug == false) { window.console = {}; console.log = console.info = console.warn = console.group = console.groupEnd = console.error = function(){}; } if (!MD.Debug) { window.onerror = function(message, url, line) { return true; }; } // Generic function for setting the contents of a container. Accepts 'string', 'element', 'array', 'elements', and 'object' types. MD.setContent = function(content, container, contentProperties) { if (content) { switch (typeOf(content)){ case 'string': if (contentProperties) { container.grab(new Element('span', Object.merge(contentProperties,{html: content}))); } else { container.grab(new Element('span', {html: content})); } break; case 'element': if (contentProperties) { container.grab(content.setProperties(contentProperties)); } else { container.grab(content); } break; case 'array': case 'elements': content.each(function(el) { MD.setContent(el, container, contentProperties); }); break; case 'object': if (content.content) { MD.setContent(content.content, container, (content.properties || contentProperties)); } else { console.error('Cannot set content. ".content" property is not valid:', content); } break; default: console.error('Cannot set content. Content type ('+typeOf(content)+') is not valid:', content); } } else { console.error('No content passed to MD.setContent. Arguments:',arguments); } }; // Timer functions for testing/debugging/optimization MD.startTimer = function(){ var timerID = String.uniqueID(); var timerStartTime = new Date(); var thisTimer = { id: timerID ,startTime: timerStartTime }; MD.timers = (MD.timers || []); MD.timers.push(thisTimer); return thisTimer; }; MD.stopTimer = function(timer){ var timerReturn = {}; if (!timer || !MD.timers) { timerReturn = null; } else { var eraseIndex = null; MD.timers.each(function(t, index) { if (t.id == timer.id) { timerReturn = t; var timerEndTime = new Date(); // t.stopTime = timerReturn.stopTime = timerEndTime; t.elapsedTime = timerReturn.elapsedTime = t.startTime.diff(timerEndTime, 'ms'); eraseIndex = index; } else { // timerReturn.stopTime = null; timerReturn.elaspedTime = -1; } }); if (eraseIndex != null) MD.timers.splice(eraseIndex,1); } return timerReturn.elaspedTime; }; /* /////////////////////////////////////////////////////////////// Extending Native Objects *///////////////////////////////////////////////////////////////// // Array Remove - By John Resig (MIT Licensed) Array.prototype.remove = function(from, to) { var rest = this.slice((to || from) + 1 || this.length); this.length = from < 0 ? this.length + from : from; return this.push.apply(this, rest); }; // Array Unique-ify-er Array.prototype.unique = function() { var o = {}, i, l = this.length, r = []; for(i=0; i b[property]) ? 1 : 0; }); } else if (order == ('dsc' || 'descending')) { r = this.sort(function (a,b) { return (a[property] < b[property]) ? 1 : (a[property] > b[property]) ? -1 : 0; }); } return r; } else { r = this.sort(function (a,b) { return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; }); return r; } }; // A 'hashchange' event to give MooTools support for this event. Element.Events.hashchange = { onAdd: function(){ var hash = self.location.hash; var hashchange = function(){ if (hash == self.location.hash) return; else hash = self.location.hash; var value = (hash.indexOf('#') == 0 ? hash.substr(1) : hash); window.fireEvent('hashchange', value); document.fireEvent('hashchange', value); }; if ("onhashchange" in window){ window.onhashchange = hashchange; } else { hashchange.periodical(50); } } }; // A 'clickout' event that can be assigned to elements, which is fired when any OTHER element is clicked. Element.Events.clickout = { base : 'click' ,condition : function(event){ event.stopPropagation(); return false; } ,onAdd : function(fn){ this.getDocument().addEvent('click', fn); } ,onRemove : function(fn){ this.getDocument().removeEvent('click', fn); } }; // Modifies the .highlight() MooTools method to include a 'pauseLength' parameter... so that it doesn't happen so bloody fast. Element.implement({ highlight: function(start, end, pauseLength, cssProperty){ cssProperty = (cssProperty ? cssProperty : 'background-color'); if (pauseLength == '') { pauseLength = 0; } if (!end){ end = this.retrieve('highlight:original', this.getStyle(cssProperty)); end = (end == 'transparent' ? '#fff' : end); } var tween = this.get('tween'); tween.start(cssProperty, start || '#ffff88').chain( function(){ (function(){this.tween(cssProperty, end);}.bind(this)).delay(pauseLength); }.bind(this) ,function(){ this.setStyle(cssProperty, this.retrieve('highlight:original')); }.bind(this) ); return this; } // MooTools bug fix for IE. ,getComputedStyle: function(property){ if (this.currentStyle) return this.currentStyle[property.camelCase()]; var defaultView = this.getDocument().defaultView; var computed = defaultView && defaultView.getComputedStyle(this, null); return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; } }); // To make sure requests never get cached Request.implement({options: {noCache: true}}); /* A nice parser for being able to handle TIME values from SQL... To use the following: var someTime = Date.parseSqlTime('14:00:00'); <--- passing in a [time] string from SQL // someTime is now '2:30PM' */ Date.parseSqlTime = function(sqlTime){ return new Date(Date.parse(sqlTime)).format('%l:%M%p'); }; Date.parseSqlDateTime = function(dateAndTime) { // dateAndTime must be formatted like this 2012-04-01T12:00:00 if (dateAndTime.contains('T')) { var date = new Date(Date.parse(dateAndTime.split('T')[0])).format('%b %e, %Y'); var time = dateAndTime.split('T')[1].contains('.') ? dateAndTime.split('T')[1].split('.')[0] : dateAndTime.split('T')[1]; time = new Date(Date.parse(time)).format('%l:%M%p'); return {date: date, time: time}; } else { return 'Date input not formated correctly.'; } }; /* script: String.Inflections.js name: String Inflections author: - Ryan Florence requires: - Core:1.2.4/String - Core:1.2.4/Number provides: - String.camelize "active_record".camelize(2); --> "ActiveRecord" ... "post_category".camelize(true); --> "postCategory" - String.classify "egg_and_hams".classify(); --> "EggAndHam" .... "posts".classify(); --> "Post" - String.dasherize "puni_puni".dasherize(); --> "puni-puni" ... "puni puni".dasherize(); --> "puni-puni" - String.foreign_key "Message".foreign_key(); // "message_id" ... "Message".foreign_key(false); // "messageid" - String.humanize "employee_salary".humanize(); // "Employee salary" ... "author_id".humanize(); // "Author" - String.ordinalize "1".ordinalize(); // "1st" ... "3".ordinalize(); // "3rd" ... "24".ordinalize(); // "24th" - String.pluralize "post".pluralize(); // "posts" ... "sheep".pluralize(); // "sheep" ... "matrix".pluralize(); // "matrices" - String.singularize "posts".singularize(); // "post" ... "octopi".singularize(); // "octopus" ... "CamelOctopi".singularize(); // "CamelOctopus" - String.tableize "RawScaledScorer".tableize(); // "raw_scaled_scorers" ... "egg_and_ham".tableize(); // "egg_and_hams" ... "fancyCategory".tableize(); // "fancy_categories" - String.titleize "man from the boondocks".titleize(); // "Man From the Boondocks" ... "x-men: the last stand".titleize(); // "X Men: The Last Stand" - String.underscore "ActiveRecord".underscore(); // "active_record" - String.capitalizeFirst "hello my name is Simon".capitalizeFirst(); // "Hello my name is Simon" - String.lowercaseFirst "Hello my name is Simon".lowercaseFirst(); // "hello my name is Simon" - Number.ordinalize 1.ordinalize(); // "1st" ... 3.ordinalize(); // "3rd" ... 24.ordinalize(); // "24th" - String.decamelize "SomethingCamelCase".decamelize() // "Something Camel Case" */ (function(){ var plurals = [ [/(quiz)$/i, '$1zes' ], [/^(ox)$/i, '$1en' ], [/([m|l])ouse$/i, '$1ice' ], [/(matr|vert|ind)ix|ex$/i, '$1ices' ], [/(x|ch|ss|sh)$/i, '$1es' ], [/([^aeiouy]|qu)y$/i, '$1ies' ], [/(hive)$/i, '$1s' ], [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'], [/sis$/i, 'ses' ], [/([ti])um$/i, '$1a' ], [/(buffal|tomat)o$/i, '$1oes' ], [/(bu)s$/i, '$1ses' ], [/(alias|status)$/i, '$1es' ], [/(octop|vir)us$/i, '$1i' ], [/(ax|test)is$/i, '$1es' ], [/s$/i, 's' ], [/$/, 's' ] ] ,singulars = [ [/(database)s$/i, '$1' ], [/(quiz)zes$/i, '$1' ], [/(matr)ices$/i, '$1ix' ], [/(vert|ind)ices$/i, '$1ex' ], [/^(ox)en/i, '$1' ], [/(alias|status)es$/i, '$1' ], [/(octop|vir)i$/i, '$1us' ], [/(cris|ax|test)es$/i, '$1is' ], [/(shoe)s$/i, '$1' ], [/(o)es$/i, '$1' ], [/(bus)es$/i, '$1' ], [/([m|l])ice$/i, '$1ouse' ], [/(x|ch|ss|sh)es$/i, '$1' ], [/(m)ovies$/i, '$1ovie' ], [/(s)eries$/i, '$1eries'], [/([^aeiouy]|qu)ies$/i, '$1y' ], [/([lr])ves$/i, '$1f' ], [/(tive)s$/i, '$1' ], [/(hive)s$/i, '$1' ], [/([^f])ves$/i, '$1fe' ], [/(^analy)ses$/i, '$1sis' ], [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '$1$2sis'], [/([ti])a$/i, '$1um' ], [/(n)ews$/i, '$1ews' ], [/s$/i, '' ] ] ,irregulars = [ ['cow', 'kine' ], ['move', 'moves' ], ['sex', 'sexes' ], ['child', 'children'], ['man', 'men' ], ['person', 'people' ] ] ,uncountables = [ 'sheep', 'fish', 'series', 'species', 'money', 'rice', 'information', 'equipment', 'jeans' ]; String.implement({ camelize: function(lower) { var str = this.replace(/_\D/g, function(match) { return match.charAt(1).toUpperCase(); }); return (lower) ? str: str.capitalize(); }, classify: function() { return this.singularize().camelize(); }, dasherize: function() { return this.replace('_', '-').replace(/ +/, '-'); }, foreign_key: function(dontUnderScoreId) { return this.underscore() + (dontUnderScoreId ? 'id': '_id'); }, humanize: function() { return this.replace(/_id$/, '').replace(/_/gi, ' ').capitalizeFirst(); }, ordinalize: function() { var parsed = parseInt(this); if (11 <= parsed % 100 && parsed % 100 <= 13) { return this + "th"; } else { switch (parsed % 10) { case 1: return this + "st"; case 2: return this + "nd"; case 3: return this + "rd"; default: return this + "th"; } } }, pluralize: function(count) { if (count && parseInt(count) == 1) return this; for (var i = 0; i < uncountables.length; i++) { var uncountable = uncountables[i]; if (this.toLowerCase() == uncountable) { return uncountable; } } for (var i = 0; i < irregulars.length; i++) { var singular = irregulars[i][0]; var plural = irregulars[i][1]; if ((this.toLowerCase() == singular) || (this == plural)) { return plural; } } for (var i = 0; i < plurals.length; i++) { var regex = plurals[i][0]; var replace_string = plurals[i][1]; if (regex.test(this)) { return this.replace(regex, replace_string); } } }, singularize: function() { for (var i = 0; i < uncountables.length; i++) { var uncountable = uncountables[i]; if (this.toLowerCase() == uncountable) { return uncountable; } } for (var i = 0; i < irregulars.length; i++) { var singular = irregulars[i][0]; var plural = irregulars[i][1]; if ((this.toLowerCase() == singular) || (this == plural)) { return singular; } } for (var i = 0; i < singulars.length; i++) { var regex = singulars[i][0]; var replace_string = singulars[i][1]; if (regex.test(this)) { return this.replace(regex, replace_string); } } }, tableize: function() { return this.underscore().pluralize(); }, titleize: function() { return this.replace(/\b[a-z]/g, function(match) { return (match.charAt(0).toUpperCase()); }); }, underscore: function() { var temp = this.replace('-', '_').replace(/\B[A-Z](?=[a-z])/g, function(match) { return ('_' + match.charAt(0)); }); temp = temp.reverse().replace(/[A-Z](?=[a-z])/g, function(match) { return (match.charAt(0) + '_'); }).reverse(); return temp; }, capitalizeFirst: function() { return this.charAt(0).toUpperCase() + this.slice(1); }, lowercaseFirst: function() { return this.charAt(0).toLowerCase() + this.slice(1); } // added by Ben :) ,decamelize: function() { return this.underscore().humanize().titleize(); } ,reverse: function() { return this.split('').reverse().join(''); } }); Number.implement({ ordinalize: function(){ return this + ''.ordinalize(); } }); })(); /* END - String.Inflections.js */ /* /////////////////////////////////////////////////////////////// Global Utility Functions *///////////////////////////////////////////////////////////////// /* A utility function for determining the width of the scrollbars within the viewing environment */ function getBrowserScrollBarWidth() { var innerElement = new Element('p', {styles: {width:'100%', height:200}}); var outerElement = new Element('div', { styles: { position:'absolute' ,top:0 ,left:0 ,visibility: 'hidden' ,width:200 ,height:150 ,overflow:'hidden' } }); // strange WebKit hack because we use "fancy" custom WebKit scrollbars... if (Browser.safari || Browser.chrome) { outerElement.setStyle('opacity', 0); outerElement.setStyle('visibility', 'visible'); } var docBody = $$('body')[0]; docBody.grab(outerElement.grab(innerElement)); var w1 = outerElement.clientWidth; outerElement.setStyle('overflow', 'scroll'); var w2 = outerElement.clientWidth; outerElement.destroy(); return (w1 - w2); };