datalist safari

parent ad35244e
<?php
$servername = "localhost";
$username = "sec_user";
//$username = "root";
$password = "5Qn6g2je6WkF7FX6CcBhAzUf";
//$password = "PkJXPQFykKLmS3cWhqmZKNYE";
$dbname = "Escuelas";
// Create connection
......
......@@ -226,7 +226,7 @@ $conn->close();*/
}
</script>
<script type="text/javascript" src="js/datalist-polyfill.js"></script>
</body>
</html>
---
duplication:
enabled: true
exclude_paths:
- 'tests/functional/dist/**'
exclude_paths:
- 'tests/functional/src/**'
- '*.min.js'
# For more information about the properties used in
# this file, please see the EditorConfig documentation:
# https://editorconfig.org/
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.js]
max_line_length = 80
quote_type = single
[package.json]
# The indent size used in the `package.json` file cannot be changed
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
indent_size = 2
indent_style = space
node_modules/
\ No newline at end of file
dependency_scanning:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
allow_failure: true
services:
- docker:stable-dind
script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--env DEP_SCAN_DISABLE_REMOTE_CHECKS="${DEP_SCAN_DISABLE_REMOTE_CHECKS:-false}"
--volume "$PWD:/code"
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
artifacts:
paths: [gl-dependency-scanning-report.json]
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Changed
- Safari TP seems to support the `datalist` element at least basically. Yeah !!! Exciting news! I'm planning to release a new major version soon to both cheer as well as accommodate their implementation.
## [1.23.3] - 2019-01-28
### Changed
- update xo to version 0.24.0
### Fixed
- No substring matching for multiple emailadress suggestions in IE10+ and EDGE / #GH-54
- EDGE: Incorrect handling of non-text input fields / #GH-55
- IE10: Changes by #39 break script execution due to usage of .dataset / #GH-56
- Some simple corrections, like e.g. removing incorrectly set `multiple` attributes
## [1.23.2] - 2019-01-08
### Fixed
- Prevent the form to be submitted on selecting a value via ENTER key within the select / #GH-51
## [1.23.1] - 2019-01-07
### Fixed
- JavaScript bug in IE9 and corrected the handling of the browsers towards IE10+ / #GH-50
## [1.23.0] - 2019-01-05
### Added
- Microsoft EDGE / datalist popups get "emptied" when receiving focus via tabbing / #GH-49
### Changed
- Updated webdriver.io testing framework to version 5
- Updated some aspects within the `README` file as well as announced some upcoming bigger changes regarding and to cheer the recognized basic support of `datalist` elements within Apple Safari browser.
- Refactoring to prevent a „Function has a complexity of 21.“
- Some simple reformatting of the code according to prettier
## [1.22.2] - 2018-11-03
### Changed
- Added comment regarding the structure of the HTML code / #GH-44 & #GH-45
### Fixed
- Preventing a JS error on no `type`-attribute being provided for the `input`-element / #GH-45
## [1.22.1] - 2018-08-27
### Fixed
- Escaping the user inputs value as doublequotes wouldn't work on the newly added IE11+ and EDGE functionality / #GH-40
## [1.22.0] - 2018-08-27
### Added
- Substring matching for the suggestions on both the `value` and the `text` values / #GH-36
## [1.21.2] - 2018-08-11
### Added
- Finally integrated the test regarding clicking the `select`s `option` elements, as this was actually previously prevented by the other bug fixed in the previous release
### Fixed
- Corrected the code style of the README file again, as this got incorrectly reformatted previously
## [1.21.1] - 2018-08-09
### Fixed
- Suggestions aren‘t working onClick any more (#GH-35)
## [1.21.0] - 2018-08-08
### Added
- Added testcases and added [crossbrowsertesting](https://crossbrowsertesting.com/) logo to README
### Changed
- increased specificity on one of the selectors according the usage in other parts of the code
- Check for correct element on the `input`s event delegation
- Simplified some code parts
- Further aligned the naming conventions
- code and complexity simplifications
### Fixed
- Arrow keys (top&down) disturb the general browser behaviour on number fields (#GH-32)
## [1.20.1] - 2018-07-20
### Changed
- Code simplifications
### Fixed
- Suggestions aren‘t working onclick any more #GH-31
## [1.20.0] - 2018-07-18
### Changed
- on `input[type=url]` omitting the scheme part and performing intelligent matching on the domain name (#GH-28)
- README: Updated the tested browsers list as well as updated the Features section due to the updates by this release
- Preparation for automated testing / splitting the demo page by regular and IE9
### Fixed
- IE9: Use .getAttribute for retrieving .type and .multiple values/existance (#GH-29)
- list IDL attribute must return the current suggestions source element (#GH-30)
## [1.19.0] - 2018-07-13
### Added
- In case of the ESC key being pressed while focusing the polyfilling select, we still want to focus the `input[list]`
### Changed
- Performance: Set a local variable
- Preparation for some automated testing
- Changed and added some functionality to the description within the README file
## [1.18.1] - 2018-07-10
### Added
- Dispatch the input event as well on the related `input[list]` on using the Backspace key within the polyfilling select
## [1.18.0] - 2018-07-10
### Changed
- Defined the system-font for the demo-page
- Renamed some variables to some more meaningful names
- Cleanup on some unnecessary variables & comments
### Removed
- Removed an old separation in between eventTarget-Tagnames of select and option, that was integrated due to the mouse-event, which has been replaced again a while ago
## [1.17.0] - 2018-07-07
### Added
- Include behavior on pressing Tab or other printable keys (#GH-#27)
- Added Greenkeeper badge. I'm using this service to keep being updated on the dev dependencies.
## [1.16.2] - 2018-07-04
### Fixed
- Fixed a bug that lead to an incorrectly selected suggestion (first instead of last) while using the up key on the input element
- Fix for `input[list]` elements with class attribute - thanks to @mricherzhagen for mentioning this and even also providing a solution by pull request #GH-25
## [1.16.1] - 2018-06-28
### Fixed
- Introduced a new bug by the fix for #GH-23. Reverted that one and corrected the ESLint rules settings. (#GH-24)
## [1.16.0] - 2018-06-27
### Added
- Linting as well as security: prettier, xo, codacy
- And their badges
### Changed
Made a lot of code changes in relation to what the previously mentioned linters reported. (e.g. #GH-23)
### Security
Made some code changes in relation to what the previously mentioned linters reported. (e.g. #GH-21, #GH-22)
## [1.15.1] - 2018-06-22
### Fixed
- A previous checkin has broken the solution provided for #GH-16, so I've fixed this again.
## [1.15.0] - 2018-06-22
### Changed
- Mainly simplified the code.
## [1.14.4] - 2018-06-21
### Fixed
- IE9: After choosing a suggestion out of the polyfilling select, the select itself wouldn't get hidden. (#GH-19)
## [1.14.3] - 2018-06-20
### Changed
- Changed the order in a comparsion as this simplifies the response.
### Fixed
- Sadly another small bug slipped through today, it's about an incorrect variable being used.
## [1.14.2] - 2018-06-20
### Fixed
- A small bug sadly slipped through that doesn't hide the polyfilling select on non-matching option elements regarding the value.
## [1.14.1] - 2018-06-20
### Added
- Hiding the polyfilling select on pressing ENTER, which is equal to the behavior on typing ESC.
- Added more badges to the readme. I'm loving badges.
### Changed
- Made some necessary changes to enhance the current demo page by the minimum amount of relevant HTML tags that should be included within every page (and even also added the IE related meta tag due to backwards compatibility).
### Removed
- Removed some sample code out of the readme page due to the new NPM websites layout.
### Fixed
- The determination of option elements within the polyfilling select has incorrectly even also included `:disabled` elements.
## [1.14.0] - 2018-06-12
### Added
- Added MutationObserver to even also capture changes to the option elements as a correction to enhance the current functionality (#GH-16).
### Changed
- Changed some URLs from HTTP to the new kid on the block: HTTPS. Nice ! ;-)
- Additionally did some necessary updates to the documentation.
## [1.13.2] - 2018-06-11
### Changed
- Focusing the input[list] after selecting a suggestion, as in #GH-18
## [1.13.1] - 2018-06-04
### Changed
- Some code refactoring, nothing really serious
By the way, it was polyfills 1st birthday one month ago. Yeah !!!
## [1.13.0] - 2018-05-28
### Added
- Thanks to @eddr and @Kravimir for inspiring me via #GH-5 that there should be another possibility on defining value and label for the suggestions. As the browser vendors (GC vs. the others) don't seem to be aligned on this topic, I've decided to enable the label-attribute to serve as the definitive label being displayed, even if a value is being defined differing from the label. Check out the „Different ways of defining an option“ section on the demo page regarding this topic.
### Changed
- The docs. And changed (dependencies) and added (jsdelivr) badges. I like badges.
- As well as extracted the CHANGELOG to an external file.
## [1.12.3] - 2018-05-04
### Fixed
- @wlekin thankfully mentioned (extracted to #GH-15) that the polyfilling `select` gets positioned incorrectly underneath the `input[list]` element on iOS.
## [1.12.2] - 2018-05-01
### Fixed
- Thank you @IceCreamYou for fixing the case sensitive focusOut -> focusout event name
## [1.12.1] - 2018-04-07
### Changed
- simple (code) style changes (plus added editorconfig to keep it that way) and typo
## [1.12.0] - 2018-03-18
### Added
- @ottoville thankfully contributed by mentioning and implementing the feature of emitting an event when item in datalist is selected
## [1.11.2] - 2018-03-17
### Changed
- @mertenhanisch has styled the code according to more „standard“ formatting and also improved the wording of the documentation, which is awesome.
- And @mitchhentges thankfully supports on reviewing your great community support and ensures to the keep the wheels turning on the development of this projects.
Many kudos to the both of you !!!
## [1.11.1] - 2017-11-24
### Fixed
- @hryamzik thankfully mentioned by #GH-7 that the polyfilling `select` gets positioned incorrectly in case of the `input[list]` element being styled as a block-level element.
## [1.11.0] - 2017-10-08
### Changed
- I'm very thankful for @ailintom mentioning the missing IE9 support with #GH-2, which is still relevant (at least and maybe foremost) for the Windows Vista users.
- Additionally @Kravimir thankfully brought to my attention, that IE9 handles the `option` subelements quite restricted - so I've added a section regarding IE9 support to the demo page with the additional two lines of HTML, that you'll need to add in case you also need / want to still support IE9 in your projects, as well as changed the JavaScript code to even also support IE9.
## [1.10.3] - 2017-10-07
### Changed
- Added a comment regarding IE9 - and some simple code styling.
## [1.10.2] - 2017-09-26
### Fixed
- Simple corrections.
## [1.10.1] - 2017-09-25
### Fixed
- Simple bugfix, that came up through the latest implementation on the up and down arrow keys.
## [1.10.0] - 2017-08-16
### Changed
- Added the ability to open the datalist on the up and down keys even in case that no value has been provided - this seems to be intentionally and even also adapts the behavior by supporting browsers.
## [1.9.0] - 2017-07-20
### Changed
Regarding the changes out of release version 1.6.0 to emulate the expected UI quite nicely, I was still struggling with using that hacky solution (`multiple` attribute) and even also of how to prevent multiple selections on the polyfilling select.
- Actually the attribute `size` came to my attention, which much better fits the requirements and behaves as designed quite perfectly. Chapeau!
## [1.8.1] - 2017-07-18
### Fixed
- Bugfix regarding the handling of the label values.
## [1.8.0] - 2017-07-24
### Changed
- Restricted the polyfill to only work with relevant input types; we’d like to exclude the ones that even already need another polyfill to „work“ correctly or have a meaningful UI, like e.g. color or date-related ones, as those polyfills should handle the support of the datalist themselves depending on their own functionality.
## [1.7.0] - 2017-06-29
### Added
- As mentioned by @aFarkas [within his review](https://github.com/h5bp/html5please/issues/18), `option` elements could be of some different formats. This release especially follows [the spec](https://www.w3.org/TR/html5/forms.html#the-datalist-element) regarding the aspect that „Each suggestion has a value and a label.“.
## [1.6.2] - 2017-06-28
### Changed
- Optimized the behavior to select the entries within the polyfilling `select[multiple]` on using the up and down arrow keys from the polyfilled `input[list]`.
## [1.6.1] - 2017-06-16
### Changed
- Introduced speaking variables for the different keycodes.
- And implemented some feedback by flow.
- As well as additional code simplifications.
## [1.6.0] - 2017-06-16
### Changed
This is so far the biggest and greatest update !
- Depending of the feedback by Michael the visual appearance has changed and will better emulate the expected layout as in other browsers (on non-touch interactions). That for the script is creating the polyfilling select as a multiple-selection type, which emulates the expected „form“ better.
- And better positioning as well as styling the polyfilling select according to the input field, like e.g. even also set the polyfilling selects border-radius equally as the one by the polyfilled input.
## [1.5.0] - 2017-06-10
### Changed
- Simplified the styling and got rid of the external CSS files / dependency. You could remove that one now. Yeah!
## [1.4.0] - 2017-06-09
### Added
- Added RTL text-direction support
## [1.3.0] - 2017-05-30
### Added
- Added support for multiple email addresses, separated by comma.
### Changed
- And again, updated documentation slightly. And demo accordingly.
## [1.2.1] - 2017-05-29
### Changed
- Simple code style modifications. Because style matters.
## [1.2.0] - 2017-05-29
### Added
- Added .options (for `datalist` elements) and .list (for `input` elements) properties according to the specs.
## [1.1.2] - 2017-05-22
### Changed
- Further simplified the code, so that we could even skip the `.matches()` polyfill. Yeah.
- And documentation updates.
## [1.1.1] - 2017-05-10
### Fixed
- fixed another simple bug that lead to an incorrect index being selected - let's skip this, as it's not even the standard behavior
## [1.1.0] - 2017-05-09
### Fixed
- some small corrections
## [1.0.3] - 2017-05-09
### Changed
- better preselection on entries within the dropdown depending on the inputs value
## [1.0.2] - 2017-05-08
### Added
- added a `package.json` file
## [1.0.1] - 2017-05-08
### Fixed
- Small, but important typo. :-) Thanks @Fyrd for mentioning this.
## [1.0.0] - 2017-05-04
### Added
- First release.
MIT License
Copyright (c) 2017
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.
[npm]: https://npmjs.com/package/datalist-polyfill 'datalist polyfill – on NPM'
# datalist-polyfill
[![MIT license](https://img.shields.io/npm/l/datalist-polyfill.svg 'license badge')](https://opensource.org/licenses/mit-license.php)
[![datalist-polyfill on Npmjs](https://img.shields.io/npm/v/datalist-polyfill.svg 'npm version')][npm]
[![Total downloads ~ Npmjs](https://img.shields.io/npm/dt/datalist-polyfill.svg 'Count of total downloads – NPM')][npm]
[![jsDelivr CDN downloads](https://data.jsdelivr.com/v1/package/npm/datalist-polyfill/badge 'Count of total downloads – jsDelivr')](https://www.jsdelivr.com/package/npm/datalist-polyfill 'datalist polyfill – on jsDelivr')
[![dependencies Status](https://david-dm.org/mfranzke/datalist-polyfill/status.svg 'Count of dependencies')](https://david-dm.org/mfranzke/datalist-polyfill 'datalist polyfill – on david-dm')
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/d1f98a2d1fd44c41b7ad5c7670d8cdcd)](https://app.codacy.com/app/mfranzke/datalist-polyfill?utm_source=github.com&utm_medium=referral&utm_content=mfranzke/datalist-polyfill&utm_campaign=badger)
[![Greenkeeper badge](https://badges.greenkeeper.io/mfranzke/datalist-polyfill.svg)](https://greenkeeper.io/)
**Update:** Safari now supports the `datalist` element at least basically, as [announced earlier this year with the latest release of Safari both for iOS and MacOS X](https://developer.apple.com/documentation/safari_release_notes/safari_12_1_release_notes#3130314). Yeah !!! Exciting news!
I'm planning to release a new major version soon to both cheer as well as accommodate their implementation.
This is a minimal and dependency-free vanilla JavaScript polyfill for the awesome datalist-functionality, that will bring joy and happiness into our lives :-)
- Supports all standard's functionality as well as mimics other browsers behavior.
- Mitigating the [different levels of support](https://caniuse.com/#feat=datalist) both by Safari and IE9+ as well as EDGE
- Released under the MIT license
- Made in Germany. And supported by so many great people from all over this planet - see "Credits" accordingly.
## Features
- Lightweight: 6.9 kB of minified JavaScript, around 2.6 kB gzipped
- Fully flexible to change the datalist entries / `<option>`s
- Supporting:
- the relevant input field types: `text`, `email`, `number`, `search`, `tel` and `url` ...
- ... while leaving the others like color or date related, as those would most likely need another polyfill to work correctly or have a meaningful UI
- `input[type=email]` elements `multiple` attribute
- properties `.options` for `datalist` elements and `.list` for `input` elements
- right to left text-direction
- non-touch and touch interactions
- different types of `option` declarations
- both Safari and Internet Explorer (IE9+) browsers
- controlling the display of differing `value` and `label` values
- on `input[type=url]` omitting the scheme part and performing intelligent matching on the domain name
- substring matching on both the `value` and the `text` values
- Emits "input" event when item in the `datalist` is selected
- Enables core keyboard controls such as
- on the `input`
- up and down arrow keys
- on the `select`
- `ESC`
- `ENTER`
- `BACKSPACE`
- pressing printable characters
- Implements the [WAI-ARIA design pattern](https://www.w3.org/TR/wai-aria-practices/)
## Core concepts
The polyfill was designed with the following concepts kept in mind:
- dependency-free
- Supporting DOM changes by event delegation and MutationObserver
- code accessibility / readability
## Installation
Just integrate the JavaScript file into your code - et voilà.
You may optionally load via NPM or Bower:
$ npm install datalist-polyfill
$ bower install datalist-polyfill
## API
Nothing really, just plug it in, it ~~will~~ should work out of the box.
This package is also enabling the [`.options` (for `datalist` elements)](https://developer.mozilla.org/en/docs/Web/API/HTMLDataListElement) and [`.list` (for `input` elements)](https://developer.mozilla.org/en/docs/Web/API/HTMLInputElement) properties according to the specs.
If you set a `title`-Attribute on the `<datalist>` HTML tag, it would get used as label for the first disabled entry within the polyfilling select on non-touch interactions.
### dynamic HTML (or DHTML, if you like to be a little bit nostalgic)
In case that you'd like to dynamically add or modify / create your HTML code, you're good to go with this polyfill, as it's based on event delegation and additionally using MutationObserver (IE11+) that makes your UI work easily - no refresh nor reinit function to call after DOM manipulation or something similar.
### Changes to the available `option` elements
If you'd like to make a change to the integrated list of `<option>` elements, feel free to either remove or add them right away - the list would get generated on the fly after the user typed in something into the `<input>` field, so you're covered on this.
You can also disable `<option>` elements by adding the `disabled` attribute to the `<option>` HTML tag if necessary.
### Differing `value` and `label` values
As the browser vendors (Google Chrome vs. the others) don't seem to be aligned on this topic, I've decided to enable the `label`-attribute to serve as the definitive label being displayed, even if a value is being defined differing from the label. On different `value` and `text` values, both of them would get displayed within the suggestions, as Google Chrome does it. But if you define a differing `label`-attribute, its value would get displayed exclusively (as all the other browsers do it) to give you some flexibility on how to define those suggestions. Check out the „Different ways of defining an option“ section on the demo page regarding this topic.
### Microsoft Internet Explorer
#### Microsoft EDGE
Microsoft EDGE doesn't trigger the `input` event any more after selecting an item via mouseclick (on `input` elements other than type of `text`), even though that IE11 still did, nevermind ...
That for the optimizations on substring matching for Microsoft EDGE specifically by #GH-39 need to get restricted to `input[type="text"]` elements even only.
There might be possible solutions to even also achieve the expected behaviour on non-text-input elements - even though that I only could think about ugly solutions that I don't want to have within the polyfill and that might even also break existing CSS & JS architecture / selectors.
#### Microsoft Internet Explorer 9
You'll need the declaration for the standard `hidden` attribute, that you might already have included in case you're using [`normalize.css`](https://github.com/necolas/normalize.css/). Otherwise just adapt it from there:
```css
/**
* Add the correct
* display in IE 10-
*/
[hidden] {
display: none;
}
```
And you need to add a nesting `select` element wrapped by a conditional comment into the `datalist` element.
Please have a look at the [demo page](https://mfranzke.github.io/datalist-polyfill/demos/ie9/) accordingly, the code is being listed at the beginning.
## Demo
See the polyfill in action either by downloading / forking this repo and have a look at `demos/index.html` and `demos/ie9/index.html`, or at the hosted demo: <https://mfranzke.github.io/datalist-polyfill/demos/> and <https://mfranzke.github.io/datalist-polyfill/demos/ie9/>
## things to keep in mind
- The demo HTML code is meant to be simple - I do know that things like a surrounding `<form>` are missing, and I've left the latin letters and english expressions for the right to left text-direction example. But lets focus on the relevant tags that this polyfill is all about for the demo.
- iOS Safari handles the `label`-attribute different from Safari on Mac OS. This is being equalized during the handling of the `label`-attributes-value for differing `value` and `label` values.
- After I thought it through and did some experiments, I've finally chosen the `<select>` element to polyfill the `<datalist>`, as it brought most of the functionality, whereas I accepted that it doesn't behave and doesn't look equally.
- As I wanted to mainly focus on native elements in the most low level / simple way instead of visually emulating a list and than afterwards regain all of the functionality via a lot of JavaScript logic, I've ended up with this element, that knows how to play nicely with nested `<option>` elements.
- I tried its `multiple` attribute, as this is most likely already what you're up to regarding appearance, but it does violate the form-follows-function concept and results in - surprise - the possibility for multiple selections, which isn't always `<datalist>` elements kind of thing... Then the `size` attribute came to my attention, which much better fits the requirements and behaves as designed quite perfectly.
- Let the `datalist` element be a direct follower of the `input` element - and don't nest it into the `label` in case that you're doing so with the `input` (which you nevertheless shouldn't do in general, but hey, gods great zoo is great).
- If embedding a webview within an iOS app, you should be using `WKWebView` instead of `UIWebView`, as it supports `datalist` right natively and the latter even also leads to a JavaScript error (thanks to @jscho13 for mentioning this).
## Credits
Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin, @eddr, @beebee1987, @mricherzhagen, @acespace90, @damien-git, @nexces, @Sora2455 and @jscho13. Thank you very much for that, highly appreciated !
## Tested with
- Mac
- Mac OSX 10.13, Safari 11
- Mac OSX 10.12, Safari 10
- Mac OSX 10.11, Safari 9
- iOS
- iPhone 8 Simulator, Mobile Safari 11.0
- iPhone 7 Plus Simulator, Mobile Safari 10.0
- iPad Pro Simulator, Mobile Safari 9.3
- Windows
- Windows 7 SP1, Internet Explorer 9.0.8112.16421
- Windows 8.1, Internet Explorer 11.0.9600.19101
### Big Thanks
Cross-browser testing platform provided by [CrossBrowserTesting][crossbrowsertestinghomepage]
[![CrossBrowserTesting](https://crossbrowsertesting.com/blog/wp-content/uploads/2017/09/cbt-wp-logo.png 'CrossBrowserTesting')][crossbrowsertestinghomepage]
[crossbrowsertestinghomepage]: https://crossbrowsertesting.com
## Prospects & functionality overview
The following problems are mainly reported and [listed on caniuse](https://caniuse.com/#feat=datalist) as well as due to issues flagged on Github.
<table>
<tr>
<th>Problem</th>
<th>IE9</th>
<th>iOS</th>
<th>Safari < 12.1</th>
<th>iOS WebView</th>
<th>Safari >= 12.1</th>
<th>IE11+</th>
<th>EDGE</th>
<th>Firefox</th>
<th>Chrome</th>
<th>Chrome WebView</th>
</tr>
<tr>
<th align="left">Basic functionality</th>
<td colspan="3" align="center"><i>Polyfill</i></td>
<td align="center">✔ via WKWebView</td>
<td colspan="5" align="center"></td>
<td align="center"><a href="https://github.com/mfranzke/datalist-polyfill/issues/33">#GH-33</a></td>
</tr>
<tr>
<th align="left"><a href="https://bugs.chromium.org/p/chromium/issues/detail?id=773041">long lists of items are unscrollable resulting in unselectable options</a></th>
<td colspan="8" align="center"></td>
<td align="center"><a href="https://bugs.chromium.org/p/chromium/issues/detail?id=773041" target="_blank">fixed with v.69</a></td>
<td align="center"></td>
</tr>
<tr>
<th align="left"><a href="https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9573654/">No substring matching for the suggestions</a></th>
<td colspan="5" align="center"></td>
<td colspan="2" align="center">✔ by <a href="https://github.com/mfranzke/datalist-polyfill/issues/39">#GH-39</a></td>
<td colspan="3" align="center"></td>
</tr>
<tr>
<th align="left"><a href="https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/20066595/">`datalist` popups gets &quot;emptied&quot; when receiving focus via tab</a></th>
<td colspan="6" align="center"></td>
<td align="center">✔ by <a href="https://github.com/mfranzke/datalist-polyfill/issues/49">#GH-49</a></td>
<td colspan="3" align="center"></td>
</tr>
</table>
## Outro
Personally I even also do like the "keep it simple" approach provided within the [W3C specs](https://www.w3.org/TR/html5/forms.html#the-datalist-element) even already.
But on the other hand this leads to an additional visible field, but doesn't emulate the (hopefully, fingers crossed) upcoming x-browser implementation and leaves unnecessary syntax for all of the clients that wouldn't even need it (anymore).
If you're trying out and using my work, feel free to contact me and give me any feedback. I'm curious about how it's gonna be used.
theme: jekyll-theme-cayman
\ No newline at end of file
{
"name": "datalist-polyfill",
"description": "A minimal and dependency-free vanilla JavaScript datalist polyfill. Supports all standard's functionality as well as mimics other browsers behavior.",
"version": "1.23.3",
"homepage": "https://github.com/mfranzke/datalist-polyfill",
"authors": [
{
"name": "Maximilian Franzke",
"url": "https://www.mfranzke.net/",
"email": "contact_mfr@nzke.net"
}
],
"keywords": [
"datalist",
"autosuggest",
"autosuggester",
"suggest",
"suggester",
"select"
],
"licenses": [
{
"type": "MIT",
"url": "https://opensource.org/licenses/mit-license.php"
}
],
"ignore": [
"bower.json",
"demos/index.html",
"demos/ie9/index.html",
"readme.md"
]
}
/*
* Datalist polyfill - https://github.com/mfranzke/datalist-polyfill
* @license Copyright(c) 2017 by Maximilian Franzke
* Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin, @eddr, @beebee1987, @mricherzhagen, @acespace90, @damien-git, @nexces, @Sora2455 and @jscho13 - many thanks for that !
*/
/*
* A minimal and dependency-free vanilla JavaScript datalist polyfill.
* Supports all standard's functionality as well as mimics other browsers behavior.
* Tests for native support of an inputs elements datalist functionality.
* Elsewhere the functionality gets emulated by a select element.
*/
(function() {
'use strict';
// Performance: Set local variables
var dcmnt = window.document,
ua = window.navigator.userAgent,
// Feature detection
datalistSupported =
'list' in dcmnt.createElement('input') &&
Boolean(dcmnt.createElement('datalist') && window.HTMLDataListElement),
// IE & EDGE browser detection via UserAgent
// TODO: obviously ugly. But sadly necessary until Microsoft enhances the UX within EDGE (compare to https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/9573654/)
// adapted out of https://gist.github.com/gaboratorium/25f08b76eb82b1e7b91b01a0448f8b1d :
isGteIE10 = Boolean(ua.match(/Trident\/[6-7]\./)),
isEDGE = Boolean(ua.indexOf('Edge/') !== -1);
// Let's break here, if it's even already supported ... and not IE10+ or EDGE
if (datalistSupported && !isGteIE10 && !isEDGE) {
return false;
}
// .matches polyfill
// TODO: probably needs enhancement on the expected to be supported browsers
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector;
}
// Define some global settings and configurations
var touched = false,
// Speaking variables for the different keycodes
keyENTER = 13,
keyESC = 27,
keyUP = 38,
keyDOWN = 40,
// Defining the text / value seperator for displaying the value and text values ...
textValueSeperator = ' / ',
// ... and defining the different input types that are supported by this polyfill
supportedTypes = ['text', 'email', 'number', 'search', 'tel', 'url'],
// Classes for elements
classNameInput = 'polyfilled',
classNamePolyfillingSelect = 'polyfilling',
// Defining a most likely unique polyfill string
uniquePolyfillString = '###[P0LYFlLLed]###';
// Differentiate for touch interactions, adapted by https://medium.com/@david.gilbertson/the-only-way-to-detect-touch-with-javascript-7791a3346685
window.addEventListener('touchstart', function onFirstTouch() {
touched = true;
window.removeEventListener('touchstart', onFirstTouch);
});
// For observing any changes to the option elements within the datalist elements, define MutationObserver initially
var MutationObserver =
window.MutationObserver || window.WebKitMutationObserver,
obs;
// Define a new observer
if (typeof MutationObserver !== 'undefined') {
obs = new MutationObserver(function(mutations) {
var datalistNeedsAnUpdate = false;
// Look through all mutations that just occured
mutations.forEach(function(mutation) {
// Check if any of the mutated nodes was a datalist
if (mutation.target instanceof HTMLElement &&
mutation.target.tagName.toLowerCase() === "datalist" &&
mutation.addedNodes.length > 1) {
datalistNeedsAnUpdate = mutation.target;
}
});
if (datalistNeedsAnUpdate) {
var input = dcmnt.querySelector(
'input[list="' + datalistNeedsAnUpdate.id + '"]'
);
if (getInputValue(input) !== '') {
// Prepare the options and toggle the visiblity afterwards
toggleVisibility(
prepOptions(datalistNeedsAnUpdate, input).length,
datalistNeedsAnUpdate.getElementsByClassName(
classNamePolyfillingSelect
)[0]
);
}
}
});
}
// Function regarding the inputs interactions on keyup event
var inputInputList = function(event) {
var input = event.target,
datalist = input.list,
keyOpen = event.keyCode === keyUP || event.keyCode === keyDOWN;
// Check for whether the events target was an input and still check for an existing instance of the datalist and polyfilling select
if (input.tagName.toLowerCase() !== 'input' || datalist === null) {
return;
}
// Handling IE10+ & EDGE
if (isGteIE10 || isEDGE) {
// On keypress check for value
if (
getInputValue(input) !== '' &&
!keyOpen &&
event.keyCode !== keyENTER &&
event.keyCode !== keyESC &&
// As only EDGE doesn't trigger the input event after selecting an item via mouse, we need to differentiate here
(isGteIE10 || input.type === 'text')
) {
updateIEOptions(input, datalist);
// TODO: Check whether this update is necessary depending on the options values
input.focus();
}
return;
}
var visible = false,
// Creating the select if there's no instance so far (e.g. because of that it hasn't been handled or it has been dynamically inserted)
datalistSelect =
datalist.getElementsByClassName(classNamePolyfillingSelect)[0] ||
setUpPolyfillingSelect(input, datalist);
// On an ESC or ENTER key press within the input, let's break here and afterwards hide the datalist select, but if the input contains a value or one of the opening keys have been pressed ...
if (
event.keyCode !== keyESC &&
event.keyCode !== keyENTER &&
(getInputValue(input) !== '' || keyOpen) &&
datalistSelect !== undefined
) {
// ... prepare the options
if (prepOptions(datalist, input).length > 0) {
visible = true;
}
var firstEntry = 0,
lastEntry = datalistSelect.options.length - 1;
// ... preselect best fitting index
if (touched) {
datalistSelect.selectedIndex = firstEntry;
} else if (keyOpen && input.getAttribute('type') !== 'number') {
datalistSelect.selectedIndex =
event.keyCode === keyUP ? lastEntry : firstEntry;
// ... and on arrow up or down keys, focus the select
datalistSelect.focus();
}
}
// Toggle the visibility of the datalist select according to previous checks
toggleVisibility(visible, datalistSelect);
};
// On keypress check all options for that as a substring, save the original value as a data-attribute and preset that inputs value (for sorting) for all option values (probably as well enhanced by a token)
var updateIEOptions = function(input, datalist) {
var inputValue = getInputValue(input);
// Loop through the options
Array.prototype.slice.call(datalist.options, 0).forEach(function(option) {
// We're using .getAttribute instead of .dataset here for IE10
var dataOriginalvalue = option.getAttribute('data-originalvalue'),
originalValue = dataOriginalvalue || option.value;
// In case of that the original value hasn't been saved as data so far, do that now
if (!dataOriginalvalue) {
// We're using .setAttribute instead of .dataset here for IE10
option.setAttribute('data-originalvalue', originalValue);
}
// As we'd manipulate the value in the next step, we'd like to put in that value as either a label or text if none of those exist
if (!option.label && !option.text) {
option.label = originalValue;
}
/*
Check for whether the current option is a valid suggestion and replace its value by
- the current input string, as IE10+ and EDGE don't do substring, but only prefix matching
- followed by a unique string that should prevent any interferance
- and the original string, that is still necessary e.g. for sorting within the suggestions list
As the value is being inserted on users selection, we'll replace that one within the upfollowing inputInputListIE function
*/
option.value = isValidSuggestion(option, inputValue)
? inputValue + uniquePolyfillString + originalValue.toLowerCase()
: originalValue;
});
};
// Check for the input and probably replace by correct options elements value
var inputInputListIE = function(event) {
var input = event.target,
datalist = input.list;
if (
!input.matches('input[list]') ||
!input.matches('.' + classNameInput) ||
!datalist
) {
return;
}
// Query for related option - and escaping the value as doublequotes wouldn't work
var option = datalist.querySelector(
'option[value="' +
getInputValue(input).replace(/\\([\s\S])|(")/g, '\\$1$2') +
'"]'
);
// We're using .getAttribute instead of .dataset here for IE10
if (option && option.getAttribute('data-originalvalue')) {
setInputValue(input, option.getAttribute('data-originalvalue'));
}
};
// Check for whether this is a valid suggestion
var isValidSuggestion = function(option, inputValue) {
var optVal = option.value.toLowerCase(),
inptVal = inputValue.toLowerCase(),
label = option.getAttribute('label'),
text = option.text.toLowerCase();
/*
"Each option element that is a descendant of the datalist element, that is not disabled, and whose value is a string that isn't the empty string, represents a suggestion. Each suggestion has a value and a label."
"If appropriate, the user agent should use the suggestion's label and value to identify the suggestion to the user."
*/
return Boolean(
option.disabled === false &&
((optVal !== '' && optVal.indexOf(inptVal) !== -1) ||
(label && label.toLowerCase().indexOf(inptVal) !== -1) ||
(text !== '' && text.indexOf(inptVal) !== -1))
);
};
// Focusin and -out events
var changesInputList = function(event) {
// Check for correct element on this event delegation
if (!event.target.matches('input[list]')) {
return;
}
var input = event.target,
datalist = input.list;
// Check for whether the events target was an input and still check for an existing instance of the datalist
if (input.tagName.toLowerCase() !== 'input' || datalist === null) {
return;
}
// Test for whether this input has already been enhanced by the polyfill
if (!input.matches('.' + classNameInput)) {
prepareInput(input, event.type);
}
// #GH-49: Microsoft EDGE / datalist popups get "emptied" when receiving focus via tabbing
if (isEDGE && event.type === 'focusin') {
// Set the value of the first option to it's value - this actually triggers a redraw of the complete list
var firstOption = input.list.options[0];
firstOption.value = firstOption.value;
}
// Break here for IE10+ & EDGE
if (isGteIE10 || isEDGE) {
return;
}
var // Creating the select if there's no instance so far (e.g. because of that it hasn't been handled or it has been dynamically inserted)
datalistSelect =
datalist.getElementsByClassName(classNamePolyfillingSelect)[0] ||
setUpPolyfillingSelect(input, datalist),
// Either have the select set to the state to get displayed in case of that it would have been focused or because it's the target on the inputs blur - and check for general existance of any option as suggestions
visible =
datalistSelect &&
datalistSelect.querySelector('option:not(:disabled)') &&
((event.type === 'focusin' && getInputValue(input) !== '') ||
(event.relatedTarget && event.relatedTarget === datalistSelect));
// Toggle the visibility of the datalist select according to previous checks
toggleVisibility(visible, datalistSelect);
};
// Prepare the input
var prepareInput = function(input, eventType) {
// We'd like to prevent autocomplete on the input datalist field
input.setAttribute('autocomplete', 'off');
// WAI ARIA attributes
input.setAttribute('role', 'textbox');
input.setAttribute('aria-haspopup', 'true');
input.setAttribute('aria-autocomplete', 'list');
input.setAttribute('aria-owns', input.getAttribute('list'));
// Bind the keyup event on the related datalists input
if (eventType === 'focusin') {
input.addEventListener('keyup', inputInputList);
input.addEventListener('focusout', changesInputList, true);
// As only EDGE doesn't trigger the input event after selecting an item via mouse, we need to differentiate here
if (isGteIE10 || (isEDGE && input.type === 'text')) {
input.addEventListener('input', inputInputListIE);
}
} else if (eventType === 'blur') {
input.removeEventListener('keyup', inputInputList);
input.removeEventListener('focusout', changesInputList, true);
// As only EDGE doesn't trigger the input event after selecting an item via mouse, we need to differentiate here
if (isGteIE10 || (isEDGE && input.type === 'text')) {
input.removeEventListener('input', inputInputListIE);
}
}
// Add class for identifying that this input is even already being polyfilled
input.className += ' ' + classNameInput;
};
// Get the input value for dividing regular and mail types
var getInputValue = function(input) {
// In case of type=email and multiple attribute, we would need to grab the last piece
// Using .getAttribute here for IE9 purpose - elsewhere it wouldn't return the newer HTML5 values correctly
return input.getAttribute('type') === 'email' &&
input.getAttribute('multiple') !== null
? input.value.substring(input.value.lastIndexOf(',') + 1)
: input.value;
};
// Set the input value for dividing regular and mail types
var setInputValue = function(input, datalistSelectValue) {
var lastSeperator;
// In case of type=email and multiple attribute, we need to set up the resulting inputs value differently
input.value =
// Using .getAttribute here for IE9 purpose - elsewhere it wouldn't return the newer HTML5 values correctly
input.getAttribute('type') === 'email' &&
input.getAttribute('multiple') !== null &&
(lastSeperator = input.value.lastIndexOf(',')) > -1
? input.value.slice(0, lastSeperator) + ',' + datalistSelectValue
: datalistSelectValue;
};
// Binding the focus event - matching the input[list]s happens in the function afterwards
dcmnt.addEventListener('focusin', changesInputList, true);
// Break here for IE10+ & EDGE
if (isGteIE10 || isEDGE) {
return;
}
// Function for preparing and sorting the options/suggestions
var prepOptions = function(datalist, input) {
if (typeof obs !== 'undefined') {
obs.disconnect();
}
var // Creating the select if there's no instance so far (e.g. because of that it hasn't been handled or it has been dynamically inserted)
datalistSelect =
datalist.getElementsByClassName(classNamePolyfillingSelect)[0] ||
setUpPolyfillingSelect(input, datalist),
inputValue = getInputValue(input),
newSelectValues = dcmnt.createDocumentFragment(),
disabledValues = dcmnt.createDocumentFragment();
// Create an array out of the options list
Array.prototype.slice
.call(datalist.querySelectorAll('option:not(:disabled)'))
// ... sort all entries and
.sort(function(a, b) {
var aValue = a.value,
bValue = b.value;
// Using the knowledge that the values are URLs to allow the user to omit the scheme part and perform intelligent matching on the domain name
if (input.getAttribute('type') === 'url') {
aValue = aValue.replace(/(^\w+:|^)\/\//, '');
bValue = bValue.replace(/(^\w+:|^)\/\//, '');
}
return aValue.localeCompare(bValue);
})
.forEach(function(opt) {
var optionValue = opt.value,
label = opt.getAttribute('label'),
text = opt.text;
// Put this option into the fragment that is meant to get inserted into the select. Additionally according to the specs ...
// TODO: This might get slightly changed/optimized in a future release
if (isValidSuggestion(opt, inputValue)) {
var textOptionPart = text.substr(
0,
optionValue.length + textValueSeperator.length
),
optionPart = optionValue + textValueSeperator;
// The innertext should be 'value seperator text' in case they are different
if (
text &&
!label &&
text !== optionValue &&
textOptionPart !== optionPart
) {
opt.innerText = optionValue + textValueSeperator + text;
} else if (!opt.text) {
// Manipulating the option inner text, that would get displayed
opt.innerText = label || optionValue;
}
newSelectValues.appendChild(opt);
} else {
// ... or put this option that isn't relevant to the users into the fragment that is supposed to get inserted outside of the select
disabledValues.appendChild(opt);
}
});
// Input the options fragment into the datalists select
datalistSelect.appendChild(newSelectValues);
var datalistSelectOptionsLength = datalistSelect.options.length;
datalistSelect.size =
datalistSelectOptionsLength > 10 ? 10 : datalistSelectOptionsLength;
datalistSelect.multiple = !touched && datalistSelectOptionsLength < 2;
// Input the unused options as siblings next to the select - and differentiate in between the regular, and the IE9 fix syntax upfront
(datalist.getElementsByClassName('ie9_fix')[0] || datalist).appendChild(
disabledValues
);
if (typeof obs !== 'undefined') {
obs.observe(datalist, {
childList: true
});
}
return datalistSelect.options;
};
// Define function for setting up the polyfilling select
var setUpPolyfillingSelect = function(input, datalist) {
// Check for whether it's of one of the supported input types defined at the beginning
// Using .getAttribute here for IE9 purpose - elsewhere it wouldn't return the newer HTML5 values correctly
// and still check for an existing instance
if (
(input.getAttribute('type') &&
supportedTypes.indexOf(input.getAttribute('type')) === -1) ||
datalist === null
) {
return;
}
var rects = input.getClientRects(),
// Measurements
inputStyles = window.getComputedStyle(input),
datalistSelect = dcmnt.createElement('select');
// Setting a class for easier identifying that select afterwards
datalistSelect.setAttribute('class', classNamePolyfillingSelect);
// Set general styling related definitions
datalistSelect.style.position = 'absolute';
// Initially hiding the datalist select
toggleVisibility(false, datalistSelect);
// The select itself shouldn't be a possible target for tabbing
datalistSelect.setAttribute('tabindex', '-1');
// WAI ARIA attributes
datalistSelect.setAttribute('aria-live', 'polite');
datalistSelect.setAttribute('role', 'listbox');
if (!touched) {
datalistSelect.setAttribute('aria-multiselectable', 'false');
}
// The select should get positioned underneath the input field ...
if (inputStyles.getPropertyValue('display') === 'block') {
datalistSelect.style.marginTop =
'-' + inputStyles.getPropertyValue('margin-bottom');
} else {
var direction =
inputStyles.getPropertyValue('direction') === 'rtl' ? 'right' : 'left';
datalistSelect.style.setProperty(
'margin-' + direction,
'-' +
(rects[0].width +
parseFloat(inputStyles.getPropertyValue('margin-' + direction))) +
'px'
);
datalistSelect.style.marginTop =
parseInt(rects[0].height + (input.offsetTop - datalist.offsetTop), 10) +
'px';
}
// Set the polyfilling selects border-radius equally to the one by the polyfilled input
datalistSelect.style.borderRadius = inputStyles.getPropertyValue(
'border-radius'
);
datalistSelect.style.minWidth = rects[0].width + 'px';
if (touched) {
var messageElement = dcmnt.createElement('option');
// ... and it's first entry should contain the localized message to select an entry
messageElement.innerText = datalist.title;
// ... and disable this option, as it shouldn't get selected by the user
messageElement.disabled = true;
// ... and assign a dividable class to it
messageElement.setAttribute('class', 'message');
// ... and finally insert it into the select
datalistSelect.appendChild(messageElement);
}
// Add select to datalist element ...
datalist.appendChild(datalistSelect);
// ... and our upfollowing functions to the related event
if (touched) {
datalistSelect.addEventListener('change', changeDataListSelect);
} else {
datalistSelect.addEventListener('click', changeDataListSelect);
}
datalistSelect.addEventListener('blur', changeDataListSelect);
datalistSelect.addEventListener('keydown', changeDataListSelect);
datalistSelect.addEventListener('keypress', datalistSelectKeyPress);
return datalistSelect;
};
// Functions regarding changes to the datalist polyfilling created selects keypress
var datalistSelectKeyPress = function(event) {
var datalistSelect = event.target,
datalist = datalistSelect.parentNode,
input = dcmnt.querySelector('input[list="' + datalist.id + '"]');
// Check for whether the events target was a select or whether the input doesn't exist
if (datalistSelect.tagName.toLowerCase() !== 'select' || input === null) {
return;
}
// Determine a relevant key - either printable characters (that would have a length of 1) or controlling like Backspace
if (event.key && (event.key === 'Backspace' || event.key.length === 1)) {
input.focus();
if (event.key === 'Backspace') {
input.value = input.value.substr(0, input.value.length - 1);
// Dispatch the input event on the related input[list]
dispatchInputEvent(input);
} else {
input.value += event.key;
}
prepOptions(datalist, input);
}
};
// Change, Click, Blur, Keydown
var changeDataListSelect = function(event) {
var datalistSelect = event.currentTarget,
datalist = datalistSelect.parentNode,
input = dcmnt.querySelector('input[list="' + datalist.id + '"]');
// Check for whether the events target was a select or whether the input doesn't exist
if (datalistSelect.tagName.toLowerCase() !== 'select' || input === null) {
return;
}
var eventType = event.type,
// ENTER and ESC
visible =
eventType === 'keydown' &&
(event.keyCode !== keyENTER && event.keyCode !== keyESC);
// On change, click or after pressing ENTER or TAB key, input the selects value into the input on a change within the list
if (
(eventType === 'change' ||
eventType === 'click' ||
(eventType === 'keydown' &&
(event.keyCode === keyENTER || event.key === 'Tab'))) &&
datalistSelect.value.length > 0 &&
datalistSelect.value !== datalist.title
) {
setInputValue(input, datalistSelect.value);
// Dispatch the input event on the related input[list]
dispatchInputEvent(input);
// Finally focusing the input, as other browser do this as well
if (event.key !== 'Tab') {
input.focus();
}
// #GH-51 / Prevent the form to be submitted on selecting a value via ENTER key within the select
if (event.keyCode === keyENTER) {
event.preventDefault();
}
// Set the visibility to false afterwards, as we're done here
visible = false;
} else if (eventType === 'keydown' && event.keyCode === keyESC) {
// In case of the ESC key being pressed, we still want to focus the input[list]
input.focus();
}
// Toggle the visibility of the datalist select according to previous checks
toggleVisibility(visible, datalistSelect);
};
// Create and dispatch the input event; divided for IE9 usage
var dispatchInputEvent = function(input) {
var evt;
if (typeof Event === 'function') {
evt = new Event('input', {
bubbles: true
});
} else {
evt = dcmnt.createEvent('Event');
evt.initEvent('input', true, false);
}
input.dispatchEvent(evt);
};
// Toggle the visibility of the datalist select
var toggleVisibility = function(visible, datalistSelect) {
if (visible) {
datalistSelect.removeAttribute('hidden');
} else {
datalistSelect.setAttributeNode(dcmnt.createAttribute('hidden'));
}
datalistSelect.setAttribute('aria-hidden', (!visible).toString());
};
// Emulate the two properties regarding the datalist and input elements
// list property / https://developer.mozilla.org/en/docs/Web/API/HTMLInputElement
(function(constructor) {
if (
constructor &&
constructor.prototype &&
constructor.prototype.list === undefined
) {
Object.defineProperty(constructor.prototype, 'list', {
get: function() {
/*
According to the specs ...
"The list IDL attribute must return the current suggestions source element, if any, or null otherwise."
"If there is no list attribute, or if there is no element with that ID, or if the first element with that ID is not a datalist element, then there is no suggestions source element."
*/
var element = dcmnt.getElementById(this.getAttribute('list'));
return typeof this === 'object' &&
this instanceof constructor &&
element &&
element.matches('datalist')
? element
: null;
}
});
}
})(window.HTMLInputElement);
// Options property / https://developer.mozilla.org/en/docs/Web/API/HTMLDataListElement
(function(constructor) {
if (
constructor &&
constructor.prototype &&
constructor.prototype.options === undefined
) {
Object.defineProperty(constructor.prototype, 'options', {
get: function() {
return typeof this === 'object' && this instanceof constructor
? this.getElementsByTagName('option')
: null;
}
});
}
})(window.HTMLElement);
})();
/*
* Datalist polyfill - https://github.com/mfranzke/datalist-polyfill
* @license Copyright(c) 2017 by Maximilian Franzke
* Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin, @eddr, @beebee1987, @mricherzhagen, @acespace90, @damien-git, @nexces, @Sora2455 and @jscho13 - many thanks for that !
*/
!function(){"use strict";var e=window.document,t=window.navigator.userAgent,i="list"in e.createElement("input")&&Boolean(e.createElement("datalist")&&window.HTMLDataListElement),n=Boolean(t.match(/Trident\/[6-7]\./)),a=Boolean(-1!==t.indexOf("Edge/"));if(i&&!n&&!a)return!1;Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector);var r=!1,o=["text","email","number","search","tel","url"];window.addEventListener("touchstart",function e(){r=!0,window.removeEventListener("touchstart",e)});var l,s=window.MutationObserver||window.WebKitMutationObserver;void 0!==s&&(l=new s(function(t){var i=!1;if(t.forEach(function(e){e.target instanceof HTMLElement&&"datalist"===e.target.tagName.toLowerCase()&&e.addedNodes.length>1&&(i=e.target)}),i){var n=e.querySelector('input[list="'+i.id+'"]');""!==f(n)&&A(b(i,n).length,i.getElementsByClassName("polyfilling")[0])}}));var u=function(e){var t=e.target,i=t.list,o=38===e.keyCode||40===e.keyCode;if("input"===t.tagName.toLowerCase()&&null!==i)if(n||a)""===f(t)||o||13===e.keyCode||27===e.keyCode||!n&&"text"!==t.type||(d(t,i),t.focus());else{var l=!1,s=i.getElementsByClassName("polyfilling")[0]||h(t,i);if(27!==e.keyCode&&13!==e.keyCode&&(""!==f(t)||o)&&void 0!==s){b(i,t).length>0&&(l=!0);var u=s.options.length-1;r?s.selectedIndex=0:o&&"number"!==t.getAttribute("type")&&(s.selectedIndex=38===e.keyCode?u:0,s.focus())}A(l,s)}},d=function(e,t){var i=f(e);Array.prototype.slice.call(t.options,0).forEach(function(e){var t=e.getAttribute("data-originalvalue"),n=t||e.value;t||e.setAttribute("data-originalvalue",n),e.label||e.text||(e.label=n),e.value=c(e,i)?i+"###[P0LYFlLLed]###"+n.toLowerCase():n})},p=function(e){var t=e.target,i=t.list;if(t.matches("input[list]")&&t.matches(".polyfilled")&&i){var n=i.querySelector('option[value="'+f(t).replace(/\\([\s\S])|(")/g,"\\$1$2")+'"]');n&&n.getAttribute("data-originalvalue")&&g(t,n.getAttribute("data-originalvalue"))}},c=function(e,t){var i=e.value.toLowerCase(),n=t.toLowerCase(),a=e.getAttribute("label"),r=e.text.toLowerCase();return Boolean(!1===e.disabled&&(""!==i&&-1!==i.indexOf(n)||a&&-1!==a.toLowerCase().indexOf(n)||""!==r&&-1!==r.indexOf(n)))},v=function(e){if(e.target.matches("input[list]")){var t=e.target,i=t.list;if("input"===t.tagName.toLowerCase()&&null!==i){if(t.matches(".polyfilled")||y(t,e.type),a&&"focusin"===e.type){var r=t.list.options[0];r.value=r.value}if(!n&&!a){var o=i.getElementsByClassName("polyfilling")[0]||h(t,i),l=o&&o.querySelector("option:not(:disabled)")&&("focusin"===e.type&&""!==f(t)||e.relatedTarget&&e.relatedTarget===o);A(l,o)}}}},y=function(e,t){e.setAttribute("autocomplete","off"),e.setAttribute("role","textbox"),e.setAttribute("aria-haspopup","true"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("aria-owns",e.getAttribute("list")),"focusin"===t?(e.addEventListener("keyup",u),e.addEventListener("focusout",v,!0),(n||a&&"text"===e.type)&&e.addEventListener("input",p)):"blur"===t&&(e.removeEventListener("keyup",u),e.removeEventListener("focusout",v,!0),(n||a&&"text"===e.type)&&e.removeEventListener("input",p)),e.className+=" polyfilled"},f=function(e){return"email"===e.getAttribute("type")&&null!==e.getAttribute("multiple")?e.value.substring(e.value.lastIndexOf(",")+1):e.value},g=function(e,t){var i;e.value="email"===e.getAttribute("type")&&null!==e.getAttribute("multiple")&&(i=e.value.lastIndexOf(","))>-1?e.value.slice(0,i)+","+t:t};if(e.addEventListener("focusin",v,!0),!n&&!a){var m,b=function(t,i){void 0!==l&&l.disconnect();var n=t.getElementsByClassName("polyfilling")[0]||h(i,t),a=f(i),o=e.createDocumentFragment(),s=e.createDocumentFragment();Array.prototype.slice.call(t.querySelectorAll("option:not(:disabled)")).sort(function(e,t){var n=e.value,a=t.value;return"url"===i.getAttribute("type")&&(n=n.replace(/(^\w+:|^)\/\//,""),a=a.replace(/(^\w+:|^)\/\//,"")),n.localeCompare(a)}).forEach(function(e){var t=e.value,i=e.getAttribute("label"),n=e.text;if(c(e,a)){var r=n.substr(0,t.length+" / ".length);n&&!i&&n!==t&&r!==t+" / "?e.innerText=t+" / "+n:e.text||(e.innerText=i||t),o.appendChild(e)}else s.appendChild(e)}),n.appendChild(o);var u=n.options.length;return n.size=u>10?10:u,n.multiple=!r&&u<2,(t.getElementsByClassName("ie9_fix")[0]||t).appendChild(s),void 0!==l&&l.observe(t,{childList:!0}),n.options},h=function(t,i){if(!(t.getAttribute("type")&&-1===o.indexOf(t.getAttribute("type"))||null===i)){var n=t.getClientRects(),a=window.getComputedStyle(t),l=e.createElement("select");if(l.setAttribute("class","polyfilling"),l.style.position="absolute",A(!1,l),l.setAttribute("tabindex","-1"),l.setAttribute("aria-live","polite"),l.setAttribute("role","listbox"),r||l.setAttribute("aria-multiselectable","false"),"block"===a.getPropertyValue("display"))l.style.marginTop="-"+a.getPropertyValue("margin-bottom");else{var s="rtl"===a.getPropertyValue("direction")?"right":"left";l.style.setProperty("margin-"+s,"-"+(n[0].width+parseFloat(a.getPropertyValue("margin-"+s)))+"px"),l.style.marginTop=parseInt(n[0].height+(t.offsetTop-i.offsetTop),10)+"px"}if(l.style.borderRadius=a.getPropertyValue("border-radius"),l.style.minWidth=n[0].width+"px",r){var u=e.createElement("option");u.innerText=i.title,u.disabled=!0,u.setAttribute("class","message"),l.appendChild(u)}return i.appendChild(l),r?l.addEventListener("change",w):l.addEventListener("click",w),l.addEventListener("blur",w),l.addEventListener("keydown",w),l.addEventListener("keypress",E),l}},E=function(t){var i=t.target,n=i.parentNode,a=e.querySelector('input[list="'+n.id+'"]');"select"===i.tagName.toLowerCase()&&null!==a&&(!t.key||"Backspace"!==t.key&&1!==t.key.length||(a.focus(),"Backspace"===t.key?(a.value=a.value.substr(0,a.value.length-1),C(a)):a.value+=t.key,b(n,a)))},w=function(t){var i=t.currentTarget,n=i.parentNode,a=e.querySelector('input[list="'+n.id+'"]');if("select"===i.tagName.toLowerCase()&&null!==a){var r=t.type,o="keydown"===r&&13!==t.keyCode&&27!==t.keyCode;("change"===r||"click"===r||"keydown"===r&&(13===t.keyCode||"Tab"===t.key))&&i.value.length>0&&i.value!==n.title?(g(a,i.value),C(a),"Tab"!==t.key&&a.focus(),13===t.keyCode&&t.preventDefault(),o=!1):"keydown"===r&&27===t.keyCode&&a.focus(),A(o,i)}},C=function(t){var i;"function"==typeof Event?i=new Event("input",{bubbles:!0}):(i=e.createEvent("Event")).initEvent("input",!0,!1),t.dispatchEvent(i)},A=function(t,i){t?i.removeAttribute("hidden"):i.setAttributeNode(e.createAttribute("hidden")),i.setAttribute("aria-hidden",(!t).toString())};(m=window.HTMLInputElement)&&m.prototype&&void 0===m.prototype.list&&Object.defineProperty(m.prototype,"list",{get:function(){var t=e.getElementById(this.getAttribute("list"));return"object"==typeof this&&this instanceof m&&t&&t.matches("datalist")?t:null}}),function(e){e&&e.prototype&&void 0===e.prototype.options&&Object.defineProperty(e.prototype,"options",{get:function(){return"object"==typeof this&&this instanceof e?this.getElementsByTagName("option"):null}})}(window.HTMLElement)}}();
{
"name": "datalist-polyfill",
"version": "1.23.3",
"description": "A minimal and dependency-free vanilla JavaScript datalist polyfill. Supports all standard's functionality as well as mimics other browsers behavior.",
"main": "datalist-polyfill.js",
"scripts": {
"test": "xo"
},
"repository": {
"type": "git",
"url": "git://github.com/mfranzke/datalist-polyfill.git"
},
"author": "Maximilian Franzke",
"license": "MIT",
"readmeFilename": "README.md",
"keywords": [
"datalist",
"polyfill",
"javascript",
"html",
"autosuggest",
"autosuggester",
"suggest",
"suggester",
"select"
],
"bugs": {
"url": "https://github.com/mfranzke/datalist-polyfill/issues"
},
"homepage": "https://github.com/mfranzke/datalist-polyfill",
"dependencies": {},
"devDependencies": {
"@wdio/cli": "^5.8.5",
"@wdio/dot-reporter": "^5.7.8",
"@wdio/local-runner": "^5.8.6",
"@wdio/mocha-framework": "^5.8.1",
"@wdio/sync": "^5.8.6",
"prettier": "^1.13.6",
"webdriverio": "^5.8.5",
"xo": "^0.24.0"
},
"xo": {
"envs": [
"browser"
],
"prettier": true,
"esnext": false,
"rules": {
"one-var": 0,
"no-use-before-define": 0
}
}
}
# For more information about the properties used in
# this file, please see the EditorConfig documentation:
# https://editorconfig.org/
[*.js]
max_line_length = 120
exports.config = {
//
// ====================
// Runner Configuration
// ====================
//
// WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
// on a remote machine).
runner: 'local',
//
// =====================
// Server Configurations
// =====================
// Host address of the running Selenium server. This information is usually obsolete as
// WebdriverIO automatically connects to localhost. Also, if you are using one of the
// supported cloud services like Sauce Labs, Browserstack, or Testing Bot you don't
// need to define host and port information because WebdriverIO can figure that out
// according to your user and key information. However, if you are using a private Selenium
// backend you should define the host address, port, and path here.
//
hostname: 'hub.crossbrowsertesting.com',
port: 80,
path: '/wd/hub',
//
// =================
// Service Providers
// =================
// WebdriverIO supports Sauce Labs, Browserstack, and Testing Bot (other cloud providers
// should work too though). These services define specific user and key (or access key)
// values you need to put in here in order to connect to these services.
//
user: process.env.XBROWSERTESTING_USERNAME,
key: process.env.XBROWSERTESTING_ACCESS_KEY,
//
// ==================
// Specify Test Files
// ==================
// Define which test specs should run. The pattern is relative to the directory
// from which `wdio` was called. Notice that, if you are calling `wdio` from an
// NPM script (see https://docs.npmjs.com/cli/run-script) then the current working
// directory is where your package.json resides, so `wdio` will be called from there.
//
specs: ['./tests/functional/dist/*.js'],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
],
//
// ============
// Capabilities
// ============
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
// time. Depending on the number of capabilities, WebdriverIO launches several test
// sessions. Within your capabilities you can overwrite the spec and exclude options in
// order to group specific specs to a specific capability.
//
// First, you can define how many instances should be started at the same time. Let's
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
// files and you set maxInstances to 10, all spec files will get tested at the same time
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
maxInstances: 5,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
// https://docs.saucelabs.com/reference/platforms-configurator
//
capabilities: [
{
// maxInstances can get overwritten per capability. So if you have an in-house Selenium
// grid with only 5 firefox instances available you can make sure that not more than
// 5 instances get started at a time.
maxInstances: 5,
// https://app.crossbrowsertesting.com/selenium/run
platform: 'Mac OSX 10.13',
browserName: 'Safari',
version: '11.0'
} /*,
// TODO: Fix the test cases regarding older versions of safari/selenium
{
// maxInstances can get overwritten per capability. So if you have an in-house Selenium
// grid with only 5 firefox instances available you can make sure that not more than
// 5 instances get started at a time.
maxInstances: 1,
// https://app.crossbrowsertesting.com/selenium/run
platform: 'Mac OSX 10.12',
browserName: 'Safari',
version: '10'
},
{
// maxInstances can get overwritten per capability. So if you have an in-house Selenium
// grid with only 5 firefox instances available you can make sure that not more than
// 5 instances get started at a time.
maxInstances: 1,
// https://app.crossbrowsertesting.com/selenium/run
platform: 'Mac OSX 10.11',
browserName: 'Safari',
version: '9'
}
*/
],
//
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// By default WebdriverIO commands are executed in a synchronous way using
// the wdio-sync package. If you still want to run your tests in an async way
// e.g. using promises you can set the sync option to false.
sync: true,
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: 'error',
//
// Set specific log levels per logger
// loggers:
// - webdriver, webdriverio
// - @wdio/applitools-service, @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
// - @wdio/mocha-framework, @wdio/jasmine-framework
// - @wdio/local-runner, @wdio/lambda-runner
// - @wdio/sumologic-reporter
// - @wdio/cli, @wdio/config, @wdio/sync, @wdio/utils
// Level of logging verbosity: trace | debug | info | warn | error | silent
// logLevels: {
// webdriver: 'info',
// '@wdio/applitools-service': 'info'
// },
//
// If you only want to run your tests until a specific amount of tests have failed use
// bail (default is 0 - don't bail, run all tests).
bail: 0,
//
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly.
baseUrl: 'https://mfranzke.github.io/datalist-polyfill/demos/',
//
// Default timeout for all waitFor* commands.
waitforTimeout: 10000,
//
// Default timeout in milliseconds for request
// if Selenium Grid doesn't send response
connectionRetryTimeout: 90000,
//
// Default request retries count
connectionRetryCount: 3,
//
// Test runner services
// Services take over a specific job you don't want to take care of. They enhance
// your test setup with almost no effort. Unlike plugins, they don't add new
// commands. Instead, they hook themselves up into the test process.
// services: [],//
// Framework you want to run your specs with.
// The following are supported: Mocha, Jasmine, and Cucumber
// see also: https://webdriver.io/docs/frameworks.html
//
// Make sure you have the wdio adapter package for the specific framework installed
// before running any tests.
framework: 'mocha',
//
// The number of times to retry the entire specfile when it fails as a whole
// specFileRetries: 1,
//
// Test reporter for stdout.
// The only one supported by default is 'dot'
// see also: https://webdriver.io/docs/dot-reporter.html
reporters: ['dot'],
//
// Options to be passed to Mocha.
// See the full list at http://mochajs.org/
mochaOpts: {
ui: 'bdd',
timeout: 60000
},
//
// =====
// Hooks
// =====
// WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
// it and to build services around it. You can either apply a single function or an array of
// methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
// resolved to continue.
/**
* Gets executed once before all workers get launched.
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
*/
// onPrepare: function (config, capabilities) {
// },
/**
* Gets executed just before initialising the webdriver session and test framework. It allows you
* to manipulate configurations depending on the capability or spec.
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
*/
// beforeSession: function (config, capabilities, specs) {
// },
/**
* Gets executed before test execution begins. At this point you can access to all global
* variables like `browser`. It is the perfect place to define custom commands.
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
*/
// before: function (capabilities, specs) {
// },
/**
* Runs before a WebdriverIO command gets executed.
* @param {String} commandName hook command name
* @param {Array} args arguments that command would receive
*/
// beforeCommand: function (commandName, args) {
// },
/**
* Hook that gets executed before the suite starts
* @param {Object} suite suite details
*/
// beforeSuite: function (suite) {
// },
/**
* Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
* @param {Object} test test details
*/
// beforeTest: function (test) {
// },
/**
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
* beforeEach in Mocha)
*/
// beforeHook: function () {
// },
/**
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
* afterEach in Mocha)
*/
// afterHook: function () {
// },
/**
* Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
* @param {Object} test test details
*/
// afterTest: function (test) {
// },
/**
* Hook that gets executed after the suite has ended
* @param {Object} suite suite details
*/
// afterSuite: function (suite) {
// },
/**
* Runs after a WebdriverIO command gets executed
* @param {String} commandName hook command name
* @param {Array} args arguments that command would receive
* @param {Number} result 0 - command success, 1 - command error
* @param {Object} error error object if any
*/
// afterCommand: function (commandName, args, result, error) {
// },
/**
* Gets executed after all tests are done. You still have access to all global variables from
* the test.
* @param {Number} result 0 - test pass, 1 - test fail
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// after: function (result, capabilities, specs) {
// },
/**
* Gets executed right after terminating the webdriver session.
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// afterSession: function (config, capabilities, specs) {
// },
/**
* Gets executed after all workers got shut down and the process is about to exit.
* @param {Object} exitCode 0 - success, 1 - fail
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {<Object>} results object containing test results
*/
// onComplete: function(exitCode, config, capabilities, results) {
// },
/**
* Gets executed when a refresh happens.
* @param {String} oldSessionId session ID of the old session
* @param {String} newSessionId session ID of the new session
*/
//onReload: function(oldSessionId, newSessionId) {
//}
}
var field = { fieldId: 'animal', initialValue: 'Ca', expectedAmount: 2, wrongValue: 'Cc' };
// @codekit-append 'tests.js';
var field = { fieldId: 'animal2', initialValue: 'Ca', expectedAmount: 2, wrongValue: 'Cc' };
// @codekit-append 'tests.js';
var field = { fieldId: 'email', initialValue: '@r', expectedAmount: 4, wrongValue: 'doe1' };
// @codekit-append 'tests.js';
/* TODO: The following additional test needs to get fixed as it doesn't work at the moment
describe('input field #' + field.fieldId + ' - extended', function() {
beforeEach(function() {
$('#' + field.fieldId).waitForDisplayed(5000);
// Setting a value within the input field
$('#' + field.fieldId).setValue(field.initialValue);
// Select should be visible
assert.ok($('#' + field.fieldId + 'list select').isDisplayed());
});
it('should provide suggestions after inserting the value "john@doe,moss"', function() {
// Setting a value within the input field
$('#' + field.fieldId).setValue('john@doe,moss');
// Assert number of results
assert.lengthOf($$('#' + field.fieldId + 'list select option:not(:disabled)'), 1);
// Check for the suggestions value
assert.equal(
$('#' + field.fieldId + 'list select option:not(:disabled)').getAttribute('value'),
'moss.m@reynholm.co.uk'
);
});
});
*/
var field = { fieldId: 'number', initialValue: '19', expectedAmount: 28, wrongValue: '99' };
// @codekit-append 'tests.js';
var field = { fieldId: 'options', initialValue: ' 1', expectedAmount: 4, wrongValue: 'options' };
// @codekit-append 'tests.js';
var field = { fieldId: 'search', initialValue: 'ma', expectedAmount: 2, wrongValue: 'google' };
// @codekit-append 'tests.js';
var field = { fieldId: 'tel', initialValue: '-3', expectedAmount: 6, wrongValue: '911' };
// @codekit-append 'tests.js';
var field = { fieldId: 'url', initialValue: '.u', expectedAmount: 3, wrongValue: 'ftp:' };
// @codekit-append 'tests.js';
/* global browser $ $$ */
/* eslint-env mocha */
const assert = require('assert');
var keysSelect = [
{ keyName: 'ESC', unicodeChars: '\uE00C' },
{ keyName: 'ENTER', unicodeChars: '\uE007' },
{ keyName: 'BACKSPACE', unicodeChars: '\uE003' },
{ keyName: 'TAB', unicodeChars: '\uE004' }
];
var keysInput = [{ keyName: 'DOWN', unicodeChars: '\uE015' }, { keyName: 'UP', unicodeChars: '\uE013' }];
browser.url('index.html');
describe('input field #' + field.fieldId, function() {
beforeEach(function() {
$('#' + field.fieldId).waitForDisplayed(5000);
// Setting a value within the input field
$('#' + field.fieldId).setValue(field.initialValue);
// Select should be visible
assert.ok($('#' + field.fieldId + 'list select').isDisplayed());
});
it('should provide suggestions after inserting the value "' + field.initialValue + '"', function() {
// Assert number of results
assert.lengthOf($$('#' + field.fieldId + 'list select option:not(:disabled)'), 1);
});
it('should not provide suggestions after inserting the value "' + field.wrongValue + '"', function() {
// Setting a value within the input field
$('#' + field.fieldId).setValue(field.wrongValue);
// Select should not be visible
assert.isNotOk($('#' + field.fieldId + 'list select').isDisplayed());
// Assert number of results
assert.lengthOf($$('#' + field.fieldId + 'list select option:not(:disabled)'), 0);
});
it(
'should provide suggestions after inserting the value "' +
field.initialValue +
'" and deleting these again bit by bit afterwards',
function() {
browser.keys('\uE003');
// Assert number of results
assert.lengthOf($$('#' + field.fieldId + 'list select option:not(:disabled)'), field.expectedAmount);
// Select should be visible
assert.ok($('#' + field.fieldId + 'list select').isDisplayed());
// Setting a value within the input field
browser
.setValue('#' + field.fieldId, field.initialValue)
.keys('\uE003')
.keys('\uE003');
// Select should not be visible
assert.isNotOk($('#' + field.fieldId + 'list select').isDisplayed());
}
);
keysInput.forEach(function(actKey) {
it('should work with the key "' + actKey.keyName + '"', function() {
browser.keys(actKey.unicodeChars);
// Select should be visible
assert.ok($('#' + field.fieldId + 'list select').isDisplayed());
if (field.fieldId === 'number') {
// Check for whether the select has focus
assert.isNotOk($('#' + field.fieldId + 'list select').isFocused());
} else {
// Check for whether the select has focus
assert.ok($('#' + field.fieldId + 'list select').isFocused());
// Check for the selected element
var options = $$('#' + field.fieldId + 'list select option:not(:disabled)'),
optionsLength = options.length,
option = actKey.keyName === 'DOWN' ? options[0] : options[optionsLength - 1];
assert.ok(option.isSelected());
}
});
});
if (field.fieldId !== 'number') {
keysSelect.forEach(function(actKey) {
it('datalists element should work with the key "' + actKey.keyName + '"', function() {
var inputInitialValue = $('#' + field.fieldId).isDisplayed('value');
// Focus the select
browser.keys('\uE015');
// Check for whether the select has focus
assert.ok($('#' + field.fieldId + 'list select').isFocused());
// Press the key to test
browser.keys(actKey.unicodeChars);
// Check for whether the select has focus
assert.isNotOk($('#' + field.fieldId + 'list select').isFocused());
// Check for visibility
if (actKey.keyName === 'BACKSPACE') {
assert.ok($('#' + field.fieldId + 'list select').isDisplayed());
} else {
assert.isNotOk($('#' + field.fieldId + 'list select').isDisplayed());
}
// Check for the inputs values
switch (actKey.keyName) {
case 'ESC':
assert.ok($('#' + field.fieldId).getAttribute('value') === inputInitialValue);
break;
case 'BACKSPACE':
assert.ok(
$('#' + field.fieldId).getAttribute('value') ===
inputInitialValue.substr(0, inputInitialValue.length - 1)
);
break;
default:
assert.ok(
$('#' + field.fieldId).getAttribute('value') ===
$('#' + field.fieldId + 'list select option:checked').getAttribute('value')
);
break;
}
});
});
}
it('should set the value on clicking on the suggestions select', function() {
// Delete the last byte to ensure that there's more than one option/suggestion
browser.keys('\uE003');
// Click the selected element with the suggestions select
$('#' + field.fieldId + 'list select').click();
// Check for whether the select has focus
assert.isNotOk($('#' + field.fieldId + 'list select').isFocused());
// Check for visibility
assert.isNotOk($('#' + field.fieldId + 'list select').isDisplayed());
// Check for the inputs values
assert.ok(
$('#' + field.fieldId).getAttribute('value') ===
$('#' + field.fieldId + 'list select option:checked').getAttribute('value')
);
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment