├── .gitignore ├── bower.json ├── test ├── index.html ├── nice-greeter.js └── tests.js ├── package.json ├── README.md └── jquery-bridget.js /.gitignore: -------------------------------------------------------------------------------- 1 | components/ 2 | bower_components/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-bridget", 3 | "main": "jquery-bridget.js", 4 | "description": "Bridget makes jQuery widgets", 5 | "dependencies": { 6 | "jquery": ">=1.4.2 <4" 7 | }, 8 | "devDependencies": {}, 9 | "homepage": "https://github.com/desandro/jquery-bridget", 10 | "authors": [ 11 | "David DeSandro " 12 | ], 13 | "moduleType": [ 14 | "globals", 15 | "node" 16 | ], 17 | "keywords": [ 18 | "jquery", 19 | "plugin", 20 | "widget" 21 | ], 22 | "license": "MIT", 23 | "ignore": [ 24 | "**/.*", 25 | "node_modules", 26 | "bower_components", 27 | "test", 28 | "tests", 29 | "package.json" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Bridget tests 7 | 8 | 9 | 20 | 21 | 22 | 23 | 24 |

Bridget tests

25 | 26 |
27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-bridget", 3 | "version": "3.0.1", 4 | "description": "Bridget makes jQuery widgets", 5 | "main": "jquery-bridget.js", 6 | "dependencies": { 7 | "jquery": ">=1.4.2 <4" 8 | }, 9 | "devDependencies": { 10 | "eslint": "^7.16.0", 11 | "eslint-plugin-metafizzy": "^1.2.1", 12 | "qunit": "^2.13.0" 13 | }, 14 | "directories": { 15 | "test": "test" 16 | }, 17 | "scripts": { 18 | "lint": "npx eslint .", 19 | "test": "npm run lint && echo \"View test/ in browser\"" 20 | }, 21 | "eslintConfig": { 22 | "plugins": [ 23 | "metafizzy" 24 | ], 25 | "extends": "plugin:metafizzy/base", 26 | "parserOptions": { 27 | "ecmaVersion": 2018 28 | }, 29 | "env": { 30 | "browser": true, 31 | "commonjs": true 32 | }, 33 | "rules": { 34 | "id-length": [ 35 | "error", 36 | { 37 | "min": 2, 38 | "max": 30, 39 | "exceptions": [ 40 | "x", 41 | "y", 42 | "i", 43 | "$" 44 | ] 45 | } 46 | ] 47 | } 48 | }, 49 | "repository": { 50 | "type": "git", 51 | "url": "git://github.com/desandro/jquery-bridget.git" 52 | }, 53 | "keywords": [ 54 | "jquery", 55 | "jquery-plugin" 56 | ], 57 | "author": "David DeSandro", 58 | "license": "MIT", 59 | "bugs": { 60 | "url": "https://github.com/desandro/jquery-bridget/issues" 61 | }, 62 | "homepage": "https://github.com/desandro/jquery-bridget" 63 | } 64 | -------------------------------------------------------------------------------- /test/nice-greeter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NiceGreeter test plugin 3 | */ 4 | 5 | /* globals jQuery */ 6 | 7 | ( function( window, $ ) { 8 | 9 | function NiceGreeter( element, options ) { 10 | this.element = $( element ); 11 | this.options = $.extend( true, {}, this.options, options ); 12 | this._create(); 13 | this._init(); 14 | } 15 | 16 | // defaults for plugin options 17 | NiceGreeter.prototype.options = { 18 | greeting: 'hello', 19 | recipient: 'world', 20 | loudGreeting: 'HEY', 21 | }; 22 | 23 | NiceGreeter.prototype._create = function() { 24 | // initial widget properties 25 | this.helloCount = 0; 26 | this.shoutCount = 0; 27 | }; 28 | 29 | // default logic 30 | // $elem.niceGreeter() 31 | NiceGreeter.prototype._init = function() { 32 | this.sayHi(); 33 | }; 34 | 35 | // enable plugin methods 36 | // $elem.myPluginWidget( 'sayHi', 'Bridget, darling' ); 37 | NiceGreeter.prototype.sayHi = function( recipient ) { 38 | recipient = recipient || this.options.recipient; 39 | this.element.text( this.options.greeting + ' ' + recipient ); 40 | this.helloCount++; 41 | console.log(`Said ${this.options.greeting} ${this.helloCount} times`); 42 | }; 43 | 44 | NiceGreeter.prototype.shout = function( recipient ) { 45 | let greeting = this.options.loudGreeting.toUpperCase(); 46 | recipient = ( recipient || this.options.recipient ).toUpperCase(); 47 | this.element.text( greeting + ' ' + recipient ); 48 | this.shoutCount++; 49 | console.log(`Shouted ${greeting} ${this.shoutCount} times`); 50 | }; 51 | 52 | // private method 53 | NiceGreeter.prototype._whisper = function( message ) { 54 | this.element.text( message ); 55 | }; 56 | 57 | // getter method 58 | NiceGreeter.prototype.getMessage = function() { 59 | return this.options.greeting + ' ' + this.options.recipient; 60 | }; 61 | 62 | window.NiceGreeter = NiceGreeter; 63 | 64 | } )( window, jQuery ); 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bridget makes jQuery plugins 2 | 3 | Bridget makes a jQuery plugin out of a constructor :factory: 4 | 5 | It's based off of the [jQuery UI widget factory](https://jqueryui.com/widget/). Used for [Masonry](https://masonry.desandro.com), [Isotope](https://isotope.metafizzy.co), [Packery](https://packery.metafizzy.co), [Flickity](https://flickity.metafizzy.co), [Infinite Scroll](https://infinite-scroll.com), and [Draggabilly](https://draggabilly.desandro.com). 6 | 7 | ## Plugin constructor 8 | 9 | A plugin constructor uses Prototypal pattern. It needs to have a `._init()` method used for its main logic. 10 | 11 | ``` js 12 | // plugin constructor 13 | // accepts two argments, element and options object 14 | function NiceGreeter( element, options ) { 15 | this.element = $( element ); 16 | this.options = $.extend( true, {}, this.options, options ); 17 | this._init(); 18 | } 19 | // defaults for plugin options 20 | NiceGreeter.prototype.options = { 21 | greeting: 'hello', 22 | recipient: 'world' 23 | }; 24 | // main plugin logic 25 | NiceGreeter.prototype._init = function() { 26 | var message = this.getMessage(); 27 | this.element.text( message ); 28 | }; 29 | // getter method 30 | NiceGreeter.prototype.getMessage = function() { 31 | return this.options.greeting + ' ' + this.options.recipient; 32 | }; 33 | ``` 34 | 35 | ## Usage 36 | 37 | Bridget can make this constructor work as a jQuery plugin. The `namespace` is the plugin method - `$elem.namespace()`. 38 | 39 | ``` js 40 | // convert constructor to jQuery plugin 41 | jQueryBridget( 'niceGreeter', NiceGreeter ); 42 | // optional: pass in jQuery variable 43 | jQueryBridget( 'niceGreeter', NiceGreeter, jQuery ); 44 | 45 | // now the constructor can be used as a jQuery plugin 46 | var $elem = $('#elem'); 47 | $elem.niceGreeter(); 48 | // >> h1 text will be 'hello world' 49 | 50 | // set options 51 | $elem.niceGreeter({ 52 | greeting: 'bonjour', 53 | recipient: 'mon ami' 54 | }); 55 | // >> text will be 'bonjour mon ami' 56 | 57 | // access constructor instance via .data() 58 | var myGreeter = $elem.data('niceGreeter'); 59 | ``` 60 | 61 | Getter methods can still be used. For jQuery objects with multiple elements, getter methods will return the value of the first element. 62 | 63 | ## Package managers 64 | 65 | Install with npm `npm install jquery-bridget` 66 | 67 | Install with Yarn `yarn add jquery-bridget` 68 | 69 | ## MIT license 70 | 71 | Bridget is released under the [MIT license](https://desandro.mit-license.org). 72 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bridget tests 3 | */ 4 | 5 | /* globals jQueryBridget, QUnit */ 6 | 7 | ( function( window, $ ) { 8 | 9 | // -------------------------- tests -------------------------- // 10 | 11 | jQueryBridget( 'niceGreeter', window.NiceGreeter ); 12 | 13 | QUnit.test( 'niceGreeter on dummy element', function( assert ) { 14 | assert.ok( $.fn.niceGreeter, 'plugin added to jQuery namespace, $.fn.niceGreeter' ); 15 | let $div = $('
'); 16 | assert.ok( $div.niceGreeter, '.niceGreeter method is there' ); 17 | $div.niceGreeter(); 18 | assert.equal( typeof $div.data('niceGreeter'), 'object', 19 | 'instance accessible in .data()' ); 20 | } ); 21 | 22 | QUnit.test( 'niceGreeter', function( assert ) { 23 | let $ex1 = $('#ex1'); 24 | $ex1.niceGreeter(); 25 | let greeter = $ex1.data('niceGreeter'); 26 | assert.equal( typeof $ex1.data('niceGreeter'), 'object', 27 | 'instance accessible in .data()' ); 28 | assert.equal( $ex1.text(), 'hello world', 'default settings' ); 29 | // method with argument 30 | $ex1.niceGreeter( 'sayHi', 'pretty boy' ); 31 | assert.equal( $ex1.text(), 'hello pretty boy', 'sayHi method with argument' ); 32 | // option setter 33 | let ret = $ex1.niceGreeter( 'option', { greeting: 'bonjour' } ); 34 | assert.equal( ret, $ex1, 'return value of method is jQuery object' ); 35 | ret.niceGreeter(); 36 | assert.equal( greeter.options.greeting, 'bonjour', 37 | 'greeter.options.greeting = bonjour' ); 38 | assert.equal( $ex1.text(), 'bonjour world', 'option setter' ); 39 | // method 40 | $ex1.niceGreeter({ loudGreeting: 'well hi there' }); 41 | $ex1.niceGreeter('shout'); 42 | assert.equal( $ex1.text(), 'WELL HI THERE WORLD', 'shout method with argument' ); 43 | // private method _whisper 44 | $ex1.niceGreeter( '_whisper', 'sweet nothings' ); 45 | assert.notEqual( $ex1.text(), 'sweet nothings', 46 | 'private method _whisper is private' ); 47 | 48 | // set second instance 49 | let $ex2 = $('#ex2').niceGreeter({ 50 | greeting: 'aloha', 51 | recipient: 'uncle', 52 | }); 53 | let greeter2 = $ex2.data('niceGreeter'); 54 | let $examples = $('.example'); 55 | // method on multiple instances 56 | $examples.niceGreeter( 'option', { 57 | loudGreeting: 'yaaarg', 58 | } ); 59 | assert.equal( greeter.options.loudGreeting, 'yaaarg', 'first greeter method worked' ); 60 | assert.equal( greeter2.options.loudGreeting, 'yaaarg', 61 | 'second greeter method worked' ); 62 | // getter method 63 | let message = $examples.niceGreeter('getMessage'); 64 | assert.equal( message, 'bonjour world', 'getter method returns first value' ); 65 | } ); 66 | 67 | QUnit.test( 'jQueryBridget', function( assert ) { 68 | jQueryBridget( 'noopPlugin', function() {} ); 69 | assert.ok( $.fn.noopPlugin, 'jQueryBridget()' ); 70 | } ); 71 | 72 | } )( window, window.jQuery ); 73 | -------------------------------------------------------------------------------- /jquery-bridget.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bridget makes jQuery widgets 3 | * v3.0.1 4 | * MIT license 5 | */ 6 | 7 | ( function( window, factory ) { 8 | // module definition 9 | if ( typeof module == 'object' && module.exports ) { 10 | // CommonJS 11 | module.exports = factory( 12 | window, 13 | require('jquery'), 14 | ); 15 | } else { 16 | // browser global 17 | window.jQueryBridget = factory( 18 | window, 19 | window.jQuery, 20 | ); 21 | } 22 | 23 | }( window, function factory( window, jQuery ) { 24 | 25 | // ----- utils ----- // 26 | 27 | // helper function for logging errors 28 | // $.error breaks jQuery chaining 29 | let console = window.console; 30 | let logError = typeof console == 'undefined' ? function() {} : 31 | function( message ) { 32 | console.error( message ); 33 | }; 34 | 35 | // ----- jQueryBridget ----- // 36 | 37 | function jQueryBridget( namespace, PluginClass, $ ) { 38 | $ = $ || jQuery || window.jQuery; 39 | if ( !$ ) { 40 | return; 41 | } 42 | 43 | // add option method -> $().plugin('option', {...}) 44 | if ( !PluginClass.prototype.option ) { 45 | // option setter 46 | PluginClass.prototype.option = function( opts ) { 47 | if ( !opts ) return; 48 | 49 | this.options = Object.assign( this.options || {}, opts ); 50 | }; 51 | } 52 | 53 | // make jQuery plugin 54 | $.fn[ namespace ] = function( arg0, ...args ) { 55 | if ( typeof arg0 == 'string' ) { 56 | // method call $().plugin( 'methodName', { options } ) 57 | return methodCall( this, arg0, args ); 58 | } 59 | // just $().plugin({ options }) 60 | plainCall( this, arg0 ); 61 | return this; 62 | }; 63 | 64 | // $().plugin('methodName') 65 | function methodCall( $elems, methodName, args ) { 66 | let returnValue; 67 | let pluginMethodStr = `$().${namespace}("${methodName}")`; 68 | 69 | $elems.each( function( i, elem ) { 70 | // get instance 71 | let instance = $.data( elem, namespace ); 72 | if ( !instance ) { 73 | logError( `${namespace} not initialized.` + 74 | ` Cannot call method ${pluginMethodStr}` ); 75 | return; 76 | } 77 | 78 | let method = instance[ methodName ]; 79 | if ( !method || methodName.charAt( 0 ) == '_' ) { 80 | logError(`${pluginMethodStr} is not a valid method`); 81 | return; 82 | } 83 | 84 | // apply method, get return value 85 | let value = method.apply( instance, args ); 86 | // set return value if value is returned, use only first value 87 | returnValue = returnValue === undefined ? value : returnValue; 88 | } ); 89 | 90 | return returnValue !== undefined ? returnValue : $elems; 91 | } 92 | 93 | function plainCall( $elems, options ) { 94 | $elems.each( function( i, elem ) { 95 | let instance = $.data( elem, namespace ); 96 | if ( instance ) { 97 | // set options & init 98 | instance.option( options ); 99 | instance._init(); 100 | } else { 101 | // initialize new instance 102 | instance = new PluginClass( elem, options ); 103 | $.data( elem, namespace, instance ); 104 | } 105 | } ); 106 | } 107 | 108 | } 109 | 110 | // ----- ----- // 111 | 112 | return jQueryBridget; 113 | 114 | } ) ); 115 | --------------------------------------------------------------------------------