mirror of
https://github.com/chubin/cheat.sh.git
synced 2025-01-06 04:16:04 +03:00
removed unused awesomeplete
This commit is contained in:
parent
ec198219b0
commit
e5d8a1c70f
@ -1,14 +0,0 @@
|
||||
engines:
|
||||
eslint:
|
||||
enabled: true
|
||||
fixme:
|
||||
enabled: true
|
||||
ratings:
|
||||
paths:
|
||||
- "**.js"
|
||||
exclude_paths:
|
||||
- "**.min.js"
|
||||
- karma*.conf.js
|
||||
- prism/**/*
|
||||
- test/**/*
|
||||
- .*
|
@ -1,254 +0,0 @@
|
||||
ecmaFeatures: {}
|
||||
rules:
|
||||
no-alert: 0
|
||||
no-array-constructor: 0
|
||||
no-bitwise: 0
|
||||
no-caller: 0
|
||||
no-catch-shadow: 0
|
||||
no-class-assign: 0
|
||||
no-cond-assign: 2
|
||||
no-console: 2
|
||||
no-const-assign: 0
|
||||
no-constant-condition: 2
|
||||
no-continue: 0
|
||||
no-control-regex: 2
|
||||
no-debugger: 2
|
||||
no-delete-var: 2
|
||||
no-div-regex: 0
|
||||
no-dupe-keys: 2
|
||||
no-dupe-args: 2
|
||||
no-duplicate-case: 2
|
||||
no-else-return: 0
|
||||
no-empty: 2
|
||||
no-empty-character-class: 2
|
||||
no-empty-label: 0
|
||||
no-eq-null: 0
|
||||
no-eval: 0
|
||||
no-ex-assign: 2
|
||||
no-extend-native: 0
|
||||
no-extra-bind: 0
|
||||
no-extra-boolean-cast: 2
|
||||
no-extra-parens: 0
|
||||
no-extra-semi: 2
|
||||
no-fallthrough: 2
|
||||
no-floating-decimal: 0
|
||||
no-func-assign: 2
|
||||
no-implicit-coercion: 0
|
||||
no-implied-eval: 0
|
||||
no-inline-comments: 0
|
||||
no-inner-declarations:
|
||||
- 2
|
||||
- functions
|
||||
no-invalid-regexp: 2
|
||||
no-invalid-this: 0
|
||||
no-irregular-whitespace: 2
|
||||
no-iterator: 0
|
||||
no-label-var: 0
|
||||
no-labels: 0
|
||||
no-lone-blocks: 0
|
||||
no-lonely-if: 0
|
||||
no-loop-func: 0
|
||||
no-mixed-requires:
|
||||
- 0
|
||||
- false
|
||||
no-mixed-spaces-and-tabs:
|
||||
- 2
|
||||
- smart-tabs
|
||||
linebreak-style:
|
||||
- 0
|
||||
- unix
|
||||
no-multi-spaces: 0
|
||||
no-multi-str: 0
|
||||
no-multiple-empty-lines:
|
||||
- 0
|
||||
- max: 2
|
||||
no-native-reassign: 0
|
||||
no-negated-in-lhs: 2
|
||||
no-nested-ternary: 0
|
||||
no-new: 0
|
||||
no-new-func: 0
|
||||
no-new-object: 0
|
||||
no-new-require: 0
|
||||
no-new-wrappers: 0
|
||||
no-obj-calls: 2
|
||||
no-octal: 2
|
||||
no-octal-escape: 0
|
||||
no-param-reassign: 0
|
||||
no-path-concat: 0
|
||||
no-plusplus: 0
|
||||
no-process-env: 0
|
||||
no-process-exit: 0
|
||||
no-proto: 0
|
||||
no-redeclare: 2
|
||||
no-regex-spaces: 2
|
||||
no-reserved-keys: 0
|
||||
no-restricted-modules: 0
|
||||
no-return-assign: 0
|
||||
no-script-url: 0
|
||||
no-self-compare: 0
|
||||
no-sequences: 0
|
||||
no-shadow: 0
|
||||
no-shadow-restricted-names: 0
|
||||
no-spaced-func: 0
|
||||
no-sparse-arrays: 2
|
||||
no-sync: 0
|
||||
no-ternary: 0
|
||||
no-trailing-spaces: 0
|
||||
no-this-before-super: 0
|
||||
no-throw-literal: 0
|
||||
no-undef: 2
|
||||
no-undef-init: 0
|
||||
no-undefined: 0
|
||||
no-unexpected-multiline: 0
|
||||
no-underscore-dangle: 0
|
||||
no-unneeded-ternary: 0
|
||||
no-unreachable: 2
|
||||
no-unused-expressions: 0
|
||||
no-unused-vars:
|
||||
- 2
|
||||
- vars: all
|
||||
args: after-used
|
||||
no-use-before-define: 0
|
||||
no-useless-call: 0
|
||||
no-void: 0
|
||||
no-var: 0
|
||||
no-warning-comments:
|
||||
- 0
|
||||
- terms:
|
||||
- todo
|
||||
- fixme
|
||||
- xxx
|
||||
location: start
|
||||
no-with: 0
|
||||
array-bracket-spacing:
|
||||
- 0
|
||||
- never
|
||||
arrow-parens: 0
|
||||
arrow-spacing: 0
|
||||
accessor-pairs: 0
|
||||
block-scoped-var: 0
|
||||
brace-style:
|
||||
- 0
|
||||
- 1tbs
|
||||
callback-return: 0
|
||||
camelcase: 0
|
||||
comma-dangle:
|
||||
- 2
|
||||
- never
|
||||
comma-spacing: 0
|
||||
comma-style: 0
|
||||
complexity:
|
||||
- 2
|
||||
- 11
|
||||
computed-property-spacing:
|
||||
- 0
|
||||
- never
|
||||
consistent-return: 0
|
||||
consistent-this:
|
||||
- 0
|
||||
- that
|
||||
constructor-super: 0
|
||||
curly:
|
||||
- 0
|
||||
- all
|
||||
default-case: 0
|
||||
dot-location: 0
|
||||
dot-notation:
|
||||
- 0
|
||||
- allowKeywords: true
|
||||
eol-last: 0
|
||||
eqeqeq: 0
|
||||
func-names: 0
|
||||
func-style:
|
||||
- 0
|
||||
- declaration
|
||||
generator-star-spacing: 0
|
||||
guard-for-in: 0
|
||||
handle-callback-err: 0
|
||||
indent: 0
|
||||
init-declarations: 0
|
||||
key-spacing:
|
||||
- 0
|
||||
- beforeColon: false
|
||||
afterColon: true
|
||||
lines-around-comment: 0
|
||||
max-depth:
|
||||
- 0
|
||||
- 4
|
||||
max-len:
|
||||
- 0
|
||||
- 80
|
||||
- 4
|
||||
max-nested-callbacks:
|
||||
- 0
|
||||
- 2
|
||||
max-params:
|
||||
- 0
|
||||
- 3
|
||||
max-statements:
|
||||
- 0
|
||||
- 10
|
||||
new-cap: 0
|
||||
new-parens: 0
|
||||
newline-after-var: 0
|
||||
object-curly-spacing:
|
||||
- 0
|
||||
- never
|
||||
object-shorthand: 0
|
||||
one-var: 0
|
||||
operator-assignment:
|
||||
- 0
|
||||
- always
|
||||
operator-linebreak: 0
|
||||
padded-blocks: 0
|
||||
prefer-const: 0
|
||||
prefer-spread: 0
|
||||
prefer-reflect: 0
|
||||
quote-props: 0
|
||||
quotes:
|
||||
- 2
|
||||
- double
|
||||
- avoid-escape
|
||||
radix: 0
|
||||
require-yield: 0
|
||||
semi: 0
|
||||
semi-spacing:
|
||||
- 0
|
||||
- before: false
|
||||
after: true
|
||||
sort-vars: 0
|
||||
space-after-keywords:
|
||||
- 0
|
||||
- always
|
||||
space-before-blocks:
|
||||
- 0
|
||||
- always
|
||||
space-before-function-paren:
|
||||
- 0
|
||||
- always
|
||||
space-in-parens:
|
||||
- 0
|
||||
- never
|
||||
space-infix-ops: 0
|
||||
space-return-throw-case: 0
|
||||
space-unary-ops:
|
||||
- 0
|
||||
- words: true
|
||||
nonwords: false
|
||||
spaced-comment: 0
|
||||
strict: 0
|
||||
use-isnan: 2
|
||||
valid-jsdoc: 0
|
||||
valid-typeof: 2
|
||||
vars-on-top: 0
|
||||
wrap-iife: 0
|
||||
wrap-regex: 0
|
||||
yoda:
|
||||
- 0
|
||||
- never
|
||||
env:
|
||||
browser: true
|
||||
node: true
|
||||
jquery: true
|
||||
amd: true
|
||||
commonjs: true
|
2
share/static/awesomplete-gh-pages/.gitignore
vendored
2
share/static/awesomplete-gh-pages/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
node_modules/
|
||||
coverage/
|
@ -1,28 +0,0 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.10"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- gh-pages
|
||||
- /v\d+\.\d+/
|
||||
|
||||
install:
|
||||
- npm install -g codeclimate-test-reporter
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- export CHROME_BIN=chromium-browser
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
|
||||
after_script:
|
||||
- codeclimate-test-reporter < ./coverage/lcov.info
|
||||
|
||||
deploy:
|
||||
provider: npm
|
||||
email: $NPM_EMAIL
|
||||
api_key: $NPM_TOKEN
|
||||
on:
|
||||
tags: true
|
@ -1,22 +0,0 @@
|
||||
# 1.1.1 (2016-06-25)
|
||||
|
||||
## Fixes
|
||||
|
||||
* Improved docs
|
||||
* Emit close reason with `awesomplete-close` events ([8c0ff62](https://github.com/LeaVerou/awesomplete/commit/8c0ff6225c96af2f5f3b7312d7ba7b69f71be575)). See [Events](http://leaverou.github.io/awesomplete/#events).
|
||||
* Fire `awesomplete-close` event only if open ([2cef2c2](https://github.com/LeaVerou/awesomplete/commit/2cef2c28a6f74ee5c0b294d2c3c7d2bad72bd466))
|
||||
|
||||
# 1.1.0 (2016-03-16)
|
||||
|
||||
## Features
|
||||
|
||||
* Separate label/value for each suggestion on the list
|
||||
* New `suggestions` property with suggestion items only (to be rendered in completer)
|
||||
* New `data` method to convert/change suggestion item data and corresponding `Awesomplete.DATA`
|
||||
* The `item` and `replace` methods have a corresponding `Awesomplete.ITEM` and `Awesomplete.REPLACE` defaults now
|
||||
* Ajax and Combobox examples
|
||||
* Nearly 100% test coverage with Travis CI and Code Climate
|
||||
|
||||
# 1.0.0 (2015-04-23)
|
||||
|
||||
## First release
|
@ -1,59 +0,0 @@
|
||||
##Contributing
|
||||
|
||||
**Prerequisites**
|
||||
|
||||
Install [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/). On OSX with [Homebrew](http://brew.sh/) installed it is as easy as:
|
||||
```
|
||||
brew install node
|
||||
```
|
||||
|
||||
Install dependencies:
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
**Running tests**
|
||||
|
||||
Run tests once and exit:
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
Continuous mode. Whenever any source or test file changes, tests will run automatically:
|
||||
```
|
||||
karma start
|
||||
```
|
||||
|
||||
Chrome starts automatically and stops on ```Ctrl+C```. You can also open ```http://localhost:9876/``` in any other browser and it will run the tests as long as the tab is open.
|
||||
|
||||
**Adding a test**
|
||||
|
||||
[Jasmine](http://jasmine.github.io/) is the testing framework used by Awesomplete.
|
||||
|
||||
To write a test (or suite of tests) start by adding a `describe` function which receives a string describing what is being tested and a function containing what you expect the test to do. Inside the function use the `it` block to arrange and assert a functionality.
|
||||
|
||||
A test would look like this:
|
||||
|
||||
```javascript
|
||||
describe("A fact", function(){
|
||||
it("is always true",function(){
|
||||
var fact = true;
|
||||
expect(fact).toBe(true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
See existing tests in ```test``` directory as an example. More expectations and examples on how to use Jasmine can be found on the official [documentation](http://jasmine.github.io/2.2/introduction.html).
|
||||
|
||||
**Build**
|
||||
|
||||
Run the build with the following command:
|
||||
|
||||
```
|
||||
gulp
|
||||
```
|
||||
|
||||
The build will:
|
||||
|
||||
1. Minify `awesomplete.js` and generate `awesomplete.min.js`.
|
||||
2. Merge `awesomplete.base.css` and `awesomplete.theme.css` and generate `awesomplete.css`.
|
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Lea Verou
|
||||
|
||||
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.
|
||||
|
@ -1,78 +0,0 @@
|
||||
# Awesomplete
|
||||
[![npm version](https://img.shields.io/npm/v/awesomplete.svg)](https://www.npmjs.com/package/awesomplete)
|
||||
[![Build Status](https://img.shields.io/travis/LeaVerou/awesomplete/gh-pages.svg)](https://travis-ci.org/LeaVerou/awesomplete)
|
||||
[![Code Climate](https://img.shields.io/codeclimate/github/LeaVerou/awesomplete.svg)](https://codeclimate.com/github/LeaVerou/awesomplete)
|
||||
[![Test Coverage](https://img.shields.io/codeclimate/coverage/github/LeaVerou/awesomplete.svg)](https://codeclimate.com/github/LeaVerou/awesomplete/coverage)
|
||||
|
||||
http://leaverou.github.io/awesomplete/
|
||||
|
||||
Awesomplete is an ultra lightweight, customizable, simple autocomplete widget with zero dependencies, built with modern standards for modern browsers.
|
||||
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Before you try anything, you need to include awesomplete.css and awesomplete.js in your page, via the usual tags:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="awesomplete.css" />
|
||||
<script src="awesomplete.js" async></script>
|
||||
```
|
||||
|
||||
Then you can add an Awesomplete widget by adding the following input tag:
|
||||
|
||||
```html
|
||||
<input class="awesomplete"
|
||||
data-list="Ada, Java, JavaScript, Brainfuck, LOLCODE, Node.js, Ruby on Rails" />
|
||||
```
|
||||
|
||||
Add `class="awesomplete"` for it to be automatically processed (you can still specify many options via HTML attributes)
|
||||
Otherwise you can instantiate with a few lines of JS code, which allow for more customization.
|
||||
|
||||
There are many ways to link an input to a list of suggestions.
|
||||
The simple example above could have also been made with the following markup, which provides a nice native fallback in case the script doesn’t load:
|
||||
|
||||
```html
|
||||
<input class="awesomplete" list="mylist" />
|
||||
<datalist id="mylist">
|
||||
<option>Ada</option>
|
||||
<option>Java</option>
|
||||
<option>JavaScript</option>
|
||||
<option>Brainfuck</option>
|
||||
<option>LOLCODE</option>
|
||||
<option>Node.js</option>
|
||||
<option>Ruby on Rails</option>
|
||||
</datalist>
|
||||
```
|
||||
|
||||
Or the following, if you don’t want to use a `<datalist>`, or if you don’t want to use IDs (since any selector will work in data-list):
|
||||
|
||||
```html
|
||||
<input class="awesomplete" data-list="#mylist" />
|
||||
<ul id="mylist">
|
||||
<li>Ada</li>
|
||||
<li>Java</li>
|
||||
<li>JavaScript</li>
|
||||
<li>Brainfuck</li>
|
||||
<li>LOLCODE</li>
|
||||
<li>Node.js</li>
|
||||
<li>Ruby on Rails</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
There are multiple customizations and properties able to be instantiated within the JS. Libraries and definitions of the properties are available in the Links below.
|
||||
|
||||
## License
|
||||
|
||||
Awesomplete is released under the MIT License. See [LICENSE][1] file for
|
||||
details.
|
||||
|
||||
## Links
|
||||
|
||||
The official site for the library is at <http://leaverou.github.io/awesomplete/>.
|
||||
|
||||
Documentation for the API and other topics is at
|
||||
<http://leaverou.github.io/awesomplete/#api>.
|
||||
|
||||
Created by Lea Verou and other fantastic contributors.
|
||||
|
||||
[1]: https://github.com/LeaVerou/awesomplete/blob/gh-pages/LICENSE
|
@ -1,33 +0,0 @@
|
||||
.awesomplete [hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.awesomplete .visually-hidden {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.awesomplete > input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.awesomplete > ul {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.awesomplete > ul:empty {
|
||||
display: none;
|
||||
}
|
@ -1 +0,0 @@
|
||||
{"version":3,"sources":["awesomplete.base.css","awesomplete.theme.css"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"awesomplete.css","sourcesContent":[".awesomplete [hidden] {\n display: none;\n}\n\n.awesomplete .visually-hidden {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n}\n\n.awesomplete {\n display: inline-block;\n position: relative;\n}\n\n.awesomplete > input {\n display: block;\n}\n\n.awesomplete > ul {\n position: absolute;\n left: 0;\n z-index: 1;\n min-width: 100%;\n box-sizing: border-box;\n list-style: none;\n padding: 0;\n margin: 0;\n background: #fff;\n}\n\n.awesomplete > ul:empty {\n display: none;\n}\n",".awesomplete > ul {\n\tborder-radius: .3em;\n\tmargin: .2em 0 0;\n\tbackground: hsla(0,0%,100%,.9);\n\tbackground: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));\n\tborder: 1px solid rgba(0,0,0,.3);\n\tbox-shadow: .05em .2em .6em rgba(0,0,0,.2);\n\ttext-shadow: none;\n}\n\n@supports (transform: scale(0)) {\n\t.awesomplete > ul {\n\t\ttransition: .3s cubic-bezier(.4,.2,.5,1.4);\n\t\ttransform-origin: 1.43em -.43em;\n\t}\n\t\n\t.awesomplete > ul[hidden],\n\t.awesomplete > ul:empty {\n\t\topacity: 0;\n\t\ttransform: scale(0);\n\t\tdisplay: block;\n\t\ttransition-timing-function: ease;\n\t}\n}\n\n\t/* Pointer */\n\t.awesomplete > ul:before {\n\t\tcontent: \"\";\n\t\tposition: absolute;\n\t\ttop: -.43em;\n\t\tleft: 1em;\n\t\twidth: 0; height: 0;\n\t\tpadding: .4em;\n\t\tbackground: white;\n\t\tborder: inherit;\n\t\tborder-right: 0;\n\t\tborder-bottom: 0;\n\t\t-webkit-transform: rotate(45deg);\n\t\ttransform: rotate(45deg);\n\t}\n\n\t.awesomplete > ul > li {\n\t\tposition: relative;\n\t\tpadding: .2em .5em;\n\t\tcursor: pointer;\n\t}\n\t\n\t.awesomplete > ul > li:hover {\n\t\tbackground: hsl(200, 40%, 80%);\n\t\tcolor: black;\n\t}\n\t\n\t.awesomplete > ul > li[aria-selected=\"true\"] {\n\t\tbackground: hsl(205, 40%, 40%);\n\t\tcolor: white;\n\t}\n\t\n\t\t.awesomplete mark {\n\t\t\tbackground: hsl(65, 100%, 50%);\n\t\t}\n\t\t\n\t\t.awesomplete li:hover mark {\n\t\t\tbackground: hsl(68, 100%, 41%);\n\t\t}\n\t\t\n\t\t.awesomplete li[aria-selected=\"true\"] mark {\n\t\t\tbackground: hsl(86, 100%, 21%);\n\t\t\tcolor: inherit;\n\t\t}"],"sourceRoot":"/source/"}
|
@ -1,454 +0,0 @@
|
||||
/**
|
||||
* Simple, lightweight, usable local autocomplete library for modern browsers
|
||||
* Because there weren’t enough autocomplete scripts in the world? Because I’m completely insane and have NIH syndrome? Probably both. :P
|
||||
* @author Lea Verou http://leaverou.github.io/awesomplete
|
||||
* MIT license
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
var _ = function (input, o) {
|
||||
var me = this;
|
||||
|
||||
// Setup
|
||||
|
||||
this.isOpened = false;
|
||||
|
||||
this.input = $(input);
|
||||
this.input.setAttribute("autocomplete", "off");
|
||||
this.input.setAttribute("aria-autocomplete", "list");
|
||||
|
||||
o = o || {};
|
||||
|
||||
configure(this, {
|
||||
minChars: 2,
|
||||
maxItems: 10,
|
||||
autoFirst: false,
|
||||
data: _.DATA,
|
||||
filter: _.FILTER_CONTAINS,
|
||||
sort: o.sort === false ? false : _.SORT_BYLENGTH,
|
||||
item: _.ITEM,
|
||||
replace: _.REPLACE
|
||||
}, o);
|
||||
|
||||
this.index = -1;
|
||||
|
||||
// Create necessary elements
|
||||
|
||||
this.container = $.create("div", {
|
||||
className: "awesomplete",
|
||||
around: input
|
||||
});
|
||||
|
||||
this.ul = $.create("ul", {
|
||||
hidden: "hidden",
|
||||
inside: this.container
|
||||
});
|
||||
|
||||
this.status = $.create("span", {
|
||||
className: "visually-hidden",
|
||||
role: "status",
|
||||
"aria-live": "assertive",
|
||||
"aria-relevant": "additions",
|
||||
inside: this.container
|
||||
});
|
||||
|
||||
// Bind events
|
||||
|
||||
$.bind(this.input, {
|
||||
"input": this.evaluate.bind(this),
|
||||
"blur": this.close.bind(this, { reason: "blur" }),
|
||||
"keydown": function(evt) {
|
||||
var c = evt.keyCode;
|
||||
|
||||
// If the dropdown `ul` is in view, then act on keydown for the following keys:
|
||||
// Enter / Esc / Up / Down
|
||||
if(me.opened) {
|
||||
if (c === 13 && me.selected) { // Enter
|
||||
evt.preventDefault();
|
||||
me.select();
|
||||
}
|
||||
else if (c === 27) { // Esc
|
||||
me.close({ reason: "esc" });
|
||||
}
|
||||
else if (c === 38 || c === 40) { // Down/Up arrow
|
||||
evt.preventDefault();
|
||||
me[c === 38? "previous" : "next"]();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.bind(this.input.form, {"submit": this.close.bind(this, { reason: "submit" })});
|
||||
|
||||
$.bind(this.ul, {"mousedown": function(evt) {
|
||||
var li = evt.target;
|
||||
|
||||
if (li !== this) {
|
||||
|
||||
while (li && !/li/i.test(li.nodeName)) {
|
||||
li = li.parentNode;
|
||||
}
|
||||
|
||||
if (li && evt.button === 0) { // Only select on left click
|
||||
evt.preventDefault();
|
||||
me.select(li, evt.target);
|
||||
}
|
||||
}
|
||||
}});
|
||||
|
||||
if (this.input.hasAttribute("list")) {
|
||||
this.list = "#" + this.input.getAttribute("list");
|
||||
this.input.removeAttribute("list");
|
||||
}
|
||||
else {
|
||||
this.list = this.input.getAttribute("data-list") || o.list || [];
|
||||
}
|
||||
|
||||
_.all.push(this);
|
||||
};
|
||||
|
||||
_.prototype = {
|
||||
set list(list) {
|
||||
if (Array.isArray(list)) {
|
||||
this._list = list;
|
||||
}
|
||||
else if (typeof list === "string" && list.indexOf(",") > -1) {
|
||||
this._list = list.split(/\s*,\s*/);
|
||||
}
|
||||
else { // Element or CSS selector
|
||||
list = $(list);
|
||||
|
||||
if (list && list.children) {
|
||||
var items = [];
|
||||
slice.apply(list.children).forEach(function (el) {
|
||||
if (!el.disabled) {
|
||||
var text = el.textContent.trim();
|
||||
var value = el.value || text;
|
||||
var label = el.label || text;
|
||||
if (value !== "") {
|
||||
items.push({ label: label, value: value });
|
||||
}
|
||||
}
|
||||
});
|
||||
this._list = items;
|
||||
}
|
||||
}
|
||||
|
||||
if (document.activeElement === this.input) {
|
||||
this.evaluate();
|
||||
}
|
||||
},
|
||||
|
||||
get selected() {
|
||||
return this.index > -1;
|
||||
},
|
||||
|
||||
get opened() {
|
||||
return this.isOpened;
|
||||
},
|
||||
|
||||
close: function (o) {
|
||||
if (!this.opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.ul.setAttribute("hidden", "");
|
||||
this.isOpened = false;
|
||||
this.index = -1;
|
||||
|
||||
$.fire(this.input, "awesomplete-close", o || {});
|
||||
},
|
||||
|
||||
open: function () {
|
||||
this.ul.removeAttribute("hidden");
|
||||
this.isOpened = true;
|
||||
|
||||
if (this.autoFirst && this.index === -1) {
|
||||
this.goto(0);
|
||||
}
|
||||
|
||||
$.fire(this.input, "awesomplete-open");
|
||||
},
|
||||
|
||||
next: function () {
|
||||
var count = this.ul.children.length;
|
||||
this.goto(this.index < count - 1 ? this.index + 1 : (count ? 0 : -1) );
|
||||
},
|
||||
|
||||
previous: function () {
|
||||
var count = this.ul.children.length;
|
||||
var pos = this.index - 1;
|
||||
|
||||
this.goto(this.selected && pos !== -1 ? pos : count - 1);
|
||||
},
|
||||
|
||||
// Should not be used, highlights specific item without any checks!
|
||||
goto: function (i) {
|
||||
var lis = this.ul.children;
|
||||
|
||||
if (this.selected) {
|
||||
lis[this.index].setAttribute("aria-selected", "false");
|
||||
}
|
||||
|
||||
this.index = i;
|
||||
|
||||
if (i > -1 && lis.length > 0) {
|
||||
lis[i].setAttribute("aria-selected", "true");
|
||||
this.status.textContent = lis[i].textContent;
|
||||
|
||||
// scroll to highlighted element in case parent's height is fixed
|
||||
this.ul.scrollTop = lis[i].offsetTop - this.ul.clientHeight + lis[i].clientHeight;
|
||||
|
||||
$.fire(this.input, "awesomplete-highlight", {
|
||||
text: this.suggestions[this.index]
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
select: function (selected, origin) {
|
||||
if (selected) {
|
||||
this.index = $.siblingIndex(selected);
|
||||
} else {
|
||||
selected = this.ul.children[this.index];
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
var suggestion = this.suggestions[this.index];
|
||||
|
||||
var allowed = $.fire(this.input, "awesomplete-select", {
|
||||
text: suggestion,
|
||||
origin: origin || selected
|
||||
});
|
||||
|
||||
if (allowed) {
|
||||
this.replace(suggestion);
|
||||
this.close({ reason: "select" });
|
||||
$.fire(this.input, "awesomplete-selectcomplete", {
|
||||
text: suggestion
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
evaluate: function() {
|
||||
var me = this;
|
||||
var value = this.input.value;
|
||||
|
||||
if (value.length >= this.minChars && this._list.length > 0) {
|
||||
this.index = -1;
|
||||
// Populate list with options that match
|
||||
this.ul.innerHTML = "";
|
||||
|
||||
this.suggestions = this._list
|
||||
.map(function(item) {
|
||||
return new Suggestion(me.data(item, value));
|
||||
})
|
||||
.filter(function(item) {
|
||||
return me.filter(item, value);
|
||||
});
|
||||
|
||||
if (this.sort !== false) {
|
||||
this.suggestions = this.suggestions.sort(this.sort);
|
||||
}
|
||||
|
||||
this.suggestions = this.suggestions.slice(0, this.maxItems);
|
||||
|
||||
this.suggestions.forEach(function(text) {
|
||||
me.ul.appendChild(me.item(text, value));
|
||||
});
|
||||
|
||||
if (this.ul.children.length === 0) {
|
||||
this.close({ reason: "nomatches" });
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.close({ reason: "nomatches" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Static methods/properties
|
||||
|
||||
_.all = [];
|
||||
|
||||
_.FILTER_CONTAINS = function (text, input) {
|
||||
return RegExp($.regExpEscape(input.trim()), "i").test(text);
|
||||
};
|
||||
|
||||
_.FILTER_STARTSWITH = function (text, input) {
|
||||
return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
|
||||
};
|
||||
|
||||
_.SORT_BYLENGTH = function (a, b) {
|
||||
if (a.length !== b.length) {
|
||||
return a.length - b.length;
|
||||
}
|
||||
|
||||
return a < b? -1 : 1;
|
||||
};
|
||||
|
||||
_.ITEM = function (text, input) {
|
||||
var html = input.trim() === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>");
|
||||
return $.create("li", {
|
||||
innerHTML: html,
|
||||
"aria-selected": "false"
|
||||
});
|
||||
};
|
||||
|
||||
_.REPLACE = function (text) {
|
||||
this.input.value = text.value;
|
||||
};
|
||||
|
||||
_.DATA = function (item/*, input*/) { return item; };
|
||||
|
||||
// Private functions
|
||||
|
||||
function Suggestion(data) {
|
||||
var o = Array.isArray(data)
|
||||
? { label: data[0], value: data[1] }
|
||||
: typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
|
||||
|
||||
this.label = o.label || o.value;
|
||||
this.value = o.value;
|
||||
}
|
||||
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
|
||||
get: function() { return this.label.length; }
|
||||
});
|
||||
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
|
||||
return "" + this.label;
|
||||
};
|
||||
|
||||
function configure(instance, properties, o) {
|
||||
for (var i in properties) {
|
||||
var initial = properties[i],
|
||||
attrValue = instance.input.getAttribute("data-" + i.toLowerCase());
|
||||
|
||||
if (typeof initial === "number") {
|
||||
instance[i] = parseInt(attrValue);
|
||||
}
|
||||
else if (initial === false) { // Boolean options must be false by default anyway
|
||||
instance[i] = attrValue !== null;
|
||||
}
|
||||
else if (initial instanceof Function) {
|
||||
instance[i] = null;
|
||||
}
|
||||
else {
|
||||
instance[i] = attrValue;
|
||||
}
|
||||
|
||||
if (!instance[i] && instance[i] !== 0) {
|
||||
instance[i] = (i in o)? o[i] : initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
function $(expr, con) {
|
||||
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
|
||||
}
|
||||
|
||||
function $$(expr, con) {
|
||||
return slice.call((con || document).querySelectorAll(expr));
|
||||
}
|
||||
|
||||
$.create = function(tag, o) {
|
||||
var element = document.createElement(tag);
|
||||
|
||||
for (var i in o) {
|
||||
var val = o[i];
|
||||
|
||||
if (i === "inside") {
|
||||
$(val).appendChild(element);
|
||||
}
|
||||
else if (i === "around") {
|
||||
var ref = $(val);
|
||||
ref.parentNode.insertBefore(element, ref);
|
||||
element.appendChild(ref);
|
||||
}
|
||||
else if (i in element) {
|
||||
element[i] = val;
|
||||
}
|
||||
else {
|
||||
element.setAttribute(i, val);
|
||||
}
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
$.bind = function(element, o) {
|
||||
if (element) {
|
||||
for (var event in o) {
|
||||
var callback = o[event];
|
||||
|
||||
event.split(/\s+/).forEach(function (event) {
|
||||
element.addEventListener(event, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.fire = function(target, type, properties) {
|
||||
var evt = document.createEvent("HTMLEvents");
|
||||
|
||||
evt.initEvent(type, true, true );
|
||||
|
||||
for (var j in properties) {
|
||||
evt[j] = properties[j];
|
||||
}
|
||||
|
||||
return target.dispatchEvent(evt);
|
||||
};
|
||||
|
||||
$.regExpEscape = function (s) {
|
||||
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
};
|
||||
|
||||
$.siblingIndex = function (el) {
|
||||
/* eslint-disable no-cond-assign */
|
||||
for (var i = 0; el = el.previousElementSibling; i++);
|
||||
return i;
|
||||
};
|
||||
|
||||
// Initialization
|
||||
|
||||
function init() {
|
||||
$$("input.awesomplete").forEach(function (input) {
|
||||
new _(input);
|
||||
});
|
||||
}
|
||||
|
||||
// Are we in a browser? Check for Document constructor
|
||||
if (typeof Document !== "undefined") {
|
||||
// DOM already loaded?
|
||||
if (document.readyState !== "loading") {
|
||||
init();
|
||||
}
|
||||
else {
|
||||
// Wait for it
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
}
|
||||
}
|
||||
|
||||
_.$ = $;
|
||||
_.$$ = $$;
|
||||
|
||||
// Make sure to export Awesomplete on self when in a browser
|
||||
if (typeof self !== "undefined") {
|
||||
self.Awesomplete = _;
|
||||
}
|
||||
|
||||
// Expose Awesomplete as a CJS module
|
||||
if (typeof module === "object" && module.exports) {
|
||||
module.exports = _;
|
||||
}
|
||||
|
||||
return _;
|
||||
|
||||
}());
|
File diff suppressed because one or more lines are too long
@ -1,69 +0,0 @@
|
||||
.awesomplete > ul {
|
||||
border-radius: .3em;
|
||||
margin: .2em 0 0;
|
||||
background: hsla(0,0%,100%,.9);
|
||||
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
|
||||
border: 1px solid rgba(0,0,0,.3);
|
||||
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
@supports (transform: scale(0)) {
|
||||
.awesomplete > ul {
|
||||
transition: .3s cubic-bezier(.4,.2,.5,1.4);
|
||||
transform-origin: 1.43em -.43em;
|
||||
}
|
||||
|
||||
.awesomplete > ul[hidden],
|
||||
.awesomplete > ul:empty {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
display: block;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pointer */
|
||||
.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0; height: 0;
|
||||
padding: .4em;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.awesomplete > ul > li {
|
||||
position: relative;
|
||||
padding: .2em .5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.awesomplete > ul > li:hover {
|
||||
background: hsl(200, 40%, 80%);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.awesomplete > ul > li[aria-selected="true"] {
|
||||
background: hsl(205, 40%, 40%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.awesomplete mark {
|
||||
background: hsl(65, 100%, 50%);
|
||||
}
|
||||
|
||||
.awesomplete li:hover mark {
|
||||
background: hsl(68, 100%, 41%);
|
||||
}
|
||||
|
||||
.awesomplete li[aria-selected="true"] mark {
|
||||
background: hsl(86, 100%, 21%);
|
||||
color: inherit;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "awesomplete",
|
||||
"main": [
|
||||
"./awesomplete.css",
|
||||
"./awesomplete.js"
|
||||
],
|
||||
"homepage": "https://github.com/LeaVerou/awesomplete",
|
||||
"authors": [
|
||||
"Lea Verou <>"
|
||||
],
|
||||
"description": "Ultra lightweight, usable autocomplete with zero dependencies.",
|
||||
"keywords": [
|
||||
"autocomplete",
|
||||
"lightweight"
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
var gulp = require('gulp');
|
||||
var uglify = require('gulp-uglify');
|
||||
var rename = require('gulp-rename');
|
||||
var header = require('gulp-header');
|
||||
var concat = require('gulp-concat');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
var banner = "// Awesomplete - Lea Verou - MIT license\n";
|
||||
|
||||
gulp.task('minify', function() {
|
||||
return gulp.src(['awesomplete.js'])
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(uglify())
|
||||
.pipe(rename({ suffix: '.min' }))
|
||||
.pipe(header(banner))
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest('.'));
|
||||
});
|
||||
|
||||
gulp.task('concat', function() {
|
||||
|
||||
return gulp.src(['awesomplete.base.css', 'awesomplete.theme.css'])
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat('awesomplete.css'))
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest('.'));
|
||||
|
||||
|
||||
});
|
||||
|
||||
gulp.task('default', ['minify', 'concat']);
|
@ -1,473 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<title>Awesomplete: Ultra lightweight, highly customizable, simple autocomplete, by Lea Verou</title>
|
||||
<link rel="stylesheet" href="prism/prism.css" />
|
||||
<link rel="stylesheet" href="awesomplete.css" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
|
||||
<script src="awesomplete.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</head>
|
||||
<body class="language-markup">
|
||||
|
||||
<header>
|
||||
|
||||
<h1>Awesomplete</h1>
|
||||
|
||||
<a href="#download" class="size"><strong>2KB</strong> minified <span class="amp">&</span> gzipped!</a>
|
||||
|
||||
<p>Ultra lightweight, customizable, simple autocomplete widget with zero dependencies, built with modern standards for <abbr title="Verified to work in: IE9 (sorta), IE10+, Chrome, Firefox, Safari 5+, Mobile Safari">modern browsers</abbr>. <a href="http://lea.verou.me/2015/02/awesomplete-2kb-autocomplete-with-zero-dependencies">Because <code><datalist></code> still doesn’t cut it.</a></p>
|
||||
|
||||
<nav></nav>
|
||||
</header>
|
||||
|
||||
<section>
|
||||
|
||||
<h1>Demo (no JS, minimal options)</h1>
|
||||
<label>
|
||||
Pick a programming language:<br />
|
||||
<input autofocus class="awesomplete" data-list="Ada, Java, JavaScript, Brainfuck, LOLCODE, Node.js, Ruby on Rails" />
|
||||
</label>
|
||||
|
||||
<p>Note that by default you need to type <strong>at least 2 characters</strong> for the popup to show up, though that’s <a href="#customization">super easy to customize</a>. With Awesomplete, making something like this can be as simple as:</p>
|
||||
|
||||
<pre class="language-markup"><code><input class="awesomplete"
|
||||
data-list="Ada, Java, JavaScript, Brainfuck, LOLCODE, Node.js, Ruby on Rails" /></code></pre>
|
||||
|
||||
<pre class="language-javascript"><code>// No extra JS needed for basic usage!</code></pre>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="basic-usage">
|
||||
|
||||
<h1>Basic usage</h1>
|
||||
<p>Before you try anything, you need to include <code>awesomplete.css</code> and <code>awesomplete.js</code> in your page, via the usual <code><link rel="stylesheet" href="awesomplete.css" /></code> and <code><script src="awesomplete.js" async></script></code> tags.</p>
|
||||
|
||||
<p>For the autocomplete, you just need an <code><input></code> text field (might work on <code><textarea></code> and elements with <code>contentEditable</code>, but that hasn’t been tested). Add <code>class="awesomplete"</code> for it to be <strong>automatically processed</strong> (you can still specify many options via HTML attributes), otherwise you can instantiate with a few lines of JS code, which allow for more customization.</p>
|
||||
<p>There are many ways <strong>to link an input to a list of suggestions</strong>. The simple example above could have also been made with the following markup, which provides a nice native fallback in case the script doesn’t load:</p>
|
||||
|
||||
<pre class="language-markup"><code><input class="awesomplete" list="mylist" />
|
||||
<datalist id="mylist">
|
||||
<option>Ada</option>
|
||||
<option>Java</option>
|
||||
<option>JavaScript</option>
|
||||
<option>Brainfuck</option>
|
||||
<option>LOLCODE</option>
|
||||
<option>Node.js</option>
|
||||
<option>Ruby on Rails</option>
|
||||
</datalist></code></pre>
|
||||
|
||||
<pre class="language-javascript"><code>// None!</code></pre>
|
||||
|
||||
<p>Or the following, if you don’t want to use a <code><datalist></code>, or if you don’t want to use IDs (since any selector will work in <code>data-list</code>):</p>
|
||||
|
||||
<pre class="language-markup"><code><input class="awesomplete" data-list="#mylist" />
|
||||
<ul id="mylist">
|
||||
<li>Ada</li>
|
||||
<li>Java</li>
|
||||
<li>JavaScript</li>
|
||||
<li>Brainfuck</li>
|
||||
<li>LOLCODE</li>
|
||||
<li>Node.js</li>
|
||||
<li>Ruby on Rails</li>
|
||||
</ul></code></pre>
|
||||
|
||||
<pre class="language-javascript"><code>// None!</code></pre>
|
||||
|
||||
<p>Or the following, if we want to instantiate in JS:</p>
|
||||
|
||||
<pre class="language-markup"><code><input id="myinput" />
|
||||
<ul id="mylist">
|
||||
<li>Ada</li>
|
||||
<li>Java</li>
|
||||
<li>JavaScript</li>
|
||||
<li>Brainfuck</li>
|
||||
<li>LOLCODE</li>
|
||||
<li>Node.js</li>
|
||||
<li>Ruby on Rails</li>
|
||||
</ul></code></pre>
|
||||
<pre class="language-javascript"><code>var input = document.getElementById("myinput");
|
||||
new Awesomplete(input, {list: "#mylist"});</code></pre>
|
||||
|
||||
<p>We can use an <strong>element reference</strong> for the list instead of a selector:</p>
|
||||
|
||||
<pre class="language-markup"><code><input id="myinput" />
|
||||
<ul id="mylist">
|
||||
<li>Ada</li>
|
||||
<li>Java</li>
|
||||
<li>JavaScript</li>
|
||||
<li>Brainfuck</li>
|
||||
<li>LOLCODE</li>
|
||||
<li>Node.js</li>
|
||||
<li>Ruby on Rails</li>
|
||||
</ul></code></pre>
|
||||
<pre class="language-javascript"><code>var input = document.getElementById("myinput");
|
||||
new Awesomplete(input, {list: document.querySelector("#mylist")});</code></pre>
|
||||
|
||||
<p>We can also directly use an <strong>array of strings</strong>:</p>
|
||||
|
||||
<pre class="language-markup"><code><input id="myinput" /></code></pre>
|
||||
<pre class="language-javascript"><code>var input = document.getElementById("myinput");
|
||||
new Awesomplete(input, {
|
||||
list: ["Ada", "Java", "JavaScript", "Brainfuck", "LOLCODE", "Node.js", "Ruby on Rails"]
|
||||
});</code></pre>
|
||||
|
||||
<p>We can even set it (or override it) later and it will just work:</p>
|
||||
|
||||
<pre class="language-markup"><code><input id="myinput" /></code></pre>
|
||||
<pre class="language-javascript"><code>var input = document.getElementById("myinput");
|
||||
var awesomplete = new Awesomplete(input);
|
||||
|
||||
/* ...more code... */
|
||||
|
||||
awesomplete.list = ["Ada", "Java", "JavaScript", "Brainfuck", "LOLCODE", "Node.js", "Ruby on Rails"];</code></pre>
|
||||
|
||||
<p>Suggestions with different <strong>label</strong> and <strong>value</strong> are supported too. The label will be shown in autocompleter and the value will be inserted into the input.</p>
|
||||
|
||||
<pre class="language-markup"><code><input id="myinput" /></code></pre>
|
||||
<pre class="language-javascript"><code>var input = document.getElementById("myinput");
|
||||
|
||||
// Show label but insert value into the input:
|
||||
new Awesomplete(input, {
|
||||
list: [
|
||||
{ label: "Belarus", value: "BY" },
|
||||
{ label: "China", value: "CN" },
|
||||
{ label: "United States", value: "US" }
|
||||
]
|
||||
});
|
||||
|
||||
// Same with arrays:
|
||||
new Awesomplete(input, {
|
||||
list: [
|
||||
[ "Belarus", "BY" ],
|
||||
[ "China", "CN" ],
|
||||
[ "United States", "US" ]
|
||||
]
|
||||
});</code></pre>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="customization">
|
||||
<h1>Customize</h1>
|
||||
|
||||
<p>All settings discussed in this section are settable via either a <code>data-</code> attribute on the <code><input></code> element or a JS property on the second argument of the <code>Awesomplete</code> constructor, like so:</p>
|
||||
|
||||
<pre class="language-javascript"><code>new Awesomplete(inputReference, {
|
||||
minChars: 3,
|
||||
maxItems: 15,
|
||||
...
|
||||
});</code></pre>
|
||||
<p>You can of course combine both HTML attributes and JS properties. <strong>In case of conflict</strong> (e.g. you’ve specified both a <code>data-minchars</code> on the text field and a <code>minChars</code> JS property, <strong>the HTML attribute wins</strong>. You can also use the JS properties to change a parameter <strong>after</strong> the object has been created, in which case the change will apply even if there is a conflicting HTML attribute.</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>JS property</th>
|
||||
<th>HTML attribute</th>
|
||||
<th>Description</th>
|
||||
<th>Value</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>list</code></td>
|
||||
<td><code>data-list</code></td>
|
||||
<td>Where to find the list of suggestions. Described in more detail in the “<a href="#basic-usage">Basic usage</a>” section above.</td>
|
||||
<td><ul>
|
||||
<li>Array of strings</li>
|
||||
<li>HTML element</li>
|
||||
<li>CSS selector (no groups, i.e. no commas)</li>
|
||||
<li>String containing a comma-separated list of items</li>
|
||||
</ul></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>minChars</code></td>
|
||||
<td><code>data-minchars</code></td>
|
||||
<td>Minimum characters the user has to type before the autocomplete popup shows up.</td>
|
||||
<td>Number</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>maxItems</code></td>
|
||||
<td><code>data-maxitems</code></td>
|
||||
<td>Maximum number of suggestions to display.</td>
|
||||
<td>Number</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>autoFirst</code></td>
|
||||
<td><code>data-autofirst</code></td>
|
||||
<td>Should the first element be automatically selected? Demo: <input class="awesomplete" data-autofirst data-list="Ada, Java, JavaScript, Brainfuck, LOLCODE, Node.js, Ruby on Rails" xautofocus /></td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="extensibility">
|
||||
<h1>Extend</h1>
|
||||
<p>The following JS properties do not have equivalent HTML attributes, because their values are functions. They allow you to completely change the way Awesomplete works:</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Description</th>
|
||||
<th>Value</th>
|
||||
<th>Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>filter</code></td>
|
||||
<td>Controls how entries get matched. By default, the input can match anywhere in the string and it’s a case insensitive match.</td>
|
||||
<td>Function that takes two parameters, the first one being the current suggestion text that’s being tested and the second a string with the user’s input it’s matched against. Returns <code>true</code> if the match is successful and <code>false</code> if it is not. For example, to only match strings that <strong>start with the user’s input</strong>, <strong>case sensitive</strong>, we can do this:
|
||||
<pre class="language-javascript"><code>filter: function (text, input) {
|
||||
return text.indexOf(input) === 0;
|
||||
}</code></pre> For case-<strong>in</strong>sensitive matching from the start of the word, there is a predefined filter that you can use, <code class="language-javascript">Awesomplete.FILTER_STARTSWITH</code>
|
||||
</td>
|
||||
<td><code class="language-javascript">Awesomplete.FILTER_CONTAINS</code>: Text can match anywhere, case insensitive.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sort</code></td>
|
||||
<td>Controls how list items are ordered.</td>
|
||||
<td>Sort function (will be passed directly to <code>Array.prototype.sort()</code>) to sort the items after they have been filtered and before they are truncated and converted to HTML elements. If value is <code>false</code>, sorting will be disabled.</td>
|
||||
<td>Sorted by length first, order second.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>item</code></td>
|
||||
<td>Controls how list items are generated.</td>
|
||||
<td>Function that takes two parameters, the first one being the suggestion text and the second one the user’s input and returns a list item.</td>
|
||||
<td>Generates list items with the user’s input highlighted via <code><mark></code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>replace</code></td>
|
||||
<td>Controls how the user’s selection replaces the user’s input. For example, this is useful if you want the selection to only partially replace the user’s input.</td>
|
||||
<td>Function that takes one parameter, the text of the selected option, and is responsible for replacing the current input value with it.
|
||||
</td>
|
||||
<td><pre class="language-javascript"><code>function (text) {
|
||||
this.input.value = text;
|
||||
}</code></pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>data</code></td>
|
||||
<td>Controls suggestions' <code>label</code> and <code>value</code>. This is useful if you have list items in custom format, or want to change list items based on user's input.</td>
|
||||
<td>Function that takes two parameters, the first one being the original list item and the second a string with the user’s input and returns a list item in one of supported by default formats:
|
||||
<ul>
|
||||
<li><code>"JavaScript"</code></li>
|
||||
<li><code>{ label: "JavaScript", value: "JS" }</code></li>
|
||||
<li><code>[ "JavaScript", "JS" ]</code></li>
|
||||
</ul>
|
||||
To <strong>use objects without <code>label</code> or <code>value</code> properties</strong>, e.g. <code>name</code> and <code>id</code> instead, you can do this:
|
||||
<pre class="language-javascript"><code>data: function (item, input) {
|
||||
return { label: item.name, value: item.id };
|
||||
}</code></pre>
|
||||
You can <strong>use any object for <code>label</code> and <code>value</code></strong> and it will be converted to String where necessary:
|
||||
<pre class="language-javascript"><code>list: [ new Date("2015-01-01"), ... ] </code></pre>
|
||||
Original list items as Date objects will be accessible in <code>filter</code>, <code>sort</code>, <code>item</code> and <code>replace</code> functions, but by default we'll just see Date objects converted to strings in autocompleter and the same value will be inserted to the input.
|
||||
<br />
|
||||
We can also <strong>generate list items based on user's input</strong>. See E-mail autocomplete example in <a href="#advanced-examples">Advanced Examples</a> section.
|
||||
</td>
|
||||
<td><code class="language-javascript">Awesomplete.DATA</code>: Identity function which just returns the original list item.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="events">
|
||||
<h1>Events</h1>
|
||||
|
||||
<p>Custom events are thrown in several places and are often cancellable. To avoid conflicts, all custom events are prefixed with <code>awesomplete-</code>.</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>event.preventDefault()?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>awesomplete-select</code></td>
|
||||
<td>The user has made a selection (either via pressing enter or clicking on an item), but it has not been applied yet. Callback will be passed an object with <code>text</code> (selected suggestion) and <code>origin</code> (DOM element) properties.</td>
|
||||
<td>Yes. The selection will not be applied and the popup will not close.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>awesomplete-selectcomplete</code></td>
|
||||
<td>The user has made a selection (either via pressing enter or clicking on an item), and it has been applied. Callback will be passed an object with a <code>text</code> property containing the selected suggestion.</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>awesomplete-open</code></td>
|
||||
<td>The popup just appeared.</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>awesomplete-close</code></td>
|
||||
<td>The popup just closed. Callback will be passed an object with a <code>reason</code> property that indicates why the event was fired. Reasons include <code>"blur"</code>, <code>"esc"</code>, <code>"submit"</code>, <code>"select"</code>, and <code>"nomatches"</code>.</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>awesomplete-highlight</code></td>
|
||||
<td>The highlighted item just changed (in response to pressing an arrow key or via an API call). Callback will be passed an object with a <code>text</code> property containing the highlighted suggestion.</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="api">
|
||||
<h1>API</h1>
|
||||
|
||||
<p>There are several methods on every Awesomplete instance that you can call to customize behavior:</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>open()</code></td>
|
||||
<td>Opens the popup.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>close()</code></td>
|
||||
<td>Closes the popup.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>next()</code></td>
|
||||
<td>Highlights the next item in the popup.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>previous()</code></td>
|
||||
<td>Highlights the previous item in the popup.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>goto(i)</code></td>
|
||||
<td>Highlights the item with index <code>i</code> in the popup (<code>-1</code> to deselect all). Avoid using this directly and try to use <code>next()</code> or <code>previous()</code> instead when possible.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>select()</code></td>
|
||||
<td>Selects the currently highlighted item, replaces the text field’s value with it and closes the popup.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>evaluate()</code></td>
|
||||
<td>Evaluates the current state of the widget and regenerates the list of suggestions or closes the popup if none are available. You need to call it if you dynamically set <code>list</code> while the popup is open.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="advanced-examples">
|
||||
<h1>Advanced Examples</h1>
|
||||
<p>These examples show how powerful Awesomplete’s minimal API can be.</p>
|
||||
|
||||
<section id="email">
|
||||
<h2>E-mail autocomplete</h2>
|
||||
<label>Type an email: <input type="email"></label>
|
||||
<pre class="language-markup"><code><input type="email" /></code></pre>
|
||||
<pre class="language-javascript"><code><script>new Awesomplete('input[type="email"]', {
|
||||
list: ["aol.com", "att.net", "comcast.net", "facebook.com", "gmail.com", "gmx.com", "googlemail.com", "google.com", "hotmail.com", "hotmail.co.uk", "mac.com", "me.com", "mail.com", "msn.com", "live.com", "sbcglobal.net", "verizon.net", "yahoo.com", "yahoo.co.uk"],
|
||||
data: function (text, input) {
|
||||
return input.slice(0, input.indexOf("@")) + "@" + text;
|
||||
},
|
||||
filter: Awesomplete.FILTER_STARTSWITH
|
||||
});</script></code></pre>
|
||||
</section>
|
||||
|
||||
<section id="multiple-values">
|
||||
<h2>Multiple values</h2>
|
||||
<label>Tags (comma separated): <input data-list="CSS, JavaScript, HTML, SVG, ARIA, MathML" data-multiple data-minchars="1" /></label>
|
||||
<pre class="language-markup"><code><input data-list="CSS, JavaScript, HTML, SVG, ARIA, MathML" data-multiple /></code></pre>
|
||||
<pre class="language-javascript"><code><script>new Awesomplete('input[data-multiple]', {
|
||||
filter: function(text, input) {
|
||||
return Awesomplete.FILTER_CONTAINS(text, input.match(/[^,]*$/)[0]);
|
||||
},
|
||||
|
||||
replace: function(text) {
|
||||
var before = this.input.value.match(/^.+,\s*|/)[0];
|
||||
this.input.value = before + text + ", ";
|
||||
}
|
||||
});</script></code></pre>
|
||||
</section>
|
||||
|
||||
<section id="ajax-example">
|
||||
<h2>Ajax example <small>(restcountries.eu api)</small></h2>
|
||||
<label class="">Select French speaking country <input type="text"></label>
|
||||
<pre class="language-javascript"><code><script>var ajax = new XMLHttpRequest();
|
||||
ajax.open("GET", "https://restcountries.eu/rest/v1/lang/fr", true);
|
||||
ajax.onload = function() {
|
||||
var list = JSON.parse(ajax.responseText).map(function(i) { return i.name; });
|
||||
new Awesomplete(document.querySelector("#ajax-example input"),{ list: list });
|
||||
};
|
||||
ajax.send();</script></code></pre>
|
||||
</section>
|
||||
|
||||
<section id="combobox">
|
||||
<h2>Combobox dropdown</h2>
|
||||
<label>Type or click dropdown: <input data-list="CSS, JavaScript, HTML, SVG, ARIA, MathML" class="dropdown-input" /><button class="dropdown-btn" type="button"><span class="caret"></span></button></label>
|
||||
<pre class="language-markup"><code><input data-list="CSS, JavaScript, HTML, SVG, ARIA, MathML" class="dropdown-input" /></code></pre>
|
||||
<pre class="language-javascript"><code><script>var comboplete = new Awesomplete('input.dropdown-input', {
|
||||
minChars: 0,
|
||||
});
|
||||
Awesomplete.$('.dropdown-btn').addEventListener("click", function() {
|
||||
if (comboplete.ul.childNodes.length === 0) {
|
||||
comboplete.minChars = 0;
|
||||
comboplete.evaluate();
|
||||
}
|
||||
else if (comboplete.ul.hasAttribute('hidden')) {
|
||||
comboplete.open();
|
||||
}
|
||||
else {
|
||||
comboplete.close();
|
||||
}
|
||||
});</script></code></pre>
|
||||
</section>
|
||||
|
||||
<section id="download">
|
||||
<h1>Download!</h1>
|
||||
|
||||
<ul>
|
||||
<li><strong><a href="https://github.com/LeaVerou/awesomplete/archive/gh-pages.zip">Download everything as a zip file</a></strong></li>
|
||||
<li><a href="https://github.com/LeaVerou/awesomplete">Fork me on Github</a></li>
|
||||
<li><a href="https://github.com/LeaVerou/awesomplete/issues/new">File a bug</a> </li>
|
||||
<li><a href="https://github.com/LeaVerou/awesomplete/issues/new">Suggest a feature</a> </li>
|
||||
<li><a href="https://github.com/LeaVerou/awesomplete/blob/gh-pages/LICENSE">License: MIT license</a></li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Pull requests are very welcome</strong>, as long as you maintain the code style and ask before adding tons of LOCs to the codebase!</p>
|
||||
</section>
|
||||
|
||||
<footer>Made with ♥ by <a href="http://lea.verou.me">Lea Verou</a> • <a href="http://lea.verou.me/2015/02/awesomplete-2kb-autocomplete-with-zero-dependencies">Read the blog post</a> • <a href="http://shop.oreilly.com/product/0636920031123.do">Buy my book!</a> </footer>
|
||||
|
||||
|
||||
<script src="prism/prism.js" defer></script>
|
||||
|
||||
<iframe src="http://ghbtns.com/github-btn.html?user=leaverou&repo=awesomplete&type=watch&count=true&size=large" height="30" width="170" frameborder="0" scrolling="0" style="width:170px; height: 30px;" allowTransparency="true" class="github-star"></iframe>
|
||||
<a href="https://twitter.com/share" class="twitter-share-button" data-via="LeaVerou" data-size="large">Tweet</a>
|
||||
<script async src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=leaveroume" id="_carbonads_js"></script>
|
||||
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-25106441-4', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +0,0 @@
|
||||
/* global Awesomplete, $:true, $$:true */
|
||||
$ = Awesomplete.$;
|
||||
$$ = Awesomplete.$$;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var nav = $("nav")
|
||||
$$("section > h1").forEach(function (h1) {
|
||||
if (h1.parentNode.id) {
|
||||
$.create("a", {
|
||||
href: "#" + h1.parentNode.id,
|
||||
textContent: h1.textContent.replace(/\(.+?\)/g, ""),
|
||||
inside: nav
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
@ -1,70 +0,0 @@
|
||||
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: ['jasmine', 'jasmine-def', 'fixture'],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'awesomplete.js',
|
||||
'test/specHelper.js',
|
||||
{
|
||||
pattern: 'test/fixtures/**/*.html',
|
||||
watched: true, included: true, served: true
|
||||
},
|
||||
'test/**/*Spec.js'
|
||||
],
|
||||
|
||||
// list of files to exclude
|
||||
exclude: [
|
||||
'**/*.swp'
|
||||
],
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
preprocessors: {
|
||||
'awesomplete.js': ['coverage'],
|
||||
'**/*.html' : ['html2js']
|
||||
},
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ['dots', 'coverage'],
|
||||
coverageReporter: {
|
||||
type: 'lcov',
|
||||
subdir: '.'
|
||||
},
|
||||
// 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: process.env.TRAVIS ? ['ChromeTravisCI'] : ['Chrome'],
|
||||
|
||||
// need this to run Chrome on Travis CI
|
||||
customLaunchers: {
|
||||
ChromeTravisCI: {
|
||||
base: 'Chrome',
|
||||
flags: ['--no-sandbox']
|
||||
}
|
||||
},
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: false
|
||||
});
|
||||
};
|
@ -1,32 +0,0 @@
|
||||
{
|
||||
"name": "awesomplete",
|
||||
"version": "1.1.1",
|
||||
"description": "http://leaverou.github.io/awesomplete/",
|
||||
"main": "awesomplete.js",
|
||||
"scripts": {
|
||||
"test": "karma start --single-run"
|
||||
},
|
||||
"repository": "LeaVerou/awesomplete",
|
||||
"author": "Lea Verou",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/LeaVerou/awesomplete/issues"
|
||||
},
|
||||
"homepage": "https://leaverou.github.io/awesomplete/",
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-header": "^1.7.1",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-sourcemaps": "^1.6.0",
|
||||
"gulp-uglify": "^2.0.0",
|
||||
"jasmine-core": "^2.4.1",
|
||||
"karma": "^0.13.19",
|
||||
"karma-chrome-launcher": "^0.2.2",
|
||||
"karma-coverage": "^0.5.3",
|
||||
"karma-fixture": "^0.2.5",
|
||||
"karma-html2js-preprocessor": "^0.1.0",
|
||||
"karma-jasmine": "^0.3.6",
|
||||
"karma-jasmine-def": "^0.1.0"
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+json */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #a67f59;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+json */
|
||||
var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=_self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=t.util.clone(e[r]));return a;case"Array":return e.map&&e.map(function(e){return t.util.clone(e)})}return e}},languages:{extend:function(e,n){var a=t.util.clone(t.languages[e]);for(var r in n)a[r]=n[r];return a},insertBefore:function(e,n,a,r){r=r||t.languages;var l=r[e];if(2==arguments.length){a=arguments[1];for(var i in a)a.hasOwnProperty(i)&&(l[i]=a[i]);return l}var o={};for(var s in l)if(l.hasOwnProperty(s)){if(s==n)for(var i in a)a.hasOwnProperty(i)&&(o[i]=a[i]);o[s]=l[s]}return t.languages.DFS(t.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=o)}),r[e]=o},DFS:function(e,n,a,r){r=r||{};for(var l in e)e.hasOwnProperty(l)&&(n.call(e,l,e[l],a||l),"Object"!==t.util.type(e[l])||r[e[l]]?"Array"!==t.util.type(e[l])||r[e[l]]||(r[e[l]]=!0,t.languages.DFS(e[l],n,l,r)):(r[e[l]]=!0,t.languages.DFS(e[l],n,null,r)))}},plugins:{},highlightAll:function(e,n){for(var a,r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'),l=0;a=r[l++];)t.highlightElement(a,e===!0,n)},highlightElement:function(n,a,r){for(var l,i,o=n;o&&!e.test(o.className);)o=o.parentNode;o&&(l=(o.className.match(e)||[,""])[1],i=t.languages[l]),n.className=n.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=n.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l);var s=n.textContent,u={element:n,language:l,grammar:i,code:s};if(!s||!i)return t.hooks.run("complete",u),void 0;if(t.hooks.run("before-highlight",u),a&&_self.Worker){var g=new Worker(t.filename);g.onmessage=function(e){u.highlightedCode=e.data,t.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(u.element),t.hooks.run("after-highlight",u),t.hooks.run("complete",u)},g.postMessage(JSON.stringify({language:u.language,code:u.code,immediateClose:!0}))}else u.highlightedCode=t.highlight(u.code,u.grammar,u.language),t.hooks.run("before-insert",u),u.element.innerHTML=u.highlightedCode,r&&r.call(n),t.hooks.run("after-highlight",u),t.hooks.run("complete",u)},highlight:function(e,a,r){var l=t.tokenize(e,a);return n.stringify(t.util.encode(l),r)},tokenize:function(e,n){var a=t.Token,r=[e],l=n.rest;if(l){for(var i in l)n[i]=l[i];delete n.rest}e:for(var i in n)if(n.hasOwnProperty(i)&&n[i]){var o=n[i];o="Array"===t.util.type(o)?o:[o];for(var s=0;s<o.length;++s){var u=o[s],g=u.inside,c=!!u.lookbehind,f=0,h=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var d=r[p];if(r.length>e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),P=[p,1];b&&P.push(b);var A=new a(i,g?t.tokenize(m,g):m,h);P.push(A),w&&P.push(w),Array.prototype.splice.apply(r,P)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var l={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}t.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+"</"+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code,l=n.immediateClose;_self.postMessage(t.highlight(r,t.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
|
||||
Prism.languages.markup={comment:/<!--[\w\W]*?-->/,prolog:/<\?[\w\W]+?\?>/,doctype:/<!DOCTYPE[\w\W]+?>/,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
|
||||
Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<style[\w\W]*?>)[\w\W]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));
|
||||
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
|
||||
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^\/])\/(?!\/)(\[.+?]|\\.|[^\/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<script[\w\W]*?>)[\w\W]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript;
|
||||
Prism.languages.json={property:/".*?"(?=\s*:)/gi,string:/"(?!:)(\\?[^"])*?"(?!:)/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,punctuation:/[{}[\]);,]/g,operator:/:/g,"boolean":/\b(true|false)\b/gi,"null":/\bnull\b/gi},Prism.languages.jsonp=Prism.languages.json;
|
@ -1,292 +0,0 @@
|
||||
body {
|
||||
max-width: 50rem;
|
||||
padding: 1rem;
|
||||
margin: auto;
|
||||
background: hsl(35, 80%, 94%);
|
||||
color: hsl(35, 50%, 20%);
|
||||
text-shadow: 0 1px 1px white;
|
||||
font: 120%/1.6 Baskerville, Palatino Linotype, Palatino, serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #58a;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
section > h1 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: hsl(35, 50%, 40%);
|
||||
font-weight: 600;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: .8em;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
abbr {
|
||||
border-bottom: .1em dotted hsl(40, 80%, 40%);
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
input, button {
|
||||
font: inherit;
|
||||
text-shadow: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: .1em .5em;
|
||||
border-radius: .3em;
|
||||
background: hsl(80, 80%, 80%);
|
||||
background: linear-gradient(hsl(40, 70%, 80%), hsl(40, 70%, 70%));
|
||||
border: 1px solid rgba(0,0,0,.3);
|
||||
box-shadow: 0 1px white inset, 0 .3em .3em -.3em rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
input {
|
||||
width: 12em;
|
||||
padding: .1em .3em;
|
||||
border: 0;
|
||||
border: 1px solid hsl(35, 80%, 60%);
|
||||
background: hsla(0,0%,100%,.2);
|
||||
border-radius: .3em;
|
||||
box-shadow: .05em .1em .3em rgba(0,0,0,.3) inset;
|
||||
}
|
||||
|
||||
@keyframes pulsate {
|
||||
to {
|
||||
box-shadow: .05em .1em .3em rgba(0,0,0,.3) inset, 0 0 .3em .1em #58a;
|
||||
}
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
border: 1px solid #58a;
|
||||
animation: pulsate 2s infinite alternate linear;
|
||||
background: hsla(0,0%,100%,.5);
|
||||
}
|
||||
|
||||
header {
|
||||
max-width: 37rem;
|
||||
margin: 0 auto 2em;
|
||||
text-align: center;
|
||||
font-size: 150%;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
margin: .1em 0;
|
||||
text-align: center;
|
||||
color: hsl(35, 50%, 40%);
|
||||
font-size: 400%;
|
||||
line-height: 1;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
header p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
header p a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.size {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
right: 1em;
|
||||
width: 4em;
|
||||
padding: .8em .6em 1em;
|
||||
background: hsl(40, 80%, 40%);
|
||||
color: hsl(35, 80%, 94%);
|
||||
text-shadow: none;
|
||||
text-align: center;
|
||||
line-height: 1.1;
|
||||
text-indent: -.1em;
|
||||
outline: .1em dotted;
|
||||
outline-offset: -.3em;
|
||||
text-decoration: none;
|
||||
border-radius: .15em;
|
||||
}
|
||||
|
||||
.size:hover {
|
||||
background: #58a;
|
||||
}
|
||||
|
||||
.size strong {
|
||||
display: block;
|
||||
margin-bottom: .1em;
|
||||
font-size: 150%;
|
||||
line-height: 1;
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.size .amp {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
bottom: 0;
|
||||
color: hsla(35, 80%, 94%,.3);
|
||||
font-size: 350%;
|
||||
}
|
||||
|
||||
nav {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
nav a {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 0 .4em;
|
||||
margin: 0 .1em;
|
||||
|
||||
color: hsl(35, 80%, 94%);
|
||||
text-shadow: none;
|
||||
text-decoration: none;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
nav a::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
z-index: -1;
|
||||
border-radius: .2em;
|
||||
background: hsl(40, 80%, 40%);
|
||||
-webkit-transform: skew(-16deg);
|
||||
transform: skew(-16deg);
|
||||
}
|
||||
|
||||
nav a[href="#download"] {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
nav a[href="#download"]::before {
|
||||
background: hsl(65, 85%, 35%);
|
||||
}
|
||||
|
||||
nav a:hover::before {
|
||||
background: #58a;
|
||||
}
|
||||
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: hsl(35, 70%, 88%);
|
||||
font-size: 80%;
|
||||
border-radius: .3em;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: .6em;
|
||||
border-top: 1px solid rgba(0,0,0,.3);
|
||||
margin-top: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
pre {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: .5em;
|
||||
padding: .3em .4em;
|
||||
border-radius: 0 0 .3em .3em;
|
||||
background: hsl(35, 50%, 60%);
|
||||
color: hsl(35, 80%, 90%);
|
||||
text-shadow: none;
|
||||
font: bold 100%/1 Baskerville, Palatino Linotype, Palatino, serif;
|
||||
}
|
||||
|
||||
pre.language-markup::before {
|
||||
content: "HTML";
|
||||
}
|
||||
|
||||
pre.language-javascript::before {
|
||||
content: "JS";
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: .5em;
|
||||
border: 1px solid rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"] {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.github-star {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
left: 1em;
|
||||
}
|
||||
|
||||
#carbonads {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
top: calc(100vh - 15em);
|
||||
right: 1em;
|
||||
max-width: 10em;
|
||||
max-width: -webkit-min-content;
|
||||
max-width: min-content;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
#carbonads a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#carbonads img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#combobox .dropdown-input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
#combobox .dropdown-btn {
|
||||
vertical-align: top;
|
||||
height: 36.5px;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
#combobox .caret {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 2px;
|
||||
vertical-align: middle;
|
||||
border-top: 4px dashed;
|
||||
border-top: 4px solid;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
describe("awesomplete.close", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () { return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] }) });
|
||||
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
this.subject.open();
|
||||
this.subject.next();
|
||||
});
|
||||
|
||||
it("closes completer", function () {
|
||||
this.subject.close();
|
||||
expect(this.subject.ul.hasAttribute("hidden")).toBe(true);
|
||||
});
|
||||
|
||||
it("makes no item selected", function () {
|
||||
this.subject.close();
|
||||
expect(this.subject.index).toBe(-1);
|
||||
});
|
||||
|
||||
it("fires awesomplete-close event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-close");
|
||||
this.subject.close();
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
jasmine.any(document.createEvent("HTMLEvents").constructor)
|
||||
);
|
||||
});
|
||||
|
||||
it("returns early if already closed", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-close");
|
||||
this.subject.close();
|
||||
this.subject.close();
|
||||
|
||||
expect(handler.calls.count()).toBe(1);
|
||||
});
|
||||
});
|
@ -1,96 +0,0 @@
|
||||
describe("awesomplete.evaluate", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
describe("with too short input value", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "i");
|
||||
});
|
||||
|
||||
it("closes completer", function () {
|
||||
spyOn(this.subject, "close");
|
||||
this.subject.evaluate();
|
||||
|
||||
expect(this.subject.close).toHaveBeenCalledWith({
|
||||
reason: "nomatches"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with no items found", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "nosuchitem");
|
||||
});
|
||||
|
||||
it("closes completer", function () {
|
||||
spyOn(this.subject, "close");
|
||||
this.subject.evaluate();
|
||||
|
||||
expect(this.subject.close).toHaveBeenCalledWith({
|
||||
reason: "nomatches"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with some items found", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
});
|
||||
|
||||
it("opens completer", function () {
|
||||
spyOn(this.subject, "open");
|
||||
this.subject.evaluate();
|
||||
|
||||
expect(this.subject.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("fills completer with found items", function () {
|
||||
this.subject.evaluate();
|
||||
expect(this.subject.ul.children.length).toBe(3);
|
||||
});
|
||||
|
||||
it("shows no more than maxItems", function () {
|
||||
this.subject.maxItems = 2;
|
||||
this.subject.evaluate();
|
||||
expect(this.subject.ul.children.length).toBe(2);
|
||||
});
|
||||
|
||||
it("makes no item selected", function () {
|
||||
this.subject.evaluate();
|
||||
expect(this.subject.index).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with minChars: 0", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.minChars = 0;
|
||||
});
|
||||
|
||||
it("opens completer", function () {
|
||||
spyOn(this.subject, "open");
|
||||
this.subject.evaluate();
|
||||
|
||||
expect(this.subject.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("fills completer with all items", function () {
|
||||
this.subject.evaluate();
|
||||
expect(this.subject.ul.children.length).toBe(3);
|
||||
});
|
||||
|
||||
it("shows no more than maxItems", function () {
|
||||
this.subject.maxItems = 2;
|
||||
this.subject.evaluate();
|
||||
expect(this.subject.ul.children.length).toBe(2);
|
||||
});
|
||||
|
||||
it("makes no item selected", function () {
|
||||
this.subject.evaluate();
|
||||
expect(this.subject.index).toBe(-1);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,67 +0,0 @@
|
||||
describe("awesomplete.goto", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
def("lastIndex", function () { return this.subject.ul.children.length - 1 });
|
||||
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
});
|
||||
|
||||
it("clears previous aria-selected", function () {
|
||||
this.subject.goto(0);
|
||||
this.subject.goto(this.lastIndex);
|
||||
|
||||
expect(this.subject.ul.children[0].getAttribute("aria-selected")).toBe("false");
|
||||
});
|
||||
|
||||
it("goes to first item", function () {
|
||||
this.subject.goto(0);
|
||||
expect(this.subject.index).toBe(0);
|
||||
});
|
||||
|
||||
it("goes to last item", function () {
|
||||
this.subject.goto(this.lastIndex);
|
||||
expect(this.subject.index).toBe(this.lastIndex);
|
||||
});
|
||||
|
||||
it("fires awesomplete-highlight event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-highlight");
|
||||
this.subject.goto(1);
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
text: jasmine.objectContaining({ label: "item2", value: "item2" })
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe("with item index > -1", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.goto(0);
|
||||
});
|
||||
|
||||
it("sets aria-selected", function () {
|
||||
expect(this.subject.ul.children[0].getAttribute("aria-selected")).toBe("true");
|
||||
});
|
||||
|
||||
it("updates status", function () {
|
||||
expect(this.subject.status.textContent).toBe("item1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with item index = -1", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.goto(0);
|
||||
this.subject.goto(-1);
|
||||
});
|
||||
|
||||
it("does not update status", function () {
|
||||
expect(this.subject.status.textContent).toBe("item1");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,56 +0,0 @@
|
||||
describe("awesomplete.next", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
def("lastIndex", function () { return this.subject.ul.children.length - 1 });
|
||||
|
||||
describe("without any items found", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "nosuchitem");
|
||||
this.subject.open();
|
||||
});
|
||||
|
||||
it("does not select any item", function () {
|
||||
this.subject.next();
|
||||
expect(this.subject.index).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with some items found", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
this.subject.open();
|
||||
});
|
||||
|
||||
describe("and no item was already selected", function () {
|
||||
it("selects the first item ", function () {
|
||||
this.subject.next();
|
||||
expect(this.subject.index).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and some item was already selected", function () {
|
||||
it("selects the second item", function () {
|
||||
this.subject.goto(0);
|
||||
this.subject.next();
|
||||
expect(this.subject.index).toBe(1);
|
||||
});
|
||||
|
||||
it("selects the last item", function () {
|
||||
this.subject.goto(this.lastIndex - 1);
|
||||
this.subject.next();
|
||||
expect(this.subject.index).toBe(this.lastIndex);
|
||||
});
|
||||
|
||||
it("selects the first item after reaching the end", function () {
|
||||
this.subject.goto(this.lastIndex);
|
||||
this.subject.next();
|
||||
expect(this.subject.index).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
describe("awesomplete.open", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () { return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] }) });
|
||||
|
||||
// Exposes this bug https://github.com/LeaVerou/awesomplete/pull/16740
|
||||
// FIXME better fix is probably required as discussed in PR above
|
||||
xit("fills in the list on creation", function () {
|
||||
$("#plain").value = "ite";
|
||||
this.subject.open();
|
||||
|
||||
expect(this.subject.ul.children.length).toBe(3);
|
||||
});
|
||||
|
||||
it("opens completer", function () {
|
||||
this.subject.open();
|
||||
expect(this.subject.ul.hasAttribute("hidden")).toBe(false);
|
||||
});
|
||||
|
||||
describe("with autoFirst: true", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.autoFirst = true;
|
||||
spyOn(this.subject, "goto");
|
||||
});
|
||||
|
||||
it("selects first item if wasn't seleted before", function () {
|
||||
this.subject.open();
|
||||
|
||||
expect(this.subject.goto).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("does not select any item if was seleted before", function () {
|
||||
this.subject.index = 0;
|
||||
this.subject.open();
|
||||
|
||||
expect(this.subject.goto).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("with autoFirst: false", function () {
|
||||
it("does not select any item", function () {
|
||||
this.subject.autoFirst = false;
|
||||
spyOn(this.subject, "goto");
|
||||
|
||||
this.subject.open();
|
||||
|
||||
expect(this.subject.goto).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("fires awesomplete-open event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-open");
|
||||
|
||||
this.subject.open();
|
||||
|
||||
expect(handler).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
describe("awesomplete.opened", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () { return new Awesomplete("#plain") });
|
||||
|
||||
describe("with newly created completer", function () {
|
||||
it("is false", function () {
|
||||
expect(this.subject.opened).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with opened completer", function () {
|
||||
it("is true", function () {
|
||||
this.subject.open();
|
||||
expect(this.subject.opened).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with closed completer", function () {
|
||||
it("is false", function () {
|
||||
this.subject.close();
|
||||
expect(this.subject.opened).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,56 +0,0 @@
|
||||
describe("awesomplete.previous", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
def("lastIndex", function () { return this.subject.ul.children.length - 1 });
|
||||
|
||||
describe("without any items found", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "nosuchitem");
|
||||
this.subject.open();
|
||||
});
|
||||
|
||||
it("does not select any item", function () {
|
||||
this.subject.previous();
|
||||
expect(this.subject.index).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with some items found", function () {
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
this.subject.open();
|
||||
});
|
||||
|
||||
describe("and no item was already selected", function () {
|
||||
it("selects the last item ", function () {
|
||||
this.subject.previous();
|
||||
expect(this.subject.index).toBe(this.lastIndex);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and some item was already selected", function () {
|
||||
it("selects the second item from the end", function () {
|
||||
this.subject.goto(this.lastIndex);
|
||||
this.subject.previous();
|
||||
expect(this.subject.index).toBe(this.lastIndex - 1);
|
||||
});
|
||||
|
||||
it("selects the first item", function () {
|
||||
this.subject.goto(1);
|
||||
this.subject.previous();
|
||||
expect(this.subject.index).toBe(0);
|
||||
});
|
||||
|
||||
it("selects the last item after reaching the start", function () {
|
||||
this.subject.goto(0);
|
||||
this.subject.previous();
|
||||
expect(this.subject.index).toBe(this.lastIndex);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,132 +0,0 @@
|
||||
describe("awesomplete.select", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
def("lastIndex", function () { return this.subject.ul.children.length - 1 });
|
||||
def("lastLi", function () { return this.subject.ul.children[this.lastIndex] });
|
||||
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
});
|
||||
|
||||
describe("with closed completer", itDoesNotSelectAnyItem);
|
||||
|
||||
describe("with opened completer", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.open();
|
||||
});
|
||||
|
||||
describe("and no current item", itDoesNotSelectAnyItem);
|
||||
|
||||
describe("and current item", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.goto(0);
|
||||
});
|
||||
|
||||
itSelects("item1");
|
||||
});
|
||||
|
||||
describe("and item specified as argument", function () {
|
||||
def("selectArgument", function () { return this.lastLi });
|
||||
|
||||
itSelects("item3");
|
||||
});
|
||||
});
|
||||
|
||||
// Shared behaviors
|
||||
|
||||
function itSelects(expectedTxt) {
|
||||
it("fires awesomplete-select event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-select");
|
||||
this.subject.select(this.selectArgument);
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
text: jasmine.objectContaining({ label: expectedTxt, value: expectedTxt }),
|
||||
origin: this.selectArgument || this.subject.ul.children[0]
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe("and awesomplete-select event was not prevented", function () {
|
||||
beforeEach(function () {
|
||||
$.on(this.subject.input, "awesomplete-select", $.noop);
|
||||
});
|
||||
|
||||
it("changes the input value", function () {
|
||||
this.subject.select(this.selectArgument);
|
||||
expect(this.subject.input.value).toBe(expectedTxt);
|
||||
});
|
||||
|
||||
it("closes completer", function () {
|
||||
spyOn(this.subject, "close");
|
||||
this.subject.select(this.selectArgument);
|
||||
|
||||
expect(this.subject.close).toHaveBeenCalledWith({
|
||||
reason: "select"
|
||||
});
|
||||
});
|
||||
|
||||
it("fires awesomplete-selectcomplete event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-selectcomplete");
|
||||
this.subject.select(this.selectArgument);
|
||||
|
||||
expect(handler).toHaveBeenCalledWith(
|
||||
jasmine.objectContaining({
|
||||
text: jasmine.objectContaining({ label: expectedTxt, value: expectedTxt })
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and awesomplete-select event was prevented", function () {
|
||||
beforeEach(function () {
|
||||
$.on(this.subject.input, "awesomplete-select", function (evt) { evt.preventDefault() });
|
||||
});
|
||||
|
||||
it("does not change the input value", function () {
|
||||
this.subject.select(this.selectArgument);
|
||||
expect(this.subject.input.value).toBe("ite");
|
||||
});
|
||||
|
||||
it("does not close completer", function () {
|
||||
spyOn(this.subject, "close");
|
||||
this.subject.select(this.selectArgument);
|
||||
|
||||
expect(this.subject.close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not fire awesomplete-selectcomplete event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-selectcomplete");
|
||||
this.subject.select(this.selectArgument);
|
||||
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function itDoesNotSelectAnyItem() {
|
||||
it("does not change the input value", function () {
|
||||
this.subject.select();
|
||||
expect(this.subject.input.value).toBe("ite");
|
||||
});
|
||||
|
||||
it("does not fire awesomplete-select event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-select");
|
||||
this.subject.select();
|
||||
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not fire awesomplete-selectcomplete event", function () {
|
||||
var handler = $.spyOnEvent(this.subject.input, "awesomplete-selectcomplete");
|
||||
this.subject.select();
|
||||
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
});
|
@ -1,41 +0,0 @@
|
||||
describe("awesomplete.selected", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
describe("with newly created completer", function () {
|
||||
it("is false", function () {
|
||||
expect(this.subject.selected).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with opened completer", function () {
|
||||
beforeEach(function () {
|
||||
this.subject.open();
|
||||
$.type(this.subject.input, "ite");
|
||||
});
|
||||
|
||||
describe("and no item selected", function () {
|
||||
it("is false", function () {
|
||||
expect(this.subject.selected).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and some item selected", function () {
|
||||
it("is true", function () {
|
||||
this.subject.next();
|
||||
expect(this.subject.selected).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with closed completer", function () {
|
||||
it("is false", function () {
|
||||
this.subject.close();
|
||||
expect(this.subject.selected).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
describe("blur event", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () { return new Awesomplete("#plain") });
|
||||
|
||||
it("closes completer", function () {
|
||||
spyOn(Awesomplete.prototype, "close");
|
||||
$.fire(this.subject.input, "blur");
|
||||
expect(Awesomplete.prototype.close).toHaveBeenCalledWith(
|
||||
{ reason: "blur" },
|
||||
jasmine.any(document.createEvent("HTMLEvents").constructor)
|
||||
);
|
||||
});
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
describe("input event", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () { return new Awesomplete("#plain") });
|
||||
|
||||
it("rebuilds the list", function () {
|
||||
spyOn(Awesomplete.prototype, "evaluate");
|
||||
$.type(this.subject.input, "ite");
|
||||
expect(Awesomplete.prototype.evaluate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,67 +0,0 @@
|
||||
describe("keydown event", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
});
|
||||
|
||||
it("supports enter", function () {
|
||||
this.subject.next();
|
||||
|
||||
spyOn(this.subject, "select");
|
||||
$.keydown(this.subject.input, $.k.ENTER);
|
||||
|
||||
expect(this.subject.select).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("supports escape", function () {
|
||||
spyOn(this.subject, "close");
|
||||
$.keydown(this.subject.input, $.k.ESC);
|
||||
|
||||
expect(this.subject.close).toHaveBeenCalledWith({
|
||||
reason: "esc"
|
||||
});
|
||||
});
|
||||
|
||||
it("supports down arrow", function () {
|
||||
spyOn(this.subject, "next");
|
||||
$.keydown(this.subject.input, $.k.DOWN);
|
||||
|
||||
expect(this.subject.next).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("supports up arrow", function () {
|
||||
spyOn(this.subject, "previous");
|
||||
$.keydown(this.subject.input, $.k.UP);
|
||||
|
||||
expect(this.subject.previous).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("ignores other keys", function() {
|
||||
spyOn(this.subject, "select");
|
||||
spyOn(this.subject, "close");
|
||||
spyOn(this.subject, "next");
|
||||
spyOn(this.subject, "previous");
|
||||
|
||||
$.keydown(this.subject.input, 111);
|
||||
|
||||
expect(this.subject.select).not.toHaveBeenCalled();
|
||||
expect(this.subject.close).not.toHaveBeenCalled();
|
||||
expect(this.subject.next).not.toHaveBeenCalled();
|
||||
expect(this.subject.previous).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does nothing if not opened", function () {
|
||||
this.subject.close();
|
||||
|
||||
spyOn(this.subject, "next");
|
||||
$.keydown(this.subject.input, $.k.DOWN);
|
||||
|
||||
expect(this.subject.next).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,62 +0,0 @@
|
||||
describe("mousedown event", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return new Awesomplete("#plain", { list: ["item1", "item2", "item3"] });
|
||||
});
|
||||
|
||||
def("li", function () { return this.subject.ul.children[1] });
|
||||
|
||||
beforeEach(function () {
|
||||
$.type(this.subject.input, "ite");
|
||||
spyOn(this.subject, "select");
|
||||
});
|
||||
|
||||
describe("with ul target", function () {
|
||||
def("target", function () { return this.subject.ul });
|
||||
|
||||
it("does not select item", function () {
|
||||
$.fire(this.target, "mousedown", { button: 0 });
|
||||
expect(this.subject.select).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("with li target", function () {
|
||||
def("target", function () { return this.li });
|
||||
|
||||
describe("on left click", function () {
|
||||
it("selects item", function () {
|
||||
var event = $.fire(this.target, "mousedown", { button: 0 });
|
||||
expect(this.subject.select).toHaveBeenCalledWith(this.li, this.target);
|
||||
expect(event.defaultPrevented).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("on right click", function () {
|
||||
it("does not select item", function () {
|
||||
$.fire(this.target, "mousedown", { button: 2 });
|
||||
expect(this.subject.select).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with child of li target", function () {
|
||||
def("target", function () { return $("mark", this.li) });
|
||||
|
||||
describe("on left click", function () {
|
||||
it("selects item", function () {
|
||||
var event = $.fire(this.target, "mousedown", { button: 0 });
|
||||
expect(this.subject.select).toHaveBeenCalledWith(this.li, this.target);
|
||||
expect(event.defaultPrevented).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("on right click", function () {
|
||||
it("does not select item", function () {
|
||||
$.fire(this.target, "mousedown", { button: 2 });
|
||||
expect(this.subject.select).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,17 +0,0 @@
|
||||
describe("form submit event", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return new Awesomplete("#inside-form") });
|
||||
|
||||
it("closes completer", function () {
|
||||
spyOn(Awesomplete.prototype, "close");
|
||||
// prevent full page reload in Firefox, which causes tests to stop running
|
||||
$.on(this.subject.input.form, "submit", function (evt) { evt.preventDefault() });
|
||||
$.fire(this.subject.input.form, "submit");
|
||||
expect(Awesomplete.prototype.close).toHaveBeenCalledWith(
|
||||
{ reason: "submit" },
|
||||
jasmine.any(document.createEvent("HTMLEvents").constructor)
|
||||
);
|
||||
});
|
||||
});
|
@ -1,22 +0,0 @@
|
||||
<input id="no-options" class="simple-input" />
|
||||
|
||||
<input id="with-custom-options" data-minchars="4" data-maxitems="8" data-autofirst="true" />
|
||||
|
||||
<input id="with-data-list-inline" data-list="With, Data, List, Inline" />
|
||||
|
||||
<input id="with-data-list" data-list="#data-list" />
|
||||
<ul id="data-list">
|
||||
<li>With</li>
|
||||
<li>Data</li>
|
||||
<li>List</li>
|
||||
</ul>
|
||||
|
||||
<input id="with-list" list="list" />
|
||||
<datalist id="list">
|
||||
<option>With</option>
|
||||
<option>List</option>
|
||||
</datalist>
|
||||
|
||||
<form>
|
||||
<input id="inside-form" />
|
||||
</form>
|
@ -1 +0,0 @@
|
||||
<input id="plain" />
|
@ -1,59 +0,0 @@
|
||||
describe("Awesomplete.$.bind", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return function () { Awesomplete.$.bind(this.element, this.events) };
|
||||
});
|
||||
|
||||
describe("whith invalid element", function () {
|
||||
it("does nothing if element is undefined", function () {
|
||||
this.element = undefined;
|
||||
expect(this.subject).not.toThrow();
|
||||
});
|
||||
|
||||
it("does nothing if element is null", function () {
|
||||
this.element = null;
|
||||
expect(this.subject).not.toThrow();
|
||||
});
|
||||
|
||||
it("does nothing if element is false", function () {
|
||||
this.element = false;
|
||||
expect(this.subject).not.toThrow();
|
||||
});
|
||||
|
||||
it("does nothing if element is 0", function () {
|
||||
this.element = 0;
|
||||
expect(this.subject).not.toThrow();
|
||||
});
|
||||
|
||||
it("does nothing if element is empty string", function () {
|
||||
this.element = "";
|
||||
expect(this.subject).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("with valid element", function () {
|
||||
def("element", function () { return $("#plain") });
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(this.element, "addEventListener");
|
||||
});
|
||||
|
||||
it("adds event listeners for all events", function () {
|
||||
this.events = { click: $.noop, input: $.noop };
|
||||
this.subject();
|
||||
|
||||
expect(this.element.addEventListener).toHaveBeenCalledWith("click", this.events.click);
|
||||
expect(this.element.addEventListener).toHaveBeenCalledWith("input", this.events.input);
|
||||
});
|
||||
|
||||
it("adds single event listener for multiple events", function () {
|
||||
this.events = { "click input": $.noop };
|
||||
this.subject();
|
||||
|
||||
expect(this.element.addEventListener).toHaveBeenCalledWith("click", this.events["click input"]);
|
||||
expect(this.element.addEventListener).toHaveBeenCalledWith("input", this.events["click input"]);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,102 +0,0 @@
|
||||
describe("Awesomplete.$.create", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return Awesomplete.$.create(this.tag, this.options || {}) });
|
||||
|
||||
def("tag", "div");
|
||||
|
||||
it("creates DOM element", function () {
|
||||
expect(this.subject instanceof HTMLElement).toBe(true);
|
||||
});
|
||||
|
||||
describe("with various tag names", function () {
|
||||
it("creates <ul> element", function () {
|
||||
this.tag = "ul";
|
||||
expect(this.subject.tagName).toEqual("UL");
|
||||
});
|
||||
|
||||
it("creates <li> element", function () {
|
||||
this.tag = "li";
|
||||
expect(this.subject.tagName).toEqual("LI");
|
||||
});
|
||||
});
|
||||
|
||||
describe("without options", function () {
|
||||
it("creates element without any attributes", function () {
|
||||
expect(this.subject.attributes.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with simple options", function () {
|
||||
it("assigns properties", function () {
|
||||
this.options = { id: "id1", className: "class-name" };
|
||||
|
||||
expect(this.subject.id).toEqual("id1");
|
||||
expect(this.subject.className).toEqual("class-name");
|
||||
});
|
||||
|
||||
it("assigns attributes", function () {
|
||||
this.options = { attr1: "val1", attr2: "val2" };
|
||||
|
||||
expect(this.subject.getAttribute("attr1")).toEqual("val1");
|
||||
expect(this.subject.getAttribute("attr2")).toEqual("val2");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with option for boolean attribute/property", function () {
|
||||
it("assigns from true value", function () {
|
||||
this.options = { hidden: true };
|
||||
expect(this.subject.hasAttribute("hidden")).toBe(true);
|
||||
});
|
||||
|
||||
it("assigns from truthy value", function () {
|
||||
this.options = { hidden: "hidden" };
|
||||
expect(this.subject.hasAttribute("hidden")).toBe(true);
|
||||
});
|
||||
|
||||
it("assigns from false value", function () {
|
||||
this.options = { hidden: false };
|
||||
expect(this.subject.hasAttribute("hidden")).toBe(false);
|
||||
});
|
||||
|
||||
it("assigns from falsy value", function () {
|
||||
this.options = { hidden: "" };
|
||||
expect(this.subject.hasAttribute("hidden")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with inside: option", function () {
|
||||
it("appends to container by element", function () {
|
||||
this.options = { inside: $("#data-list") };
|
||||
|
||||
expect(this.subject).toEqual(this.options.inside.lastChild);
|
||||
});
|
||||
|
||||
it("appends to container by selector", function () {
|
||||
this.options = { inside: "#data-list" };
|
||||
|
||||
expect(this.subject).toEqual($(this.options.inside).lastChild);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with around: option", function () {
|
||||
it("wraps specified element", function () {
|
||||
this.options = { around: $("#no-options") };
|
||||
|
||||
var originalParent = this.options.around.parentNode;
|
||||
expect(this.subject.parentNode).toEqual(originalParent);
|
||||
|
||||
expect(this.subject.firstChild).toEqual(this.options.around);
|
||||
});
|
||||
|
||||
it("wraps element specified by selector", function () {
|
||||
this.options = { around: "#no-options" };
|
||||
|
||||
var originalParent = $(this.options.around).parentNode;
|
||||
expect(this.subject.parentNode).toEqual(originalParent);
|
||||
|
||||
expect(this.subject.firstChild).toEqual($(this.options.around));
|
||||
});
|
||||
});
|
||||
});
|
@ -1,62 +0,0 @@
|
||||
describe("Awesomplete.$", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return Awesomplete.$(this.expression, this.context) });
|
||||
|
||||
describe("with default context", itFindsElement);
|
||||
|
||||
describe("with custom context", function () {
|
||||
def("context", function () { return fixture.el });
|
||||
|
||||
itFindsElement();
|
||||
});
|
||||
|
||||
describe("with truthy non string expression", function () {
|
||||
it("returns the expression back", function () {
|
||||
this.expression = $("#no-options");
|
||||
expect(this.subject).toBe(this.expression);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with falsy non string expression", function () {
|
||||
it("returns null if expression is undefined", function () {
|
||||
this.expression = undefined;
|
||||
expect(this.subject).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null if expression is null", function () {
|
||||
this.expression = null;
|
||||
expect(this.subject).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null if expression is false", function () {
|
||||
this.expression = false;
|
||||
expect(this.subject).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
// Shared behaviors
|
||||
|
||||
function itFindsElement() {
|
||||
it("returns DOM element", function () {
|
||||
this.expression = "#no-options";
|
||||
expect(this.subject instanceof HTMLElement).toBe(true);
|
||||
});
|
||||
|
||||
it("finds by id", function () {
|
||||
this.expression = "#no-options";
|
||||
expect(this.subject.id).toEqual("no-options");
|
||||
});
|
||||
|
||||
it("finds by class name", function () {
|
||||
this.expression = ".simple-input";
|
||||
expect(this.subject.id).toEqual("no-options");
|
||||
});
|
||||
|
||||
it("finds by tag name", function () {
|
||||
this.expression = "datalist";
|
||||
expect(this.subject.id).toEqual("list");
|
||||
});
|
||||
}
|
||||
});
|
@ -1,49 +0,0 @@
|
||||
describe("Awesomplete.$$", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return Awesomplete.$$(this.expression, this.context) });
|
||||
|
||||
describe("with default context", itFindsAllElements);
|
||||
|
||||
describe("with custom context", function () {
|
||||
def("context", function () { return fixture.el });
|
||||
|
||||
itFindsAllElements();
|
||||
});
|
||||
|
||||
// Shared behaviors
|
||||
|
||||
function itFindsAllElements() {
|
||||
it("returns an array of DOM elements", function () {
|
||||
this.expression = "#no-options";
|
||||
expect(this.subject).toEqual(jasmine.any(Array));
|
||||
expect(this.subject[0] instanceof HTMLElement).toBe(true);
|
||||
});
|
||||
|
||||
it("finds all elements", function () {
|
||||
this.expression = "input";
|
||||
expect(this.subject.length).toEqual($$("input").length);
|
||||
});
|
||||
|
||||
it("finds DOM element", function () {
|
||||
this.expression = "#no-options";
|
||||
expect(this.subject[0] instanceof HTMLElement).toBe(true);
|
||||
});
|
||||
|
||||
it("finds by id", function () {
|
||||
this.expression = "#no-options";
|
||||
expect(this.subject[0].id).toEqual("no-options");
|
||||
});
|
||||
|
||||
it("finds by class name", function () {
|
||||
this.expression = ".simple-input";
|
||||
expect(this.subject[0].id).toEqual("no-options");
|
||||
});
|
||||
|
||||
it("finds by tag name", function () {
|
||||
this.expression = "datalist";
|
||||
expect(this.subject[0].id).toEqual("list");
|
||||
});
|
||||
}
|
||||
});
|
@ -1,60 +0,0 @@
|
||||
describe("Awesomplete.$.fire", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () {
|
||||
return Awesomplete.$.fire.bind(Awesomplete.$, this.element);
|
||||
});
|
||||
|
||||
def("element", function () { return $("#plain") });
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(this.element, "dispatchEvent");
|
||||
});
|
||||
|
||||
it("fires event once", function () {
|
||||
this.subject("click");
|
||||
expect(this.element.dispatchEvent.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
describe("fires different event types", function () {
|
||||
it("fires click event", function () {
|
||||
this.subject("click");
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining({ type: "click" }));
|
||||
});
|
||||
|
||||
it("fires input event", function () {
|
||||
this.subject("input");
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining({ type: "input" }));
|
||||
});
|
||||
});
|
||||
|
||||
describe("sets event properties", function () {
|
||||
it("makes cancelable event", function () {
|
||||
this.subject("click");
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining({ cancelable: true }));
|
||||
});
|
||||
|
||||
it("can't make non cancelable event", function () {
|
||||
this.subject("click", { cancelable: false });
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining({ cancelable: true }));
|
||||
});
|
||||
|
||||
it("makes event that bubbles", function () {
|
||||
this.subject("click");
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining({ bubbles: true }));
|
||||
});
|
||||
|
||||
it("can't make event that does not bubble", function () {
|
||||
this.subject("click", { bubbles: false });
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining({ bubbles: true }));
|
||||
});
|
||||
|
||||
it("sets properties on the event", function () {
|
||||
var properties = { text: "hello", preventDefault: $.noop };
|
||||
|
||||
this.subject("click", properties);
|
||||
expect(this.element.dispatchEvent).toHaveBeenCalledWith(jasmine.objectContaining(properties));
|
||||
});
|
||||
});
|
||||
});
|
@ -1,38 +0,0 @@
|
||||
describe("Awesomplete.$.regExpEscape", function () {
|
||||
|
||||
subject(function () { return Awesomplete.$.regExpEscape(this.str) });
|
||||
|
||||
describe("with regular expression special characters", function () {
|
||||
it("escapes backslashes", function () {
|
||||
this.str = "\\";
|
||||
expect(this.subject).toBe("\\\\");
|
||||
});
|
||||
|
||||
it("escapes brackets, braces and parentheses", function () {
|
||||
this.str = "[]{}()";
|
||||
expect(this.subject).toBe("\\[\\]\\{\\}\\(\\)");
|
||||
});
|
||||
|
||||
it("escapes other special characters", function () {
|
||||
this.str = "-^$*+?.|";
|
||||
expect(this.subject).toBe("\\-\\^\\$\\*\\+\\?\\.\\|");
|
||||
});
|
||||
|
||||
it("escapes the whole string", function () {
|
||||
this.str = "**";
|
||||
expect(this.subject).toBe("\\*\\*");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with plain characters", function () {
|
||||
it("does not escape letters", function () {
|
||||
this.str = "abcdefjhijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ";
|
||||
expect(this.subject).toBe(this.str);
|
||||
});
|
||||
|
||||
it("does not escape numbers", function () {
|
||||
this.str = "0123456789";
|
||||
expect(this.subject).toBe(this.str);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,60 +0,0 @@
|
||||
describe("Html modifications", function () {
|
||||
|
||||
$.fixture("plain");
|
||||
|
||||
subject(function () { return new Awesomplete("#plain") });
|
||||
|
||||
it("binds to correct input", function () {
|
||||
expect(this.subject.input instanceof HTMLElement).toBe(true);
|
||||
expect(this.subject.input.id).toBe("plain");
|
||||
});
|
||||
|
||||
it("turns native autocompleter off", function () {
|
||||
expect(this.subject.input.getAttribute("autocomplete")).toBe("off");
|
||||
});
|
||||
|
||||
describe("HTML tweaks", function () {
|
||||
it("creates container", function () {
|
||||
expect(this.subject.container instanceof HTMLElement).toBe(true);
|
||||
expect(this.subject.container.className).toBe("awesomplete");
|
||||
});
|
||||
|
||||
it("places input inside container", function () {
|
||||
expect(this.subject.input.parentNode).toBe(this.subject.container);
|
||||
});
|
||||
|
||||
it("creates list", function () {
|
||||
expect(this.subject.ul instanceof HTMLElement).toBe(true);
|
||||
expect(this.subject.ul.tagName).toBe("UL");
|
||||
});
|
||||
|
||||
it("puts list inside container", function () {
|
||||
expect(this.subject.ul.parentNode).toBe(this.subject.container);
|
||||
});
|
||||
|
||||
it("hides list", function () {
|
||||
expect(this.subject.ul.hasAttribute("hidden")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ARIA support", function () {
|
||||
it("makes input accessible", function () {
|
||||
expect(this.subject.input.getAttribute("aria-autocomplete")).toBe("list");
|
||||
});
|
||||
|
||||
it("creates status", function () {
|
||||
expect(this.subject.status instanceof HTMLElement).toBe(true);
|
||||
expect(this.subject.status.getAttribute("role")).toBe("status");
|
||||
expect(this.subject.status.getAttribute("aria-live")).toBe("assertive");
|
||||
expect(this.subject.status.getAttribute("aria-relevant")).toBe("additions");
|
||||
});
|
||||
|
||||
it("puts status inside container", function () {
|
||||
expect(this.subject.status.parentNode).toBe(this.subject.container);
|
||||
});
|
||||
|
||||
it("hides status", function () {
|
||||
expect(this.subject.status.className).toBe("visually-hidden");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,121 +0,0 @@
|
||||
describe("Awesomplete list", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return new Awesomplete(this.element, this.options) });
|
||||
|
||||
def("element", "#no-options");
|
||||
|
||||
it("is empty if not provided", function () {
|
||||
expect(this.subject._list).toEqual([]);
|
||||
});
|
||||
|
||||
describe("setter", function () {
|
||||
it("assigns from array", function () {
|
||||
this.subject.list = [ "From", "Array" ];
|
||||
expect(this.subject._list).toEqual([ "From", "Array" ]);
|
||||
});
|
||||
|
||||
it("assigns from comma separated list", function () {
|
||||
this.subject.list = "From, Inline, List";
|
||||
expect(this.subject._list).toEqual([ "From", "Inline", "List" ]);
|
||||
});
|
||||
|
||||
it("assigns from element specified by selector", function () {
|
||||
this.subject.list = "#data-list";
|
||||
expect(this.subject._list).toEqual([
|
||||
{ label: "With", value: "With" },
|
||||
{ label: "Data", value: "Data" },
|
||||
{ label: "List", value: "List" }
|
||||
]);
|
||||
});
|
||||
|
||||
it("assigns from element", function () {
|
||||
this.subject.list = $("#data-list");
|
||||
expect(this.subject._list).toEqual([
|
||||
{ label: "With", value: "With" },
|
||||
{ label: "Data", value: "Data" },
|
||||
{ label: "List", value: "List" }
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not assigns from not found list", function () {
|
||||
this.subject.list = "#nosuchlist";
|
||||
expect(this.subject._list).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not assigns from empty list", function () {
|
||||
this.subject.list = "#empty-list";
|
||||
expect(this.subject._list).toEqual([]);
|
||||
});
|
||||
|
||||
describe("with active input", function() {
|
||||
beforeEach(function() {
|
||||
this.subject.input.focus();
|
||||
});
|
||||
|
||||
it("evaluates completer", function() {
|
||||
spyOn(this.subject, "evaluate");
|
||||
this.subject.list = "#data-list";
|
||||
|
||||
expect(this.subject.evaluate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("constructor option", function () {
|
||||
it("assigns from array", function () {
|
||||
this.options = { list: [ "From", "Array" ] };
|
||||
expect(this.subject._list).toEqual([ "From", "Array" ]);
|
||||
});
|
||||
|
||||
it("assigns from comma separated list", function () {
|
||||
this.options = { list: "From, Inline, List" };
|
||||
expect(this.subject._list).toEqual([ "From", "Inline", "List" ]);
|
||||
});
|
||||
|
||||
it("assigns from element specified by selector", function () {
|
||||
this.options = { list: "#data-list" };
|
||||
expect(this.subject._list).toEqual([
|
||||
{ label: "With", value: "With" },
|
||||
{ label: "Data", value: "Data" },
|
||||
{ label: "List", value: "List" }
|
||||
]);
|
||||
});
|
||||
|
||||
it("assigns from list specified by element", function () {
|
||||
this.options = { list: $("#data-list") };
|
||||
expect(this.subject._list).toEqual([
|
||||
{ label: "With", value: "With" },
|
||||
{ label: "Data", value: "Data" },
|
||||
{ label: "List", value: "List" }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("data-list html attribute", function () {
|
||||
it("assigns from comma separated list", function () {
|
||||
this.element = "#with-data-list-inline";
|
||||
expect(this.subject._list).toEqual(["With", "Data", "List", "Inline"]);
|
||||
});
|
||||
|
||||
it("assigns from element referenced by selector", function () {
|
||||
this.element = "#with-data-list";
|
||||
expect(this.subject._list).toEqual([
|
||||
{ label: "With", value: "With" },
|
||||
{ label: "Data", value: "Data" },
|
||||
{ label: "List", value: "List" }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("list html attribute", function () {
|
||||
it("assigns from element referenced by id", function () {
|
||||
this.element = "#with-list";
|
||||
expect(this.subject._list).toEqual([
|
||||
{ label: "With", value: "With" },
|
||||
{ label: "List", value: "List" }
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,80 +0,0 @@
|
||||
describe("Constructor options", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return new Awesomplete(this.element, this.options) });
|
||||
|
||||
describe("with default options", function () {
|
||||
def("element", "#with-data-list");
|
||||
|
||||
it("requires minimum 2 chars to open completer", function () {
|
||||
expect(this.subject.minChars).toBe(2);
|
||||
});
|
||||
|
||||
it("shows 10 items in completer", function () {
|
||||
expect(this.subject.maxItems).toBe(10);
|
||||
});
|
||||
|
||||
it("does not select the first ocurrence automatically" , function () {
|
||||
expect(this.subject.autoFirst).toBe(false);
|
||||
});
|
||||
|
||||
it("modifies list item with DATA", function () {
|
||||
expect(this.subject.data).toBe(Awesomplete.DATA);
|
||||
});
|
||||
|
||||
it("filters with FILTER_CONTAINS", function () {
|
||||
expect(this.subject.filter).toBe(Awesomplete.FILTER_CONTAINS);
|
||||
});
|
||||
|
||||
it("orders with SORT_BYLENGTH", function () {
|
||||
expect(this.subject.sort).toBe(Awesomplete.SORT_BYLENGTH);
|
||||
});
|
||||
|
||||
it("creates item with ITEM", function () {
|
||||
expect(this.subject.item).toEqual(Awesomplete.ITEM);
|
||||
});
|
||||
|
||||
it("replaces input value with REPLACE", function () {
|
||||
expect(this.subject.replace).toEqual(Awesomplete.REPLACE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with custom options in constructor", function () {
|
||||
def("element", "#with-data-list");
|
||||
def("options", function () {
|
||||
return {
|
||||
minChars: 3,
|
||||
maxItems: 9,
|
||||
autoFirst: true,
|
||||
filter: $.noop,
|
||||
sort: $.noop,
|
||||
item: $.noop,
|
||||
replace: $.noop
|
||||
};
|
||||
});
|
||||
|
||||
it("overrides simple default options", function () {
|
||||
expect(this.subject.minChars).toBe(3);
|
||||
expect(this.subject.maxItems).toBe(9);
|
||||
expect(this.subject.autoFirst).toBe(true);
|
||||
});
|
||||
|
||||
it("overrides default functions", function () {
|
||||
expect(this.subject.filter).toBe(this.options.filter);
|
||||
expect(this.subject.sort).toBe(this.options.sort);
|
||||
expect(this.subject.item).toBe(this.options.item);
|
||||
expect(this.subject.replace).toBe(this.options.replace);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with custom options in data-* attributes", function () {
|
||||
def("element", "#with-custom-options");
|
||||
|
||||
it("overrides simple default options", function () {
|
||||
expect(this.subject.minChars).toBe(4);
|
||||
expect(this.subject.maxItems).toBe(8);
|
||||
expect(this.subject.autoFirst).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,69 +0,0 @@
|
||||
fixture.setBase("test/fixtures");
|
||||
|
||||
// finds DOM elements in tests
|
||||
function $ (str, context) {
|
||||
return (context || fixture.el).querySelector(str);
|
||||
}
|
||||
|
||||
function $$ (str, context) {
|
||||
return (context || fixture.el).querySelectorAll(str);
|
||||
}
|
||||
|
||||
// bundled fixture load/cleanup
|
||||
$.fixture = function (fixtureName) {
|
||||
beforeEach(function () {
|
||||
// Awesomplete probably needs to cleanup this by itself
|
||||
try { Awesomplete.all = []; } catch(e) {};
|
||||
fixture.load(fixtureName + ".html");
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
fixture.cleanup();
|
||||
});
|
||||
};
|
||||
|
||||
// spy to check if event was fired or not
|
||||
$.spyOnEvent = function (target, type) {
|
||||
var handler = jasmine.createSpy(type);
|
||||
$.on(target, type, handler);
|
||||
return handler;
|
||||
};
|
||||
|
||||
$.on = function (target, type, callback) {
|
||||
target.addEventListener(type, callback);
|
||||
};
|
||||
|
||||
$.fire = function (target, type, properties) {
|
||||
var evt = document.createEvent("HTMLEvents");
|
||||
evt.initEvent(type, true, true );
|
||||
for (var j in properties) {
|
||||
evt[j] = properties[j];
|
||||
}
|
||||
target.dispatchEvent(evt);
|
||||
return evt;
|
||||
};
|
||||
|
||||
// simulates text input (very simple, only "input" event is fired)
|
||||
$.type = function (input, text) {
|
||||
input.focus();
|
||||
input.value = text;
|
||||
return $.fire(input, "input");
|
||||
};
|
||||
|
||||
// simulates keydown events
|
||||
$.keydown = function (target, keyCode) {
|
||||
return $.fire(target, "keydown", { keyCode: keyCode });
|
||||
};
|
||||
$.k = {
|
||||
ENTER: 13,
|
||||
ESC: 27,
|
||||
DOWN: 40,
|
||||
UP: 38
|
||||
};
|
||||
|
||||
// $.noop returns a new empty function each time it's being called
|
||||
Object.defineProperty($, "noop", {
|
||||
get: function () {
|
||||
return function noop () {}
|
||||
}
|
||||
});
|
@ -1,21 +0,0 @@
|
||||
describe("Awesomplete.all", function () {
|
||||
|
||||
$.fixture("options");
|
||||
|
||||
subject(function () { return Awesomplete.all });
|
||||
|
||||
it("is empty initially", function () {
|
||||
expect(this.subject.length).toBe(0);
|
||||
});
|
||||
|
||||
it("keeps a list of created instances", function () {
|
||||
var first = new Awesomplete("#with-data-list-inline");
|
||||
expect(this.subject.length).toBe(1);
|
||||
expect(this.subject).toContain(first);
|
||||
|
||||
var second = new Awesomplete("#with-data-list");
|
||||
expect(this.subject.length).toBe(2);
|
||||
expect(this.subject).toContain(first);
|
||||
expect(this.subject).toContain(second);
|
||||
});
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
describe("Awesomplete.DATA", function () {
|
||||
|
||||
subject(function () { return Awesomplete.DATA(this.item) });
|
||||
|
||||
it("returns original String", function () {
|
||||
this.item = "JavaScript";
|
||||
expect(this.subject).toEqual("JavaScript");
|
||||
});
|
||||
|
||||
it("returns original Object", function () {
|
||||
this.item = { label: "JavaScript", value: "JS" };
|
||||
expect(this.subject).toEqual({ label: "JavaScript", value: "JS" });
|
||||
});
|
||||
|
||||
it("returns original Array", function () {
|
||||
this.item = [ "JavaScript", "JS" ];
|
||||
expect(this.subject).toEqual([ "JavaScript", "JS" ]);
|
||||
});
|
||||
});
|
@ -1,56 +0,0 @@
|
||||
describe("Awesomplete.FILTER_CONTAINS", function () {
|
||||
|
||||
subject(function () { return Awesomplete.FILTER_CONTAINS });
|
||||
|
||||
describe("search in a plain string", function () {
|
||||
it("matches at the start", function () {
|
||||
expect(this.subject("Hello world", "Hello")).toBe(true);
|
||||
});
|
||||
|
||||
it("matches in the middle", function () {
|
||||
expect(this.subject("Ticket to the moon", "to the")).toBe(true);
|
||||
});
|
||||
|
||||
it("matches at the end", function () {
|
||||
expect(this.subject("This is the end", "end")).toBe(true);
|
||||
});
|
||||
|
||||
it("performs case insensitive match", function () {
|
||||
expect(this.subject("Hey You", "HEY YOU")).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores whitespaces around the search value", function () {
|
||||
expect(this.subject("Watch this", " Watch ")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match if substring is not found", function () {
|
||||
expect(this.subject("No", "way")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("search in string with special RegExp chars", function () {
|
||||
it("matches at the start", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "[^j(a)v?a-")).toBe(true);
|
||||
});
|
||||
|
||||
it("matches in the middle", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "sc|ri\\p+t*")).toBe(true);
|
||||
});
|
||||
|
||||
it("matches at the end", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "{.$}")).toBe(true);
|
||||
});
|
||||
|
||||
it("performs case insensitive match", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "[^J(A)V?A-SC|RI\\P+T*]{.$}")).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores whitespaces around the search value", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", " [^j(a)v?a- ")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match if substring is not found", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "no way")).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,56 +0,0 @@
|
||||
describe("Awesomplete.FILTER_STARTSWITH", function () {
|
||||
|
||||
subject(function () { return Awesomplete.FILTER_STARTSWITH });
|
||||
|
||||
describe("search in plain string", function () {
|
||||
it("matches at the start", function () {
|
||||
expect(this.subject("Hello world", "Hello")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match in the middle", function () {
|
||||
expect(this.subject("Ticket to the moon", "to the")).toBe(false);
|
||||
});
|
||||
|
||||
it("does not match at the end", function () {
|
||||
expect(this.subject("This is the end", "end")).toBe(false);
|
||||
});
|
||||
|
||||
it("performs case insensitive match", function () {
|
||||
expect(this.subject("Hey You", "HEY YOU")).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores whitespaces around the search value", function () {
|
||||
expect(this.subject("Watch this", " Watch ")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match if substring is not found", function () {
|
||||
expect(this.subject("No", "way")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("search in string with special RegExp chars", function () {
|
||||
it("matches at the start", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "[^j(a)v?a-")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match in the middle", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "sc|ri\\p+t*")).toBe(false);
|
||||
});
|
||||
|
||||
it("does not match at the end", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "{.$}")).toBe(false);
|
||||
});
|
||||
|
||||
it("performs case insensitive match", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "[^J(A)V?A-SC|RI\\P+T*]{.$}")).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores whitespaces around the search value", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", " [^j(a)v?a- ")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match if substring is not found", function () {
|
||||
expect(this.subject("[^j(a)v?a-sc|ri\\p+t*]{.$}", "no way")).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,58 +0,0 @@
|
||||
describe("Awesomplete.ITEM", function () {
|
||||
|
||||
subject(function () { return Awesomplete.ITEM });
|
||||
|
||||
def("element", function () { return this.subject("JavaScript", this.input || "") });
|
||||
|
||||
it("creates DOM element", function () {
|
||||
expect(this.element instanceof HTMLElement).toBe(true);
|
||||
});
|
||||
|
||||
it("creates LI element", function () {
|
||||
expect(this.element.tagName).toBe("LI");
|
||||
});
|
||||
|
||||
it("sets aria-selected to false", function () {
|
||||
expect(this.element.getAttribute("aria-selected")).toBe("false");
|
||||
});
|
||||
|
||||
describe("with matched input", function () {
|
||||
def("input", "jav");
|
||||
|
||||
it("marks the match", function () {
|
||||
expect(this.element.innerHTML).toBe("<mark>Jav</mark>aScript");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with multiple matches", function () {
|
||||
def("input", "a");
|
||||
|
||||
it("marks all matches", function () {
|
||||
expect(this.element.innerHTML).toBe("J<mark>a</mark>v<mark>a</mark>Script");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with no match", function () {
|
||||
def("input", "foo");
|
||||
|
||||
it("does not mark anything", function () {
|
||||
expect(this.element.innerHTML).toBe("JavaScript");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with empty input", function () {
|
||||
def("input", "");
|
||||
|
||||
it("does not mark anything", function () {
|
||||
expect(this.element.innerHTML).toBe("JavaScript");
|
||||
});
|
||||
});
|
||||
|
||||
describe("with space input", function () {
|
||||
def("input", " ");
|
||||
|
||||
it("does not mark anything", function () {
|
||||
expect(this.element.innerHTML).toBe("JavaScript");
|
||||
});
|
||||
});
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
describe("Awesomplete.REPLACE", function () {
|
||||
|
||||
subject(function () { return Awesomplete.REPLACE });
|
||||
|
||||
def("instance", function() { return { input: { value: "initial" } } });
|
||||
|
||||
it("replaces input value", function () {
|
||||
this.subject.call(this.instance, { value: "JavaScript" });
|
||||
expect(this.instance.input.value).toBe("JavaScript");
|
||||
});
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
describe("Awesomplete.SORT_BYLENGTH", function () {
|
||||
|
||||
subject(function () { return Awesomplete.SORT_BYLENGTH });
|
||||
|
||||
describe("with strings of different length", function () {
|
||||
it("returns negative number if the first string is shorter", function () {
|
||||
expect(this.subject("a", "aa")).toBe(-1);
|
||||
expect(this.subject("a", "bb")).toBe(-1);
|
||||
expect(this.subject("b", "aa")).toBe(-1);
|
||||
|
||||
expect(this.subject("a", "aaa")).toBe(-2);
|
||||
expect(this.subject("a", "bbb")).toBe(-2);
|
||||
expect(this.subject("b", "aaa")).toBe(-2);
|
||||
});
|
||||
|
||||
it("returns positive number if the first string is longer", function () {
|
||||
expect(this.subject("aa", "a")).toBe(1);
|
||||
expect(this.subject("bb", "a")).toBe(1);
|
||||
expect(this.subject("aa", "b")).toBe(1);
|
||||
|
||||
expect(this.subject("aaa", "a")).toBe(2);
|
||||
expect(this.subject("bbb", "a")).toBe(2);
|
||||
expect(this.subject("aaa", "b")).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with strings of the same length", function () {
|
||||
it("returns -1 if the first string < second string", function () {
|
||||
expect(this.subject("a", "b")).toBe(-1);
|
||||
expect(this.subject("aa", "bb")).toBe(-1);
|
||||
expect(this.subject("aaa", "bbb")).toBe(-1);
|
||||
});
|
||||
|
||||
it("returns 1 if the first string > second string", function () {
|
||||
expect(this.subject("b", "a")).toBe(1);
|
||||
expect(this.subject("bb", "aa")).toBe(1);
|
||||
expect(this.subject("bbb", "aaa")).toBe(1);
|
||||
});
|
||||
|
||||
// FIXME SORT_BYLENGTH should probably return 0 like classic string comparison
|
||||
it("returns 1 if the first string == second string", function () {
|
||||
expect(this.subject("a", "a")).toBe(1);
|
||||
expect(this.subject("aa", "aa")).toBe(1);
|
||||
expect(this.subject("aaa", "aaa")).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,104 +0,0 @@
|
||||
.awesomplete [hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.awesomplete .visually-hidden {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.awesomplete > input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.awesomplete > ul {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.awesomplete > ul:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.awesomplete > ul {
|
||||
border-radius: .3em;
|
||||
margin: .2em 0 0;
|
||||
background: hsla(0,0%,100%,.9);
|
||||
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
|
||||
border: 1px solid rgba(0,0,0,.3);
|
||||
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
@supports (transform: scale(0)) {
|
||||
.awesomplete > ul {
|
||||
transition: .3s cubic-bezier(.4,.2,.5,1.4);
|
||||
transform-origin: 1.43em -.43em;
|
||||
}
|
||||
|
||||
.awesomplete > ul[hidden],
|
||||
.awesomplete > ul:empty {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
display: block;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pointer */
|
||||
.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0; height: 0;
|
||||
padding: .4em;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.awesomplete > ul > li {
|
||||
position: relative;
|
||||
padding: .2em .5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.awesomplete > ul > li:hover {
|
||||
background: hsl(200, 40%, 80%);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.awesomplete > ul > li[aria-selected="true"] {
|
||||
background: hsl(205, 40%, 40%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.awesomplete mark {
|
||||
background: hsl(65, 100%, 50%);
|
||||
}
|
||||
|
||||
.awesomplete li:hover mark {
|
||||
background: hsl(68, 100%, 41%);
|
||||
}
|
||||
|
||||
.awesomplete li[aria-selected="true"] mark {
|
||||
background: hsl(86, 100%, 21%);
|
||||
color: inherit;
|
||||
}
|
||||
/*# sourceMappingURL=awesomplete.css.map */
|
3
share/static/awesomplete.min.js
vendored
3
share/static/awesomplete.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user