├── .editorconfig ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── codecov.yml ├── package.json ├── src ├── addCssRule.ts ├── delegate.ts ├── dom.ts ├── form.ts ├── has.ts ├── interfaces.ts ├── main.ts └── schedule.ts ├── tests ├── functional │ └── all.ts ├── intern-local.ts ├── intern-saucelabs.ts ├── intern.ts ├── run.html ├── support │ └── util.ts └── unit │ ├── addCssRule.ts │ ├── all.ts │ ├── delegate.ts │ ├── dom.ts │ ├── form.ts │ └── schedule.ts ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case users don't have core.autocrlf set 2 | * text=auto 3 | 4 | # Files that should always be normalized and converted to native line 5 | # endings on checkout. 6 | *.js text 7 | *.json text 8 | *.ts text 9 | *.md text 10 | *.yml text 11 | LICENSE text 12 | 13 | # Files that are truly binary and should not be modified 14 | *.png binary 15 | *.jpg binary 16 | *.jpeg binary 17 | *.gif binary 18 | *.jar binary 19 | *.zip binary 20 | *.psd binary 21 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Thank You 2 | 3 | We very much welcome contributions to Dojo 2. 4 | 5 | Because we have so many repositories that are part of Dojo 2, we have located our [Contributing Guidelines](https://github.com/dojo/meta/blob/master/CONTRIBUTING.md) in our [Dojo 2 Meta Repository](https://github.com/dojo/meta#readme). 6 | 7 | Look forward to working with you on Dojo 2!!! 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | **Bug / Enhancement** 13 | 14 | 15 | 16 | Package Version: 17 | 18 | **Code** 19 | 20 | 21 | 22 | **Expected behavior:** 23 | 24 | 25 | 26 | **Actual behavior:** 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Type:** bug / feature 2 | 3 | The following has been addressed in the PR: 4 | 5 | * [ ] There is a related issue 6 | * [ ] All code matches the [style guide](https://github.com/dojo/meta/blob/master/STYLE.md) 7 | * [ ] Unit or Functional tests are included in the PR 8 | 9 | 17 | 18 | **Description:** 19 | 20 | Resolves #??? 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sublimets 2 | .tscache 3 | .tsconfig*.json 4 | *.js 5 | !/index.js 6 | *.js.map 7 | !/*.js 8 | !/tasks/*.js 9 | dist 10 | _build 11 | node_modules 12 | bower_components 13 | tests/typings/dist/ 14 | /typings/** 15 | .baseDir.ts 16 | html-report 17 | coverage-unmapped.json 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /_build 2 | /html-report 3 | /support 4 | /tests 5 | /typings/** 6 | !/typings/extras.d.ts 7 | .editorconfig 8 | .gitattributes 9 | .gitignore 10 | .npmignore 11 | .travis.yml 12 | .tscache 13 | .vscode 14 | codecov.yml 15 | Gruntfile.js 16 | tsconfig.json 17 | tslint.json 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '6' 5 | env: 6 | global: 7 | - SAUCE_USERNAME: dojo2-ts-ci 8 | - SAUCE_ACCESS_KEY: e92610e3-834e-4bec-a3b5-6f7b9d874601 9 | - BROWSERSTACK_USERNAME: dtktestaccount1 10 | - BROWSERSTACK_ACCESS_KEY: mG2qbEFJCZY2qLsM7yfx 11 | install: 12 | - npm install grunt-cli 13 | - npm install 14 | script: 15 | - grunt 16 | - grunt intern:saucelabs --combined 17 | - grunt remapIstanbul:ci 18 | - grunt uploadCoverage 19 | notifications: 20 | slack: 21 | secure: OlHK5Ulgwan/uh6A4S4+Ex8oKORJ5fO6zbiQgwQNzTpfTglq5lwKgo110XmP4GSRNecFrVp5l6uCbxnX8RITO5Iki0ijjn1IIP0LADjvKsIpbIIcUJHQcWb3sPGP31Uuw6jdKkdG9F/WUDKPAiOUDLojL5p99wdQguAH/Yfgx2uxo7RoX0R8i69+M/IKEuz9jYn8LG5ZsKFHxPONsVPmVNXOThSgfkl/bGExHldV+z/5O5IKqOeGv3K2gD1SZN9qJs/lVA38rTMogyW4L0GUvSTpUGFuI2D9sB2ktQf2+s+QsugFiYgpYrvRiVCMNATah0yhwesaX+3xX4lUa+h873Mhw+Ii+uzicewDCfY9SZP+mZ2ct4YfwkvQxsn2LbL7lDUDK58NkHiQod0+RtQyFt4PXA8DIIhwcfrlvshhAGiQbnBmQvotxM0KpkBFQfq2SkBZY8vhkNQYTEj5U6MEOb3zjE4DhzN3ShpFSPhTENYbNdsUMzpEo/FNssjjCQf3vM+lq+5s7rTY5djQxi+GJqtlh5yf0uoPlsjwTk5e+8rCT+fp8qIoHocrP6zP9XLReMQnOes4im4Pzk9exfX6vnaIPQobDEykjyGIFdv6Y05A86CHdc4rcC7HC4EBTa6lAmqbayTng6nxYB+R0+M3mHBh0a5Zbh6igyFXVI5+sq0= 22 | on_success: change 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | The [Contributing Guidelines](https://github.com/dojo/meta/blob/master/CONTRIBUTING.md) 2 | for all Dojo 2 packages can be found in the [Dojo 2 Meta Repository](https://github.com/dojo/meta#readme). 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | require('grunt-dojo2').initConfig(grunt); 3 | }; 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The "New" BSD License 2 | ********************* 3 | 4 | Copyright (c) 2015 - 2017, [JS Foundation](https://js.foundation/) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | * Neither the name of the JS Foundation nor the names of its contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @dojo/dom 2 | 3 | **WARNING** This package is deprecated in favor of functionality found elsewhere in Dojo 2. This package is not being further developed at this time as its feature set is redundant with other capabilities. 4 | 5 | [![Build Status](https://travis-ci.org/dojo/dom.svg?branch=master)](https://travis-ci.org/dojo/dom) 6 | [![codecov.io](https://codecov.io/github/dojo/dom/coverage.svg?branch=master)](https://codecov.io/github/dojo/dom?branch=master) 7 | [![npm version](https://badge.fury.io/js/@dojo/dom.svg)](https://badge.fury.io/js/@dojo/dom) 8 | 9 | The `@dojo/dom` package provides utilities for DOM manipulation and event handling/delegation in browser runtimes. 10 | It encourages (and shims) standard DOM methods where possible, but also provides utilities to make 11 | common and recommended use cases easy and obvious, and harder use cases less painful. 12 | 13 | ## Features 14 | 15 | ### DOM Manipulation 16 | 17 | * `dom.applyFeatureClass` - accepts any number of feature test names (registered with the `has` module), and adds 18 | corresponding classes to the document element. 19 | * `dom.byId` - Retrieves an element by ID (shorthand for `document.getElementById`) 20 | * `dom.contains` - Determines if an element contains a given node 21 | * `dom.create` - Creates an element 22 | * `dom.fromString` - Creates an element or elements from a string of HTML 23 | * `dom.remove` - Detaches a node from its parent 24 | * `dom.place` - Places a node relative to another element 25 | 26 | ### CSS Class Manipulation 27 | 28 | The class manipulation APIs provide analogues to the `DOMTokenList` API. They will delegate to `classList` 29 | when available, adding logic when necessary to comply with the more recent parts of the standard 30 | (e.g. multiple add/remove arguments, optional force parameter for toggle). 31 | 32 | * `dom.addClass` - Adds one or more classes to an element 33 | * `dom.containsClass` - Tests if a particular class exists on an element 34 | * `dom.removeClass` - Removes one or more classes from an element 35 | * `dom.toggleClass` - Toggles a class on an element, optionally accepting a boolean to specifically add or remove 36 | 37 | ### CSS Style Manipulation 38 | 39 | The dom package provides the `addCssRule` function for adding styles *in a stylesheet*, rather than inline. This allows 40 | styles to be added programmatically on a per-selector basis, which is often more flexible and efficient than 41 | setting styles directly inline on one element. When used, `addCssRule` returns a handle that allows the rules for the provided selector to be manipulated. 42 | 43 | The dom package does *not* provide helpers for setting inline styles, as `element.style` generally accomplishes that, 44 | but moreover, inline styles should be discouraged as they override stylesheets and can be difficult to maintain. 45 | 46 | 47 | ### Form Manipulation 48 | 49 | These APIs are implemented in a separate `dom/form` module. 50 | 51 | * `form.fromObject` - Populates a DOM form's fields from a JavaScript object 52 | * `form.toObject` - Serializes the values in a form into a JavaScript object 53 | 54 | ### DOM Events 55 | 56 | The `@dojo/core/on` module already contains basic support for registering and removing DOM event handlers. 57 | The dom package adds APIs for event delegation in the `delegate` module. The `delegate` function allows an event 58 | handler to be attached to an element in order to respond to events raised by contained elements that match the provided 59 | selector. 60 | 61 | NOTE: `delegate` will only respond to events raised by contained elements. It will not respond to events raised by the container itself. 62 | 63 | 64 | ### Batch Operations 65 | 66 | There are many times when a large number of operations need to be applied to the DOM at one time. In order to enable this to be done 67 | as efficiently as possible, the `schedule` module provides functionality to group the operations together. 68 | 69 | * `schedule.read` - Schedules a function that will retrieve information about the DOM's current state 70 | * `schedule.write` - Schedules a function that will update the state of the DOM 71 | 72 | NOTE: In order to be as flexible as possible, the `read` and `write` functions define very generic interfaces. In order 73 | to ensure that the operations are executed efficiently, it is important to use these functions only for their intended purpose. 74 | 75 | ## How do I use this package? 76 | 77 | Users will need to download and compile directly from this repository and 78 | [dojo/core](https://github.com/dojo/core) for the time being. 79 | Precompiled AMD/CommonJS modules will be provided in the near future as our release tools are improved. 80 | 81 | Once you've downloaded `@dojo/core` and `@dojo/dom`, perform the following steps: 82 | 83 | ```sh 84 | cd @dojo/core 85 | grunt dist 86 | cd dist 87 | npm link 88 | cd ../../@dojo/dom 89 | npm install # (if you haven't already done this) 90 | npm link @dojo/core 91 | ``` 92 | 93 | ## How do I contribute? 94 | 95 | We appreciate your interest! Please see the [Guidelines Repository](https://github.com/dojo/guidelines#readme) for the 96 | Contributing Guidelines and Style Guide. 97 | 98 | ## Testing 99 | 100 | Test cases MUST be written using Intern using the Object test interface and Assert assertion interface. 101 | 102 | 90% branch coverage MUST be provided for all code submitted to this repository, as reported by istanbul’s combined coverage results for all supported platforms. 103 | 104 | ## Licensing information 105 | 106 | © 2004–2017 [JS Foundation](https://js.foundation/) & contributors. [New BSD](http://opensource.org/licenses/BSD-3-Clause) license. 107 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | notify: 3 | slack: 4 | default: 5 | url: "secret:k5GEC8oEbZhRsGocDatHxBOTUHbS+VJFidgXdldS4CwouRiILECdLvSEDA7720/VQKJUz8dnPx+I9ylsUkch+27/J2YNAmGAL6a84cikuk5n4WzUbvCkE7OYZlETF6U8Rdr3/6rRifmcbRurzL4frCq0I+/iBO4rPGrTHuaFTzQ=" 6 | threshold: 2 7 | attachments: "sunburst, diff" 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dojo/dom", 3 | "version": "2.0.0-pre", 4 | "description": "DOM Utilities for Dojo 2", 5 | "homepage": "https://dojo.io", 6 | "bugs": { 7 | "url": "https://github.com/dojo/dom/issues" 8 | }, 9 | "license": "BSD-3-Clause", 10 | "main": "main.js", 11 | "private": true, 12 | "engines": { 13 | "npm": ">=3.0.0" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/dojo/dom.git" 18 | }, 19 | "scripts": { 20 | "prepublish": "grunt peerDepInstall", 21 | "test": "grunt test" 22 | }, 23 | "peerDependencies": { 24 | "@dojo/core": "2.0.0-alpha.25", 25 | "@dojo/has": "2.0.0-alpha.8", 26 | "@dojo/shim": "2.0.0-beta.10" 27 | }, 28 | "devDependencies": { 29 | "@types/chai": "~3.4.0", 30 | "@types/es6-shim": "~0.31.0", 31 | "@types/glob": "~5.0.0", 32 | "@types/grunt": "~0.4.0", 33 | "@types/node": "^6.0.46", 34 | "@dojo/interfaces": "2.0.0-alpha.11", 35 | "@dojo/loader": "2.0.0-beta.9", 36 | "grunt": "^1.0.1", 37 | "grunt-dojo2": ">=2.0.0-beta.36", 38 | "intern": "^3.4.1", 39 | "istanbul": "~0.4.5", 40 | "remap-istanbul": ">=0.6.4", 41 | "typescript": "~2.2.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/addCssRule.ts: -------------------------------------------------------------------------------- 1 | import { Handle } from '@dojo/interfaces/core'; 2 | 3 | // The stylesheet that addCssRule adds rules to 4 | let extraSheet: CSSStyleSheet; 5 | 6 | // Array used to keep track of added rule indexes, used when rules are removed 7 | const ruleIndices: (number | undefined)[] = []; 8 | 9 | /** 10 | * A handle that can be used to update or remove a rule added by addCssRule. 11 | */ 12 | export interface CssRuleHandle extends Handle { 13 | get(property: string): string; 14 | remove(property: string): void; 15 | set(property: string, value: string): void; 16 | set(properties: { [property: string]: string }): void; 17 | } 18 | 19 | function destroyedFunc(): any { 20 | return null; 21 | } 22 | 23 | // The implementation is embedded in an internal namespace to allow it to use the same name as the interface. 24 | // Only the interface is exposed externally. 25 | namespace Impl { 26 | export class CssRuleHandle implements CssRuleHandle { 27 | constructor(index: number) { 28 | Object.defineProperty(this, '_index', { 29 | configurable: true, 30 | value: index 31 | }); 32 | Object.defineProperty(this, '_style', { 33 | configurable: true, 34 | value: ( extraSheet.cssRules[ ruleIndices[this._index]]).style 35 | }); 36 | } 37 | 38 | protected _index: number; 39 | protected _style: CSSStyleDeclaration; 40 | 41 | /** 42 | * Removes this rule entirely. 43 | * 44 | * @example 45 | * let handle = addCssRule('.foo', 'font-size:8px'); 46 | * handle.destroy(); 47 | */ 48 | destroy() { 49 | // Remove the rule from the dynamic styesheet 50 | const ruleIndex = ruleIndices[this._index] || 0; 51 | extraSheet.deleteRule(ruleIndex); 52 | 53 | // NOTE: This is intentionally not a splice, since the purpose of this array is 54 | // specifically to negotiate the splicing that occurs in the stylesheet itself 55 | ruleIndices[this._index] = undefined; 56 | 57 | // Update all the rule indices that were added after the one being removed to account for the removed rule. 58 | const numRules = ruleIndices.length; 59 | for (let i = this._index + 1; i < numRules; i++) { 60 | const currentRuleIndex = ruleIndices[i] || 0; 61 | if (currentRuleIndex > ruleIndex) { 62 | ruleIndices[i] = currentRuleIndex - 1; 63 | } 64 | } 65 | 66 | // Delete the cached style 67 | Object.defineProperty(this, '_style', { configurable: false, value: undefined }); 68 | Object.defineProperty(this, '_index', { configurable: false, value: undefined }); 69 | 70 | // Disable all functions on this handle to avoid errors from future calls 71 | this.destroy = this.get = this.remove = this.set = destroyedFunc; 72 | } 73 | 74 | /** 75 | * Gets the value for a style property in this rule. 76 | * 77 | * @param property A CSS property name (e.g. 'font-size') 78 | * 79 | * @example 80 | * let handle = addCssRule('.foo', 'font-size:8px'); 81 | * handle.get('font-size'); // '8px' 82 | */ 83 | get(property: string) { 84 | return this._style.getPropertyValue(property); 85 | } 86 | 87 | /** 88 | * Removes a style property from this rule. 89 | * 90 | * @param property A CSS property name (e.g. 'font-size') 91 | * 92 | * @example 93 | * let handle = addCssRule('.foo', 'font-size:8px;font-style:italic;'); 94 | * handle.remove('font-size'); 95 | */ 96 | remove(property: string) { 97 | this._style.removeProperty(property); 98 | } 99 | 100 | /** 101 | * Sets the value of a style property in this rule. 102 | * 103 | * @param property A CSS property name (e.g., 'font-size') or an object mapping property names to string values 104 | * @param value A property value (only used when property is a single property name) 105 | * 106 | * @example 107 | * let handle = addCssRule('.foo', 'font-size:8px'); 108 | * handle.set('font-size', '10px'); 109 | * handle.set({ 'font-style', 'italic', 'text-decoration': 'underline' }); 110 | */ 111 | set(property: { [property: string]: string }): void; 112 | set(property: string, value: string): void; 113 | set(property: string | { [ name: string ]: string }, value?: string): void { 114 | if (typeof property === 'object') { 115 | for (const name in property) { 116 | this._style.setProperty(name, property[name]); 117 | } 118 | } 119 | else if (value) { 120 | this._style.setProperty( property, value); 121 | } 122 | } 123 | } 124 | } 125 | 126 | /** 127 | * Dynamically adds a CSS rule to the document. 128 | * 129 | * @param selector a CSS selector 130 | * @param css a CSS rule string 131 | * @return an object that can be used to update and remove the rule 132 | * 133 | * @example 134 | * let handle = addCssRule('div.alert', 'background: red; color: white;'); 135 | */ 136 | export default function addCssRule(selector: string, css: string): CssRuleHandle { 137 | if (!extraSheet) { 138 | const style = document.createElement('style'); 139 | document.head.appendChild(style); 140 | extraSheet = style.sheet; 141 | } 142 | const index = ruleIndices.length; 143 | ruleIndices[index] = extraSheet.cssRules.length; 144 | extraSheet.insertRule(`${selector}{${css}}`, ruleIndices[index]); 145 | 146 | return new Impl.CssRuleHandle(index); 147 | } 148 | -------------------------------------------------------------------------------- /src/delegate.ts: -------------------------------------------------------------------------------- 1 | import { Handle } from '@dojo/interfaces/core'; 2 | import on from '@dojo/core/on'; 3 | import has from './has'; 4 | 5 | const matchesMethod = has('dom-element-matches') as string; 6 | 7 | /** 8 | * Provides a normalized mechanism for using a single event handler to listen 9 | * to delegated events from DOM nodes. 10 | * 11 | * @param target The Element to which to attach a single event handler 12 | * @param selector A CSS selector used to determine whether the event handler is called 13 | * @param type Event type(s) to listen for; may be strings or extension events 14 | * @param listener Callback to handle the event when it fires 15 | * @return A handle which will remove the listener when destroy is called 16 | * 17 | * @example 18 | * dom.delegate(document.body, 'li', 'click', function () { 19 | * // ... 20 | * }); 21 | * 22 | * @example 23 | * dom.delegate(document.body, 'li', ['click', 'mouseover'], function () { 24 | * // ... 25 | * }); 26 | */ 27 | export default function delegate(target: HTMLElement, selector: string, type: string, listener: (event: UIEvent) => void): Handle; 28 | export default function delegate(target: HTMLElement, selector: string, type: string[], listener: (event: UIEvent) => void): Handle; 29 | export default function delegate(target: HTMLElement, selector: string, type: any, listener: (event: UIEvent) => void): Handle { 30 | function matches(element: HTMLElement, selector: string) { 31 | // Search in ancestors of the given element as well, 32 | // since the event could have bubbled into an element matching the selector. 33 | // Once the target is reached, stop searching up the ancestor chain (for performance). 34 | 35 | // TS7017 36 | while (!( element)[matchesMethod](selector)) { 37 | if (element === target || !element.parentNode || !( element.parentNode)[matchesMethod]) { 38 | return null; 39 | } 40 | element = element.parentNode; 41 | } 42 | 43 | return element; 44 | } 45 | 46 | return on(target, type, function(event: Event) { 47 | // Add an ID to the selector used for matching, to avoid unwanted matches due to elements outside the root 48 | // (Adapted from code in Dojo 1, which itself was adapted from a strategy employed by Sizzle) 49 | const existingId = target.getAttribute('id'); 50 | let id = existingId || '__dojo__'; 51 | 52 | if (!existingId) { 53 | target.setAttribute('id', id); 54 | } else { 55 | id = id.replace(/"/g, '\\"'); 56 | } 57 | 58 | let selectors = selector.split(/\s*,\s*/); 59 | for (let i = 0; i < selectors.length; i++) { 60 | selectors[i] = '[id="' + id + '"] ' + selectors[i]; 61 | } 62 | 63 | let eventTarget = event.target; 64 | if (eventTarget.nodeType !== 1 && eventTarget.parentNode) { 65 | // Text nodes don't have .matches; other node types generally aren't applicable 66 | eventTarget = eventTarget.parentNode; 67 | } 68 | let matchedEventTarget: HTMLElement | null = null; 69 | 70 | try { 71 | matchedEventTarget = matches( eventTarget, selectors.join(',')); 72 | } 73 | catch (error) { 74 | // Nothing needs to be done here, but this block is needed to suppress console errors 75 | } 76 | finally { 77 | if (!existingId) { 78 | target.removeAttribute('id'); 79 | } 80 | } 81 | 82 | if (matchedEventTarget) { 83 | return listener.call(matchedEventTarget, event); 84 | } 85 | }); 86 | } 87 | -------------------------------------------------------------------------------- /src/dom.ts: -------------------------------------------------------------------------------- 1 | import has from './has'; 2 | import { CreateArgs, CreateFunction } from './interfaces'; 3 | 4 | /** 5 | * Validates a token for the CSS class manipulation methods. 6 | */ 7 | function validateToken(token: string): void { 8 | if (token === '') { 9 | throw new Error('An invalid or illegal string was specified'); 10 | } 11 | if (/\s/.test(token)) { 12 | throw new Error('String contains an invalid character'); 13 | } 14 | } 15 | 16 | /** 17 | * Adds one or more CSS class names to an HTMLElement, without duplication. 18 | * 19 | * @param element The Element to which to add CSS classes 20 | * @param classes One or more CSS class strings to add to the Element 21 | * 22 | * @example 23 | * dom.addClass(document.body, 'loaded'); 24 | * 25 | * @example 26 | * dom.addClass(document.body, 'loaded', 'ready'); 27 | */ 28 | export function addClass(element: HTMLElement, ...classes: string[]): void { 29 | // Cast to to support multiple Element types. For more info, 30 | // see https://github.com/Microsoft/TypeScript/issues/3220 31 | let targetElement = element; 32 | if (!targetElement || !classes.length) { 33 | return; 34 | } 35 | let newClasses: string[] = []; 36 | for (let className of classes) { 37 | validateToken(className); 38 | if (!containsClass(targetElement, className)) { 39 | // Convert to string to match native classList implementations for values like null 40 | newClasses.push(String(className)); 41 | } 42 | } 43 | if (newClasses.length) { 44 | targetElement.className += (targetElement.className.length ? ' ' : '') + newClasses.join(' '); 45 | } 46 | } 47 | 48 | /** 49 | * Applies CSS classes to the root element if the specified has features have truthy values. 50 | * 51 | * @param features One or more features to test and potentially apply CSS classes based on 52 | */ 53 | export function applyFeatureClass(...features: string[]) { 54 | // args will be applied to addClass, so start with the element classes will be added to 55 | let args: any[] = [ document.documentElement ]; 56 | for (let feature of features) { 57 | if (has(feature)) { 58 | args.push('has-' + feature.replace(/\s/g, '-')); 59 | } 60 | } 61 | addClass.apply(null, args); 62 | } 63 | 64 | /** 65 | * Retrieves an element from the document by its ID attribute. 66 | * 67 | * @param id ID to match in the DOM 68 | * @return the element with a matching ID attribute if found, otherwise null 69 | * 70 | * @example 71 | * let element = dom.byId('anElement'); 72 | */ 73 | export function byId(id: string): HTMLElement | null { 74 | return document.getElementById(id); 75 | } 76 | 77 | /** 78 | * Indicates whether the given parent contains the given node. 79 | * @param parent The parent node to check within 80 | * @param node The node to test whether parent is its ancestor 81 | * @return `true` if parent contains node, `false` otherwise 82 | */ 83 | export function contains(parent: Element, node: Node): boolean { 84 | // While modern browsers do support parent.contains, some support it only on HTML elements, 85 | // and IE has a known bug involving passing a text node as the argument: 86 | // https://connect.microsoft.com/IE/feedback/details/780874/node-contains-is-incorrect 87 | // Meanwhile, compareDocumentPosition works in all supported browsers. 88 | 89 | if (node == null) { 90 | return false; 91 | } 92 | if (parent === node) { 93 | return true; 94 | } 95 | return Boolean(node.compareDocumentPosition(parent) & Node.DOCUMENT_POSITION_CONTAINS); 96 | } 97 | 98 | /* 99 | * Creates an Element. 100 | * 101 | * @param tagName Type of Element to create 102 | * @param kwArgs An object containing properties to add to the Element. 103 | * If an "attributes" property is present, each member of this sub-object will be added to the Element 104 | * via element.setAttribute 105 | * @param children An array of Nodes or strings, the latter of which will be converted to Text nodes 106 | * @return The created Element, with any passed properties/attributes applied 107 | * 108 | * @example 109 | * let div = dom.create('div', { className: 'loaded', attributes: { 'data-index': '1' } }); 110 | * 111 | * @example 112 | * let div = dom.create('ul', null, [ dom.create('li'), dom.create('li') ]); 113 | * 114 | * @example 115 | * let div = dom.create('div', null, [ 'hello', ' ', 'world' ]); 116 | */ 117 | 118 | export let create: CreateFunction = function ( 119 | tagName: string, kwArgs?: CreateArgs, children?: (Node | string)[]): any { 120 | const element = document.createElement(tagName); 121 | if (children) { 122 | for (let child of children) { 123 | if (typeof child === 'string') { 124 | child = document.createTextNode( child); 125 | } 126 | element.appendChild( child); 127 | } 128 | } 129 | if (kwArgs) { 130 | for (let property in kwArgs) { 131 | if (property === 'attributes') { 132 | if (kwArgs.attributes) { 133 | for (let attribute in kwArgs.attributes) { 134 | element.setAttribute(attribute, kwArgs.attributes[attribute]); 135 | } 136 | } 137 | } 138 | else { 139 | ( element)[property] = kwArgs[property]; 140 | } 141 | } 142 | } 143 | return element; 144 | }; 145 | 146 | // Tag trees for element creation, used by fromString 147 | const tagWrap: {[key: string]: any} = { 148 | caption: [ 'table' ], 149 | col: [ 'table', 'colgroup' ], 150 | colgroup: [ 'table' ], 151 | optgroup: [ 'select' ], 152 | option: [ 'select' ], 153 | rp: [ 'ruby' ], 154 | rt: [ 'ruby' ], 155 | rtc: [ 'ruby' ], 156 | source: [ 'audio' ], 157 | tbody: [ 'table' ], 158 | td: [ 'table', 'tbody', 'tr' ], 159 | tfoot: [ 'table' ], 160 | th: [ 'table', 'thead', 'tr' ], 161 | thead: [ 'table' ], 162 | tr: [ 'table', 'tbody' ] 163 | }; 164 | 165 | for (const param in tagWrap) { 166 | const tw = tagWrap[param]; 167 | tw.pre = param === 'option' ? ' 20 | 21 | `; 22 | form.fromObject(testForm, { text1: 'foo', text2: 'bar' }); 23 | assert.strictEqual(testForm['text1'].value, 'foo'); 24 | assert.strictEqual(testForm['text2'].value, 'bar'); 25 | }, 26 | 27 | disabled() { 28 | testForm.innerHTML = ` 29 | 30 | 31 | `; 32 | form.fromObject(testForm, { text: 'foo', disabled: 'bar' }); 33 | assert.strictEqual(testForm['text'].value, 'foo'); 34 | assert.strictEqual(testForm['disabled'].value, ''); 35 | }, 36 | 37 | checkbox() { 38 | testForm.innerHTML = ` 39 | 40 | 41 | 42 | 43 | `; 44 | 45 | // Set everything 46 | form.fromObject(testForm, { cb1: [ 'foo', 'bar' ], cb2: 'baz', cb3: 'on' }); 47 | assert.isTrue(testForm['cb1'][0].checked); 48 | assert.isTrue(testForm['cb1'][1].checked); 49 | assert.isTrue(testForm['cb2'].checked); 50 | assert.isTrue(testForm['cb3'].checked); 51 | 52 | // Set nothing (should clear all checkboxes) 53 | form.fromObject(testForm, {}); 54 | assert.isFalse(testForm['cb1'][0].checked); 55 | assert.isFalse(testForm['cb1'][1].checked); 56 | assert.isFalse(testForm['cb2'].checked); 57 | assert.isFalse(testForm['cb3'].checked); 58 | 59 | // Set group to single value 60 | form.fromObject(testForm, { cb1: 'foo' }); 61 | assert.isTrue(testForm['cb1'][0].checked); 62 | assert.isFalse(testForm['cb1'][1].checked); 63 | assert.isFalse(testForm['cb2'].checked); 64 | assert.isFalse(testForm['cb3'].checked); 65 | 66 | // Set field to an invalid value 67 | form.fromObject(testForm, { cb2: 'bar' }); 68 | assert.isFalse(testForm['cb1'][0].checked); 69 | assert.isFalse(testForm['cb1'][1].checked); 70 | assert.isFalse(testForm['cb2'].checked); 71 | assert.isFalse(testForm['cb3'].checked); 72 | }, 73 | 74 | radio() { 75 | testForm.innerHTML = ` 76 | 77 | 78 | 79 | `; 80 | 81 | // Set value 82 | form.fromObject(testForm, { r1: 'foo' }); 83 | assert.isTrue(testForm['r1'][0].checked); 84 | assert.isFalse(testForm['r1'][1].checked); 85 | assert.isFalse(testForm['r1'][2].checked); 86 | 87 | // Clear value 88 | form.fromObject(testForm, {}); 89 | assert.isFalse(testForm['r1'][0].checked); 90 | assert.isFalse(testForm['r1'][1].checked); 91 | assert.isFalse(testForm['r1'][2].checked); 92 | }, 93 | 94 | 'select-single': (function () { 95 | function runTest(object: { [ key: string ]: any }, index: number, value: string) { 96 | form.fromObject(testForm, object); 97 | assert.strictEqual(testForm['select'].selectedIndex, index); 98 | assert.strictEqual(testForm['select'].value, value); 99 | } 100 | 101 | return { 102 | flat() { 103 | testForm.innerHTML = ` 104 | 110 | `; 111 | runTest({ select: 'bar' }, 1, 'bar'); 112 | }, 113 | 114 | group() { 115 | testForm.innerHTML = ` 116 | 126 | `; 127 | runTest({ select: 'bar' }, 1, 'bar'); 128 | }, 129 | 130 | clear() { 131 | testForm.innerHTML = ` 132 | 137 | `; 138 | runTest({}, 0, 'foo'); 139 | }, 140 | 141 | 'clear with disabled first option'() { 142 | testForm.innerHTML = ` 143 | 148 | `; 149 | runTest({}, 1, 'bar'); 150 | }, 151 | 152 | 'clear with disabled first option and optgroup'() { 153 | testForm.innerHTML = ` 154 | 163 | `; 164 | runTest({}, 1, 'bar'); 165 | } 166 | }; 167 | })(), 168 | 169 | 'select-multiple': (function () { 170 | function runTest() { 171 | const options = testForm['select'].options; 172 | 173 | // Set multiple values 174 | form.fromObject(testForm, { select: [ 'bar', 'baz' ] }); 175 | assert.isFalse(options[0].selected); 176 | assert.isTrue(options[1].selected); 177 | assert.isTrue(options[2].selected); 178 | assert.isFalse(options[3].selected); 179 | 180 | // Set single value 181 | form.fromObject(testForm, { select: 'foo' }); 182 | assert.isTrue(options[0].selected); 183 | assert.isFalse(options[1].selected); 184 | assert.isFalse(options[2].selected); 185 | assert.isFalse(options[3].selected); 186 | 187 | } 188 | 189 | return { 190 | flat() { 191 | testForm.innerHTML = ` 192 | 198 | `; 199 | runTest(); 200 | }, 201 | 202 | group() { 203 | testForm.innerHTML = ` 204 | 214 | `; 215 | runTest(); 216 | }, 217 | 218 | clear() { 219 | testForm.innerHTML = ` 220 | 224 | `; 225 | form.fromObject(testForm, {}); 226 | const options = testForm['select'].options; 227 | assert.isFalse(options[0].selected); 228 | assert.isFalse(options[1].selected); 229 | } 230 | }; 231 | })(), 232 | 233 | text() { 234 | testForm.innerHTML = ` 235 | 236 | 237 | 238 | 239 | `; 240 | const expected = { 241 | text: 'foo', 242 | hidden: 'bar', 243 | password: 'baz', 244 | implicit: 'qux' 245 | }; 246 | 247 | form.fromObject(testForm, expected); 248 | for (const name in expected) { 249 | assert.strictEqual(testForm[name].value, expected[name]); 250 | } 251 | } 252 | }, 253 | 254 | '.toObject': { 255 | capitalization() { 256 | testForm.innerHTML = ` 257 | 258 | 259 | 260 | `; 261 | assert.deepEqual(form.toObject(testForm), { text1: 'foo', text2: 'bar', text3: 'baz' }); 262 | }, 263 | 264 | disabled() { 265 | testForm.innerHTML = ` 266 | 267 | 268 | `; 269 | assert.deepEqual(form.toObject(testForm), { text: 'foo' }); 270 | }, 271 | 272 | checkbox: { 273 | 'single check'() { 274 | testForm.innerHTML = ` 275 | 276 | 277 | `; 278 | assert.deepEqual(form.toObject(testForm), { cb1: [ 'bar' ] }); 279 | }, 280 | 281 | 'multiple checks'() { 282 | testForm.innerHTML = ` 283 | 284 | 285 | 286 | 287 | `; 288 | assert.deepEqual(form.toObject(testForm), { cb1: [ 'foo', 'bar', 'baz' ] }); 289 | }, 290 | 291 | 'implicit value'() { 292 | testForm.innerHTML = ''; 293 | assert.deepEqual(form.toObject(testForm), { implicit: 'on' }); 294 | } 295 | }, 296 | 297 | radio() { 298 | testForm.innerHTML = ` 299 | 300 | 301 | 302 | `; 303 | assert.deepEqual(form.toObject(testForm), { r1: 'bar' }); 304 | 305 | }, 306 | 307 | 'select-single': { 308 | flat() { 309 | testForm.innerHTML = ` 310 | 316 | `; 317 | assert.deepEqual(form.toObject(testForm), { select: 'bar' }); 318 | }, 319 | 320 | group() { 321 | testForm.innerHTML = ` 322 | 332 | `; 333 | assert.deepEqual(form.toObject(testForm), { select: 'bar' }); 334 | } 335 | }, 336 | 337 | 'select-multiple': { 338 | none() { 339 | testForm.innerHTML = ` 340 | 344 | `; 345 | assert.deepEqual(form.toObject(testForm), {}); 346 | }, 347 | 348 | single() { 349 | testForm.innerHTML = ` 350 | 356 | `; 357 | assert.deepEqual(form.toObject(testForm), { select: [ 'bar' ] }); 358 | }, 359 | 360 | flat() { 361 | testForm.innerHTML = ` 362 | 368 | `; 369 | assert.deepEqual(form.toObject(testForm), { select: [ 'bar', 'qux' ] }); 370 | }, 371 | 372 | group() { 373 | testForm.innerHTML = ` 374 | 384 | `; 385 | assert.deepEqual(form.toObject(testForm), { select: [ 'bar', 'qux' ] }); 386 | } 387 | }, 388 | 389 | text() { 390 | testForm.innerHTML = ` 391 | 392 | 393 | 394 | 395 | 396 | `; 397 | assert.deepEqual(form.toObject(testForm), { 398 | text: 'foo', 399 | hidden: 'bar', 400 | password: 'baz', 401 | implicit: 'qux', 402 | empty: '' 403 | }); 404 | } 405 | }, 406 | 407 | 'to and from'() { 408 | testForm.innerHTML = ` 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 428 | 429 | 435 | `; 436 | 437 | const value = { 438 | text: 'text-foo', 439 | hidden: 'hidden-foo', 440 | password: 'password-foo', 441 | implicit: 'implicit-foo', 442 | cb1: [ 'bar' ], 443 | r1: 'foo', 444 | select: 'qux', 445 | multiselect: [ 'foo', 'baz' ] 446 | }; 447 | 448 | form.fromObject(testForm, value); 449 | 450 | value['empty'] = ''; 451 | assert.deepEqual(form.toObject(testForm), value); 452 | } 453 | }); 454 | -------------------------------------------------------------------------------- /tests/unit/schedule.ts: -------------------------------------------------------------------------------- 1 | import registerSuite = require('intern!object'); 2 | import assert = require('intern/chai!assert'); 3 | import { read, write } from '../../src/schedule'; 4 | import Promise from '@dojo/shim/Promise'; 5 | 6 | registerSuite({ 7 | read(this: any) { 8 | const dfd = this.async(); 9 | read(dfd.callback(function () {})); 10 | }, 11 | 12 | write(this: any) { 13 | const dfd = this.async(); 14 | write(dfd.callback(function () {})); 15 | }, 16 | 17 | destroy: { 18 | read(this: any) { 19 | let didRead = false; 20 | const handle = read(function () { 21 | didRead = true; 22 | }); 23 | handle.destroy(); 24 | 25 | const dfd = this.async(); 26 | setTimeout(dfd.callback(function () { 27 | assert.isFalse(didRead); 28 | }), 100); 29 | }, 30 | 31 | write(this: any) { 32 | let didWrite = false; 33 | const handle = read(function () { 34 | didWrite = true; 35 | }); 36 | handle.destroy(); 37 | 38 | const dfd = this.async(); 39 | setTimeout(dfd.callback(function () { 40 | assert.isFalse(didWrite); 41 | }), 100); 42 | }, 43 | 44 | 'multiple reads and writes'() { 45 | const operations: string[] = []; 46 | const readPromise1 = new Promise(function (resolve, reject) { 47 | read(function () { 48 | operations.push('read1'); 49 | resolve(); 50 | }); 51 | }); 52 | 53 | const readHandle = read(function () { 54 | operations.push('read1.5'); 55 | }); 56 | 57 | const writePromise1 = new Promise(function (resolve, reject) { 58 | write(function () { 59 | operations.push('write1'); 60 | resolve(); 61 | }); 62 | }); 63 | 64 | const writeHandle = write(function () { 65 | operations.push('write1.5'); 66 | }); 67 | 68 | const readPromise2 = new Promise(function (resolve, reject) { 69 | read(function () { 70 | operations.push('read2'); 71 | resolve(); 72 | }); 73 | }); 74 | 75 | const writePromise2 = new Promise(function (resolve, reject) { 76 | write(function () { 77 | operations.push('write2'); 78 | resolve(); 79 | }); 80 | }); 81 | 82 | readHandle.destroy(); 83 | writeHandle.destroy(); 84 | 85 | return Promise.all([ readPromise1, readPromise2, writePromise1, writePromise2 ]).then(function () { 86 | assert.deepEqual(operations, [ 'read1', 'read2', 'write1', 'write2' ], 87 | 'Read queue should drain before write, and destroyed items should not run'); 88 | }); 89 | }, 90 | 91 | 're-destroy'() { 92 | const handle = read(function () {}); 93 | handle.destroy(); 94 | assert.doesNotThrow(function () { 95 | handle.destroy(); 96 | }); 97 | } 98 | }, 99 | 100 | order: { 101 | 'read first'() { 102 | const operations: string[] = []; 103 | return Promise.all([ 104 | new Promise(function (resolve, reject) { 105 | read(function () { 106 | operations.push('read1'); 107 | resolve(); 108 | }); 109 | }), 110 | 111 | new Promise(function (resolve, reject) { 112 | write(function () { 113 | operations.push('write1'); 114 | resolve(); 115 | }); 116 | }), 117 | 118 | new Promise(function (resolve, reject) { 119 | read(function () { 120 | operations.push('read2'); 121 | resolve(); 122 | }); 123 | }), 124 | 125 | new Promise(function (resolve, reject) { 126 | write(function () { 127 | operations.push('write2'); 128 | resolve(); 129 | }); 130 | }) 131 | ]).then(function () { 132 | assert.deepEqual(operations, [ 'read1', 'read2', 'write1', 'write2' ], 133 | 'Read queue should drain before write queue'); 134 | }); 135 | }, 136 | 137 | 'write first'() { 138 | const operations: string[] = []; 139 | return Promise.all([ 140 | new Promise(function (resolve, reject) { 141 | write(function () { 142 | operations.push('write1'); 143 | resolve(); 144 | }); 145 | }), 146 | 147 | new Promise(function (resolve, reject) { 148 | read(function () { 149 | operations.push('read1'); 150 | resolve(); 151 | }); 152 | }), 153 | 154 | new Promise(function (resolve, reject) { 155 | write(function () { 156 | operations.push('write2'); 157 | resolve(); 158 | }); 159 | }), 160 | 161 | new Promise(function (resolve, reject) { 162 | read(function () { 163 | operations.push('read2'); 164 | resolve(); 165 | }); 166 | }) 167 | ]).then(function () { 168 | assert.deepEqual(operations, [ 'read1', 'read2', 'write1', 'write2' ], 169 | 'Read queue should drain before write queue'); 170 | }); 171 | }, 172 | 173 | 'reads within writes'() { 174 | const operations: string[] = []; 175 | return Promise.all([ 176 | new Promise(function (resolve, reject) { 177 | write(function () { 178 | operations.push('write1'); 179 | read(function () { 180 | operations.push('read3'); 181 | resolve(); 182 | }); 183 | }); 184 | }), 185 | 186 | new Promise(function (resolve, reject) { 187 | write(function () { 188 | operations.push('write2'); 189 | read(function () { 190 | operations.push('read4'); 191 | resolve(); 192 | }); 193 | }); 194 | }) 195 | ]).then(function () { 196 | assert.deepEqual(operations, [ 'write1', 'write2', 'read3', 'read4' ], 197 | 'Reads queued while draining write queue should not fire until next turn'); 198 | }); 199 | }, 200 | 201 | 'reads within reads before writes'() { 202 | const operations: string[] = []; 203 | return Promise.all([ 204 | new Promise(function (resolve, reject) { 205 | read(function () { 206 | operations.push('read1'); 207 | read(function () { 208 | operations.push('read2'); 209 | resolve(); 210 | }); 211 | }); 212 | }), 213 | 214 | new Promise(function (resolve, reject) { 215 | write(function () { 216 | operations.push('write'); 217 | resolve(); 218 | }); 219 | }) 220 | ]).then(function () { 221 | assert.deepEqual(operations, [ 'read1', 'read2', 'write' ], 222 | 'Read queue should drain before write queue, even if more reads are queued while draining it'); 223 | }); 224 | }, 225 | 226 | 'reads within writes after writes'() { 227 | const operations: string[] = []; 228 | return Promise.all([ 229 | new Promise(function (resolve, reject) { 230 | read(function () { 231 | operations.push('read1'); 232 | read(function () { 233 | operations.push('read2'); 234 | resolve(); 235 | }); 236 | }); 237 | }), 238 | 239 | new Promise(function (resolve, reject) { 240 | write(function () { 241 | operations.push('write1'); 242 | read(function () { 243 | operations.push('read3'); 244 | resolve(); 245 | }); 246 | }); 247 | }) 248 | ]).then(function () { 249 | assert.deepEqual(operations, [ 'read1', 'read2', 'write1', 'read3' ], 250 | 'Read queue should drain before write queue, except for reads queued while draining write queue'); 251 | }); 252 | } 253 | } 254 | }); 255 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": false, 4 | "experimentalDecorators": true, 5 | "lib": [ 6 | "dom", 7 | "es5", 8 | "es2015.iterable", 9 | "es2015.symbol", 10 | "es2015.symbol.wellknown" 11 | ], 12 | "module": "umd", 13 | "moduleResolution": "node", 14 | "noImplicitAny": true, 15 | "noImplicitThis": true, 16 | "outDir": "_build/", 17 | "removeComments": false, 18 | "sourceMap": true, 19 | "strictNullChecks": true, 20 | "target": "es5", 21 | "types": [ "intern" ] 22 | }, 23 | "include": [ 24 | "./src/**/*.ts", 25 | "./tests/**/*.ts", 26 | "./typings/index.d.ts" 27 | ], 28 | "exclude": [ 29 | "_build", 30 | "dist", 31 | "node_modules" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": false, 4 | "ban": [], 5 | "class-name": true, 6 | "comment-format": [ true, "check-space" ], 7 | "curly": true, 8 | "eofline": true, 9 | "forin": false, 10 | "indent": [ true, "tabs" ], 11 | "interface-name": [ true, "never-prefix" ], 12 | "jsdoc-format": true, 13 | "label-position": true, 14 | "max-line-length": 120, 15 | "member-access": false, 16 | "member-ordering": false, 17 | "no-any": false, 18 | "no-arg": true, 19 | "no-bitwise": false, 20 | "no-consecutive-blank-lines": true, 21 | "no-console": false, 22 | "no-construct": false, 23 | "no-debugger": true, 24 | "no-duplicate-variable": true, 25 | "no-empty": false, 26 | "no-eval": true, 27 | "no-inferrable-types": [ true, "ignore-params" ], 28 | "no-shadowed-variable": false, 29 | "no-string-literal": false, 30 | "no-switch-case-fall-through": false, 31 | "no-trailing-whitespace": true, 32 | "no-unused-expression": false, 33 | "no-unused-variable": true, 34 | "no-use-before-declare": false, 35 | "no-var-keyword": true, 36 | "no-var-requires": false, 37 | "object-literal-sort-keys": false, 38 | "one-line": [ true, "check-open-brace", "check-whitespace" ], 39 | "quotemark": [ true, "single" ], 40 | "radix": true, 41 | "semicolon": [ true, "always" ], 42 | "trailing-comma": [ true, { 43 | "multiline": "never", 44 | "singleline": "never" 45 | } ], 46 | "triple-equals": [ true, "allow-null-check" ], 47 | "typedef": false, 48 | "typedef-whitespace": [ true, { 49 | "call-signature": "nospace", 50 | "index-signature": "nospace", 51 | "parameter": "nospace", 52 | "property-declaration": "nospace", 53 | "variable-declaration": "nospace" 54 | }, { 55 | "call-signature": "onespace", 56 | "index-signature": "onespace", 57 | "parameter": "onespace", 58 | "property-declaration": "onespace", 59 | "variable-declaration": "onespace" 60 | } ], 61 | "use-strict": false, 62 | "variable-name": [ true, "check-format", "allow-leading-underscore", "ban-keywords" ], 63 | "whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-module", "check-separator", "check-type", "check-typecast" ] 64 | } 65 | } 66 | --------------------------------------------------------------------------------