diff --git a/.config/babel.config.json b/.config/babel.config.json
index 5d321a38f..3bc495084 100644
--- a/.config/babel.config.json
+++ b/.config/babel.config.json
@@ -4,14 +4,11 @@
[
"@babel/preset-env",
{
- loose: true,
- bugfixes: true,
- modules: false
+ "loose": true,
+ "bugfixes": true,
+ "modules": false
}
],
"@babel/typescript"
- ],
- "plugins": [
- ["@babel/plugin-proposal-class-properties", { "loose": true }]
- ]
+ ]
}
diff --git a/.config/eleventy.csp.js b/.config/eleventy.csp.cjs
similarity index 97%
rename from .config/eleventy.csp.js
rename to .config/eleventy.csp.cjs
index 82b4a9b9c..ac0521468 100644
--- a/.config/eleventy.csp.js
+++ b/.config/eleventy.csp.cjs
@@ -45,7 +45,7 @@ module.exports = function( eleventyConfig, config = {} ) {
dom.window.document.querySelectorAll(type).forEach( (element) => {
if( element.hasAttribute('csp-hash') ){
const hash = 'sha256-'+crypto.createHash('sha256').update(element.textContent).digest('base64')
- element.setAttribute("csp-hash", hash);
+ element.removeAttribute('csp-hash');
hashes.push(`'${hash}'`);
}else if( element.textContent.trim() == '' && element.getAttribute('src') === null ){
element.remove();
diff --git a/.config/eleventy.js b/.config/eleventy.js
index aca471254..a58e7c7a2 100644
--- a/.config/eleventy.js
+++ b/.config/eleventy.js
@@ -1,16 +1,18 @@
+import { IdAttributePlugin } from "@11ty/eleventy";
+import syntaxHighlight from '@11ty/eleventy-plugin-syntaxhighlight';
+import markdownIt from 'markdown-it';
+import csp_plugin from './eleventy.csp.cjs';
-
-module.exports = function(eleventyConfig) {
+export default function(eleventyConfig) {
// Aliases are in relation to the _includes folder
eleventyConfig.addLayoutAlias('about', 'layouts/about.html');
eleventyConfig.addPassthroughCopy({'doc_src/css':'css'});
eleventyConfig.addPassthroughCopy({'doc_src/js':'js'});
- eleventyConfig.addPassthroughCopy({'build/js':'js'});
- eleventyConfig.addPassthroughCopy({'build/css':'css'});
- eleventyConfig.addPassthroughCopy({'build/esm':'esm'});
+ eleventyConfig.addPassthroughCopy({'dist/js':'js'});
+ eleventyConfig.addPassthroughCopy({'dist/css':'css'});
+ eleventyConfig.addPassthroughCopy({'dist/esm':'esm'});
// content security policy
- const csp_plugin = require('./eleventy.csp.js');
eleventyConfig.addPlugin(csp_plugin,{
csp:{
'default-src': ["'self'"],
@@ -23,23 +25,9 @@ module.exports = function(eleventyConfig) {
});
// header anchors
- const anchors_plugin = require('@orchidjs/eleventy-plugin-ids');
- eleventyConfig.addPlugin(anchors_plugin,{
- prefix:'',
- selectors:[
- '.container h1',
- '.container h2',
- '.container h3',
- '.container h4',
- '.container h5',
- '.container h6',
- '.container td:first-child',
- ]
- });
-
+ eleventyConfig.addPlugin(IdAttributePlugin);
// syntax highlighting
- const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
eleventyConfig.addPlugin(syntaxHighlight);
function GlobCollection(name, glob){
@@ -81,8 +69,7 @@ module.exports = function(eleventyConfig) {
- let markdownIt = require('markdown-it');
- md = markdownIt({
+ const md = markdownIt({
html: true,
breaks: false,
//linkify: true
@@ -109,7 +96,7 @@ module.exports = function(eleventyConfig) {
dir: {
data: '../data', // relative to input path
input: 'doc_src/pages', // relative to project root
- output: 'build/docs', // relative to project root
+ output: 'build-docs', // relative to project root
includes: '../includes', // relative to input path
}
};
diff --git a/.config/karma.conf.js b/.config/karma.conf.cjs
similarity index 82%
rename from .config/karma.conf.js
rename to .config/karma.conf.cjs
index aeb867639..5efd023d2 100644
--- a/.config/karma.conf.js
+++ b/.config/karma.conf.cjs
@@ -102,7 +102,7 @@ module.exports = function(config) {
flags: [
'--disable-translate',
'--disable-extensions',
- '--remote-debugging-port=9223'
+ '--remote-debugging-port=9223',
]
};
}
@@ -113,12 +113,28 @@ module.exports = function(config) {
'HeadlessChrome': ['HeadlessChrome']
};
- var reporters = ['mocha','coverage','aChecker'];
+ var reporters = [
+ 'mocha',
+ 'coverage',
+ //'aChecker'
+ ];
if( process.env.TRAVIS_CI ){
- reporters = ['mocha', 'coverage', 'coveralls','aChecker']
+ reporters = [
+ 'mocha',
+ 'coverage',
+ 'coveralls',
+ //'aChecker'
+ ]
}
- var browsers = targets[process.env.TARGET || 'HeadlessFirefox'];
+ var target = process.env.TARGET;
+ if( !target ){
+ target = 'HeadlessChrome';
+ process.env.CHROME_BIN = require('puppeteer').executablePath();
+ }
+
+
+ var browsers = targets[target];
if( process.env.BROWSERS ){
browsers = process.env.BROWSERS.split(',');
}
@@ -126,7 +142,11 @@ module.exports = function(config) {
config.set({
basePath: '../',
- frameworks: ['mocha', 'chai','aChecker'],
+ frameworks: [
+ 'mocha',
+ 'chai',
+ //'aChecker'
+ ],
files: [
{
pattern: 'test/tests/esm-module.js',
@@ -134,21 +154,20 @@ module.exports = function(config) {
included: true,
},
- 'build/js/tom-select.complete.js',
+ 'dist/js/tom-select.complete.js',
'node_modules/syn/dist/global/syn.js',
- 'node_modules/jquery/dist/jquery.js',
- 'build/css/tom-select.default.css',
+ 'dist/css/tom-select.default.css',
'test/support/*.js',
config.test_one ? 'test/tests/interaction.js' : 'test/tests/**/*.js',
{
- pattern: 'build/**/*',
+ pattern: 'dist/**/*',
included: false,
},
],
preprocessors: {
- 'build/**/*.js': ['sourcemap','coverage'],
+ 'dist/**/*.js': ['sourcemap','coverage'],
},
coverageReporter: {
reporters:[
@@ -171,7 +190,8 @@ module.exports = function(config) {
browsers: browsers,
singleRun: true,
browserDisconnectTolerance: 3,
- browserDisconnectTimeout: 10000,
- browserNoActivityTimeout: 120000
+ browserDisconnectTimeout: 15000,
+ browserNoActivityTimeout: 120000,
+ concurrency: 3,
});
};
diff --git a/.config/rollup.config.js b/.config/rollup.config.mjs
similarity index 69%
rename from .config/rollup.config.js
rename to .config/rollup.config.mjs
index 125285e56..028d5a6fb 100644
--- a/.config/rollup.config.js
+++ b/.config/rollup.config.mjs
@@ -1,15 +1,21 @@
-import resolve from '@rollup/plugin-node-resolve'; // so Rollup can resolve imports without file extensions and `node_modules`
-import commonjs from '@rollup/plugin-commonjs'; // so Rollup can convert commonjs to an ES module
+import {nodeResolve} from '@rollup/plugin-node-resolve'; // so Rollup can resolve imports without file extensions and `node_modules`
import babel from '@rollup/plugin-babel';
-import { terser } from 'rollup-plugin-terser';
-import pkg from '../package.json';
+import terser from '@rollup/plugin-terser';
import path from 'path';
import fs from 'fs';
+import { fileURLToPath } from 'url';
+import { dirname } from 'path';
const tom_select_path_js = path.resolve( 'src/tom-select.js' );
const tom_select_path_ts = path.resolve( 'src/tom-select.ts' );
const configs = [];
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname,'../package.json'),'utf-8'));
+
const banner = `/**
* Tom Select v${pkg.version}
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +23,7 @@ const banner = `/**
`;
const extensions = [
- '.js', '.jsx', '.ts', '.tsx',
+ '.js', '.jsx', '.ts', '.tsx', '.mjs',
];
var babel_config = babel({
@@ -27,53 +33,10 @@ var babel_config = babel({
exclude:'node_modules/**/*.js'
});
-var resolve_config = resolve({
+var resolve_config = nodeResolve({
+ //browser: true,
extensions: extensions,
-});
-
-
-// esm & cjs
-const inputs = [
- 'tom-select.ts',
- 'tom-select.complete.ts',
- 'tom-select.popular.ts',
- 'utils.ts',
-];
-
-inputs.forEach((slug)=>{
-
- let input = path.resolve(__dirname,'../src',slug)
-
- // esm
- configs.push({
- input: input,
- output:{
- //file: path.resolve(__dirname,'../build/esm',slug),
- dir: path.resolve(__dirname,'../build/esm'),
- format: 'esm',
- preserveModules: false,
- sourcemap: true,
- banner: banner,
- },
- plugins:[babel_config,resolve_config,],
- //external: ['@orchidjs/sifter/dist/esm/sifter.js'],
- });
-
- // cjs
- configs.push({
- input: input,
- output:{
- dir: path.resolve(__dirname,'../build/cjs'),
- format: 'cjs',
- preserveModules: false,
- sourcemap: true,
- banner: banner,
- exports: "auto",
- },
- plugins:[babel_config,resolve_config],
- //external: ['@orchidjs/sifter/dist/esm/sifter.js'],
- });
-
+ mainFields: ['module'],
});
@@ -110,8 +73,7 @@ function createConfig( input, output, plugins ){
config.plugins = [
resolve_config,
- babel_config,
- commonjs(),
+ babel_config
];
config.plugins = config.plugins.concat(plugins);
@@ -123,7 +85,7 @@ function configCore( input, filename, plugins ){
var output = {
name: 'TomSelect',
- file: `build/js/${filename}`,
+ file: `dist/js/${filename}`,
footer: 'var tomSelect=function(el,opts){return new TomSelect(el,opts);} ',
};
@@ -151,7 +113,7 @@ var plugin_dir = path.resolve(__dirname,'../src/plugins');
var files = fs.readdirSync( plugin_dir );
files.map(function(file){
let input = path.resolve(__dirname,'../src/plugins',file,'plugin.ts');
- let output = {file:`build/js/plugins/${file}.js`,'name':file};
+ let output = {file:`dist/js/plugins/${file}.js`,'name':file};
pluginConfig( input, output);
@@ -159,7 +121,7 @@ files.map(function(file){
configs.push({
input: input,
output:{
- file: path.resolve(__dirname,'../build/esm/plugins',file,'plugin.js'),
+ file: path.resolve(__dirname,'../dist/esm/plugins',file,'plugin.js'),
format: 'esm',
preserveModules: false,
sourcemap: true,
diff --git a/.config/rollup.docs.js b/.config/rollup.docs.mjs
similarity index 80%
rename from .config/rollup.docs.js
rename to .config/rollup.docs.mjs
index fc9c2f44c..f6bcfd015 100644
--- a/.config/rollup.docs.js
+++ b/.config/rollup.docs.mjs
@@ -1,8 +1,13 @@
import alias from '@rollup/plugin-alias';
import resolve from '@rollup/plugin-node-resolve'; // so Rollup can resolve imports without file extensions and `node_modules`
import babel from '@rollup/plugin-babel';
-import { terser } from 'rollup-plugin-terser';
+import terser from '@rollup/plugin-terser';
import path from 'path';
+import { fileURLToPath } from 'url';
+import { dirname } from 'path';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
var configs = [];
@@ -21,6 +26,7 @@ var resolve_config = resolve({
extensions: extensions,
});
+
var terser_config = terser({
mangle: true,
toplevel: true, // removes tomSelect footer
@@ -29,11 +35,12 @@ var terser_config = terser({
},
});
+
// bootstrap tabs for docs
configs.push({
input: 'doc_src/js/index.js',
output: {
- file: path.resolve(__dirname,'../build/docs/js/index.bundle.js'),
+ file: path.resolve(__dirname,'../build-docs/js/index.bundle.js'),
name: 'bootstrap',
format: 'umd',
sourcemap: true,
diff --git a/.config/stylelintrc.json b/.config/stylelintrc.json
new file mode 100644
index 000000000..77b9f9120
--- /dev/null
+++ b/.config/stylelintrc.json
@@ -0,0 +1,15 @@
+{
+ "extends": [
+ "stylelint-config-standard-scss",
+ "stylelint-config-prettier-scss"
+ ],
+
+ "rules": {
+ "color-function-notation": "legacy",
+ "selector-class-pattern": null,
+ "shorthand-property-no-redundant-values": null,
+ "scss/dollar-variable-pattern": null,
+ "scss/load-partial-extension": null,
+ "scss/no-global-function-names": null
+ }
+}
diff --git a/.config/tsconfig.cjs.json b/.config/tsconfig.cjs.json
new file mode 100644
index 000000000..0f4283aa1
--- /dev/null
+++ b/.config/tsconfig.cjs.json
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "module": "CommonJS",
+ "moduleResolution": "Node",
+ "outDir": "../dist/cjs"
+ }
+}
diff --git a/.config/tsconfig.esm.json b/.config/tsconfig.esm.json
new file mode 100644
index 000000000..222434514
--- /dev/null
+++ b/.config/tsconfig.esm.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "module": "NodeNext",
+ "outDir": "../dist/esm"
+ }
+}
diff --git a/.config/tsconfig.json b/.config/tsconfig.json
index 5567e626d..57962440f 100644
--- a/.config/tsconfig.json
+++ b/.config/tsconfig.json
@@ -4,13 +4,20 @@
"allowJs": true,
"checkJs": true,
"strict": true,
- "target": "esnext",
- "module": "esnext",
+ "target": "ES6",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "alwaysStrict": true,
+ "strictNullChecks": true,
+ "noImplicitReturns": true,
"noUnusedLocals": true,
-
+ "allowUnreachableCode": false,
+ "noUncheckedIndexedAccess": true,
"declaration": true,
- "declarationDir": "../dist/types",
"isolatedModules": true,
- "moduleResolution": "node"
+ "sourceMap": true,
+ "rewriteRelativeImportExtensions": true,
+
+ "lib": ["ESNext", "dom"],
},
}
diff --git a/.config/tsconfig.types.json b/.config/tsconfig.types.json
new file mode 100644
index 000000000..646244432
--- /dev/null
+++ b/.config/tsconfig.types.json
@@ -0,0 +1,11 @@
+{
+ // This exists for backwards compatibility. In the wild, folks are importing
+ // paths like `tom-select/dist/types/...`.
+ //
+ // Consider removing this in the next major version.
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../dist/types",
+ "emitDeclarationOnly": true
+ }
+}
diff --git a/.editorconfig b/.editorconfig
index 13ef9afb7..c72e4e324 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,3 +1,15 @@
[*]
indent_style = tab
tab_width = 4
+
+[package.json]
+indent_style = space
+indent_size = 2
+
+[.github/workflows/*]
+indent_style = space
+indent_size = 2
+
+[*.yml]
+indent_style = space
+indent_size = 2
diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml
new file mode 100644
index 000000000..f66155c08
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml
@@ -0,0 +1,52 @@
+name: "Tom Select Bug report"
+description: "Submit a report and help us improve our free and open-source project"
+title: "[Bug]: "
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ ### Thank you for contributing to our project!
+ Before submitting, we'd appreciate it if you:
+ - Verify that your issue is not [already reported on GitHub](https://github.com/orchidjs/tom-select/issues?q=is%3Aissue).
+ - Check if your TomSelect is up to date. If not, we recommend that you update first.
+ - type: textarea
+ id: bug-description
+ attributes:
+ label: Bug description
+ description: Provide a description of the bug you're experiencing. Please include any relevant error messages.
+ validations:
+ required: true
+ - type: textarea
+ id: expected-behavior
+ attributes:
+ label: Expected behavior
+ description: Describe what you expected to happen.
+ validations:
+ required: true
+ - type: textarea
+ id: reproduce
+ attributes:
+ label: Steps to reproduce
+ description: |
+ Create an example on JSFiddle, CodePen or similar service and outline the steps for reproducing the bug.
+ **Tip** go to tom-select.js.org and click "edit" -> "JSFiddle" or "CodePen" to start a example)
+ value: |
+ 1. Go to ...
+ 2. Click on ....
+ ...
+ X. See error
+ validations:
+ required: true
+ - type: textarea
+ id: additional-info
+ attributes:
+ label: Additional context
+ description: Add any other context about the problem here
+ value: |
+ - OS: [e.g. iOS, Windows]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+ - Device: [e.g. iPhone6]
+ validations:
+ required: true
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index e6911ee6e..000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior.
-If possible, please provide a JSFiddle or CodePen example.
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Additional context**
-Add any other context about the problem here.
- - OS: [e.g. iOS, Windows]
- - Browser [e.g. chrome, safari]
- - Version [e.g. 22]
- - Device: [e.g. iPhone6]
-
-
-
-
```
+
+
+
Multiple instances using a .class selector
+
+```html
+
+
+ ...
+
+```
+
+
+
### Glossary
-- Config / configuration: settings passed to the object constructor
-- Settings: the current settings. Accessible with the `settings` property of the select object.
-- Options: the list of objects to display.
- Each object must have a property with an unique **value** to identify the option; the property name is defined by the `valueField` setting.
- Option objects must also have a property with the **label** to display (as tag, in the drop down, etc.); the property name is defined by the `labelField` setting.
- The options can have other properties, ignored, unless referenced by other settings, like `sortField` or `searchField`.
-- Items: the list of selected options. Or more exactly, the list of the values of the selected options.
+
+
Settings
+
Configuration parameters passed to the TomSelect constructor and accessible with the settings property of the select object
+
Options
+
The list of objects to display.
+ Each object must have a property with an unique value to identify the option; the property name is defined by the valueField setting.
+ Option objects must also have a property with the label to display (as tag, in the drop down, etc.); the property name is defined by the labelField setting.
+ The options can have other properties, ignored, unless referenced by other settings, like sortField or searchField.
+
+
Items
+
The list of selected options. Or more exactly, the list of the values of the selected options.
After a selection is made, the dropdown will remain open if in a multi-selection control or will close in a single-selection control.
Setting closeAfterSelect to true will force the dropdown to close after selections are made.
- Setting closeAfterSelect to false will keep the dropdown open after selections are made.
+ Setting closeAfterSelect to false will keep the dropdown open after selections are made.
The placeholder of the control. Defaults to input element's placeholder, unless this one is specified.
+
The placeholder of the control. Defaults to input element's placeholder, unless this one is specified.
+ To update the placeholder setting after initialization, call inputState()
+
+```js
+const tom = new TomSelect('#input-id');
+tom.settings.placeholder = "New placeholder";
+tom.inputState();
+```
+
If true, the load function will be called upon control initialization (with an empty search). Alternatively it can be set to 'focus' to call the load function when control receives focus.
A single field or an array of fields to sort by. Each item in the array should be an object containing at least a field property. Optionally, direction can be set to 'asc' or 'desc'. The order of the array defines the sort precedence.
-
Unless present, a special `$score` field will be automatically added to the beginning of the sort list. This will make results sorted primarily by match quality (descending).
-
You can override the `$score` function. For more information, see the sifter documentation.
By default, results will be sorted by their $score first, then by the original order of options.
+ To disable sorting entirely and maintain the original order of options, use:
+
+```js
+sortField:[{field:'$order'},{field:'$score'}]
+```
+
+
string array function
+
[{field:'$score'}, {field:'$order'}]
searchField
@@ -333,6 +379,12 @@ Weights can be given to each field to improve search results
searchField: [{field:'text',weight:2},{field:'text2',weight:0.5}]
```
+To completely disable the client side filtering (if youre getting the search results from an external source), set the `searchField` to an empty array.
+
+```js
+searchField: []
+```
+
array
['text']
@@ -414,7 +466,7 @@ new TomSelect('#select',{
Invoked when an item is selected.
-
onItemRemove(value)
+
onItemRemove(value, $item)
Invoked when an item is deselected.
@@ -454,7 +506,7 @@ new TomSelect('#select',{
## Render Templates
Nearly every piece of HTML in Tom Select is customizable with a render template.
-Each template is defined by a function that is passed two arguments (data and escape) and returns HTML (string or DOM element) with a single root element. The escape argument is a function that takes a string and escapes all special HTML characters. This is very important to use to prevent XSS vulnerabilities.
+Each template is defined by a function that is passed two arguments (data and escape) and returns NodeDefinition with a single root element. The escape argument is a function that takes a string and escapes all special HTML characters. This is very important to use to prevent XSS vulnerabilities.
```js
new TomSelect('#input',{
diff --git a/doc_src/pages/docs/migration.md b/doc_src/pages/docs/migration.md
index f4cd42dd6..ea6bd4741 100644
--- a/doc_src/pages/docs/migration.md
+++ b/doc_src/pages/docs/migration.md
@@ -22,5 +22,5 @@ Review changes to the Tom Select API to help you migrate from v1 to v2.
* Multiple CSS classes are now toggled on the wrapper element instead of the control element: ```.focus```, ```.disabled```, ```.required```, ```.invalid```, ```.locked```, ```.full```, ```.not-full```, ```.input-active```, ```.dropdown-active```, ```.has-options```, ```.has-items```
* Removed bootstrap3 style
-## Options
+## Settings
* ```copyClassesToDropdown``` defaults to false
diff --git a/doc_src/pages/docs/plugins.md b/doc_src/pages/docs/plugins.md
index 1cc33c390..47d0ed2f8 100644
--- a/doc_src/pages/docs/plugins.md
+++ b/doc_src/pages/docs/plugins.md
@@ -45,10 +45,30 @@ Save some bandwidth with a bundle that's about 4kb smaller. tom-select.pop
#### tom-select.base.js
If you don't need any plugins, or want to load plugins individually, use tom-select.base.js.
-Add plugins to your project by including their js files: /js/plugins/remove_button.js, /js/plugins/dropdown_header.js, etc.
+
+Add plugins to your project by including their js files and calling `TomSelect.define`.
+
+```js
+import TomSelect from 'tom-select/base';
+import TomSelect_remove_button from 'tom-select/plugins/remove_button.js';
+import TomSelect_dropdown_header from 'tom-select/dropdown_header.js';
+
+TomSelect.define('remove_button', TomSelect_remove_button);
+TomSelect.define('dropdown_header', TomSelect_dropdown_header);
+```
+
+Alternatively you can `require` plugins directly if your build tool supports it.
+
+```js
+import TomSelect from 'tom-select/base';
+
+TomSelect.define('remove_button', require('tom-select/plugins/remove_button.js'));
+TomSelect.define('dropdown_header', require('tom-select/plugins/dropdown_header.js'));
+```
+
#### tom-select.custom.js
-Use NPM to hand-pick plugins and create /build/js/tom-select.custom.js
+Use NPM to hand-pick plugins and create /dist/js/tom-select.custom.js
```shell
# clone the repo
@@ -58,11 +78,10 @@ cd tom-select
# install dev dependencies
npm install
-# create /build/js/tom-select.custom.js
+# create /dist/js/tom-select.custom.js
npm run build -- --plugins=remove_button,restore_on_backspace
```
-
## Creating Plugins
**A few notes:**
@@ -70,6 +89,7 @@ npm run build -- --plugins=remove_button,restore_on_backspace
- Plugin names should follow the format: `/[a-z_]+$`
- JS source should live in a "plugin.js" file (required).
- CSS should live in a "plugin.scss" file (optional). It will be bundled at build time.
+- Plugins should not call `TomSelect.define` directly, this is done when importing the plugin.
- Plugins are initialized right before the control is setup.
This means that if you want to listen for events on any of the control's
elements, you should override the `setup()` method (see ["DOM Events"](#dom-events)).
@@ -78,18 +98,20 @@ npm run build -- --plugins=remove_button,restore_on_backspace
### Boilerplate
```js
-TomSelect.define('plugin_name', function(plugin_options) {
- // options: plugin-specific options
+// in src/plugins/plugin_name/plugin.js
+export default function(plugin_options) {
+ // plugin_options: plugin-specific options
// this: TomSelect instance
-});
+};
```
#### Adding Dependencies
```js
-TomSelect.define('plugin_name', function(plugin_options) {
+// in src/plugins/plugin_name/plugin.js
+export default function(plugin_options) {
this.require('another_plugin');
-});
+};
```
#### Method Hooks
@@ -97,11 +119,12 @@ TomSelect.define('plugin_name', function(plugin_options) {
Execute plugin code 'before' or 'after' existing methods
```js
-TomSelect.define('plugin_name', function(plugin_options) {
- this.hook('after','setup',function(){
+// in src/plugins/plugin_name/plugin.js
+export default function(plugin_options) {
+ this.hook('after', 'setup', function() {
// .. additional setup
});
-});
+};
```
#### Overriding Methods
@@ -111,13 +134,14 @@ Use the 'instead' hook to override existing methods.
overridden function returns a value as well.
```js
-TomSelect.define('plugin_name', function(plugin_options) {
+// in src/plugins/plugin_name/plugin.js
+export default function(plugin_options) {
var original_setup = this.setup;
- this.hook('instead','setup',function(){
+ this.hook('instead', 'setup', function() {
// .. custom setup
return original_setup.apply(this, arguments);
});
-});
+};
```
@@ -125,11 +149,12 @@ TomSelect.define('plugin_name', function(plugin_options) {
If you want to add event listeners to dom elements, add them after the `setup()` method.
```js
-TomSelect.define('plugin_name', function(plugin_options) {
- this.hook('after','setup',function(){
+// in src/plugins/plugin_name/plugin.js
+export default function(plugin_options) {
+ this.hook('after', 'setup', function() {
this.control.addEventListener('click',function(evt){
alert('the control was clicked');
});
});
-});
+};
```
diff --git a/doc_src/pages/examples/api.njk b/doc_src/pages/examples/api.njk
index b27f20fd3..73e5b68aa 100644
--- a/doc_src/pages/examples/api.njk
+++ b/doc_src/pages/examples/api.njk
@@ -15,7 +15,7 @@ tags: demo
{% set html %}
-
+
diff --git a/doc_src/pages/examples/customization.njk b/doc_src/pages/examples/customization.njk
index 1acf3f877..fcb6c78e1 100644
--- a/doc_src/pages/examples/customization.njk
+++ b/doc_src/pages/examples/customization.njk
@@ -1,6 +1,6 @@
---
-title: Customizing HTML
-nav_title: Custom HTML
+title: Customizing
+nav_title: Customizing
tags: demo
---
@@ -13,7 +13,7 @@ tags: demo
{% set label %}
This example provides a simple demonstration of how to override the default templates for options and items along with proper use of the escape() method.
@@ -66,3 +66,67 @@ new TomSelect('#select-links',{
{{ demo( label, html, script, style) }}
+
+
+
+
+
+{% set label %}
+
+
+ There are a number of ways to customize the JavaScript functionality.
+ Plugins are a great example but sometimes you just want to add some functionality to items or options.
+ The example below shows how to add a clickable button within an option but the same concept can be applied to items.
+