/* =============================================================================== Chili is the jQuery code highlighter plugin ............................................................................... Copyright 2007 / Andrea Ercolino ------------------------------------------------------------------------------- LICENSE: http://www.opensource.org/licenses/mit-license.php WEBSITE: http://noteslog.com/chili/ =============================================================================== =============================================================================== Metaobjects is the jQuery metadata plugin on steroids ............................................................................... Copyright 2007 / Andrea Ercolino ------------------------------------------------------------------------------- LICENSE: http://www.opensource.org/licenses/mit-license.php WEBSITE: http://noteslog.com/metaobjects/ =============================================================================== */ //----------------------------------------------------------------------------- ( function($) { ChiliBook = { //implied global version: "1.8b" // 2007-05-26 , automatic: true , automaticSelector: "code" , codeLanguage: function( el ) { var recipeName = $( el ).attr( "class" ); return recipeName ? recipeName : ''; } , metadataSelector: "object.chili" // use an empty string for not executing , recipeLoading: true , recipeFolder: "" // used like: recipeFolder + recipeName + '.js' , stylesheetLoading: true , stylesheetFolder: "" // used like: stylesheetFolder + recipeName + '.css' , defaultReplacement: '<span class="$0">$$</span>' , replaceSpace: " " // use an empty string for not replacing , replaceTab: "    " // use an empty string for not replacing , replaceNewLine: " <br/>" // use an empty string for not replacing , recipes: {} //repository , queue: {} //register //fix for IE: copy of PREformatted text strips off all html, losing newlines , preFixCopy: document.selection && document.selection.createRange , preContent: "" , preElement: null }; $.metaobjects = function( options ) { options = $.extend( { context: document , clean: true , selector: 'object.metaobject' }, options ); function jsValue( value ) { eval( 'value = ' + value + ";" ); return value; } return $( options.selector, options.context ) .each( function() { var settings = { target: this.parentNode }; $( '> param[@name=metaparam]', this ) .each( function() { $.extend( settings, jsValue( this.value ) ); } ); $( '> param', this ) .not( '[@name=metaparam]' ) .each( function() { var name = this.name, value = jsValue( this.value ); $( settings.target ) .each( function() { this[ name ] = value; } ); } ); if( options.clean ) { $( this ).remove(); } } ); }; $.fn.chili = function( options ) { var book = $.extend( {}, ChiliBook, options || {} ); function cook( ingredients, recipe ) { function prepareStep( stepName, step ) { var exp = ( typeof step.exp == "string" ) ? step.exp : step.exp.source; steps.push( { stepName: stepName , exp: "(" + exp + ")" , length: 1 // add 1 to account for the newly added parentheses + (exp // count number of submatches in here .replace( /\\./g, "%" ) // disable any escaped character .replace( /\[.*?\]/g, "%" ) // disable any character class .match( /\((?!\?)/g ) // match any open parenthesis, not followed by a ? || [] // make sure it is an empty array if there are no matches ).length // get the number of matches , replacement: (step.replacement) ? step.replacement : book.defaultReplacement } ); } // function prepareStep( stepName, step ) function knowHow() { var prevLength = 0; var exps = new Array; for (var i = 0; i < steps.length; i++) { var exp = steps[ i ].exp; // adjust backreferences exp = exp.replace( /\\\\|\\(\d+)/g, function( m, aNum ) { return !aNum ? m : "\\" + ( prevLength + 1 + parseInt( aNum, 10 ) ); } ); exps.push( exp ); prevLength += steps[ i ].length; } var source = exps.join( "|" ); return new RegExp( source, (recipe.ignoreCase) ? "gi" : "g" ); } // function knowHow() function escapeHTML( str ) { return str.replace( /&/g, "&" ).replace( /</g, "<" ); } // function escapeHTML( str ) function replaceSpaces( str ) { return str.replace( / +/g, function( spaces ) { return spaces.replace( / /g, replaceSpace ); } ); } // function replaceSpaces( str ) function filter( str ) { str = escapeHTML( str ); if( replaceSpace ) { str = replaceSpaces( str ); } return str; } // function filter( str ) function chef( matched ) { var i = 0; // iterate steps var j = 1; // iterate chef's arguments var step; while( step = steps[ i++ ] ) { var aux = arguments; // this unmasks chef's arguments inside the next function if( aux[ j ] ) { var pattern = /(\\\$)|(?:\$\$)|(?:\$(\d+))/g; var replacement = step.replacement .replace( pattern, function( m, escaped, K ) { var bit = ''; if( escaped ) { /* \$ */ return "$"; } else if( !K ) { /* $$ */ return filter( aux[ j ] ); } else if( K == "0" ) { /* $0 */ return step.stepName; } else { /* $K */ return filter( aux[ j + parseInt( K, 10 ) ] ); } } ); var offset = arguments[ arguments.length - 2 ]; var input = arguments[ arguments.length - 1 ]; var unmatched = input.substring( lastIndex, offset ); lastIndex = offset + matched.length; // lastIndex for the next call to chef perfect += filter( unmatched ) + replacement; // use perfect for all the replacing return replacement; } else { j+= step.length; } } } // function chef( matched ) var replaceSpace = book.replaceSpace; var steps = new Array; for( var stepName in recipe.steps ) { prepareStep( stepName, recipe.steps[ stepName ] ); } var perfect = ""; //replace doesn't provide a handle to the ongoing partially replaced string var lastIndex = 0; //regexp.lastIndex is available after a string.match, but not in a string.replace ingredients.replace( knowHow(), chef ); var lastUnmatched = ingredients.substring( lastIndex, ingredients.length ); perfect += filter( lastUnmatched ); return perfect; } // function cook( ingredients, recipe ) function checkCSS( stylesheetPath ) { if( ! book.queue[ stylesheetPath ] ) { var e = document.createElement( "link" ); e.rel = "stylesheet"; e.type = "text/css"; e.href = stylesheetPath; document.getElementsByTagName( "head" )[0].appendChild( e ); book.queue[ stylesheetPath ] = true; } } // function checkCSS( recipeName ) function makeDish( el, recipePath ) { var recipe = book.recipes[ recipePath ]; if( ! recipe ) { return; } var chunks = el && el.childNodes && el.childNodes.length; if( chunks && chunks > 1 ) { return; } var ingredients = el.childNodes[0] && el.childNodes[0].data; if( ! ingredients ) { return; } // hack for IE: \r is used instead of \n ingredients = ingredients.replace(/\r\n?/g, "\n"); var dish = cook( ingredients, recipe ); // all happens here if( book.replaceTab ) { dish = dish.replace( /\t/g, book.replaceTab ); } if( book.replaceNewLine ) { dish = dish.replace( /\n/g, book.replaceNewLine ); } $( el ).html( dish ); if( ChiliBook.preFixCopy ) { $( el ) .parents() .filter( "pre" ) .bind( "mousedown", function() { ChiliBook.preElement = this; } ) .bind( "mouseup", function() { if( ChiliBook.preElement == this ) { ChiliBook.preContent = document.selection.createRange().htmlText; } } ) ; } } // function makeDish( el ) function getPath( recipeName, options ) { var settingsDef = { recipeFolder: book.recipeFolder , recipeFile: recipeName + ".js" , stylesheetFolder: book.stylesheetFolder , stylesheetFile: recipeName + ".css" }; var settings; if( options && typeof options == "object" ) { settings = $.extend( settingsDef, options ); } else { settings = settingsDef; } return { recipe : settings.recipeFolder + settings.recipeFile , stylesheet: settings.stylesheetFolder + settings.stylesheetFile }; } //function getPath( recipeName, options ) //----------------------------------------------------------------------------- // initializations if( book.metadataSelector ) { $.metaobjects( { context: this, selector: book.metadataSelector } ); } //----------------------------------------------------------------------------- // the coloring starts here this .each( function() { var el = this; var recipeName = book.codeLanguage( el ); if( '' != recipeName ) { var path = getPath( recipeName, el.chili ); if( book.recipeLoading || el.chili ) { /* dynamic setups come here */ if( ! book.queue[ path.recipe ] ) { /* this is a new recipe to download */ try { book.queue[ path.recipe ] = [ el ]; $.getJSON( path.recipe, function( recipeLoaded ) { recipeLoaded.path = path.recipe; book.recipes[ path.recipe ] = recipeLoaded; if( book.stylesheetLoading ) { checkCSS( path.stylesheet ); } var q = book.queue[ path.recipe ]; for( var i = 0, iTop = q.length; i < iTop; i++ ) { makeDish( q[ i ], path.recipe ); } } ); } catch( recipeNotAvailable ) { alert( "the recipe for '" + recipeName + "' was not found in '" + path.recipe + "'" ); } } else { /* not a new recipe, so just enqueue this element */ book.queue[ path.recipe ].push( el ); } /* a recipe could have been already downloaded */ makeDish( el, path.recipe ); } else { /* static setups come here */ makeDish( el, path.recipe ); } } } ); return this; //----------------------------------------------------------------------------- }; //main $( function() { if( ChiliBook.automatic ) { if( ChiliBook.elementPath ) { //preserve backward compatibility ChiliBook.automaticSelector = ChiliBook.elementPath; if( ChiliBook.elementClass ) { ChiliBook.codeLanguage = function ( el ) { var selectClass = new RegExp( "\\b" + ChiliBook.elementClass + "\\b", "gi" ); var elClass = $( el ).attr( "class" ); if( ! elClass ) { return ''; } var recipeName = $.trim( elClass.replace( selectClass, "" ) ); return recipeName; }; } } $( ChiliBook.automaticSelector ).chili(); } if( ChiliBook.preFixCopy ) { function preformatted( text ) { if( '' == text ) { return ""; } do { var newline_flag = (new Date()).valueOf(); } while( text.indexOf( newline_flag ) > -1 ); text = text.replace( /\<br[^>]*?\>/ig, newline_flag ); var el = document.createElement( '<pre>' ); el.innerHTML = text; text = el.innerText.replace( new RegExp( newline_flag, "g" ), '\r\n' ); return text; } $( "body" ) .bind( "copy", function() { if( '' != ChiliBook.preContent ) { window.clipboardData.setData( 'Text', preformatted( ChiliBook.preContent ) ); event.returnValue = false; } } ) .bind( "mousedown", function() { ChiliBook.preContent = ""; } ) .bind( "mouseup", function() { ChiliBook.preElement = null; } ) ; } } ); } ) ( jQuery ); // load progress bar myBar.loaded('chili.js');