Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
M
Materialize
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
CI / CD
CI / CD
Pipelines
Schedules
Registry
Registry
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
jedife
Materialize
Commits
6f8cb4b0
Commit
6f8cb4b0
authored
May 19, 2017
by
Artem Larionov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Materialize.select.js
parents
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
587 additions
and
0 deletions
+587
-0
Materialize.select.js
Materialize.select.js
+587
-0
No files found.
Materialize.select.js
0 → 100644
View file @
6f8cb4b0
//;// Required for Meteor package, the use of window prevents export by Meteor
(
function
(
window
){
if
(
window
.
Package
){
Materialize
=
{};
}
else
{
window
.
Materialize
=
{};
}
})(
window
);
Materialize
.
guid
=
(
function
()
{
function
s4
()
{
return
Math
.
floor
((
1
+
Math
.
random
())
*
0x10000
)
.
toString
(
16
)
.
substring
(
1
);
}
return
function
()
{
return
s4
()
+
s4
()
+
'-'
+
s4
()
+
'-'
+
s4
()
+
'-'
+
s4
()
+
'-'
+
s4
()
+
s4
()
+
s4
();
};
})();
(
function
(
$
)
{
// Add posibility to scroll to selected option
// usefull for select for example
$
.
fn
.
scrollTo
=
function
(
elem
)
{
$
(
this
).
scrollTop
(
$
(
this
).
scrollTop
()
-
$
(
this
).
offset
().
top
+
$
(
elem
).
offset
().
top
);
return
this
;
};
$
.
fn
.
dropdown
=
function
(
option
)
{
var
defaults
=
{
inDuration
:
300
,
outDuration
:
225
,
constrain_width
:
true
,
// Constrains width of dropdown to the activator
hover
:
false
,
gutter
:
0
,
// Spacing from edge
belowOrigin
:
false
,
alignment
:
'left'
};
this
.
each
(
function
(){
var
origin
=
$
(
this
);
var
popup
=
option
.
popup
;
var
options
=
$
.
extend
({},
defaults
,
option
);
var
isFocused
=
false
;
// Dropdown menu
var
activates
=
$
(
"#"
+
origin
.
attr
(
'data-activates'
));
function
updateOptions
()
{
if
(
origin
.
data
(
'induration'
)
!==
undefined
)
options
.
inDuration
=
origin
.
data
(
'inDuration'
);
if
(
origin
.
data
(
'outduration'
)
!==
undefined
)
options
.
outDuration
=
origin
.
data
(
'outDuration'
);
if
(
origin
.
data
(
'constrainwidth'
)
!==
undefined
)
options
.
constrain_width
=
origin
.
data
(
'constrainwidth'
);
if
(
origin
.
data
(
'hover'
)
!==
undefined
)
options
.
hover
=
origin
.
data
(
'hover'
);
if
(
origin
.
data
(
'gutter'
)
!==
undefined
)
options
.
gutter
=
origin
.
data
(
'gutter'
);
if
(
origin
.
data
(
'beloworigin'
)
!==
undefined
)
options
.
belowOrigin
=
origin
.
data
(
'beloworigin'
);
if
(
origin
.
data
(
'alignment'
)
!==
undefined
)
options
.
alignment
=
origin
.
data
(
'alignment'
);
}
updateOptions
();
// Attach dropdown to its activator
origin
.
after
(
activates
);
/*
Helper function to position and resize dropdown.
Used in hover and click handler.
*/
function
placeDropdown
(
eventType
)
{
// Check for simultaneous focus and click events.
if
(
eventType
===
'focus'
)
{
isFocused
=
true
;
}
// Check html data attributes
updateOptions
();
// Set Dropdown state
activates
.
addClass
(
'active'
);
origin
.
addClass
(
'active'
);
// Constrain width
if
(
options
.
constrain_width
===
true
)
{
activates
.
css
(
'width'
,
origin
.
outerWidth
());
}
else
{
activates
.
css
(
'white-space'
,
'nowrap'
);
}
// Offscreen detection
var
windowHeight
=
window
.
innerHeight
;
var
originHeight
=
origin
.
innerHeight
();
var
offsetLeft
=
origin
.
offset
().
left
;
var
offsetTop
=
origin
.
offset
().
top
-
$
(
window
).
scrollTop
();
var
currAlignment
=
options
.
alignment
;
var
gutterSpacing
=
0
;
var
leftPosition
=
0
;
// Below Origin
var
verticalOffset
=
0
;
if
(
options
.
belowOrigin
===
true
)
{
verticalOffset
=
originHeight
;
}
// Check for scrolling positioned container.
var
scrollOffset
=
0
;
var
wrapper
=
origin
.
parent
();
if
(
!
wrapper
.
is
(
'body'
)
&&
wrapper
[
0
].
scrollHeight
>
wrapper
[
0
].
clientHeight
)
{
scrollOffset
=
wrapper
[
0
].
scrollTop
;
}
if
(
offsetLeft
+
activates
.
innerWidth
()
>
$
(
window
).
width
())
{
// Dropdown goes past screen on right, force right alignment
currAlignment
=
'right'
;
}
else
if
(
offsetLeft
-
activates
.
innerWidth
()
+
origin
.
innerWidth
()
<
0
)
{
// Dropdown goes past screen on left, force left alignment
currAlignment
=
'left'
;
}
// Vertical bottom offscreen detection
var
popupHeight
=
popup
&&
popup
.
innerHeight
()
?
popup
.
innerHeight
()
:
0
;
if
((
offsetTop
+
activates
.
innerHeight
()
>
windowHeight
)
||
(
popupHeight
&&
(
offsetTop
+
activates
.
innerHeight
()
>
popupHeight
)))
{
// If going upwards still goes offscreen, just crop height of dropdown.
if
(
offsetTop
+
originHeight
-
activates
.
innerHeight
()
<
0
)
{
var
adjustedHeight
=
windowHeight
-
offsetTop
-
verticalOffset
;
activates
.
css
(
'max-height'
,
adjustedHeight
);
}
else
{
// Flow upwards.
if
(
!
verticalOffset
)
{
verticalOffset
+=
originHeight
;
}
verticalOffset
-=
activates
.
innerHeight
();
}
}
// Handle edge alignment
if
(
currAlignment
===
'left'
)
{
gutterSpacing
=
options
.
gutter
;
leftPosition
=
origin
.
position
().
left
+
gutterSpacing
;
}
else
if
(
currAlignment
===
'right'
)
{
var
offsetRight
=
origin
.
position
().
left
+
origin
.
outerWidth
()
-
activates
.
outerWidth
();
gutterSpacing
=
-
options
.
gutter
;
leftPosition
=
offsetRight
+
gutterSpacing
;
}
// Position dropdown
activates
.
css
({
position
:
'absolute'
,
top
:
origin
.
position
().
top
+
verticalOffset
+
scrollOffset
,
left
:
leftPosition
});
// Show dropdown
activates
.
stop
(
true
,
true
).
css
(
'opacity'
,
0
)
.
slideDown
({
queue
:
false
,
duration
:
options
.
inDuration
,
easing
:
'easeOutCubic'
,
complete
:
function
()
{
$
(
this
).
css
(
'height'
,
''
).
trigger
(
'jspShowDropdown'
);
}
})
.
animate
(
{
opacity
:
1
},
{
queue
:
false
,
duration
:
options
.
inDuration
,
easing
:
'easeOutSine'
});
}
function
hideDropdown
()
{
// Check for simultaneous focus and click events.
isFocused
=
false
;
activates
.
fadeOut
(
options
.
outDuration
);
activates
.
removeClass
(
'active'
);
origin
.
removeClass
(
'active'
);
setTimeout
(
function
()
{
activates
.
css
(
'max-height'
,
''
);
},
options
.
outDuration
);
}
// Hover
if
(
options
.
hover
)
{
var
open
=
false
;
origin
.
unbind
(
'click.'
+
origin
.
attr
(
'id'
));
// Hover handler to show dropdown
origin
.
on
(
'mouseenter'
,
function
(
e
){
// Mouse over
if
(
open
===
false
)
{
placeDropdown
();
open
=
true
;
}
});
origin
.
on
(
'mouseleave'
,
function
(
e
){
// If hover on origin then to something other than dropdown content, then close
var
toEl
=
e
.
toElement
||
e
.
relatedTarget
;
// added browser compatibility for target element
if
(
!
$
(
toEl
).
closest
(
'.dropdown-content'
).
is
(
activates
))
{
activates
.
stop
(
true
,
true
);
hideDropdown
();
open
=
false
;
}
});
activates
.
on
(
'mouseleave'
,
function
(
e
){
// Mouse out
var
toEl
=
e
.
toElement
||
e
.
relatedTarget
;
if
(
!
$
(
toEl
).
closest
(
'.dropdown-button'
).
is
(
origin
))
{
activates
.
stop
(
true
,
true
);
hideDropdown
();
open
=
false
;
}
});
// Click
}
else
{
// Click handler to show dropdown
origin
.
unbind
(
'click.'
+
origin
.
attr
(
'id'
));
origin
.
bind
(
'click.'
+
origin
.
attr
(
'id'
),
function
(
e
){
if
(
!
isFocused
)
{
if
(
origin
[
0
]
==
e
.
currentTarget
&&
!
origin
.
hasClass
(
'active'
)
&&
(
$
(
e
.
target
).
closest
(
'.dropdown-content'
).
length
===
0
))
{
e
.
preventDefault
();
// Prevents button click from moving window
placeDropdown
(
'click'
);
}
// If origin is clicked and menu is open, close menu
else
if
(
origin
.
hasClass
(
'active'
))
{
hideDropdown
();
$
(
document
).
unbind
(
'click.'
+
activates
.
attr
(
'id'
)
+
' touchstart.'
+
activates
.
attr
(
'id'
));
}
// If menu open, add click close handler to document
if
(
activates
.
hasClass
(
'active'
))
{
$
(
document
).
bind
(
'click.'
+
activates
.
attr
(
'id'
)
+
' touchstart.'
+
activates
.
attr
(
'id'
),
function
(
e
)
{
if
(
!
activates
.
is
(
e
.
target
)
&&
!
origin
.
is
(
e
.
target
)
&&
(
!
origin
.
find
(
e
.
target
).
length
)
)
{
hideDropdown
();
$
(
document
).
unbind
(
'click.'
+
activates
.
attr
(
'id'
)
+
' touchstart.'
+
activates
.
attr
(
'id'
));
}
});
}
}
});
}
// End else
// Listen to open and close event - useful for select component
origin
.
on
(
'open'
,
function
(
e
,
eventType
)
{
placeDropdown
(
eventType
);
});
origin
.
on
(
'close'
,
hideDropdown
);
});
};
// End dropdown plugin
/*******************
* Select Plugin *
******************/
$
.
fn
.
material_select
=
function
(
callback
,
optionAdvanced
)
{
optionAdvanced
=
optionAdvanced
||
{};
$
(
this
).
each
(
function
(){
var
$select
=
$
(
this
);
if
(
$select
.
hasClass
(
'browser-default'
))
{
return
;
// Continue to next (return false breaks out of entire loop)
}
var
multiple
=
$select
.
attr
(
'multiple'
)
?
true
:
false
,
lastID
=
$select
.
data
(
'select-id'
);
// Tear down structure if Select needs to be rebuilt
if
(
lastID
)
{
$select
.
parent
().
find
(
'span.caret'
).
remove
();
$select
.
parent
().
find
(
'input'
).
remove
();
$select
.
unwrap
();
$
(
'ul#select-options-'
+
lastID
).
remove
();
}
// If destroying the select, remove the selelct-id and reset it to it's uninitialized state.
if
(
callback
===
'destroy'
)
{
$select
.
data
(
'select-id'
,
null
).
removeClass
(
'initialized'
);
return
;
}
var
uniqueID
=
Materialize
.
guid
();
$select
.
data
(
'select-id'
,
uniqueID
);
var
wrapper
=
$
(
'<div class="select-wrapper"></div>'
);
wrapper
.
addClass
(
$select
.
attr
(
'class'
));
var
options
=
$
(
'<ul id="select-options-'
+
uniqueID
+
'" class="dropdown-content select-dropdown '
+
(
multiple
?
'multiple-select-dropdown'
:
''
)
+
'"></ul>'
),
selectChildren
=
$select
.
children
(
'option, optgroup'
),
valuesSelected
=
[],
optionsHover
=
false
;
var
label
=
$select
.
find
(
'option:selected'
).
html
()
||
$select
.
find
(
'option:first'
).
html
()
||
""
;
// Function that renders and appends the option taking into
// account type and possible image icon.
var
appendOptionWithIcon
=
function
(
select
,
option
,
type
)
{
// Add disabled attr if disabled
var
disabledClass
=
(
option
.
is
(
':disabled'
))
?
'disabled '
:
''
;
var
optgroupClass
=
(
type
===
'optgroup-option'
)
?
'optgroup-option '
:
''
;
// add icons
var
icon_url
=
option
.
data
(
'icon'
);
var
classes
=
option
.
attr
(
'class'
);
if
(
!!
icon_url
)
{
var
classString
=
''
;
if
(
!!
classes
)
classString
=
' class="'
+
classes
+
'"'
;
// Check for multiple type.
if
(
type
===
'multiple'
)
{
options
.
append
(
$
(
'<li class="'
+
disabledClass
+
'"><img src="'
+
icon_url
+
'"'
+
classString
+
'><span><input type="checkbox"'
+
disabledClass
+
'/><label></label>'
+
option
.
html
()
+
'</span></li>'
));
}
else
{
options
.
append
(
$
(
'<li class="'
+
disabledClass
+
optgroupClass
+
'"><img src="'
+
icon_url
+
'"'
+
classString
+
'><span>'
+
option
.
html
()
+
'</span></li>'
));
}
return
true
;
}
// Check for multiple type.
if
(
type
===
'multiple'
)
{
options
.
append
(
$
(
'<li class="'
+
disabledClass
+
'"><span><input type="checkbox"'
+
disabledClass
+
'/><label></label>'
+
option
.
html
()
+
'</span></li>'
));
}
else
{
options
.
append
(
$
(
'<li class="'
+
disabledClass
+
optgroupClass
+
'"><span>'
+
option
.
html
()
+
'</span></li>'
));
}
};
/* Create dropdown structure. */
if
(
selectChildren
.
length
)
{
selectChildren
.
each
(
function
()
{
if
(
$
(
this
).
is
(
'option'
))
{
// Direct descendant option.
if
(
multiple
)
{
appendOptionWithIcon
(
$select
,
$
(
this
),
'multiple'
);
}
else
{
appendOptionWithIcon
(
$select
,
$
(
this
));
}
}
else
if
(
$
(
this
).
is
(
'optgroup'
))
{
// Optgroup.
var
selectOptions
=
$
(
this
).
children
(
'option'
);
options
.
append
(
$
(
'<li class="optgroup"><span>'
+
$
(
this
).
attr
(
'label'
)
+
'</span></li>'
));
selectOptions
.
each
(
function
()
{
appendOptionWithIcon
(
$select
,
$
(
this
),
'optgroup-option'
);
});
}
});
}
options
.
find
(
'li:not(.optgroup)'
).
each
(
function
(
i
)
{
$
(
this
).
click
(
function
(
e
)
{
// Check if option element is disabled
if
(
!
$
(
this
).
hasClass
(
'disabled'
)
&&
!
$
(
this
).
hasClass
(
'optgroup'
))
{
var
selected
=
true
;
if
(
multiple
)
{
$
(
'input[type="checkbox"]'
,
this
).
prop
(
'checked'
,
function
(
i
,
v
)
{
return
!
v
;
});
selected
=
toggleEntryFromArray
(
valuesSelected
,
$
(
this
).
index
(),
$select
);
$newSelect
.
trigger
(
'focus'
);
}
else
{
options
.
find
(
'li'
).
removeClass
(
'active'
);
$
(
this
).
toggleClass
(
'active'
);
$newSelect
.
val
(
$
(
this
).
text
());
}
activateOption
(
options
,
$
(
this
));
$select
.
find
(
'option'
).
eq
(
i
).
prop
(
'selected'
,
selected
);
// Trigger onchange() event
$select
.
trigger
(
'change'
);
if
(
typeof
callback
!==
'undefined'
)
callback
();
}
e
.
stopPropagation
();
});
});
// Wrap Elements
$select
.
wrap
(
wrapper
);
// Add Select Display Element
var
dropdownIcon
=
$
(
'<span class="caret">▼</span>'
);
if
(
$select
.
is
(
':disabled'
))
dropdownIcon
.
addClass
(
'disabled'
);
// escape double quotes
var
sanitizedLabelHtml
=
label
.
replace
(
/"/g
,
'"'
);
var
$newSelect
=
$
(
'<input type="text" class="select-dropdown" readonly="true" '
+
((
$select
.
is
(
':disabled'
))
?
'disabled'
:
''
)
+
' data-activates="select-options-'
+
uniqueID
+
'" value="'
+
sanitizedLabelHtml
+
'"/>'
);
$select
.
before
(
$newSelect
);
$newSelect
.
before
(
dropdownIcon
);
$newSelect
.
after
(
options
);
// Check if section element is disabled
if
(
!
$select
.
is
(
':disabled'
))
{
var
optionDefault
=
{
'hover'
:
false
,
'closeOnClick'
:
false
};
$newSelect
.
dropdown
(
$
.
extend
(
optionDefault
,
optionAdvanced
));
}
// Copy tabindex
if
(
$select
.
attr
(
'tabindex'
))
{
$
(
$newSelect
[
0
]).
attr
(
'tabindex'
,
$select
.
attr
(
'tabindex'
));
}
$select
.
addClass
(
'initialized'
);
$newSelect
.
on
({
'focus'
:
function
(){
if
(
$
(
'ul.select-dropdown'
).
not
(
options
[
0
]).
is
(
':visible'
))
{
$
(
'input.select-dropdown'
).
trigger
(
'close'
);
}
if
(
!
options
.
is
(
':visible'
))
{
$
(
this
).
trigger
(
'open'
,
[
'focus'
]);
var
label
=
$
(
this
).
val
();
var
selectedOption
=
options
.
find
(
'li'
).
filter
(
function
()
{
return
$
(
this
).
text
().
toLowerCase
()
===
label
.
toLowerCase
();
})[
0
];
activateOption
(
options
,
selectedOption
);
}
},
'click'
:
function
(
e
){
e
.
stopPropagation
();
}
});
$newSelect
.
on
(
'blur'
,
function
()
{
if
(
!
multiple
)
{
$
(
this
).
trigger
(
'close'
);
}
options
.
find
(
'li.selected'
).
removeClass
(
'selected'
);
});
options
.
hover
(
function
()
{
optionsHover
=
true
;
},
function
()
{
optionsHover
=
false
;
});
options
.
on
(
'jspScrollToElement'
,
function
(
e
,
elem
)
{
options
.
scrollTo
(
elem
);
});
$
(
window
).
on
({
'click'
:
function
()
{
multiple
&&
(
optionsHover
||
$newSelect
.
trigger
(
'close'
));
}
});
// Add initial multiple selections.
if
(
multiple
)
{
$select
.
find
(
"option:selected:not(:disabled)"
).
each
(
function
()
{
var
index
=
$
(
this
).
index
();
toggleEntryFromArray
(
valuesSelected
,
index
,
$select
);
options
.
find
(
"li"
).
eq
(
index
).
find
(
":checkbox"
).
prop
(
"checked"
,
true
);
});
}
// Make option as selected and scroll to selected position
var
activateOption
=
function
(
collection
,
newOption
)
{
if
(
newOption
)
{
collection
.
find
(
'li.selected'
).
removeClass
(
'selected'
);
var
option
=
$
(
newOption
);
option
.
addClass
(
'selected'
);
options
.
trigger
(
'jspScrollToElement'
,
option
);
}
};
// Allow user to search by typing
// this array is cleared after 1 second
var
filterQuery
=
[],
onKeyDown
=
function
(
e
){
// TAB - switch to another input
if
(
e
.
which
==
9
){
$newSelect
.
trigger
(
'close'
);
return
;
}
// ARROW DOWN WHEN SELECT IS CLOSED - open select options
if
(
e
.
which
==
40
&&
!
options
.
is
(
':visible'
)){
$newSelect
.
trigger
(
'open'
);
return
;
}
// ENTER WHEN SELECT IS CLOSED - submit form
if
(
e
.
which
==
13
&&
!
options
.
is
(
':visible'
)){
return
;
}
e
.
preventDefault
();
// CASE WHEN USER TYPE LETTERS
var
letter
=
String
.
fromCharCode
(
e
.
which
).
toLowerCase
(),
nonLetters
=
[
9
,
13
,
27
,
38
,
40
];
if
(
letter
&&
(
nonLetters
.
indexOf
(
e
.
which
)
===
-
1
))
{
filterQuery
.
push
(
letter
);
var
string
=
filterQuery
.
join
(
''
),
newOption
=
options
.
find
(
'li'
).
filter
(
function
()
{
return
$
(
this
).
text
().
toLowerCase
().
indexOf
(
string
)
===
0
;
})[
0
];
if
(
newOption
)
{
activateOption
(
options
,
newOption
);
}
}
// ENTER - select option and close when select options are opened
if
(
e
.
which
==
13
)
{
var
activeOption
=
options
.
find
(
'li.selected:not(.disabled)'
)[
0
];
if
(
activeOption
){
$
(
activeOption
).
trigger
(
'click'
);
if
(
!
multiple
)
{
$newSelect
.
trigger
(
'close'
);
}
}
}
// ARROW DOWN - move to next not disabled option
if
(
e
.
which
==
40
)
{
if
(
options
.
find
(
'li.selected'
).
length
)
{
newOption
=
options
.
find
(
'li.selected'
).
next
(
'li:not(.disabled)'
)[
0
];
}
else
{
newOption
=
options
.
find
(
'li:not(.disabled)'
)[
0
];
}
activateOption
(
options
,
newOption
);
}
// ESC - close options
if
(
e
.
which
==
27
)
{
$newSelect
.
trigger
(
'close'
);
}
// ARROW UP - move to previous not disabled option
if
(
e
.
which
==
38
)
{
newOption
=
options
.
find
(
'li.selected'
).
prev
(
'li:not(.disabled)'
)[
0
];
if
(
newOption
)
activateOption
(
options
,
newOption
);
}
// Automaticaly clean filter query so user can search again by starting letters
setTimeout
(
function
(){
filterQuery
=
[];
},
1000
);
};
$newSelect
.
on
(
'keydown'
,
onKeyDown
);
});
function
toggleEntryFromArray
(
entriesArray
,
entryIndex
,
select
)
{
var
index
=
entriesArray
.
indexOf
(
entryIndex
),
notAdded
=
index
===
-
1
;
if
(
notAdded
)
{
entriesArray
.
push
(
entryIndex
);
}
else
{
entriesArray
.
splice
(
index
,
1
);
}
select
.
siblings
(
'ul.dropdown-content'
).
find
(
'li'
).
eq
(
entryIndex
).
toggleClass
(
'active'
);
// use notAdded instead of true (to detect if the option is selected or not)
select
.
find
(
'option'
).
eq
(
entryIndex
).
prop
(
'selected'
,
notAdded
);
setValueToInput
(
entriesArray
,
select
);
return
notAdded
;
}
function
setValueToInput
(
entriesArray
,
select
)
{
var
value
=
''
;
for
(
var
i
=
0
,
count
=
entriesArray
.
length
;
i
<
count
;
i
++
)
{
var
text
=
select
.
find
(
'option'
).
eq
(
entriesArray
[
i
]).
text
();
i
===
0
?
value
+=
text
:
value
+=
', '
+
text
;
}
if
(
value
===
''
)
{
value
=
select
.
find
(
'option:disabled'
).
eq
(
0
).
text
();
}
select
.
siblings
(
'input.select-dropdown'
).
val
(
value
);
}
};
})
(
jQuery
);
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment