├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── Gruntfile.js
├── demo
├── chili-1.8.js
├── images
│ ├── 1.gif
│ ├── 2.gif
│ ├── 3.gif
│ ├── bg.gif
│ ├── external.png
│ └── jq.png
├── index.html
├── jq.css
└── tabs.css
├── jquery.expander.js
├── jquery.expander.min.js
├── license.txt
├── package.json
├── readme.md
├── test
├── index.html
├── jquery.1.11.3.js
└── tests.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; This file is for unifying the coding style for different editors and IDEs.
2 | ; More information at http://EditorConfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | end_of_line = LF
8 |
9 | [*.js]
10 | indent_style = space
11 | indent_size = 2
12 |
13 | [demo/*.html]
14 | indent_style = space
15 | indent_size = 2
16 |
17 | [*.json]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | [/test/qunit/*]
22 | indent_style = tab
23 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'kswedberg/es5',
3 | rules: {
4 | 'comma-dangle': ['warn', 'never'],
5 | 'no-param-reassign': 'off',
6 | 'newline-per-chained-call': 'off',
7 | 'no-use-before-define': ['error', {functions: false}],
8 | 'func-style': 'off'
9 | },
10 | globals: {
11 | define: false
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | lib/*
3 | /index.html
4 | node_modules
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | gitignore
2 | test
3 | demo
4 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | var versionedFiles = [
3 | 'package.json',
4 | 'jquery.<%= pluginName %>.js'
5 | ];
6 |
7 | var lintedFiles = [
8 | 'Gruntfile.js',
9 | 'jquery.expander.js',
10 | 'test/tests.js'
11 | ];
12 | var semv = ['patch', 'minor', 'major'];
13 | var versions = {
14 | same: {
15 | src: versionedFiles
16 | }
17 | };
18 |
19 | semv.forEach(function(v) {
20 | versions[v] = {
21 | src: versionedFiles,
22 | options: {
23 | release: v
24 | }
25 | };
26 | versions[v + 'Banner'] = {
27 | src: ['jquery.<%= pluginName %>.js'],
28 | options: {
29 | prefix: '- v',
30 | release: v
31 | }
32 | };
33 | });
34 | // Project configuration.
35 | grunt.initConfig({
36 | pluginName: 'expander',
37 | bower: './bower.json',
38 | pkg: grunt.file.readJSON('package.json'),
39 | meta: {
40 | banner: '/*!<%= "\\n" %>' +
41 | ' * <%= pkg.title %> - v<%= pkg.version %> - ' +
42 | '<%= grunt.template.today("yyyy-mm-dd") + "\\n" %>' +
43 | '<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
44 | ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>' +
45 | '<%= "\\n" %>' +
46 | ' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>' +
47 | ' (<%= _.pluck(pkg.licenses, "url").join(", ") %>)' +
48 | '<%= "\\n" %>' + ' */' +
49 | '<%= "\\n\\n" %>'
50 | },
51 | // concat: {
52 | // all: {
53 | // src: ['src/jquery.<%= pluginName %>.js'],
54 | // dest: 'jquery.<%= pluginName %>.js'
55 | // },
56 | // options: {
57 | // stripBanners: true,
58 | // banner: '<%= meta.banner %>',
59 | // process: function(src) {
60 | // var umdHead = grunt.file.read('lib/tmpl/umdhead.tpl'),
61 | // umdFoot = grunt.file.read('lib/tmpl/umdfoot.tpl');
62 |
63 | // src = src
64 | // .replace('(function($) {', umdHead)
65 | // .replace('})(jQuery);', umdFoot);
66 |
67 | // return src;
68 | // }
69 | // }
70 | // },
71 | uglify: {
72 | all: {
73 | files: {
74 | 'jquery.<%= pluginName %>.min.js': ['jquery.<%= pluginName %>.js']
75 | },
76 | options: {
77 | preserveComments: 'some'
78 | }
79 | }
80 | },
81 | watch: {
82 | scripts: {
83 | files: lintedFiles,
84 | tasks: ['eslint', 'qunit']
85 | }
86 | },
87 | eslint: {
88 | target: lintedFiles
89 | },
90 | qunit: {
91 | all: ['test/*.html']
92 | },
93 | version: versions
94 | });
95 |
96 | grunt.registerTask('test', ['eslint', 'qunit']);
97 | grunt.registerTask('build', ['test', 'version:same', 'uglify']);
98 |
99 | // Register grunt major, grunt minor, and grunt patch
100 | semv.forEach(function(v) {
101 | grunt.registerTask(v, ['version:' + v + 'Banner', 'version:' + v, 'uglify']);
102 | });
103 | grunt.registerTask('default', ['build']);
104 |
105 | grunt.loadNpmTasks('grunt-contrib-uglify');
106 | grunt.loadNpmTasks('grunt-contrib-concat');
107 | grunt.loadNpmTasks('grunt-contrib-watch');
108 | grunt.loadNpmTasks('grunt-contrib-qunit');
109 | grunt.loadNpmTasks('grunt-eslint');
110 | grunt.loadNpmTasks('grunt-version');
111 |
112 | };
113 |
--------------------------------------------------------------------------------
/demo/chili-1.8.js:
--------------------------------------------------------------------------------
1 | /*
2 | ===============================================================================
3 | Chili is the jQuery code highlighter plugin
4 | ...............................................................................
5 | Copyright 2007 / Andrea Ercolino
6 | -------------------------------------------------------------------------------
7 | LICENSE: http://www.opensource.org/licenses/mit-license.php
8 | WEBSITE: http://noteslog.com/chili/
9 | ===============================================================================
10 |
11 | ===============================================================================
12 | Metaobjects is the jQuery metadata plugin on steroids
13 | ...............................................................................
14 | Copyright 2007 / Andrea Ercolino
15 | -------------------------------------------------------------------------------
16 | LICENSE: http://www.opensource.org/licenses/mit-license.php
17 | WEBSITE: http://noteslog.com/metaobjects/
18 | ===============================================================================
19 | */
20 |
21 | //-----------------------------------------------------------------------------
22 | ( function($) {
23 |
24 | ChiliBook = { //implied global
25 |
26 | version: "1.8" // 2007-05-13
27 |
28 | , automatic: true
29 | , automaticSelector: "code"
30 |
31 | , codeLanguage: function( el ) {
32 | var recipeName = $( el ).attr( "class" );
33 | return recipeName ? recipeName : '';
34 | }
35 |
36 | , metadataSelector: "object.chili"
37 |
38 | , recipeLoading: false
39 | , recipeFolder: "" // used like: recipeFolder + recipeName + '.js'
40 | , stylesheetLoading: false
41 | , stylesheetFolder: "" // used like: stylesheetFolder + recipeName + '.css'
42 |
43 | , defaultReplacement: '$$'
44 |
45 | , replaceSpace: " " // use an empty string for not replacing
46 | , replaceTab: " " // use an empty string for not replacing
47 | //, replaceNewLine: "
" // use an empty string for not replacing
48 | , replaceNewLine: null // use an empty string for not replacing
49 |
50 | , recipes: {} //repository
51 | , queue: {} //register
52 |
53 | //fix for IE: copy of PREformatted text strips off all html, losing newlines
54 | , preFixCopy: document.selection && document.selection.createRange
55 | , preContent: ""
56 | , preElement: null
57 | };
58 |
59 |
60 | $.metaobjects = function( options ) {
61 |
62 | options = $.extend( {
63 | context: document
64 | , clean: true
65 | , selector: 'object.metaobject'
66 | }, options );
67 |
68 | function jsValue( value ) {
69 | eval( 'value = ' + value + ";" );
70 | return value;
71 | }
72 |
73 | return $( options.selector, options.context )
74 | .each( function() {
75 |
76 | var settings = { target: this.parentNode };
77 | $( '> param[name="metaparam"]', this )
78 | .each( function() {
79 | $.extend( settings, jsValue( this.value ) );
80 | } );
81 |
82 | $( '> param', this )
83 | .not( '[name="metaparam"]' )
84 | .each( function() {
85 | var name = this.name, value = jsValue( this.value );
86 | $( settings.target )
87 | .each( function() {
88 | this[ name ] = value;
89 | } );
90 | } );
91 |
92 | if( options.clean ) {
93 | $( this ).remove();
94 | }
95 | } );
96 | };
97 |
98 | $.fn.chili = function( options ) {
99 | var book = $.extend( {}, ChiliBook, options || {} );
100 |
101 | function cook( ingredients, recipe ) {
102 |
103 | function prepareStep( stepName, step ) {
104 | var exp = ( typeof step.exp == "string" ) ? step.exp : step.exp.source;
105 | steps.push( {
106 | stepName: stepName,
107 | exp: "(" + exp + ")",
108 | length: 1 // add 1 to account for the newly added parentheses
109 | + (exp // count number of submatches in here
110 | .replace( /\\./g, "%" ) // disable any escaped character
111 | .replace( /\[.*?\]/g, "%" ) // disable any character class
112 | .match( /\((?!\?)/g ) // match any open parenthesis, not followed by a ?
113 | || [] // make sure it is an empty array if there are no matches
114 | ).length // get the number of matches
115 | , replacement: (step.replacement) ? step.replacement : book.defaultReplacement
116 | } );
117 | } // function prepareStep( stepName, step )
118 |
119 | function knowHow() {
120 | var prevLength = 0;
121 | var exps = new Array;
122 | for (var i = 0; i < steps.length; i++) {
123 | var exp = steps[ i ].exp;
124 | // adjust backreferences
125 | exp = exp.replace( /\\\\|\\(\d+)/g, function( m, aNum ) {
126 | return !aNum ? m : "\\" + ( prevLength + 1 + parseInt( aNum, 10 ) );
127 | } );
128 | exps.push( exp );
129 | prevLength += steps[ i ].length;
130 | }
131 | var source = exps.join( "|" );
132 | return new RegExp( source, (recipe.ignoreCase) ? "gi" : "g" );
133 | } // function knowHow()
134 |
135 | function escapeHTML( str ) {
136 | return str.replace( /&/g, "&" ).replace( /'
213 | ;
214 | book.queue[ stylesheetPath ] = true;
215 | if( $.browser.msie ) {
216 | var domLink = document.createElement( link );
217 | var $domLink = $( domLink );
218 | $( "head" ).append( $domLink );
219 | }
220 | else {
221 | $( "head" ).append( link );
222 | }
223 | }
224 | } // function checkCSS( recipeName )
225 |
226 | function makeDish( el, recipePath ) {
227 | var recipe = book.recipes[ recipePath ];
228 | if( recipe ) {
229 | var ingredients = el && el.childNodes && el.childNodes[0] && el.childNodes[0].data;
230 | if( ! ingredients ) {
231 | ingredients = "";
232 | }
233 |
234 | // hack for IE: \r is used instead of \n
235 | ingredients = ingredients.replace(/\r\n?/g, "\n");
236 |
237 | var dish = cook( ingredients, recipe ); // all happens here
238 |
239 | if( book.replaceTab ) {
240 | dish = dish.replace( /\t/g, book.replaceTab );
241 | }
242 | if( book.replaceNewLine ) {
243 | dish = dish.replace( /\n/g, book.replaceNewLine );
244 | }
245 |
246 | $( el ).html( dish );
247 | if( ChiliBook.preFixCopy ) {
248 | $( el )
249 | .parents()
250 | .filter( "pre" )
251 | .bind( "mousedown", function() {
252 | ChiliBook.preElement = this;
253 | } )
254 | .bind( "mouseup", function() {
255 | if( ChiliBook.preElement == this ) {
256 | ChiliBook.preContent = document.selection.createRange().htmlText;
257 | }
258 | } )
259 | ;
260 | }
261 |
262 | }
263 | } // function makeDish( el )
264 |
265 | function getPath( recipeName, options ) {
266 | var settingsDef = {
267 | recipeFolder: book.recipeFolder
268 | , recipeFile: recipeName + ".js"
269 | , stylesheetFolder: book.stylesheetFolder
270 | , stylesheetFile: recipeName + ".css"
271 | };
272 | var settings;
273 | if( options && typeof options == "object" ) {
274 | settings = $.extend( settingsDef, options );
275 | }
276 | else {
277 | settings = settingsDef;
278 | }
279 | return {
280 | recipe : settings.recipeFolder + settings.recipeFile
281 | , stylesheet: settings.stylesheetFolder + settings.stylesheetFile
282 | };
283 | } //function getPath( recipeName, options )
284 |
285 | //-----------------------------------------------------------------------------
286 | // initializations
287 | $.metaobjects( { context: this, selector: book.metadataSelector } );
288 |
289 | //-----------------------------------------------------------------------------
290 | // the coloring starts here
291 | this
292 | .each( function() {
293 | var el = this;
294 | var recipeName = book.codeLanguage( el );
295 | if( '' != recipeName ) {
296 | var path = getPath( recipeName, el.chili );
297 | if( book.recipeLoading || el.chili ) {
298 | /* dynamic setups come here */
299 | if( ! book.queue[ path.recipe ] ) {
300 | /* this is a new recipe to download */
301 | try {
302 | book.queue[ path.recipe ] = [ el ];
303 | $.getJSON( path.recipe, function( recipeLoaded ) {
304 | recipeLoaded.path = path.recipe;
305 | book.recipes[ path.recipe ] = recipeLoaded;
306 | if( book.stylesheetLoading ) {
307 | checkCSS( path.stylesheet );
308 | }
309 | var q = book.queue[ path.recipe ];
310 | for( var i = 0, iTop = q.length; i < iTop; i++ ) {
311 | makeDish( q[ i ], path.recipe );
312 | }
313 | } );
314 | }
315 | catch( recipeNotAvailable ) {
316 | alert( "the recipe for '" + recipeName + "' was not found in '" + path.recipe + "'" );
317 | }
318 | }
319 | else {
320 | /* not a new recipe, so just enqueue this element */
321 | book.queue[ path.recipe ].push( el );
322 | }
323 | /* a recipe could have been already downloaded */
324 | makeDish( el, path.recipe );
325 | }
326 | else {
327 | /* static setups come here */
328 | makeDish( el, path.recipe );
329 | }
330 | }
331 | } );
332 |
333 | return this;
334 | //-----------------------------------------------------------------------------
335 | };
336 |
337 | //main
338 | $( function() {
339 |
340 | if( ChiliBook.automatic ) {
341 | if( ChiliBook.elementPath ) {
342 | //preserve backward compatibility
343 | ChiliBook.automaticSelector = ChiliBook.elementPath;
344 | if( ChiliBook.elementClass ) {
345 | ChiliBook.codeLanguage = function ( el ) {
346 | var selectClass = new RegExp( "\\b" + ChiliBook.elementClass + "\\b", "gi" );
347 | var elClass = $( el ).attr( "class" );
348 | if( ! elClass ) {
349 | return '';
350 | }
351 | var recipeName = $.trim( elClass.replace( selectClass, "" ) );
352 | return recipeName;
353 | };
354 | }
355 | }
356 |
357 | $( ChiliBook.automaticSelector ).chili();
358 | }
359 |
360 | if( ChiliBook.preFixCopy ) {
361 | function preformatted( text ) {
362 | if( '' == text ) {
363 | return "";
364 | }
365 | do {
366 | var newline_flag = (new Date()).valueOf();
367 | }
368 | while( text.indexOf( newline_flag ) > -1 );
369 | text = text.replace( /\
]*?\>/ig, newline_flag );
370 | var el = document.createElement( '
' ); 371 | el.innerHTML = text; 372 | text = el.innerText.replace( new RegExp( newline_flag, "g" ), '\r\n' ); 373 | return text; 374 | } 375 | 376 | $( "body" ) 377 | .bind( "copy", function() { 378 | if( '' != ChiliBook.preContent ) { 379 | window.clipboardData.setData( 'Text', preformatted( ChiliBook.preContent ) ); 380 | event.returnValue = false; 381 | } 382 | } ) 383 | .bind( "mousedown", function() { 384 | ChiliBook.preContent = ""; 385 | } ) 386 | .bind( "mouseup", function() { 387 | ChiliBook.preElement = null; 388 | } ) 389 | ; 390 | } 391 | 392 | } ); 393 | 394 | } ) ( jQuery ); 395 | 396 | ChiliBook.recipes[ "mix.js" ] = { 397 | steps: { 398 | tag : { exp: /(?:\<\w+)|(?:[^-]?\>)|(?:\<\/\w+\>)|(?:\/\>)/ } 399 | , doctype : { exp: /\<\!DOCTYPE([^>]+)?/} 400 | , jscom : { exp: /\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\// } 401 | , htcom : { exp: /\ 115 | 116 |117 |127 | 128 | 129 |Example 3
118 |The Expander Plugin now works for block-level elements, too.
119 |120 | 121 | 125 | 126 |$('div.expander').expander();