From 0bef58a8a4b155e0f8f06d4b987f32e2a845ca1c Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 7 Jan 2016 13:05:36 -0500 Subject: [PATCH] Added a fixture that has submodules. --- .../git/repo-with-submodules/.gitmodules | 6 + spec/fixtures/git/repo-with-submodules/README | 0 .../You-Dont-Need-jQuery/.babelrc | 3 + .../You-Dont-Need-jQuery/.eslintrc | 18 + .../You-Dont-Need-jQuery/.gitignore | 5 + .../You-Dont-Need-jQuery/.travis.yml | 10 + .../You-Dont-Need-jQuery/LICENSE | 22 + .../You-Dont-Need-jQuery/README-es.md | 637 +++++++++ .../You-Dont-Need-jQuery/README-id.md | 634 +++++++++ .../You-Dont-Need-jQuery/README-it.md | 651 +++++++++ .../You-Dont-Need-jQuery/README-my.md | 615 +++++++++ .../You-Dont-Need-jQuery/README-ru.md | 650 +++++++++ .../You-Dont-Need-jQuery/README-tr.md | 665 +++++++++ .../You-Dont-Need-jQuery/README-vi.md | 634 +++++++++ .../You-Dont-Need-jQuery/README.ko-KR.md | 709 ++++++++++ .../You-Dont-Need-jQuery/README.md | 1190 +++++++++++++++++ .../You-Dont-Need-jQuery/README.pt-BR.md | 628 +++++++++ .../You-Dont-Need-jQuery/README.zh-CN.md | 656 +++++++++ .../You-Dont-Need-jQuery/git.git | 1 + .../You-Dont-Need-jQuery/karma.conf.js | 92 ++ .../You-Dont-Need-jQuery/package.json | 53 + .../You-Dont-Need-jQuery/test/README.md | 13 + .../You-Dont-Need-jQuery/test/css.spec.js | 1 + .../You-Dont-Need-jQuery/test/dom.spec.js | 1 + .../You-Dont-Need-jQuery/test/query.spec.js | 71 + .../test/utilities.spec.js | 1 + .../git.git/COMMIT_EDITMSG | 9 + .../git/repo-with-submodules/git.git/HEAD | 1 + .../git/repo-with-submodules/git.git/config | 11 + .../repo-with-submodules/git.git/description | 1 + .../git.git/hooks/applypatch-msg.sample | 15 + .../git.git/hooks/commit-msg.sample | 24 + .../git.git/hooks/post-update.sample | 8 + .../git.git/hooks/pre-applypatch.sample | 14 + .../git.git/hooks/pre-commit.sample | 49 + .../git.git/hooks/pre-push.sample | 53 + .../git.git/hooks/pre-rebase.sample | 169 +++ .../git.git/hooks/prepare-commit-msg.sample | 36 + .../git.git/hooks/update.sample | 128 ++ .../git/repo-with-submodules/git.git/index | Bin 0 -> 377 bytes .../repo-with-submodules/git.git/info/exclude | 6 + .../repo-with-submodules/git.git/logs/HEAD | 2 + .../git.git/logs/refs/heads/master | 2 + .../git.git/modules/You-Dont-Need-jQuery/HEAD | 1 + .../modules/You-Dont-Need-jQuery/ORIG_HEAD | 1 + .../modules/You-Dont-Need-jQuery/config | 14 + .../modules/You-Dont-Need-jQuery/description | 1 + .../modules/You-Dont-Need-jQuery/gitdir | 1 + .../hooks/applypatch-msg.sample | 15 + .../hooks/commit-msg.sample | 24 + .../hooks/post-update.sample | 8 + .../hooks/pre-applypatch.sample | 14 + .../hooks/pre-commit.sample | 49 + .../hooks/pre-push.sample | 53 + .../hooks/pre-rebase.sample | 169 +++ .../hooks/prepare-commit-msg.sample | 36 + .../You-Dont-Need-jQuery/hooks/update.sample | 128 ++ .../modules/You-Dont-Need-jQuery/index | Bin 0 -> 1919 bytes .../modules/You-Dont-Need-jQuery/info/exclude | 6 + .../modules/You-Dont-Need-jQuery/logs/HEAD | 1 + .../logs/refs/heads/master | 1 + .../logs/refs/remotes/origin/HEAD | 1 + ...8b3bc339acd655e8dae9c0dcea8bb2ec174d16.idx | Bin 0 -> 18152 bytes ...b3bc339acd655e8dae9c0dcea8bb2ec174d16.pack | Bin 0 -> 202626 bytes .../modules/You-Dont-Need-jQuery/packed-refs | 2 + .../You-Dont-Need-jQuery/refs/heads/master | 1 + .../refs/remotes/origin/HEAD | 1 + .../git.git/modules/jstips/HEAD | 1 + .../git.git/modules/jstips/ORIG_HEAD | 1 + .../git.git/modules/jstips/config | 14 + .../git.git/modules/jstips/description | 1 + .../git.git/modules/jstips/gitdir | 1 + .../jstips/hooks/applypatch-msg.sample | 15 + .../modules/jstips/hooks/commit-msg.sample | 24 + .../modules/jstips/hooks/post-update.sample | 8 + .../jstips/hooks/pre-applypatch.sample | 14 + .../modules/jstips/hooks/pre-commit.sample | 49 + .../modules/jstips/hooks/pre-push.sample | 53 + .../modules/jstips/hooks/pre-rebase.sample | 169 +++ .../jstips/hooks/prepare-commit-msg.sample | 36 + .../modules/jstips/hooks/update.sample | 128 ++ .../git.git/modules/jstips/index | Bin 0 -> 427 bytes .../git.git/modules/jstips/info/exclude | 6 + .../git.git/modules/jstips/logs/HEAD | 1 + .../modules/jstips/logs/refs/heads/master | 1 + .../jstips/logs/refs/remotes/origin/HEAD | 1 + ...68a55e02b6b7b75582924204669e4f3ed5276f.idx | Bin 0 -> 6728 bytes ...8a55e02b6b7b75582924204669e4f3ed5276f.pack | Bin 0 -> 1081001 bytes .../git.git/modules/jstips/packed-refs | 2 + .../git.git/modules/jstips/refs/heads/master | 1 + .../modules/jstips/refs/remotes/origin/HEAD | 1 + .../3e/2fe2f8226faab789f70d6d8a7231e4f2bd54df | Bin 0 -> 165 bytes .../40/f4e79926a85134d4c905d04e70573b6616f3bc | Bin 0 -> 126 bytes .../50/b89367d8f0acd312ef5aa012eac20a75c91351 | Bin 0 -> 85 bytes .../54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd | Bin 0 -> 51 bytes .../d2/b0ad9cbc6f6c4372e8956e5cc5af771b2342e5 | Bin 0 -> 156 bytes .../d3/e073baf592c56614c68ead9e2cd0a3880140cd | 1 + .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin 0 -> 15 bytes .../git.git/refs/heads/master | 1 + .../jstips/CONTRIBUTING.md | 20 + .../git/repo-with-submodules/jstips/README.md | 323 +++++ .../git/repo-with-submodules/jstips/git.git | 1 + .../jstips/resources/jstips-header-blog.gif | Bin 0 -> 1061017 bytes .../jstips/resources/log.js | 3 + 104 files changed, 9897 insertions(+) create mode 100644 spec/fixtures/git/repo-with-submodules/.gitmodules create mode 100644 spec/fixtures/git/repo-with-submodules/README create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.babelrc create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.eslintrc create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.gitignore create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.travis.yml create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/LICENSE create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-es.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-id.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-it.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-my.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-ru.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-tr.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-vi.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.ko-KR.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.pt-BR.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.zh-CN.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/git.git create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/karma.conf.js create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/package.json create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/README.md create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/css.spec.js create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/dom.spec.js create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/query.spec.js create mode 100644 spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/utilities.spec.js create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/COMMIT_EDITMSG create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/config create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/description create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/applypatch-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/commit-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/post-update.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-applypatch.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-commit.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-push.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-rebase.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/prepare-commit-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/hooks/update.sample create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/index create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/info/exclude create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/logs/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/logs/refs/heads/master create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/ORIG_HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/config create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/description create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/gitdir create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/applypatch-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/commit-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/post-update.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-applypatch.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-commit.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-push.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-rebase.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/prepare-commit-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/update.sample create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/index create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/info/exclude create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/heads/master create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/remotes/origin/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/objects/pack/pack-d38b3bc339acd655e8dae9c0dcea8bb2ec174d16.idx create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/objects/pack/pack-d38b3bc339acd655e8dae9c0dcea8bb2ec174d16.pack create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/packed-refs create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/refs/heads/master create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/refs/remotes/origin/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/ORIG_HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/config create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/description create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/gitdir create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/applypatch-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/commit-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/post-update.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/pre-applypatch.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/pre-commit.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/pre-push.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/pre-rebase.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/prepare-commit-msg.sample create mode 100755 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/hooks/update.sample create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/index create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/info/exclude create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/logs/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/logs/refs/heads/master create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/logs/refs/remotes/origin/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/objects/pack/pack-e568a55e02b6b7b75582924204669e4f3ed5276f.idx create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/objects/pack/pack-e568a55e02b6b7b75582924204669e4f3ed5276f.pack create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/packed-refs create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/refs/heads/master create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/modules/jstips/refs/remotes/origin/HEAD create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/3e/2fe2f8226faab789f70d6d8a7231e4f2bd54df create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/40/f4e79926a85134d4c905d04e70573b6616f3bc create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/50/b89367d8f0acd312ef5aa012eac20a75c91351 create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/54/3b9bebdc6bd5c4b22136034a95dd097a57d3dd create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/d2/b0ad9cbc6f6c4372e8956e5cc5af771b2342e5 create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/d3/e073baf592c56614c68ead9e2cd0a3880140cd create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 create mode 100644 spec/fixtures/git/repo-with-submodules/git.git/refs/heads/master create mode 100644 spec/fixtures/git/repo-with-submodules/jstips/CONTRIBUTING.md create mode 100644 spec/fixtures/git/repo-with-submodules/jstips/README.md create mode 100644 spec/fixtures/git/repo-with-submodules/jstips/git.git create mode 100644 spec/fixtures/git/repo-with-submodules/jstips/resources/jstips-header-blog.gif create mode 100644 spec/fixtures/git/repo-with-submodules/jstips/resources/log.js diff --git a/spec/fixtures/git/repo-with-submodules/.gitmodules b/spec/fixtures/git/repo-with-submodules/.gitmodules new file mode 100644 index 000000000..40f4e7992 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/.gitmodules @@ -0,0 +1,6 @@ +[submodule "jstips"] + path = jstips + url = https://github.com/loverajoel/jstips +[submodule "You-Dont-Need-jQuery"] + path = You-Dont-Need-jQuery + url = https://github.com/oneuijs/You-Dont-Need-jQuery diff --git a/spec/fixtures/git/repo-with-submodules/README b/spec/fixtures/git/repo-with-submodules/README new file mode 100644 index 000000000..e69de29bb diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.babelrc b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.babelrc new file mode 100644 index 000000000..e2472af86 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.babelrc @@ -0,0 +1,3 @@ +{ + presets: ["es2015", "stage-0"] +} diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.eslintrc b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.eslintrc new file mode 100644 index 000000000..46faa7c5f --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.eslintrc @@ -0,0 +1,18 @@ +{ + "extends": "eslint-config-airbnb", + "env": { + "browser": true, + "mocha": true, + "node": true + }, + "rules": { + "valid-jsdoc": 2, + "no-param-reassign": 0, + "comma-dangle": 0, + "one-var": 0, + "no-else-return": 1, + "no-unused-expressions": 0, + "indent": 1, + "eol-last": 0 + } +} diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.gitignore b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.gitignore new file mode 100644 index 000000000..539682cbf --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +*.log +node_modules +coverage +logs diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.travis.yml b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.travis.yml new file mode 100644 index 000000000..69cf1679a --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: + - "5" + - "4" +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start +script: + - npm run lint + - npm test diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/LICENSE b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/LICENSE new file mode 100644 index 000000000..df3175928 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 oneuijs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-es.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-es.md new file mode 100644 index 000000000..652124255 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-es.md @@ -0,0 +1,637 @@ + +> #### You Don't Need jQuery + +Tú no necesitas jQuery +--- +El desarrollo Frontend evoluciona día a día, y los navegadores modernos ya han implementado nativamente APIs para trabajar con DOM/BOM, las cuales son muy buenas, por lo que definitivamente no es necesario aprender jQuery desde cero para manipular el DOM. En la actualidad, gracias al surgimiento de librerías frontend como React, Angular y Vue, manipular el DOM es contrario a los patrones establecidos, y jQuery se ha vuelto menos importante. Este proyecto resume la mayoría de métodos alternativos a jQuery, pero de forma nativa con soporte IE 10+. + +## Tabla de Contenidos + +1. [Query Selector](#query-selector) +1. [CSS & Estilo](#css--estilo) +1. [Manipulación DOM](#manipulación-dom) +1. [Ajax](#ajax) +1. [Eventos](#eventos) +1. [Utilidades](#utilidades) +1. [Traducción](#traducción) +1. [Soporte de Navegadores](#soporte-de-navegadores) + + +## Query Selector + +En lugar de los selectores comunes como clase, id o atributos podemos usar `document.querySelector` o `document.querySelectorAll` como alternativas. Las diferencias radican en: +* `document.querySelector` devuelve el primer elemento que cumpla con la condición +* `document.querySelectorAll` devuelve todos los elementos que cumplen con la condición en forma de NodeList. Puede ser convertido a Array usando `[].slice.call(document.querySelectorAll(selector) || []);` +* Si ningún elemento cumple con la condición, jQuery retornaría `[]` mientras la API DOM retornaría `null`. Nótese el NullPointerException. Se puede usar `||` para establecer el valor por defecto al no encontrar elementos, como en `document.querySelectorAll(selector) || []` + +> Notice: `document.querySelector` and `document.querySelectorAll` are quite **SLOW**, try to use `getElementById`, `document.getElementsByClassName` o `document.getElementsByTagName` if you want to Obtener a performance bonus. + +- [1.0](#1.0) Buscar por selector + + ```js + // jQuery + $('selector'); + + // Nativo + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Buscar por Clase + + ```js + // jQuery + $('.class'); + + // Nativo + document.querySelectorAll('.class'); + + // Forma alternativa + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Buscar por id + + ```js + // jQuery + $('#id'); + + // Nativo + document.querySelector('#id'); + + // Forma alternativa + document.getElementById('id'); + ``` + +- [1.3](#1.3) Buscar por atributo + + ```js + // jQuery + $('a[target=_blank]'); + + // Nativo + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Buscar + + + Buscar nodos + + ```js + // jQuery + $el.find('li'); + + // Nativo + el.querySelectorAll('li'); + ``` + + + Buscar "body" + + ```js + // jQuery + $('body'); + + // Nativo + document.body; + ``` + + + Buscar Atributo + + ```js + // jQuery + $el.attr('foo'); + + // Nativo + e.getAttribute('foo'); + ``` + + + Buscar atributo "data" + + ```js + // jQuery + $el.data('foo'); + + // Nativo + // Usando getAttribute + el.getAttribute('data-foo'); + // También puedes utilizar `dataset` desde IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Elementos Hermanos/Previos/Siguientes + + + Elementos hermanos + + ```js + // jQuery + $el.siblings(); + + // Nativo + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Elementos previos + + ```js + // jQuery + $el.prev(); + + // Nativo + el.previousElementSibling; + ``` + + + Elementos siguientes + + ```js + // jQuery + $el.next(); + + // Nativo + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Retorna el elemento más cercano que coincida con la condición, partiendo desde el nodo actual hasta document. + + ```js + // jQuery + $el.closest(queryString); + + // Nativo + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + Obtiene los ancestros de cada elemento en el set actual de elementos que cumplan con la condición, sin incluir el actual + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Nativo + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // Partir desde el elemento padre + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Formularios + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Nativo + document.querySelector('#my-input').value; + ``` + + + Obtener el índice de e.currentTarget en `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Nativo + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Contenidos de Iframe + + `$('iframe').contents()` devuelve `contentDocument` para este iframe específico + + + Contenidos de Iframe + + ```js + // jQuery + $iframe.contents(); + + // Nativo + iframe.contentDocument; + ``` + + + Buscar dentro de un Iframe + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Nativo + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ volver al inicio](#tabla-de-contenidos)** + +## CSS & Estilo + +- [2.1](#2.1) CSS + + + Obtener Estilo + + ```js + // jQuery + $el.css("color"); + + // Nativo + // NOTA: Bug conocido, retornará 'auto' si el valor de estilo es 'auto' + const win = el.ownerDocument.defaultView; + // null significa que no tiene pseudo estilos + win.getComputedStyle(el, null).color; + ``` + + + Establecer style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Nativo + el.style.color = '#ff0011'; + ``` + + + Obtener/Establecer Estilos + + Nótese que si se desea establecer múltiples estilos a la vez, se puede utilizar el método [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) en el paquete oui-dom-utils. + + + Agregar clase + + ```js + // jQuery + $el.addClass(className); + + // Nativo + el.classList.add(className); + ``` + + + Quitar Clase + + ```js + // jQuery + $el.removeClass(className); + + // Nativo + el.classList.remove(className); + ``` + + + Consultar si tiene clase + + ```js + // jQuery + $el.hasClass(className); + + // Nativo + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Nativo + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Width & Height + + Ancho y Alto son teóricamente idénticos. Usaremos el Alto como ejemplo: + + + Alto de Ventana + + ```js + // alto de ventana + $(window).height(); + // Sin scrollbar, se comporta como jQuery + window.document.documentElement.clientHeight; + // Con scrollbar + window.innerHeight; + ``` + + + Alto de Documento + + ```js + // jQuery + $(document).height(); + + // Nativo + document.documentElement.scrollHeight; + ``` + + + Alto de Elemento + + ```js + // jQuery + $el.height(); + + // Nativo + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // Precisión de integer(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.clientHeight; + // Precisión de decimal(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Posición & Offset + + + Posición + + ```js + // jQuery + $el.position(); + + // Nativo + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Nativo + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Posición del Scroll Vertical + + ```js + // jQuery + $(window).scrollTop(); + + // Nativo + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ volver al inicio](#tabla-de-contenidos)** + +## Manipulación DOM + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Nativo + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Obtener Texto + + ```js + // jQuery + $el.text(); + + // Nativo + el.textContent; + ``` + + + Establecer Texto + + ```js + // jQuery + $el.text(string); + + // Nativo + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Obtener HTML + + ```js + // jQuery + $el.html(); + + // Nativo + el.innerHTML; + ``` + + + Establecer HTML + + ```js + // jQuery + $el.html(htmlString); + + // Nativo + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + Añadir elemento hijo después del último hijo del elemento padre + + ```js + // jQuery + $el.append("
hello
"); + + // Nativo + el.insertAdjacentHTML("beforeend","
hello
"); + ``` + +- [3.5](#3.5) Prepend + + Añadir elemento hijo después del último hijo del elemento padre + + ```js + // jQuery + $el.prepend("
hello
"); + + // Nativo + el.insertAdjacentHTML("afterbegin","
hello
"); + ``` + +- [3.6](#3.6) insertBefore + + Insertar un nuevo nodo antes del primero de los elementos seleccionados + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Nativo + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Insertar un nuevo nodo después de los elementos seleccionados + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Nativo + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +**[⬆ volver al inicio](#tabla-de-contenidos)** + +## Ajax + +Reemplazar con [fetch](https://github.com/camsong/fetch-ie8) y [fetch-jsonp](https://github.com/camsong/fetch-jsonp) ++[Fetch API](https://fetch.spec.whatwg.org/) es el nuevo estándar quue reemplaza a XMLHttpRequest para efectuar peticiones AJAX. Funciona en Chrome y Firefox, como también es posible usar un polyfill en otros navegadores. ++ ++Es una buena alternativa utilizar [github/fetch](http://github.com/github/fetch) en IE9+ o [fetch-ie8](https://github.com/camsong/fetch-ie8/) en IE8+, [fetch-jsonp](https://github.com/camsong/fetch-jsonp) para efectuar peticiones JSONP. +**[⬆ volver al inicio](#tabla-de-contenidos)** + +## Eventos + +Para un reemplazo completo con namespace y delegación, utilizar https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Asignar un evento con "on" + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Nativo + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Desasignar un evento con "off" + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Nativo + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Nativo + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ volver al inicio](#tabla-de-contenidos)** + +## Utilidades + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Nativo + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Nativo + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + Utilizar polyfill para object.assign https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Nativo + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Nativo + el !== child && el.contains(child); + ``` + +**[⬆ volver al inicio](#tabla-de-contenidos)** + +## Traducción + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) + +## Soporte de Navegadores + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Última ✔ | Última ✔ | 10+ ✔ | Última ✔ | 6.1+ ✔ | + +# Licencia + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-id.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-id.md new file mode 100644 index 000000000..13ca75b6c --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-id.md @@ -0,0 +1,634 @@ +## Anda tidak memerlukan jQuery + +Dewasa ini perkembangan environment frontend sangatlah pesat, dimana banyak browser sudah mengimplementasikan DOM/BOM APIs dengan baik. Kita tidak perlu lagi belajar jQuery dari nol untuk keperluan manipulasi DOM atau events. Disaat yang sama; dengan berterimakasih kepada library frontend terkini seperti React, Angular dan Vue; Memanipulasi DOM secara langsung telah menjadi anti-pattern alias sesuatu yang tidak perlu dilakukan. Dengan kata lain, jQuery sekarang menjadi semakin tidak diperlukan. Projek ini memberikan informasi mengenai metode alternatif dari jQuery untuk implementasi Native dengan support untuk browser IE 10+. + + +## Daftar Isi + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css-style) +1. [DOM Manipulation](#dom-manipulation) +1. [Ajax](#ajax) +1. [Events](#events) +1. [Utilities](#utilities) +1. [Translation](#translation) +1. [Browser Support](#browser-yang-di-support) + +## Query Selector + +Untuk selector-selector umum seperti class, id atau attribute, kita dapat menggunakan `document.querySelector` atau `document.querySelectorAll` sebagai pengganti. Perbedaan diantaranya adalah: +* `document.querySelector` mengembalikan elemen pertama yang cocok +* `document.querySelectorAll` mengembalikan semua elemen yang cocok sebagai NodeList. Hasilnya bisa dikonversikan menjadi Array `[].slice.call(document.querySelectorAll(selector) || []);` +* Bila tidak ada hasil pengembalian elemen yang cocok, jQuery akan mengembalikan `[]` sedangkan DOM API akan mengembalikan `null`. Mohon diperhatikan mengenai Null Pointer Exception. Anda juga bisa menggunakan operator `||` untuk set nilai awal jika hasil pencarian tidak ditemukan : `document.querySelectorAll(selector) || []` + +> Perhatian: `document.querySelector` dan `document.querySelectorAll` sedikit **LAMBAT**. Silahkan menggunakan `getElementById`, `document.getElementsByClassName` atau `document.getElementsByTagName` jika anda menginginkan tambahan performa. + +- [1.0](#1.0) Query by selector + + ```js + // jQuery + $('selector'); + + // Native + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Query by class + + ```js + // jQuery + $('.class'); + + // Native + document.querySelectorAll('.class'); + + // or + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Query by id + + ```js + // jQuery + $('#id'); + + // Native + document.querySelector('#id'); + + // or + document.getElementById('id'); + ``` + +- [1.3](#1.3) Query menggunakan attribute + + ```js + // jQuery + $('a[target=_blank]'); + + // Native + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Pencarian. + + + Mencari nodes + + ```js + // jQuery + $el.find('li'); + + // Native + el.querySelectorAll('li'); + ``` + + + Mencari body + + ```js + // jQuery + $('body'); + + // Native + document.body; + ``` + + + Mencari Attribute + + ```js + // jQuery + $el.attr('foo'); + + // Native + e.getAttribute('foo'); + ``` + + + Mencari data attribute + + ```js + // jQuery + $el.data('foo'); + + // Native + // gunakan getAttribute + el.getAttribute('data-foo'); + // anda juga bisa menggunakan `dataset` bila anda perlu support IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Elemen-elemen Sibling/Previous/Next + + + Elemen Sibling + + ```js + // jQuery + $el.siblings(); + + // Native + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Elemen Previous + + ```js + // jQuery + $el.prev(); + + // Native + el.previousElementSibling; + + ``` + + + Elemen Next + + ```js + // next + $el.next(); + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Mengembalikan elemen pertama yang cocok dari selector yang digunakan, dengan cara mencari mulai dari elemen-sekarang sampai ke document. + + ```js + // jQuery + $el.closest(queryString); + + // Native + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + Digunakan untuk mendapatkan "ancestor" dari setiap elemen yang ditemukan. Namun tidak termasuk elemen-sekarang yang didapat dari pencarian oleh selector, DOM node, atau object jQuery. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Native + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + Get index of e.currentTarget between `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Native + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + `$('iframe').contents()` mengembalikan `contentDocument` + + + Iframe contents + + ```js + // jQuery + $iframe.contents(); + + // Native + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Native + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ back to top](#daftar-isi)** + +## CSS Style + +- [2.1](#2.1) CSS + + + Get style + + ```js + // jQuery + $el.css("color"); + + // Native + // PERHATIAN: ada bug disini, dimana fungsi ini akan mengembalikan nilai 'auto' bila nilai dari atribut style adalah 'auto' + const win = el.ownerDocument.defaultView; + // null artinya tidak mengembalikan pseudo styles + win.getComputedStyle(el, null).color; + ``` + + + Set style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Native + el.style.color = '#ff0011'; + ``` + + + Get/Set Styles + + Mohon dicatat jika anda ingin men-set banyak style bersamaan, anda dapat menemukan referensi di metode [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) pada package oui-dom-utils + + + Add class + + ```js + // jQuery + $el.addClass(className); + + // Native + el.classList.add(className); + ``` + + + Remove class + + ```js + // jQuery + $el.removeClass(className); + + // Native + el.classList.remove(className); + ``` + + + has class + + ```js + // jQuery + $el.hasClass(className); + + // Native + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Native + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Width & Height + + Secara teori, width dan height identik, contohnya Height: + + + Window height + + ```js + // window height + $(window).height(); + // without scrollbar, behaves like jQuery + window.document.documentElement.clientHeight; + // with scrollbar + window.innerHeight; + ``` + + + Document height + + ```js + // jQuery + $(document).height(); + + // Native + document.documentElement.scrollHeight; + ``` + + + Element height + + ```js + // jQuery + $el.height(); + + // Native + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // accurate to integer(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.clientHeight; + // accurate to decimal(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Native + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Native + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Native + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ back to top](#daftar-isi)** + +## DOM Manipulation + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Native + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Get text + + ```js + // jQuery + $el.text(); + + // Native + el.textContent; + ``` + + + Set text + + ```js + // jQuery + $el.text(string); + + // Native + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Get HTML + + ```js + // jQuery + $el.html(); + + // Native + el.innerHTML; + ``` + + + Set HTML + + ```js + // jQuery + $el.html(htmlString); + + // Native + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + Menambahkan elemen-anak setelah anak terakhir dari elemen-parent + + ```js + // jQuery + $el.append("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.appendChild(newEl); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.insertBefore(newEl, el.firstChild); + ``` + +- [3.6](#3.6) insertBefore + + Memasukkan node baru sebelum elemen yang dipilih. + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Memasukkan node baru sesudah elemen yang dipilih. + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +**[⬆ back to top](#daftar-isi)** + +## Ajax + +Gantikan dengan [fetch](https://github.com/camsong/fetch-ie8) dan [fetch-jsonp](https://github.com/camsong/fetch-jsonp) + +**[⬆ back to top](#daftar-isi)** + +## Events + +Untuk penggantian secara menyeluruh dengan namespace dan delegation, rujuk ke https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Bind event dengan menggunakan on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Native + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Unbind event dengan menggunakan off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Native + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Native + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ back to top](#daftar-isi)** + +## Utilities + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Native + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Native + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + Extend, use object.assign polyfill https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Native + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Native + el !== child && el.contains(child); + ``` + +**[⬆ back to top](#daftar-isi)** + +## Terjemahan + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) + +## Browser yang di Support + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# License + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-it.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-it.md new file mode 100644 index 000000000..2af89202a --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-it.md @@ -0,0 +1,651 @@ +## Non hai bisogno di jQuery + +Il mondo del Frontend si evolve rapidamente oggigiorno, i browsers moderni hanno gia' implementato un'ampia gamma di DOM/BOM API soddisfacenti. Non dobbiamo imparare jQuery dalle fondamenta per la manipolazione del DOM o di eventi. Nel frattempo, grazie al prevalicare di librerie per il frontend come React, Angular a Vue, manipolare il DOM direttamente diventa un anti-pattern, di consequenza jQuery non e' mai stato meno importante. Questo progetto sommarizza la maggior parte dei metodi e implementazioni alternative a jQuery, con il supporto di IE 10+. + +## Tabella contenuti + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css--style) +1. [Manipolazione DOM](#manipolazione-dom) +1. [Ajax](#ajax) +1. [Eventi](#eventi) +1. [Utilities](#utilities) +1. [Alternative](#alternative) +1. [Traduzioni](#traduzioni) +1. [Supporto Browsers](#supporto-browsers) + +## Query Selector + +Al posto di comuni selettori come class, id o attributi possiamo usare `document.querySelector` o `document.querySelectorAll` per sostituzioni. La differenza risiede in: +* `document.querySelector` restituisce il primo elemento combiaciante +* `document.querySelectorAll` restituisce tutti gli elementi combiacianti della NodeList. Puo' essere convertito in Array usando `[].slice.call(document.querySelectorAll(selector) || []);` +* Se nessun elemento combiacia, jQuery restituitirebbe `[]` li' dove il DOM API ritornera' `null`. Prestate attenzione al Null Pointer Exception. Potete anche usare `||` per settare valori di default se non trovato, come `document.querySelectorAll(selector) || []` + +> Notare: `document.querySelector` e `document.querySelectorAll` sono abbastanza **SLOW**, provate ad usare `getElementById`, `document.getElementsByClassName` o `document.getElementsByTagName` se volete avere un bonus in termini di performance. + +- [1.0](#1.0) Query da selettore + + ```js + // jQuery + $('selector'); + + // Nativo + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Query da classe + + ```js + // jQuery + $('.class'); + + // Nativo + document.querySelectorAll('.class'); + + // or + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Query da id + + ```js + // jQuery + $('#id'); + + // Nativo + document.querySelector('#id'); + + // o + document.getElementById('id'); + ``` + +- [1.3](#1.3) Query da attributo + + ```js + // jQuery + $('a[target=_blank]'); + + // Nativo + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Trovare qualcosa. + + + Trovare nodes + + ```js + // jQuery + $el.find('li'); + + // Nativo + el.querySelectorAll('li'); + ``` + + + Trovare body + + ```js + // jQuery + $('body'); + + // Nativo + document.body; + ``` + + + Trovare Attributi + + ```js + // jQuery + $el.attr('foo'); + + // Nativo + e.getAttribute('foo'); + ``` + + + Trovare attributo data + + ```js + // jQuery + $el.data('foo'); + + // Nativo + // using getAttribute + el.getAttribute('data-foo'); + // potete usare `dataset` solo se supportate IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Fratelli/Precedento/Successivo Elemento + + + Elementi fratelli + + ```js + // jQuery + $el.siblings(); + + // Nativo + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Elementi precedenti + + ```js + // jQuery + $el.prev(); + + // Nativo + el.previousElementSibling; + ``` + + + Elementi successivi + + ```js + // jQuery + $el.next(); + + // Nativo + el.nextElementSibling; + ``` + +- [1.6](#1.6) Il piu' vicino + + Restituisce il primo elementi combiaciante il selettore fornito, attraversando dall'elemento corrente fino al document . + + ```js + // jQuery + $el.closest(queryString); + + // Nativo - Solo ultimo, NO IE + el.closest(selector); + + // Nativo - IE10+ + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Fino a parenti + + Ottiene il parente di ogni elemento nel set corrente di elementi combiacianti, fino a ma non incluso, l'elemento combiaciante il selettorer, DOM node, o jQuery object. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Nativo + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // il match parte dal parente + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + Get index of e.currentTarget between `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Nativo + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + `$('iframe').contents()` restituisce `contentDocument` per questo specifico iframe + + + Iframe contenuti + + ```js + // jQuery + $iframe.contents(); + + // Nativo + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Nativo + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ back to top](#table-of-contents)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + Ottenere style + + ```js + // jQuery + $el.css("color"); + + // Nativo + // NOTA: Bug conosciuto, restituira' 'auto' se il valore di style e' 'auto' + const win = el.ownerDocument.defaultView; + // null significa che non restituira' lo psuedo style + win.getComputedStyle(el, null).color; + ``` + + + Settare style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Nativo + el.style.color = '#ff0011'; + ``` + + + Ottenere/Settare Styles + + Nota che se volete settare styles multipli in una sola volta, potete riferire [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) metodo in oui-dom-utils package. + + + + Aggiungere classe + + ```js + // jQuery + $el.addClass(className); + + // Nativo + el.classList.add(className); + ``` + + + Rimouvere class + + ```js + // jQuery + $el.removeClass(className); + + // Nativo + el.classList.remove(className); + ``` + + + has class + + ```js + // jQuery + $el.hasClass(className); + + // Nativo + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Nativo + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Width & Height + + Width e Height sono teoricamente identici, prendendo Height come esempio: + + + Window height + + ```js + // window height + $(window).height(); + // senza scrollbar, si comporta comporta jQuery + window.document.documentElement.clientHeight; + // con scrollbar + window.innerHeight; + ``` + + + Document height + + ```js + // jQuery + $(document).height(); + + // Nativo + document.documentElement.scrollHeight; + ``` + + + Element height + + ```js + // jQuery + $el.height(); + + // Nativo + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // preciso a intero(quando `border-box`, e' `height`; quando `content-box`, e' `height + padding + border`) + el.clientHeight; + // preciso a decimale(quando `border-box`, e' `height`; quando `content-box`, e' `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Nativo + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Nativo + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Nativo + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Manipolazione DOM + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Nativo + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Get text + + ```js + // jQuery + $el.text(); + + // Nativo + el.textContent; + ``` + + + Set text + + ```js + // jQuery + $el.text(string); + + // Nativo + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Ottenere HTML + + ```js + // jQuery + $el.html(); + + // Nativo + el.innerHTML; + ``` + + + Settare HTML + + ```js + // jQuery + $el.html(htmlString); + + // Nativo + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + appendere elemento figlio dopo l'ultimo elemento figlio del genitore + + ```js + // jQuery + $el.append("
hello
"); + + // Nativo + el.insertAdjacentHTML("beforeend","
hello
"); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Nativo + el.insertAdjacentHTML("afterbegin","
hello
"); + ``` + +- [3.6](#3.6) insertBefore + + Inserire un nuovo node dopo l'elmento selezionato + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Nativo + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Insert a new node after the selected elements + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Nativo + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +- [3.8](#3.8) is + + Restituisce `true` se combacia con l'elemento selezionato + + ```js + // jQuery - Notare `is` funziona anche con `function` o `elements` non di importanza qui + $el.is(selector); + + // Nativo + el.matches(selector); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Ajax + +Sostituire con [fetch](https://github.com/camsong/fetch-ie8) and [fetch-jsonp](https://github.com/camsong/fetch-jsonp) + +**[⬆ back to top](#table-of-contents)** + +## Eventi + +Per una completa sostituzione con namespace e delegation, riferire a https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Bind un evento con on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Nativo + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Unbind an event with off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Nativo + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Nativo + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Utilities + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Nativo + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Nativo + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + Extend, usa object.assign polyfill https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Nativo + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Nativo + el !== child && el.contains(child); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Alternative + +* [Forse non hai bisogno di jQuery](http://youmightnotneedjquery.com/) - Esempi di come creare eventi comuni, elementi, ajax etc usando puramente javascript. +* [npm-dom](http://github.com/npm-dom) e [webmodules](http://github.com/webmodules) - Organizzazione dove puoi trovare moduli per il DOM individuale su NPM + +## Traduzioni + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Italiano](./README-it.md) +* [Türkçe](./README-tr.md) + +## Supporto Browsers + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Ultimo ✔ | Ultimo ✔ | 10+ ✔ | Ultimo ✔ | 6.1+ ✔ | + +# Licenza + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-my.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-my.md new file mode 100644 index 000000000..1f0a759c3 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-my.md @@ -0,0 +1,615 @@ +## Anda tidak memerlukan jQuery + +Mutakhir ini perkembangan dalam persekitaran frontend berlaku begitu pesat sekali. Justeru itu kebanyakan pelayar moden telahpun menyediakan API yang memadai untuk pengaksesan DOM/BOM. Kita tak payah lagi belajar jQuery dari asas untuk memanipulasi DOM dan acara-acara. Projek ini menawarkan perlaksanaan alternatif kepada kebanyakan kaedah-kaedah jQuery yang menyokong IE 10+. + +## Isi Kandungan + +1. [Pemilihan elemen](#pemilihan-elemen) +1. [CSS & Penggayaan](#css-penggayaan) +1. [Manipulasi DOM](#manipulasi-dom) +1. [Ajax](#ajax) +1. [Events](#events) +1. [Utiliti](#utiliti) +1. [Terjemahan](#terjemahan) +1. [Browser Support](#browser-support) + +## Pemilihan Elemen + +Pemilihan elemen yang umum seperti class, id atau atribut, biasanya kita boleh pakai `document.querySelector` atau `document.querySelectorAll` sebagai ganti. Bezanya terletak pada +* `document.querySelector` akan mengembalikan elemen pertama sekali yang sepadan dijumpai +* `document.querySelectorAll` akan mengembalikan kesemua elemen yang sepadan dijumpai kedalam sebuah NodeList. Ia boleh ditukar kedalam bentuk array menggunakan `[].slice.call` +* Sekiranya tiada elemen yang sepadan dijumpai, jQuery akan mengembalikan `[]` dimana API DOM pula akan mengembalikan `null`. Sila ambil perhatian pada Null Pointer Exception + +> AWAS: `document.querySelector` dan `document.querySelectorAll` agak **LEMBAB** berbanding `getElementById`, `document.getElementsByClassName` atau `document.getElementsByTagName` jika anda menginginkan bonus dari segi prestasi. + +- [1.1](#1.1) Pemilihan menggunakan class + + ```js + // jQuery + $('.css'); + + // Native + document.querySelectorAll('.css'); + ``` + +- [1.2](#1.2) Pemilihan menggunakan id + + ```js + // jQuery + $('#id'); + + // Native + document.querySelector('#id'); + ``` + +- [1.3](#1.3) Pemilihan menggunakan atribut + + ```js + // jQuery + $('a[target=_blank]'); + + // Native + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Cari sth. + + + Find nodes + + ```js + // jQuery + $el.find('li'); + + // Native + el.querySelectorAll('li'); + ``` + + + Cari body + + ```js + // jQuery + $('body'); + + // Native + document.body; + ``` + + + Cari Attribute + + ```js + // jQuery + $el.attr('foo'); + + // Native + e.getAttribute('foo'); + ``` + + + Cari atribut data + + ```js + // jQuery + $el.data('foo'); + + // Native + // menggunakan getAttribute + el.getAttribute('data-foo'); + // anda boleh juga gunakan `dataset` jika ingin pakai IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Sibling/Previous/Next Elements + + + Sibling elements + + ```js + // jQuery + $el.siblings(); + + // Native + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Previous elements + + ```js + // jQuery + $el.prev(); + + // Native + el.previousElementSibling; + + ``` + + + Next elements + + ```js + // next + $el.next(); + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Return the first matched element by provided selector, traversing from current element to document. + + ```js + // jQuery + $el.closest(queryString); + + // Native + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Native + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + Get index of e.currentTarget between `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Native + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + `$('iframe').contents()` returns `contentDocument` for this specific iframe + + + Iframe contents + + ```js + // jQuery + $iframe.contents(); + + // Native + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Native + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ back to top](#table-of-contents)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + Get style + + ```js + // jQuery + $el.css("color"); + + // Native + // NOTE: Known bug, will return 'auto' if style value is 'auto' + const win = el.ownerDocument.defaultView; + // null means not return presudo styles + win.getComputedStyle(el, null).color; + ``` + + + Set style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Native + el.style.color = '#ff0011'; + ``` + + + Get/Set Styles + + Note that if you want to set multiple styles once, you could refer to [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) method in oui-dom-utils package. + + + + Add class + + ```js + // jQuery + $el.addClass(className); + + // Native + el.classList.add(className); + ``` + + + Remove class + + ```js + // jQuery + $el.removeClass(className); + + // Native + el.classList.remove(className); + ``` + + + has class + + ```js + // jQuery + $el.hasClass(className); + + // Native + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Native + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Width & Height + + Width and Height are theoretically identical, take Height as example: + + + Window height + + ```js + // window height + $(window).height(); + // without scrollbar, behaves like jQuery + window.document.documentElement.clientHeight; + // with scrollbar + window.innerHeight; + ``` + + + Document height + + ```js + // jQuery + $(document).height(); + + // Native + document.documentElement.scrollHeight; + ``` + + + Element height + + ```js + // jQuery + $el.height(); + + // Native + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // accurate to integer(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.clientHeight; + // accurate to decimal(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Native + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Native + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Native + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ back to top](#table-of-contents)** + +## DOM Manipulation + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Native + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Get text + + ```js + // jQuery + $el.text(); + + // Native + el.textContent; + ``` + + + Set text + + ```js + // jQuery + $el.text(string); + + // Native + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Get HTML + + ```js + // jQuery + $el.html(); + + // Native + el.innerHTML; + ``` + + + Set HTML + + ```js + // jQuery + $el.html(htmlString); + + // Native + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + append child element after the last child of parent element + + ```js + // jQuery + $el.append("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.appendChild(newEl); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.insertBefore(newEl, el.firstChild); + ``` + +- [3.6](#3.6) insertBefore + + Insert a new node before the selected elements + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Insert a new node after the selected elements + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Ajax + +Replace with [fetch](https://github.com/camsong/fetch-ie8) and [fetch-jsonp](https://github.com/camsong/fetch-jsonp) + +**[⬆ back to top](#table-of-contents)** + +## Events + +For a complete replacement with namespace and delegation, refer to https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Bind an event with on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Native + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Unbind an event with off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Native + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Native + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Utility + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Native + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Native + String.trim(string); + ``` + +- [6.3](#6.3) Object Assign + + Extend, use object.assign polyfill https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Native + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Native + el !== child && el.contains(child); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Terjemahan + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [English](./README.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) + +## Sokongan Pelayar + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# Lesen + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-ru.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-ru.md new file mode 100644 index 000000000..561bdb96f --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-ru.md @@ -0,0 +1,650 @@ +## Вам не нужен jQuery + +В наше время среда фронт энд разработки быстро развивается, современные браузеры уже реализовали значимую часть DOM/BOM APIs и это хорошо. Вам не нужно изучать jQuery с нуля для манипуляцией DOM'ом или обектами событий. В то же время, благодаря лидирующим фронт энд библиотекам, таким как React, Angular и Vue, манипуляция DOM'ом напрямую становится противо шаблонной, jQuery никогда не был менее важен. Этот проект суммирует большинство альтернатив методов jQuery в нативном исполнении с поддержкой IE 10+. + +## Содержание + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css--style) +1. [Манипуляция DOM](#Манипуляции-dom) +1. [Ajax](#ajax) +1. [События](#События) +1. [Утилиты](#Утилиты) +1. [Альтернативы](#Альтернативы) +1. [Переводы](#Переводы) +1. [Поддержка браузеров](#Поддержка-браузеров) + +## Query Selector +Для часто используемых селекторов, таких как class, id или attribute мы можем использовать `document.querySelector` или `document.querySelectorAll` для замены. Разница такова: +* `document.querySelector` возвращает первый совпавший элемент +* `document.querySelectorAll` возвращает все совспавшие элементы как коллекцию узлов(NodeList). Его можно конвертировать в массив используя `[].slice.call(document.querySelectorAll(selector) || []);` +* Если никакие элементы не совпадут, jQuery вернет `[]` где DOM API вернет `null`. Обратите внимание на указатель исключения Null (Null Pointer Exception). Вы так же можете использовать `||` для установки значения по умолчанию если не было найдемо совпадений `document.querySelectorAll(selector) || []` + +> Заметка: `document.querySelector` и `document.querySelectorAll` достаточно **МЕДЛЕННЫ**, старайтесь использовать `getElementById`, `document.getElementsByClassName` или `document.getElementsByTagName` если хотите улучшить производительность. + +- [1.0](#1.0) Query by selector + + ```js + // jQuery + $('selector'); + + // Нативно + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Запрос по классу + + ```js + // jQuery + $('.class'); + + // Нативно + document.querySelectorAll('.class'); + + // или + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Запрос по ID + + ```js + // jQuery + $('#id'); + + // Нативно + document.querySelector('#id'); + + // или + document.getElementById('id'); + ``` + +- [1.3](#1.3) Запрос по атрибуту + + ```js + // jQuery + $('a[target=_blank]'); + + // Нативно + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Найти среди потомков + + + Найти nodes + + ```js + // jQuery + $el.find('li'); + + // Нативно + el.querySelectorAll('li'); + ``` + + + Найти body + + ```js + // jQuery + $('body'); + + // Нативно + document.body; + ``` + + + Найти атрибуты + + ```js + // jQuery + $el.attr('foo'); + + // Нативно + e.getAttribute('foo'); + ``` + + + Найти data attribute + + ```js + // jQuery + $el.data('foo'); + + // Нативно + // используя getAttribute + el.getAttribute('data-foo'); + // также можно использовать `dataset`, если не требуется поддержка ниже IE 11. + el.dataset['foo']; + ``` + +- [1.5](#1.5) Родственные/Предыдущие/Следующие Элементы + + + Родственные элементы + + ```js + // jQuery + $el.siblings(); + + // Нативно + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Предыдущие элементы + + ```js + // jQuery + $el.prev(); + + // Нативно + el.previousElementSibling; + ``` + + + Следующие элементы + + ```js + // jQuery + $el.next(); + + // Нативно + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Возвращает первый совпавший элемент по предоставленному селектору, обоходя от текущего элементы до документа. + + ```js + // jQuery + $el.closest(queryString); + + // Нативно - Only latest, NO IE + el.closest(selector); + + // Нативно - IE10+ + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Родители до + + Получить родителей кажого элемента в текущем сете совпавших элементов, но не включая элемент совпавший с селектором, узел DOM'а, или объект jQuery. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Нативно + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // Совпадать начиная от родителя + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) От + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Нативно + document.querySelector('#my-input').value; + ``` + + + получить индекс e.currentTarget между `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Нативно + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Контент Iframe + + `$('iframe').contents()` возвращает `contentDocument` для именно этого iframe + + + Контент Iframe + + ```js + // jQuery + $iframe.contents(); + + // Нативно + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Нативно + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ Наверх](#Содержание)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + Получить стиль + + ```js + // jQuery + $el.css("color"); + + // Нативно + // ЗАМЕТКА: Известная ошика, возвращает 'auto' если значение стиля 'auto' + const win = el.ownerDocument.defaultView; + // null означает не возвращать псевдостили + win.getComputedStyle(el, null).color; + ``` + + + Присвоение style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Нативно + el.style.color = '#ff0011'; + ``` + + + Получение/Присвоение стилей + + Заметьте что если вы хотите присвоить несколько стилей за раз, вы можете сослаться на [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) метод в oui-dom-utils package. + + + + Добавить класс + + ```js + // jQuery + $el.addClass(className); + + // Нативно + el.classList.add(className); + ``` + + + Удалить class + + ```js + // jQuery + $el.removeClass(className); + + // Нативно + el.classList.remove(className); + ``` + + + Имеет класс + + ```js + // jQuery + $el.hasClass(className); + + // Нативно + el.classList.contains(className); + ``` + + + Переключать класс + + ```js + // jQuery + $el.toggleClass(className); + + // Нативно + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Ширина и Высота + + Ширина и высота теоритечески идентичны, например возьмем высоту: + + + высота окна + + ```js + // Высота окна + $(window).height(); + // без скроллбара, ведет себя как jQuery + window.document.documentElement.clientHeight; + // вместе с скроллбаром + window.innerHeight; + ``` + + + высота документа + + ```js + // jQuery + $(document).height(); + + // Нативно + document.documentElement.scrollHeight; + ``` + + + Высота элемента + + ```js + // jQuery + $el.height(); + + // Нативно + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // С точностью до целого числа(когда `border-box`, это `height`; когда `content-box`, это `height + padding + border`) + el.clientHeight; + // с точностью до десятых(когда `border-box`, это `height`; когда `content-box`, это `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Позиция и смещение + + + Позиция + + ```js + // jQuery + $el.position(); + + // Нативно + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Смещение + + ```js + // jQuery + $el.offset(); + + // Нативно + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Прокрутка вверх + + ```js + // jQuery + $(window).scrollTop(); + + // Нативно + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ Наверх](#Содержание)** + +## Манипуляции DOM + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Нативно + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Текст + + + Получить текст + + ```js + // jQuery + $el.text(); + + // Нативно + el.textContent; + ``` + + + Присвоить текст + + ```js + // jQuery + $el.text(string); + + // Нативно + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Получить HTML + + ```js + // jQuery + $el.html(); + + // Нативно + el.innerHTML; + ``` + + + Присвоить HTML + + ```js + // jQuery + $el.html(htmlString); + + // Нативно + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + Добавление элемента ребенка после последнего ребенка элемента родителя + + ```js + // jQuery + $el.append("
hello
"); + + // Нативно + el.insertAdjacentHTML("beforeend","
hello
"); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Нативно + el.insertAdjacentHTML("afterbegin","
hello
"); + ``` + +- [3.6](#3.6) insertBefore + + Вставка нового элемента перед выбранным элементом + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Нативно + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Вставка новго элемента после выбранного элемента + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Нативно + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +- [3.8](#3.8) is + + Возвращает `true` если совпадает с селектором запроса + + ```js + // jQuery - заметьте что `is` так же работает с `function` или `elements` которые не имют к этому отношения + $el.is(selector); + + // Нативно + el.matches(selector); + ``` + +**[⬆ Наверх](#Содержание)** + +## Ajax + +Заменить с [fetch](https://github.com/camsong/fetch-ie8) и [fetch-jsonp](https://github.com/camsong/fetch-jsonp) + +**[⬆ Наверх](#Содержание)** + +## События + +Для полной замены с пространством имен и делегация, сослаться на [oui-dom-events](https://github.com/oneuijs/oui-dom-events) + +- [5.1](#5.1) Связать событие используя on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Нативно + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Отвязать событие используя off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Нативно + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Нативно + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ Наверх](#Содержание)** + +## Утилиты + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Нативно + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Нативно + string.trim(); + ``` + +- [6.3](#6.3) Назначение объекта + + Дополнительно, используйте полифил object.assign https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Нативно + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Нативно + el !== child && el.contains(child); + ``` + +**[⬆ Наверх](#Содержание)** + +## Альтернативы + +* [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Примеры как исполняются частые события, элементы, ajax и тд с ванильным javascript. +* [npm-dom](http://github.com/npm-dom) и [webmodules](http://github.com/webmodules) - Отдельные DOM модули можно найти на NPM + +## Переводы + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) + +## Поддержка браузеров + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# License + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-tr.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-tr.md new file mode 100644 index 000000000..85d614f5f --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-tr.md @@ -0,0 +1,665 @@ +## jQuery'e İhtiyacınız Yok [![Build Status](https://travis-ci.org/oneuijs/You-Dont-Need-jQuery.svg)](https://travis-ci.org/oneuijs/You-Dont-Need-jQuery) + +Önyüz ortamları bugünlerde çok hızlı gelişiyor, öyle ki modern tarayıcılar DOM/DOM APİ'lere ait önemli gereklilikleri çoktan yerine getirdiler. DOM işleme ve olaylar için, en baştan jQuery ögrenmemize gerek kalmadı. Bu arada, üstünlükleri ile jQuery'i önemsizleştiren ve doğrudan DOM değişikliklerinin bir Anti-pattern olduğunu gösteren, React, Angular ve Vue gibi gelişmiş önyüz kütüphanelerine ayrıca teşekkür ederiz. Bu proje, IE10+ desteği ile coğunluğu jQuery yöntemlerine alternatif olan yerleşik uygulamaları içerir. + +## İçerik Tablosu + +1. [Sorgu seçiciler](#sorgu-seçiciler) +1. [CSS & Stil](#css--stil) +1. [DOM düzenleme](#dom-düzenleme) +1. [Ajax](#ajax) +1. [Olaylar](#olaylar) +1. [Araçlar](#araçlar) +1. [Alternatifler](#alternatifler) +1. [Çeviriler](#Çeviriler) +1. [Tarayıcı desteği](#tarayıcı-desteği) + +## Sorgu seçiciler + +Yaygın olan class, id ve özellik seçiciler yerine, `document.querySelector` yada `document.querySelectorAll` kullanabiliriz. Ayrıldıkları nokta: +* `document.querySelector` ilk seçilen öğeyi döndürür +* `document.querySelectorAll` Seçilen tüm öğeleri NodeList olarak geri döndürür. `[].slice.call(document.querySelectorAll(selector) || []);` kullanarak bir diziye dönüştürebilirsiniz. +* Herhangi bir öğenin seçilememesi durumda ise, jQuery `[]` döndürürken, DOM API `null` döndürecektir. Null Pointer istisnası almamak için `||` ile varsayılan değere atama yapabilirsiniz, örnek: `document.querySelectorAll(selector) || []` + +> Uyarı: `document.querySelector` ve `document.querySelectorAll` biraz **YAVAŞ** olabilir, Daha hızlısını isterseniz, `getElementById`, `document.getElementsByClassName` yada `document.getElementsByTagName` kullanabilirsiniz. + +- [1.0](#1.0) Seçici ile sorgu + + ```js + // jQuery + $('selector'); + + // Yerleşik + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Sınıf ile sorgu + + ```js + // jQuery + $('.class'); + + // Yerleşik + document.querySelectorAll('.class'); + + // yada + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Id ile sorgu + + ```js + // jQuery + $('#id'); + + // Yerleşik + document.querySelector('#id'); + + // yada + document.getElementById('id'); + ``` + +- [1.3](#1.3) Özellik ile sorgu + + ```js + // jQuery + $('a[target=_blank]'); + + // Yerleşik + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Öğe erişimi + + + Node'a erişim + + ```js + // jQuery + $el.find('li'); + + // Yerleşik + el.querySelectorAll('li'); + ``` + + + Body'e erişim + + ```js + // jQuery + $('body'); + + // Yerleşik + document.body; + ``` + + + Özelliğe erişim + + ```js + // jQuery + $el.attr('foo'); + + // Yerleşik + el.getAttribute('foo'); + ``` + + + Data özelliğine erişim + + ```js + // jQuery + $el.data('foo'); + + // Yerleşik + // getAttribute kullanarak + el.getAttribute('data-foo'); + // Eğer IE 11+ kullanıyor iseniz, `dataset` ile de erişebilirsiniz + el.dataset['foo']; + ``` + +- [1.5](#1.5) Kardeş/Önceki/Sonraki öğeler + + + Kardeş öğeler + + ```js + // jQuery + $el.siblings(); + + // Yerleşik + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Önceki öğeler + + ```js + // jQuery + $el.prev(); + + // Yerleşik + el.previousElementSibling; + ``` + + + Sonraki öğeler + + ```js + // jQuery + $el.next(); + + // Yerleşik + el.nextElementSibling; + ``` + +- [1.6](#1.6) En yakın + + Verilen seçici ile eşleşen ilk öğeyi döndürür, geçerli öğeden başlayarak document'a kadar geçiş yapar. + + ```js + // jQuery + $el.closest(selector); + + // Yerleşik - Sadece en güncellerde, IE desteklemiyor + el.closest(selector); + + // Yerleşik - IE10+ + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Önceki atalar + + Verilen seçici ile eşleşen öğe veya DOM node veya jQuery nesnesi hariç, mevcut öğe ile aradaki tüm önceki ataları bir set dahilinde verir. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Yerleşik + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // eşleştirme, atadan başlar + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Yerleşik + document.querySelector('#my-input').value; + ``` + + + e.currentTarget ile `.radio` arasındaki dizini verir + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Yerleşik + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe İçeriği + + Mevcut Iframe için `$('iframe').contents()` yerine `contentDocument` döndürür. + + + Iframe İçeriği + + ```js + // jQuery + $iframe.contents(); + + // Yerleşik + iframe.contentDocument; + ``` + + + Iframe seçici + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Yerleşik + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ üste dön](#İçerik-tablosu)** + +## CSS & Stil + +- [2.1](#2.1) CSS + + + Stili verir + + ```js + // jQuery + $el.css("color"); + + // Yerleşik + // NOT: Bilinen bir hata, eğer stil değeri 'auto' ise 'auto' döndürür + const win = el.ownerDocument.defaultView; + // null sahte tipleri döndürmemesi için + win.getComputedStyle(el, null).color; + ``` + + + Stil değiştir + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Yerleşik + el.style.color = '#ff0011'; + ``` + + + Stil değeri al/değiştir + + Eğer aynı anda birden fazla stili değiştirmek istiyor iseniz, oui-dom-utils paketi içindeki [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) metoduna göz atınız. + + + + Sınıf ekle + + ```js + // jQuery + $el.addClass(className); + + // Yerleşik + el.classList.add(className); + ``` + + + Sınıf çıkart + + ```js + // jQuery + $el.removeClass(className); + + // Yerleşik + el.classList.remove(className); + ``` + + + sınfı var mı? + + ```js + // jQuery + $el.hasClass(className); + + // Yerleşik + el.classList.contains(className); + ``` + + + Sınfı takas et + + ```js + // jQuery + $el.toggleClass(className); + + // Yerleşik + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Genişlik ve Yükseklik + + Genişlik ve Yükseklik teorik olarak aynı şekilde, örnek olarak Yükseklik veriliyor + + + Window Yüksekliği + + ```js + // window yüksekliği + $(window).height(); + // kaydırma çubuğu olmaksızın, jQuery ile aynı + window.document.documentElement.clientHeight; + // kaydırma çubuğu ile birlikte + window.innerHeight; + ``` + + + Document yüksekliği + + ```js + // jQuery + $(document).height(); + + // Yerleşik + document.documentElement.scrollHeight; + ``` + + + Öğe yüksekliği + + ```js + // jQuery + $el.height(); + + // Yerleşik + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // Tamsayı olarak daha doğru olanı(`border-box` iken, `height` esas; `content-box` ise, `height + padding + border` esas alınır) + el.clientHeight; + // Ondalık olarak daha doğru olanı(`border-box` iken, `height` esas; `content-box` ise, `height + padding + border` esas alınır) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Pozisyon ve Ara-Açıklığı + + + Pozisyon + + ```js + // jQuery + $el.position(); + + // Yerleşik + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Ara-Açıklığı + + ```js + // jQuery + $el.offset(); + + // Yerleşik + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Üste kaydır + + ```js + // jQuery + $(window).scrollTop(); + + // Yerleşik + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ üste dön](#İçerik-tablosu)** + +## DOM düzenleme + +- [3.1](#3.1) Çıkartma + ```js + // jQuery + $el.remove(); + + // Yerleşik + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Metin + + + Get text + + ```js + // jQuery + $el.text(); + + // Yerleşik + el.textContent; + ``` + + + Set text + + ```js + // jQuery + $el.text(string); + + // Yerleşik + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + HTML'i alma + + ```js + // jQuery + $el.html(); + + // Yerleşik + el.innerHTML; + ``` + + + HTML atama + + ```js + // jQuery + $el.html(htmlString); + + // Yerleşik + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Sona ekleme + + Ata öğenin son çocuğundan sonra öğe ekleme + + ```js + // jQuery + $el.append("
hello
"); + + // Yerleşik + el.insertAdjacentHTML("beforeend","
hello
"); + ``` + +- [3.5](#3.5) Öne ekleme + + ```js + // jQuery + $el.prepend("
hello
"); + + // Yerleşik + el.insertAdjacentHTML("afterbegin","
hello
"); + ``` + +- [3.6](#3.6) Öncesine Ekleme + + Seçili öğeden önceki yere yeni öğe ekleme + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Yerleşik + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) Sonrasına ekleme + + Seçili öğeden sonraki yere yeni öğe ekleme + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Yerleşik + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +- [3.8](#3.8) eşit mi? + + Sorgu seçici ile eşleşiyor ise `true` döner + + ```js + // jQuery için not: `is` aynı zamanda `function` veya `elements` için de geçerlidir fakat burada bir önemi bulunmuyor + $el.is(selector); + + // Yerleşik + el.matches(selector); + ``` +- [3.9](#3.9) Klonlama + + Mevcut öğenin bir derin kopyasını oluşturur + + ```js + // jQuery + $el.clone(); + + // Yerleşik + el.cloneNode(); + + // Derin kopya için, `true` parametresi kullanınız + ``` +**[⬆ üste dön](#İçerik-tablosu)** + +## Ajax + +[Fetch API](https://fetch.spec.whatwg.org/) ajax için XMLHttpRequest yerine kullanan yeni standarttır. Chrome ve Firefox destekler, eski tarayıcılar için polyfill kullanabilirsiniz. + +IE9+ ve üstü için [github/fetch](http://github.com/github/fetch) yada IE8+ ve üstü için [fetch-ie8](https://github.com/camsong/fetch-ie8/), JSONP istekler için [fetch-jsonp](https://github.com/camsong/fetch-jsonp) deneyiniz. + +**[⬆ üste dön](#İçerik-tablosu)** + +## Olaylar + +Namespace ve Delegasyon ile tam olarak değiştirmek için, https://github.com/oneuijs/oui-dom-events sayfasına bakınız + +- [5.1](#5.1) on ile bir öğeye bağlama + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Yerleşik + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) off ile bir bağlamayı sonlandırma + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Yerleşik + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Tetikleyici + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Yerleşik + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ üste dön](#İçerik-tablosu)** + +## Araçlar + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Yerleşik + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Yerleşik + string.trim(); + ``` + +- [6.3](#6.3) Nesne atama + + Türetmek için, object.assign polyfill'ini deneyiniz https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Yerleşik + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) İçerme + + ```js + // jQuery + $.contains(el, child); + + // Yerleşik + el !== child && el.contains(child); + ``` + +**[⬆ üste dön](#İçerik-tablosu)** + +## Alternatifler + +* [jQuery'e İhtiyacınız Yok](http://youmightnotneedjquery.com/) - Yaygın olan olay, öğe ve ajax işlemlerinin yalın Javascript'teki karşılıklarına ait örnekler +* [npm-dom](http://github.com/npm-dom) ve [webmodules](http://github.com/webmodules) - NPM için ayrı DOM modül organizasyonları + +## Çeviriler + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) + +## Tarayıcı Desteği + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# Lisans + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-vi.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-vi.md new file mode 100644 index 000000000..7eb60f456 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README-vi.md @@ -0,0 +1,634 @@ +## Bạn không cần jQuery nữa đâu + +Ngày nay, môi trường lập trình front-end phát triển rất nhanh chóng, các trình duyệt hiện đại đã cung cấp các API đủ tốt để làm việc với DOM/BOM. Bạn không còn cần phải học về jQuery nữa. Đồng thời, nhờ sự ra đời của các thư viện như React, Angular và Vue đã khiến cho việc can thiệp trực tiếp vào DOM trở thành một việc không tốt. jQuery đã không còn quan trọng như trước nữa. Bài viết này tổng hợp những cách để thay thế các hàm của jQuery bằng các hàm được hỗ trợ bởi trình duyệt, và hó cũng hoạt động trên IE 10+ + +## Danh mục + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css--style) +1. [Thao tác với DOM](#thao-tác-với-dom) +1. [Ajax](#ajax) +1. [Events](#events) +1. [Hàm tiện ích](#hàm-tiện-ích) +1. [Ngôn ngữ khác](#ngôn-ngữ-khác) +1. [Các trình duyệt hỗ trợ](#các-trình-duyệt-hỗ-trợ) + +## Query Selector + +Đối với những selector phổ biến như class, id hoặc thuộc tính thì chúng ta có thể sử dụng `document.querySelector` hoặc `document.querySelectorAll` để thay thế cho jQuery selector. Sự khác biệt của hai hàm này là ở chỗ: + +* `document.querySelector` trả về element đầu tiên được tìm thấy +* `document.querySelectorAll` trả về tất cả các element được tìm thấy dưới dạng một instance của NodeList. Nó có thể được convert qua array bằng cách `[].slice.call(document.querySelectorAll(selector) || []);` +* Nếu không có element nào được tìm thấy, thì jQuery sẽ trả về một array rỗng `[]` trong khi đó DOM API sẽ trả về `null`. Hãy chú ý đến Null Pointer Exception. Bạn có thể sử dụng toán tử `||` để đặt giá trị default nếu như không có element nào được tìm thấy, ví dụ như `document.querySelectorAll(selector) || []` + +> Chú ý : `document.querySelector` và `document.querySelectorAll` hoạt động khá **CHẬM**, hãy thử dùng `getElementById`, `document.getElementsByClassName` hoặc `document.getElementsByTagName` nếu bạn muốn đạt hiệu suất tốt hơn. + +- [1.0](#1.0) Query bằng selector + + ```js + // jQuery + $('selector'); + + // Native + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Query bằng class + + ```js + // jQuery + $('.class'); + + // Native + document.querySelectorAll('.class'); + + // hoặc + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Query bằng id + + ```js + // jQuery + $('#id'); + + // Native + document.querySelector('#id'); + + // hoặc + document.getElementById('id'); + ``` + +- [1.3](#1.3) Query bằng thuộc tính + + ```js + // jQuery + $('a[target=_blank]'); + + // Native + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Tìm bất cứ gì. + + + Tìm node + + ```js + // jQuery + $el.find('li'); + + // Native + el.querySelectorAll('li'); + ``` + + + Tìm body + + ```js + // jQuery + $('body'); + + // Native + document.body; + ``` + + + lấy thuộc tính + + ```js + // jQuery + $el.attr('foo'); + + // Native + e.getAttribute('foo'); + ``` + + + Lấy giá trị của thuộc tính `data` + + ```js + // jQuery + $el.data('foo'); + + // Native + // using getAttribute + el.getAttribute('data-foo'); + // you can also use `dataset` if only need to support IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Tìm element cùng level/trước/sau + + + Element cùng level + + ```js + // jQuery + $el.siblings(); + + // Native + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Element ở phía trước + + ```js + // jQuery + $el.prev(); + + // Native + el.previousElementSibling; + + ``` + + + Element ở phía sau + + ```js + // next + $el.next(); + el.nextElementSibling; + ``` + +- [1.6](#1.6) Element gần nhất + + Trả về element đầu tiên có selector khớp với yêu cầu khi duyệt từ element hiện tại trở lên tới document. + + ```js + // jQuery + $el.closest(queryString); + + // Native + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Tìm parent + + Truy ngược một cách đệ quy tổ tiên của element hiện tại, cho đến khi tìm được một element tổ tiên ( element cần tìm ) mà element đó là con trực tiếp của element khớp với selector được cung cấp, Return lại element cần tìm đó. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Native + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + Lấy index của e.currentTarget trong danh sách các element khớp với selector `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Native + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Nội dung Iframe + + `$('iframe').contents()` trả về thuộc tính `contentDocument` của iframe được tìm thấy + + + Nọi dung iframe + + ```js + // jQuery + $iframe.contents(); + + // Native + iframe.contentDocument; + ``` + + + Query Iframe + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Native + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ Trở về đầu](#danh-mục)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + Lấy style + + ```js + // jQuery + $el.css("color"); + + // Native + // NOTE: Bug đã được biết, sẽ trả về 'auto' nếu giá trị của style là 'auto' + const win = el.ownerDocument.defaultView; + // null means not return presudo styles + win.getComputedStyle(el, null).color; + ``` + + + Đặt style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Native + el.style.color = '#ff0011'; + ``` + + + Lấy/Đặt Nhiều style + + Nếu bạn muốn đặt nhiều style một lần, bạn có thể sẽ thích phương thức [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) trong thư viện oui-dom-utils. + + + + Thêm class và element + + ```js + // jQuery + $el.addClass(className); + + // Native + el.classList.add(className); + ``` + + + Loại bỏ class class ra khỏi element + + ```js + // jQuery + $el.removeClass(className); + + // Native + el.classList.remove(className); + ``` + + + Kiểm tra xem element có class nào đó hay không + + ```js + // jQuery + $el.hasClass(className); + + // Native + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Native + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Chiều rộng, chiều cao + + Về mặt lý thuyết thì chiều rộng và chiều cao giống như nhau trong cả jQuery và DOM API: + + + Chiều rộng của window + + ```js + // window height + $(window).height(); + // trừ đi scrollbar + window.document.documentElement.clientHeight; + // Tính luôn scrollbar + window.innerHeight; + ``` + + + Chiều cao của Document + + ```js + // jQuery + $(document).height(); + + // Native + document.documentElement.scrollHeight; + ``` + + + Chiều cao của element + + ```js + // jQuery + $el.height(); + + // Native + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // chính xác tới số nguyên(khi có thuộc tính `box-sizing` là `border-box`, nó là `height`; khi box-sizing là `content-box`, nó là `height + padding + border`) + el.clientHeight; + // Chính xác tới số thập phân(khi `box-sizing` là `border-box`, nó là `height`; khi `box-sizing` là `content-box`, nó là `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Native + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Native + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Native + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ Trở về đầu](#danh-mục)** + +## Thao tác với DOM + +- [3.1](#3.1) Loại bỏ + ```js + // jQuery + $el.remove(); + + // Native + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Lấy text + + ```js + // jQuery + $el.text(); + + // Native + el.textContent; + ``` + + + Đặt giá trị text + + ```js + // jQuery + $el.text(string); + + // Native + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Lấy HTML + + ```js + // jQuery + $el.html(); + + // Native + el.innerHTML; + ``` + + + Đặt giá trị HTML + + ```js + // jQuery + $el.html(htmlString); + + // Native + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + append một element sau element con cuối cùng của element cha + + ```js + // jQuery + $el.append("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.appendChild(newEl); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.insertBefore(newEl, el.firstChild); + ``` + +- [3.6](#3.6) insertBefore + + Chèn một node vào trước element được query. + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Chèn node vào sau element được query + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +**[⬆ Trở về đầu](#danh-mục)** + +## Ajax + +Thay thế bằng [fetch](https://github.com/camsong/fetch-ie8) và [fetch-jsonp](https://github.com/camsong/fetch-jsonp) + +**[⬆ Trở về đầu](#danh-mục)** + +## Events + +Để có một sự thay thế đầy đủ nhất, bạn nên sử dụng https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Bind event bằng on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Native + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Unbind event bằng off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Native + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Native + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ Trở về đầu](#danh-mục)** + +## Hàm tiện ích + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Native + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Native + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + Mở rộng, sử dụng object.assign https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Native + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Native + el !== child && el.contains(child); + ``` + +**[⬆ Trở về đầu](#danh-mục)** + +## Ngôn ngữ khác + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) + +## Các trình duyệt hỗ trợ + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# Giấy phép + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.ko-KR.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.ko-KR.md new file mode 100644 index 000000000..54455115e --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.ko-KR.md @@ -0,0 +1,709 @@ +## You Don't Need jQuery + +오늘날 프론트엔드 개발 환경은 급격히 진화하고 있고, 모던 브라우저들은 이미 충분히 많은 DOM/BOM API들을 구현했습니다. 우리는 jQuery를 DOM 처리나 이벤트를 위해 처음부터 배울 필요가 없습니다. React, Angular, Vue같은 프론트엔드 라이브러리들이 주도권을 차지하는 동안 DOM을 바로 처리하는 것은 안티패턴이 되었고, jQuery의 중요성은 줄어들었습니다. 이 프로젝트는 대부분의 jQuery 메소드의 대안을 IE 10+ 이상을 지원하는 네이티브 구현으로 소개합니다. + +## 목차 + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css--style) +1. [DOM 조작](#dom-조작) +1. [Ajax](#ajax) +1. [이벤트](#이벤트) +1. [유틸리티](#유틸리티) +1. [대안방법](#대안방법) +1. [번역](#번역) +1. [브라우저 지원](#브라우저-지원) + +## Query Selector + +평범한 class, id, attribute같은 selecotor는 `document.querySelector`나 `document.querySelectorAll`으로 대체할 수 있습니다. +* `document.querySelector`는 처음 매칭된 엘리먼트를 반환합니다. +* `document.querySelectorAll`는 모든 매칭된 엘리먼트를 NodeList로 반환합니다. `[].slice.call`을 사용해서 Array로 변환할 수 있습니다. +* 만약 매칭된 엘리멘트가 없으면 jQuery는 `[]` 를 반환하지만 DOM API는 `null`을 반환합니다. Null Pointer Exception에 주의하세요. + +> 안내: `document.querySelector`와 `document.querySelectorAll`는 꽤 **느립니다**, `getElementById`나 `document.getElementsByClassName`, `document.getElementsByTagName`를 사용하면 퍼포먼스가 향상을 기대할 수 있습니다. + +- [1.0](#1.0) selector로 찾기 + + ```js + // jQuery + $('selector'); + + // Native + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) class로 찾기 + + ```js + // jQuery + $('.class'); + + // Native + document.querySelectorAll('.class'); + + // or + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) id로 찾기 + + ```js + // jQuery + $('#id'); + + // Native + document.querySelector('#id'); + + // or + document.getElementById('id'); + ``` + +- [1.3](#1.3) 속성(attribute)으로 찾기 + + ```js + // jQuery + $('a[target=_blank]'); + + // Native + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) 자식에서 찾기 + + ```js + // jQuery + $el.find('li'); + + // Native + el.querySelectorAll('li'); + ``` + +- [1.5](#1.5) 형제/이전/다음 엘리먼트 찾기 + + + 형제 엘리먼트 + + ```js + // jQuery + $el.siblings(); + + // Native + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + 이전 엘리먼트 + + ```js + // jQuery + $el.prev(); + + // Native + el.previousElementSibling; + ``` + + + 다음 엘리먼트 + + ```js + // jQuery + $el.next(); + + // Native + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + 현재 엘리먼트부터 document로 이동하면서 주어진 셀렉터와 일치하는 가장 가까운 엘리먼트를 반환합니다. + + ```js + // jQuery + $el.closest(selector); + + // Native - 최신 브라우저만, IE는 미지원 + el.closest(selector); + + // Native - IE10 이상 + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + 주어진 셀렉터에 매칭되는 엘리먼트를 찾기까지 부모 태그들을 위로 올라가며 탐색하여 저장해두었다가 DOM 노드 또는 jQuery object로 반환합니다. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Native + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + e.currentTarget이 `.radio`의 몇번째인지 구하기 + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Native + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + `$('iframe').contents()`는 iframe에 한정해서 `contentDocument`를 반환합니다. + + + Iframe contents + + ```js + // jQuery + $iframe.contents(); + + // Native + iframe.contentDocument; + ``` + + + Iframe에서 찾기 + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Native + iframe.contentDocument.querySelectorAll('.css'); + ``` + +- [1.10](#1.10) body 얻기 + + ```js + // jQuery + $('body'); + + // Native + document.body; + ``` + +- [1.11](#1.11) 속성 얻기 및 설정 + + + 속성 얻기 + + ```js + // jQuery + $el.attr('foo'); + + // Native + el.getAttribute('foo'); + ``` + + 속성 설정하기 + + ```js + // jQuery, DOM 변형 없이 메모리에서 작동됩니다. + $el.attr('foo', 'bar'); + + // Native + el.setAttribute('foo', 'bar'); + ``` + + + `data-` 속성 얻기 + + ```js + // jQuery + $el.data('foo'); + + // Native (`getAttribute` 사용) + el.getAttribute('data-foo'); + // Native (IE 11 이상의 지원만 필요하다면 `dataset`을 사용) + el.dataset['foo']; + ``` + +**[⬆ 목차로 돌아가기](#목차)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + style값 얻기 + + ```js + // jQuery + $el.css("color"); + + // Native + // NOTE: 알려진 버그로, style값이 'auto'이면 'auto'를 반환합니다. + const win = el.ownerDocument.defaultView; + // null은 가상 스타일은 반환하지 않음을 의미합니다. + win.getComputedStyle(el, null).color; + ``` + + + style값 설정하기 + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Native + el.style.color = '#ff0011'; + ``` + + + Style값들을 동시에 얻거나 설정하기 + + 만약 한번에 여러 style값을 바꾸고 싶다면 oui-dom-utils 패키지의 [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194)를 사용해보세요. + + + + class 추가하기 + + ```js + // jQuery + $el.addClass(className); + + // Native + el.classList.add(className); + ``` + + + class 제거하기 + + ```js + // jQuery + $el.removeClass(className); + + // Native + el.classList.remove(className); + ``` + + + class를 포함하고 있는지 검사하기 + + ```js + // jQuery + $el.hasClass(className); + + // Native + el.classList.contains(className); + ``` + + + class 토글하기 + + ```js + // jQuery + $el.toggleClass(className); + + // Native + el.classList.toggle(className); + ``` + +- [2.2](#2.2) 폭과 높이 + + 폭과 높이는 이론상 동일합니다. 높이로 예를 들겠습니다. + + + Window의 높이 + + ```js + // window 높이 + $(window).height(); + // jQuery처럼 스크롤바를 제외하기 + window.document.documentElement.clientHeight; + // 스크롤바 포함 + window.innerHeight; + ``` + + + 문서 높이 + + ```js + // jQuery + $(document).height(); + + // Native + document.documentElement.scrollHeight; + ``` + + + Element 높이 + + ```js + // jQuery + $el.height(); + + // Native + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // 정수로 정확하게(`border-box`일 때 이 값은 `height`이고, `content-box`일 때, 이 값은 `height + padding + border`) + el.clientHeight; + // 실수로 정확하게(`border-box`일 때 이 값은 `height`이고, `content-box`일 때, 이 값은 `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Native + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Native + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Native + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ 목차로 돌아가기](#목차)** + +## DOM 조작 + +- [3.1](#3.1) 제거 + ```js + // jQuery + $el.remove(); + + // Native + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + text 가져오기 + + ```js + // jQuery + $el.text(); + + // Native + el.textContent; + ``` + + + text 설정하기 + + ```js + // jQuery + $el.text(string); + + // Native + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + HTML 가져오기 + + ```js + // jQuery + $el.html(); + + // Native + el.innerHTML; + ``` + + + HTML 설정하기 + + ```js + // jQuery + $el.html(htmlString); + + // Native + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) 해당 엘리먼트의 자식들 뒤에 넣기(Append) + + 부모 엘리먼트의 마지막 자식으로 엘리먼트를 추가합니다. + + ```js + // jQuery + $el.append("
hello
"); + + // Native + el.insertAdjacentHTML("beforeend","
hello
"); + ``` + +- [3.5](#3.5) 해당 엘리먼트의 자식들 앞에 넣기(Prepend) + + ```js + // jQuery + $el.prepend("
hello
"); + + // Native +el.insertAdjacentHTML("afterbegin","
hello
"); + ``` + +- [3.6](#3.6) 해당 엘리먼트 앞에 넣기(insertBefore) + + 새 노드를 선택한 엘리먼트 앞에 넣습니다. + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) 해당 엘리먼트 뒤에 넣기(insertAfter) + + 새 노드를 선택한 엘리먼트 뒤에 넣습니다. + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` +- [3.8](#3.8) is + + query selector와 일치하면 `true` 를 반환합니다. + + ```js + // jQuery + $el.is(selector); + + // Native + el.matches(selector); + ``` + +- [3.9](#3.9) clone + + 엘리먼트의 복제본을 만듭니다. + + ```js + // jQuery + $el.clone(); + + // Native + el.cloneNode(); + + // Deep clone은 파라미터를 `true` 로 설정하세요. + ``` + +- [3.10](#3.10) empty + + 모든 자식 노드를 제거합니다. + + ```js + // jQuery + $el.empty(); + + // Native + el.innerHTML = ''; + ``` + +**[⬆ 목차로 돌아가기](#목차)** + +## Ajax + +[Fetch API](https://fetch.spec.whatwg.org/) 는 XMLHttpRequest를 ajax로 대체하는 새로운 표준 입니다. Chrome과 Firefox에서 작동하며, polyfill을 이용해서 구형 브라우저에서 작동되도록 만들 수도 있습니다. + +IE9 이상에서 지원하는 [github/fetch](http://github.com/github/fetch) 혹은 IE8 이상에서 지원하는 [fetch-ie8](https://github.com/camsong/fetch-ie8/), JSONP 요청을 만드는 [fetch-jsonp](https://github.com/camsong/fetch-jsonp)를 이용해보세요. + +**[⬆ 목차로 돌아가기](#목차)** + +## 이벤트 + +namespace와 delegation을 포함해서 완전히 갈아 엎길 원하시면 https://github.com/oneuijs/oui-dom-events 를 고려해보세요. + +- [5.1](#5.1) 이벤트 Bind 걸기 + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Native + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) 이벤트 Bind 풀기 + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Native + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) 이벤트 발생시키기(Trigger) + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Native + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ 목차로 돌아가기](#목차)** + +## 유틸리티 + +- [6.1](#6.1) 배열인지 검사(isArray) + + ```js + // jQuery + $.isArray(range); + + // Native + Array.isArray(range); + ``` + +- [6.2](#6.2) 앞뒤 공백 지우기(Trim) + + ```js + // jQuery + $.trim(string); + + // Native + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + 사용하려면 object.assign polyfill을 사용하세요. https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Native + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Native + el !== child && el.contains(child); + ``` + +- [6.5](#6.5) inArray + + ```js + // jQuery + $.inArray(item, array); + + // Native + array.indexOf(item); + ``` + +- [6.6](#6.6) map + + ```js + // jQuery + $.map(array, function(value, index) { + }); + + // Native + Array.map(function(value, index) { + }); + ``` + +**[⬆ 목차로 돌아가기](#목차)** + +## 대안방법 + +* [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - 일반 자바스크립트로 공통이벤트, 엘리먼트, ajax 등을 다루는 방법 예제. +* [npm-dom](http://github.com/npm-dom) 과 [webmodules](http://github.com/webmodules) - 개별 DOM모듈을 NPM에서 찾을 수 있습니다. + +## 번역 + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) +* [Italian](./README-it.md) + +## 브라우저 지원 + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# License + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.md new file mode 100644 index 000000000..6476f5034 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.md @@ -0,0 +1,1190 @@ +## You Don't Need jQuery [![Build Status](https://travis-ci.org/oneuijs/You-Dont-Need-jQuery.svg)](https://travis-ci.org/oneuijs/You-Dont-Need-jQuery) + +Frontend environments evolve rapidly nowadays, modern browsers have already implemented a great deal of DOM/BOM APIs which are good enough. We don't have to learn jQuery from scratch for DOM manipulation or events. In the meantime, thanks to the prevailment of frontend libraries such as React, Angular and Vue, manipulating DOM directly becomes anti-pattern, jQuery has never been less important. This project summarizes most of the jQuery method alternatives in native implementation, with IE 10+ support. + +## Table of Contents + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css--style) +1. [DOM Manipulation](#dom-manipulation) +1. [Ajax](#ajax) +1. [Events](#events) +1. [Utilities](#utilities) +1. [Promises](#promises) +1. [Animation](#animation) +1. [Alternatives](#alternatives) +1. [Translations](#translations) +1. [Browser Support](#browser-support) + +## Query Selector + +In place of common selectors like class, id or attribute we can use `document.querySelector` or `document.querySelectorAll` for substitution. The differences lie in: +* `document.querySelector` returns the first matched element +* `document.querySelectorAll` returns all matched elements as NodeList. It can be converted to Array using `[].slice.call(document.querySelectorAll(selector) || []);` +* If no elements matched, jQuery would return `[]` whereas the DOM API will return `null`. Pay attention to Null Pointer Exception. You can also use `||` to set default value if not found, like `document.querySelectorAll(selector) || []` + +> Notice: `document.querySelector` and `document.querySelectorAll` are quite **SLOW**, try to use `getElementById`, `document.getElementsByClassName` or `document.getElementsByTagName` if you want to get a performance bonus. + +- [1.0](#1.0) Query by selector + + ```js + // jQuery + $('selector'); + + // Native + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Query by class + + ```js + // jQuery + $('.class'); + + // Native + document.querySelectorAll('.class'); + + // or + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Query by id + + ```js + // jQuery + $('#id'); + + // Native + document.querySelector('#id'); + + // or + document.getElementById('id'); + ``` + +- [1.3](#1.3) Query by attribute + + ```js + // jQuery + $('a[target=_blank]'); + + // Native + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Query in descendents + + ```js + // jQuery + $el.find('li'); + + // Native + el.querySelectorAll('li'); + ``` + +- [1.5](#1.5) Sibling/Previous/Next Elements + + + Sibling elements + + ```js + // jQuery + $el.siblings(); + + // Native + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Previous elements + + ```js + // jQuery + $el.prev(); + + // Native + el.previousElementSibling; + ``` + + + Next elements + + ```js + // jQuery + $el.next(); + + // Native + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Return the first matched element by provided selector, traversing from current element to document. + + ```js + // jQuery + $el.closest(selector); + + // Native - Only latest, NO IE + el.closest(selector); + + // Native - IE10+ + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Native + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + Get index of e.currentTarget between `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Native + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + `$('iframe').contents()` returns `contentDocument` for this specific iframe + + + Iframe contents + + ```js + // jQuery + $iframe.contents(); + + // Native + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Native + iframe.contentDocument.querySelectorAll('.css'); + ``` + +- [1.10](#1.10) Get body + + ```js + // jQuery + $('body'); + + // Native + document.body; + ``` + +- [1.11](#1.11) Attribute getter and setter + + + Get an attribute + + ```js + // jQuery + $el.attr('foo'); + + // Native + el.getAttribute('foo'); + ``` + + Set an attribute + + ```js + // jQuery, note that this works in memory without change the DOM + $el.attr('foo', 'bar'); + + // Native + el.setAttribute('foo', 'bar'); + ``` + + + Get a `data-` attribute + + ```js + // jQuery + $el.data('foo'); + + // Native (use `getAttribute`) + el.getAttribute('data-foo'); + // Native (use `dataset` if only need to support IE 11+) + el.dataset['foo']; + ``` + +**[⬆ back to top](#table-of-contents)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + Get style + + ```js + // jQuery + $el.css("color"); + + // Native + // NOTE: Known bug, will return 'auto' if style value is 'auto' + const win = el.ownerDocument.defaultView; + // null means not return pseudo styles + win.getComputedStyle(el, null).color; + ``` + + + Set style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Native + el.style.color = '#ff0011'; + ``` + + + Get/Set Styles + + Note that if you want to set multiple styles once, you could refer to [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) method in oui-dom-utils package. + + + + Add class + + ```js + // jQuery + $el.addClass(className); + + // Native + el.classList.add(className); + ``` + + + Remove class + + ```js + // jQuery + $el.removeClass(className); + + // Native + el.classList.remove(className); + ``` + + + has class + + ```js + // jQuery + $el.hasClass(className); + + // Native + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Native + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Width & Height + + Width and Height are theoretically identical, take Height as example: + + + Window height + + ```js + // window height + $(window).height(); + // without scrollbar, behaves like jQuery + window.document.documentElement.clientHeight; + // with scrollbar + window.innerHeight; + ``` + + + Document height + + ```js + // jQuery + $(document).height(); + + // Native + document.documentElement.scrollHeight; + ``` + + + Element height + + ```js + // jQuery + $el.height(); + + // Native + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // accurate to integer(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.clientHeight; + // accurate to decimal(when `border-box`, it's `height`; when `content-box`, it's `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Native + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Native + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Native + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ back to top](#table-of-contents)** + +## DOM Manipulation + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Native + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Get text + + ```js + // jQuery + $el.text(); + + // Native + el.textContent; + ``` + + + Set text + + ```js + // jQuery + $el.text(string); + + // Native + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Get HTML + + ```js + // jQuery + $el.html(); + + // Native + el.innerHTML; + ``` + + + Set HTML + + ```js + // jQuery + $el.html(htmlString); + + // Native + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + Append child element after the last child of parent element + + ```js + // jQuery + $el.append("
hello
"); + + // Native + el.insertAdjacentHTML("beforeend","
hello
"); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Native + el.insertAdjacentHTML("afterbegin","
hello
"); + ``` + +- [3.6](#3.6) insertBefore + + Insert a new node before the selected elements + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Insert a new node after the selected elements + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +- [3.8](#3.8) is + + Return `true` if it matches the query selector + + ```js + // jQuery - Notice `is` also work with `function` or `elements` which is not concerned here + $el.is(selector); + + // Native + el.matches(selector); + ``` +- [3.9](#3.9) clone + + Create a deep copy of that element + + ```js + // jQuery + $el.clone(); + + // Native + el.cloneNode(); + + // For Deep clone , set param as `true` + ``` + +- [3.10](#3.10) empty + + Remove all child nodes + + ```js + // jQuery + $el.empty(); + + // Native + el.innerHTML = ''; + ``` + +- [3.11](#3.11) wrap + + Wrap an HTML structure around each element + + ```js + // jQuery + $('.inner').wrap('
'); + + // Native + [].slice.call(document.querySelectorAll('.inner')).forEach(function(el){ + var wrapper = document.createElement('div'); + wrapper.className = 'wrapper'; + el.parentNode.insertBefore(wrapper, el); + el.parentNode.removeChild(el); + wrapper.appendChild(el); + }); + ``` + +- [3.12](#3.12) unwrap + + Remove the parents of the set of matched elements from the DOM + + ```js + // jQuery + $('.inner').unwrap(); + + // Native + [].slice.call(document.querySelectorAll('.inner')).forEach(function(el){ + [].slice.call(el.childNodes).forEach(function(child){ + el.parentNode.insertBefore(child, el); + }); + el.parentNode.removeChild(el); + }); + ``` + + - [3.13](#3.13) replaceWith + + Replace each element in the set of matched elements with the provided new content + + ```js + // jQuery + $('.inner').replaceWith('
'); + + // Native + [].slice.call(document.querySelectorAll('.inner')).forEach(function(el){ + var outer = document.createElement('div'); + outer.className = 'outer'; + el.parentNode.insertBefore(outer, el); + el.parentNode.removeChild(el); + }); + ``` + + +**[⬆ back to top](#table-of-contents)** + +## Ajax + +[Fetch API](https://fetch.spec.whatwg.org/) is the new standard to replace XMLHttpRequest to do ajax. It works on Chrome and Firefox, you can use polyfills to make it work on legacy browsers. + +Try [github/fetch](http://github.com/github/fetch) on IE9+ or [fetch-ie8](https://github.com/camsong/fetch-ie8/) on IE8+, [fetch-jsonp](https://github.com/camsong/fetch-jsonp) to make JSONP requests. + +**[⬆ back to top](#table-of-contents)** + +## Events + +For a complete replacement with namespace and delegation, refer to https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Bind an event with on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Native + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Unbind an event with off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Native + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Native + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Utilities + +Most of utilities are found by native API. Others advanced functions could be choosed better utilities library focus on consistency and performance. Recommend [lodash](https://lodash.com) to replace. + +- [6.1](#6.1) Basic utilities + + + isArray + + Determine whether the argument is an array. + + ```js + // jQuery + $.isArray(array); + + // Native + Array.isArray(array); + ``` + + + isWindow + + Determine whether the argument is a window. + + ```js + // jQuery + $.isArray(obj); + + // Native + function isWindow(obj) { + return obj != null && obj === obj.window; + } + ``` + + + inArray + + Search for a specified value within an array and return its index (or -1 if not found). + + ```js + // jQuery + $.inArray(item, array); + + // Native + Array.indexOf(item); + ``` + + + isNumbic + + Determines whether its argument is a number. + Use `typeof` to decide type. if necessary to use library, sometimes `typeof` isn't accurate. + + ```js + // jQuery + $.isNumbic(item); + + // Native + function isNumbic(item) { + return typeof value === 'number'; + } + ``` + + + isFunction + + Determine if the argument passed is a JavaScript function object. + + ```js + // jQuery + $.isFunction(item); + + // Native + function isFunction(item) { + return typeof value === 'function'; + } + ``` + + + isEmptyObject + + Check to see if an object is empty (contains no enumerable properties). + + ```js + // jQuery + $.isEmptyObject(obj); + + // Native + function isEmptyObject(obj) { + for (let key in obj) { + return false; + } + return true; + } + ``` + + + isPlanObject + + Check to see if an object is a plain object (created using “{}” or “new Object”). + + ```js + // jQuery + $.isPlanObject(obj); + + // Native + function isPlainObject(obj) { + if (typeof (obj) !== 'object' || obj.nodeType || obj != null && obj === obj.window) { + return false; + } + + if (obj.constructor && + !{}.hasOwnPropert.call(obj.constructor.prototype, 'isPrototypeOf')) { + return false; + } + + return true; + } + ``` + + + extend + + Merge the contents of two or more objects together into the first object. + object.assign is ES6 API, and you could use [polyfill](https://github.com/ljharb/object.assign) also. + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Native + Object.assign({}, defaultOpts, opts); + ``` + + + trim + + Remove the whitespace from the beginning and end of a string. + + ```js + // jQuery + $.trim(string); + + // Native + string.trim(); + ``` + + + map + + Translate all items in an array or object to new array of items. + + ```js + // jQuery + $.map(array, function(value, index) { + }); + + // Native + array.map(function(value, index) { + }); + ``` + + + each + + A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. + + ```js + // jQuery + $.each(array, function(value, index) { + }); + + // Native + array.forEach(function(value, index) { + }); + ``` + + + grep + + Finds the elements of an array which satisfy a filter function. + + ```js + // jQuery + $.grep(array, function(value, index) { + }); + + // Native + array.filter(function(value, index) { + }); + ``` + + + type + + Determine the internal JavaScript [[Class]] of an object. + + ```js + // jQuery + $.type(obj); + + // Native + Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase(); + ``` + + + merge + + Merge the contents of two arrays together into the first array. + + ```js + // jQuery + $.merge(array1, array2); + + // Native + // But concat function don't remove duplicate items. + function merge() { + return Array.prototype.concat.apply([], arguments) + } + ``` + + + now + + Return a number representing the current time. + + ```js + // jQuery + $.now(); + + // Native + Date.now(); + ``` + + + proxy + + Takes a function and returns a new one that will always have a particular context. + + ```js + // jQuery + $.proxy(fn, context); + + // Native + fn.bind(context); + ``` + + + makeArray + + Convert an array-like object into a true JavaScript array. + + ```js + // jQuery + $.makeArray(array); + + // Native + [].slice.call(array); + ``` + +- [6.2](#6.2) DOM utilities + + + unique + + Sorts an array of DOM elements, in place, with the duplicates removed. Note that this only works on arrays of DOM elements, not strings or numbers. + + Sizzle's API + + + contains + + Check to see if a DOM element is a descendant of another DOM element. + + ```js + // jQuery + $.contains(el, child); + + // Native + el !== child && el.contains(child); + ``` + +- [6.3](#6.3) Globaleval + + ```js + // jQuery + $.globaleval(code); + + // Native + function Globaleval(code) { + let script = document.createElement('script'); + script.text = code; + + document.head.appendChild(script).parentNode.removeChild(script); + } + + // Use eval, but context of eval is current, context of $.Globaleval is global. + eval(code); + ``` + +- [6.4](#6.4) parse + + + parseHTML + + Parses a string into an array of DOM nodes. + + ```js + // jQuery + $.parseHTML(htmlString); + + // Native + function parseHTML(string) { + const tmp = document.implementation.createHTMLDocument(); + tmp.body.innerHTML = string; + return tmp.body.children; + } + ``` + + + parseJSON + + Takes a well-formed JSON string and returns the resulting JavaScript value. + + ```js + // jQuery + $.parseJSON(str); + + // Native + JSON.parse(str); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Promises + +A promise represents the eventual result of an asynchronous operation. jQuery has its own way to handle promises. Native JavaScript implements a thin and minimal API to handle promises according to the [Promises/A+](http://promises-aplus.github.io/promises-spec/) specification. + +- [7.1](#7.1) done, fail, always + + `done` is called when promise is resolved, `fail` is called when promise is rejected, `always` is called when promise is either resolved or rejected. + + ```js + // jQuery + $promise.done(doneCallback).fail(failCallback).always(alwaysCallback) + + // Native + promise.then(doneCallback, failCallback).then(alwaysCallback, alwaysCallback) + ``` + +- [7.2](#7.2) when + + `when` is used to handle multiple promises. It will resolve when all promises are resolved, and reject if either one is rejected. + + ```js + // jQuery + $.when($promise1, $promise2).done((promise1Result, promise2Result) => {}) + + // Native + Promise.all([$promise1, $promise2]).then([promise1Result, promise2Result] => {}); + ``` + +- [7.3](#7.3) Deferred + + Deferred is a way to create promises. + + ```js + // jQuery + function asyncFunc() { + var d = new $.Deferred(); + setTimeout(function() { + if(true) { + d.resolve('some_value_compute_asynchronously'); + } else { + d.reject('failed'); + } + }, 1000); + return d.promise(); + } + + // Native + function asyncFunc() { + return new Promise((resolve, reject) => { + setTimeout(function() { + if (true) { + resolve('some_value_compute_asynchronously'); + } else { + reject('failed'); + } + }, 1000); + }); + } + ``` + +**[⬆ back to top](#table-of-contents)** + +## Animation + +- [8.1](#8.1) Show & Hide + + ```js + // jQuery + $el.show(); + $el.hide(); + + // Native + // More detail about show method, please refer to https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L363 + el.style.display = ''|'inline'|'inline-block'|'inline-table'|'block'; + el.style.display = 'none'; + ``` + +- [8.2](#8.2) Toggle + + ```js + // jQuery + $el.toggle(); + + // Native + if (el.ownerDocument.defaultView.getComputedStyle(el, null).display === 'none') { + el.style.display = ''|'inline'|'inline-block'|'inline-table'|'block'; + } + else { + el.style.display = 'none'; + } + ``` + +- [8.3](#8.3) FadeIn & FadeOut + + ```js + // jQuery + $el.fadeIn(3000); + $el.fadeOut(3000); + + // Native + el.style.transition = 'opacity 3s'; + // fadeIn + el.style.opacity = '1'; + // fadeOut + el.style.opacity = '0'; + ``` + +- [8.4](#8.4) FadeTo + + ```js + // jQuery + $el.fadeTo('slow',0.15); + // Native + el.style.transition = 'opacity 3s'; // assume 'slow' equals 3 seconds + el.style.opacity = '0.15'; + ``` + +- [8.5](#8.5) FadeToggle + + ```js + // jQuery + $el.fadeToggle(); + + // Native + el.style.transition = 'opacity 3s'; + let { opacity } = el.ownerDocument.defaultView.getComputedStyle(el, null); + if (opacity === '1') { + el.style.opacity = '0'; + } + else { + el.style.opacity = '1'; + } + ``` + +- [8.6](#8.6) SlideUp & SlideDown + + ```js + // jQuery + $el.slideUp(); + $el.slideDown(); + + // Native + let originHeight = '100px'; + el.style.transition = 'height 3s'; + // slideUp + el.style.height = '0px'; + // slideDown + el.style.height = originHeight; + ``` + +- [8.7](#8.7) SlideToggle + + ```js + // jQuery + $el.slideToggle(); + + // Native + let originHeight = '100px'; + el.style.transition = 'height 3s'; + let { height } = el.ownerDocument.defaultView.getComputedStyle(el, null); + if (parseInt(height, 10) === 0) { + el.style.height = originHeight; + } + else { + el.style.height = '0px'; + } + ``` + +- [8.8](#8.8) Animate + + ```js + // jQuery + $el.animate({params}, speed); + + // Native + el.style.transition = 'all' + speed; + Object.keys(params).forEach(function(key) { + el.style[key] = params[key]; + }) + ``` + +## Alternatives + +* [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Examples of how to do common event, element, ajax etc with plain javascript. +* [npm-dom](http://github.com/npm-dom) and [webmodules](http://github.com/webmodules) - Organizations you can find individual DOM modules on NPM + +## Translations + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) +* [Italian](./README-it.md) + +## Browser Support + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# License + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.pt-BR.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.pt-BR.md new file mode 100644 index 000000000..e576f0ec4 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.pt-BR.md @@ -0,0 +1,628 @@ +> #### You Don't Need jQuery + +Você não precisa de jQuery +--- + +Ambientes Frontend evoluem rapidamente nos dias de hoje, navegadores modernos já implementaram uma grande parte das APIs DOM/BOM que são boas o suficiente. Nós não temos que aprender jQuery a partir do zero para manipulação do DOM ou eventos. Nesse meio tempo, graças a bibliotecas frontend como React, Angular e Vue, a manipulação direta do DOM torna-se um anti-padrão, jQuery é menos importante do que nunca. Este projeto resume a maioria das alternativas dos métodos jQuery em implementação nativa, com suporte ao IE 10+. + +## Tabela de conteúdos + +1. [Query Selector](#query-selector) +1. [CSS & Estilo](#css--estilo) +1. [Manipulação do DOM](#manipulação-do-dom) +1. [Ajax](#ajax) +1. [Eventos](#eventos) +1. [Utilitários](#utilitários) +1. [Suporte dos Navegadores](#suporte-dos-navegadores) + +## Query Selector + +No lugar de seletores comuns como classe, id ou atributo podemos usar `document.querySelector` ou `document.querySelectorAll` para substituição. As diferenças são: +* `document.querySelector` retorna o primeiro elemento correspondente +* `document.querySelectorAll` retorna todos os elementos correspondentes como NodeList. Pode ser convertido para Array usando `[].slice.call(document.querySelectorAll(selector) || []);` +* Se não tiver elementos correspondentes, jQuery retornaria `[]` considerando que a DOM API irá retornar `null`. Preste atenção ao Null Pointer Exception. Você também pode usar `||` para definir um valor padrão caso nenhum elemento seja encontrado, como `document.querySelectorAll(selector) || []` + +> Aviso: `document.querySelector` e `document.querySelectorAll` são bastante **LENTOS**, tente usar `getElementById`, `document.getElementsByClassName` ou `document.getElementsByTagName` se você quer ter uma maior performance. + +- [1.0](#1.0) Query por seletor + + ```js + // jQuery + $('selector'); + + // Nativo + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Query por classe + + ```js + // jQuery + $('.class'); + + // Nativo + document.querySelectorAll('.class'); + + // ou + document.getElementsByClassName('class'); + ``` + +- [1.2](#1.2) Query por id + + ```js + // jQuery + $('#id'); + + // Nativo + document.querySelector('#id'); + + // ou + document.getElementById('id'); + ``` + +- [1.3](#1.3) Query por atributo + + ```js + // jQuery + $('a[target=_blank]'); + + // Nativo + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Find sth. + + + Busca por nós + + ```js + // jQuery + $el.find('li'); + + // Nativo + el.querySelectorAll('li'); + ``` + + + Buscar `body` + + ```js + // jQuery + $('body'); + + // Nativo + document.body; + ``` + + + Buscar atributos + + ```js + // jQuery + $el.attr('foo'); + + // Nativo + e.getAttribute('foo'); + ``` + + + Buscar atributos `data-` + + ```js + // jQuery + $el.data('foo'); + + // Nativo + // usando getAttribute + el.getAttribute('data-foo'); + // você também pode usar `dataset` se você precisar suportar apenas IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Sibling/Previous/Next Elements + + + Sibling elements + + ```js + // jQuery + $el.siblings(); + + // Nativo + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Previous elements + + ```js + // jQuery + $el.prev(); + + // Nativo + el.previousElementSibling; + + ``` + + + Next elements + + ```js + // jQuery + $el.next(); + + // Nativo + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Retorna o primeiro elemento que corresponda ao seletor, partindo do elemento atual para o document. + + ```js + // jQuery + $el.closest(queryString); + + // Nativo + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + Obtém os ancestrais de cada elemento no atual conjunto de elementos combinados, mas não inclui o elemento correspondente pelo seletor, nó do DOM, ou objeto jQuery. + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Nativo + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Nativo + document.querySelector('#my-input').value; + ``` + + + Obter o índice do e.currentTarget entre `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Nativo + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + `$('iframe').contents()` retorna `contentDocument` para este iframe específico + + + Iframe contents + + ```js + // jQuery + $iframe.contents(); + + // Nativo + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Nativo + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ ir para o topo](#tabela-de-conteúdos)** + + +## CSS & Estilo + +- [2.1](#2.1) CSS + + + Obter estilo + + ```js + // jQuery + $el.css("color"); + + // Nativo + // AVISO: Bug conhecido, irá retornar 'auto' se o valor do estilo for 'auto' + const win = el.ownerDocument.defaultView; + // null significa não retornar estilos + win.getComputedStyle(el, null).color; + ``` + + + Definir Estilo + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Nativo + el.style.color = '#ff0011'; + ``` + + + Get/Set Styles + + Observe que se você deseja setar vários estilos de uma vez, você pode optar por [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) método no pacote oui-dom-utils. + + + + Adicionar classe + + ```js + // jQuery + $el.addClass(className); + + // Nativo + el.classList.add(className); + ``` + + + Remover classe + + ```js + // jQuery + $el.removeClass(className); + + // Nativo + el.classList.remove(className); + ``` + + + Verificar classe + + ```js + // jQuery + $el.hasClass(className); + + // Nativo + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Nativo + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Largura e Altura + + `width` e `height` são teoricamente idênticos, vamos pegar `height` como exemplo: + + + Altura da janela + + ```jsc + // window height + $(window).height(); + // sem scrollbar, se comporta como jQuery + window.document.documentElement.clientHeight; + // com scrollbar + window.innerHeight; + ``` + + + Altura do Documento + + ```js + // jQuery + $(document).height(); + + // Nativo + document.documentElement.scrollHeight; + ``` + + + Altura do Elemento + + ```js + // jQuery + $el.height(); + + // Nativo + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // preciso para inteiro(quando `border-box`, é `height`; quando `content-box`, é `height + padding + border`) + el.clientHeight; + // preciso para decimal(quando `border-box`, é `height`; quando `content-box`, é `height + padding + border`) + el.getBoundingClientRect().height; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Nativo + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Nativo + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Rolar para o topo + + ```js + // jQuery + $(window).scrollTop(); + + // Nativo + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ ir para o topo](#tabela-de-conteúdos)** + +## Manipulação do Dom + +- [3.1](#3.1) Remover + ```js + // jQuery + $el.remove(); + + // Nativo + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Texto + + + Obter texto + + ```js + // jQuery + $el.text(); + + // Nativo + el.textContent; + ``` + + + Definir texto + + ```js + // jQuery + $el.text(string); + + // Nativo + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Obter HTML + + ```js + // jQuery + $el.html(); + + // Nativo + el.innerHTML; + ``` + + + Definir HTML + + ```js + // jQuery + $el.html(htmlString); + + // Nativo + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + Incluir elemento filho após o último filho do elemento pai. + + ```js + // jQuery + $el.append("
hello
"); + + // Nativo + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.appendChild(newEl); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Nativo + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.insertBefore(newEl, el.firstChild); + ``` + +- [3.6](#3.6) insertBefore + + Insere um novo nó antes dos elementos selecionados. + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Nativo + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + Insere um novo nó após os elementos selecionados. + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Nativo + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +**[⬆ ir para o topo](#tabela-de-conteúdos)** + +## Ajax + +Substitua por [fetch](https://github.com/camsong/fetch-ie8) e [fetch-jsonp](https://github.com/camsong/fetch-jsonp) + +**[⬆ ir para o topo](#tabela-de-conteúdos)** + +## Eventos + +Para uma substituição completa com namespace e delegation, consulte https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) `Bind` num evento com `on` + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Nativo + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) `Unbind` num evento com `off` + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Nativo + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Nativo + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ ir para o topo](#tabela-de-conteúdos)** + +## Utilitários + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Nativo + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Nativo + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + Use o polyfill `object.assign` para eetender um Object: https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Nativo + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Nativo + el !== child && el.contains(child); + ``` + +**[⬆ ir para o topo](#tabela-de-conteúdos)** + +## Suporte dos Navegadores + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# Licença + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.zh-CN.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.zh-CN.md new file mode 100644 index 000000000..24d6f8795 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/README.zh-CN.md @@ -0,0 +1,656 @@ +## You Don't Need jQuery + +前端发展很快,现代浏览器原生 API 已经足够好用。我们并不需要为了操作 DOM、Event 等再学习一下 jQuery 的 API。同时由于 React、Angular、Vue 等框架的流行,直接操作 DOM 不再是好的模式,jQuery 使用场景大大减少。本项目总结了大部分 jQuery API 替代的方法,暂时只支持 IE10+ 以上浏览器。 + +## 目录 + +1. [Query Selector](#query-selector) +1. [CSS & Style](#css--style) +1. [DOM Manipulation](#dom-manipulation) +1. [Ajax](#ajax) +1. [Events](#events) +1. [Utilities](#utilities) +1. [Alternatives](#alternatives) +1. [Translations](#translations) +1. [Browser Support](#browser-support) + +## Query Selector + +常用的 class、id、属性 选择器都可以使用 `document.querySelector` 或 `document.querySelectorAll` 替代。区别是 +* `document.querySelector` 返回第一个匹配的 Element +* `document.querySelectorAll` 返回所有匹配的 Element 组成的 NodeList。它可以通过 `[].slice.call()` 把它转成 Array +* 如果匹配不到任何 Element,jQuery 返回空数组 `[]`,但 `document.querySelector` 返回 `null`,注意空指针异常。当找不到时,也可以使用 `||` 设置默认的值,如 `document.querySelectorAll(selector) || []` + +> 注意:`document.querySelector` 和 `document.querySelectorAll` 性能很**差**。如果想提高性能,尽量使用 `document.getElementById`、`document.getElementsByClassName` 或 `document.getElementsByTagName`。 + +- [1.0](#1.0) Query by selector + + ```js + // jQuery + $('selector'); + + // Native + document.querySelectorAll('selector'); + ``` + +- [1.1](#1.1) Query by class + + ```js + // jQuery + $('.css'); + + // Native + document.querySelectorAll('.css'); + + // or + document.getElementsByClassName('css'); + ``` + +- [1.2](#1.2) Query by id + + ```js + // jQuery + $('#id'); + + // Native + document.querySelector('#id'); + + // or + document.getElementById('id'); + ``` + +- [1.3](#1.3) Query by attribute + + ```js + // jQuery + $('a[target=_blank]'); + + // Native + document.querySelectorAll('a[target=_blank]'); + ``` + +- [1.4](#1.4) Find sth. + + + Find nodes + + ```js + // jQuery + $el.find('li'); + + // Native + el.querySelectorAll('li'); + ``` + + + Find body + + ```js + // jQuery + $('body'); + + // Native + document.body; + ``` + + + Find Attribute + + ```js + // jQuery + $el.attr('foo'); + + // Native + e.getAttribute('foo'); + ``` + + + Find data attribute + + ```js + // jQuery + $el.data('foo'); + + // Native + // using getAttribute + el.getAttribute('data-foo'); + // you can also use `dataset` if only need to support IE 11+ + el.dataset['foo']; + ``` + +- [1.5](#1.5) Sibling/Previous/Next Elements + + + Sibling elements + + ```js + // jQuery + $el.siblings(); + + // Native + [].filter.call(el.parentNode.children, function(child) { + return child !== el; + }); + ``` + + + Previous elements + + ```js + // jQuery + $el.prev(); + + // Native + el.previousElementSibling; + + ``` + + + Next elements + + ```js + // next + $el.next(); + el.nextElementSibling; + ``` + +- [1.6](#1.6) Closest + + Closest 获得匹配选择器的第一个祖先元素,从当前元素开始沿 DOM 树向上。 + + ```js + // jQuery + $el.closest(queryString); + + // Native + function closest(el, selector) { + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + while (el) { + if (matchesSelector.call(el, selector)) { + return el; + } else { + el = el.parentElement; + } + } + return null; + } + ``` + +- [1.7](#1.7) Parents Until + + 获取当前每一个匹配元素集的祖先,不包括匹配元素的本身。 + + ```js + // jQuery + $el.parentsUntil(selector, filter); + + // Native + function parentsUntil(el, selector, filter) { + const result = []; + const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector; + + // match start from parent + el = el.parentElement; + while (el && !matchesSelector.call(el, selector)) { + if (!filter) { + result.push(el); + } else { + if (matchesSelector.call(el, filter)) { + result.push(el); + } + } + el = el.parentElement; + } + return result; + } + ``` + +- [1.8](#1.8) Form + + + Input/Textarea + + ```js + // jQuery + $('#my-input').val(); + + // Native + document.querySelector('#my-input').value; + ``` + + + Get index of e.currentTarget between `.radio` + + ```js + // jQuery + $(e.currentTarget).index('.radio'); + + // Native + [].indexOf.call(document.querySelectAll('.radio'), e.currentTarget); + ``` + +- [1.9](#1.9) Iframe Contents + + jQuery 对象的 iframe `contents()` 返回的是 iframe 内的 `document` + + + Iframe contents + + ```js + // jQuery + $iframe.contents(); + + // Native + iframe.contentDocument; + ``` + + + Iframe Query + + ```js + // jQuery + $iframe.contents().find('.css'); + + // Native + iframe.contentDocument.querySelectorAll('.css'); + ``` + +**[⬆ 回到顶部](#目录)** + +## CSS & Style + +- [2.1](#2.1) CSS + + + Get style + + ```js + // jQuery + $el.css("color"); + + // Native + // 注意:此处为了解决当 style 值为 auto 时,返回 auto 的问题 + const win = el.ownerDocument.defaultView; + // null 的意思是不返回伪类元素 + win.getComputedStyle(el, null).color; + ``` + + + Set style + + ```js + // jQuery + $el.css({ color: "#ff0011" }); + + // Native + el.style.color = '#ff0011'; + ``` + + + Get/Set Styles + + 注意,如果想一次设置多个 style,可以参考 oui-dom-utils 中 [setStyles](https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L194) 方法 + + + Add class + + ```js + // jQuery + $el.addClass(className); + + // Native + el.classList.add(className); + ``` + + + Remove class + + ```js + // jQuery + $el.removeClass(className); + + // Native + el.classList.remove(className); + ``` + + + has class + + ```js + // jQuery + $el.hasClass(className); + + // Native + el.classList.contains(className); + ``` + + + Toggle class + + ```js + // jQuery + $el.toggleClass(className); + + // Native + el.classList.toggle(className); + ``` + +- [2.2](#2.2) Width & Height + + Width 与 Height 获取方法相同,下面以 Height 为例: + + + Window height + + ```js + // jQuery + $(window).height(); + + // Native + // 不含 scrollbar,与 jQuery 行为一致 + window.document.documentElement.clientHeight; + // 含 scrollbar + window.innerHeight; + ``` + + + Document height + + ```js + // jQuery + $(document).height(); + + // Native + document.documentElement.scrollHeight; + ``` + + + Element height + + ```js + // jQuery + $el.height(); + + // Native + // 与 jQuery 一致(一直为 content 区域的高度) + function getHeight(el) { + const styles = this.getComputedStyles(el); + const height = el.offsetHeight; + const borderTopWidth = parseFloat(styles.borderTopWidth); + const borderBottomWidth = parseFloat(styles.borderBottomWidth); + const paddingTop = parseFloat(styles.paddingTop); + const paddingBottom = parseFloat(styles.paddingBottom); + return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom; + } + // 精确到整数(border-box 时为 height 值,content-box 时为 height + padding + border 值) + el.clientHeight; + // 精确到小数(border-box 时为 height 值,content-box 时为 height + padding + border 值) + el.getBoundingClientRect().height; + ``` + + + Iframe height + + $iframe .contents() 方法返回 iframe 的 contentDocument + + ```js + // jQuery + $('iframe').contents().height(); + + // Native + iframe.contentDocument.documentElement.scrollHeight; + ``` + +- [2.3](#2.3) Position & Offset + + + Position + + ```js + // jQuery + $el.position(); + + // Native + { left: el.offsetLeft, top: el.offsetTop } + ``` + + + Offset + + ```js + // jQuery + $el.offset(); + + // Native + function getOffset (el) { + const box = el.getBoundingClientRect(); + + return { + top: box.top + window.pageYOffset - document.documentElement.clientTop, + left: box.left + window.pageXOffset - document.documentElement.clientLeft + } + } + ``` + +- [2.4](#2.4) Scroll Top + + ```js + // jQuery + $(window).scrollTop(); + + // Native + (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop; + ``` + +**[⬆ 回到顶部](#目录)** + +## DOM Manipulation + +- [3.1](#3.1) Remove + ```js + // jQuery + $el.remove(); + + // Native + el.parentNode.removeChild(el); + ``` + +- [3.2](#3.2) Text + + + Get text + + ```js + // jQuery + $el.text(); + + // Native + el.textContent; + ``` + + + Set text + + ```js + // jQuery + $el.text(string); + + // Native + el.textContent = string; + ``` + +- [3.3](#3.3) HTML + + + Get HTML + + ```js + // jQuery + $el.html(); + + // Native + el.innerHTML; + ``` + + + Set HTML + + ```js + // jQuery + $el.html(htmlString); + + // Native + el.innerHTML = htmlString; + ``` + +- [3.4](#3.4) Append + + Append 插入到子节点的末尾 + + ```js + // jQuery + $el.append("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.appendChild(newEl); + ``` + +- [3.5](#3.5) Prepend + + ```js + // jQuery + $el.prepend("
hello
"); + + // Native + let newEl = document.createElement('div'); + newEl.setAttribute('id', 'container'); + newEl.innerHTML = 'hello'; + el.insertBefore(newEl, el.firstChild); + ``` + +- [3.6](#3.6) insertBefore + + 在选中元素前插入新节点 + + ```js + // jQuery + $newEl.insertBefore(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target); + ``` + +- [3.7](#3.7) insertAfter + + 在选中元素后插入新节点 + + ```js + // jQuery + $newEl.insertAfter(queryString); + + // Native + const target = document.querySelector(queryString); + target.parentNode.insertBefore(newEl, target.nextSibling); + ``` + +**[⬆ 回到顶部](#目录)** + +## Ajax + +用 [fetch](https://github.com/camsong/fetch-ie8) 和 [fetch-jsonp](https://github.com/camsong/fetch-jsonp) 替代 + +**[⬆ 回到顶部](#目录)** + +## Events + +完整地替代命名空间和事件代理,链接到 https://github.com/oneuijs/oui-dom-events + +- [5.1](#5.1) Bind an event with on + + ```js + // jQuery + $el.on(eventName, eventHandler); + + // Native + el.addEventListener(eventName, eventHandler); + ``` + +- [5.2](#5.2) Unbind an event with off + + ```js + // jQuery + $el.off(eventName, eventHandler); + + // Native + el.removeEventListener(eventName, eventHandler); + ``` + +- [5.3](#5.3) Trigger + + ```js + // jQuery + $(el).trigger('custom-event', {key1: 'data'}); + + // Native + if (window.CustomEvent) { + const event = new CustomEvent('custom-event', {detail: {key1: 'data'}}); + } else { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('custom-event', true, true, {key1: 'data'}); + } + + el.dispatchEvent(event); + ``` + +**[⬆ 回到顶部](#目录)** + +## Utilities + +- [6.1](#6.1) isArray + + ```js + // jQuery + $.isArray(range); + + // Native + Array.isArray(range); + ``` + +- [6.2](#6.2) Trim + + ```js + // jQuery + $.trim(string); + + // Native + string.trim(); + ``` + +- [6.3](#6.3) Object Assign + + 继承,使用 object.assign polyfill https://github.com/ljharb/object.assign + + ```js + // jQuery + $.extend({}, defaultOpts, opts); + + // Native + Object.assign({}, defaultOpts, opts); + ``` + +- [6.4](#6.4) Contains + + ```js + // jQuery + $.contains(el, child); + + // Native + el !== child && el.contains(child); + ``` + +**[⬆ 回到顶部](#目录)** + +## Alternatives + +* [你可能不需要 jQuery (You Might Not Need jQuery)](http://youmightnotneedjquery.com/) - 如何使用原生 JavaScript 实现通用事件,元素,ajax 等用法。 +* [npm-dom](http://github.com/npm-dom) 以及 [webmodules](http://github.com/webmodules) - 在 NPM 上提供独立 DOM 模块的组织 + +## Translations + +* [한국어](./README.ko-KR.md) +* [简体中文](./README.zh-CN.md) +* [Bahasa Melayu](./README-my.md) +* [Bahasa Indonesia](./README-id.md) +* [Português(PT-BR)](./README.pt-BR.md) +* [Tiếng Việt Nam](./README-vi.md) +* [Español](./README-es.md) +* [Русский](./README-ru.md) +* [Türkçe](./README-tr.md) +* [Italian](./README-it.md) + +## Browser Support + +![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +--- | --- | --- | --- | --- | +Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ | + +# License + +MIT diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/git.git b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/git.git new file mode 100644 index 000000000..c115085f7 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/git.git @@ -0,0 +1 @@ +gitdir: ../.git/modules/You-Dont-Need-jQuery diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/karma.conf.js b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/karma.conf.js new file mode 100644 index 000000000..f935ae405 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/karma.conf.js @@ -0,0 +1,92 @@ +// Karma configuration +// Generated on Sun Nov 22 2015 22:10:47 GMT+0800 (CST) +require('babel-core/register'); + +module.exports = function(config) { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '.', + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['mocha'], + + // list of files / patterns to load in the browser + files: [ + './test/**/*.spec.js' + ], + + // list of files to exclude + exclude: [ + ], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + 'test/**/*.spec.js': ['webpack', 'sourcemap'] + }, + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + coverageReporter: { + reporters: [ + {type: 'text'}, + {type: 'html', dir: 'coverage'}, + ] + }, + + webpackMiddleware: { + stats: 'minimal' + }, + + webpack: { + cache: true, + devtool: 'inline-source-map', + module: { + loaders: [{ + test: /\.jsx?$/, + loader: 'babel-loader', + exclude: /node_modules/ + }], + postLoaders: [{ + test: /\.js/, + exclude: /(test|node_modules)/, + loader: 'istanbul-instrumenter' + }], + }, + resolve: { + extensions: ['', '.js', '.jsx'] + } + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Firefox'], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + // singleRun: false, + + // Concurrency level + // how many browser should be started simultanous + // concurrency: Infinity, + + // plugins: ['karma-phantomjs-launcher', 'karma-sourcemap-loader', 'karma-webpack'] + }) +} diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/package.json b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/package.json new file mode 100644 index 000000000..734e6ca90 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/package.json @@ -0,0 +1,53 @@ +{ + "name": "You-Dont-Need-jQuery", + "version": "1.0.0", + "description": "Examples of how to do query, style, dom, ajax, event etc like jQuery with plain javascript.", + "scripts": { + "test": "karma start --single-run", + "tdd": "karma start --auto-watch --no-single-run", + "test-cov": "karma start --auto-watch --single-run --reporters progress,coverage", + "lint": "eslint src test" + }, + "dependencies": {}, + "devDependencies": { + "babel-cli": "^6.2.0", + "babel-core": "^6.1.21", + "babel-eslint": "^4.1.5", + "babel-loader": "^6.2.0", + "babel-preset-es2015": "^6.1.18", + "babel-preset-stage-0": "^6.1.18", + "chai": "^3.4.1", + "eslint": "^1.9.0", + "eslint-config-airbnb": "^1.0.0", + "eslint-plugin-react": "^3.10.0", + "isparta": "^4.0.0", + "istanbul-instrumenter-loader": "^0.1.3", + "jquery": "^2.1.4", + "karma": "^0.13.15", + "karma-coverage": "^0.5.3", + "karma-firefox-launcher": "^0.1.7", + "karma-mocha": "^0.2.1", + "karma-sourcemap-loader": "^0.3.6", + "karma-webpack": "^1.7.0", + "mocha": "^2.3.4", + "webpack": "^1.12.9" + }, + "repository": { + "type": "git", + "url": "https://github.com/oneuijs/You-Dont-Need-jQuery.git" + }, + "keywords": [ + "convertion guide", + "jQuery", + "es6", + "es2015", + "babel", + "OneUI Group" + ], + "author": "OneUI Group", + "license": "MIT", + "bugs": { + "url": "https://github.com/oneuijs/You-Dont-Need-jQuery/issues" + }, + "homepage": "https://github.com/oneuijs/You-Dont-Need-jQuery" +} diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/README.md b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/README.md new file mode 100644 index 000000000..f0f376887 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/README.md @@ -0,0 +1,13 @@ +# Test cases for all the tips + +## Usage + +run all tests once +``` +npm run test +``` + +run tests on TDD(Test Driven Development) mode +``` +npm run tdd +``` diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/css.spec.js b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/css.spec.js new file mode 100644 index 000000000..99248f2bb --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/css.spec.js @@ -0,0 +1 @@ +// test for CSS related \ No newline at end of file diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/dom.spec.js b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/dom.spec.js new file mode 100644 index 000000000..5bfc287e9 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/dom.spec.js @@ -0,0 +1 @@ +// test for CSS and style related \ No newline at end of file diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/query.spec.js b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/query.spec.js new file mode 100644 index 000000000..f6b9c300e --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/query.spec.js @@ -0,0 +1,71 @@ +// tests for Query Selector related +import { expect } from 'chai'; +import $ from 'jquery'; + +describe('query selector', () => { + describe('basic', () => { + beforeEach(() => { + document.body.innerHTML = ` + + `; + }); + + afterEach(() => { + const el = document.querySelector('#query-selector-test1'); + el.parentNode.removeChild(el); + }); + + it('1.0 Query by selector', () => { + const $els = $('li.item[data-role="red"]'); + const els = document.querySelectorAll('li.item[data-role="red"]'); + + expect($els.length).to.equal(2); + [].forEach.call($els, function($el, i) { + expect($el).to.equal(els[i]); + }); + }); + + it('1.1 Query by class', () => { + const $els = $('.item'); + const els = document.getElementsByClassName('item'); + + [].forEach.call($els, function($el, i) { + expect($el).to.equal(els[i]); + }); + }); + + it('1.2 Query by id', () => { + expect($('#nested-ul')[0]).to.equal(document.getElementById('nested-ul')); + }); + + it('1.3 Query by attribute', () => { + const $els = $('[data-role="blue"]'); + const els = document.querySelectorAll('[data-role="blue"]'); + + expect($els.length).to.equal(2); + [].forEach.call($els, function($el, i) { + expect($el).to.equal(els[i]); + }); + }); + + it('1.4 Query in descendents', () => { + const $els = $('#query-selector-test1').find('.item'); + const els = document.getElementById('query-selector-test1').querySelectorAll('.item'); + + expect($els.length).to.equal(4); + [].forEach.call($els, function($el, i) { + expect($el).to.equal(els[i]); + }); + }); + }); +}); \ No newline at end of file diff --git a/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/utilities.spec.js b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/utilities.spec.js new file mode 100644 index 000000000..d68e723c5 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/You-Dont-Need-jQuery/test/utilities.spec.js @@ -0,0 +1 @@ +// test for Utilities related \ No newline at end of file diff --git a/spec/fixtures/git/repo-with-submodules/git.git/COMMIT_EDITMSG b/spec/fixtures/git/repo-with-submodules/git.git/COMMIT_EDITMSG new file mode 100644 index 000000000..196384738 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/COMMIT_EDITMSG @@ -0,0 +1,9 @@ +submodules +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# Changes to be committed: +# new file: .gitmodules +# new file: You-Dont-Need-jQuery +# new file: jstips +# diff --git a/spec/fixtures/git/repo-with-submodules/git.git/HEAD b/spec/fixtures/git/repo-with-submodules/git.git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/spec/fixtures/git/repo-with-submodules/git.git/config b/spec/fixtures/git/repo-with-submodules/git.git/config new file mode 100644 index 000000000..ab57cc5f1 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/config @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[submodule "jstips"] + url = https://github.com/loverajoel/jstips +[submodule "You-Dont-Need-jQuery"] + url = https://github.com/oneuijs/You-Dont-Need-jQuery diff --git a/spec/fixtures/git/repo-with-submodules/git.git/description b/spec/fixtures/git/repo-with-submodules/git.git/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/applypatch-msg.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/applypatch-msg.sample new file mode 100755 index 000000000..a5d7b84a6 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/commit-msg.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/commit-msg.sample new file mode 100755 index 000000000..b58d1184a --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/post-update.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/post-update.sample new file mode 100755 index 000000000..ec17ec193 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-applypatch.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-applypatch.sample new file mode 100755 index 000000000..4142082bc --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-commit.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-commit.sample new file mode 100755 index 000000000..68d62d544 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-push.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-push.sample new file mode 100755 index 000000000..6187dbf43 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-rebase.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-rebase.sample new file mode 100755 index 000000000..9773ed4cb --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +exit 0 + +################################################################ + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/prepare-commit-msg.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/prepare-commit-msg.sample new file mode 100755 index 000000000..f093a02ec --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/spec/fixtures/git/repo-with-submodules/git.git/hooks/update.sample b/spec/fixtures/git/repo-with-submodules/git.git/hooks/update.sample new file mode 100755 index 000000000..d84758373 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/spec/fixtures/git/repo-with-submodules/git.git/index b/spec/fixtures/git/repo-with-submodules/git.git/index new file mode 100644 index 0000000000000000000000000000000000000000..20f2cdc44cc7953336ba167ea622ac57807d3a5d GIT binary patch literal 377 zcmZ?q402{*U|<4bmax8AH9(pHMl%A%*d;cuU|?um!oa}z6(}VF#K#@JJfEqyBGBZ@ zN!AN~1>x3dVxRXgaO5bm(J>}Q<6<)jPt&P???hu`{ zb0-&rNMwGgu1kJiiLPI2YKm@FU}ebFyOM&fAm8sf7SNR@4UHPMTSp4?G3rl Zbbj)_S+51vScSe`S>5#c_E~B3?*J0haH#+Q literal 0 HcmV?d00001 diff --git a/spec/fixtures/git/repo-with-submodules/git.git/info/exclude b/spec/fixtures/git/repo-with-submodules/git.git/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/spec/fixtures/git/repo-with-submodules/git.git/logs/HEAD b/spec/fixtures/git/repo-with-submodules/git.git/logs/HEAD new file mode 100644 index 000000000..d41c1a106 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/logs/HEAD @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 d3e073baf592c56614c68ead9e2cd0a3880140cd joshaber 1452185922 -0500 commit (initial): first +d3e073baf592c56614c68ead9e2cd0a3880140cd d2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5 joshaber 1452186239 -0500 commit: submodules diff --git a/spec/fixtures/git/repo-with-submodules/git.git/logs/refs/heads/master b/spec/fixtures/git/repo-with-submodules/git.git/logs/refs/heads/master new file mode 100644 index 000000000..d41c1a106 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/logs/refs/heads/master @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 d3e073baf592c56614c68ead9e2cd0a3880140cd joshaber 1452185922 -0500 commit (initial): first +d3e073baf592c56614c68ead9e2cd0a3880140cd d2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5 joshaber 1452186239 -0500 commit: submodules diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/HEAD b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/ORIG_HEAD b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/ORIG_HEAD new file mode 100644 index 000000000..b7cdcfd53 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/ORIG_HEAD @@ -0,0 +1 @@ +2e9bbc77d60f20eb462ead5b2ac7405b62b9b90a diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/config b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/config new file mode 100644 index 000000000..6ce8d21dd --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/config @@ -0,0 +1,14 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + worktree = ../../../You-Dont-Need-jQuery + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = https://github.com/oneuijs/You-Dont-Need-jQuery + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/description b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/gitdir b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/gitdir new file mode 100644 index 000000000..6b8710a71 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/gitdir @@ -0,0 +1 @@ +.git diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/applypatch-msg.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/applypatch-msg.sample new file mode 100755 index 000000000..a5d7b84a6 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/commit-msg.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/commit-msg.sample new file mode 100755 index 000000000..b58d1184a --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/post-update.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/post-update.sample new file mode 100755 index 000000000..ec17ec193 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-applypatch.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-applypatch.sample new file mode 100755 index 000000000..4142082bc --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-commit.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-commit.sample new file mode 100755 index 000000000..68d62d544 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-push.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-push.sample new file mode 100755 index 000000000..6187dbf43 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-rebase.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-rebase.sample new file mode 100755 index 000000000..9773ed4cb --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +exit 0 + +################################################################ + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/prepare-commit-msg.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/prepare-commit-msg.sample new file mode 100755 index 000000000..f093a02ec --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/update.sample b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/update.sample new file mode 100755 index 000000000..d84758373 --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/index b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/index new file mode 100644 index 0000000000000000000000000000000000000000..202c1f9ceb11e5e0d6143722d77602bbb12dd012 GIT binary patch literal 1919 zcmZ?q402{*U|<4b@vy#GH9(pHMl&)nu&_&P>}6nRT*AP>_!TH60>rA1+_iqB@0ulQ z%(ym3<(_T)&qdSEFmUK4B_^fj6eT0{qnXo(Y7V27+ppzEzdsPx6m;%ziaI~NlxwQS zHU>_;)Z(1Xyb_>6F#RwZ>Yjd7a~QOPr!}4ayY;<$z3q&JZe?3l&j%d4&A_FXo>`Ka zo|j*g3i1;Oz|4WsQ1d3BnKvu*yjbM|tI3QTUeC0Z`MopCWzV6j4BUDpMTupZ#d?*w zIS}K3<}G>xF&9EZ%sY1u)jSsC`-Y{Hy15_Uk=wJlB}psmN6W&1Vg_~}PiI%ZU{~Dk znuKbOMRBU4ifVL)z?6Awa&n~EYuS39Jo0AX337FG@paWrE!N9TfjA82KNt=5=VVm# z%nF51m2Nx!BH~3_`09OM_=S%Dx_Rmv+`P;bLgr0DHP1pp>&GOfwQuUIC-w{G{y6AZ z$GG^%L48Moa`obP7!!_6zpBxK%9RP*e9hqwlcJ`LQy zvS_tk@H1oErT>DWOu;c9EACfMr$NCB%o?fT69By7!hOV<8UVqL-HIH-2Pt$b{VVS)F z{hDQ>y$uy>zTdj?oPjqxu_!lDFF8LiO)sk$oY7$Zgwas{&Ox8-oDYyyW6y zz2bt@WU!ZE=D=vEd5h4@Q;hzjQ8%YeS3mZM?d;Dt7Ek$o=lMsdc`5n11kGEFY95Ev zx1EO>-rh@ow6%N+>(RYyUM)CleV;)H?7qU%)S^m+iFm^iScjq1W3t!!ifkfV_dnU& zs?F`#oy;k6tLPJh7}(s>lFS@n^#LqY;l5{J2nlip71!nrM#c(;T&wjK?Mt=eNxOY3 zH1TPxSk8+xre+|$45kVOT#lMsU! 1452186236 -0500 clone: from https://github.com/oneuijs/You-Dont-Need-jQuery diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/heads/master b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/heads/master new file mode 100644 index 000000000..a76a6d29f --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 2e9bbc77d60f20eb462ead5b2ac7405b62b9b90a joshaber 1452186236 -0500 clone: from https://github.com/oneuijs/You-Dont-Need-jQuery diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/remotes/origin/HEAD b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/remotes/origin/HEAD new file mode 100644 index 000000000..a76a6d29f --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 2e9bbc77d60f20eb462ead5b2ac7405b62b9b90a joshaber 1452186236 -0500 clone: from https://github.com/oneuijs/You-Dont-Need-jQuery diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/objects/pack/pack-d38b3bc339acd655e8dae9c0dcea8bb2ec174d16.idx b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/objects/pack/pack-d38b3bc339acd655e8dae9c0dcea8bb2ec174d16.idx new file mode 100644 index 0000000000000000000000000000000000000000..cb4b0b44e5f8cf06c01d8ac8368ec2008a8eb09a GIT binary patch literal 18152 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 literal 0 HcmV?d00001 diff --git a/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/objects/pack/pack-d38b3bc339acd655e8dae9c0dcea8bb2ec174d16.pack b/spec/fixtures/git/repo-with-submodules/git.git/modules/You-Dont-Need-jQuery/objects/pack/pack-d38b3bc339acd655e8dae9c0dcea8bb2ec174d16.pack new file mode 100644 index 0000000000000000000000000000000000000000..89a46ce6f10d13fb52dd189c2c05d6e9bd192155 GIT binary patch literal 202626 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