├── .eslintrc ├── .gitignore ├── .testem.json ├── README.md ├── dist ├── jquery.component.js └── jquery.component.min.js ├── doc └── API.md ├── example ├── basic.html ├── binding.html ├── children.html └── events.html ├── package.json ├── src ├── index.js ├── jquery.bindData.js ├── jquery.component.js └── jquery.events.js └── test ├── browser └── index.html ├── jquery.bindData.js ├── jquery.component.js └── jquery.events.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | }, 5 | "rules": { 6 | "comma-dangle": 1, 7 | "no-cond-assign": 2, 8 | "no-console": 1, 9 | "no-constant-condition": 2, 10 | "no-control-regex": 2, 11 | "no-debugger": 2, 12 | "no-dupe-keys": 2, 13 | "no-empty": 2, 14 | "no-empty-character-class": 2, 15 | "no-ex-assign": 2, 16 | "no-extra-boolean-cast": 2, 17 | "no-extra-parens": 0, 18 | "no-extra-semi": 2, 19 | "no-func-assign": 1, 20 | "no-inner-declarations": 2, 21 | "no-invalid-regexp": 2, 22 | "no-irregular-whitespace": 2, 23 | "no-negated-in-lhs": 2, 24 | "no-obj-calls": 2, 25 | "no-regex-spaces": 2, 26 | "no-reserved-keys": 0, 27 | "no-sparse-arrays": 2, 28 | "no-unreachable": 2, 29 | "use-isnan": 2, 30 | "valid-typeof": 2, 31 | "block-scoped-var": 0, 32 | "complexity": [ 33 | 1, 34 | 10 35 | ], 36 | "consistent-return": 0, 37 | "curly": 0, 38 | "default-case": 0, 39 | "dot-notation": 2, 40 | "eqeqeq": [ 41 | 2, 42 | "smart" 43 | ], 44 | "guard-for-in": 0, 45 | "no-alert": 1, 46 | "no-caller": 2, 47 | "no-div-regex": 2, 48 | "no-else-return": 2, 49 | "no-eq-null": 0, 50 | "no-eval": 1, 51 | "no-extend-native": 1, 52 | "no-extra-bind": 2, 53 | "no-fallthrough": 0, 54 | "no-floating-decimal": 1, 55 | "no-implied-eval": 2, 56 | "no-iterator": 2, 57 | "no-labels": 2, 58 | "no-lone-blocks": 2, 59 | "no-loop-func": 2, 60 | "no-multi-spaces": 2, 61 | "no-multi-str": 2, 62 | "no-native-reassign": 2, 63 | "no-new": 2, 64 | "no-new-func": 2, 65 | "no-new-wrappers": 2, 66 | "no-octal": 2, 67 | "no-octal-escape": 2, 68 | "no-process-env": 0, 69 | "no-proto": 2, 70 | "no-redeclare": 2, 71 | "no-return-assign": 2, 72 | "no-script-url": 2, 73 | "no-self-compare": 2, 74 | "no-sequences": 2, 75 | "no-unused-expressions": 2, 76 | "no-var": 0, 77 | "no-void": 2, 78 | "no-warning-comments": 2, 79 | "no-with": 2, 80 | "no-wrap-func": 0, 81 | "radix": 2, 82 | "vars-on-top": 0, 83 | "wrap-iife": 2, 84 | "yoda": 2, 85 | "global-strict": 0, 86 | "strict": 0, 87 | "no-catch-shadow": 2, 88 | "no-delete-var": 2, 89 | "no-label-var": 2, 90 | "no-shadow": 0, 91 | "no-shadow-restricted-names": 2, 92 | "no-undef": 1, 93 | "no-undef-init": 2, 94 | "no-undefined": 0, 95 | "no-unused-vars": 2, 96 | "no-use-before-define": 0, 97 | "handle-callback-err": 1, 98 | "no-mixed-requires": 0, 99 | "no-new-require": 2, 100 | "no-path-concat": 2, 101 | "no-process-exit": 2, 102 | "no-restricted-modules": 0, 103 | "no-sync": 0, 104 | "brace-style": [ 105 | 1, 106 | "1tbs" 107 | ], 108 | "camelcase": 0, 109 | "comma-spacing": [ 110 | 1, 111 | { 112 | "before": false, 113 | "after": true 114 | } 115 | ], 116 | "comma-style": [ 117 | 1, 118 | "last" 119 | ], 120 | "consistent-this": 0, 121 | "eol-last": 1, 122 | "func-names": 0, 123 | "func-style": 0, 124 | "key-spacing": [ 125 | 1, 126 | { 127 | "beforeColon": false, 128 | "afterColon": true 129 | } 130 | ], 131 | "max-nested-callbacks": 0, 132 | "new-cap": 2, 133 | "new-parens": 2, 134 | "no-array-constructor": 2, 135 | "no-inline-comments": 0, 136 | "no-lonely-if": 2, 137 | "no-mixed-spaces-and-tabs": 2, 138 | "no-multiple-empty-lines": 2, 139 | "no-nested-ternary": 0, 140 | "no-new-object": 2, 141 | "semi-spacing": 2, 142 | "no-spaced-func": 2, 143 | "no-ternary": 0, 144 | "no-trailing-spaces": 2, 145 | "no-underscore-dangle": 0, 146 | "one-var": 0, 147 | "operator-assignment": [ 148 | 2, 149 | "always" 150 | ], 151 | "padded-blocks": 0, 152 | "quote-props": [ 153 | 1, 154 | "as-needed" 155 | ], 156 | "quotes": [ 157 | 2, 158 | "single" 159 | ], 160 | "semi": 2, 161 | "sort-vars": 0, 162 | "keyword-spacing": 1, 163 | "space-before-blocks": [ 164 | 1, 165 | "always" 166 | ], 167 | "space-in-parens": [ 168 | 1, 169 | "never" 170 | ], 171 | "space-infix-ops": 1, 172 | "space-unary-ops": [ 173 | 1, 174 | { 175 | "words": true, 176 | "nonwords": false 177 | } 178 | ], 179 | "spaced-line-comment": 0, 180 | "wrap-regex": 0 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | test/browser/tests-bundle.js 4 | -------------------------------------------------------------------------------- /.testem.json: -------------------------------------------------------------------------------- 1 | { 2 | "framework": "qunit", 3 | "test_page": "test/browser/index.html", 4 | "launch_in_dev": [ 5 | "Chrome" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery.component 2 | 3 | Create a component with jQuery. Inspired by Backbone View model. 4 | 5 | ![release](https://img.shields.io/badge/release-1.3.5-blue.svg) 6 | ![coverage](https://img.shields.io/badge/coverage-70%25-green.svg) 7 | [![license](https://img.shields.io/badge/license-MIT%20License-blue.svg)](https://opensource.org/licenses/MIT) 8 | [![requirement](https://img.shields.io/badge/jquery-required-lightgrey.svg)](https://www.npmjs.com/package/jquery) 9 | [![requirement](https://img.shields.io/badge/lodash-required-lightgrey.svg)](https://www.npmjs.com/package/lodash) 10 | 11 | ## Requirement 12 | You must include in your html jQuery and lodash. 13 | 14 | ## How to install 15 | ```terminal 16 | npm install --save jquery.component 17 | ``` 18 | Include in your .html this library after jQuery and lodash files. 19 | 20 | ## How it works 21 | ### Basically 22 | jquery.component uses template method of lodash so you can integrate a template in your .html. For example: 23 | ```html 24 | 30 | ``` 31 | Then in your js file, call your template and declare events in component method: 32 | ```javascript 33 | var titleComponent = $.component({ 34 | template: $('#title-template').html(), 35 | events: { 36 | 'click h1': function() { 37 | $(this).parent().find('p').append('Hello everyone !'); 38 | } 39 | } 40 | }); 41 | ``` 42 | After you can use your component with some data by using the render method: 43 | ```javascript 44 | $('body').append(titleComponent.render({ 45 | title: 'Hello World' 46 | })); 47 | ``` 48 | ### Children 49 | If you want to include another component or element in your component. You can use `data-children` attribute in the parent container: 50 | ```html 51 | 57 | 58 | 61 | 62 | 72 | ``` 73 | `children` attribute accept an array of components or elements. If you pass a function, it will be evaluate with the model. 74 | 75 | By the way, if you declare an object into children attribute, use `data-child` with the key name: 76 | ```html 77 | 84 | 85 | 88 | 89 | 92 | 93 | 112 | ``` 113 | ### Bind data 114 | You can also bind your data by declaring a `data-bind-id` attribute with a name and then apply a `data-bind` attribute to another element with the name target. Follow this example: 115 | ```html 116 | 122 | 123 | 130 | ``` 131 | It's possible to pass a callback method in $.component: 132 | ```javascript 133 | var componentName = $.component({ 134 | template: $('#name-template').html(), 135 | bindData: function (val) { 136 | return val + val; 137 | } 138 | }); 139 | ``` 140 | ### Lifecycle of component 141 | - `componentWillMount` method option will run before the render of component. 142 | - `componentDidMount` method option will run after the render of component. 143 | - `componentWillUpdate` each time, method option will run before the component re-renders. As argument, you can use old declared data. 144 | - `componentDidUpdate` each time, method option will run after the component re-renders. As argument, you can use old declared data. 145 | 146 | ## Contributing 147 | 1. Fork it 148 | 2. Create your feature branch (git checkout -b my-new-feature) 149 | 3. Commit your changes (git commit -am 'Added some feature') 150 | 4. Push to the branch (git push origin my-new-feature) 151 | 5. Create new Pull Request 152 | 153 | ## Licence 154 | ``` 155 | MIT 156 | ``` 157 | -------------------------------------------------------------------------------- /dist/jquery.component.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1) { 224 | result = [separator.shift(), separator.join(' ')]; 225 | this.find(result[1]).bind(i, o[i]); 226 | } else { 227 | this.bind(i, o[i]); 228 | } 229 | } 230 | return this; 231 | }; 232 | }(jQuery)); 233 | 234 | },{}]},{},[1]); 235 | -------------------------------------------------------------------------------- /dist/jquery.component.min.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o1){result=[separator.shift(),separator.join(" ")];this.find(result[1]).bind(i,o[i])}else{this.bind(i,o[i])}}return this}})(jQuery)},{}]},{},[1]); -------------------------------------------------------------------------------- /doc/API.md: -------------------------------------------------------------------------------- 1 | ## API instance 2 | ### `clone` 3 | clone component instance. Useful for set new data. 4 | 5 | ### `model.data` 6 | Object where all associate datas of component are stored. 7 | 8 | ### `model.get(key)` 9 | Take as argument an attribute key of object `model.data` and return this value. 10 | 11 | ### `model.set(key, value)` 12 | Pass in first argument the key name to declare or overwrite in `model.data` and then pass in second argument this value. 13 | You can also pass in argument an object. 14 | 15 | ### `setBindData(callback)` 16 | Set or replace the callback method called after a change on input, selector or textarea tag. 17 | 18 | ### `setChildren(children)` 19 | Set or replace the children defined. Children argument must be in html. 20 | 21 | ### `setEvents(events)` 22 | Set or replace events methods. Take as example Backbone events. ([doc](http://backbonejs.org/#View-events)) 23 | 24 | ### `setModel(model)` 25 | Set or replace object data used in your component. 26 | 27 | ### `setTemplate(newTemplate)` 28 | Set or replace the template html of component. 29 | 30 | ### `render(datas, optionsTemplate)` 31 | Render the component with the template attribute declared and datas passed in argument (optional). In second argument you can pass all options lodash template. 32 | -------------------------------------------------------------------------------- /example/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Basic example 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/binding.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Binding data example 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /example/children.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Children example 6 | 7 | 8 | 15 | 16 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Events example 6 | 7 | 8 | 9 | 18 | 19 | 20 | 21 | 22 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery.component", 3 | "version": "1.3.5", 4 | "description": "Create a component with jQuery. Inspired by Backbone View model.", 5 | "main": "dist/jquery.component.js", 6 | "scripts": { 7 | "browserify": "browserify src/index.js > dist/jquery.component.js", 8 | "uglify": "uglifyjs dist/jquery.component.js -o dist/jquery.component.min.js", 9 | "dist": "npm run browserify && npm run uglify", 10 | "pretest-browser": "browserify test/jquery.component.js > test/browser/tests-bundle.js", 11 | "posttest-browser": "rm test/browser/tests-bundle.js", 12 | "test-browser": "testem" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/olivmonnier/jquery-component.git" 17 | }, 18 | "keywords": [ 19 | "component", 20 | "dom", 21 | "jquery", 22 | "template" 23 | ], 24 | "author": "oliv75", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/olivmonnier/jquery-component/issues" 28 | }, 29 | "homepage": "https://github.com/olivmonnier/jquery-component#readme", 30 | "devDependencies": { 31 | "blanket": "1.1.7", 32 | "browserify": "^12.0.1", 33 | "jquery": "^2.1.4", 34 | "lodash": "^3.10.1", 35 | "qunitjs": "^1.20.0", 36 | "testem": "^0.9.11", 37 | "uglify-js": "^2.6.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | require('./jquery.events.js'); 2 | require('./jquery.bindData.js'); 3 | require('./jquery.component.js'); 4 | -------------------------------------------------------------------------------- /src/jquery.bindData.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.bindData = function(callback) { 3 | var self = this; 4 | $(self).find('[data-bind-id]').each(function() { 5 | var pubSub = $({}); 6 | var id = $(this).data('bind-id'); 7 | var eventName = id + ':change'; 8 | 9 | $(this).on('change input', function() { 10 | var $input = $(this); 11 | pubSub.trigger(eventName, [$input.val()]); 12 | }); 13 | 14 | pubSub.on(eventName, function(evt, val) { 15 | if (callback) var newVal = callback(val); 16 | 17 | $(self).find('[data-bind = ' + id + ']').each(function() { 18 | var $bound = $(this); 19 | 20 | if ($bound.is('input, textarea, select')) { 21 | $bound.val(newVal); 22 | } else { 23 | $bound.html(newVal); 24 | } 25 | }); 26 | }); 27 | }); 28 | return this; 29 | }; 30 | }(jQuery)); 31 | -------------------------------------------------------------------------------- /src/jquery.component.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.component = function(options) { 3 | var opts = options || {}; 4 | 5 | var Component = function() { 6 | var self = this; 7 | this.$el = ''; 8 | this.mounted = false; 9 | this.children = opts.children || ''; 10 | this.events = opts.events || {}; 11 | this.model = { 12 | oldData: null, 13 | data: opts.model || {}, 14 | get: function(attr) { 15 | return this.data[attr]; 16 | }, 17 | set: function(key, val) { 18 | var attrs; 19 | var modelData = Object.create({}); 20 | 21 | if (key == null) return this; 22 | 23 | if (typeof key === 'object') { 24 | attrs = key; 25 | } else { 26 | (attrs = {})[key] = val; 27 | } 28 | 29 | for (var k in this.data) { 30 | Object.defineProperty(modelData, k, { 31 | value: this.data[k], 32 | writable: true, 33 | enumerable: true, 34 | configurable: true 35 | }); 36 | } 37 | for (var attr in attrs) { 38 | Object.defineProperty(modelData, attr, { 39 | value: attrs[attr], 40 | writable: true, 41 | enumerable: true, 42 | configurable: true 43 | }); 44 | } 45 | 46 | if (self.$el) { 47 | self.$el.replaceWith(self.render(modelData)); 48 | } else { 49 | this.data = modelData; 50 | } 51 | } 52 | }; 53 | this.optionsTemplate = opts.optionsTemplate || {}; 54 | this.template = opts.template || ''; 55 | }; 56 | 57 | Component.prototype.bindData = opts.bindData || null; 58 | 59 | Component.prototype.clone = function() { 60 | return $.extend(true, {}, this); 61 | } 62 | 63 | Component.prototype.componentDidMount = opts.componentDidMount || null; 64 | 65 | Component.prototype.componentDidUpdate = opts.componentDidUpdate || null; 66 | 67 | Component.prototype.componentWillMount = opts.componentWillMount || null; 68 | 69 | Component.prototype.componentWillUpdate = opts.componentWillUpdate || null; 70 | 71 | Component.prototype.render = function(data, optionsTemplate) { 72 | this.model.oldData = this.model.data; 73 | if (data) this.model.data = data; 74 | if (optionsTemplate) this.optionsTemplate = optionsTemplate; 75 | 76 | if (!this.mounted && this.componentWillMount) { 77 | this.componentWillMount(); 78 | } 79 | if (this.mounted && this.componentWillUpdate) { 80 | this.componentWillUpdate(this.model.oldData); 81 | } 82 | 83 | var $el = $(_.template(this.template, this.optionsTemplate)(this.model)); 84 | 85 | if (typeof this.children == 'function') this.children = this.children(); 86 | 87 | if (typeof this.children == 'object' && this.children.length == undefined) { 88 | for (var child in this.children) { 89 | $el.find('[data-child="' + child + '"]').html(this.children[child]); 90 | } 91 | } else { 92 | if (!Array.isArray(this.children)) this.children = [this.children]; 93 | 94 | this.children.forEach(function(child) { 95 | $el.find('[data-children]').append(child); 96 | }); 97 | } 98 | $el.events(this.events).bindData(this.bindData); 99 | this.$el = $el; 100 | 101 | if (!this.mounted && this.componentDidMount) { 102 | this.componentDidMount(); 103 | } 104 | if (this.mounted && this.componentDidUpdate) { 105 | this.componentDidUpdate(this.model.oldData); 106 | } 107 | 108 | this.mounted = true; 109 | 110 | return this.$el; 111 | }; 112 | 113 | Component.prototype.setBindData = function(callback) { 114 | this.bindData = callback; 115 | 116 | return this; 117 | }; 118 | 119 | Component.prototype.setChildren = function(children) { 120 | this.children = children; 121 | 122 | if (this.$el) { 123 | this.$el.find('[data-children]').empty(); 124 | 125 | if (typeof this.children == 'function') this.children = this.children(); 126 | 127 | if (typeof this.children == 'object' && this.children.length == undefined) { 128 | for (var child in this.children) { 129 | $el.find('[data-child="' + child + '"]').html(this.children[child]); 130 | } 131 | } else { 132 | if (!Array.isArray(this.children)) this.children = [this.children]; 133 | 134 | this.children.forEach(function(child) { 135 | $el.find('[data-children]').append(child); 136 | }); 137 | } 138 | } 139 | 140 | return this; 141 | }; 142 | 143 | Component.prototype.setEvents = function(events) { 144 | this.events = events; 145 | 146 | if (this.$el) { 147 | this.$el.replaceWith(this.render()); 148 | } 149 | 150 | return this; 151 | }; 152 | 153 | Component.prototype.setModel = function(model) { 154 | 155 | if (this.$el) { 156 | this.$el.replaceWith(this.render(model)); 157 | } else { 158 | this.model.data = model; 159 | } 160 | 161 | return this; 162 | }; 163 | 164 | Component.prototype.setTemplate = function(newTemplate) { 165 | this.template = newTemplate; 166 | 167 | if (this.$el) { 168 | this.$el.replaceWith(this.render()); 169 | } 170 | 171 | return this; 172 | }; 173 | 174 | return new Component(); 175 | }; 176 | }(jQuery)); 177 | -------------------------------------------------------------------------------- /src/jquery.events.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.events = function(o) { 3 | for (var i in o) { 4 | var separator = i.split(' '); 5 | var result = []; 6 | 7 | if (separator.length > 1) { 8 | result = [separator.shift(), separator.join(' ')]; 9 | this.find(result[1]).bind(i, o[i]); 10 | } else { 11 | this.bind(i, o[i]); 12 | } 13 | } 14 | return this; 15 | }; 16 | }(jQuery)); 17 | -------------------------------------------------------------------------------- /test/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test jQuery.component plugin 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/jquery.bindData.js: -------------------------------------------------------------------------------- 1 | QUnit.test('$.fn.bindData', function(assert) { 2 | assert.equal(typeof $.fn.bindData, 'function', 'Is function ?'); 3 | }); 4 | -------------------------------------------------------------------------------- /test/jquery.component.js: -------------------------------------------------------------------------------- 1 | require('./jquery.bindData'); 2 | require('./jquery.events'); 3 | 4 | QUnit.test('$.component', function(assert) { 5 | var component = $.component(); 6 | assert.equal(typeof $.component, 'function', 'Is function ?'); 7 | assert.equal(typeof component, 'object', 'No parameters'); 8 | }); 9 | 10 | QUnit.test('$.component API bindData', function(assert) { 11 | var component = $.component(); 12 | assert.equal(component.bindData, null, 'Is null'); 13 | }); 14 | 15 | QUnit.test('$.component API children', function(assert) { 16 | var component = $.component(); 17 | assert.equal(component.children, '', 'Is an empty string'); 18 | 19 | var component2 = $.component({ 20 | template: '', 21 | children: function() { 22 | return document.createElement('span'); 23 | } 24 | }); 25 | component2.render(); 26 | assert.equal(typeof component2.children, 'object', 'Is become an object after render running'); 27 | 28 | var child = $.component({ 29 | template: 'Foo' 30 | }); 31 | var component3 = $.component({ 32 | template: '
', 33 | children: child.render() 34 | }); 35 | component3.render(); 36 | assert.equal(component3.$el.children().length, 1, 'Is populating by children after render running'); 37 | 38 | var component4 = $.component({ 39 | template: '
', 40 | children: { 41 | foo: child.render() 42 | } 43 | }); 44 | component4.render(); 45 | assert.equal(component4.$el.find('[data-child="foo"]').children().length, 1, 'Is populating by children object key'); 46 | }); 47 | 48 | QUnit.test('$.component API clone', function(assert) { 49 | var component1 = $.component(); 50 | assert.equal(typeof component1.clone, 'function', 'Is function'); 51 | 52 | var component2 = component1.clone(); 53 | assert.equal(typeof component2, 'object', 'Is an object'); 54 | assert.equal(typeof component2.render, 'function', 'Is a deep clone'); 55 | 56 | component1.render({foo: 'bar'}); 57 | component2.render({foo: 'baz'}); 58 | assert.equal(component1.model.data.foo, 'bar', 'Is data declare on render launch for component1'); 59 | assert.equal(component2.model.data.foo, 'baz', 'Is data declare on render launch for component2'); 60 | }); 61 | 62 | QUnit.test('$.component API componentDidMount', function(assert) { 63 | var component1 = $.component(); 64 | assert.equal(component1.componentDidMount, null, 'Is null'); 65 | 66 | var count = 0; 67 | var component2 = $.component({ 68 | componentDidMount: function() { 69 | count++; 70 | } 71 | }); 72 | for (var i = 0; i < 2; i++) { 73 | component2.render(); 74 | } 75 | assert.equal(count, 1, 'Expect run in first time on render'); 76 | }); 77 | 78 | QUnit.test('$.component API componentDidUpdate', function(assert) { 79 | var component1 = $.component(); 80 | assert.equal(component1.componentDidUpdate, null, 'Is null'); 81 | 82 | var count = 0; 83 | var component2 = $.component({ 84 | componentDidUpdate: function() { 85 | count++; 86 | } 87 | }); 88 | for (var i = 0; i < 3; i++) { 89 | component2.render(); 90 | 91 | if (i === 0) { 92 | assert.equal(count, 0, 'Expect not run in first time on render'); 93 | } 94 | } 95 | assert.equal(count, 2, 'Expect run each time render is called'); 96 | }); 97 | 98 | QUnit.test('$.component API componentWillMount', function(assert) { 99 | var component1 = $.component(); 100 | assert.equal(component1.componentWillMount, null, 'Is null'); 101 | 102 | var count = 0; 103 | var component2 = $.component({ 104 | componentWillMount: function() { 105 | count++; 106 | } 107 | }); 108 | for (var i = 0; i < 2; i++) { 109 | component2.render(); 110 | } 111 | assert.equal(count, 1, 'Expect run in first time on render'); 112 | }); 113 | 114 | QUnit.test('$.component API componentWillUpdate', function(assert) { 115 | var component1 = $.component(); 116 | assert.equal(component1.componentWillUpdate, null, 'Is null'); 117 | 118 | var count = 0; 119 | var component2 = $.component({ 120 | componentWillUpdate: function() { 121 | count++; 122 | } 123 | }); 124 | for (var i = 0; i < 3; i++) { 125 | component2.render(); 126 | if (i === 0) { 127 | assert.equal(count, 0, 'Expect not run in first time on render'); 128 | } 129 | } 130 | assert.equal(count, 2, 'Expect run each time render is called'); 131 | }); 132 | 133 | QUnit.test('$.component API model', function(assert) { 134 | var component = $.component(); 135 | assert.equal(typeof component.model, 'object', 'Is object'); 136 | }); 137 | 138 | QUnit.test('$.component API model.data', function(assert) { 139 | var component = $.component(); 140 | assert.equal(typeof component.model.data, 'object', 'Is object'); 141 | }); 142 | 143 | QUnit.test('$.component API model.get', function(assert) { 144 | var component1 = $.component(); 145 | assert.equal(typeof component1.model.get, 'function', 'Is function'); 146 | 147 | var component2 = $.component({ 148 | model: { 149 | msg: 'Hello World' 150 | } 151 | }); 152 | assert.equal(component2.model.get('msg'), 'Hello World', 'Expect return value declared'); 153 | }); 154 | 155 | QUnit.test('$.component API model.set', function(assert) { 156 | var component1 = $.component(); 157 | assert.equal(typeof component1.model.set, 'function', 'Is function'); 158 | 159 | var component2 = $.component({ 160 | model: { 161 | msg: 'Hello World' 162 | } 163 | }); 164 | component2.model.set({msg: 'Hello Everyone'}); 165 | assert.equal(component2.model.data.msg, 'Hello Everyone', 'Expect set value in model.data'); 166 | }); 167 | 168 | QUnit.test('$.component API render', function(assert) { 169 | var component1 = $.component(); 170 | assert.equal(typeof component1.render, 'function', 'Is function'); 171 | assert.equal(component1.mounted, false, 'Is not declared as mounted before render running'); 172 | 173 | component1.render({foo: 'bar'}); 174 | assert.equal(component1.mounted, true, 'Is declared as mounted after render running'); 175 | assert.equal(component1.model.data.foo, 'bar', 'Is updating the model'); 176 | 177 | var template = '

Hello World

'; 178 | var component2 = $.component({ template: template }); 179 | assert.deepEqual(component2.render(), $(template), 'Expect return element defined in template'); 180 | }); 181 | 182 | QUnit.test('$.component API template', function(assert) { 183 | var component1 = $.component(); 184 | assert.equal(typeof component1.template, 'string', 'Is string'); 185 | 186 | var component2 = $.component({ 187 | template: $('body').html() 188 | }); 189 | assert.equal(typeof component2.template, 'string', 'Expect return a string with a selector'); 190 | }); 191 | 192 | QUnit.test('$.component API setBindData', function(assert) { 193 | var component1 = $.component(); 194 | assert.equal(typeof component1.setBindData, 'function', 'Is function'); 195 | 196 | var component2 = $.component(); 197 | var bindData = function(val) { 198 | return val + val; 199 | }; 200 | component2.setBindData(bindData); 201 | assert.deepEqual(component2.bindData, bindData, 'Expect set attribute bindData in component'); 202 | }); 203 | 204 | QUnit.test('$.component API setChildren', function(assert) { 205 | var component1 = $.component(); 206 | assert.equal(typeof component1.setChildren, 'function', 'Is function'); 207 | 208 | var component2 = $.component(); 209 | var children = '

Hello World !

'; 210 | component2.setChildren(children); 211 | assert.equal(component2.children, children, 'Expect set attribute children in component'); 212 | }); 213 | 214 | QUnit.test('$.component API setEvents', function(assert) { 215 | var component1 = $.component(); 216 | assert.equal(typeof component1.setEvents, 'function', 'Is function'); 217 | 218 | var component2 = $.component(); 219 | var events = { 220 | 'click body': function() { 221 | console.log('Clicked !'); 222 | } 223 | }; 224 | component2.setEvents(events); 225 | assert.deepEqual(component2.events, events, 'Expect set attribute events in component'); 226 | }); 227 | 228 | QUnit.test('$.component API setModel', function(assert) { 229 | var component1 = $.component(); 230 | assert.equal(typeof component1.setModel, 'function', 'Is function'); 231 | 232 | var component2 = $.component({ 233 | model: { 234 | msg: 'Hello World' 235 | } 236 | }); 237 | component2.setModel({ 238 | msg: 'Hello Everyone' 239 | }); 240 | assert.equal(component2.model.data.msg, 'Hello Everyone', 'Expect set value in model.data'); 241 | }); 242 | 243 | QUnit.test('$.component API setTemplate', function(assert) { 244 | var component1 = $.component(); 245 | assert.equal(typeof component1.setTemplate, 'function', 'Is function'); 246 | 247 | var component2 = $.component(); 248 | var template = '

Hello World !

'; 249 | component2.setTemplate(template); 250 | assert.equal(component2.template, template, 'Expect set attribute template in component'); 251 | }); 252 | -------------------------------------------------------------------------------- /test/jquery.events.js: -------------------------------------------------------------------------------- 1 | QUnit.test('$.fn.events', function(assert) { 2 | assert.equal(typeof $.fn.events, 'function', 'Is function ?'); 3 | }); 4 | --------------------------------------------------------------------------------