flounder
v1.3.13
Published
a native friendly dropdown menu
Downloads
66
Maintainers
Readme
Flounder.js 1.3.13
(for modern browsers and ie10+)
Flounder is a styled select box replacement aimed at being easily configurable while conforming to native functionality and accessibility standards.
// npm
require('flounder');
// es6
import Flounder from 'flounder';
Usage
Flounder can be used in vanilla js, requirejs, jquery, and microbe.
Flounder can also be used in react, however there is a seperate repo for that
// vanilla
new Flounder( target, configOptions );
// requirejs
requirejs( [ 'flounder' ], function( Flounder )
{
new Flounder( target, configOptions );
} );
// jQuery plugin
$( '.example--class' ).flounder( configOptions );
// microbe plugin
µ( '.example--class' ).flounder( configOptions )
Flounder also adds a reference of itself to its target element. So if you lose the reference, you can just grab it from the element again
document.querySelector( '#vanilla--select' ).flounder.destroy()
Target options
Flounder's target is quite flexible, however it will only build on the first element it finds.
- if you would like to build multiple flounders from an array or selector, use
Flounder.find( <selector or array-like object>, [configOptions] )
you can give it an element:
new Flounder( document.getElementsByTagName( 'input--el' )[0], configOptions );
an HTML collection:
new Flounder( document.getElementsByTagName( 'input' ), configOptions );
a jQuery object:
new Flounder( $( 'input' ), configOptions );
a microbe:
new Flounder( µ( 'input' ), configOptions );
or, just a selector string:
new Flounder( 'input', configOptions );
If flounder is fed an element that already has a flounder, it will destroy it and re initialize it with the new config options.
Available config options
{
allowHTML : false,
classes : {
ARROW : `class-for-arrow-wrapper`,
ARROW_INNER : `class-for-arrow-inner`,
DESCRIPTION : `class-for-option-description`,
DISABLED : `class-for-disabled`,
HEADER : `class-for-header`,
HIDDEN : `class-for-hidden`,
HIDDEN_IOS : `class-for-hidden-ios`,
HOVER : `class-for-hover`,
LIST : `class-for-list`,
LOADING : `class-for-loading`,
LOADING_FAILED : `class-for-loading-failed`,
MAIN : `class-for-flounder`,
MAIN_WRAPPER : `class-for-wrapper`,
MULTIPLE_TAG_FLOUNDER : `class-for-multiple`,
MULTI_TAG_LIST : `class-for-multi-tag-list`,
MULTIPLE_SELECT_TAG : `class-for-multiple-select-tag`,
MULTIPLE_TAG_CLOSE : `class-for-multiple-tag-close`,
NO_RESULTS : `class-for-no-results`,
OPEN : `class-for-open`,
OPTION : `class-for-option`,
OPTION_TAG : `class-for-option-tag`,
OPTIONS_WRAPPER : `class-for-list-wrapper`,
PLACEHOLDER : `class-for-placeholder`,
PLUG : `class-for-ios-plug`,
SECTION : `class-for-section`,
SELECTED : `class-for-option-selected`,
SELECTED_HIDDEN : `class-for-option-selected-hidden`,
SELECTED_DISPLAYED : `class-for-option-selected-displayed`,
SEARCH : `class-for-input-search`,
SEARCH_HIDDEN : `class-for-search-hidden`,
SELECT_TAG : `class-for-select-tag`
},
data : dataObject,
defaultEmpty : true,
defaultValue : defaultValue,
defaultIndex : defaultIndex,
disableArrow : false,
keepChangesOnDestroy : false,
multiple : false,
multipleTags : false,
multipleMessage : '(Multiple Items Selected)',
noMoreOptionsMessage : 'No more options to add',
noMoreResultsMessage : 'No matches found',
onChange : function( e, valueArray ){},
onClose : function( e, valueArray ){},
onComponentDidMount : function(){},
onComponentWillUnmount : function(){},
onFirstTouch : function( e ){},
onInit : function(){},
onInputChange : function( e ){},
onOpen : function( e, valueArray ){},
openOnHover : false,
placeholder : 'Please choose an option',
search : false,
selectDataOverride : false
}
allowHTML
- (boolean) Renders the data text as HTML. With this option enabled, any api call that must compare text will need the exact html in order to be a matchclasses
- (object) Custom CSS classes for Flounder DOM elements (overrides defaults; only the classes specified will be overridden).data
- (array) select box options to build in the select box. Can be organized various waysdefaultEmpty
- (boolean) first in priority, this makes the flounder start with a blank valueless optiondefaultValue
- (string) Sets the default value to the passed value but only if it matches one of the select box options. Multi-tag select boxes only support placeholdersdefaultIndex
- (number) Sets the default option to the passed index but only if it exists. This overrides defaultValue. Multi-tag select boxes only support placeholders.disableArrow
- (boolean) does not add the dropdown arrow elementkeepChangesOnDestroy
- (boolean) Determines whether on destroy the old element is restored, or the flounder changes to the select box are kept. This only applies when the initial element for flounder is a select boxmultiple
- (boolean) Determines whether it is a multi-select box or singlemultipleTags
- (boolean) Determines how a multi-select box is displayedmultipleMessage
- (string) If there are no tags, this is the message that will be displayed in the selected area when there are multiple options selectednoMoreOptionsMessage
- message to display when there are no option left (default : 'No more options to add' )noMoreResultsMessage
- message to display when there are no results left after a search (default : 'No matches found' )onChange
- (function) Triggered when the selection is changedonClose
- (function) Triggered when the selectbox is closedonComponentDidMount
- (function) Triggered when the selectbox is finished buildingonComponentWillUnmount
- (function) Triggered right before flounder is removed from the domonFirstTouch
- (function) Triggered the first time flounder is interacted with. An example usage would be calling an api for a list of data to populate a drop down, but waiting to see if the user interacts with itonInit
- (function) Triggered when the selectbox is initiated, but before it's builtonInputChange
- (function) Triggered when someone types in a search box. note: this will do nothing if search is not enabled.onOpen
- (function) Triggered when the selectbox is openedopenOnHover
- (boolean) replaces click to open action with hoverplaceholder
- (string) Builds a blank option with the placeholder text that is selected by default. This overrides defaultIndexsearch
- (boolean) Determines whether the select box is searchableselectDataOverride
- (boolean) If this is true, flounder will ignore sleect box options tags and just apply the passed data
IMPORTANT DEFAULT PRIORITY
1 ) placeholder
2 ) defaultIndex
3 ) defaultValue
4 ) whatever is at index 0
Building the select box
selectbox data must be passed as an array of objects
[
{
text : 'probably the string you want to see',
value : 'return value',
description : 'a longer description of this element', // optional, string
extraClass : 'extra--classname', // optional, string
disabled : false // optional, boolean
},
...
]
or a simple array of strings. The passed text will be both the text and the value. There would be no description in this case
[
'value 1',
'value 2',
'value 3',
...
]
or, if you want section headers. You can even add uncatagorized things intermingled
[
{
header : header1,
data : [ option1, option2, ... ]
},
{
text : 'probably the string you want to see',
value : 'return value',
description : 'a longer description of this element'
},
{
header : header2,
data : [ option1, option2, ... ]
},
...
]
all extra properties passed in an option that are not shown here will be added as data attributes for the sake of reference later. The data can be accessed in the init (before building) as this.data if they need reformatting or filtering.
API
These functions are intended for use in the user provided event callbacks
this.buildFromUrl( url, callback )
this.clickByIndex( index, multiple* )
this.clickByText( text, multiple* )
this.clickByValue( value, multiple* )
this.deselectAll( silent )
this.destroy()
this.disable( bool* )
this.disableByIndex( index )
this.disableByText( text )
this.disableByValue( value )
this.enableByIndex( index )
this.enableByText( text )
this.enableByValue( value )
this.getData( num* )
this.getSelected()
this.getSelectedValues()
this.loadDataFromUrl( url, callback )
this.props
this.rebuild( data*, props* )
this.refs
this.setByIndex( index, multiple* )
this.setByText( text, multiple* )
this.setByValue( value, multiple* )
*optional
buildFromUrl( url, callback )
loads data from a remote address, passes it to a callback, then builds the flounder objectclickByIndex( index, multiple )
sets the item with the passed index as selected. If multiple is true and it is a multi-select box, it is selected additionally. Otherwise it's selected instead. This accepts arrays as well. Without multiple equaling true it will only select the last option. This fires the onClick event. A negative index will start counting from the end.clickByText( text, multiple )
sets the item with the passed text as selected. If multiple is true and it is a multi-select box, it is selected additionally. Otherwise it's selected instead. This accepts arrays as well. Without multiple equaling true it will only select the last option. This fires the onClick eventclickByValue( value, multiple )
sets the item with the passed value as selected. If multiple is true and it is a multi-select box, it is selected additionally. Otherwise it's selected instead. This accepts arrays as well. Without multiple equaling true it will only select the last option. This fires the onClick eventdeselectAll( silent )
deselects all data. Fires one change event when done deselecting all. whilesilent
= true, this event will be suppresseddestroy()
removes event listeners, then flounder. this will return the element to it's original statedisable( bool )
disables or reenables flounderdisableByIndex( index )
disables a flounder option by index. A negative index will start counting from the end.disableByText( text )
disables a flounder option by textdisableByValue( value )
disables a flounder option by valueenableByIndex( index )
enables a flounder option by index. A negative index will start counting from the end.enableByText( text )
enables a flounder option by textenableByValue( value )
enables a flounder option by valuegetData( num )
returns the option element and the div element at a specified index as an object{ option : option element, div : div element }
. If no number is given, it will return all data.getSelected()
returns the currently selected option tags in an arraygetSelectedValues()
returns the currently selected values in an arrayloadDataFromUrl( url, callback )
loads data from a remote address and returns it to a passed callback.props
the props set in the initial constructorrebuild( data, props )
rebuilds the select box options with new or altered data. If props are set, this completely rebuilds flounder. Here, props do not necessarily need to include data. If props include data, the data argument can be omitted. Both data and props are optional (rebuild w/ current options).refs
contains references to all flounder elementssetByIndex( index, multiple )
sets the item with the passed index as selected. If multiple is true and it is a multi-select box, it is selected additionally. Otherwise it's selected instead. This accepts arrays as well. Without multiple equaling true it will only select the last option. This does not fire the onClick event. A negative index will start counting from the end.setByText( text, multiple )
sets the item with the passed text as selected. If multiple is true and it is a multi-select box, it is selected additionally. Otherwise it's selected instead. This accepts arrays as well. Without multiple equaling true it will only select the last option. This does not fire the onClick event.setByValue( value, multiple )
sets the item with the passed value as selected. If multiple is true and it is a multi-select box, it is selected additionally. Otherwise it's selected instead. This accepts arrays as well. Without multiple equaling true it will only select the last option. This does not fire the onClick event.
npm scripts
bash
creates thedist
folder and copiesflounder-structure.css
to itbuild
runsbash
,gulp
andtest:unit:coverage:cli
gulp
runs bash and compiles flounderlint
checks the code with eslinttest
runs ling and then a coverage testtest:unit:coverage
runs theistanbul
tests and opens the browser reporttest:unit:coverage:cli
runs theistanbul
tests on the command lineversionBump
bumps the version by 0.0.1
Contributing
Development of Flounder requires node '7.0.0' or higher.
Flounder's branch structure goes as follows:
release
- contains stavle including the dist files. this is the branch that is used to make the npm and git releasesmaster
- latest stable git repo. This is like release but without the noise of the dist filesdev
- current development branch. This is where feature branches should branch fromfeature branches - these branches come from
dev
, are branched for a specific geature or bug, then get merged back intodev
Releasing
When you release a new verion, commit it to master, then commit it to release. It must be released from the release
branch. It is the only branch that commits the dist files
We gladly accept and review any pull-requests into the current dev
branch. Feel free! :heart:
Otherwise, if you just want to talk, we are very easy to get a hold of!
- Slack: flounder.slack.com
- Email: [email protected]
- Web: http://flounderjs.com/
- Git: https://github.com/sociomantic-tsunami/flounder/
This project adheres to the Contributor Covenant. By participating, you are expected to honor this code.
Need to report something? [email protected]
Example
Given the example data:
var data = [
{
cssClass : 'select-filters',
id : 'All',
isTaxonomy : true,
text : 'All'
},
{
cssClass : 'category',
id : 'category',
isTaxonomy : true,
text : 'Categories'
},
{
cssClass : 'tag',
id : 'tag',
isTaxonomy : true,
text : 'Tags'
}
];
a vanilla flounder
flounder can be attached to basically anything
new flounder( document.getElementById( 'example' ), {
placeholder : 'placeholders!',
onInit : function()
{
var res = [];
data.forEach( function( dataObj )
{
res.push( {
text : dataObj.text,
value : dataObj.id
} );
} );
this.data = res;
}
} );
The result of these is shown here (only styled with the structural css)
closed
open menu
1 selected
See more examples on the demo page
Change Log
1.3.0
performance improvements for large datasets
- debounced search
- defer calling focus on flounder main div and search input
- addSelectKeyListener no longer called when search is enabled
- removed calls to Array.prototype.slice
- test event functions/hooks are defined before calling
- use display:none to hide options filtered by search
- move user-select:none CSS rule
build
- fixes extraClass for default selected option
utils
- scrollTo fixes/improvements
api
- no longer adds disabled class to selectedDisplayed on disable(true)
fix the license file name
1.2.1
tests
- test coverage brought back to 100%
release
- coverage data is no longer included in the release
search
- fixes multitag search performance
1.2.0
Flounder
- moved multitag search input location inside multitag list
- extraClass is added to displayed option
- removed redundant MULTIPLE_SELECTED CSS class
api
- deselectAll fixes
build
- makes a copy of props.data to prevent unwanted mutation
- search input has tab index -1
events
- disallows selecting disabled options by typing
- checkEnterOnSearch fires onChange
- checkFlounderKeypress stops ENTER propagation
- clickSet explicitly closes the dropdown list
search
- section headers hidden when no results
- pressing ENTER on exact match selects that option
- No more results message fixes
1.1.1
- tests
- lint fixed
- test coverage brought back to 100%
1.1.0
Flounder
- last of the
0.8.5
changes merged in - added eslint requirements
- removed duplicate methods
- last of the
default
- placeholder tweak for the flounder-react
config
- added configurable noMoreOptionsMessage && noMoreResultsMessage messages
api
- onSelect changed to onChange. Deprication warning added. Will be removed 2.0.0
1.0.1
- just a readme fix
1.0.0
Flounder
- branch structure reorganized
- Flounder now only handles one element
- new Flounder always returns a instance of Flounder
- Flounder will warn if it drops elements
- some methods moved to events.js because that's obviously where they live
- Flounder now gets Flounder.find() to apply build multiples. This accepts anything array-like, elements, and selector strings
- internal refactoring
- dropped support for node 4.1
events
- multiTags now support aria
- multiTags now support keyboard navigation
- keyboard navigation flow / tag selection optimized
- fixed focus toggleOpen from multipleTags to search box
- tabbing away now closes the menu
- fixed multitag focus
- fixed multitag search with empty results
api
- buildFromUrl now returns a placeholder array
build
- multiTag construction added to build
- changed build order of DOM elements to fix multiTag tab order
- fixed a selectOption class bug
- adjusted default search indent settings
search
- improved imteraction between tags and search box
readme
- npm scripts added
tests
- removed qunit
- added mocha
- added istanbul
Older Changes
To keep the length of this file down, older changes are here