Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
PSW_II_PARIWISATA_TRANSPORTASI
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Proyek_PSW_II_PARIWISATA
PSW_II_PARIWISATA_TRANSPORTASI
Commits
4c11fa36
Commit
4c11fa36
authored
Jun 06, 2020
by
11319009_Pratiwi Sibarani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upload New File
parent
97b7829a
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
3563 additions
and
0 deletions
+3563
-0
isotope.pkgd.js
transportasi/public/vendor/isotope-layout/isotope.pkgd.js
+3563
-0
No files found.
transportasi/public/vendor/isotope-layout/isotope.pkgd.js
0 → 100644
View file @
4c11fa36
/*!
* Isotope PACKAGED v3.0.6
*
* Licensed GPLv3 for open source use
* or Isotope Commercial License for commercial use
*
* https://isotope.metafizzy.co
* Copyright 2010-2018 Metafizzy
*/
/**
* Bridget makes jQuery widgets
* v2.0.1
* MIT license
*/
/* jshint browser: true, strict: true, undef: true, unused: true */
(
function
(
window
,
factory
)
{
// universal module definition
/*jshint strict: false */
/* globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'jquery-bridget/jquery-bridget'
,[
'jquery'
],
function
(
jQuery
)
{
return
factory
(
window
,
jQuery
);
});
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
window
,
require
(
'jquery'
)
);
}
else
{
// browser global
window
.
jQueryBridget
=
factory
(
window
,
window
.
jQuery
);
}
}(
window
,
function
factory
(
window
,
jQuery
)
{
'use strict'
;
// ----- utils ----- //
var
arraySlice
=
Array
.
prototype
.
slice
;
// helper function for logging errors
// $.error breaks jQuery chaining
var
console
=
window
.
console
;
var
logError
=
typeof
console
==
'undefined'
?
function
()
{}
:
function
(
message
)
{
console
.
error
(
message
);
};
// ----- jQueryBridget ----- //
function
jQueryBridget
(
namespace
,
PluginClass
,
$
)
{
$
=
$
||
jQuery
||
window
.
jQuery
;
if
(
!
$
)
{
return
;
}
// add option method -> $().plugin('option', {...})
if
(
!
PluginClass
.
prototype
.
option
)
{
// option setter
PluginClass
.
prototype
.
option
=
function
(
opts
)
{
// bail out if not an object
if
(
!
$
.
isPlainObject
(
opts
)
){
return
;
}
this
.
options
=
$
.
extend
(
true
,
this
.
options
,
opts
);
};
}
// make jQuery plugin
$
.
fn
[
namespace
]
=
function
(
arg0
/*, arg1 */
)
{
if
(
typeof
arg0
==
'string'
)
{
// method call $().plugin( 'methodName', { options } )
// shift arguments by 1
var
args
=
arraySlice
.
call
(
arguments
,
1
);
return
methodCall
(
this
,
arg0
,
args
);
}
// just $().plugin({ options })
plainCall
(
this
,
arg0
);
return
this
;
};
// $().plugin('methodName')
function
methodCall
(
$elems
,
methodName
,
args
)
{
var
returnValue
;
var
pluginMethodStr
=
'$().'
+
namespace
+
'("'
+
methodName
+
'")'
;
$elems
.
each
(
function
(
i
,
elem
)
{
// get instance
var
instance
=
$
.
data
(
elem
,
namespace
);
if
(
!
instance
)
{
logError
(
namespace
+
' not initialized. Cannot call methods, i.e. '
+
pluginMethodStr
);
return
;
}
var
method
=
instance
[
methodName
];
if
(
!
method
||
methodName
.
charAt
(
0
)
==
'_'
)
{
logError
(
pluginMethodStr
+
' is not a valid method'
);
return
;
}
// apply method, get return value
var
value
=
method
.
apply
(
instance
,
args
);
// set return value if value is returned, use only first value
returnValue
=
returnValue
===
undefined
?
value
:
returnValue
;
});
return
returnValue
!==
undefined
?
returnValue
:
$elems
;
}
function
plainCall
(
$elems
,
options
)
{
$elems
.
each
(
function
(
i
,
elem
)
{
var
instance
=
$
.
data
(
elem
,
namespace
);
if
(
instance
)
{
// set options & init
instance
.
option
(
options
);
instance
.
_init
();
}
else
{
// initialize new instance
instance
=
new
PluginClass
(
elem
,
options
);
$
.
data
(
elem
,
namespace
,
instance
);
}
});
}
updateJQuery
(
$
);
}
// ----- updateJQuery ----- //
// set $.bridget for v1 backwards compatibility
function
updateJQuery
(
$
)
{
if
(
!
$
||
(
$
&&
$
.
bridget
)
)
{
return
;
}
$
.
bridget
=
jQueryBridget
;
}
updateJQuery
(
jQuery
||
window
.
jQuery
);
// ----- ----- //
return
jQueryBridget
;
}));
/**
* EvEmitter v1.1.0
* Lil' event emitter
* MIT License
*/
/* jshint unused: true, undef: true, strict: true */
(
function
(
global
,
factory
)
{
// universal module definition
/* jshint strict: false */
/* globals define, module, window */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD - RequireJS
define
(
'ev-emitter/ev-emitter'
,
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS - Browserify, Webpack
module
.
exports
=
factory
();
}
else
{
// Browser globals
global
.
EvEmitter
=
factory
();
}
}(
typeof
window
!=
'undefined'
?
window
:
this
,
function
()
{
function
EvEmitter
()
{}
var
proto
=
EvEmitter
.
prototype
;
proto
.
on
=
function
(
eventName
,
listener
)
{
if
(
!
eventName
||
!
listener
)
{
return
;
}
// set events hash
var
events
=
this
.
_events
=
this
.
_events
||
{};
// set listeners array
var
listeners
=
events
[
eventName
]
=
events
[
eventName
]
||
[];
// only add once
if
(
listeners
.
indexOf
(
listener
)
==
-
1
)
{
listeners
.
push
(
listener
);
}
return
this
;
};
proto
.
once
=
function
(
eventName
,
listener
)
{
if
(
!
eventName
||
!
listener
)
{
return
;
}
// add event
this
.
on
(
eventName
,
listener
);
// set once flag
// set onceEvents hash
var
onceEvents
=
this
.
_onceEvents
=
this
.
_onceEvents
||
{};
// set onceListeners object
var
onceListeners
=
onceEvents
[
eventName
]
=
onceEvents
[
eventName
]
||
{};
// set flag
onceListeners
[
listener
]
=
true
;
return
this
;
};
proto
.
off
=
function
(
eventName
,
listener
)
{
var
listeners
=
this
.
_events
&&
this
.
_events
[
eventName
];
if
(
!
listeners
||
!
listeners
.
length
)
{
return
;
}
var
index
=
listeners
.
indexOf
(
listener
);
if
(
index
!=
-
1
)
{
listeners
.
splice
(
index
,
1
);
}
return
this
;
};
proto
.
emitEvent
=
function
(
eventName
,
args
)
{
var
listeners
=
this
.
_events
&&
this
.
_events
[
eventName
];
if
(
!
listeners
||
!
listeners
.
length
)
{
return
;
}
// copy over to avoid interference if .off() in listener
listeners
=
listeners
.
slice
(
0
);
args
=
args
||
[];
// once stuff
var
onceListeners
=
this
.
_onceEvents
&&
this
.
_onceEvents
[
eventName
];
for
(
var
i
=
0
;
i
<
listeners
.
length
;
i
++
)
{
var
listener
=
listeners
[
i
]
var
isOnce
=
onceListeners
&&
onceListeners
[
listener
];
if
(
isOnce
)
{
// remove listener
// remove before trigger to prevent recursion
this
.
off
(
eventName
,
listener
);
// unset once flag
delete
onceListeners
[
listener
];
}
// trigger listener
listener
.
apply
(
this
,
args
);
}
return
this
;
};
proto
.
allOff
=
function
()
{
delete
this
.
_events
;
delete
this
.
_onceEvents
;
};
return
EvEmitter
;
}));
/*!
* getSize v2.0.3
* measure size of elements
* MIT license
*/
/* jshint browser: true, strict: true, undef: true, unused: true */
/* globals console: false */
(
function
(
window
,
factory
)
{
/* jshint strict: false */
/* globals define, module */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'get-size/get-size'
,
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
();
}
else
{
// browser global
window
.
getSize
=
factory
();
}
})(
window
,
function
factory
()
{
'use strict'
;
// -------------------------- helpers -------------------------- //
// get a number from a string, not a percentage
function
getStyleSize
(
value
)
{
var
num
=
parseFloat
(
value
);
// not a percent like '100%', and a number
var
isValid
=
value
.
indexOf
(
'%'
)
==
-
1
&&
!
isNaN
(
num
);
return
isValid
&&
num
;
}
function
noop
()
{}
var
logError
=
typeof
console
==
'undefined'
?
noop
:
function
(
message
)
{
console
.
error
(
message
);
};
// -------------------------- measurements -------------------------- //
var
measurements
=
[
'paddingLeft'
,
'paddingRight'
,
'paddingTop'
,
'paddingBottom'
,
'marginLeft'
,
'marginRight'
,
'marginTop'
,
'marginBottom'
,
'borderLeftWidth'
,
'borderRightWidth'
,
'borderTopWidth'
,
'borderBottomWidth'
];
var
measurementsLength
=
measurements
.
length
;
function
getZeroSize
()
{
var
size
=
{
width
:
0
,
height
:
0
,
innerWidth
:
0
,
innerHeight
:
0
,
outerWidth
:
0
,
outerHeight
:
0
};
for
(
var
i
=
0
;
i
<
measurementsLength
;
i
++
)
{
var
measurement
=
measurements
[
i
];
size
[
measurement
]
=
0
;
}
return
size
;
}
// -------------------------- getStyle -------------------------- //
/**
* getStyle, get style of element, check for Firefox bug
* https://bugzilla.mozilla.org/show_bug.cgi?id=548397
*/
function
getStyle
(
elem
)
{
var
style
=
getComputedStyle
(
elem
);
if
(
!
style
)
{
logError
(
'Style returned '
+
style
+
'. Are you running this code in a hidden iframe on Firefox? '
+
'See https://bit.ly/getsizebug1'
);
}
return
style
;
}
// -------------------------- setup -------------------------- //
var
isSetup
=
false
;
var
isBoxSizeOuter
;
/**
* setup
* check isBoxSizerOuter
* do on first getSize() rather than on page load for Firefox bug
*/
function
setup
()
{
// setup once
if
(
isSetup
)
{
return
;
}
isSetup
=
true
;
// -------------------------- box sizing -------------------------- //
/**
* Chrome & Safari measure the outer-width on style.width on border-box elems
* IE11 & Firefox<29 measures the inner-width
*/
var
div
=
document
.
createElement
(
'div'
);
div
.
style
.
width
=
'200px'
;
div
.
style
.
padding
=
'1px 2px 3px 4px'
;
div
.
style
.
borderStyle
=
'solid'
;
div
.
style
.
borderWidth
=
'1px 2px 3px 4px'
;
div
.
style
.
boxSizing
=
'border-box'
;
var
body
=
document
.
body
||
document
.
documentElement
;
body
.
appendChild
(
div
);
var
style
=
getStyle
(
div
);
// round value for browser zoom. desandro/masonry#928
isBoxSizeOuter
=
Math
.
round
(
getStyleSize
(
style
.
width
)
)
==
200
;
getSize
.
isBoxSizeOuter
=
isBoxSizeOuter
;
body
.
removeChild
(
div
);
}
// -------------------------- getSize -------------------------- //
function
getSize
(
elem
)
{
setup
();
// use querySeletor if elem is string
if
(
typeof
elem
==
'string'
)
{
elem
=
document
.
querySelector
(
elem
);
}
// do not proceed on non-objects
if
(
!
elem
||
typeof
elem
!=
'object'
||
!
elem
.
nodeType
)
{
return
;
}
var
style
=
getStyle
(
elem
);
// if hidden, everything is 0
if
(
style
.
display
==
'none'
)
{
return
getZeroSize
();
}
var
size
=
{};
size
.
width
=
elem
.
offsetWidth
;
size
.
height
=
elem
.
offsetHeight
;
var
isBorderBox
=
size
.
isBorderBox
=
style
.
boxSizing
==
'border-box'
;
// get all measurements
for
(
var
i
=
0
;
i
<
measurementsLength
;
i
++
)
{
var
measurement
=
measurements
[
i
];
var
value
=
style
[
measurement
];
var
num
=
parseFloat
(
value
);
// any 'auto', 'medium' value will be 0
size
[
measurement
]
=
!
isNaN
(
num
)
?
num
:
0
;
}
var
paddingWidth
=
size
.
paddingLeft
+
size
.
paddingRight
;
var
paddingHeight
=
size
.
paddingTop
+
size
.
paddingBottom
;
var
marginWidth
=
size
.
marginLeft
+
size
.
marginRight
;
var
marginHeight
=
size
.
marginTop
+
size
.
marginBottom
;
var
borderWidth
=
size
.
borderLeftWidth
+
size
.
borderRightWidth
;
var
borderHeight
=
size
.
borderTopWidth
+
size
.
borderBottomWidth
;
var
isBorderBoxSizeOuter
=
isBorderBox
&&
isBoxSizeOuter
;
// overwrite width and height if we can get it from style
var
styleWidth
=
getStyleSize
(
style
.
width
);
if
(
styleWidth
!==
false
)
{
size
.
width
=
styleWidth
+
// add padding and border unless it's already including it
(
isBorderBoxSizeOuter
?
0
:
paddingWidth
+
borderWidth
);
}
var
styleHeight
=
getStyleSize
(
style
.
height
);
if
(
styleHeight
!==
false
)
{
size
.
height
=
styleHeight
+
// add padding and border unless it's already including it
(
isBorderBoxSizeOuter
?
0
:
paddingHeight
+
borderHeight
);
}
size
.
innerWidth
=
size
.
width
-
(
paddingWidth
+
borderWidth
);
size
.
innerHeight
=
size
.
height
-
(
paddingHeight
+
borderHeight
);
size
.
outerWidth
=
size
.
width
+
marginWidth
;
size
.
outerHeight
=
size
.
height
+
marginHeight
;
return
size
;
}
return
getSize
;
});
/**
* matchesSelector v2.0.2
* matchesSelector( element, '.selector' )
* MIT license
*/
/*jshint browser: true, strict: true, undef: true, unused: true */
(
function
(
window
,
factory
)
{
/*global define: false, module: false */
'use strict'
;
// universal module definition
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'desandro-matches-selector/matches-selector'
,
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
();
}
else
{
// browser global
window
.
matchesSelector
=
factory
();
}
}(
window
,
function
factory
()
{
'use strict'
;
var
matchesMethod
=
(
function
()
{
var
ElemProto
=
window
.
Element
.
prototype
;
// check for the standard method name first
if
(
ElemProto
.
matches
)
{
return
'matches'
;
}
// check un-prefixed
if
(
ElemProto
.
matchesSelector
)
{
return
'matchesSelector'
;
}
// check vendor prefixes
var
prefixes
=
[
'webkit'
,
'moz'
,
'ms'
,
'o'
];
for
(
var
i
=
0
;
i
<
prefixes
.
length
;
i
++
)
{
var
prefix
=
prefixes
[
i
];
var
method
=
prefix
+
'MatchesSelector'
;
if
(
ElemProto
[
method
]
)
{
return
method
;
}
}
})();
return
function
matchesSelector
(
elem
,
selector
)
{
return
elem
[
matchesMethod
](
selector
);
};
}));
/**
* Fizzy UI utils v2.0.7
* MIT license
*/
/*jshint browser: true, undef: true, unused: true, strict: true */
(
function
(
window
,
factory
)
{
// universal module definition
/*jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'fizzy-ui-utils/utils'
,[
'desandro-matches-selector/matches-selector'
],
function
(
matchesSelector
)
{
return
factory
(
window
,
matchesSelector
);
});
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
window
,
require
(
'desandro-matches-selector'
)
);
}
else
{
// browser global
window
.
fizzyUIUtils
=
factory
(
window
,
window
.
matchesSelector
);
}
}(
window
,
function
factory
(
window
,
matchesSelector
)
{
var
utils
=
{};
// ----- extend ----- //
// extends objects
utils
.
extend
=
function
(
a
,
b
)
{
for
(
var
prop
in
b
)
{
a
[
prop
]
=
b
[
prop
];
}
return
a
;
};
// ----- modulo ----- //
utils
.
modulo
=
function
(
num
,
div
)
{
return
(
(
num
%
div
)
+
div
)
%
div
;
};
// ----- makeArray ----- //
var
arraySlice
=
Array
.
prototype
.
slice
;
// turn element or nodeList into an array
utils
.
makeArray
=
function
(
obj
)
{
if
(
Array
.
isArray
(
obj
)
)
{
// use object if already an array
return
obj
;
}
// return empty array if undefined or null. #6
if
(
obj
===
null
||
obj
===
undefined
)
{
return
[];
}
var
isArrayLike
=
typeof
obj
==
'object'
&&
typeof
obj
.
length
==
'number'
;
if
(
isArrayLike
)
{
// convert nodeList to array
return
arraySlice
.
call
(
obj
);
}
// array of single index
return
[
obj
];
};
// ----- removeFrom ----- //
utils
.
removeFrom
=
function
(
ary
,
obj
)
{
var
index
=
ary
.
indexOf
(
obj
);
if
(
index
!=
-
1
)
{
ary
.
splice
(
index
,
1
);
}
};
// ----- getParent ----- //
utils
.
getParent
=
function
(
elem
,
selector
)
{
while
(
elem
.
parentNode
&&
elem
!=
document
.
body
)
{
elem
=
elem
.
parentNode
;
if
(
matchesSelector
(
elem
,
selector
)
)
{
return
elem
;
}
}
};
// ----- getQueryElement ----- //
// use element as selector string
utils
.
getQueryElement
=
function
(
elem
)
{
if
(
typeof
elem
==
'string'
)
{
return
document
.
querySelector
(
elem
);
}
return
elem
;
};
// ----- handleEvent ----- //
// enable .ontype to trigger from .addEventListener( elem, 'type' )
utils
.
handleEvent
=
function
(
event
)
{
var
method
=
'on'
+
event
.
type
;
if
(
this
[
method
]
)
{
this
[
method
](
event
);
}
};
// ----- filterFindElements ----- //
utils
.
filterFindElements
=
function
(
elems
,
selector
)
{
// make array of elems
elems
=
utils
.
makeArray
(
elems
);
var
ffElems
=
[];
elems
.
forEach
(
function
(
elem
)
{
// check that elem is an actual element
if
(
!
(
elem
instanceof
HTMLElement
)
)
{
return
;
}
// add elem if no selector
if
(
!
selector
)
{
ffElems
.
push
(
elem
);
return
;
}
// filter & find items if we have a selector
// filter
if
(
matchesSelector
(
elem
,
selector
)
)
{
ffElems
.
push
(
elem
);
}
// find children
var
childElems
=
elem
.
querySelectorAll
(
selector
);
// concat childElems to filterFound array
for
(
var
i
=
0
;
i
<
childElems
.
length
;
i
++
)
{
ffElems
.
push
(
childElems
[
i
]
);
}
});
return
ffElems
;
};
// ----- debounceMethod ----- //
utils
.
debounceMethod
=
function
(
_class
,
methodName
,
threshold
)
{
threshold
=
threshold
||
100
;
// original method
var
method
=
_class
.
prototype
[
methodName
];
var
timeoutName
=
methodName
+
'Timeout'
;
_class
.
prototype
[
methodName
]
=
function
()
{
var
timeout
=
this
[
timeoutName
];
clearTimeout
(
timeout
);
var
args
=
arguments
;
var
_this
=
this
;
this
[
timeoutName
]
=
setTimeout
(
function
()
{
method
.
apply
(
_this
,
args
);
delete
_this
[
timeoutName
];
},
threshold
);
};
};
// ----- docReady ----- //
utils
.
docReady
=
function
(
callback
)
{
var
readyState
=
document
.
readyState
;
if
(
readyState
==
'complete'
||
readyState
==
'interactive'
)
{
// do async to allow for other scripts to run. metafizzy/flickity#441
setTimeout
(
callback
);
}
else
{
document
.
addEventListener
(
'DOMContentLoaded'
,
callback
);
}
};
// ----- htmlInit ----- //
// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
utils
.
toDashed
=
function
(
str
)
{
return
str
.
replace
(
/
(
.
)([
A-Z
])
/g
,
function
(
match
,
$1
,
$2
)
{
return
$1
+
'-'
+
$2
;
}).
toLowerCase
();
};
var
console
=
window
.
console
;
/**
* allow user to initialize classes via [data-namespace] or .js-namespace class
* htmlInit( Widget, 'widgetName' )
* options are parsed from data-namespace-options
*/
utils
.
htmlInit
=
function
(
WidgetClass
,
namespace
)
{
utils
.
docReady
(
function
()
{
var
dashedNamespace
=
utils
.
toDashed
(
namespace
);
var
dataAttr
=
'data-'
+
dashedNamespace
;
var
dataAttrElems
=
document
.
querySelectorAll
(
'['
+
dataAttr
+
']'
);
var
jsDashElems
=
document
.
querySelectorAll
(
'.js-'
+
dashedNamespace
);
var
elems
=
utils
.
makeArray
(
dataAttrElems
)
.
concat
(
utils
.
makeArray
(
jsDashElems
)
);
var
dataOptionsAttr
=
dataAttr
+
'-options'
;
var
jQuery
=
window
.
jQuery
;
elems
.
forEach
(
function
(
elem
)
{
var
attr
=
elem
.
getAttribute
(
dataAttr
)
||
elem
.
getAttribute
(
dataOptionsAttr
);
var
options
;
try
{
options
=
attr
&&
JSON
.
parse
(
attr
);
}
catch
(
error
)
{
// log error, do not initialize
if
(
console
)
{
console
.
error
(
'Error parsing '
+
dataAttr
+
' on '
+
elem
.
className
+
': '
+
error
);
}
return
;
}
// initialize
var
instance
=
new
WidgetClass
(
elem
,
options
);
// make available via $().data('namespace')
if
(
jQuery
)
{
jQuery
.
data
(
elem
,
namespace
,
instance
);
}
});
});
};
// ----- ----- //
return
utils
;
}));
/**
* Outlayer Item
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/* globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD - RequireJS
define
(
'outlayer/item'
,[
'ev-emitter/ev-emitter'
,
'get-size/get-size'
],
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS - Browserify, Webpack
module
.
exports
=
factory
(
require
(
'ev-emitter'
),
require
(
'get-size'
)
);
}
else
{
// browser global
window
.
Outlayer
=
{};
window
.
Outlayer
.
Item
=
factory
(
window
.
EvEmitter
,
window
.
getSize
);
}
}(
window
,
function
factory
(
EvEmitter
,
getSize
)
{
'use strict'
;
// ----- helpers ----- //
function
isEmptyObj
(
obj
)
{
for
(
var
prop
in
obj
)
{
return
false
;
}
prop
=
null
;
return
true
;
}
// -------------------------- CSS3 support -------------------------- //
var
docElemStyle
=
document
.
documentElement
.
style
;
var
transitionProperty
=
typeof
docElemStyle
.
transition
==
'string'
?
'transition'
:
'WebkitTransition'
;
var
transformProperty
=
typeof
docElemStyle
.
transform
==
'string'
?
'transform'
:
'WebkitTransform'
;
var
transitionEndEvent
=
{
WebkitTransition
:
'webkitTransitionEnd'
,
transition
:
'transitionend'
}[
transitionProperty
];
// cache all vendor properties that could have vendor prefix
var
vendorProperties
=
{
transform
:
transformProperty
,
transition
:
transitionProperty
,
transitionDuration
:
transitionProperty
+
'Duration'
,
transitionProperty
:
transitionProperty
+
'Property'
,
transitionDelay
:
transitionProperty
+
'Delay'
};
// -------------------------- Item -------------------------- //
function
Item
(
element
,
layout
)
{
if
(
!
element
)
{
return
;
}
this
.
element
=
element
;
// parent layout class, i.e. Masonry, Isotope, or Packery
this
.
layout
=
layout
;
this
.
position
=
{
x
:
0
,
y
:
0
};
this
.
_create
();
}
// inherit EvEmitter
var
proto
=
Item
.
prototype
=
Object
.
create
(
EvEmitter
.
prototype
);
proto
.
constructor
=
Item
;
proto
.
_create
=
function
()
{
// transition objects
this
.
_transn
=
{
ingProperties
:
{},
clean
:
{},
onEnd
:
{}
};
this
.
css
({
position
:
'absolute'
});
};
// trigger specified handler for event type
proto
.
handleEvent
=
function
(
event
)
{
var
method
=
'on'
+
event
.
type
;
if
(
this
[
method
]
)
{
this
[
method
](
event
);
}
};
proto
.
getSize
=
function
()
{
this
.
size
=
getSize
(
this
.
element
);
};
/**
* apply CSS styles to element
* @param {Object} style
*/
proto
.
css
=
function
(
style
)
{
var
elemStyle
=
this
.
element
.
style
;
for
(
var
prop
in
style
)
{
// use vendor property if available
var
supportedProp
=
vendorProperties
[
prop
]
||
prop
;
elemStyle
[
supportedProp
]
=
style
[
prop
];
}
};
// measure position, and sets it
proto
.
getPosition
=
function
()
{
var
style
=
getComputedStyle
(
this
.
element
);
var
isOriginLeft
=
this
.
layout
.
_getOption
(
'originLeft'
);
var
isOriginTop
=
this
.
layout
.
_getOption
(
'originTop'
);
var
xValue
=
style
[
isOriginLeft
?
'left'
:
'right'
];
var
yValue
=
style
[
isOriginTop
?
'top'
:
'bottom'
];
var
x
=
parseFloat
(
xValue
);
var
y
=
parseFloat
(
yValue
);
// convert percent to pixels
var
layoutSize
=
this
.
layout
.
size
;
if
(
xValue
.
indexOf
(
'%'
)
!=
-
1
)
{
x
=
(
x
/
100
)
*
layoutSize
.
width
;
}
if
(
yValue
.
indexOf
(
'%'
)
!=
-
1
)
{
y
=
(
y
/
100
)
*
layoutSize
.
height
;
}
// clean up 'auto' or other non-integer values
x
=
isNaN
(
x
)
?
0
:
x
;
y
=
isNaN
(
y
)
?
0
:
y
;
// remove padding from measurement
x
-=
isOriginLeft
?
layoutSize
.
paddingLeft
:
layoutSize
.
paddingRight
;
y
-=
isOriginTop
?
layoutSize
.
paddingTop
:
layoutSize
.
paddingBottom
;
this
.
position
.
x
=
x
;
this
.
position
.
y
=
y
;
};
// set settled position, apply padding
proto
.
layoutPosition
=
function
()
{
var
layoutSize
=
this
.
layout
.
size
;
var
style
=
{};
var
isOriginLeft
=
this
.
layout
.
_getOption
(
'originLeft'
);
var
isOriginTop
=
this
.
layout
.
_getOption
(
'originTop'
);
// x
var
xPadding
=
isOriginLeft
?
'paddingLeft'
:
'paddingRight'
;
var
xProperty
=
isOriginLeft
?
'left'
:
'right'
;
var
xResetProperty
=
isOriginLeft
?
'right'
:
'left'
;
var
x
=
this
.
position
.
x
+
layoutSize
[
xPadding
];
// set in percentage or pixels
style
[
xProperty
]
=
this
.
getXValue
(
x
);
// reset other property
style
[
xResetProperty
]
=
''
;
// y
var
yPadding
=
isOriginTop
?
'paddingTop'
:
'paddingBottom'
;
var
yProperty
=
isOriginTop
?
'top'
:
'bottom'
;
var
yResetProperty
=
isOriginTop
?
'bottom'
:
'top'
;
var
y
=
this
.
position
.
y
+
layoutSize
[
yPadding
];
// set in percentage or pixels
style
[
yProperty
]
=
this
.
getYValue
(
y
);
// reset other property
style
[
yResetProperty
]
=
''
;
this
.
css
(
style
);
this
.
emitEvent
(
'layout'
,
[
this
]
);
};
proto
.
getXValue
=
function
(
x
)
{
var
isHorizontal
=
this
.
layout
.
_getOption
(
'horizontal'
);
return
this
.
layout
.
options
.
percentPosition
&&
!
isHorizontal
?
(
(
x
/
this
.
layout
.
size
.
width
)
*
100
)
+
'%'
:
x
+
'px'
;
};
proto
.
getYValue
=
function
(
y
)
{
var
isHorizontal
=
this
.
layout
.
_getOption
(
'horizontal'
);
return
this
.
layout
.
options
.
percentPosition
&&
isHorizontal
?
(
(
y
/
this
.
layout
.
size
.
height
)
*
100
)
+
'%'
:
y
+
'px'
;
};
proto
.
_transitionTo
=
function
(
x
,
y
)
{
this
.
getPosition
();
// get current x & y from top/left
var
curX
=
this
.
position
.
x
;
var
curY
=
this
.
position
.
y
;
var
didNotMove
=
x
==
this
.
position
.
x
&&
y
==
this
.
position
.
y
;
// save end position
this
.
setPosition
(
x
,
y
);
// if did not move and not transitioning, just go to layout
if
(
didNotMove
&&
!
this
.
isTransitioning
)
{
this
.
layoutPosition
();
return
;
}
var
transX
=
x
-
curX
;
var
transY
=
y
-
curY
;
var
transitionStyle
=
{};
transitionStyle
.
transform
=
this
.
getTranslate
(
transX
,
transY
);
this
.
transition
({
to
:
transitionStyle
,
onTransitionEnd
:
{
transform
:
this
.
layoutPosition
},
isCleaning
:
true
});
};
proto
.
getTranslate
=
function
(
x
,
y
)
{
// flip cooridinates if origin on right or bottom
var
isOriginLeft
=
this
.
layout
.
_getOption
(
'originLeft'
);
var
isOriginTop
=
this
.
layout
.
_getOption
(
'originTop'
);
x
=
isOriginLeft
?
x
:
-
x
;
y
=
isOriginTop
?
y
:
-
y
;
return
'translate3d('
+
x
+
'px, '
+
y
+
'px, 0)'
;
};
// non transition + transform support
proto
.
goTo
=
function
(
x
,
y
)
{
this
.
setPosition
(
x
,
y
);
this
.
layoutPosition
();
};
proto
.
moveTo
=
proto
.
_transitionTo
;
proto
.
setPosition
=
function
(
x
,
y
)
{
this
.
position
.
x
=
parseFloat
(
x
);
this
.
position
.
y
=
parseFloat
(
y
);
};
// ----- transition ----- //
/**
* @param {Object} style - CSS
* @param {Function} onTransitionEnd
*/
// non transition, just trigger callback
proto
.
_nonTransition
=
function
(
args
)
{
this
.
css
(
args
.
to
);
if
(
args
.
isCleaning
)
{
this
.
_removeStyles
(
args
.
to
);
}
for
(
var
prop
in
args
.
onTransitionEnd
)
{
args
.
onTransitionEnd
[
prop
].
call
(
this
);
}
};
/**
* proper transition
* @param {Object} args - arguments
* @param {Object} to - style to transition to
* @param {Object} from - style to start transition from
* @param {Boolean} isCleaning - removes transition styles after transition
* @param {Function} onTransitionEnd - callback
*/
proto
.
transition
=
function
(
args
)
{
// redirect to nonTransition if no transition duration
if
(
!
parseFloat
(
this
.
layout
.
options
.
transitionDuration
)
)
{
this
.
_nonTransition
(
args
);
return
;
}
var
_transition
=
this
.
_transn
;
// keep track of onTransitionEnd callback by css property
for
(
var
prop
in
args
.
onTransitionEnd
)
{
_transition
.
onEnd
[
prop
]
=
args
.
onTransitionEnd
[
prop
];
}
// keep track of properties that are transitioning
for
(
prop
in
args
.
to
)
{
_transition
.
ingProperties
[
prop
]
=
true
;
// keep track of properties to clean up when transition is done
if
(
args
.
isCleaning
)
{
_transition
.
clean
[
prop
]
=
true
;
}
}
// set from styles
if
(
args
.
from
)
{
this
.
css
(
args
.
from
);
// force redraw. http://blog.alexmaccaw.com/css-transitions
var
h
=
this
.
element
.
offsetHeight
;
// hack for JSHint to hush about unused var
h
=
null
;
}
// enable transition
this
.
enableTransition
(
args
.
to
);
// set styles that are transitioning
this
.
css
(
args
.
to
);
this
.
isTransitioning
=
true
;
};
// dash before all cap letters, including first for
// WebkitTransform => -webkit-transform
function
toDashedAll
(
str
)
{
return
str
.
replace
(
/
([
A-Z
])
/g
,
function
(
$1
)
{
return
'-'
+
$1
.
toLowerCase
();
});
}
var
transitionProps
=
'opacity,'
+
toDashedAll
(
transformProperty
);
proto
.
enableTransition
=
function
(
/* style */
)
{
// HACK changing transitionProperty during a transition
// will cause transition to jump
if
(
this
.
isTransitioning
)
{
return
;
}
// make `transition: foo, bar, baz` from style object
// HACK un-comment this when enableTransition can work
// while a transition is happening
// var transitionValues = [];
// for ( var prop in style ) {
// // dash-ify camelCased properties like WebkitTransition
// prop = vendorProperties[ prop ] || prop;
// transitionValues.push( toDashedAll( prop ) );
// }
// munge number to millisecond, to match stagger
var
duration
=
this
.
layout
.
options
.
transitionDuration
;
duration
=
typeof
duration
==
'number'
?
duration
+
'ms'
:
duration
;
// enable transition styles
this
.
css
({
transitionProperty
:
transitionProps
,
transitionDuration
:
duration
,
transitionDelay
:
this
.
staggerDelay
||
0
});
// listen for transition end event
this
.
element
.
addEventListener
(
transitionEndEvent
,
this
,
false
);
};
// ----- events ----- //
proto
.
onwebkitTransitionEnd
=
function
(
event
)
{
this
.
ontransitionend
(
event
);
};
proto
.
onotransitionend
=
function
(
event
)
{
this
.
ontransitionend
(
event
);
};
// properties that I munge to make my life easier
var
dashedVendorProperties
=
{
'-webkit-transform'
:
'transform'
};
proto
.
ontransitionend
=
function
(
event
)
{
// disregard bubbled events from children
if
(
event
.
target
!==
this
.
element
)
{
return
;
}
var
_transition
=
this
.
_transn
;
// get property name of transitioned property, convert to prefix-free
var
propertyName
=
dashedVendorProperties
[
event
.
propertyName
]
||
event
.
propertyName
;
// remove property that has completed transitioning
delete
_transition
.
ingProperties
[
propertyName
];
// check if any properties are still transitioning
if
(
isEmptyObj
(
_transition
.
ingProperties
)
)
{
// all properties have completed transitioning
this
.
disableTransition
();
}
// clean style
if
(
propertyName
in
_transition
.
clean
)
{
// clean up style
this
.
element
.
style
[
event
.
propertyName
]
=
''
;
delete
_transition
.
clean
[
propertyName
];
}
// trigger onTransitionEnd callback
if
(
propertyName
in
_transition
.
onEnd
)
{
var
onTransitionEnd
=
_transition
.
onEnd
[
propertyName
];
onTransitionEnd
.
call
(
this
);
delete
_transition
.
onEnd
[
propertyName
];
}
this
.
emitEvent
(
'transitionEnd'
,
[
this
]
);
};
proto
.
disableTransition
=
function
()
{
this
.
removeTransitionStyles
();
this
.
element
.
removeEventListener
(
transitionEndEvent
,
this
,
false
);
this
.
isTransitioning
=
false
;
};
/**
* removes style property from element
* @param {Object} style
**/
proto
.
_removeStyles
=
function
(
style
)
{
// clean up transition styles
var
cleanStyle
=
{};
for
(
var
prop
in
style
)
{
cleanStyle
[
prop
]
=
''
;
}
this
.
css
(
cleanStyle
);
};
var
cleanTransitionStyle
=
{
transitionProperty
:
''
,
transitionDuration
:
''
,
transitionDelay
:
''
};
proto
.
removeTransitionStyles
=
function
()
{
// remove transition
this
.
css
(
cleanTransitionStyle
);
};
// ----- stagger ----- //
proto
.
stagger
=
function
(
delay
)
{
delay
=
isNaN
(
delay
)
?
0
:
delay
;
this
.
staggerDelay
=
delay
+
'ms'
;
};
// ----- show/hide/remove ----- //
// remove element from DOM
proto
.
removeElem
=
function
()
{
this
.
element
.
parentNode
.
removeChild
(
this
.
element
);
// remove display: none
this
.
css
({
display
:
''
});
this
.
emitEvent
(
'remove'
,
[
this
]
);
};
proto
.
remove
=
function
()
{
// just remove element if no transition support or no transition
if
(
!
transitionProperty
||
!
parseFloat
(
this
.
layout
.
options
.
transitionDuration
)
)
{
this
.
removeElem
();
return
;
}
// start transition
this
.
once
(
'transitionEnd'
,
function
()
{
this
.
removeElem
();
});
this
.
hide
();
};
proto
.
reveal
=
function
()
{
delete
this
.
isHidden
;
// remove display: none
this
.
css
({
display
:
''
});
var
options
=
this
.
layout
.
options
;
var
onTransitionEnd
=
{};
var
transitionEndProperty
=
this
.
getHideRevealTransitionEndProperty
(
'visibleStyle'
);
onTransitionEnd
[
transitionEndProperty
]
=
this
.
onRevealTransitionEnd
;
this
.
transition
({
from
:
options
.
hiddenStyle
,
to
:
options
.
visibleStyle
,
isCleaning
:
true
,
onTransitionEnd
:
onTransitionEnd
});
};
proto
.
onRevealTransitionEnd
=
function
()
{
// check if still visible
// during transition, item may have been hidden
if
(
!
this
.
isHidden
)
{
this
.
emitEvent
(
'reveal'
);
}
};
/**
* get style property use for hide/reveal transition end
* @param {String} styleProperty - hiddenStyle/visibleStyle
* @returns {String}
*/
proto
.
getHideRevealTransitionEndProperty
=
function
(
styleProperty
)
{
var
optionStyle
=
this
.
layout
.
options
[
styleProperty
];
// use opacity
if
(
optionStyle
.
opacity
)
{
return
'opacity'
;
}
// get first property
for
(
var
prop
in
optionStyle
)
{
return
prop
;
}
};
proto
.
hide
=
function
()
{
// set flag
this
.
isHidden
=
true
;
// remove display: none
this
.
css
({
display
:
''
});
var
options
=
this
.
layout
.
options
;
var
onTransitionEnd
=
{};
var
transitionEndProperty
=
this
.
getHideRevealTransitionEndProperty
(
'hiddenStyle'
);
onTransitionEnd
[
transitionEndProperty
]
=
this
.
onHideTransitionEnd
;
this
.
transition
({
from
:
options
.
visibleStyle
,
to
:
options
.
hiddenStyle
,
// keep hidden stuff hidden
isCleaning
:
true
,
onTransitionEnd
:
onTransitionEnd
});
};
proto
.
onHideTransitionEnd
=
function
()
{
// check if still hidden
// during transition, item may have been un-hidden
if
(
this
.
isHidden
)
{
this
.
css
({
display
:
'none'
});
this
.
emitEvent
(
'hide'
);
}
};
proto
.
destroy
=
function
()
{
this
.
css
({
position
:
''
,
left
:
''
,
right
:
''
,
top
:
''
,
bottom
:
''
,
transition
:
''
,
transform
:
''
});
};
return
Item
;
}));
/*!
* Outlayer v2.1.1
* the brains and guts of a layout library
* MIT license
*/
(
function
(
window
,
factory
)
{
'use strict'
;
// universal module definition
/* jshint strict: false */
/* globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD - RequireJS
define
(
'outlayer/outlayer'
,[
'ev-emitter/ev-emitter'
,
'get-size/get-size'
,
'fizzy-ui-utils/utils'
,
'./item'
],
function
(
EvEmitter
,
getSize
,
utils
,
Item
)
{
return
factory
(
window
,
EvEmitter
,
getSize
,
utils
,
Item
);
}
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS - Browserify, Webpack
module
.
exports
=
factory
(
window
,
require
(
'ev-emitter'
),
require
(
'get-size'
),
require
(
'fizzy-ui-utils'
),
require
(
'./item'
)
);
}
else
{
// browser global
window
.
Outlayer
=
factory
(
window
,
window
.
EvEmitter
,
window
.
getSize
,
window
.
fizzyUIUtils
,
window
.
Outlayer
.
Item
);
}
}(
window
,
function
factory
(
window
,
EvEmitter
,
getSize
,
utils
,
Item
)
{
'use strict'
;
// ----- vars ----- //
var
console
=
window
.
console
;
var
jQuery
=
window
.
jQuery
;
var
noop
=
function
()
{};
// -------------------------- Outlayer -------------------------- //
// globally unique identifiers
var
GUID
=
0
;
// internal store of all Outlayer intances
var
instances
=
{};
/**
* @param {Element, String} element
* @param {Object} options
* @constructor
*/
function
Outlayer
(
element
,
options
)
{
var
queryElement
=
utils
.
getQueryElement
(
element
);
if
(
!
queryElement
)
{
if
(
console
)
{
console
.
error
(
'Bad element for '
+
this
.
constructor
.
namespace
+
': '
+
(
queryElement
||
element
)
);
}
return
;
}
this
.
element
=
queryElement
;
// add jQuery
if
(
jQuery
)
{
this
.
$element
=
jQuery
(
this
.
element
);
}
// options
this
.
options
=
utils
.
extend
(
{},
this
.
constructor
.
defaults
);
this
.
option
(
options
);
// add id for Outlayer.getFromElement
var
id
=
++
GUID
;
this
.
element
.
outlayerGUID
=
id
;
// expando
instances
[
id
]
=
this
;
// associate via id
// kick it off
this
.
_create
();
var
isInitLayout
=
this
.
_getOption
(
'initLayout'
);
if
(
isInitLayout
)
{
this
.
layout
();
}
}
// settings are for internal use only
Outlayer
.
namespace
=
'outlayer'
;
Outlayer
.
Item
=
Item
;
// default options
Outlayer
.
defaults
=
{
containerStyle
:
{
position
:
'relative'
},
initLayout
:
true
,
originLeft
:
true
,
originTop
:
true
,
resize
:
true
,
resizeContainer
:
true
,
// item options
transitionDuration
:
'0.4s'
,
hiddenStyle
:
{
opacity
:
0
,
transform
:
'scale(0.001)'
},
visibleStyle
:
{
opacity
:
1
,
transform
:
'scale(1)'
}
};
var
proto
=
Outlayer
.
prototype
;
// inherit EvEmitter
utils
.
extend
(
proto
,
EvEmitter
.
prototype
);
/**
* set options
* @param {Object} opts
*/
proto
.
option
=
function
(
opts
)
{
utils
.
extend
(
this
.
options
,
opts
);
};
/**
* get backwards compatible option value, check old name
*/
proto
.
_getOption
=
function
(
option
)
{
var
oldOption
=
this
.
constructor
.
compatOptions
[
option
];
return
oldOption
&&
this
.
options
[
oldOption
]
!==
undefined
?
this
.
options
[
oldOption
]
:
this
.
options
[
option
];
};
Outlayer
.
compatOptions
=
{
// currentName: oldName
initLayout
:
'isInitLayout'
,
horizontal
:
'isHorizontal'
,
layoutInstant
:
'isLayoutInstant'
,
originLeft
:
'isOriginLeft'
,
originTop
:
'isOriginTop'
,
resize
:
'isResizeBound'
,
resizeContainer
:
'isResizingContainer'
};
proto
.
_create
=
function
()
{
// get items from children
this
.
reloadItems
();
// elements that affect layout, but are not laid out
this
.
stamps
=
[];
this
.
stamp
(
this
.
options
.
stamp
);
// set container style
utils
.
extend
(
this
.
element
.
style
,
this
.
options
.
containerStyle
);
// bind resize method
var
canBindResize
=
this
.
_getOption
(
'resize'
);
if
(
canBindResize
)
{
this
.
bindResize
();
}
};
// goes through all children again and gets bricks in proper order
proto
.
reloadItems
=
function
()
{
// collection of item elements
this
.
items
=
this
.
_itemize
(
this
.
element
.
children
);
};
/**
* turn elements into Outlayer.Items to be used in layout
* @param {Array or NodeList or HTMLElement} elems
* @returns {Array} items - collection of new Outlayer Items
*/
proto
.
_itemize
=
function
(
elems
)
{
var
itemElems
=
this
.
_filterFindItemElements
(
elems
);
var
Item
=
this
.
constructor
.
Item
;
// create new Outlayer Items for collection
var
items
=
[];
for
(
var
i
=
0
;
i
<
itemElems
.
length
;
i
++
)
{
var
elem
=
itemElems
[
i
];
var
item
=
new
Item
(
elem
,
this
);
items
.
push
(
item
);
}
return
items
;
};
/**
* get item elements to be used in layout
* @param {Array or NodeList or HTMLElement} elems
* @returns {Array} items - item elements
*/
proto
.
_filterFindItemElements
=
function
(
elems
)
{
return
utils
.
filterFindElements
(
elems
,
this
.
options
.
itemSelector
);
};
/**
* getter method for getting item elements
* @returns {Array} elems - collection of item elements
*/
proto
.
getItemElements
=
function
()
{
return
this
.
items
.
map
(
function
(
item
)
{
return
item
.
element
;
});
};
// ----- init & layout ----- //
/**
* lays out all items
*/
proto
.
layout
=
function
()
{
this
.
_resetLayout
();
this
.
_manageStamps
();
// don't animate first layout
var
layoutInstant
=
this
.
_getOption
(
'layoutInstant'
);
var
isInstant
=
layoutInstant
!==
undefined
?
layoutInstant
:
!
this
.
_isLayoutInited
;
this
.
layoutItems
(
this
.
items
,
isInstant
);
// flag for initalized
this
.
_isLayoutInited
=
true
;
};
// _init is alias for layout
proto
.
_init
=
proto
.
layout
;
/**
* logic before any new layout
*/
proto
.
_resetLayout
=
function
()
{
this
.
getSize
();
};
proto
.
getSize
=
function
()
{
this
.
size
=
getSize
(
this
.
element
);
};
/**
* get measurement from option, for columnWidth, rowHeight, gutter
* if option is String -> get element from selector string, & get size of element
* if option is Element -> get size of element
* else use option as a number
*
* @param {String} measurement
* @param {String} size - width or height
* @private
*/
proto
.
_getMeasurement
=
function
(
measurement
,
size
)
{
var
option
=
this
.
options
[
measurement
];
var
elem
;
if
(
!
option
)
{
// default to 0
this
[
measurement
]
=
0
;
}
else
{
// use option as an element
if
(
typeof
option
==
'string'
)
{
elem
=
this
.
element
.
querySelector
(
option
);
}
else
if
(
option
instanceof
HTMLElement
)
{
elem
=
option
;
}
// use size of element, if element
this
[
measurement
]
=
elem
?
getSize
(
elem
)[
size
]
:
option
;
}
};
/**
* layout a collection of item elements
* @api public
*/
proto
.
layoutItems
=
function
(
items
,
isInstant
)
{
items
=
this
.
_getItemsForLayout
(
items
);
this
.
_layoutItems
(
items
,
isInstant
);
this
.
_postLayout
();
};
/**
* get the items to be laid out
* you may want to skip over some items
* @param {Array} items
* @returns {Array} items
*/
proto
.
_getItemsForLayout
=
function
(
items
)
{
return
items
.
filter
(
function
(
item
)
{
return
!
item
.
isIgnored
;
});
};
/**
* layout items
* @param {Array} items
* @param {Boolean} isInstant
*/
proto
.
_layoutItems
=
function
(
items
,
isInstant
)
{
this
.
_emitCompleteOnItems
(
'layout'
,
items
);
if
(
!
items
||
!
items
.
length
)
{
// no items, emit event with empty array
return
;
}
var
queue
=
[];
items
.
forEach
(
function
(
item
)
{
// get x/y object from method
var
position
=
this
.
_getItemLayoutPosition
(
item
);
// enqueue
position
.
item
=
item
;
position
.
isInstant
=
isInstant
||
item
.
isLayoutInstant
;
queue
.
push
(
position
);
},
this
);
this
.
_processLayoutQueue
(
queue
);
};
/**
* get item layout position
* @param {Outlayer.Item} item
* @returns {Object} x and y position
*/
proto
.
_getItemLayoutPosition
=
function
(
/* item */
)
{
return
{
x
:
0
,
y
:
0
};
};
/**
* iterate over array and position each item
* Reason being - separating this logic prevents 'layout invalidation'
* thx @paul_irish
* @param {Array} queue
*/
proto
.
_processLayoutQueue
=
function
(
queue
)
{
this
.
updateStagger
();
queue
.
forEach
(
function
(
obj
,
i
)
{
this
.
_positionItem
(
obj
.
item
,
obj
.
x
,
obj
.
y
,
obj
.
isInstant
,
i
);
},
this
);
};
// set stagger from option in milliseconds number
proto
.
updateStagger
=
function
()
{
var
stagger
=
this
.
options
.
stagger
;
if
(
stagger
===
null
||
stagger
===
undefined
)
{
this
.
stagger
=
0
;
return
;
}
this
.
stagger
=
getMilliseconds
(
stagger
);
return
this
.
stagger
;
};
/**
* Sets position of item in DOM
* @param {Outlayer.Item} item
* @param {Number} x - horizontal position
* @param {Number} y - vertical position
* @param {Boolean} isInstant - disables transitions
*/
proto
.
_positionItem
=
function
(
item
,
x
,
y
,
isInstant
,
i
)
{
if
(
isInstant
)
{
// if not transition, just set CSS
item
.
goTo
(
x
,
y
);
}
else
{
item
.
stagger
(
i
*
this
.
stagger
);
item
.
moveTo
(
x
,
y
);
}
};
/**
* Any logic you want to do after each layout,
* i.e. size the container
*/
proto
.
_postLayout
=
function
()
{
this
.
resizeContainer
();
};
proto
.
resizeContainer
=
function
()
{
var
isResizingContainer
=
this
.
_getOption
(
'resizeContainer'
);
if
(
!
isResizingContainer
)
{
return
;
}
var
size
=
this
.
_getContainerSize
();
if
(
size
)
{
this
.
_setContainerMeasure
(
size
.
width
,
true
);
this
.
_setContainerMeasure
(
size
.
height
,
false
);
}
};
/**
* Sets width or height of container if returned
* @returns {Object} size
* @param {Number} width
* @param {Number} height
*/
proto
.
_getContainerSize
=
noop
;
/**
* @param {Number} measure - size of width or height
* @param {Boolean} isWidth
*/
proto
.
_setContainerMeasure
=
function
(
measure
,
isWidth
)
{
if
(
measure
===
undefined
)
{
return
;
}
var
elemSize
=
this
.
size
;
// add padding and border width if border box
if
(
elemSize
.
isBorderBox
)
{
measure
+=
isWidth
?
elemSize
.
paddingLeft
+
elemSize
.
paddingRight
+
elemSize
.
borderLeftWidth
+
elemSize
.
borderRightWidth
:
elemSize
.
paddingBottom
+
elemSize
.
paddingTop
+
elemSize
.
borderTopWidth
+
elemSize
.
borderBottomWidth
;
}
measure
=
Math
.
max
(
measure
,
0
);
this
.
element
.
style
[
isWidth
?
'width'
:
'height'
]
=
measure
+
'px'
;
};
/**
* emit eventComplete on a collection of items events
* @param {String} eventName
* @param {Array} items - Outlayer.Items
*/
proto
.
_emitCompleteOnItems
=
function
(
eventName
,
items
)
{
var
_this
=
this
;
function
onComplete
()
{
_this
.
dispatchEvent
(
eventName
+
'Complete'
,
null
,
[
items
]
);
}
var
count
=
items
.
length
;
if
(
!
items
||
!
count
)
{
onComplete
();
return
;
}
var
doneCount
=
0
;
function
tick
()
{
doneCount
++
;
if
(
doneCount
==
count
)
{
onComplete
();
}
}
// bind callback
items
.
forEach
(
function
(
item
)
{
item
.
once
(
eventName
,
tick
);
});
};
/**
* emits events via EvEmitter and jQuery events
* @param {String} type - name of event
* @param {Event} event - original event
* @param {Array} args - extra arguments
*/
proto
.
dispatchEvent
=
function
(
type
,
event
,
args
)
{
// add original event to arguments
var
emitArgs
=
event
?
[
event
].
concat
(
args
)
:
args
;
this
.
emitEvent
(
type
,
emitArgs
);
if
(
jQuery
)
{
// set this.$element
this
.
$element
=
this
.
$element
||
jQuery
(
this
.
element
);
if
(
event
)
{
// create jQuery event
var
$event
=
jQuery
.
Event
(
event
);
$event
.
type
=
type
;
this
.
$element
.
trigger
(
$event
,
args
);
}
else
{
// just trigger with type if no event available
this
.
$element
.
trigger
(
type
,
args
);
}
}
};
// -------------------------- ignore & stamps -------------------------- //
/**
* keep item in collection, but do not lay it out
* ignored items do not get skipped in layout
* @param {Element} elem
*/
proto
.
ignore
=
function
(
elem
)
{
var
item
=
this
.
getItem
(
elem
);
if
(
item
)
{
item
.
isIgnored
=
true
;
}
};
/**
* return item to layout collection
* @param {Element} elem
*/
proto
.
unignore
=
function
(
elem
)
{
var
item
=
this
.
getItem
(
elem
);
if
(
item
)
{
delete
item
.
isIgnored
;
}
};
/**
* adds elements to stamps
* @param {NodeList, Array, Element, or String} elems
*/
proto
.
stamp
=
function
(
elems
)
{
elems
=
this
.
_find
(
elems
);
if
(
!
elems
)
{
return
;
}
this
.
stamps
=
this
.
stamps
.
concat
(
elems
);
// ignore
elems
.
forEach
(
this
.
ignore
,
this
);
};
/**
* removes elements to stamps
* @param {NodeList, Array, or Element} elems
*/
proto
.
unstamp
=
function
(
elems
)
{
elems
=
this
.
_find
(
elems
);
if
(
!
elems
){
return
;
}
elems
.
forEach
(
function
(
elem
)
{
// filter out removed stamp elements
utils
.
removeFrom
(
this
.
stamps
,
elem
);
this
.
unignore
(
elem
);
},
this
);
};
/**
* finds child elements
* @param {NodeList, Array, Element, or String} elems
* @returns {Array} elems
*/
proto
.
_find
=
function
(
elems
)
{
if
(
!
elems
)
{
return
;
}
// if string, use argument as selector string
if
(
typeof
elems
==
'string'
)
{
elems
=
this
.
element
.
querySelectorAll
(
elems
);
}
elems
=
utils
.
makeArray
(
elems
);
return
elems
;
};
proto
.
_manageStamps
=
function
()
{
if
(
!
this
.
stamps
||
!
this
.
stamps
.
length
)
{
return
;
}
this
.
_getBoundingRect
();
this
.
stamps
.
forEach
(
this
.
_manageStamp
,
this
);
};
// update boundingLeft / Top
proto
.
_getBoundingRect
=
function
()
{
// get bounding rect for container element
var
boundingRect
=
this
.
element
.
getBoundingClientRect
();
var
size
=
this
.
size
;
this
.
_boundingRect
=
{
left
:
boundingRect
.
left
+
size
.
paddingLeft
+
size
.
borderLeftWidth
,
top
:
boundingRect
.
top
+
size
.
paddingTop
+
size
.
borderTopWidth
,
right
:
boundingRect
.
right
-
(
size
.
paddingRight
+
size
.
borderRightWidth
),
bottom
:
boundingRect
.
bottom
-
(
size
.
paddingBottom
+
size
.
borderBottomWidth
)
};
};
/**
* @param {Element} stamp
**/
proto
.
_manageStamp
=
noop
;
/**
* get x/y position of element relative to container element
* @param {Element} elem
* @returns {Object} offset - has left, top, right, bottom
*/
proto
.
_getElementOffset
=
function
(
elem
)
{
var
boundingRect
=
elem
.
getBoundingClientRect
();
var
thisRect
=
this
.
_boundingRect
;
var
size
=
getSize
(
elem
);
var
offset
=
{
left
:
boundingRect
.
left
-
thisRect
.
left
-
size
.
marginLeft
,
top
:
boundingRect
.
top
-
thisRect
.
top
-
size
.
marginTop
,
right
:
thisRect
.
right
-
boundingRect
.
right
-
size
.
marginRight
,
bottom
:
thisRect
.
bottom
-
boundingRect
.
bottom
-
size
.
marginBottom
};
return
offset
;
};
// -------------------------- resize -------------------------- //
// enable event handlers for listeners
// i.e. resize -> onresize
proto
.
handleEvent
=
utils
.
handleEvent
;
/**
* Bind layout to window resizing
*/
proto
.
bindResize
=
function
()
{
window
.
addEventListener
(
'resize'
,
this
);
this
.
isResizeBound
=
true
;
};
/**
* Unbind layout to window resizing
*/
proto
.
unbindResize
=
function
()
{
window
.
removeEventListener
(
'resize'
,
this
);
this
.
isResizeBound
=
false
;
};
proto
.
onresize
=
function
()
{
this
.
resize
();
};
utils
.
debounceMethod
(
Outlayer
,
'onresize'
,
100
);
proto
.
resize
=
function
()
{
// don't trigger if size did not change
// or if resize was unbound. See #9
if
(
!
this
.
isResizeBound
||
!
this
.
needsResizeLayout
()
)
{
return
;
}
this
.
layout
();
};
/**
* check if layout is needed post layout
* @returns Boolean
*/
proto
.
needsResizeLayout
=
function
()
{
var
size
=
getSize
(
this
.
element
);
// check that this.size and size are there
// IE8 triggers resize on body size change, so they might not be
var
hasSizes
=
this
.
size
&&
size
;
return
hasSizes
&&
size
.
innerWidth
!==
this
.
size
.
innerWidth
;
};
// -------------------------- methods -------------------------- //
/**
* add items to Outlayer instance
* @param {Array or NodeList or Element} elems
* @returns {Array} items - Outlayer.Items
**/
proto
.
addItems
=
function
(
elems
)
{
var
items
=
this
.
_itemize
(
elems
);
// add items to collection
if
(
items
.
length
)
{
this
.
items
=
this
.
items
.
concat
(
items
);
}
return
items
;
};
/**
* Layout newly-appended item elements
* @param {Array or NodeList or Element} elems
*/
proto
.
appended
=
function
(
elems
)
{
var
items
=
this
.
addItems
(
elems
);
if
(
!
items
.
length
)
{
return
;
}
// layout and reveal just the new items
this
.
layoutItems
(
items
,
true
);
this
.
reveal
(
items
);
};
/**
* Layout prepended elements
* @param {Array or NodeList or Element} elems
*/
proto
.
prepended
=
function
(
elems
)
{
var
items
=
this
.
_itemize
(
elems
);
if
(
!
items
.
length
)
{
return
;
}
// add items to beginning of collection
var
previousItems
=
this
.
items
.
slice
(
0
);
this
.
items
=
items
.
concat
(
previousItems
);
// start new layout
this
.
_resetLayout
();
this
.
_manageStamps
();
// layout new stuff without transition
this
.
layoutItems
(
items
,
true
);
this
.
reveal
(
items
);
// layout previous items
this
.
layoutItems
(
previousItems
);
};
/**
* reveal a collection of items
* @param {Array of Outlayer.Items} items
*/
proto
.
reveal
=
function
(
items
)
{
this
.
_emitCompleteOnItems
(
'reveal'
,
items
);
if
(
!
items
||
!
items
.
length
)
{
return
;
}
var
stagger
=
this
.
updateStagger
();
items
.
forEach
(
function
(
item
,
i
)
{
item
.
stagger
(
i
*
stagger
);
item
.
reveal
();
});
};
/**
* hide a collection of items
* @param {Array of Outlayer.Items} items
*/
proto
.
hide
=
function
(
items
)
{
this
.
_emitCompleteOnItems
(
'hide'
,
items
);
if
(
!
items
||
!
items
.
length
)
{
return
;
}
var
stagger
=
this
.
updateStagger
();
items
.
forEach
(
function
(
item
,
i
)
{
item
.
stagger
(
i
*
stagger
);
item
.
hide
();
});
};
/**
* reveal item elements
* @param {Array}, {Element}, {NodeList} items
*/
proto
.
revealItemElements
=
function
(
elems
)
{
var
items
=
this
.
getItems
(
elems
);
this
.
reveal
(
items
);
};
/**
* hide item elements
* @param {Array}, {Element}, {NodeList} items
*/
proto
.
hideItemElements
=
function
(
elems
)
{
var
items
=
this
.
getItems
(
elems
);
this
.
hide
(
items
);
};
/**
* get Outlayer.Item, given an Element
* @param {Element} elem
* @param {Function} callback
* @returns {Outlayer.Item} item
*/
proto
.
getItem
=
function
(
elem
)
{
// loop through items to get the one that matches
for
(
var
i
=
0
;
i
<
this
.
items
.
length
;
i
++
)
{
var
item
=
this
.
items
[
i
];
if
(
item
.
element
==
elem
)
{
// return item
return
item
;
}
}
};
/**
* get collection of Outlayer.Items, given Elements
* @param {Array} elems
* @returns {Array} items - Outlayer.Items
*/
proto
.
getItems
=
function
(
elems
)
{
elems
=
utils
.
makeArray
(
elems
);
var
items
=
[];
elems
.
forEach
(
function
(
elem
)
{
var
item
=
this
.
getItem
(
elem
);
if
(
item
)
{
items
.
push
(
item
);
}
},
this
);
return
items
;
};
/**
* remove element(s) from instance and DOM
* @param {Array or NodeList or Element} elems
*/
proto
.
remove
=
function
(
elems
)
{
var
removeItems
=
this
.
getItems
(
elems
);
this
.
_emitCompleteOnItems
(
'remove'
,
removeItems
);
// bail if no items to remove
if
(
!
removeItems
||
!
removeItems
.
length
)
{
return
;
}
removeItems
.
forEach
(
function
(
item
)
{
item
.
remove
();
// remove item from collection
utils
.
removeFrom
(
this
.
items
,
item
);
},
this
);
};
// ----- destroy ----- //
// remove and disable Outlayer instance
proto
.
destroy
=
function
()
{
// clean up dynamic styles
var
style
=
this
.
element
.
style
;
style
.
height
=
''
;
style
.
position
=
''
;
style
.
width
=
''
;
// destroy items
this
.
items
.
forEach
(
function
(
item
)
{
item
.
destroy
();
});
this
.
unbindResize
();
var
id
=
this
.
element
.
outlayerGUID
;
delete
instances
[
id
];
// remove reference to instance by id
delete
this
.
element
.
outlayerGUID
;
// remove data for jQuery
if
(
jQuery
)
{
jQuery
.
removeData
(
this
.
element
,
this
.
constructor
.
namespace
);
}
};
// -------------------------- data -------------------------- //
/**
* get Outlayer instance from element
* @param {Element} elem
* @returns {Outlayer}
*/
Outlayer
.
data
=
function
(
elem
)
{
elem
=
utils
.
getQueryElement
(
elem
);
var
id
=
elem
&&
elem
.
outlayerGUID
;
return
id
&&
instances
[
id
];
};
// -------------------------- create Outlayer class -------------------------- //
/**
* create a layout class
* @param {String} namespace
*/
Outlayer
.
create
=
function
(
namespace
,
options
)
{
// sub-class Outlayer
var
Layout
=
subclass
(
Outlayer
);
// apply new options and compatOptions
Layout
.
defaults
=
utils
.
extend
(
{},
Outlayer
.
defaults
);
utils
.
extend
(
Layout
.
defaults
,
options
);
Layout
.
compatOptions
=
utils
.
extend
(
{},
Outlayer
.
compatOptions
);
Layout
.
namespace
=
namespace
;
Layout
.
data
=
Outlayer
.
data
;
// sub-class Item
Layout
.
Item
=
subclass
(
Item
);
// -------------------------- declarative -------------------------- //
utils
.
htmlInit
(
Layout
,
namespace
);
// -------------------------- jQuery bridge -------------------------- //
// make into jQuery plugin
if
(
jQuery
&&
jQuery
.
bridget
)
{
jQuery
.
bridget
(
namespace
,
Layout
);
}
return
Layout
;
};
function
subclass
(
Parent
)
{
function
SubClass
()
{
Parent
.
apply
(
this
,
arguments
);
}
SubClass
.
prototype
=
Object
.
create
(
Parent
.
prototype
);
SubClass
.
prototype
.
constructor
=
SubClass
;
return
SubClass
;
}
// ----- helpers ----- //
// how many milliseconds are in each unit
var
msUnits
=
{
ms
:
1
,
s
:
1000
};
// munge time-like parameter into millisecond number
// '0.4s' -> 40
function
getMilliseconds
(
time
)
{
if
(
typeof
time
==
'number'
)
{
return
time
;
}
var
matches
=
time
.
match
(
/
(
^
\d
*
\.?\d
*
)(\w
*
)
/
);
var
num
=
matches
&&
matches
[
1
];
var
unit
=
matches
&&
matches
[
2
];
if
(
!
num
.
length
)
{
return
0
;
}
num
=
parseFloat
(
num
);
var
mult
=
msUnits
[
unit
]
||
1
;
return
num
*
mult
;
}
// ----- fin ----- //
// back in global
Outlayer
.
Item
=
Item
;
return
Outlayer
;
}));
/**
* Isotope Item
**/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'isotope-layout/js/item'
,[
'outlayer/outlayer'
],
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
require
(
'outlayer'
)
);
}
else
{
// browser global
window
.
Isotope
=
window
.
Isotope
||
{};
window
.
Isotope
.
Item
=
factory
(
window
.
Outlayer
);
}
}(
window
,
function
factory
(
Outlayer
)
{
'use strict'
;
// -------------------------- Item -------------------------- //
// sub-class Outlayer Item
function
Item
()
{
Outlayer
.
Item
.
apply
(
this
,
arguments
);
}
var
proto
=
Item
.
prototype
=
Object
.
create
(
Outlayer
.
Item
.
prototype
);
var
_create
=
proto
.
_create
;
proto
.
_create
=
function
()
{
// assign id, used for original-order sorting
this
.
id
=
this
.
layout
.
itemGUID
++
;
_create
.
call
(
this
);
this
.
sortData
=
{};
};
proto
.
updateSortData
=
function
()
{
if
(
this
.
isIgnored
)
{
return
;
}
// default sorters
this
.
sortData
.
id
=
this
.
id
;
// for backward compatibility
this
.
sortData
[
'original-order'
]
=
this
.
id
;
this
.
sortData
.
random
=
Math
.
random
();
// go thru getSortData obj and apply the sorters
var
getSortData
=
this
.
layout
.
options
.
getSortData
;
var
sorters
=
this
.
layout
.
_sorters
;
for
(
var
key
in
getSortData
)
{
var
sorter
=
sorters
[
key
];
this
.
sortData
[
key
]
=
sorter
(
this
.
element
,
this
);
}
};
var
_destroy
=
proto
.
destroy
;
proto
.
destroy
=
function
()
{
// call super
_destroy
.
apply
(
this
,
arguments
);
// reset display, #741
this
.
css
({
display
:
''
});
};
return
Item
;
}));
/**
* Isotope LayoutMode
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'isotope-layout/js/layout-mode'
,[
'get-size/get-size'
,
'outlayer/outlayer'
],
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
require
(
'get-size'
),
require
(
'outlayer'
)
);
}
else
{
// browser global
window
.
Isotope
=
window
.
Isotope
||
{};
window
.
Isotope
.
LayoutMode
=
factory
(
window
.
getSize
,
window
.
Outlayer
);
}
}(
window
,
function
factory
(
getSize
,
Outlayer
)
{
'use strict'
;
// layout mode class
function
LayoutMode
(
isotope
)
{
this
.
isotope
=
isotope
;
// link properties
if
(
isotope
)
{
this
.
options
=
isotope
.
options
[
this
.
namespace
];
this
.
element
=
isotope
.
element
;
this
.
items
=
isotope
.
filteredItems
;
this
.
size
=
isotope
.
size
;
}
}
var
proto
=
LayoutMode
.
prototype
;
/**
* some methods should just defer to default Outlayer method
* and reference the Isotope instance as `this`
**/
var
facadeMethods
=
[
'_resetLayout'
,
'_getItemLayoutPosition'
,
'_manageStamp'
,
'_getContainerSize'
,
'_getElementOffset'
,
'needsResizeLayout'
,
'_getOption'
];
facadeMethods
.
forEach
(
function
(
methodName
)
{
proto
[
methodName
]
=
function
()
{
return
Outlayer
.
prototype
[
methodName
].
apply
(
this
.
isotope
,
arguments
);
};
});
// ----- ----- //
// for horizontal layout modes, check vertical size
proto
.
needsVerticalResizeLayout
=
function
()
{
// don't trigger if size did not change
var
size
=
getSize
(
this
.
isotope
.
element
);
// check that this.size and size are there
// IE8 triggers resize on body size change, so they might not be
var
hasSizes
=
this
.
isotope
.
size
&&
size
;
return
hasSizes
&&
size
.
innerHeight
!=
this
.
isotope
.
size
.
innerHeight
;
};
// ----- measurements ----- //
proto
.
_getMeasurement
=
function
()
{
this
.
isotope
.
_getMeasurement
.
apply
(
this
,
arguments
);
};
proto
.
getColumnWidth
=
function
()
{
this
.
getSegmentSize
(
'column'
,
'Width'
);
};
proto
.
getRowHeight
=
function
()
{
this
.
getSegmentSize
(
'row'
,
'Height'
);
};
/**
* get columnWidth or rowHeight
* segment: 'column' or 'row'
* size 'Width' or 'Height'
**/
proto
.
getSegmentSize
=
function
(
segment
,
size
)
{
var
segmentName
=
segment
+
size
;
var
outerSize
=
'outer'
+
size
;
// columnWidth / outerWidth // rowHeight / outerHeight
this
.
_getMeasurement
(
segmentName
,
outerSize
);
// got rowHeight or columnWidth, we can chill
if
(
this
[
segmentName
]
)
{
return
;
}
// fall back to item of first element
var
firstItemSize
=
this
.
getFirstItemSize
();
this
[
segmentName
]
=
firstItemSize
&&
firstItemSize
[
outerSize
]
||
// or size of container
this
.
isotope
.
size
[
'inner'
+
size
];
};
proto
.
getFirstItemSize
=
function
()
{
var
firstItem
=
this
.
isotope
.
filteredItems
[
0
];
return
firstItem
&&
firstItem
.
element
&&
getSize
(
firstItem
.
element
);
};
// ----- methods that should reference isotope ----- //
proto
.
layout
=
function
()
{
this
.
isotope
.
layout
.
apply
(
this
.
isotope
,
arguments
);
};
proto
.
getSize
=
function
()
{
this
.
isotope
.
getSize
();
this
.
size
=
this
.
isotope
.
size
;
};
// -------------------------- create -------------------------- //
LayoutMode
.
modes
=
{};
LayoutMode
.
create
=
function
(
namespace
,
options
)
{
function
Mode
()
{
LayoutMode
.
apply
(
this
,
arguments
);
}
Mode
.
prototype
=
Object
.
create
(
proto
);
Mode
.
prototype
.
constructor
=
Mode
;
// default options
if
(
options
)
{
Mode
.
options
=
options
;
}
Mode
.
prototype
.
namespace
=
namespace
;
// register in Isotope
LayoutMode
.
modes
[
namespace
]
=
Mode
;
return
Mode
;
};
return
LayoutMode
;
}));
/*!
* Masonry v4.2.1
* Cascading grid layout library
* https://masonry.desandro.com
* MIT License
* by David DeSandro
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'masonry-layout/masonry'
,[
'outlayer/outlayer'
,
'get-size/get-size'
],
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
require
(
'outlayer'
),
require
(
'get-size'
)
);
}
else
{
// browser global
window
.
Masonry
=
factory
(
window
.
Outlayer
,
window
.
getSize
);
}
}(
window
,
function
factory
(
Outlayer
,
getSize
)
{
// -------------------------- masonryDefinition -------------------------- //
// create an Outlayer layout class
var
Masonry
=
Outlayer
.
create
(
'masonry'
);
// isFitWidth -> fitWidth
Masonry
.
compatOptions
.
fitWidth
=
'isFitWidth'
;
var
proto
=
Masonry
.
prototype
;
proto
.
_resetLayout
=
function
()
{
this
.
getSize
();
this
.
_getMeasurement
(
'columnWidth'
,
'outerWidth'
);
this
.
_getMeasurement
(
'gutter'
,
'outerWidth'
);
this
.
measureColumns
();
// reset column Y
this
.
colYs
=
[];
for
(
var
i
=
0
;
i
<
this
.
cols
;
i
++
)
{
this
.
colYs
.
push
(
0
);
}
this
.
maxY
=
0
;
this
.
horizontalColIndex
=
0
;
};
proto
.
measureColumns
=
function
()
{
this
.
getContainerWidth
();
// if columnWidth is 0, default to outerWidth of first item
if
(
!
this
.
columnWidth
)
{
var
firstItem
=
this
.
items
[
0
];
var
firstItemElem
=
firstItem
&&
firstItem
.
element
;
// columnWidth fall back to item of first element
this
.
columnWidth
=
firstItemElem
&&
getSize
(
firstItemElem
).
outerWidth
||
// if first elem has no width, default to size of container
this
.
containerWidth
;
}
var
columnWidth
=
this
.
columnWidth
+=
this
.
gutter
;
// calculate columns
var
containerWidth
=
this
.
containerWidth
+
this
.
gutter
;
var
cols
=
containerWidth
/
columnWidth
;
// fix rounding errors, typically with gutters
var
excess
=
columnWidth
-
containerWidth
%
columnWidth
;
// if overshoot is less than a pixel, round up, otherwise floor it
var
mathMethod
=
excess
&&
excess
<
1
?
'round'
:
'floor'
;
cols
=
Math
[
mathMethod
](
cols
);
this
.
cols
=
Math
.
max
(
cols
,
1
);
};
proto
.
getContainerWidth
=
function
()
{
// container is parent if fit width
var
isFitWidth
=
this
.
_getOption
(
'fitWidth'
);
var
container
=
isFitWidth
?
this
.
element
.
parentNode
:
this
.
element
;
// check that this.size and size are there
// IE8 triggers resize on body size change, so they might not be
var
size
=
getSize
(
container
);
this
.
containerWidth
=
size
&&
size
.
innerWidth
;
};
proto
.
_getItemLayoutPosition
=
function
(
item
)
{
item
.
getSize
();
// how many columns does this brick span
var
remainder
=
item
.
size
.
outerWidth
%
this
.
columnWidth
;
var
mathMethod
=
remainder
&&
remainder
<
1
?
'round'
:
'ceil'
;
// round if off by 1 pixel, otherwise use ceil
var
colSpan
=
Math
[
mathMethod
](
item
.
size
.
outerWidth
/
this
.
columnWidth
);
colSpan
=
Math
.
min
(
colSpan
,
this
.
cols
);
// use horizontal or top column position
var
colPosMethod
=
this
.
options
.
horizontalOrder
?
'_getHorizontalColPosition'
:
'_getTopColPosition'
;
var
colPosition
=
this
[
colPosMethod
](
colSpan
,
item
);
// position the brick
var
position
=
{
x
:
this
.
columnWidth
*
colPosition
.
col
,
y
:
colPosition
.
y
};
// apply setHeight to necessary columns
var
setHeight
=
colPosition
.
y
+
item
.
size
.
outerHeight
;
var
setMax
=
colSpan
+
colPosition
.
col
;
for
(
var
i
=
colPosition
.
col
;
i
<
setMax
;
i
++
)
{
this
.
colYs
[
i
]
=
setHeight
;
}
return
position
;
};
proto
.
_getTopColPosition
=
function
(
colSpan
)
{
var
colGroup
=
this
.
_getTopColGroup
(
colSpan
);
// get the minimum Y value from the columns
var
minimumY
=
Math
.
min
.
apply
(
Math
,
colGroup
);
return
{
col
:
colGroup
.
indexOf
(
minimumY
),
y
:
minimumY
,
};
};
/**
* @param {Number} colSpan - number of columns the element spans
* @returns {Array} colGroup
*/
proto
.
_getTopColGroup
=
function
(
colSpan
)
{
if
(
colSpan
<
2
)
{
// if brick spans only one column, use all the column Ys
return
this
.
colYs
;
}
var
colGroup
=
[];
// how many different places could this brick fit horizontally
var
groupCount
=
this
.
cols
+
1
-
colSpan
;
// for each group potential horizontal position
for
(
var
i
=
0
;
i
<
groupCount
;
i
++
)
{
colGroup
[
i
]
=
this
.
_getColGroupY
(
i
,
colSpan
);
}
return
colGroup
;
};
proto
.
_getColGroupY
=
function
(
col
,
colSpan
)
{
if
(
colSpan
<
2
)
{
return
this
.
colYs
[
col
];
}
// make an array of colY values for that one group
var
groupColYs
=
this
.
colYs
.
slice
(
col
,
col
+
colSpan
);
// and get the max value of the array
return
Math
.
max
.
apply
(
Math
,
groupColYs
);
};
// get column position based on horizontal index. #873
proto
.
_getHorizontalColPosition
=
function
(
colSpan
,
item
)
{
var
col
=
this
.
horizontalColIndex
%
this
.
cols
;
var
isOver
=
colSpan
>
1
&&
col
+
colSpan
>
this
.
cols
;
// shift to next row if item can't fit on current row
col
=
isOver
?
0
:
col
;
// don't let zero-size items take up space
var
hasSize
=
item
.
size
.
outerWidth
&&
item
.
size
.
outerHeight
;
this
.
horizontalColIndex
=
hasSize
?
col
+
colSpan
:
this
.
horizontalColIndex
;
return
{
col
:
col
,
y
:
this
.
_getColGroupY
(
col
,
colSpan
),
};
};
proto
.
_manageStamp
=
function
(
stamp
)
{
var
stampSize
=
getSize
(
stamp
);
var
offset
=
this
.
_getElementOffset
(
stamp
);
// get the columns that this stamp affects
var
isOriginLeft
=
this
.
_getOption
(
'originLeft'
);
var
firstX
=
isOriginLeft
?
offset
.
left
:
offset
.
right
;
var
lastX
=
firstX
+
stampSize
.
outerWidth
;
var
firstCol
=
Math
.
floor
(
firstX
/
this
.
columnWidth
);
firstCol
=
Math
.
max
(
0
,
firstCol
);
var
lastCol
=
Math
.
floor
(
lastX
/
this
.
columnWidth
);
// lastCol should not go over if multiple of columnWidth #425
lastCol
-=
lastX
%
this
.
columnWidth
?
0
:
1
;
lastCol
=
Math
.
min
(
this
.
cols
-
1
,
lastCol
);
// set colYs to bottom of the stamp
var
isOriginTop
=
this
.
_getOption
(
'originTop'
);
var
stampMaxY
=
(
isOriginTop
?
offset
.
top
:
offset
.
bottom
)
+
stampSize
.
outerHeight
;
for
(
var
i
=
firstCol
;
i
<=
lastCol
;
i
++
)
{
this
.
colYs
[
i
]
=
Math
.
max
(
stampMaxY
,
this
.
colYs
[
i
]
);
}
};
proto
.
_getContainerSize
=
function
()
{
this
.
maxY
=
Math
.
max
.
apply
(
Math
,
this
.
colYs
);
var
size
=
{
height
:
this
.
maxY
};
if
(
this
.
_getOption
(
'fitWidth'
)
)
{
size
.
width
=
this
.
_getContainerFitWidth
();
}
return
size
;
};
proto
.
_getContainerFitWidth
=
function
()
{
var
unusedCols
=
0
;
// count unused columns
var
i
=
this
.
cols
;
while
(
--
i
)
{
if
(
this
.
colYs
[
i
]
!==
0
)
{
break
;
}
unusedCols
++
;
}
// fit container to columns that have been used
return
(
this
.
cols
-
unusedCols
)
*
this
.
columnWidth
-
this
.
gutter
;
};
proto
.
needsResizeLayout
=
function
()
{
var
previousWidth
=
this
.
containerWidth
;
this
.
getContainerWidth
();
return
previousWidth
!=
this
.
containerWidth
;
};
return
Masonry
;
}));
/*!
* Masonry layout mode
* sub-classes Masonry
* https://masonry.desandro.com
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'isotope-layout/js/layout-modes/masonry'
,[
'../layout-mode'
,
'masonry-layout/masonry'
],
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
require
(
'../layout-mode'
),
require
(
'masonry-layout'
)
);
}
else
{
// browser global
factory
(
window
.
Isotope
.
LayoutMode
,
window
.
Masonry
);
}
}(
window
,
function
factory
(
LayoutMode
,
Masonry
)
{
'use strict'
;
// -------------------------- masonryDefinition -------------------------- //
// create an Outlayer layout class
var
MasonryMode
=
LayoutMode
.
create
(
'masonry'
);
var
proto
=
MasonryMode
.
prototype
;
var
keepModeMethods
=
{
_getElementOffset
:
true
,
layout
:
true
,
_getMeasurement
:
true
};
// inherit Masonry prototype
for
(
var
method
in
Masonry
.
prototype
)
{
// do not inherit mode methods
if
(
!
keepModeMethods
[
method
]
)
{
proto
[
method
]
=
Masonry
.
prototype
[
method
];
}
}
var
measureColumns
=
proto
.
measureColumns
;
proto
.
measureColumns
=
function
()
{
// set items, used if measuring first item
this
.
items
=
this
.
isotope
.
filteredItems
;
measureColumns
.
call
(
this
);
};
// point to mode options for fitWidth
var
_getOption
=
proto
.
_getOption
;
proto
.
_getOption
=
function
(
option
)
{
if
(
option
==
'fitWidth'
)
{
return
this
.
options
.
isFitWidth
!==
undefined
?
this
.
options
.
isFitWidth
:
this
.
options
.
fitWidth
;
}
return
_getOption
.
apply
(
this
.
isotope
,
arguments
);
};
return
MasonryMode
;
}));
/**
* fitRows layout mode
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'isotope-layout/js/layout-modes/fit-rows'
,[
'../layout-mode'
],
factory
);
}
else
if
(
typeof
exports
==
'object'
)
{
// CommonJS
module
.
exports
=
factory
(
require
(
'../layout-mode'
)
);
}
else
{
// browser global
factory
(
window
.
Isotope
.
LayoutMode
);
}
}(
window
,
function
factory
(
LayoutMode
)
{
'use strict'
;
var
FitRows
=
LayoutMode
.
create
(
'fitRows'
);
var
proto
=
FitRows
.
prototype
;
proto
.
_resetLayout
=
function
()
{
this
.
x
=
0
;
this
.
y
=
0
;
this
.
maxY
=
0
;
this
.
_getMeasurement
(
'gutter'
,
'outerWidth'
);
};
proto
.
_getItemLayoutPosition
=
function
(
item
)
{
item
.
getSize
();
var
itemWidth
=
item
.
size
.
outerWidth
+
this
.
gutter
;
// if this element cannot fit in the current row
var
containerWidth
=
this
.
isotope
.
size
.
innerWidth
+
this
.
gutter
;
if
(
this
.
x
!==
0
&&
itemWidth
+
this
.
x
>
containerWidth
)
{
this
.
x
=
0
;
this
.
y
=
this
.
maxY
;
}
var
position
=
{
x
:
this
.
x
,
y
:
this
.
y
};
this
.
maxY
=
Math
.
max
(
this
.
maxY
,
this
.
y
+
item
.
size
.
outerHeight
);
this
.
x
+=
itemWidth
;
return
position
;
};
proto
.
_getContainerSize
=
function
()
{
return
{
height
:
this
.
maxY
};
};
return
FitRows
;
}));
/**
* vertical layout mode
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
'isotope-layout/js/layout-modes/vertical'
,[
'../layout-mode'
],
factory
);
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
require
(
'../layout-mode'
)
);
}
else
{
// browser global
factory
(
window
.
Isotope
.
LayoutMode
);
}
}(
window
,
function
factory
(
LayoutMode
)
{
'use strict'
;
var
Vertical
=
LayoutMode
.
create
(
'vertical'
,
{
horizontalAlignment
:
0
});
var
proto
=
Vertical
.
prototype
;
proto
.
_resetLayout
=
function
()
{
this
.
y
=
0
;
};
proto
.
_getItemLayoutPosition
=
function
(
item
)
{
item
.
getSize
();
var
x
=
(
this
.
isotope
.
size
.
innerWidth
-
item
.
size
.
outerWidth
)
*
this
.
options
.
horizontalAlignment
;
var
y
=
this
.
y
;
this
.
y
+=
item
.
size
.
outerHeight
;
return
{
x
:
x
,
y
:
y
};
};
proto
.
_getContainerSize
=
function
()
{
return
{
height
:
this
.
y
};
};
return
Vertical
;
}));
/*!
* Isotope v3.0.6
*
* Licensed GPLv3 for open source use
* or Isotope Commercial License for commercial use
*
* https://isotope.metafizzy.co
* Copyright 2010-2018 Metafizzy
*/
(
function
(
window
,
factory
)
{
// universal module definition
/* jshint strict: false */
/*globals define, module, require */
if
(
typeof
define
==
'function'
&&
define
.
amd
)
{
// AMD
define
(
[
'outlayer/outlayer'
,
'get-size/get-size'
,
'desandro-matches-selector/matches-selector'
,
'fizzy-ui-utils/utils'
,
'isotope-layout/js/item'
,
'isotope-layout/js/layout-mode'
,
// include default layout modes
'isotope-layout/js/layout-modes/masonry'
,
'isotope-layout/js/layout-modes/fit-rows'
,
'isotope-layout/js/layout-modes/vertical'
],
function
(
Outlayer
,
getSize
,
matchesSelector
,
utils
,
Item
,
LayoutMode
)
{
return
factory
(
window
,
Outlayer
,
getSize
,
matchesSelector
,
utils
,
Item
,
LayoutMode
);
});
}
else
if
(
typeof
module
==
'object'
&&
module
.
exports
)
{
// CommonJS
module
.
exports
=
factory
(
window
,
require
(
'outlayer'
),
require
(
'get-size'
),
require
(
'desandro-matches-selector'
),
require
(
'fizzy-ui-utils'
),
require
(
'isotope-layout/js/item'
),
require
(
'isotope-layout/js/layout-mode'
),
// include default layout modes
require
(
'isotope-layout/js/layout-modes/masonry'
),
require
(
'isotope-layout/js/layout-modes/fit-rows'
),
require
(
'isotope-layout/js/layout-modes/vertical'
)
);
}
else
{
// browser global
window
.
Isotope
=
factory
(
window
,
window
.
Outlayer
,
window
.
getSize
,
window
.
matchesSelector
,
window
.
fizzyUIUtils
,
window
.
Isotope
.
Item
,
window
.
Isotope
.
LayoutMode
);
}
}(
window
,
function
factory
(
window
,
Outlayer
,
getSize
,
matchesSelector
,
utils
,
Item
,
LayoutMode
)
{
// -------------------------- vars -------------------------- //
var
jQuery
=
window
.
jQuery
;
// -------------------------- helpers -------------------------- //
var
trim
=
String
.
prototype
.
trim
?
function
(
str
)
{
return
str
.
trim
();
}
:
function
(
str
)
{
return
str
.
replace
(
/^
\s
+|
\s
+$/g
,
''
);
};
// -------------------------- isotopeDefinition -------------------------- //
// create an Outlayer layout class
var
Isotope
=
Outlayer
.
create
(
'isotope'
,
{
layoutMode
:
'masonry'
,
isJQueryFiltering
:
true
,
sortAscending
:
true
});
Isotope
.
Item
=
Item
;
Isotope
.
LayoutMode
=
LayoutMode
;
var
proto
=
Isotope
.
prototype
;
proto
.
_create
=
function
()
{
this
.
itemGUID
=
0
;
// functions that sort items
this
.
_sorters
=
{};
this
.
_getSorters
();
// call super
Outlayer
.
prototype
.
_create
.
call
(
this
);
// create layout modes
this
.
modes
=
{};
// start filteredItems with all items
this
.
filteredItems
=
this
.
items
;
// keep of track of sortBys
this
.
sortHistory
=
[
'original-order'
];
// create from registered layout modes
for
(
var
name
in
LayoutMode
.
modes
)
{
this
.
_initLayoutMode
(
name
);
}
};
proto
.
reloadItems
=
function
()
{
// reset item ID counter
this
.
itemGUID
=
0
;
// call super
Outlayer
.
prototype
.
reloadItems
.
call
(
this
);
};
proto
.
_itemize
=
function
()
{
var
items
=
Outlayer
.
prototype
.
_itemize
.
apply
(
this
,
arguments
);
// assign ID for original-order
for
(
var
i
=
0
;
i
<
items
.
length
;
i
++
)
{
var
item
=
items
[
i
];
item
.
id
=
this
.
itemGUID
++
;
}
this
.
_updateItemsSortData
(
items
);
return
items
;
};
// -------------------------- layout -------------------------- //
proto
.
_initLayoutMode
=
function
(
name
)
{
var
Mode
=
LayoutMode
.
modes
[
name
];
// set mode options
// HACK extend initial options, back-fill in default options
var
initialOpts
=
this
.
options
[
name
]
||
{};
this
.
options
[
name
]
=
Mode
.
options
?
utils
.
extend
(
Mode
.
options
,
initialOpts
)
:
initialOpts
;
// init layout mode instance
this
.
modes
[
name
]
=
new
Mode
(
this
);
};
proto
.
layout
=
function
()
{
// if first time doing layout, do all magic
if
(
!
this
.
_isLayoutInited
&&
this
.
_getOption
(
'initLayout'
)
)
{
this
.
arrange
();
return
;
}
this
.
_layout
();
};
// private method to be used in layout() & magic()
proto
.
_layout
=
function
()
{
// don't animate first layout
var
isInstant
=
this
.
_getIsInstant
();
// layout flow
this
.
_resetLayout
();
this
.
_manageStamps
();
this
.
layoutItems
(
this
.
filteredItems
,
isInstant
);
// flag for initalized
this
.
_isLayoutInited
=
true
;
};
// filter + sort + layout
proto
.
arrange
=
function
(
opts
)
{
// set any options pass
this
.
option
(
opts
);
this
.
_getIsInstant
();
// filter, sort, and layout
// filter
var
filtered
=
this
.
_filter
(
this
.
items
);
this
.
filteredItems
=
filtered
.
matches
;
this
.
_bindArrangeComplete
();
if
(
this
.
_isInstant
)
{
this
.
_noTransition
(
this
.
_hideReveal
,
[
filtered
]
);
}
else
{
this
.
_hideReveal
(
filtered
);
}
this
.
_sort
();
this
.
_layout
();
};
// alias to _init for main plugin method
proto
.
_init
=
proto
.
arrange
;
proto
.
_hideReveal
=
function
(
filtered
)
{
this
.
reveal
(
filtered
.
needReveal
);
this
.
hide
(
filtered
.
needHide
);
};
// HACK
// Don't animate/transition first layout
// Or don't animate/transition other layouts
proto
.
_getIsInstant
=
function
()
{
var
isLayoutInstant
=
this
.
_getOption
(
'layoutInstant'
);
var
isInstant
=
isLayoutInstant
!==
undefined
?
isLayoutInstant
:
!
this
.
_isLayoutInited
;
this
.
_isInstant
=
isInstant
;
return
isInstant
;
};
// listen for layoutComplete, hideComplete and revealComplete
// to trigger arrangeComplete
proto
.
_bindArrangeComplete
=
function
()
{
// listen for 3 events to trigger arrangeComplete
var
isLayoutComplete
,
isHideComplete
,
isRevealComplete
;
var
_this
=
this
;
function
arrangeParallelCallback
()
{
if
(
isLayoutComplete
&&
isHideComplete
&&
isRevealComplete
)
{
_this
.
dispatchEvent
(
'arrangeComplete'
,
null
,
[
_this
.
filteredItems
]
);
}
}
this
.
once
(
'layoutComplete'
,
function
()
{
isLayoutComplete
=
true
;
arrangeParallelCallback
();
});
this
.
once
(
'hideComplete'
,
function
()
{
isHideComplete
=
true
;
arrangeParallelCallback
();
});
this
.
once
(
'revealComplete'
,
function
()
{
isRevealComplete
=
true
;
arrangeParallelCallback
();
});
};
// -------------------------- filter -------------------------- //
proto
.
_filter
=
function
(
items
)
{
var
filter
=
this
.
options
.
filter
;
filter
=
filter
||
'*'
;
var
matches
=
[];
var
hiddenMatched
=
[];
var
visibleUnmatched
=
[];
var
test
=
this
.
_getFilterTest
(
filter
);
// test each item
for
(
var
i
=
0
;
i
<
items
.
length
;
i
++
)
{
var
item
=
items
[
i
];
if
(
item
.
isIgnored
)
{
continue
;
}
// add item to either matched or unmatched group
var
isMatched
=
test
(
item
);
// item.isFilterMatched = isMatched;
// add to matches if its a match
if
(
isMatched
)
{
matches
.
push
(
item
);
}
// add to additional group if item needs to be hidden or revealed
if
(
isMatched
&&
item
.
isHidden
)
{
hiddenMatched
.
push
(
item
);
}
else
if
(
!
isMatched
&&
!
item
.
isHidden
)
{
visibleUnmatched
.
push
(
item
);
}
}
// return collections of items to be manipulated
return
{
matches
:
matches
,
needReveal
:
hiddenMatched
,
needHide
:
visibleUnmatched
};
};
// get a jQuery, function, or a matchesSelector test given the filter
proto
.
_getFilterTest
=
function
(
filter
)
{
if
(
jQuery
&&
this
.
options
.
isJQueryFiltering
)
{
// use jQuery
return
function
(
item
)
{
return
jQuery
(
item
.
element
).
is
(
filter
);
};
}
if
(
typeof
filter
==
'function'
)
{
// use filter as function
return
function
(
item
)
{
return
filter
(
item
.
element
);
};
}
// default, use filter as selector string
return
function
(
item
)
{
return
matchesSelector
(
item
.
element
,
filter
);
};
};
// -------------------------- sorting -------------------------- //
/**
* @params {Array} elems
* @public
*/
proto
.
updateSortData
=
function
(
elems
)
{
// get items
var
items
;
if
(
elems
)
{
elems
=
utils
.
makeArray
(
elems
);
items
=
this
.
getItems
(
elems
);
}
else
{
// update all items if no elems provided
items
=
this
.
items
;
}
this
.
_getSorters
();
this
.
_updateItemsSortData
(
items
);
};
proto
.
_getSorters
=
function
()
{
var
getSortData
=
this
.
options
.
getSortData
;
for
(
var
key
in
getSortData
)
{
var
sorter
=
getSortData
[
key
];
this
.
_sorters
[
key
]
=
mungeSorter
(
sorter
);
}
};
/**
* @params {Array} items - of Isotope.Items
* @private
*/
proto
.
_updateItemsSortData
=
function
(
items
)
{
// do not update if no items
var
len
=
items
&&
items
.
length
;
for
(
var
i
=
0
;
len
&&
i
<
len
;
i
++
)
{
var
item
=
items
[
i
];
item
.
updateSortData
();
}
};
// ----- munge sorter ----- //
// encapsulate this, as we just need mungeSorter
// other functions in here are just for munging
var
mungeSorter
=
(
function
()
{
// add a magic layer to sorters for convienent shorthands
// `.foo-bar` will use the text of .foo-bar querySelector
// `[foo-bar]` will use attribute
// you can also add parser
// `.foo-bar parseInt` will parse that as a number
function
mungeSorter
(
sorter
)
{
// if not a string, return function or whatever it is
if
(
typeof
sorter
!=
'string'
)
{
return
sorter
;
}
// parse the sorter string
var
args
=
trim
(
sorter
).
split
(
' '
);
var
query
=
args
[
0
];
// check if query looks like [an-attribute]
var
attrMatch
=
query
.
match
(
/^
\[(
.+
)\]
$/
);
var
attr
=
attrMatch
&&
attrMatch
[
1
];
var
getValue
=
getValueGetter
(
attr
,
query
);
// use second argument as a parser
var
parser
=
Isotope
.
sortDataParsers
[
args
[
1
]
];
// parse the value, if there was a parser
sorter
=
parser
?
function
(
elem
)
{
return
elem
&&
parser
(
getValue
(
elem
)
);
}
:
// otherwise just return value
function
(
elem
)
{
return
elem
&&
getValue
(
elem
);
};
return
sorter
;
}
// get an attribute getter, or get text of the querySelector
function
getValueGetter
(
attr
,
query
)
{
// if query looks like [foo-bar], get attribute
if
(
attr
)
{
return
function
getAttribute
(
elem
)
{
return
elem
.
getAttribute
(
attr
);
};
}
// otherwise, assume its a querySelector, and get its text
return
function
getChildText
(
elem
)
{
var
child
=
elem
.
querySelector
(
query
);
return
child
&&
child
.
textContent
;
};
}
return
mungeSorter
;
})();
// parsers used in getSortData shortcut strings
Isotope
.
sortDataParsers
=
{
'parseInt'
:
function
(
val
)
{
return
parseInt
(
val
,
10
);
},
'parseFloat'
:
function
(
val
)
{
return
parseFloat
(
val
);
}
};
// ----- sort method ----- //
// sort filteredItem order
proto
.
_sort
=
function
()
{
if
(
!
this
.
options
.
sortBy
)
{
return
;
}
// keep track of sortBy History
var
sortBys
=
utils
.
makeArray
(
this
.
options
.
sortBy
);
if
(
!
this
.
_getIsSameSortBy
(
sortBys
)
)
{
// concat all sortBy and sortHistory, add to front, oldest goes in last
this
.
sortHistory
=
sortBys
.
concat
(
this
.
sortHistory
);
}
// sort magic
var
itemSorter
=
getItemSorter
(
this
.
sortHistory
,
this
.
options
.
sortAscending
);
this
.
filteredItems
.
sort
(
itemSorter
);
};
// check if sortBys is same as start of sortHistory
proto
.
_getIsSameSortBy
=
function
(
sortBys
)
{
for
(
var
i
=
0
;
i
<
sortBys
.
length
;
i
++
)
{
if
(
sortBys
[
i
]
!=
this
.
sortHistory
[
i
]
)
{
return
false
;
}
}
return
true
;
};
// returns a function used for sorting
function
getItemSorter
(
sortBys
,
sortAsc
)
{
return
function
sorter
(
itemA
,
itemB
)
{
// cycle through all sortKeys
for
(
var
i
=
0
;
i
<
sortBys
.
length
;
i
++
)
{
var
sortBy
=
sortBys
[
i
];
var
a
=
itemA
.
sortData
[
sortBy
];
var
b
=
itemB
.
sortData
[
sortBy
];
if
(
a
>
b
||
a
<
b
)
{
// if sortAsc is an object, use the value given the sortBy key
var
isAscending
=
sortAsc
[
sortBy
]
!==
undefined
?
sortAsc
[
sortBy
]
:
sortAsc
;
var
direction
=
isAscending
?
1
:
-
1
;
return
(
a
>
b
?
1
:
-
1
)
*
direction
;
}
}
return
0
;
};
}
// -------------------------- methods -------------------------- //
// get layout mode
proto
.
_mode
=
function
()
{
var
layoutMode
=
this
.
options
.
layoutMode
;
var
mode
=
this
.
modes
[
layoutMode
];
if
(
!
mode
)
{
// TODO console.error
throw
new
Error
(
'No layout mode: '
+
layoutMode
);
}
// HACK sync mode's options
// any options set after init for layout mode need to be synced
mode
.
options
=
this
.
options
[
layoutMode
];
return
mode
;
};
proto
.
_resetLayout
=
function
()
{
// trigger original reset layout
Outlayer
.
prototype
.
_resetLayout
.
call
(
this
);
this
.
_mode
().
_resetLayout
();
};
proto
.
_getItemLayoutPosition
=
function
(
item
)
{
return
this
.
_mode
().
_getItemLayoutPosition
(
item
);
};
proto
.
_manageStamp
=
function
(
stamp
)
{
this
.
_mode
().
_manageStamp
(
stamp
);
};
proto
.
_getContainerSize
=
function
()
{
return
this
.
_mode
().
_getContainerSize
();
};
proto
.
needsResizeLayout
=
function
()
{
return
this
.
_mode
().
needsResizeLayout
();
};
// -------------------------- adding & removing -------------------------- //
// HEADS UP overwrites default Outlayer appended
proto
.
appended
=
function
(
elems
)
{
var
items
=
this
.
addItems
(
elems
);
if
(
!
items
.
length
)
{
return
;
}
// filter, layout, reveal new items
var
filteredItems
=
this
.
_filterRevealAdded
(
items
);
// add to filteredItems
this
.
filteredItems
=
this
.
filteredItems
.
concat
(
filteredItems
);
};
// HEADS UP overwrites default Outlayer prepended
proto
.
prepended
=
function
(
elems
)
{
var
items
=
this
.
_itemize
(
elems
);
if
(
!
items
.
length
)
{
return
;
}
// start new layout
this
.
_resetLayout
();
this
.
_manageStamps
();
// filter, layout, reveal new items
var
filteredItems
=
this
.
_filterRevealAdded
(
items
);
// layout previous items
this
.
layoutItems
(
this
.
filteredItems
);
// add to items and filteredItems
this
.
filteredItems
=
filteredItems
.
concat
(
this
.
filteredItems
);
this
.
items
=
items
.
concat
(
this
.
items
);
};
proto
.
_filterRevealAdded
=
function
(
items
)
{
var
filtered
=
this
.
_filter
(
items
);
this
.
hide
(
filtered
.
needHide
);
// reveal all new items
this
.
reveal
(
filtered
.
matches
);
// layout new items, no transition
this
.
layoutItems
(
filtered
.
matches
,
true
);
return
filtered
.
matches
;
};
/**
* Filter, sort, and layout newly-appended item elements
* @param {Array or NodeList or Element} elems
*/
proto
.
insert
=
function
(
elems
)
{
var
items
=
this
.
addItems
(
elems
);
if
(
!
items
.
length
)
{
return
;
}
// append item elements
var
i
,
item
;
var
len
=
items
.
length
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
item
=
items
[
i
];
this
.
element
.
appendChild
(
item
.
element
);
}
// filter new stuff
var
filteredInsertItems
=
this
.
_filter
(
items
).
matches
;
// set flag
for
(
i
=
0
;
i
<
len
;
i
++
)
{
items
[
i
].
isLayoutInstant
=
true
;
}
this
.
arrange
();
// reset flag
for
(
i
=
0
;
i
<
len
;
i
++
)
{
delete
items
[
i
].
isLayoutInstant
;
}
this
.
reveal
(
filteredInsertItems
);
};
var
_remove
=
proto
.
remove
;
proto
.
remove
=
function
(
elems
)
{
elems
=
utils
.
makeArray
(
elems
);
var
removeItems
=
this
.
getItems
(
elems
);
// do regular thing
_remove
.
call
(
this
,
elems
);
// bail if no items to remove
var
len
=
removeItems
&&
removeItems
.
length
;
// remove elems from filteredItems
for
(
var
i
=
0
;
len
&&
i
<
len
;
i
++
)
{
var
item
=
removeItems
[
i
];
// remove item from collection
utils
.
removeFrom
(
this
.
filteredItems
,
item
);
}
};
proto
.
shuffle
=
function
()
{
// update random sortData
for
(
var
i
=
0
;
i
<
this
.
items
.
length
;
i
++
)
{
var
item
=
this
.
items
[
i
];
item
.
sortData
.
random
=
Math
.
random
();
}
this
.
options
.
sortBy
=
'random'
;
this
.
_sort
();
this
.
_layout
();
};
/**
* trigger fn without transition
* kind of hacky to have this in the first place
* @param {Function} fn
* @param {Array} args
* @returns ret
* @private
*/
proto
.
_noTransition
=
function
(
fn
,
args
)
{
// save transitionDuration before disabling
var
transitionDuration
=
this
.
options
.
transitionDuration
;
// disable transition
this
.
options
.
transitionDuration
=
0
;
// do it
var
returnValue
=
fn
.
apply
(
this
,
args
);
// re-enable transition for reveal
this
.
options
.
transitionDuration
=
transitionDuration
;
return
returnValue
;
};
// ----- helper methods ----- //
/**
* getter method for getting filtered item elements
* @returns {Array} elems - collection of item elements
*/
proto
.
getFilteredItemElements
=
function
()
{
return
this
.
filteredItems
.
map
(
function
(
item
)
{
return
item
.
element
;
});
};
// ----- ----- //
return
Isotope
;
}));
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