├── .github ├── FUNDING.yml └── workflows │ └── tests.yml ├── .gitignore ├── Contributing.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── docs ├── CNAME ├── documentation.html ├── documentation.html.jade ├── font │ ├── fontello.eot │ ├── fontello.svg │ ├── fontello.ttf │ └── fontello.woff ├── fontello.css ├── img │ ├── card.png │ ├── city.svg │ ├── city_orig.svg │ ├── cloud.svg │ ├── cloud_orig.svg │ ├── drop.svg │ └── drop_orig.svg ├── index.html ├── index.html.jade ├── layout.jade ├── logo.svg ├── picnic.css ├── style.css ├── test.js ├── tests.html ├── tests.html.jade ├── umbrella.min.js ├── umbrella.png ├── umbrella.svg └── vendor │ ├── chai.js │ ├── jquery.js │ ├── mocha.css │ ├── mocha.js │ ├── polyfill.js │ └── sinon.js ├── documentation.md ├── jquery.md ├── migrate-2-to-3.md ├── package-lock.json ├── package.json ├── polyfill.js ├── src ├── export.js ├── plugins │ ├── addclass │ │ ├── addclass.js │ │ ├── readme.md │ │ └── test.js │ ├── adjacent │ │ └── adjacent.js │ ├── after │ │ ├── after.js │ │ ├── readme.md │ │ └── test.js │ ├── append │ │ ├── append.js │ │ ├── readme.md │ │ └── test.js │ ├── args │ │ ├── args.js │ │ └── test.js │ ├── array │ │ ├── array.js │ │ ├── readme.md │ │ └── test.js │ ├── attr │ │ ├── attr.js │ │ ├── readme.md │ │ └── test.js │ ├── before │ │ ├── before.js │ │ ├── readme.md │ │ └── test.js │ ├── children │ │ ├── children.js │ │ ├── readme.md │ │ └── test.js │ ├── clone │ │ ├── clone.js │ │ ├── readme.md │ │ └── test.js │ ├── closest │ │ ├── closest.js │ │ ├── readme.md │ │ └── test.js │ ├── data │ │ ├── data.js │ │ ├── readme.md │ │ └── test.js │ ├── each │ │ ├── each.js │ │ ├── readme.md │ │ └── test.js │ ├── eacharg │ │ ├── eacharg.js │ │ └── test.js │ ├── empty │ │ ├── empty.js │ │ ├── readme.md │ │ └── test.js │ ├── filter │ │ ├── filter.js │ │ ├── readme.md │ │ └── test.js │ ├── find │ │ ├── find.js │ │ ├── readme.md │ │ └── test.js │ ├── first │ │ ├── first.js │ │ ├── readme.md │ │ └── test.js │ ├── generate │ │ └── generate.js │ ├── handle │ │ ├── handle.js │ │ ├── readme.md │ │ └── test.js │ ├── hasclass │ │ ├── hasclass.js │ │ ├── readme.md │ │ └── test.js │ ├── html │ │ ├── html.js │ │ ├── readme.md │ │ └── test.js │ ├── is │ │ ├── is.js │ │ ├── readme.md │ │ └── test.js │ ├── isInPage │ │ └── isInPage.js │ ├── last │ │ ├── last.js │ │ ├── readme.md │ │ └── test.js │ ├── map │ │ ├── map.js │ │ ├── readme.md │ │ └── test.js │ ├── not │ │ ├── not.js │ │ ├── readme.md │ │ └── test.js │ ├── off │ │ ├── off.js │ │ ├── readme.md │ │ └── test.js │ ├── on │ │ ├── on.js │ │ ├── readme.md │ │ └── test.js │ ├── pairs │ │ └── pairs.js │ ├── param │ │ └── param.js │ ├── parent │ │ ├── parent.js │ │ ├── readme.md │ │ └── test.js │ ├── prepend │ │ ├── prepend.js │ │ ├── readme.md │ │ └── test.js │ ├── remove │ │ ├── readme.md │ │ ├── remove.js │ │ └── test.js │ ├── removeclass │ │ ├── readme.md │ │ ├── removeclass.js │ │ └── test.js │ ├── replace │ │ ├── readme.md │ │ ├── replace.js │ │ └── test.js │ ├── scroll │ │ ├── readme.md │ │ ├── scroll.js │ │ └── test.js │ ├── select │ │ ├── select.js │ │ └── test.js │ ├── serialize │ │ ├── readme.md │ │ ├── serialize.js │ │ └── test.js │ ├── siblings │ │ ├── readme.md │ │ ├── siblings.js │ │ └── test.js │ ├── size │ │ ├── readme.md │ │ ├── size.js │ │ └── test.js │ ├── slice │ │ ├── slice.js │ │ └── test.js │ ├── str │ │ └── str.js │ ├── text │ │ ├── readme.md │ │ ├── test.js │ │ └── text.js │ ├── toggleclass │ │ ├── readme.md │ │ ├── test.js │ │ └── toggleclass.js │ ├── trigger │ │ ├── readme.md │ │ ├── test.js │ │ └── trigger.js │ ├── unique │ │ └── unique.js │ ├── uri │ │ └── uri.js │ └── wrap │ │ ├── readme.md │ │ ├── test.js │ │ └── wrap.js ├── readme.md ├── test.js └── umbrella.js ├── umbrella.d.ts ├── umbrella.esm.js ├── umbrella.js └── umbrella.min.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://www.paypal.me/franciscopresencia/19 2 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | platform: [ubuntu-latest, macos-latest, windows-latest] 12 | node-version: [12.x, 14.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - name: Installing 21 | run: npm install 22 | - name: Testing 23 | run: npm test 24 | env: 25 | CI: true 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git 2 | node_modules 3 | npm-debug.log 4 | .DS_Store 5 | .vscode -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for contributing! Developing Umbrella is quite easy: 4 | 5 | 1. Clone the repository 6 | `git clone git://github.com/franciscop/umbrella.git && cd ./umbrella` 7 | 1. Install Phantom JS 1.9.7. For Linux ([based on this](https://gist.github.com/julionc/7476620)): 8 | `npm run installphantom` 9 | 1. Install the dependencies 10 | `npm install` 11 | 1. Run `grunt watch` 12 | 1. Modify any file within `/src` (code, tests or documentation) 13 | 14 | After these steps, the library, tests and documentation will be automatically built each time a change is saved. To see the tests open `/test/index.html` in your browser. Please try not to make a PR with broken tests. 15 | 16 | 17 | ## New plugins 18 | 19 | Recommended to copy one of the existing ones and modify the files, specially `addclass` (folder `/src/plugins/addclass`). 20 | 21 | 22 | ## Testing 23 | 24 | Each test should make sure that the smallest possible part of a feature works. While this seems simple, some times it's not so much. For example, let's study the 'addClass' for a single class, one of the simplest examples. You might think this is enough: 25 | 26 | ```js 27 | it("can add a single class", function(){ 28 | base.addClass('bla'); 29 | expect(base.hasClass('bla')).to.equal(true); 30 | }); 31 | ``` 32 | 33 | You can use these methods to ease your testing: 34 | 35 | ```js 36 | // Expect something to be a function: 37 | isFn(function(){}); // good 38 | isFn("a"); // throw 39 | 40 | // Expect the selector to have the size: 41 | size('body', 1); // good 42 | size('body', 2); // bad 43 | 44 | // Expect the selector, or the `base` if there's none, to have the class 45 | hasClass('bla') // good 46 | hasClass('bla', '.bla') // good 47 | hasClass('non-exist') // bad 48 | 49 | // You can also chain all of them: 50 | isFn(function(){})(function(){})(function(){}) 51 | size('body', 1)('html', 1) 52 | hasClass('bla')('blu') 53 | ``` 54 | 55 | While a priori it might seem right, there are two potential and serious problems: the class might be there already and we might affect other tests. These can be corrected if we follow few simple principles: 56 | 57 | 1. Make sure that the data at the begin of the test does *not* pass the test 58 | 1. Add the code that we want to test 59 | 1. Make sure we leave the DOM as it was before 60 | 61 | So that's it, for our example of addClass we could now do: 62 | 63 | ```js 64 | it("can add a single class", function(){ 65 | 66 | // 1. Check that the class is not there previously 67 | expect(base.hasClass('bla')).to.equal(false); 68 | 69 | // 2. The code to test and its test 70 | base.addClass('bla'); 71 | expect(base.hasClass('bla')).to.equal(true); 72 | 73 | // 3. Make sure we clean up 74 | base.removeClass('bla'); 75 | }); 76 | ``` 77 | 78 | Furthermore, as it can be seen in the tests for addClass, when all the tests can reuse methods, it's better to do so: 79 | 80 | ```js 81 | beforeEach(function(){ 82 | expect(base.hasClass('bla')).to.equal(false); 83 | expect(base.hasClass('blu')).to.equal(false); 84 | }); 85 | 86 | afterEach(function(){ 87 | base.removeClass('bla blu'); 88 | }); 89 | ``` 90 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // This builds the library itself 2 | module.exports = function (grunt) { 3 | // Configuration 4 | grunt.initConfig({ 5 | uglify: { 6 | options: { 7 | banner: '/* Umbrella JS ' + grunt.file.readJSON('package.json').version + ' umbrellajs.com */\n' 8 | }, 9 | umbrella: { 10 | files: { 11 | 'umbrella.min.js': 'umbrella.js' 12 | } 13 | }, 14 | web: { 15 | files: { 16 | 'docs/umbrella.min.js': 'umbrella.js' 17 | } 18 | }, 19 | es6: { 20 | options: { 21 | footer: '\nexport default u;' 22 | }, 23 | files: { 24 | 'umbrella.esm.js': 'umbrella.js' 25 | } 26 | } 27 | }, 28 | 29 | semistandard: { 30 | app: { 31 | src: [] 32 | } 33 | }, 34 | 35 | watch: { 36 | scripts: { 37 | files: [ 38 | 'package.js', // To bump versions 39 | 'Gruntfile.js', 40 | 'src/*.js', 41 | 'src/*.md', 42 | 'src/**/*.*', 43 | 'docs/**.*' 44 | ], 45 | tasks: ['default'], 46 | options: { 47 | spawn: false, 48 | livereload: true 49 | } 50 | } 51 | }, 52 | 53 | jade: { 54 | compile: { 55 | options: { 56 | client: false 57 | }, 58 | files: [ { 59 | cwd: '.', 60 | src: '**/*.html.jade', 61 | dest: '.', 62 | expand: true, 63 | ext: '.html' 64 | } ] 65 | } 66 | }, 67 | 68 | mocha_phantomjs: { 69 | all: './docs/tests.html', 70 | options: { 71 | 'web-security': false 72 | } 73 | }, 74 | 75 | concat: { 76 | main: { 77 | // No test files 78 | options: { 79 | process: function (src, file) { 80 | return /test\.js/.test(file) ? '' : src; 81 | } 82 | }, 83 | files: { 84 | 'umbrella.js': ['src/umbrella.js', 'src/plugins/**/*.js', 'src/export.js'], 85 | 'documentation.md': ['src/readme.md', 'src/plugins/**/readme.md'] 86 | } 87 | }, 88 | test: { 89 | files: { 90 | 'docs/test.js': ['src/test.js', 'src/plugins/**/test.js'] 91 | } 92 | } 93 | }, 94 | 95 | bytesize: { 96 | all: { 97 | src: [ 98 | 'umbrella.min.js' 99 | ] 100 | } 101 | } 102 | }); 103 | 104 | grunt.loadNpmTasks('grunt-semistandard'); 105 | grunt.loadNpmTasks('grunt-contrib-concat'); 106 | grunt.loadNpmTasks('grunt-contrib-uglify'); 107 | grunt.loadNpmTasks('grunt-contrib-watch'); 108 | grunt.loadNpmTasks('grunt-contrib-jade'); 109 | grunt.loadNpmTasks('grunt-mocha-phantomjs'); 110 | grunt.loadNpmTasks('grunt-bytesize'); 111 | 112 | grunt.registerTask('build', ['concat', 'uglify', 'jade']); 113 | grunt.registerTask('test', ['semistandard', 'mocha_phantomjs']); 114 | grunt.registerTask('default', ['build', 'test', 'bytesize']); 115 | }; 116 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Francisco Presencia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Umbrella JS [![test badge](https://github.com/franciscop/umbrella/workflows/tests/badge.svg)](https://github.com/franciscop/umbrella/actions) [![stats](https://data.jsdelivr.com/v1/package/npm/umbrellajs/badge?style=rounded)](https://www.jsdelivr.com/package/npm/umbrellajs) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/franciscop/umbrella/blob/master/LICENSE) 2 | 3 | > [**Library Documentation**](http://umbrellajs.com/documentation) | [**Migrating from jQuery guide**](https://github.com/franciscop/umbrella/blob/master/jquery.md) 4 | 5 | Covers your javascript needs for those rainy days. A <3kb performant jQuery-like library born from the question: [You might not need jQuery](http://youmightnotneedjquery.com/), then what do you need? 6 | 7 | You probably need awesome CSS (like [Picnic CSS](http://picnicss.com/)) and a lightweight, modern and performant javascript library. This does: 8 | 9 | - DOM traversal (selector, filter, find, each, etc.) 10 | - DOM editing (classes & attributes, html, before, etc.) 11 | - Event handling 12 | 13 | A couple of simple examples: 14 | 15 | ```js 16 | // Simple events like jQuery 17 | u("button").on('click', e => { 18 | alert("Hello world"); 19 | }); 20 | 21 | // Handle form submissions 22 | u('form.login').handle('submit', async e => { 23 | const user = await fetch('/login', { 24 | method: 'POST', body: new FormData(e.target) 25 | }).then(res => res.json()); 26 | window.href = '/user/' + user.id; 27 | }); 28 | ``` 29 | 30 | 31 | ## Getting started 32 | 33 | There are few ways to use Umbrella JS: 34 | 35 | 36 | ### Play with it 37 | 38 | Instead of installing it, you can just play with it in JSFiddle: 39 | 40 | [**Try on JSFiddle**](https://jsfiddle.net/franciscop/mwpcqddj/) 41 | 42 | 43 | ### Use a CDN 44 | 45 | jsdelivr.com is an awesome OSS service that hosts many open source projects so you don't need to even download the code: 46 | 47 | ```js 48 | 49 | ``` 50 | 51 | 52 | ### Install with `npm` 53 | 54 | Using npm is a front-end package manager that makes it super-easy to add a new package: 55 | 56 | ``` 57 | npm install umbrellajs 58 | ``` 59 | 60 | 61 | ### Module support 62 | 63 | If you use a front-end module bundler like Webpack or Browserify, `u` is exposed as CommonJS exports. You can pull them in like so: 64 | 65 | ```js 66 | // ES Modules/Webpack/etc 67 | import u from 'umbrellajs'; 68 | 69 | // Commonjs 70 | var u = require('umbrellajs'); 71 | ``` 72 | 73 | ### ES Module support 74 | 75 | If you use an ES Module, `u` and `ajax` are exposed as ES Module exports. 76 | You can pull them in like so: 77 | 78 | ``` 79 | import u from 'umbrellajs/umbrella.esm.js' 80 | ``` 81 | 82 | ### Download it 83 | 84 | If you like it or prefer to try it locally, just download `umbrella.min.js`: 85 | 86 | [**Download Umbrella JS**](https://raw.githubusercontent.com/franciscop/umbrella/master/umbrella.min.js) 87 | 88 | Add it to your project: 89 | 90 | ```html 91 | 92 | ``` 93 | 94 | 95 | 96 | ## Support: IE11+ 97 | 98 | Current usage for IE 10- is under 1% for each version (8, 9, 10) so it's not Umbrella's mission to support this. However, those extra seconds gained from loading faster on mobile might be even bigger than that percentage. You should probably test it. 99 | 100 | Known, wontfix IE10- bugs: 101 | 102 | - [Invalid target element for this operation](http://caniuse.com/#feat=insertadjacenthtml) when trying to use any of these methods on **table**, **tbody**, **thead** or **tr**. Check [the issue on StackOverflow](http://stackoverflow.com/q/8771498/938236). For those elements, this gives an error: 103 | - `.before()` 104 | - `.after()` 105 | - `.append()` 106 | - `.prepend()` 107 | 108 | 109 | - [Unable to get property ____ of undefined or null reference](http://caniuse.com/#search=classList) since classList is not supported by IE9-. Just use `polyfill.js` and they will work. Affects: 110 | - `.addClass()` 111 | - `.removeClass()` 112 | - `.hasClass()` 113 | - `.toggleClass()` 114 | 115 | - Choosing multiple options within `' 148 | ); 149 | base.on('change', '.cb', function () { 150 | checkboxChanged = true; 151 | if (checkboxChanged && checkboxWrapperChanged) { 152 | done(); 153 | } 154 | }); 155 | base.find('.cb-wrapper').on('change', '.cb', function () { 156 | checkboxWrapperChanged = true; 157 | if (checkboxChanged && checkboxWrapperChanged) { 158 | done(); 159 | } 160 | }); 161 | base.find('.cb').trigger('change'); 162 | base.find('.cb-wrapper').remove(); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /src/plugins/pairs/pairs.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | 3 | // Take the arguments and a couple of callback to handle the getter/setter pairs 4 | // such as: .css('a'), .css('a', 'b'), .css({ a: 'b' }) 5 | u.prototype.pairs = function (name, value, get, set) { 6 | // Convert it into a plain object if it is not 7 | if (typeof value !== 'undefined') { 8 | var nm = name; 9 | name = {}; 10 | name[nm] = value; 11 | } 12 | 13 | if (typeof name === 'object') { 14 | // Set the value of each one, for each of the { prop: value } pairs 15 | return this.each(function (node, i) { 16 | for (var key in name) { 17 | if (typeof name[key] === 'function') { 18 | set(node, key, name[key](node, i)); 19 | } else { 20 | set(node, key, name[key]); 21 | } 22 | } 23 | }); 24 | } 25 | 26 | // Return the style of the first one 27 | return this.length ? get(this.first(), name) : ''; 28 | }; 29 | -------------------------------------------------------------------------------- /src/plugins/param/param.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | 3 | // Parametize an object: { a: 'b', c: 'd' } => 'a=b&c=d' 4 | u.prototype.param = function (obj) { 5 | return Object.keys(obj).map(function (key) { 6 | return this.uri(key) + '=' + this.uri(obj[key]); 7 | }.bind(this)).join('&'); 8 | }; 9 | -------------------------------------------------------------------------------- /src/plugins/parent/parent.js: -------------------------------------------------------------------------------- 1 | // Travel the matched elements one node up 2 | u.prototype.parent = function (selector) { 3 | return this.map(function (node) { 4 | return node.parentNode; 5 | }).filter(selector); 6 | }; 7 | -------------------------------------------------------------------------------- /src/plugins/parent/readme.md: -------------------------------------------------------------------------------- 1 | ## .parent() 2 | 3 | Retrieve each parent of the matched nodes, optionally filtered by a selector 4 | 5 | ```js 6 | .parent() 7 | .parent('p') 8 | .parent(u('p')) 9 | .parent(function(node, i){}) 10 | ``` 11 | 12 | 13 | ### Parameters 14 | 15 | `selector`: Optional filter argument for the parents 16 | 17 | 18 | 19 | ### Examples 20 | 21 | Retrieve all of the parents of `
  • ` in the page: 22 | 23 | ```js 24 | u('li').parent(); 25 | ``` 26 | 27 | Retrieve all the paragraphs that have a link as a direct child 28 | 29 | ```js 30 | u('a').parent('p'); 31 | ``` 32 | 33 | 34 | ### Related 35 | 36 | [.children()](#parent) get all of the direct children 37 | 38 | [.find()](#find) get all of the descendants of the matched nodes 39 | 40 | [.closest()](#closest) get the first ascendant that matches the selector -------------------------------------------------------------------------------- /src/plugins/parent/test.js: -------------------------------------------------------------------------------- 1 | describe('.parent()', function() { 2 | 3 | it('should be defined', function() { 4 | expect(typeof base.parent).to.equal('function'); 5 | }); 6 | 7 | it('can loop the li', function() { 8 | expect(u('li').parent().is('ol, ul')).to.equal(true); 9 | }); 10 | 11 | it('can retrieve the direct parent with a filter', function() { 12 | expect(base.parent('#demo').is('div')).to.equal(true); 13 | }); 14 | 15 | it('will filter out if none is matched', function() { 16 | expect(base.parent('#fake').is('div')).to.equal(false); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/plugins/prepend/prepend.js: -------------------------------------------------------------------------------- 1 | // Add nodes at the beginning of each node 2 | u.prototype.prepend = function (html, data) { 3 | return this.adjacent(html, data, function (node, fragment) { 4 | node.insertBefore(fragment, node.firstChild); 5 | }); 6 | }; 7 | -------------------------------------------------------------------------------- /src/plugins/prepend/readme.md: -------------------------------------------------------------------------------- 1 | ## .prepend() 2 | 3 | Add some html as a child at the beginning of each of the matched elements. 4 | 5 | ```js 6 | .prepend(html) 7 | 8 | .prepend('
    ') 9 | .prepend(u('
    ')) 10 | .prepend(u('
    ').first()) // Same as document.createElement('div') 11 | .prepend(u('
    ').nodes) 12 | .prepend(function(){}) 13 | .prepend(function(el){}, elements) 14 | .prepend(function(el){}, 10) 15 | ``` 16 | 17 | 18 | 19 | ### Parameters 20 | 21 | `html = ""`: 22 | - Any of these elements: 23 | - **string** containing the html that is going to be inserted 24 | - **instance of Umbrella** 25 | - **HTML node** 26 | - **array** containing HTML nodes 27 | - A callback that returns any of the previous. It gets passed these parameters: 28 | - **el**: the current element from the elements parameter, {} if none is specified and i if elements is number 29 | - **i**: the index of the current element 30 | 31 | `elements = [{}]` (optional): It can be any of the following: 32 | - An array of elements that will be passed to the callback. The callback is executed once per element, and all of them are added consecutively. 33 | - A CSS selector, so the function will be executed once per matched element. 34 | - A number, in which case the function will be executed that number of times 35 | 36 | 37 | 38 | ### Return 39 | 40 | `u`: returns the same instance of Umbrella JS 41 | 42 | 43 | 44 | ### Examples 45 | 46 | Add a header to each of the articles 47 | 48 | ```js 49 | u("article").prepend("
    Hello world
    "); 50 | ``` 51 | 52 | Add three elements at the beginning of the list. All of these methods are equivalent: 53 | 54 | ```js 55 | // Add them all like a single string 56 | u("ul").prepend("
  • One
  • Two
  • Three
  • "); 57 | 58 | // Add them in a chain 59 | u("ul").prepend("
  • Three
  • ").append("
  • Two
  • ").append("
  • One
  • "); 60 | 61 | // Add them with a function parameter 62 | var cb = function(txt){ return "
  • " + txt + "
  • " }; 63 | u("ul").prepend(cb, ["One", "Two", "Three"]); 64 | 65 | // Same as the previous one but with ES6 66 | u("ul").prepend(txt => `
  • ${ txt }
  • `, ["One", "Two", "Three"]); 67 | ``` 68 | 69 | They all result in: 70 | 71 | ```html 72 | 79 | ``` 80 | 81 | You can also add some events to them by creating an html node: 82 | 83 | ```js 84 | function greeting(){ alert("Hello world"); } 85 | 86 | u("a.main").prepend(function(){ 87 | return u('').addClass('hi').on('click', greeting).html("Greetings!"); 88 | }); 89 | ``` 90 | 91 | 92 | 93 | ### Related 94 | 95 | [.append()](#append) Add some html as a child at the end of each of the matched elements 96 | 97 | [.before()](#before) Add some html before each of the matched elements. 98 | 99 | [.after()](#after) Add some html as a sibling after each of the matched elements. 100 | -------------------------------------------------------------------------------- /src/plugins/prepend/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".prepend()", function() { 3 | 4 | // Default callback for the tests 5 | function callback(cl){ 6 | return 'Link'; 7 | } 8 | 9 | beforeEach(function(){ 10 | 11 | // Just in case it stringifies the callback 12 | expect(base.html().match('function')).to.equal(null); 13 | expect(u('.bla, .blu').length).to.equal(0); 14 | }); 15 | 16 | afterEach(function(){ 17 | u('.bla, .blu').remove(); 18 | }); 19 | 20 | it("should be a function", function() { 21 | expect(typeof base.prepend).to.equal('function'); 22 | }); 23 | 24 | it("can add content in the right place", function() { 25 | base.prepend('Link'); 26 | size('.base > .bla', 1); 27 | }); 28 | 29 | it("can add content with a callback", function() { 30 | base.prepend(callback); 31 | size('.base > .bla', 1)('.base > .bla:first-child', 1); 32 | }); 33 | 34 | it("is called as many times as data in the second param", function() { 35 | base.prepend('Link', ["a", "b"]); 36 | size('.base > .bla', 2)('.base > .bla:first-child', 1); 37 | }); 38 | 39 | it("can add content inverted with a callback and data", function() { 40 | base.prepend(callback, ["a", "b"]); 41 | //throw "Error"; 42 | size('.base > .bla', 2)('.base > .bla.a', 1)('.base > .bla.b', 1); 43 | size('.bla.a + .bla.b', 1)('.bla.b + .bla.a', 0)('.base > .bla.a:first-child', 1); 44 | }); 45 | 46 | it("can generate some text", function(){ 47 | var list = u("
    "); 48 | if (work) list.prepend (function(n){ return n + "\n" }, ['a', 'b']); 49 | 50 | expect(list.children().length).to.equal(0); 51 | expect(list.html()).to.equal('a\nb\n'); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/plugins/remove/readme.md: -------------------------------------------------------------------------------- 1 | ## .remove() 2 | 3 | Removes the matched elements. 4 | 5 | ```js 6 | .remove(); 7 | ``` 8 | 9 | 10 | ### Parameters 11 | 12 | This method doesn't accept any parameters 13 | 14 | 15 | ### Return 16 | 17 | `u`: Returns an instance of Umbrella JS with the removed nodes. 18 | 19 | 20 | ### Examples 21 | 22 | Remove all the elements of a list: 23 | 24 | ```js 25 | u("ul.demo li").remove(); 26 | ``` 27 | -------------------------------------------------------------------------------- /src/plugins/remove/remove.js: -------------------------------------------------------------------------------- 1 | // Delete the matched nodes from the DOM 2 | u.prototype.remove = function () { 3 | // Loop through all the nodes 4 | return this.each(function (node) { 5 | // Perform the removal only if the node has a parent 6 | if (node.parentNode) { 7 | node.parentNode.removeChild(node); 8 | } 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /src/plugins/remove/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".remove()", function() { 3 | 4 | beforeEach(function() { 5 | base.append('\ 6 | \ 10 | '); 11 | 12 | expect(u('.remove-test').length).to.equal(1); 13 | expect(u('.remove-test li').length).to.equal(2); 14 | }); 15 | 16 | afterEach(function() { 17 | u('.remove-test').remove(); 18 | }); 19 | 20 | 21 | it("should be defined", function() { 22 | expect(typeof base.remove).to.equal('function'); 23 | }); 24 | 25 | it("can be called even without any node", function() { 26 | expect(u('.remove-test div').length).to.equal(0); 27 | u('.remove-test div').remove(); 28 | }); 29 | 30 | it("can be called even without parentNode", function() { 31 | var children = u('.remove-test li'); 32 | children.remove(); 33 | expect(children.first().parentNode).to.be.null; 34 | children.remove(); // Remove them again 35 | }); 36 | 37 | it("should return an instance of umbrella with the removed nodes", function() { 38 | var result = u('.remove-test').remove(); 39 | 40 | expect(result).to.be.instanceof(u); 41 | expect(result.nodes).to.have.length(1); 42 | expect(result.attr('class')).to.equal('remove-test'); 43 | expect(result.children().nodes).to.have.length(2); // Two li children. 44 | }); 45 | 46 | it("removes a single element", function() { 47 | u('.remove-test').remove(); 48 | expect(u('.remove-test').length).to.equal(0); 49 | }); 50 | 51 | it("removes several elements", function() { 52 | u('.remove-test li').remove(); 53 | expect(u('.remove-test li').length).to.equal(0); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/plugins/removeclass/readme.md: -------------------------------------------------------------------------------- 1 | ## .removeClass() 2 | 3 | Remove html class(es) to all of the matched elements. 4 | 5 | ```js 6 | .removeClass('name1'); 7 | .removeClass('name1 name2 nameN'); 8 | .removeClass('name1,name2,nameN'); 9 | .removeClass('name1', 'name2', 'nameN'); 10 | .removeClass(['name1', 'name2', 'nameN']); 11 | .removeClass(['name1', 'name2'], ['name3'], ['nameN']); 12 | .removeClass(function(){ return 'name1'; }); 13 | .removeClass(function(){ return 'name1'; }, function(){ return 'name2'; }); 14 | ``` 15 | 16 | 17 | ### Parameters 18 | 19 | `name1`, `name2`, `nameN`: the class name (or variable containing it) to be removed to all of the matched elements. It accepts many different types of parameters (see above). 20 | 21 | 22 | 23 | ### Return 24 | 25 | `u`: returns the same instance of Umbrella JS 26 | 27 | 28 | 29 | ### Examples 30 | 31 | Remove the class `main` to all the `

    ` from the page: 32 | 33 | ```js 34 | u("h2").removeClass("main"); 35 | ``` 36 | 37 | Remove the class `toValidate` and `ajaxify` to all the `
    ` present in the page: 38 | 39 | ```js 40 | u("form").removeClass("toValidate", "ajaxify"); 41 | ``` 42 | 43 | ### Related 44 | 45 | [.addClass()](#addclass) adds class(es) from the matched elements. 46 | 47 | [.hasClass()](#hasclass) finds if the matched elements contain the class(es) 48 | -------------------------------------------------------------------------------- /src/plugins/removeclass/removeclass.js: -------------------------------------------------------------------------------- 1 | // Removes a class from all of the matched nodes 2 | u.prototype.removeClass = function () { 3 | // Loop the combination of each node with each argument 4 | return this.eacharg(arguments, function (el, name) { 5 | // Remove the class using the native method 6 | el.classList.remove(name); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /src/plugins/removeclass/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".removeClass()", function() { 3 | 4 | //var work = false; 5 | 6 | beforeEach(function(){ 7 | base.addClass('bla blu blo'); 8 | hasClass('bla blu blo'); 9 | }); 10 | 11 | afterEach(function(){ 12 | base.removeClass('bla blu blo'); 13 | hasClass('bla blu blo', true); 14 | }); 15 | 16 | it("should be defined", function() { 17 | isFn(work ? base.removeClass : false); 18 | }); 19 | 20 | it("can be called empty", function() { 21 | base.removeClass(); 22 | base.removeClass(""); 23 | base.removeClass([]); 24 | base.removeClass("",""); 25 | base.removeClass(" "); 26 | 27 | if (!work) throw "Force failure"; 28 | }); 29 | 30 | it("removes a single class", function() { 31 | if (work) base.removeClass('bla'); 32 | hasClass('bla', true); 33 | }); 34 | 35 | it("can be concatenated", function() { 36 | if (work) base.removeClass('bla').removeClass('blu'); 37 | hasClass('bla blu', true); 38 | }); 39 | 40 | 41 | 42 | 43 | describe("single argument", function(){ 44 | base.addClass('bla blu blo'); 45 | listOfClasses.forEach(function(part){ 46 | it("accepts " + part.it, function(){ 47 | if (work) base.removeClass(part.from); 48 | hasClass('bla blu blo', true); 49 | }); 50 | }); 51 | }); 52 | 53 | describe("single function argument uses the return value", function(){ 54 | base.addClass('bla blu blo'); 55 | listOfClasses.forEach(function(part){ 56 | it("accepts as a return value " + part.it, function(){ 57 | if (work) base.removeClass(function() { return part.from; }); 58 | hasClass('bla blu blo', true); 59 | }); 60 | }); 61 | }); 62 | 63 | describe("multiple functions uses the return value", function(){ 64 | function add(arg){ return function(){ return arg; }; } 65 | listOfClasses.forEach(function(part){ 66 | it("accepts as a return value " + part.it, function(){ 67 | if (work) base.removeClass(add(part.from), add("bli")); 68 | hasClass('bla blu blo bli', true); 69 | }); 70 | }); 71 | }); 72 | 73 | describe("several arguments", function(){ 74 | listOfClasses.filter(function(part){ 75 | return Array.isArray(part.from); 76 | }).forEach(function(part){ 77 | it("used .apply() with " + part.it, function(){ 78 | if (work) base.removeClass.apply(base, part.from); 79 | hasClass('bla blu blo', true); 80 | }); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /src/plugins/replace/readme.md: -------------------------------------------------------------------------------- 1 | ## .replace() 2 | 3 | Replace the matched elements with the passed argument. 4 | 5 | ```js 6 | .replace(); 7 | ``` 8 | 9 | ### Parameters 10 | 11 | The parameter can be any of these types: 12 | - string: html tag like `
    ` 13 | - function: a function which returns an html tag. 14 | 15 | 16 | ### Return 17 | 18 | The newly created element. 19 | 20 | 21 | 22 | ### Examples 23 | 24 | Replace elements with class 'save' by a button with class 'update': 25 | 26 | ```js 27 | u('.save').replace(''); 28 | ``` 29 | 30 | Replace element button by a link with class 'button': 31 | 32 | ```js 33 | u('button').replace(function(btn){ 34 | return '' + btn.innerHTML + ''; 35 | }); 36 | ``` 37 | -------------------------------------------------------------------------------- /src/plugins/replace/replace.js: -------------------------------------------------------------------------------- 1 | // Replace the matched elements with the passed argument. 2 | u.prototype.replace = function (html, data) { 3 | var nodes = []; 4 | this.adjacent(html, data, function (node, fragment) { 5 | nodes = nodes.concat(this.slice(fragment.children)); 6 | node.parentNode.replaceChild(fragment, node); 7 | }); 8 | return u(nodes); 9 | }; 10 | -------------------------------------------------------------------------------- /src/plugins/replace/test.js: -------------------------------------------------------------------------------- 1 | // Based on 2 | if(u(document.createDocumentFragment()).append('
    ').children().length == 0) { 3 | Object.defineProperty(DocumentFragment.prototype, "children", {"get" : function() { 4 | var arr = [], 5 | child = this.firstChild; 6 | 7 | while (child) { 8 | if (child.nodeType == 1) arr.push(child); 9 | child = child.nextSibling; 10 | } 11 | 12 | return arr; 13 | }}); 14 | }; 15 | 16 | 17 | // Testing the replace plugin main file 18 | describe(".replace(newValue)", function() { 19 | 20 | afterEach(function(){ 21 | base.find('button.update').remove(); 22 | }); 23 | 24 | it("should be a function", function() { 25 | expect(typeof base.replace).to.equal('function'); 26 | }); 27 | 28 | it("replace the single node string case", function() { 29 | base.append('Save'); 30 | 31 | base.find('a.save').replace(''); 32 | size('.base > button.update', 1); 33 | 34 | base.find('button.update').remove(); 35 | }); 36 | 37 | it("returns the correct values", function(){ 38 | base.append('Save'); 39 | var button = base.find('a.save').replace('').first(); 40 | expect(button.nodeName).to.equal('BUTTON'); 41 | expect(u(button).closest('body').length).to.equal(1); 42 | 43 | 44 | base.find('button.update').remove(); 45 | }); 46 | 47 | it("replace multi nodes string case", function() { 48 | base.append('SaveSave'); 49 | 50 | base.find('a.save').replace(''); 51 | size('.base > button.update', 2); 52 | 53 | base.find('button.update').remove(); 54 | }); 55 | 56 | it("replace the single node function case", function() { 57 | base.append('Save'); 58 | 59 | base.find('a.save').replace(function(link){ 60 | return ''; 61 | }); 62 | size('.base > button.update', 1); 63 | 64 | base.find('button.update').remove(); 65 | }); 66 | 67 | it("replace multi nodes function case", function() { 68 | base.append('SaveSave'); 69 | 70 | base.find('a.save').replace(function(link){ 71 | return ''; 72 | }); 73 | size('.base > button.update', 2); 74 | 75 | base.find('button.update').remove(); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /src/plugins/scroll/readme.md: -------------------------------------------------------------------------------- 1 | ## .scroll() 2 | 3 | Scroll to the first matched element, smoothly if supported. 4 | 5 | ```js 6 | .scroll() 7 | ``` 8 | 9 | 10 | ### Examples 11 | 12 | Scroll to the first `
  • ` in the page: 13 | 14 | ```js 15 | u('li').scroll(); 16 | ``` 17 | 18 | On click event, scroll the first `
    ` element with the class "team": 19 | 20 | ```js 21 | u('a.team').on('click', function(e){ 22 | e.preventDefault(); 23 | u('section.team').scroll(); 24 | }); 25 | ``` 26 | -------------------------------------------------------------------------------- /src/plugins/scroll/scroll.js: -------------------------------------------------------------------------------- 1 | // Scroll to the first matched element 2 | u.prototype.scroll = function () { 3 | var first = this.first(); 4 | 5 | if (first) { 6 | first.scrollIntoView({ behavior: 'smooth' }); 7 | } 8 | 9 | return this; 10 | }; 11 | -------------------------------------------------------------------------------- /src/plugins/scroll/test.js: -------------------------------------------------------------------------------- 1 | // insert tall element to test scroll() 2 | var elHeight = window.innerHeight + 100; 3 | var el = '
    '; 4 | u('body').append(el); 5 | 6 | 7 | describe('.scroll()', function() { 8 | 9 | it('should be a function', function() { 10 | expect(typeof base.scroll).to.equal('function'); 11 | }); 12 | 13 | it('should return this Umbrella Object', function() { 14 | size(u('li').scroll(), u('li').length); 15 | }); 16 | 17 | it('can scroll to the element', function(done) { 18 | expect(u('body').size().top).to.be.above(-10); 19 | u('#scrollTest').scroll(); 20 | 21 | setTimeout(function(){ 22 | expect(u('body').size().top).to.be.below(-10); 23 | u('#scrollTest').remove(); 24 | u('body').scroll(); 25 | done(); 26 | }, 100); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/plugins/select/select.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | // Select the adecuate part from the context 3 | u.prototype.select = function (parameter, context) { 4 | // Allow for spaces before or after 5 | parameter = parameter.replace(/^\s*/, '').replace(/\s*$/, ''); 6 | 7 | if (/^').length).to.equal(1); 30 | expect(u('
    ').first().nodeName).to.equal('DIV'); 31 | }); 32 | 33 | it("can create many elements", function(){ 34 | expect(u('

    ').length).to.equal(2); 35 | expect(u('

    ').first().nodeName).to.equal('P'); 36 | }); 37 | 38 | it("can have spaces before or after", function(){ 39 | expect(u('

    ').length).to.equal(2); 40 | expect(u('

    ').first().nodeName).to.equal('P'); 41 | 42 | expect(u('

    ').length).to.equal(2); 43 | expect(u('

    ').first().nodeName).to.equal('P'); 44 | }); 45 | 46 | it("can create table stuff", function() { 47 | size('Hello
    ', 1); 48 | size('Hello', 1); 49 | size('Hello', 1); 50 | size('Hello', 1); 51 | }); 52 | 53 | it("can create list stuff", function() { 54 | size('
    • A
    ', 1); 55 | size('
  • B
  • ', 1); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/plugins/serialize/readme.md: -------------------------------------------------------------------------------- 1 | ## .serialize() 2 | 3 | > Note: you probably want to use the native `FormData()` instead of `.serialize()`. [See relevant issue](https://github.com/franciscop/umbrella/issues/114). 4 | 5 | Converts a form into a string to be sent: 6 | 7 | ```js 8 | .serialize() 9 | ``` 10 | 11 | > Note: multiple-select are not supported in Internet Explorer, [similarly to jQuery](https://github.com/jquery/jquery-mobile/issues/3947) 12 | 13 | ### Example 14 | 15 | For this form: 16 | 17 | ```html 18 | 19 | Email: 20 | 21 | Message: 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | When the user clicks on the "Send" button, the following handler can be used to send the data through Ajax: 29 | 30 | ```js 31 | // .handle() == .on() + preventDefault() 32 | u('form.contact').handle('submit', async e => { 33 | // Body: email=test@example.com&message=Hello+world 34 | const body = u(e.target).serialize(); 35 | const data = await fetch('/contact', { 36 | method: 'POST', body 37 | }).then(res => res.json()); 38 | console.log('Response data:', data); 39 | }); 40 | ``` 41 | 42 | If you were using the native FormData: 43 | 44 | ```js 45 | // .handle() == .on() + preventDefault() 46 | u('form.contact').handle('submit', async e => { 47 | const body = new FormData(e.target); 48 | const data = await fetch('/contact', { 49 | method: 'POST', body 50 | }).then(res => res.json()); 51 | console.log('Response data:', data); 52 | }); 53 | ``` 54 | -------------------------------------------------------------------------------- /src/plugins/serialize/serialize.js: -------------------------------------------------------------------------------- 1 | // Convert forms into a string able to be submitted 2 | // Original source: http://stackoverflow.com/q/11661187 3 | u.prototype.serialize = function () { 4 | var self = this; 5 | 6 | // Store the class in a variable for manipulation 7 | return this.slice(this.first().elements).reduce(function (query, el) { 8 | // We only want to match enabled elements with names, but not files 9 | if (!el.name || el.disabled || el.type === 'file') return query; 10 | 11 | // Ignore the checkboxes that are not checked 12 | if (/(checkbox|radio)/.test(el.type) && !el.checked) return query; 13 | 14 | // Handle multiple selects 15 | if (el.type === 'select-multiple') { 16 | u(el.options).each(function (opt) { 17 | if (opt.selected) { 18 | query += '&' + self.uri(el.name) + '=' + self.uri(opt.value); 19 | } 20 | }); 21 | return query; 22 | } 23 | 24 | // Add the element to the object 25 | return query + '&' + self.uri(el.name) + '=' + self.uri(el.value); 26 | }, '').slice(1); 27 | }; 28 | -------------------------------------------------------------------------------- /src/plugins/serialize/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".serialize()", function() { 3 | 4 | afterEach(function() { 5 | u('.serialize-test').remove(); 6 | }); 7 | 8 | 9 | it("should be defined", function() { 10 | expect(typeof u('.serialize-test').serialize).to.equal('function'); 11 | }); 12 | 13 | it("can handle arrays", function() { 14 | base.append('\ 15 |
    \ 16 | \ 17 | \ 18 |
    \ 19 | '); 20 | expect(u('.serialize-test').serialize()).to.equal('test%5B%5D=a&test%5B%5D=b'); 21 | }); 22 | 23 | 24 | 25 | it("can handle select multiple", function() { 26 | base.append('\ 27 |
    \ 28 | \ 33 |
    \ 34 | '); 35 | expect(u('.serialize-test').serialize()).to.equal('select=a&select=b'); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/plugins/siblings/readme.md: -------------------------------------------------------------------------------- 1 | ## .siblings() 2 | 3 | Get the siblings of all of the nodes with an optional filter 4 | 5 | ```js 6 | .siblings(selector); 7 | ``` 8 | 9 | 10 | ### Parameters 11 | 12 | `selector`: a string containing a selector that nodes must pass or a function that return a boolean. See [.filter()](#selector) for a better explanation 13 | 14 | 15 | 16 | ### Return 17 | 18 | `u`: returns an instance of Umbrella JS with the new siblings as nodes 19 | 20 | 21 | 22 | ### Examples 23 | 24 | Get the all the siblings of the hovered `
  • ` 25 | 26 | ```js 27 | u("li:hover").siblings('li:first-child'); 28 | ``` 29 | 30 | Get all the siblings 31 | 32 | ```js 33 | u("li").siblings(); 34 | ``` 35 | 36 | 37 | 38 | ### Related 39 | 40 | [.parent()](#parent) get all of the direct parents 41 | 42 | [.find()](#find) get all of the descendants of the matched nodes 43 | 44 | [.closest()](#closest) get the first ascendant that matches the selector 45 | 46 | [.children()](#closest) get the direct children of all of the nodes with an optional filter 47 | -------------------------------------------------------------------------------- /src/plugins/siblings/siblings.js: -------------------------------------------------------------------------------- 1 | // Travel the matched elements at the same level 2 | u.prototype.siblings = function (selector) { 3 | return this.parent().children(selector).not(this); 4 | }; 5 | -------------------------------------------------------------------------------- /src/plugins/siblings/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".siblings(selector)", function() { 3 | 4 | beforeEach(function() { 5 | base.append('\ 6 |
      \ 7 |
    • \ 8 |
    • \ 9 |
    • \ 10 |
    \ 11 |
      \ 12 |
    • \ 13 |
    • \ 14 |
    • \ 15 |
    \ 16 | '); 17 | 18 | expect(u('.siblings-test').nodes.length).to.equal(2); 19 | expect(u('.siblings-test li').nodes.length).to.equal(6); 20 | }); 21 | 22 | afterEach(function() { 23 | u('.siblings-test').remove(); 24 | expect(u('.siblings-test').nodes.length).to.equal(0); 25 | }); 26 | 27 | it("should be a function", function() { 28 | expect(typeof base.siblings).to.equal('function'); 29 | }); 30 | 31 | it("can select multiple siblings", function() { 32 | expect(base.find('#siblings-2').siblings().nodes.length).to.equal(2); 33 | }); 34 | 35 | it("can filter the siblings", function() { 36 | expect(base.find('#siblings-1').siblings('#siblings-2').nodes.length).to.equal(1); 37 | }); 38 | 39 | it("can handle non existant siblings ", function() { 40 | expect(base.find('#siblings-2').siblings('.nonexist').nodes.length).to.equal(0); 41 | }); 42 | 43 | it("can handle multiple nodes", function() { 44 | expect(base.find('.siblings-test').children('.selected').siblings().nodes.length).to.equal(4); 45 | }); 46 | }); -------------------------------------------------------------------------------- /src/plugins/size/readme.md: -------------------------------------------------------------------------------- 1 | ## .size() 2 | 3 | Get the [bounding client rect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) of the first matched element. This has height, width, top, left, right and bottom properties 4 | 5 | ```js 6 | .size() 7 | ``` 8 | 9 | ### Parameters 10 | 11 | None 12 | 13 | 14 | ### Return 15 | 16 | Returns a simple object with the following properties referring to the first matched element, or `null` if there is no one: 17 | 18 | - left 19 | - right 20 | - top 21 | - height 22 | - bottom 23 | - width 24 | 25 | 26 | 27 | 28 | ### Examples 29 | 30 | ```js 31 | u('body').size(); 32 | // {"left":0,"right":400,"top":0,"height":300,"bottom":300,"width":400} 33 | 34 | u().size() 35 | // null 36 | ``` 37 | -------------------------------------------------------------------------------- /src/plugins/size/size.js: -------------------------------------------------------------------------------- 1 | // Find the size of the first matched element 2 | u.prototype.size = function () { 3 | var first = this.first(); 4 | 5 | return first ? first.getBoundingClientRect() : null; 6 | }; 7 | -------------------------------------------------------------------------------- /src/plugins/size/test.js: -------------------------------------------------------------------------------- 1 | describe('.size()', function() { 2 | 3 | it('should be a function', function() { 4 | expect(typeof base.size).to.equal('function'); 5 | }); 6 | 7 | it('should return this Umbrella Object', function() { 8 | size(u('li').scroll(), u('li').length); 9 | }); 10 | 11 | it('can get the right size', function() { 12 | var size = u('body').size(); 13 | expect(size).to.deep.equal(u('body').first().getBoundingClientRect()); 14 | }); 15 | 16 | it('can get the height', function() { 17 | var size = u('body').size(); 18 | expect(Math.round(size.height)).to.equal(u('body').first().clientHeight); 19 | }); 20 | 21 | it('should return null for an empty Umbrella instance', function() { 22 | expect(u().size()).to.equal(null); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/plugins/slice/slice.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | 3 | // Force it to be an array AND also it clones them 4 | // http://toddmotto.com/a-comprehensive-dive-into-nodelists-arrays-converting-nodelists-and-understanding-the-dom/ 5 | u.prototype.slice = function (pseudo) { 6 | // Check that it's not a valid object 7 | if (!pseudo || 8 | pseudo.length === 0 || 9 | typeof pseudo === 'string' || 10 | pseudo.toString() === '[object Function]') return []; 11 | 12 | // Accept also a u() object (that has .nodes) 13 | return pseudo.length ? [].slice.call(pseudo.nodes || pseudo) : [pseudo]; 14 | }; 15 | -------------------------------------------------------------------------------- /src/plugins/slice/test.js: -------------------------------------------------------------------------------- 1 | describe(".slice()", function() { 2 | 3 | it("should be a function", function() { 4 | expect(typeof base.slice).to.equal('function'); 5 | }); 6 | 7 | it("can be called empty", function() { 8 | same(base.slice(), []); 9 | same(base.slice(''), []); 10 | same(base.slice(null), []); 11 | same(base.slice(undefined), []); 12 | same(base.slice(false), []); 13 | }); 14 | 15 | it("can slice an array", function() { 16 | same(base.slice(['a', 'b']), ['a', 'b']); 17 | }); 18 | 19 | it("ignores a string", function() { 20 | same(base.slice('Hello world'), []); 21 | }); 22 | 23 | it("ignores a function", function() { 24 | same(base.slice(function(){}), []); 25 | }); 26 | 27 | it("accepts a simple number", function() { 28 | same(base.slice(5), [5]); 29 | }); 30 | 31 | it("converts a simple object to array", function() { 32 | same(base.slice({ a: 'b' }), [{ a: 'b' }]); 33 | }); 34 | 35 | it("accepts an XMLRequest", function() { 36 | var request = new XMLHttpRequest; 37 | same(base.slice(request), [request]); 38 | }); 39 | 40 | it("accepts the document", function() { 41 | same(base.slice(document), [document]); 42 | }); 43 | 44 | it("accepts an argument list", function() { 45 | (function(){ 46 | same(base.slice(arguments), ['a', 'b']); 47 | })('a', 'b'); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/plugins/str/str.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | 3 | // Create a string from different things 4 | u.prototype.str = function (node, i) { 5 | return function (arg) { 6 | // Call the function with the corresponding nodes 7 | if (typeof arg === 'function') { 8 | return arg.call(this, node, i); 9 | } 10 | 11 | // From an array or other 'weird' things 12 | return arg.toString(); 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /src/plugins/text/readme.md: -------------------------------------------------------------------------------- 1 | ## .text() 2 | 3 | Retrieve or set the text content of matched elements: 4 | 5 | 6 | ```js 7 | // GET 8 | .text(); 9 | 10 | // SET 11 | .text(text); 12 | ``` 13 | 14 | 15 | ### Parameters 16 | 17 | *GET* 18 | should pass no parameter so it retrieves the text from the first matched element. 19 | 20 | *SET* 21 | `html`: the new text content that you want to set for all of the matched elements. To remove it, pass an empty string: `""` 22 | 23 | 24 | 25 | ### Return 26 | 27 | *GET* 28 | `string`: the text content of the first matched element 29 | 30 | *SET* 31 | `u`: returns the same instance of Umbrella JS 32 | 33 | 34 | 35 | ### Examples 36 | 37 | Get the main title text: 38 | 39 | ```js 40 | var title = u('h1').text(); 41 | ``` 42 | 43 | Set the main title text: 44 | 45 | ```js 46 | u('h1').text('Hello world'); 47 | ``` 48 | 49 | 50 | ### Related 51 | 52 | [.html()](#html) Retrieve or set the HTML of matched elements 53 | -------------------------------------------------------------------------------- /src/plugins/text/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".text(content)", function() { 3 | 4 | it("should be a function", function() { 5 | expect(typeof base.hasClass).to.equal('function'); 6 | }); 7 | 8 | it("can get the text content", function() { 9 | expect(base.find('#world').text()).to.equal('Hello world'); 10 | }); 11 | 12 | it("can set the text content", function() { 13 | expect(base.find('#world').text()).not.to.equal('hello!'); 14 | base.find('#world').text('hello!'); 15 | expect(base.find('#world').text()).to.equal('hello!'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/plugins/text/text.js: -------------------------------------------------------------------------------- 1 | // Set or retrieve the text content from the matched node(s) 2 | u.prototype.text = function (text) { 3 | // Needs to check undefined as it might be "" 4 | if (text === undefined) { 5 | return this.first().textContent || ''; 6 | } 7 | 8 | // If we're attempting to set some text 9 | // Loop through all the nodes 10 | return this.each(function (node) { 11 | // Set the text content to the node 12 | node.textContent = text; 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/plugins/toggleclass/readme.md: -------------------------------------------------------------------------------- 1 | ## .toggleClass() 2 | 3 | Toggles html class(es) to all of the matched elements. 4 | 5 | ```js 6 | .toggleClass('name1'); 7 | .toggleClass('name1 name2 nameN'); 8 | .toggleClass('name1,name2,nameN'); 9 | .toggleClass(['name1', 'name2', 'nameN']); 10 | .toggleClass('name1', forceAdd); 11 | ``` 12 | 13 | ### Parameters 14 | 15 | `name1`, `name2`, `nameN`: the class name (or variable containing it) to be toggled to all of the matched elements. It accepts many different types of parameters (see above). 16 | 17 | `forceAdd`: boolean telling the method whether to force an `.addClass()` (true) or `.removeClass()` (false). 18 | 19 | 20 | 21 | ### Return 22 | 23 | `u`: returns the same instance of Umbrella JS 24 | 25 | 26 | 27 | ### Examples 28 | 29 | Add the class `main` to all the `

    ` from the page: 30 | 31 | ```js 32 | u("h2").toggleClass("main"); 33 | ``` 34 | 35 | Add the class `toValidate` and remove `ajaxify` from the element `
    ` present in the page: 36 | 37 | ```js 38 | u("form.ajaxify").toggleClass("toValidate ajaxify"); 39 | ``` 40 | 41 | Force an `.addClass()` on the element `

    ` from the page: 42 | 43 | ```js 44 | u("h2").toggleClass("main", true); 45 | ``` 46 | 47 | Note however that this last example by itself doesn't make much sense as you could just use `addClass()` instead. It makes a lot more sense when the second parameter is checked dynamically: 48 | 49 | ```js 50 | u("h2").toggleClass("main", u('.accept').is(':checked')); 51 | ``` 52 | 53 | 54 | 55 | ### Related 56 | 57 | [.addClass()](#addclass) adds class(es) from the matched elements. 58 | 59 | [.removeClass()](#removeclass) deletes class(es) from the matched elements. 60 | 61 | [.hasClass()](#hasclass) finds if the matched elements contain the class(es) 62 | -------------------------------------------------------------------------------- /src/plugins/toggleclass/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".toggleClass(name1, name2, ...)", function() { 3 | 4 | beforeEach(function(){ 5 | base.addClass('blu'); 6 | expect(base.hasClass('bla')).to.equal(false); 7 | expect(base.hasClass('blu')).to.equal(true); 8 | }); 9 | 10 | afterEach(function(){ 11 | base.removeClass('bla'); 12 | base.addClass('blu'); 13 | }); 14 | 15 | it("should be defined", function() { 16 | expect(typeof base.toggleClass).to.equal('function'); 17 | }); 18 | 19 | it("can be called empty", function() { 20 | base.toggleClass(); 21 | base.toggleClass(""); 22 | base.toggleClass([]); 23 | base.toggleClass("",""); 24 | base.toggleClass(" "); 25 | }); 26 | 27 | it("adds a class by toggling", function() { 28 | base.toggleClass('bla'); 29 | expect(base.hasClass('bla')).to.equal(true); 30 | }); 31 | 32 | it("removes a class by toggling", function() { 33 | base.toggleClass('blu'); 34 | expect(base.hasClass('blu')).to.equal(false); 35 | }); 36 | 37 | it("can be concatenated", function() { 38 | base.toggleClass('bla').toggleClass('bla'); 39 | expect(base.hasClass('bla')).to.equal(false); 40 | }); 41 | 42 | it("can do double toggle and stays the same", function() { 43 | base.toggleClass('bla bla'); 44 | expect(base.hasClass('bla')).to.equal(false); 45 | }); 46 | 47 | it("toggles several classes separated by comma", function() { 48 | len = base.toggleClass('bla,blu').length; 49 | expect(len).to.equal(1); 50 | }); 51 | 52 | 53 | // Second Parameter 54 | it("can be called with a second parameter to force a addClass", function() { 55 | base.toggleClass('blu', true); 56 | expect(base.hasClass('blu')).to.equal(true); 57 | }); 58 | 59 | it("can be called with a second parameter to force a removeClass", function() { 60 | base.toggleClass('blu', false); 61 | expect(base.hasClass('blu')).to.equal(false); 62 | }); 63 | 64 | it("ignores the second parameter if string", function() { 65 | base.toggleClass('blu', 'peter'); 66 | expect(base.hasClass('blu')).to.equal(false); 67 | expect(base.hasClass('peter')).to.equal(false); 68 | 69 | base.toggleClass('blu', 'peter'); 70 | expect(base.hasClass('blu')).to.equal(true); 71 | }); 72 | 73 | it("ignores the second parameter if falsy but not false", function() { 74 | base.toggleClass('blu', null); 75 | expect(base.hasClass('blu')).to.equal(false); 76 | 77 | base.toggleClass('blu', null); 78 | expect(base.hasClass('blu')).to.equal(true); 79 | 80 | base.toggleClass('blu', undefined); 81 | expect(base.hasClass('blu')).to.equal(false); 82 | 83 | base.toggleClass('blu', undefined); 84 | expect(base.hasClass('blu')).to.equal(true); 85 | 86 | base.toggleClass('blu', 0); 87 | expect(base.hasClass('blu')).to.equal(false); 88 | 89 | base.toggleClass('blu', 0); 90 | expect(base.hasClass('blu')).to.equal(true); 91 | 92 | base.toggleClass('blu', ''); 93 | expect(base.hasClass('blu')).to.equal(false); 94 | 95 | base.toggleClass('blu', ''); 96 | expect(base.hasClass('blu')).to.equal(true); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /src/plugins/toggleclass/toggleclass.js: -------------------------------------------------------------------------------- 1 | // Activate/deactivate classes in the elements 2 | u.prototype.toggleClass = function (classes, addOrRemove) { 3 | /* jshint -W018 */ 4 | // Check if addOrRemove was passed as a boolean 5 | if (!!addOrRemove === addOrRemove) { 6 | return this[addOrRemove ? 'addClass' : 'removeClass'](classes); 7 | } 8 | /* jshint +W018 */ 9 | 10 | // Loop through all the nodes and classes combinations 11 | return this.eacharg(classes, function (el, name) { 12 | el.classList.toggle(name); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/plugins/trigger/readme.md: -------------------------------------------------------------------------------- 1 | ## .trigger() 2 | 3 | Calls an event on all of the matched nodes 4 | 5 | ```js 6 | .trigger('event1', data) 7 | .trigger('event1 event2 eventN', data1, data2, dataN) 8 | .trigger('event1,event2,eventN', data1, data2, dataN) 9 | .trigger(['event1', 'event2', 'eventN'], data1, data2, dataN) 10 | ``` 11 | 12 | 13 | 14 | ### Parameters 15 | 16 | `event1`, `event2`, `eventN`: the name(s) of the events to listen for actions, such as `click`, `submit`, `change`, etc. 17 | 18 | `data1`, `data2`, `dataN` (optional): the data that will be passed to the event listener in the `e.details` variable and as arguments. 19 | 20 | 21 | ### Return 22 | 23 | Umbrella instance 24 | 25 | 26 | 27 | ### Examples 28 | 29 | An auto-save feature that submits the form through AJAX every 10 seconds 30 | 31 | ```js 32 | // Submit it every 10s 33 | setInterval(function(){ 34 | u('button.save').trigger('click'); 35 | }, 10000); 36 | ``` 37 | 38 | 39 | ### Related 40 | 41 | [.on()](#on) add an event listener to the matched nodes 42 | 43 | [.handle()](#off) Same as `.on()`, but it prevents the default action 44 | 45 | [.off()](#off) Removes an event from matched nodes 46 | -------------------------------------------------------------------------------- /src/plugins/trigger/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".trigger()", function() { 3 | 4 | afterEach(function(){ 5 | base.off('click bla'); 6 | }); 7 | 8 | it("should be a function", function() { 9 | isFn(base.trigger); 10 | }); 11 | 12 | it("can trigger a click", function() { 13 | base.on('click', function(e){ 14 | expect(!!e).to.equal(true); 15 | }); 16 | base.trigger('click'); 17 | }); 18 | 19 | it("can be concatenated", function() { 20 | base.on('click', function(e){ 21 | expect(!!e).to.equal(true); 22 | }); 23 | base.trigger('click').trigger('click'); 24 | }); 25 | 26 | it("can trigger an event in the wrong element", function() { 27 | base.on('click', function(e){ 28 | expect(!!e).to.equal(true); 29 | }); 30 | base.trigger('click'); 31 | }); 32 | 33 | it("doesn't trigger all events", function() { 34 | base.on('click', function(e){ 35 | throw "Shouldn't be called"; 36 | }); 37 | base.trigger('submit'); 38 | }); 39 | 40 | it("triggers custom event", function(done) { 41 | base.on('bla', function(e){ 42 | expect(!!e).to.equal(true); 43 | done(); 44 | }); 45 | base.trigger('bla'); 46 | }); 47 | 48 | it("passes data", function(done) { 49 | base.on('click', function(e, go){ 50 | expect(!!e).to.equal(true); 51 | same(e.detail, ["good"]); 52 | same(go, "good"); 53 | done(); 54 | }); 55 | base.trigger('click', 'good'); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/plugins/trigger/trigger.js: -------------------------------------------------------------------------------- 1 | // Call an event manually on all the nodes 2 | u.prototype.trigger = function (events) { 3 | var data = this.slice(arguments).slice(1); 4 | 5 | return this.eacharg(events, function (node, event) { 6 | var ev; 7 | 8 | // Allow the event to bubble up and to be cancelable (as default) 9 | var opts = { bubbles: true, cancelable: true, detail: data }; 10 | 11 | try { 12 | // Accept different types of event names or an event itself 13 | ev = new window.CustomEvent(event, opts); 14 | } catch (e) { 15 | ev = document.createEvent('CustomEvent'); 16 | ev.initCustomEvent(event, true, true, data); 17 | } 18 | 19 | node.dispatchEvent(ev); 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /src/plugins/unique/unique.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | 3 | // Removed duplicated nodes, used for some specific methods 4 | u.prototype.unique = function () { 5 | return u(this.nodes.reduce(function (clean, node) { 6 | var istruthy = node !== null && node !== undefined && node !== false; 7 | return (istruthy && clean.indexOf(node) === -1) ? clean.concat(node) : clean; 8 | }, [])); 9 | }; 10 | -------------------------------------------------------------------------------- /src/plugins/uri/uri.js: -------------------------------------------------------------------------------- 1 | // [INTERNAL USE ONLY] 2 | 3 | // Encode the different strings https://gist.github.com/brettz9/7147458 4 | u.prototype.uri = function (str) { 5 | return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+'); 6 | }; 7 | -------------------------------------------------------------------------------- /src/plugins/wrap/readme.md: -------------------------------------------------------------------------------- 1 | ## .wrap() 2 | 3 | Wraps the matched element(s) with the passed argument. The argument gets processed with the constructor u() and it accepts an html tag like ```.wrap('
    ')``` 4 | 5 | ```js 6 | .wrap(selector); 7 | ``` 8 | 9 | 10 | ### Parameters 11 | 12 | `selector`: a formatted string of the desired selector. For example ```.wrap('
    ')```. Nested selectors are supported in a similar way to [jQuery wrap](http://api.jquery.com/wrap/). For example ```.wrap('
    ')```. Matched element(s) will be wrapped with innermost node of the first child of a nested argument. See examples below. 13 | 14 | 15 | 16 | ### Return 17 | 18 | `u`: returns an instance of Umbrella JS with the wrapped node(s) 19 | 20 | 21 | 22 | ### Examples 23 | 24 | Wrap an element in an html element: 25 | 26 | Original element: 27 | ```html 28 | Link1 29 | ``` 30 | 31 | ```js 32 | u(".example").wrap(''); 33 | ``` 34 | 35 | Result: 36 | ```html 37 | 38 | Link1 39 | 40 | ``` 41 | 42 | Wrap an element in an html element and chain Umbrella methods: 43 | 44 | ```js 45 | u(".example").wrap('').attr({class: "wrapper", href: "http://google.com"}); 46 | ``` 47 | 48 | Result: 49 | ```html 50 | 51 | Link1 52 | 53 | ``` 54 | 55 | Wrap several elements in an html element 56 | 57 | ```html 58 | Link1 59 | Link2 60 | Link3 61 | 62 | ``` 63 | 64 | ```js 65 | u(".example").wrap('').attr({class: "wrapper", href: "http://google.com"}); 66 | ``` 67 | 68 | Result: 69 | ```html 70 | 71 | Link1 72 | 73 | 74 | Link2 75 | 76 | 77 | Link3 78 | 79 | ``` 80 | 81 | Nested selector arguments: 82 | 83 | ```html 84 | Link1 85 | ``` 86 | 87 | ```js 88 | u(".example").wrap('
    '); 89 | ``` 90 | 91 | Result: 92 | ```html 93 |
    94 |
    95 | 100 |
    101 |
    102 | ``` 103 | 104 | Nested selector arguments with multiple child nodes: 105 | 106 | ```html 107 | Link1 108 | ``` 109 | 110 | ```js 111 | u(".example").wrap('
    '); 112 | ``` 113 | 114 | Result: 115 | ```html 116 |
    117 |
    118 | 123 |
    124 |
    125 |
    126 |
    127 |
    128 |
    129 |
    130 | ``` 131 | -------------------------------------------------------------------------------- /src/plugins/wrap/test.js: -------------------------------------------------------------------------------- 1 | // Testing the main file 2 | describe(".wrap()", function() { 3 | beforeEach(function(){ 4 | base.append(''); 5 | size('.base > .example', 1); 6 | }); 7 | 8 | afterEach(function(){ 9 | u('.example, .example-wrapper').remove(); 10 | }); 11 | 12 | it("should be a function", function() { 13 | expect(typeof base.wrap).to.equal('function'); 14 | }); 15 | 16 | it("should correctly wrap a single element using a chained umbrella.js function", function() { 17 | u('.example').wrap('').attr({ href: 'http://google.com/', class: 'example-wrapper' }); 18 | size('.example-wrapper > .example', 1); 19 | }); 20 | 21 | it("should correctly wrap a single formatted selector", function() { 22 | u('.example').wrap(''); 23 | size('.example-wrapper > .example', 1); 24 | }); 25 | 26 | it("should wrap multiple elements using a chained umbrella.js function", function() { 27 | base.append(''); 28 | 29 | u('.example').wrap('').addClass('example-wrapper'); 30 | size('.example-wrapper .example', 2); 31 | }); 32 | 33 | it("when wrapping multiple elements it should return a copy of the original node", function() { 34 | base.append(''); 35 | 36 | var wrappedNodes = u('.example').wrap('').addClass('example-wrapper'); 37 | expect(wrappedNodes.nodes[0].innerText).to.equal('Link1') 38 | expect(wrappedNodes.nodes[1].innerText).to.equal('Link2') 39 | }); 40 | 41 | it("should add all specified attributes to the wrapper element using a chained umbrella js function", function() { 42 | u('.example').wrap('').attr({ href: 'http://google.com/', class: 'example-wrapper' }); 43 | expect(u('.example-wrapper').attr('href')).to.equal('http://google.com/'); 44 | }); 45 | 46 | it("should add all specified attributes to the wrapper element using a formatted selector", function() { 47 | u('.example').wrap(''); 48 | expect(u('.example-wrapper').attr('href')).to.equal('http://google.com/'); 49 | }); 50 | 51 | it("should support nested selector arguments", function() { 52 | u('.example').wrap('
    '); 53 | size('#one #two .example', 1); 54 | }); 55 | 56 | it("should support nested selector arguments with more than one nested child", function() { 57 | u('.example').wrap('
    '); 58 | size('#a1 #b1 #c1 .example', 1); 59 | }); 60 | 61 | it("should only append to the last child of the nested selector argument's first child", function() { 62 | u('.example').wrap('
    '); 63 | size('#a2 #b2 #c2 #d1 .example', 0); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /src/plugins/wrap/wrap.js: -------------------------------------------------------------------------------- 1 | u.prototype.wrap = function (selector) { 2 | function findDeepestNode (node) { 3 | while (node.firstElementChild) { 4 | node = node.firstElementChild; 5 | } 6 | 7 | return u(node); 8 | } 9 | // 1) Construct dom node e.g. u('
    '), 10 | // 2) clone the currently matched node 11 | // 3) append cloned dom node to constructed node based on selector 12 | return this.map(function (node) { 13 | return u(selector).each(function (n) { 14 | findDeepestNode(n) 15 | .append(node.cloneNode(true)); 16 | 17 | node 18 | .parentNode 19 | .replaceChild(n, node); 20 | }); 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | Find nodes from the HTML with a CSS selector: 4 | 5 | ```js 6 | u('ul#demo li') 7 | u(document.getElementById('demo')) 8 | u(document.getElementsByClassName('demo')) 9 | u([ document.getElementById('demo') ]) 10 | u( u('ul li') ) 11 | u('') 12 | u('li', context) 13 | ``` 14 | 15 | 16 | ### Parameters 17 | 18 | The first parameter can be: 19 | 20 | - A text CSS selector 21 | - A single HTML Node. This is specially useful in events where you can just pass `this` 22 | - A NodeList or other similar objects that can be converted to an array 23 | - An array of nodes* 24 | - Another Umbrella instance 25 | - An HTML fragment as a string 26 | - Nothing 27 | 28 | The second parameter is only for the CSS selector, which indicates a portion of the DOM where the selector is applied. For example, with `u('li', u('ul').first())` it will find all of the `li` from the first `ul`. 29 | 30 | 31 | \* actually it can be an array of anything you want as in `["a", "b"]`, however this is not officially supported and might change at any moment 32 | 33 | > You *should* use `u('#demo')` instead of `u(document.getElementById('demo'))`, internally it's optimized to do this in a fast way. That was only an example of what's possible. 34 | 35 | 36 | ### Return 37 | 38 | An instance of Umbrella JS so you can chain it to any of the other methods. 39 | 40 | 41 | 42 | ### Examples 43 | 44 | Select all of the list elements that are children of `ul` 45 | 46 | ```js 47 | var lis = u('ul > li'); // Same as u('ul').children('li'); 48 | ``` 49 | 50 | Find all of the headers from the page to create a Table of Contents: 51 | 52 | ```js 53 | var headers = u('h1, h2, h3, h4, h5, h6'); 54 | ``` 55 | 56 | Generate a link on the fly: 57 | 58 | ```js 59 | var link = u('').addClass('main').attr({ href: '/hello' }); 60 | ``` 61 | 62 | You can use this to generate many kind of elements on the fly. For example, for a simple grocery list (using ES6 for simplicity): 63 | 64 | ```js 65 | var fruits = ['apple', 'strawberry', 'pear', 'banana']; 66 | var list = u('