53452 lines
1.9 MiB
53452 lines
1.9 MiB
/*
|
|
* File: iframeResizer.js
|
|
* Desc: Force iframes to size to content.
|
|
* Requires: iframeResizer.contentWindow.js to be loaded into the target frame.
|
|
* Doc: https://github.com/davidjbradshaw/iframe-resizer
|
|
* Author: David J. Bradshaw - dave@bradshaw.net
|
|
* Contributor: Jure Mav - jure.mav@gmail.com
|
|
* Contributor: Reed Dadoune - reed@dadoune.com
|
|
*/
|
|
|
|
// eslint-disable-next-line sonarjs/cognitive-complexity, no-shadow-restricted-names
|
|
;(function(undefined) {
|
|
if (typeof window === 'undefined') return // don't run for server side render
|
|
|
|
var count = 0,
|
|
logEnabled = false,
|
|
hiddenCheckEnabled = false,
|
|
msgHeader = 'message',
|
|
msgHeaderLen = msgHeader.length,
|
|
msgId = '[iFrameSizer]', // Must match iframe msg ID
|
|
msgIdLen = msgId.length,
|
|
pagePosition = null,
|
|
requestAnimationFrame = window.requestAnimationFrame,
|
|
resetRequiredMethods = {
|
|
max: 1,
|
|
scroll: 1,
|
|
bodyScroll: 1,
|
|
documentElementScroll: 1
|
|
},
|
|
settings = {},
|
|
timer = null,
|
|
defaults = {
|
|
autoResize: true,
|
|
bodyBackground: null,
|
|
bodyMargin: null,
|
|
bodyMarginV1: 8,
|
|
bodyPadding: null,
|
|
checkOrigin: true,
|
|
inPageLinks: false,
|
|
enablePublicMethods: true,
|
|
heightCalculationMethod: 'bodyOffset',
|
|
id: 'iFrameResizer',
|
|
interval: 32,
|
|
log: false,
|
|
maxHeight: Infinity,
|
|
maxWidth: Infinity,
|
|
minHeight: 0,
|
|
minWidth: 0,
|
|
resizeFrom: 'parent',
|
|
scrolling: false,
|
|
sizeHeight: true,
|
|
sizeWidth: false,
|
|
warningTimeout: 5000,
|
|
tolerance: 0,
|
|
widthCalculationMethod: 'scroll',
|
|
onClosed: function() {},
|
|
onInit: function() {},
|
|
onMessage: function() {
|
|
warn('onMessage function not defined')
|
|
},
|
|
onResized: function() {},
|
|
onScroll: function() {
|
|
return true
|
|
}
|
|
}
|
|
|
|
function getMutationObserver() {
|
|
return (
|
|
window.MutationObserver ||
|
|
window.WebKitMutationObserver ||
|
|
window.MozMutationObserver
|
|
)
|
|
}
|
|
|
|
function addEventListener(el, evt, func) {
|
|
el.addEventListener(evt, func, false)
|
|
}
|
|
|
|
function removeEventListener(el, evt, func) {
|
|
el.removeEventListener(evt, func, false)
|
|
}
|
|
|
|
function setupRequestAnimationFrame() {
|
|
var vendors = ['moz', 'webkit', 'o', 'ms']
|
|
var x
|
|
|
|
// Remove vendor prefixing if prefixed and break early if not
|
|
for (x = 0; x < vendors.length && !requestAnimationFrame; x += 1) {
|
|
requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']
|
|
}
|
|
|
|
if (!requestAnimationFrame) {
|
|
log('setup', 'RequestAnimationFrame not supported')
|
|
}
|
|
}
|
|
|
|
function getMyID(iframeId) {
|
|
var retStr = 'Host page: ' + iframeId
|
|
|
|
if (window.top !== window.self) {
|
|
if (window.parentIFrame && window.parentIFrame.getId) {
|
|
retStr = window.parentIFrame.getId() + ': ' + iframeId
|
|
} else {
|
|
retStr = 'Nested host page: ' + iframeId
|
|
}
|
|
}
|
|
|
|
return retStr
|
|
}
|
|
|
|
function formatLogHeader(iframeId) {
|
|
return msgId + '[' + getMyID(iframeId) + ']'
|
|
}
|
|
|
|
function isLogEnabled(iframeId) {
|
|
return settings[iframeId] ? settings[iframeId].log : logEnabled
|
|
}
|
|
|
|
function log(iframeId, msg) {
|
|
output('log', iframeId, msg, isLogEnabled(iframeId))
|
|
}
|
|
|
|
function info(iframeId, msg) {
|
|
output('info', iframeId, msg, isLogEnabled(iframeId))
|
|
}
|
|
|
|
function warn(iframeId, msg) {
|
|
output('warn', iframeId, msg, true)
|
|
}
|
|
|
|
function output(type, iframeId, msg, enabled) {
|
|
if (true === enabled && 'object' === typeof window.console) {
|
|
// eslint-disable-next-line no-console
|
|
console[type](formatLogHeader(iframeId), msg)
|
|
}
|
|
}
|
|
|
|
function iFrameListener(event) {
|
|
function resizeIFrame() {
|
|
function resize() {
|
|
setSize(messageData)
|
|
setPagePosition(iframeId)
|
|
on('onResized', messageData)
|
|
}
|
|
|
|
ensureInRange('Height')
|
|
ensureInRange('Width')
|
|
|
|
syncResize(resize, messageData, 'init')
|
|
}
|
|
|
|
function processMsg() {
|
|
var data = msg.substr(msgIdLen).split(':')
|
|
|
|
return {
|
|
iframe: settings[data[0]] && settings[data[0]].iframe,
|
|
id: data[0],
|
|
height: data[1],
|
|
width: data[2],
|
|
type: data[3]
|
|
}
|
|
}
|
|
|
|
function ensureInRange(Dimension) {
|
|
var max = Number(settings[iframeId]['max' + Dimension]),
|
|
min = Number(settings[iframeId]['min' + Dimension]),
|
|
dimension = Dimension.toLowerCase(),
|
|
size = Number(messageData[dimension])
|
|
|
|
log(iframeId, 'Checking ' + dimension + ' is in range ' + min + '-' + max)
|
|
|
|
if (size < min) {
|
|
size = min
|
|
log(iframeId, 'Set ' + dimension + ' to min value')
|
|
}
|
|
|
|
if (size > max) {
|
|
size = max
|
|
log(iframeId, 'Set ' + dimension + ' to max value')
|
|
}
|
|
|
|
messageData[dimension] = '' + size
|
|
}
|
|
|
|
function isMessageFromIFrame() {
|
|
function checkAllowedOrigin() {
|
|
function checkList() {
|
|
var i = 0,
|
|
retCode = false
|
|
|
|
log(
|
|
iframeId,
|
|
'Checking connection is from allowed list of origins: ' +
|
|
checkOrigin
|
|
)
|
|
|
|
for (; i < checkOrigin.length; i++) {
|
|
if (checkOrigin[i] === origin) {
|
|
retCode = true
|
|
break
|
|
}
|
|
}
|
|
return retCode
|
|
}
|
|
|
|
function checkSingle() {
|
|
var remoteHost = settings[iframeId] && settings[iframeId].remoteHost
|
|
log(iframeId, 'Checking connection is from: ' + remoteHost)
|
|
return origin === remoteHost
|
|
}
|
|
|
|
return checkOrigin.constructor === Array ? checkList() : checkSingle()
|
|
}
|
|
|
|
var origin = event.origin,
|
|
checkOrigin = settings[iframeId] && settings[iframeId].checkOrigin
|
|
|
|
if (checkOrigin && '' + origin !== 'null' && !checkAllowedOrigin()) {
|
|
throw new Error(
|
|
'Unexpected message received from: ' +
|
|
origin +
|
|
' for ' +
|
|
messageData.iframe.id +
|
|
'. Message was: ' +
|
|
event.data +
|
|
'. This error can be disabled by setting the checkOrigin: false option or by providing of array of trusted domains.'
|
|
)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
function isMessageForUs() {
|
|
return (
|
|
msgId === ('' + msg).substr(0, msgIdLen) &&
|
|
msg.substr(msgIdLen).split(':')[0] in settings
|
|
) // ''+Protects against non-string msg
|
|
}
|
|
|
|
function isMessageFromMetaParent() {
|
|
// Test if this message is from a parent above us. This is an ugly test, however, updating
|
|
// the message format would break backwards compatibity.
|
|
var retCode = messageData.type in { true: 1, false: 1, undefined: 1 }
|
|
|
|
if (retCode) {
|
|
log(iframeId, 'Ignoring init message from meta parent page')
|
|
}
|
|
|
|
return retCode
|
|
}
|
|
|
|
function getMsgBody(offset) {
|
|
return msg.substr(msg.indexOf(':') + msgHeaderLen + offset)
|
|
}
|
|
|
|
function forwardMsgFromIFrame(msgBody) {
|
|
log(
|
|
iframeId,
|
|
'onMessage passed: {iframe: ' +
|
|
messageData.iframe.id +
|
|
', message: ' +
|
|
msgBody +
|
|
'}'
|
|
)
|
|
on('onMessage', {
|
|
iframe: messageData.iframe,
|
|
message: JSON.parse(msgBody)
|
|
})
|
|
log(iframeId, '--')
|
|
}
|
|
|
|
function getPageInfo() {
|
|
var bodyPosition = document.body.getBoundingClientRect(),
|
|
iFramePosition = messageData.iframe.getBoundingClientRect()
|
|
|
|
return JSON.stringify({
|
|
iframeHeight: iFramePosition.height,
|
|
iframeWidth: iFramePosition.width,
|
|
clientHeight: Math.max(
|
|
document.documentElement.clientHeight,
|
|
window.innerHeight || 0
|
|
),
|
|
clientWidth: Math.max(
|
|
document.documentElement.clientWidth,
|
|
window.innerWidth || 0
|
|
),
|
|
offsetTop: parseInt(iFramePosition.top - bodyPosition.top, 10),
|
|
offsetLeft: parseInt(iFramePosition.left - bodyPosition.left, 10),
|
|
scrollTop: window.pageYOffset,
|
|
scrollLeft: window.pageXOffset,
|
|
documentHeight: document.documentElement.clientHeight,
|
|
documentWidth: document.documentElement.clientWidth,
|
|
windowHeight: window.innerHeight,
|
|
windowWidth: window.innerWidth
|
|
})
|
|
}
|
|
|
|
function sendPageInfoToIframe(iframe, iframeId) {
|
|
function debouncedTrigger() {
|
|
trigger('Send Page Info', 'pageInfo:' + getPageInfo(), iframe, iframeId)
|
|
}
|
|
debounceFrameEvents(debouncedTrigger, 32, iframeId)
|
|
}
|
|
|
|
function startPageInfoMonitor() {
|
|
function setListener(type, func) {
|
|
function sendPageInfo() {
|
|
if (settings[id]) {
|
|
sendPageInfoToIframe(settings[id].iframe, id)
|
|
} else {
|
|
stop()
|
|
}
|
|
}
|
|
|
|
;['scroll', 'resize'].forEach(function(evt) {
|
|
log(id, type + evt + ' listener for sendPageInfo')
|
|
func(window, evt, sendPageInfo)
|
|
})
|
|
}
|
|
|
|
function stop() {
|
|
setListener('Remove ', removeEventListener)
|
|
}
|
|
|
|
function start() {
|
|
setListener('Add ', addEventListener)
|
|
}
|
|
|
|
var id = iframeId // Create locally scoped copy of iFrame ID
|
|
|
|
start()
|
|
|
|
if (settings[id]) {
|
|
settings[id].stopPageInfo = stop
|
|
}
|
|
}
|
|
|
|
function stopPageInfoMonitor() {
|
|
if (settings[iframeId] && settings[iframeId].stopPageInfo) {
|
|
settings[iframeId].stopPageInfo()
|
|
delete settings[iframeId].stopPageInfo
|
|
}
|
|
}
|
|
|
|
function checkIFrameExists() {
|
|
var retBool = true
|
|
|
|
if (null === messageData.iframe) {
|
|
warn(iframeId, 'IFrame (' + messageData.id + ') not found')
|
|
retBool = false
|
|
}
|
|
return retBool
|
|
}
|
|
|
|
function getElementPosition(target) {
|
|
var iFramePosition = target.getBoundingClientRect()
|
|
|
|
getPagePosition(iframeId)
|
|
|
|
return {
|
|
x: Math.floor(Number(iFramePosition.left) + Number(pagePosition.x)),
|
|
y: Math.floor(Number(iFramePosition.top) + Number(pagePosition.y))
|
|
}
|
|
}
|
|
|
|
function scrollRequestFromChild(addOffset) {
|
|
/* istanbul ignore next */ // Not testable in Karma
|
|
function reposition() {
|
|
pagePosition = newPosition
|
|
scrollTo()
|
|
log(iframeId, '--')
|
|
}
|
|
|
|
function calcOffset() {
|
|
return {
|
|
x: Number(messageData.width) + offset.x,
|
|
y: Number(messageData.height) + offset.y
|
|
}
|
|
}
|
|
|
|
function scrollParent() {
|
|
if (window.parentIFrame) {
|
|
window.parentIFrame['scrollTo' + (addOffset ? 'Offset' : '')](
|
|
newPosition.x,
|
|
newPosition.y
|
|
)
|
|
} else {
|
|
warn(
|
|
iframeId,
|
|
'Unable to scroll to requested position, window.parentIFrame not found'
|
|
)
|
|
}
|
|
}
|
|
|
|
var offset = addOffset
|
|
? getElementPosition(messageData.iframe)
|
|
: { x: 0, y: 0 },
|
|
newPosition = calcOffset()
|
|
|
|
log(
|
|
iframeId,
|
|
'Reposition requested from iFrame (offset x:' +
|
|
offset.x +
|
|
' y:' +
|
|
offset.y +
|
|
')'
|
|
)
|
|
|
|
if (window.top !== window.self) {
|
|
scrollParent()
|
|
} else {
|
|
reposition()
|
|
}
|
|
}
|
|
|
|
function scrollTo() {
|
|
if (false !== on('onScroll', pagePosition)) {
|
|
setPagePosition(iframeId)
|
|
} else {
|
|
unsetPagePosition()
|
|
}
|
|
}
|
|
|
|
function findTarget(location) {
|
|
function jumpToTarget() {
|
|
var jumpPosition = getElementPosition(target)
|
|
|
|
log(
|
|
iframeId,
|
|
'Moving to in page link (#' +
|
|
hash +
|
|
') at x: ' +
|
|
jumpPosition.x +
|
|
' y: ' +
|
|
jumpPosition.y
|
|
)
|
|
pagePosition = {
|
|
x: jumpPosition.x,
|
|
y: jumpPosition.y
|
|
}
|
|
|
|
scrollTo()
|
|
log(iframeId, '--')
|
|
}
|
|
|
|
function jumpToParent() {
|
|
if (window.parentIFrame) {
|
|
window.parentIFrame.moveToAnchor(hash)
|
|
} else {
|
|
log(
|
|
iframeId,
|
|
'In page link #' +
|
|
hash +
|
|
' not found and window.parentIFrame not found'
|
|
)
|
|
}
|
|
}
|
|
|
|
var hash = location.split('#')[1] || '',
|
|
hashData = decodeURIComponent(hash),
|
|
target =
|
|
document.getElementById(hashData) ||
|
|
document.getElementsByName(hashData)[0]
|
|
|
|
if (target) {
|
|
jumpToTarget()
|
|
} else if (window.top !== window.self) {
|
|
jumpToParent()
|
|
} else {
|
|
log(iframeId, 'In page link #' + hash + ' not found')
|
|
}
|
|
}
|
|
|
|
function on(funcName, val) {
|
|
return chkEvent(iframeId, funcName, val)
|
|
}
|
|
|
|
function actionMsg() {
|
|
if (settings[iframeId] && settings[iframeId].firstRun) firstRun()
|
|
|
|
switch (messageData.type) {
|
|
case 'close':
|
|
if (settings[iframeId].closeRequeston)
|
|
chkEvent(iframeId, 'onCloseRequest', settings[iframeId].iframe)
|
|
else closeIFrame(messageData.iframe)
|
|
break
|
|
|
|
case 'message':
|
|
forwardMsgFromIFrame(getMsgBody(6))
|
|
break
|
|
|
|
case 'scrollTo':
|
|
scrollRequestFromChild(false)
|
|
break
|
|
|
|
case 'scrollToOffset':
|
|
scrollRequestFromChild(true)
|
|
break
|
|
|
|
case 'pageInfo':
|
|
sendPageInfoToIframe(
|
|
settings[iframeId] && settings[iframeId].iframe,
|
|
iframeId
|
|
)
|
|
startPageInfoMonitor()
|
|
break
|
|
|
|
case 'pageInfoStop':
|
|
stopPageInfoMonitor()
|
|
break
|
|
|
|
case 'inPageLink':
|
|
findTarget(getMsgBody(9))
|
|
break
|
|
|
|
case 'reset':
|
|
resetIFrame(messageData)
|
|
break
|
|
|
|
case 'init':
|
|
resizeIFrame()
|
|
on('onInit', messageData.iframe)
|
|
break
|
|
|
|
default:
|
|
resizeIFrame()
|
|
}
|
|
}
|
|
|
|
function hasSettings(iframeId) {
|
|
var retBool = true
|
|
|
|
if (!settings[iframeId]) {
|
|
retBool = false
|
|
warn(
|
|
messageData.type +
|
|
' No settings for ' +
|
|
iframeId +
|
|
'. Message was: ' +
|
|
msg
|
|
)
|
|
}
|
|
|
|
return retBool
|
|
}
|
|
|
|
function iFrameReadyMsgReceived() {
|
|
// eslint-disable-next-line no-restricted-syntax, guard-for-in
|
|
for (var iframeId in settings) {
|
|
trigger(
|
|
'iFrame requested init',
|
|
createOutgoingMsg(iframeId),
|
|
document.getElementById(iframeId),
|
|
iframeId
|
|
)
|
|
}
|
|
}
|
|
|
|
function firstRun() {
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].firstRun = false
|
|
}
|
|
}
|
|
|
|
var msg = event.data,
|
|
messageData = {},
|
|
iframeId = null
|
|
|
|
if ('[iFrameResizerChild]Ready' === msg) {
|
|
iFrameReadyMsgReceived()
|
|
} else if (isMessageForUs()) {
|
|
messageData = processMsg()
|
|
iframeId = messageData.id
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].loaded = true
|
|
}
|
|
|
|
if (!isMessageFromMetaParent() && hasSettings(iframeId)) {
|
|
log(iframeId, 'Received: ' + msg)
|
|
|
|
if (checkIFrameExists() && isMessageFromIFrame()) {
|
|
actionMsg()
|
|
}
|
|
}
|
|
} else {
|
|
info(iframeId, 'Ignored: ' + msg)
|
|
}
|
|
}
|
|
|
|
function chkEvent(iframeId, funcName, val) {
|
|
var func = null,
|
|
retVal = null
|
|
|
|
if (settings[iframeId]) {
|
|
func = settings[iframeId][funcName]
|
|
|
|
if ('function' === typeof func) {
|
|
retVal = func(val)
|
|
} else {
|
|
throw new TypeError(
|
|
funcName + ' on iFrame[' + iframeId + '] is not a function'
|
|
)
|
|
}
|
|
}
|
|
|
|
return retVal
|
|
}
|
|
|
|
function removeIframeListeners(iframe) {
|
|
var iframeId = iframe.id
|
|
delete settings[iframeId]
|
|
}
|
|
|
|
function closeIFrame(iframe) {
|
|
var iframeId = iframe.id
|
|
log(iframeId, 'Removing iFrame: ' + iframeId)
|
|
|
|
try {
|
|
// Catch race condition error with React
|
|
if (iframe.parentNode) {
|
|
iframe.parentNode.removeChild(iframe)
|
|
}
|
|
} catch (error) {
|
|
warn(error)
|
|
}
|
|
|
|
chkEvent(iframeId, 'onClosed', iframeId)
|
|
log(iframeId, '--')
|
|
removeIframeListeners(iframe)
|
|
}
|
|
|
|
function getPagePosition(iframeId) {
|
|
if (null === pagePosition) {
|
|
pagePosition = {
|
|
x:
|
|
window.pageXOffset !== undefined
|
|
? window.pageXOffset
|
|
: document.documentElement.scrollLeft,
|
|
y:
|
|
window.pageYOffset !== undefined
|
|
? window.pageYOffset
|
|
: document.documentElement.scrollTop
|
|
}
|
|
log(
|
|
iframeId,
|
|
'Get page position: ' + pagePosition.x + ',' + pagePosition.y
|
|
)
|
|
}
|
|
}
|
|
|
|
function setPagePosition(iframeId) {
|
|
if (null !== pagePosition) {
|
|
window.scrollTo(pagePosition.x, pagePosition.y)
|
|
log(
|
|
iframeId,
|
|
'Set page position: ' + pagePosition.x + ',' + pagePosition.y
|
|
)
|
|
unsetPagePosition()
|
|
}
|
|
}
|
|
|
|
function unsetPagePosition() {
|
|
pagePosition = null
|
|
}
|
|
|
|
function resetIFrame(messageData) {
|
|
function reset() {
|
|
setSize(messageData)
|
|
trigger('reset', 'reset', messageData.iframe, messageData.id)
|
|
}
|
|
|
|
log(
|
|
messageData.id,
|
|
'Size reset requested by ' +
|
|
('init' === messageData.type ? 'host page' : 'iFrame')
|
|
)
|
|
getPagePosition(messageData.id)
|
|
syncResize(reset, messageData, 'reset')
|
|
}
|
|
|
|
function setSize(messageData) {
|
|
function setDimension(dimension) {
|
|
if (!messageData.id) {
|
|
log('undefined', 'messageData id not set')
|
|
return
|
|
}
|
|
messageData.iframe.style[dimension] = messageData[dimension] + 'px'
|
|
log(
|
|
messageData.id,
|
|
'IFrame (' +
|
|
iframeId +
|
|
') ' +
|
|
dimension +
|
|
' set to ' +
|
|
messageData[dimension] +
|
|
'px'
|
|
)
|
|
}
|
|
|
|
function chkZero(dimension) {
|
|
// FireFox sets dimension of hidden iFrames to zero.
|
|
// So if we detect that set up an event to check for
|
|
// when iFrame becomes visible.
|
|
|
|
/* istanbul ignore next */ // Not testable in PhantomJS
|
|
if (!hiddenCheckEnabled && '0' === messageData[dimension]) {
|
|
hiddenCheckEnabled = true
|
|
log(iframeId, 'Hidden iFrame detected, creating visibility listener')
|
|
fixHiddenIFrames()
|
|
}
|
|
}
|
|
|
|
function processDimension(dimension) {
|
|
setDimension(dimension)
|
|
chkZero(dimension)
|
|
}
|
|
|
|
var iframeId = messageData.iframe.id
|
|
|
|
if (settings[iframeId]) {
|
|
if (settings[iframeId].sizeHeight) {
|
|
processDimension('height')
|
|
}
|
|
if (settings[iframeId].sizeWidth) {
|
|
processDimension('width')
|
|
}
|
|
}
|
|
}
|
|
|
|
function syncResize(func, messageData, doNotSync) {
|
|
/* istanbul ignore if */ // Not testable in PhantomJS
|
|
if (doNotSync !== messageData.type && requestAnimationFrame) {
|
|
log(messageData.id, 'Requesting animation frame')
|
|
requestAnimationFrame(func)
|
|
} else {
|
|
func()
|
|
}
|
|
}
|
|
|
|
function trigger(calleeMsg, msg, iframe, id, noResponseWarning) {
|
|
function postMessageToIFrame() {
|
|
var target = settings[id] && settings[id].targetOrigin
|
|
log(
|
|
id,
|
|
'[' +
|
|
calleeMsg +
|
|
'] Sending msg to iframe[' +
|
|
id +
|
|
'] (' +
|
|
msg +
|
|
') targetOrigin: ' +
|
|
target
|
|
)
|
|
iframe.contentWindow.postMessage(msgId + msg, target)
|
|
}
|
|
|
|
function iFrameNotFound() {
|
|
warn(id, '[' + calleeMsg + '] IFrame(' + id + ') not found')
|
|
}
|
|
|
|
function chkAndSend() {
|
|
if (
|
|
iframe &&
|
|
'contentWindow' in iframe &&
|
|
null !== iframe.contentWindow
|
|
) {
|
|
// Null test for PhantomJS
|
|
postMessageToIFrame()
|
|
} else {
|
|
iFrameNotFound()
|
|
}
|
|
}
|
|
|
|
function warnOnNoResponse() {
|
|
function warning() {
|
|
if (settings[id] && !settings[id].loaded && !errorShown) {
|
|
errorShown = true
|
|
warn(
|
|
id,
|
|
'IFrame has not responded within ' +
|
|
settings[id].warningTimeout / 1000 +
|
|
' seconds. Check iFrameResizer.contentWindow.js has been loaded in iFrame. This message can be ignored if everything is working, or you can set the warningTimeout option to a higher value or zero to suppress this warning.'
|
|
)
|
|
}
|
|
}
|
|
|
|
if (
|
|
!!noResponseWarning &&
|
|
settings[id] &&
|
|
!!settings[id].warningTimeout
|
|
) {
|
|
settings[id].msgTimeout = setTimeout(
|
|
warning,
|
|
settings[id].warningTimeout
|
|
)
|
|
}
|
|
}
|
|
|
|
var errorShown = false
|
|
|
|
id = id || iframe.id
|
|
|
|
if (settings[id]) {
|
|
chkAndSend()
|
|
warnOnNoResponse()
|
|
}
|
|
}
|
|
|
|
function createOutgoingMsg(iframeId) {
|
|
return (
|
|
iframeId +
|
|
':' +
|
|
settings[iframeId].bodyMarginV1 +
|
|
':' +
|
|
settings[iframeId].sizeWidth +
|
|
':' +
|
|
settings[iframeId].log +
|
|
':' +
|
|
settings[iframeId].interval +
|
|
':' +
|
|
settings[iframeId].enablePublicMethods +
|
|
':' +
|
|
settings[iframeId].autoResize +
|
|
':' +
|
|
settings[iframeId].bodyMargin +
|
|
':' +
|
|
settings[iframeId].heightCalculationMethod +
|
|
':' +
|
|
settings[iframeId].bodyBackground +
|
|
':' +
|
|
settings[iframeId].bodyPadding +
|
|
':' +
|
|
settings[iframeId].tolerance +
|
|
':' +
|
|
settings[iframeId].inPageLinks +
|
|
':' +
|
|
settings[iframeId].resizeFrom +
|
|
':' +
|
|
settings[iframeId].widthCalculationMethod
|
|
)
|
|
}
|
|
|
|
function setupIFrame(iframe, options) {
|
|
function setLimits() {
|
|
function addStyle(style) {
|
|
if (
|
|
Infinity !== settings[iframeId][style] &&
|
|
0 !== settings[iframeId][style]
|
|
) {
|
|
iframe.style[style] = settings[iframeId][style] + 'px'
|
|
log(
|
|
iframeId,
|
|
'Set ' + style + ' = ' + settings[iframeId][style] + 'px'
|
|
)
|
|
}
|
|
}
|
|
|
|
function chkMinMax(dimension) {
|
|
if (
|
|
settings[iframeId]['min' + dimension] >
|
|
settings[iframeId]['max' + dimension]
|
|
) {
|
|
throw new Error(
|
|
'Value for min' +
|
|
dimension +
|
|
' can not be greater than max' +
|
|
dimension
|
|
)
|
|
}
|
|
}
|
|
|
|
chkMinMax('Height')
|
|
chkMinMax('Width')
|
|
|
|
addStyle('maxHeight')
|
|
addStyle('minHeight')
|
|
addStyle('maxWidth')
|
|
addStyle('minWidth')
|
|
}
|
|
|
|
function newId() {
|
|
var id = (options && options.id) || defaults.id + count++
|
|
if (null !== document.getElementById(id)) {
|
|
id += count++
|
|
}
|
|
return id
|
|
}
|
|
|
|
function ensureHasId(iframeId) {
|
|
if ('' === iframeId) {
|
|
// eslint-disable-next-line no-multi-assign
|
|
iframe.id = iframeId = newId()
|
|
logEnabled = (options || {}).log
|
|
log(
|
|
iframeId,
|
|
'Added missing iframe ID: ' + iframeId + ' (' + iframe.src + ')'
|
|
)
|
|
}
|
|
|
|
return iframeId
|
|
}
|
|
|
|
function setScrolling() {
|
|
log(
|
|
iframeId,
|
|
'IFrame scrolling ' +
|
|
(settings[iframeId] && settings[iframeId].scrolling
|
|
? 'enabled'
|
|
: 'disabled') +
|
|
' for ' +
|
|
iframeId
|
|
)
|
|
iframe.style.overflow =
|
|
false === (settings[iframeId] && settings[iframeId].scrolling)
|
|
? 'hidden'
|
|
: 'auto'
|
|
switch (settings[iframeId] && settings[iframeId].scrolling) {
|
|
case 'omit':
|
|
break
|
|
|
|
case true:
|
|
iframe.scrolling = 'yes'
|
|
break
|
|
|
|
case false:
|
|
iframe.scrolling = 'no'
|
|
break
|
|
|
|
default:
|
|
iframe.scrolling = settings[iframeId]
|
|
? settings[iframeId].scrolling
|
|
: 'no'
|
|
}
|
|
}
|
|
|
|
// The V1 iFrame script expects an int, where as in V2 expects a CSS
|
|
// string value such as '1px 3em', so if we have an int for V2, set V1=V2
|
|
// and then convert V2 to a string PX value.
|
|
function setupBodyMarginValues() {
|
|
if (
|
|
'number' ===
|
|
typeof (settings[iframeId] && settings[iframeId].bodyMargin) ||
|
|
'0' === (settings[iframeId] && settings[iframeId].bodyMargin)
|
|
) {
|
|
settings[iframeId].bodyMarginV1 = settings[iframeId].bodyMargin
|
|
settings[iframeId].bodyMargin =
|
|
'' + settings[iframeId].bodyMargin + 'px'
|
|
}
|
|
}
|
|
|
|
function checkReset() {
|
|
// Reduce scope of firstRun to function, because IE8's JS execution
|
|
// context stack is borked and this value gets externally
|
|
// changed midway through running this function!!!
|
|
var firstRun = settings[iframeId] && settings[iframeId].firstRun,
|
|
resetRequertMethod =
|
|
settings[iframeId] &&
|
|
settings[iframeId].heightCalculationMethod in resetRequiredMethods
|
|
|
|
if (!firstRun && resetRequertMethod) {
|
|
resetIFrame({ iframe: iframe, height: 0, width: 0, type: 'init' })
|
|
}
|
|
}
|
|
|
|
function setupIFrameObject() {
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].iframe.iFrameResizer = {
|
|
close: closeIFrame.bind(null, settings[iframeId].iframe),
|
|
|
|
removeListeners: removeIframeListeners.bind(
|
|
null,
|
|
settings[iframeId].iframe
|
|
),
|
|
|
|
resize: trigger.bind(
|
|
null,
|
|
'Window resize',
|
|
'resize',
|
|
settings[iframeId].iframe
|
|
),
|
|
|
|
moveToAnchor: function(anchor) {
|
|
trigger(
|
|
'Move to anchor',
|
|
'moveToAnchor:' + anchor,
|
|
settings[iframeId].iframe,
|
|
iframeId
|
|
)
|
|
},
|
|
|
|
sendMessage: function(message) {
|
|
message = JSON.stringify(message)
|
|
trigger(
|
|
'Send Message',
|
|
'message:' + message,
|
|
settings[iframeId].iframe,
|
|
iframeId
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// We have to call trigger twice, as we can not be sure if all
|
|
// iframes have completed loading when this code runs. The
|
|
// event listener also catches the page changing in the iFrame.
|
|
function init(msg) {
|
|
function iFrameLoaded() {
|
|
trigger('iFrame.onload', msg, iframe, undefined, true)
|
|
checkReset()
|
|
}
|
|
|
|
function createDestroyObserver(MutationObserver) {
|
|
if (!iframe.parentNode) {
|
|
return
|
|
}
|
|
|
|
var destroyObserver = new MutationObserver(function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
var removedNodes = Array.prototype.slice.call(mutation.removedNodes) // Transform NodeList into an Array
|
|
removedNodes.forEach(function(removedNode) {
|
|
if (removedNode === iframe) {
|
|
closeIFrame(iframe)
|
|
}
|
|
})
|
|
})
|
|
})
|
|
destroyObserver.observe(iframe.parentNode, {
|
|
childList: true
|
|
})
|
|
}
|
|
|
|
var MutationObserver = getMutationObserver()
|
|
if (MutationObserver) {
|
|
createDestroyObserver(MutationObserver)
|
|
}
|
|
|
|
addEventListener(iframe, 'load', iFrameLoaded)
|
|
trigger('init', msg, iframe, undefined, true)
|
|
}
|
|
|
|
function checkOptions(options) {
|
|
if ('object' !== typeof options) {
|
|
throw new TypeError('Options is not an object')
|
|
}
|
|
}
|
|
|
|
function copyOptions(options) {
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
for (var option in defaults) {
|
|
if (Object.prototype.hasOwnProperty.call(defaults, option)) {
|
|
settings[iframeId][option] = Object.prototype.hasOwnProperty.call(
|
|
options,
|
|
option
|
|
)
|
|
? options[option]
|
|
: defaults[option]
|
|
}
|
|
}
|
|
}
|
|
|
|
function getTargetOrigin(remoteHost) {
|
|
return '' === remoteHost || 'file://' === remoteHost ? '*' : remoteHost
|
|
}
|
|
|
|
function depricate(key) {
|
|
var splitName = key.split('Callback')
|
|
|
|
if (splitName.length === 2) {
|
|
var name =
|
|
'on' + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1)
|
|
this[name] = this[key]
|
|
delete this[key]
|
|
warn(
|
|
iframeId,
|
|
"Deprecated: '" +
|
|
key +
|
|
"' has been renamed '" +
|
|
name +
|
|
"'. The old method will be removed in the next major version."
|
|
)
|
|
}
|
|
}
|
|
|
|
function processOptions(options) {
|
|
options = options || {}
|
|
settings[iframeId] = {
|
|
firstRun: true,
|
|
iframe: iframe,
|
|
remoteHost: iframe.src
|
|
.split('/')
|
|
.slice(0, 3)
|
|
.join('/')
|
|
}
|
|
|
|
checkOptions(options)
|
|
Object.keys(options).forEach(depricate, options)
|
|
copyOptions(options)
|
|
|
|
if (settings[iframeId]) {
|
|
settings[iframeId].targetOrigin =
|
|
true === settings[iframeId].checkOrigin
|
|
? getTargetOrigin(settings[iframeId].remoteHost)
|
|
: '*'
|
|
}
|
|
}
|
|
|
|
function beenHere() {
|
|
return iframeId in settings && 'iFrameResizer' in iframe
|
|
}
|
|
|
|
var iframeId = ensureHasId(iframe.id)
|
|
|
|
if (!beenHere()) {
|
|
processOptions(options)
|
|
setScrolling()
|
|
setLimits()
|
|
setupBodyMarginValues()
|
|
init(createOutgoingMsg(iframeId))
|
|
setupIFrameObject()
|
|
} else {
|
|
warn(iframeId, 'Ignored iFrame, already setup.')
|
|
}
|
|
}
|
|
|
|
function debouce(fn, time) {
|
|
if (null === timer) {
|
|
timer = setTimeout(function() {
|
|
timer = null
|
|
fn()
|
|
}, time)
|
|
}
|
|
}
|
|
|
|
var frameTimer = {}
|
|
function debounceFrameEvents(fn, time, frameId) {
|
|
if (!frameTimer[frameId]) {
|
|
frameTimer[frameId] = setTimeout(function() {
|
|
frameTimer[frameId] = null
|
|
fn()
|
|
}, time)
|
|
}
|
|
}
|
|
|
|
// Not testable in PhantomJS
|
|
/* istanbul ignore next */
|
|
|
|
function fixHiddenIFrames() {
|
|
function checkIFrames() {
|
|
function checkIFrame(settingId) {
|
|
function chkDimension(dimension) {
|
|
return (
|
|
'0px' ===
|
|
(settings[settingId] && settings[settingId].iframe.style[dimension])
|
|
)
|
|
}
|
|
|
|
function isVisible(el) {
|
|
return null !== el.offsetParent
|
|
}
|
|
|
|
if (
|
|
settings[settingId] &&
|
|
isVisible(settings[settingId].iframe) &&
|
|
(chkDimension('height') || chkDimension('width'))
|
|
) {
|
|
trigger(
|
|
'Visibility change',
|
|
'resize',
|
|
settings[settingId].iframe,
|
|
settingId
|
|
)
|
|
}
|
|
}
|
|
|
|
Object.keys(settings).forEach(function(key) {
|
|
checkIFrame(settings[key])
|
|
})
|
|
}
|
|
|
|
function mutationObserved(mutations) {
|
|
log(
|
|
'window',
|
|
'Mutation observed: ' + mutations[0].target + ' ' + mutations[0].type
|
|
)
|
|
debouce(checkIFrames, 16)
|
|
}
|
|
|
|
function createMutationObserver() {
|
|
var target = document.querySelector('body'),
|
|
config = {
|
|
attributes: true,
|
|
attributeOldValue: false,
|
|
characterData: true,
|
|
characterDataOldValue: false,
|
|
childList: true,
|
|
subtree: true
|
|
},
|
|
observer = new MutationObserver(mutationObserved)
|
|
|
|
observer.observe(target, config)
|
|
}
|
|
|
|
var MutationObserver = getMutationObserver()
|
|
if (MutationObserver) {
|
|
createMutationObserver()
|
|
}
|
|
}
|
|
|
|
function resizeIFrames(event) {
|
|
function resize() {
|
|
sendTriggerMsg('Window ' + event, 'resize')
|
|
}
|
|
|
|
log('window', 'Trigger event: ' + event)
|
|
debouce(resize, 16)
|
|
}
|
|
|
|
// Not testable in PhantomJS
|
|
/* istanbul ignore next */
|
|
function tabVisible() {
|
|
function resize() {
|
|
sendTriggerMsg('Tab Visable', 'resize')
|
|
}
|
|
|
|
if ('hidden' !== document.visibilityState) {
|
|
log('document', 'Trigger event: Visiblity change')
|
|
debouce(resize, 16)
|
|
}
|
|
}
|
|
|
|
function sendTriggerMsg(eventName, event) {
|
|
function isIFrameResizeEnabled(iframeId) {
|
|
return (
|
|
settings[iframeId] &&
|
|
'parent' === settings[iframeId].resizeFrom &&
|
|
settings[iframeId].autoResize &&
|
|
!settings[iframeId].firstRun
|
|
)
|
|
}
|
|
|
|
Object.keys(settings).forEach(function(iframeId) {
|
|
if (isIFrameResizeEnabled(iframeId)) {
|
|
trigger(eventName, event, document.getElementById(iframeId), iframeId)
|
|
}
|
|
})
|
|
}
|
|
|
|
function setupEventListeners() {
|
|
addEventListener(window, 'message', iFrameListener)
|
|
|
|
addEventListener(window, 'resize', function() {
|
|
resizeIFrames('resize')
|
|
})
|
|
|
|
addEventListener(document, 'visibilitychange', tabVisible)
|
|
|
|
addEventListener(document, '-webkit-visibilitychange', tabVisible)
|
|
}
|
|
|
|
function factory() {
|
|
function init(options, element) {
|
|
function chkType() {
|
|
if (!element.tagName) {
|
|
throw new TypeError('Object is not a valid DOM element')
|
|
} else if ('IFRAME' !== element.tagName.toUpperCase()) {
|
|
throw new TypeError(
|
|
'Expected <IFRAME> tag, found <' + element.tagName + '>'
|
|
)
|
|
}
|
|
}
|
|
|
|
if (element) {
|
|
chkType()
|
|
setupIFrame(element, options)
|
|
iFrames.push(element)
|
|
}
|
|
}
|
|
|
|
function warnDeprecatedOptions(options) {
|
|
if (options && options.enablePublicMethods) {
|
|
warn(
|
|
'enablePublicMethods option has been removed, public methods are now always available in the iFrame'
|
|
)
|
|
}
|
|
}
|
|
|
|
var iFrames
|
|
|
|
setupRequestAnimationFrame()
|
|
setupEventListeners()
|
|
|
|
return function iFrameResizeF(options, target) {
|
|
iFrames = [] // Only return iFrames past in on this call
|
|
|
|
warnDeprecatedOptions(options)
|
|
|
|
switch (typeof target) {
|
|
case 'undefined':
|
|
case 'string':
|
|
Array.prototype.forEach.call(
|
|
document.querySelectorAll(target || 'iframe'),
|
|
init.bind(undefined, options)
|
|
)
|
|
break
|
|
|
|
case 'object':
|
|
init(options, target)
|
|
break
|
|
|
|
default:
|
|
throw new TypeError('Unexpected data type (' + typeof target + ')')
|
|
}
|
|
|
|
return iFrames
|
|
}
|
|
}
|
|
|
|
function createJQueryPublicMethod($) {
|
|
if (!$.fn) {
|
|
info('', 'Unable to bind to jQuery, it is not fully loaded.')
|
|
} else if (!$.fn.iFrameResize) {
|
|
$.fn.iFrameResize = function $iFrameResizeF(options) {
|
|
function init(index, element) {
|
|
setupIFrame(element, options)
|
|
}
|
|
|
|
return this.filter('iframe')
|
|
.each(init)
|
|
.end()
|
|
}
|
|
}
|
|
}
|
|
|
|
if (window.jQuery) {
|
|
createJQueryPublicMethod(window.jQuery)
|
|
}
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
define([], factory)
|
|
} else if (typeof module === 'object' && typeof module.exports === 'object') {
|
|
// Node for browserfy
|
|
module.exports = factory()
|
|
}
|
|
window.iFrameResize = window.iFrameResize || factory()
|
|
})();
|
|
/*
|
|
* File: iframeResizer.contentWindow.js
|
|
* Desc: Include this file in any page being loaded into an iframe
|
|
* to force the iframe to resize to the content size.
|
|
* Requires: iframeResizer.js on host page.
|
|
* Doc: https://github.com/davidjbradshaw/iframe-resizer
|
|
* Author: David J. Bradshaw - dave@bradshaw.net
|
|
*
|
|
*/
|
|
|
|
// eslint-disable-next-line sonarjs/cognitive-complexity, no-shadow-restricted-names
|
|
;(function(undefined) {
|
|
if (typeof window === 'undefined') return // don't run for server side render
|
|
|
|
var autoResize = true,
|
|
base = 10,
|
|
bodyBackground = '',
|
|
bodyMargin = 0,
|
|
bodyMarginStr = '',
|
|
bodyObserver = null,
|
|
bodyPadding = '',
|
|
calculateWidth = false,
|
|
doubleEventList = { resize: 1, click: 1 },
|
|
eventCancelTimer = 128,
|
|
firstRun = true,
|
|
height = 1,
|
|
heightCalcModeDefault = 'bodyOffset',
|
|
heightCalcMode = heightCalcModeDefault,
|
|
initLock = true,
|
|
initMsg = '',
|
|
inPageLinks = {},
|
|
interval = 32,
|
|
intervalTimer = null,
|
|
logging = false,
|
|
msgID = '[iFrameSizer]', // Must match host page msg ID
|
|
msgIdLen = msgID.length,
|
|
myID = '',
|
|
resetRequiredMethods = {
|
|
max: 1,
|
|
min: 1,
|
|
bodyScroll: 1,
|
|
documentElementScroll: 1
|
|
},
|
|
resizeFrom = 'child',
|
|
sendPermit = true,
|
|
target = window.parent,
|
|
targetOriginDefault = '*',
|
|
tolerance = 0,
|
|
triggerLocked = false,
|
|
triggerLockedTimer = null,
|
|
throttledTimer = 16,
|
|
width = 1,
|
|
widthCalcModeDefault = 'scroll',
|
|
widthCalcMode = widthCalcModeDefault,
|
|
win = window,
|
|
onMessage = function() {
|
|
warn('onMessage function not defined')
|
|
},
|
|
onReady = function() {},
|
|
onPageInfo = function() {},
|
|
customCalcMethods = {
|
|
height: function() {
|
|
warn('Custom height calculation function not defined')
|
|
return document.documentElement.offsetHeight
|
|
},
|
|
width: function() {
|
|
warn('Custom width calculation function not defined')
|
|
return document.body.scrollWidth
|
|
}
|
|
},
|
|
eventHandlersByName = {},
|
|
passiveSupported = false
|
|
|
|
function noop() {}
|
|
|
|
try {
|
|
var options = Object.create(
|
|
{},
|
|
{
|
|
passive: {
|
|
get: function() {
|
|
passiveSupported = true
|
|
}
|
|
}
|
|
}
|
|
)
|
|
window.addEventListener('test', noop, options)
|
|
window.removeEventListener('test', noop, options)
|
|
} catch (error) {
|
|
/* */
|
|
}
|
|
|
|
function addEventListener(el, evt, func, options) {
|
|
el.addEventListener(evt, func, passiveSupported ? options || {} : false)
|
|
}
|
|
|
|
function removeEventListener(el, evt, func) {
|
|
el.removeEventListener(evt, func, false)
|
|
}
|
|
|
|
function capitalizeFirstLetter(string) {
|
|
return string.charAt(0).toUpperCase() + string.slice(1)
|
|
}
|
|
|
|
// Based on underscore.js
|
|
function throttle(func) {
|
|
var context,
|
|
args,
|
|
result,
|
|
timeout = null,
|
|
previous = 0,
|
|
later = function() {
|
|
previous = getNow()
|
|
timeout = null
|
|
result = func.apply(context, args)
|
|
if (!timeout) {
|
|
// eslint-disable-next-line no-multi-assign
|
|
context = args = null
|
|
}
|
|
}
|
|
|
|
return function() {
|
|
var now = getNow()
|
|
|
|
if (!previous) {
|
|
previous = now
|
|
}
|
|
|
|
var remaining = throttledTimer - (now - previous)
|
|
|
|
context = this
|
|
args = arguments
|
|
|
|
if (remaining <= 0 || remaining > throttledTimer) {
|
|
if (timeout) {
|
|
clearTimeout(timeout)
|
|
timeout = null
|
|
}
|
|
|
|
previous = now
|
|
result = func.apply(context, args)
|
|
|
|
if (!timeout) {
|
|
// eslint-disable-next-line no-multi-assign
|
|
context = args = null
|
|
}
|
|
} else if (!timeout) {
|
|
timeout = setTimeout(later, remaining)
|
|
}
|
|
|
|
return result
|
|
}
|
|
}
|
|
|
|
var getNow =
|
|
Date.now ||
|
|
function() {
|
|
/* istanbul ignore next */ // Not testable in PhantonJS
|
|
return new Date().getTime()
|
|
}
|
|
|
|
function formatLogMsg(msg) {
|
|
return msgID + '[' + myID + '] ' + msg
|
|
}
|
|
|
|
function log(msg) {
|
|
if (logging && 'object' === typeof window.console) {
|
|
// eslint-disable-next-line no-console
|
|
console.log(formatLogMsg(msg))
|
|
}
|
|
}
|
|
|
|
function warn(msg) {
|
|
if ('object' === typeof window.console) {
|
|
// eslint-disable-next-line no-console
|
|
console.warn(formatLogMsg(msg))
|
|
}
|
|
}
|
|
|
|
function init() {
|
|
readDataFromParent()
|
|
log('Initialising iFrame (' + location.href + ')')
|
|
readDataFromPage()
|
|
setMargin()
|
|
setBodyStyle('background', bodyBackground)
|
|
setBodyStyle('padding', bodyPadding)
|
|
injectClearFixIntoBodyElement()
|
|
checkHeightMode()
|
|
checkWidthMode()
|
|
stopInfiniteResizingOfIFrame()
|
|
setupPublicMethods()
|
|
startEventListeners()
|
|
inPageLinks = setupInPageLinks()
|
|
sendSize('init', 'Init message from host page')
|
|
onReady()
|
|
}
|
|
|
|
function readDataFromParent() {
|
|
function strBool(str) {
|
|
return 'true' === str
|
|
}
|
|
|
|
var data = initMsg.substr(msgIdLen).split(':')
|
|
|
|
myID = data[0]
|
|
bodyMargin = undefined !== data[1] ? Number(data[1]) : bodyMargin // For V1 compatibility
|
|
calculateWidth = undefined !== data[2] ? strBool(data[2]) : calculateWidth
|
|
logging = undefined !== data[3] ? strBool(data[3]) : logging
|
|
interval = undefined !== data[4] ? Number(data[4]) : interval
|
|
autoResize = undefined !== data[6] ? strBool(data[6]) : autoResize
|
|
bodyMarginStr = data[7]
|
|
heightCalcMode = undefined !== data[8] ? data[8] : heightCalcMode
|
|
bodyBackground = data[9]
|
|
bodyPadding = data[10]
|
|
tolerance = undefined !== data[11] ? Number(data[11]) : tolerance
|
|
inPageLinks.enable = undefined !== data[12] ? strBool(data[12]) : false
|
|
resizeFrom = undefined !== data[13] ? data[13] : resizeFrom
|
|
widthCalcMode = undefined !== data[14] ? data[14] : widthCalcMode
|
|
}
|
|
|
|
function depricate(key) {
|
|
var splitName = key.split('Callback')
|
|
|
|
if (splitName.length === 2) {
|
|
var name =
|
|
'on' + splitName[0].charAt(0).toUpperCase() + splitName[0].slice(1)
|
|
this[name] = this[key]
|
|
delete this[key]
|
|
warn(
|
|
"Deprecated: '" +
|
|
key +
|
|
"' has been renamed '" +
|
|
name +
|
|
"'. The old method will be removed in the next major version."
|
|
)
|
|
}
|
|
}
|
|
|
|
function readDataFromPage() {
|
|
function readData() {
|
|
var data = window.iFrameResizer
|
|
|
|
log('Reading data from page: ' + JSON.stringify(data))
|
|
Object.keys(data).forEach(depricate, data)
|
|
|
|
onMessage = 'onMessage' in data ? data.onMessage : onMessage
|
|
onReady = 'onReady' in data ? data.onReady : onReady
|
|
targetOriginDefault =
|
|
'targetOrigin' in data ? data.targetOrigin : targetOriginDefault
|
|
heightCalcMode =
|
|
'heightCalculationMethod' in data
|
|
? data.heightCalculationMethod
|
|
: heightCalcMode
|
|
widthCalcMode =
|
|
'widthCalculationMethod' in data
|
|
? data.widthCalculationMethod
|
|
: widthCalcMode
|
|
}
|
|
|
|
function setupCustomCalcMethods(calcMode, calcFunc) {
|
|
if ('function' === typeof calcMode) {
|
|
log('Setup custom ' + calcFunc + 'CalcMethod')
|
|
customCalcMethods[calcFunc] = calcMode
|
|
calcMode = 'custom'
|
|
}
|
|
|
|
return calcMode
|
|
}
|
|
|
|
if (
|
|
'iFrameResizer' in window &&
|
|
Object === window.iFrameResizer.constructor
|
|
) {
|
|
readData()
|
|
heightCalcMode = setupCustomCalcMethods(heightCalcMode, 'height')
|
|
widthCalcMode = setupCustomCalcMethods(widthCalcMode, 'width')
|
|
}
|
|
|
|
log('TargetOrigin for parent set to: ' + targetOriginDefault)
|
|
}
|
|
|
|
function chkCSS(attr, value) {
|
|
if (-1 !== value.indexOf('-')) {
|
|
warn('Negative CSS value ignored for ' + attr)
|
|
value = ''
|
|
}
|
|
return value
|
|
}
|
|
|
|
function setBodyStyle(attr, value) {
|
|
if (undefined !== value && '' !== value && 'null' !== value) {
|
|
document.body.style[attr] = value
|
|
log('Body ' + attr + ' set to "' + value + '"')
|
|
}
|
|
}
|
|
|
|
function setMargin() {
|
|
// If called via V1 script, convert bodyMargin from int to str
|
|
if (undefined === bodyMarginStr) {
|
|
bodyMarginStr = bodyMargin + 'px'
|
|
}
|
|
|
|
setBodyStyle('margin', chkCSS('margin', bodyMarginStr))
|
|
}
|
|
|
|
function stopInfiniteResizingOfIFrame() {
|
|
document.documentElement.style.height = ''
|
|
document.body.style.height = ''
|
|
log('HTML & body height set to "auto"')
|
|
}
|
|
|
|
function manageTriggerEvent(options) {
|
|
var listener = {
|
|
add: function(eventName) {
|
|
function handleEvent() {
|
|
sendSize(options.eventName, options.eventType)
|
|
}
|
|
|
|
eventHandlersByName[eventName] = handleEvent
|
|
|
|
addEventListener(window, eventName, handleEvent, { passive: true })
|
|
},
|
|
remove: function(eventName) {
|
|
var handleEvent = eventHandlersByName[eventName]
|
|
delete eventHandlersByName[eventName]
|
|
|
|
removeEventListener(window, eventName, handleEvent)
|
|
}
|
|
}
|
|
|
|
if (options.eventNames && Array.prototype.map) {
|
|
options.eventName = options.eventNames[0]
|
|
options.eventNames.map(listener[options.method])
|
|
} else {
|
|
listener[options.method](options.eventName)
|
|
}
|
|
|
|
log(
|
|
capitalizeFirstLetter(options.method) +
|
|
' event listener: ' +
|
|
options.eventType
|
|
)
|
|
}
|
|
|
|
function manageEventListeners(method) {
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Animation Start',
|
|
eventNames: ['animationstart', 'webkitAnimationStart']
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Animation Iteration',
|
|
eventNames: ['animationiteration', 'webkitAnimationIteration']
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Animation End',
|
|
eventNames: ['animationend', 'webkitAnimationEnd']
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Input',
|
|
eventName: 'input'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Mouse Up',
|
|
eventName: 'mouseup'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Mouse Down',
|
|
eventName: 'mousedown'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Orientation Change',
|
|
eventName: 'orientationchange'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Print',
|
|
eventName: ['afterprint', 'beforeprint']
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Ready State Change',
|
|
eventName: 'readystatechange'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Touch Start',
|
|
eventName: 'touchstart'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Touch End',
|
|
eventName: 'touchend'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Touch Cancel',
|
|
eventName: 'touchcancel'
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Transition Start',
|
|
eventNames: [
|
|
'transitionstart',
|
|
'webkitTransitionStart',
|
|
'MSTransitionStart',
|
|
'oTransitionStart',
|
|
'otransitionstart'
|
|
]
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Transition Iteration',
|
|
eventNames: [
|
|
'transitioniteration',
|
|
'webkitTransitionIteration',
|
|
'MSTransitionIteration',
|
|
'oTransitionIteration',
|
|
'otransitioniteration'
|
|
]
|
|
})
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'Transition End',
|
|
eventNames: [
|
|
'transitionend',
|
|
'webkitTransitionEnd',
|
|
'MSTransitionEnd',
|
|
'oTransitionEnd',
|
|
'otransitionend'
|
|
]
|
|
})
|
|
if ('child' === resizeFrom) {
|
|
manageTriggerEvent({
|
|
method: method,
|
|
eventType: 'IFrame Resized',
|
|
eventName: 'resize'
|
|
})
|
|
}
|
|
}
|
|
|
|
function checkCalcMode(calcMode, calcModeDefault, modes, type) {
|
|
if (calcModeDefault !== calcMode) {
|
|
if (!(calcMode in modes)) {
|
|
warn(
|
|
calcMode + ' is not a valid option for ' + type + 'CalculationMethod.'
|
|
)
|
|
calcMode = calcModeDefault
|
|
}
|
|
log(type + ' calculation method set to "' + calcMode + '"')
|
|
}
|
|
|
|
return calcMode
|
|
}
|
|
|
|
function checkHeightMode() {
|
|
heightCalcMode = checkCalcMode(
|
|
heightCalcMode,
|
|
heightCalcModeDefault,
|
|
getHeight,
|
|
'height'
|
|
)
|
|
}
|
|
|
|
function checkWidthMode() {
|
|
widthCalcMode = checkCalcMode(
|
|
widthCalcMode,
|
|
widthCalcModeDefault,
|
|
getWidth,
|
|
'width'
|
|
)
|
|
}
|
|
|
|
function startEventListeners() {
|
|
if (true === autoResize) {
|
|
manageEventListeners('add')
|
|
setupMutationObserver()
|
|
} else {
|
|
log('Auto Resize disabled')
|
|
}
|
|
}
|
|
|
|
function stopMsgsToParent() {
|
|
log('Disable outgoing messages')
|
|
sendPermit = false
|
|
}
|
|
|
|
function removeMsgListener() {
|
|
log('Remove event listener: Message')
|
|
removeEventListener(window, 'message', receiver)
|
|
}
|
|
|
|
function disconnectMutationObserver() {
|
|
if (null !== bodyObserver) {
|
|
/* istanbul ignore next */ // Not testable in PhantonJS
|
|
bodyObserver.disconnect()
|
|
}
|
|
}
|
|
|
|
function stopEventListeners() {
|
|
manageEventListeners('remove')
|
|
disconnectMutationObserver()
|
|
clearInterval(intervalTimer)
|
|
}
|
|
|
|
function teardown() {
|
|
stopMsgsToParent()
|
|
removeMsgListener()
|
|
if (true === autoResize) stopEventListeners()
|
|
}
|
|
|
|
function injectClearFixIntoBodyElement() {
|
|
var clearFix = document.createElement('div')
|
|
clearFix.style.clear = 'both'
|
|
// Guard against the following having been globally redefined in CSS.
|
|
clearFix.style.display = 'block'
|
|
clearFix.style.height = '0'
|
|
document.body.appendChild(clearFix)
|
|
}
|
|
|
|
function setupInPageLinks() {
|
|
function getPagePosition() {
|
|
return {
|
|
x:
|
|
window.pageXOffset !== undefined
|
|
? window.pageXOffset
|
|
: document.documentElement.scrollLeft,
|
|
y:
|
|
window.pageYOffset !== undefined
|
|
? window.pageYOffset
|
|
: document.documentElement.scrollTop
|
|
}
|
|
}
|
|
|
|
function getElementPosition(el) {
|
|
var elPosition = el.getBoundingClientRect(),
|
|
pagePosition = getPagePosition()
|
|
|
|
return {
|
|
x: parseInt(elPosition.left, 10) + parseInt(pagePosition.x, 10),
|
|
y: parseInt(elPosition.top, 10) + parseInt(pagePosition.y, 10)
|
|
}
|
|
}
|
|
|
|
function findTarget(location) {
|
|
function jumpToTarget(target) {
|
|
var jumpPosition = getElementPosition(target)
|
|
|
|
log(
|
|
'Moving to in page link (#' +
|
|
hash +
|
|
') at x: ' +
|
|
jumpPosition.x +
|
|
' y: ' +
|
|
jumpPosition.y
|
|
)
|
|
sendMsg(jumpPosition.y, jumpPosition.x, 'scrollToOffset') // X&Y reversed at sendMsg uses height/width
|
|
}
|
|
|
|
var hash = location.split('#')[1] || location, // Remove # if present
|
|
hashData = decodeURIComponent(hash),
|
|
target =
|
|
document.getElementById(hashData) ||
|
|
document.getElementsByName(hashData)[0]
|
|
|
|
if (undefined !== target) {
|
|
jumpToTarget(target)
|
|
} else {
|
|
log(
|
|
'In page link (#' +
|
|
hash +
|
|
') not found in iFrame, so sending to parent'
|
|
)
|
|
sendMsg(0, 0, 'inPageLink', '#' + hash)
|
|
}
|
|
}
|
|
|
|
function checkLocationHash() {
|
|
if ('' !== location.hash && '#' !== location.hash) {
|
|
findTarget(location.href)
|
|
}
|
|
}
|
|
|
|
function bindAnchors() {
|
|
function setupLink(el) {
|
|
function linkClicked(e) {
|
|
e.preventDefault()
|
|
|
|
/* jshint validthis:true */
|
|
findTarget(this.getAttribute('href'))
|
|
}
|
|
|
|
if ('#' !== el.getAttribute('href')) {
|
|
addEventListener(el, 'click', linkClicked)
|
|
}
|
|
}
|
|
|
|
Array.prototype.forEach.call(
|
|
document.querySelectorAll('a[href^="#"]'),
|
|
setupLink
|
|
)
|
|
}
|
|
|
|
function bindLocationHash() {
|
|
addEventListener(window, 'hashchange', checkLocationHash)
|
|
}
|
|
|
|
function initCheck() {
|
|
// Check if page loaded with location hash after init resize
|
|
setTimeout(checkLocationHash, eventCancelTimer)
|
|
}
|
|
|
|
function enableInPageLinks() {
|
|
/* istanbul ignore else */ // Not testable in phantonJS
|
|
if (Array.prototype.forEach && document.querySelectorAll) {
|
|
log('Setting up location.hash handlers')
|
|
bindAnchors()
|
|
bindLocationHash()
|
|
initCheck()
|
|
} else {
|
|
warn(
|
|
'In page linking not fully supported in this browser! (See README.md for IE8 workaround)'
|
|
)
|
|
}
|
|
}
|
|
|
|
if (inPageLinks.enable) {
|
|
enableInPageLinks()
|
|
} else {
|
|
log('In page linking not enabled')
|
|
}
|
|
|
|
return {
|
|
findTarget: findTarget
|
|
}
|
|
}
|
|
|
|
function setupPublicMethods() {
|
|
log('Enable public methods')
|
|
|
|
win.parentIFrame = {
|
|
autoResize: function autoResizeF(resize) {
|
|
if (true === resize && false === autoResize) {
|
|
autoResize = true
|
|
startEventListeners()
|
|
} else if (false === resize && true === autoResize) {
|
|
autoResize = false
|
|
stopEventListeners()
|
|
}
|
|
|
|
return autoResize
|
|
},
|
|
|
|
close: function closeF() {
|
|
sendMsg(0, 0, 'close')
|
|
teardown()
|
|
},
|
|
|
|
getId: function getIdF() {
|
|
return myID
|
|
},
|
|
|
|
getPageInfo: function getPageInfoF(callback) {
|
|
if ('function' === typeof callback) {
|
|
onPageInfo = callback
|
|
sendMsg(0, 0, 'pageInfo')
|
|
} else {
|
|
onPageInfo = function() {}
|
|
sendMsg(0, 0, 'pageInfoStop')
|
|
}
|
|
},
|
|
|
|
moveToAnchor: function moveToAnchorF(hash) {
|
|
inPageLinks.findTarget(hash)
|
|
},
|
|
|
|
reset: function resetF() {
|
|
resetIFrame('parentIFrame.reset')
|
|
},
|
|
|
|
scrollTo: function scrollToF(x, y) {
|
|
sendMsg(y, x, 'scrollTo') // X&Y reversed at sendMsg uses height/width
|
|
},
|
|
|
|
scrollToOffset: function scrollToF(x, y) {
|
|
sendMsg(y, x, 'scrollToOffset') // X&Y reversed at sendMsg uses height/width
|
|
},
|
|
|
|
sendMessage: function sendMessageF(msg, targetOrigin) {
|
|
sendMsg(0, 0, 'message', JSON.stringify(msg), targetOrigin)
|
|
},
|
|
|
|
setHeightCalculationMethod: function setHeightCalculationMethodF(
|
|
heightCalculationMethod
|
|
) {
|
|
heightCalcMode = heightCalculationMethod
|
|
checkHeightMode()
|
|
},
|
|
|
|
setWidthCalculationMethod: function setWidthCalculationMethodF(
|
|
widthCalculationMethod
|
|
) {
|
|
widthCalcMode = widthCalculationMethod
|
|
checkWidthMode()
|
|
},
|
|
|
|
setTargetOrigin: function setTargetOriginF(targetOrigin) {
|
|
log('Set targetOrigin: ' + targetOrigin)
|
|
targetOriginDefault = targetOrigin
|
|
},
|
|
|
|
size: function sizeF(customHeight, customWidth) {
|
|
var valString =
|
|
'' + (customHeight || '') + (customWidth ? ',' + customWidth : '')
|
|
sendSize(
|
|
'size',
|
|
'parentIFrame.size(' + valString + ')',
|
|
customHeight,
|
|
customWidth
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
function initInterval() {
|
|
if (0 !== interval) {
|
|
log('setInterval: ' + interval + 'ms')
|
|
intervalTimer = setInterval(function() {
|
|
sendSize('interval', 'setInterval: ' + interval)
|
|
}, Math.abs(interval))
|
|
}
|
|
}
|
|
|
|
// Not testable in PhantomJS
|
|
/* istanbul ignore next */
|
|
function setupBodyMutationObserver() {
|
|
function addImageLoadListners(mutation) {
|
|
function addImageLoadListener(element) {
|
|
if (false === element.complete) {
|
|
log('Attach listeners to ' + element.src)
|
|
element.addEventListener('load', imageLoaded, false)
|
|
element.addEventListener('error', imageError, false)
|
|
elements.push(element)
|
|
}
|
|
}
|
|
|
|
if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
|
|
addImageLoadListener(mutation.target)
|
|
} else if (mutation.type === 'childList') {
|
|
Array.prototype.forEach.call(
|
|
mutation.target.querySelectorAll('img'),
|
|
addImageLoadListener
|
|
)
|
|
}
|
|
}
|
|
|
|
function removeFromArray(element) {
|
|
elements.splice(elements.indexOf(element), 1)
|
|
}
|
|
|
|
function removeImageLoadListener(element) {
|
|
log('Remove listeners from ' + element.src)
|
|
element.removeEventListener('load', imageLoaded, false)
|
|
element.removeEventListener('error', imageError, false)
|
|
removeFromArray(element)
|
|
}
|
|
|
|
function imageEventTriggered(event, type, typeDesc) {
|
|
removeImageLoadListener(event.target)
|
|
sendSize(type, typeDesc + ': ' + event.target.src, undefined, undefined)
|
|
}
|
|
|
|
function imageLoaded(event) {
|
|
imageEventTriggered(event, 'imageLoad', 'Image loaded')
|
|
}
|
|
|
|
function imageError(event) {
|
|
imageEventTriggered(event, 'imageLoadFailed', 'Image load failed')
|
|
}
|
|
|
|
function mutationObserved(mutations) {
|
|
sendSize(
|
|
'mutationObserver',
|
|
'mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type
|
|
)
|
|
|
|
// Deal with WebKit / Blink asyncing image loading when tags are injected into the page
|
|
mutations.forEach(addImageLoadListners)
|
|
}
|
|
|
|
function createMutationObserver() {
|
|
var target = document.querySelector('body'),
|
|
config = {
|
|
attributes: true,
|
|
attributeOldValue: false,
|
|
characterData: true,
|
|
characterDataOldValue: false,
|
|
childList: true,
|
|
subtree: true
|
|
}
|
|
|
|
observer = new MutationObserver(mutationObserved)
|
|
|
|
log('Create body MutationObserver')
|
|
observer.observe(target, config)
|
|
|
|
return observer
|
|
}
|
|
|
|
var elements = [],
|
|
MutationObserver =
|
|
window.MutationObserver || window.WebKitMutationObserver,
|
|
observer = createMutationObserver()
|
|
|
|
return {
|
|
disconnect: function() {
|
|
if ('disconnect' in observer) {
|
|
log('Disconnect body MutationObserver')
|
|
observer.disconnect()
|
|
elements.forEach(removeImageLoadListener)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function setupMutationObserver() {
|
|
var forceIntervalTimer = 0 > interval
|
|
|
|
// Not testable in PhantomJS
|
|
/* istanbul ignore if */ if (
|
|
window.MutationObserver ||
|
|
window.WebKitMutationObserver
|
|
) {
|
|
if (forceIntervalTimer) {
|
|
initInterval()
|
|
} else {
|
|
bodyObserver = setupBodyMutationObserver()
|
|
}
|
|
} else {
|
|
log('MutationObserver not supported in this browser!')
|
|
initInterval()
|
|
}
|
|
}
|
|
|
|
// document.documentElement.offsetHeight is not reliable, so
|
|
// we have to jump through hoops to get a better value.
|
|
function getComputedStyle(prop, el) {
|
|
var retVal = 0
|
|
el = el || document.body // Not testable in phantonJS
|
|
|
|
retVal = document.defaultView.getComputedStyle(el, null)
|
|
retVal = null !== retVal ? retVal[prop] : 0
|
|
|
|
return parseInt(retVal, base)
|
|
}
|
|
|
|
function chkEventThottle(timer) {
|
|
if (timer > throttledTimer / 2) {
|
|
throttledTimer = 2 * timer
|
|
log('Event throttle increased to ' + throttledTimer + 'ms')
|
|
}
|
|
}
|
|
|
|
// Idea from https://github.com/guardian/iframe-messenger
|
|
function getMaxElement(side, elements) {
|
|
var elementsLength = elements.length,
|
|
elVal = 0,
|
|
maxVal = 0,
|
|
Side = capitalizeFirstLetter(side),
|
|
timer = getNow()
|
|
|
|
for (var i = 0; i < elementsLength; i++) {
|
|
elVal =
|
|
elements[i].getBoundingClientRect()[side] +
|
|
getComputedStyle('margin' + Side, elements[i])
|
|
if (elVal > maxVal) {
|
|
maxVal = elVal
|
|
}
|
|
}
|
|
|
|
timer = getNow() - timer
|
|
|
|
log('Parsed ' + elementsLength + ' HTML elements')
|
|
log('Element position calculated in ' + timer + 'ms')
|
|
|
|
chkEventThottle(timer)
|
|
|
|
return maxVal
|
|
}
|
|
|
|
function getAllMeasurements(dimention) {
|
|
return [
|
|
dimention.bodyOffset(),
|
|
dimention.bodyScroll(),
|
|
dimention.documentElementOffset(),
|
|
dimention.documentElementScroll()
|
|
]
|
|
}
|
|
|
|
function getTaggedElements(side, tag) {
|
|
function noTaggedElementsFound() {
|
|
warn('No tagged elements (' + tag + ') found on page')
|
|
return document.querySelectorAll('body *')
|
|
}
|
|
|
|
var elements = document.querySelectorAll('[' + tag + ']')
|
|
|
|
if (0 === elements.length) noTaggedElementsFound()
|
|
|
|
return getMaxElement(side, elements)
|
|
}
|
|
|
|
function getAllElements() {
|
|
return document.querySelectorAll('body *')
|
|
}
|
|
|
|
var getHeight = {
|
|
bodyOffset: function getBodyOffsetHeight() {
|
|
return (
|
|
document.body.offsetHeight +
|
|
getComputedStyle('marginTop') +
|
|
getComputedStyle('marginBottom')
|
|
)
|
|
},
|
|
|
|
offset: function() {
|
|
return getHeight.bodyOffset() // Backwards compatability
|
|
},
|
|
|
|
bodyScroll: function getBodyScrollHeight() {
|
|
return document.body.scrollHeight
|
|
},
|
|
|
|
custom: function getCustomWidth() {
|
|
return customCalcMethods.height()
|
|
},
|
|
|
|
documentElementOffset: function getDEOffsetHeight() {
|
|
return document.documentElement.offsetHeight
|
|
},
|
|
|
|
documentElementScroll: function getDEScrollHeight() {
|
|
return document.documentElement.scrollHeight
|
|
},
|
|
|
|
max: function getMaxHeight() {
|
|
return Math.max.apply(null, getAllMeasurements(getHeight))
|
|
},
|
|
|
|
min: function getMinHeight() {
|
|
return Math.min.apply(null, getAllMeasurements(getHeight))
|
|
},
|
|
|
|
grow: function growHeight() {
|
|
return getHeight.max() // Run max without the forced downsizing
|
|
},
|
|
|
|
lowestElement: function getBestHeight() {
|
|
return Math.max(
|
|
getHeight.bodyOffset() || getHeight.documentElementOffset(),
|
|
getMaxElement('bottom', getAllElements())
|
|
)
|
|
},
|
|
|
|
taggedElement: function getTaggedElementsHeight() {
|
|
return getTaggedElements('bottom', 'data-iframe-height')
|
|
}
|
|
},
|
|
getWidth = {
|
|
bodyScroll: function getBodyScrollWidth() {
|
|
return document.body.scrollWidth
|
|
},
|
|
|
|
bodyOffset: function getBodyOffsetWidth() {
|
|
return document.body.offsetWidth
|
|
},
|
|
|
|
custom: function getCustomWidth() {
|
|
return customCalcMethods.width()
|
|
},
|
|
|
|
documentElementScroll: function getDEScrollWidth() {
|
|
return document.documentElement.scrollWidth
|
|
},
|
|
|
|
documentElementOffset: function getDEOffsetWidth() {
|
|
return document.documentElement.offsetWidth
|
|
},
|
|
|
|
scroll: function getMaxWidth() {
|
|
return Math.max(getWidth.bodyScroll(), getWidth.documentElementScroll())
|
|
},
|
|
|
|
max: function getMaxWidth() {
|
|
return Math.max.apply(null, getAllMeasurements(getWidth))
|
|
},
|
|
|
|
min: function getMinWidth() {
|
|
return Math.min.apply(null, getAllMeasurements(getWidth))
|
|
},
|
|
|
|
rightMostElement: function rightMostElement() {
|
|
return getMaxElement('right', getAllElements())
|
|
},
|
|
|
|
taggedElement: function getTaggedElementsWidth() {
|
|
return getTaggedElements('right', 'data-iframe-width')
|
|
}
|
|
}
|
|
|
|
function sizeIFrame(
|
|
triggerEvent,
|
|
triggerEventDesc,
|
|
customHeight,
|
|
customWidth
|
|
) {
|
|
function resizeIFrame() {
|
|
height = currentHeight
|
|
width = currentWidth
|
|
|
|
sendMsg(height, width, triggerEvent)
|
|
}
|
|
|
|
function isSizeChangeDetected() {
|
|
function checkTolarance(a, b) {
|
|
var retVal = Math.abs(a - b) <= tolerance
|
|
return !retVal
|
|
}
|
|
|
|
currentHeight =
|
|
undefined !== customHeight ? customHeight : getHeight[heightCalcMode]()
|
|
currentWidth =
|
|
undefined !== customWidth ? customWidth : getWidth[widthCalcMode]()
|
|
|
|
return (
|
|
checkTolarance(height, currentHeight) ||
|
|
(calculateWidth && checkTolarance(width, currentWidth))
|
|
)
|
|
}
|
|
|
|
function isForceResizableEvent() {
|
|
return !(triggerEvent in { init: 1, interval: 1, size: 1 })
|
|
}
|
|
|
|
function isForceResizableCalcMode() {
|
|
return (
|
|
heightCalcMode in resetRequiredMethods ||
|
|
(calculateWidth && widthCalcMode in resetRequiredMethods)
|
|
)
|
|
}
|
|
|
|
function logIgnored() {
|
|
log('No change in size detected')
|
|
}
|
|
|
|
function checkDownSizing() {
|
|
if (isForceResizableEvent() && isForceResizableCalcMode()) {
|
|
resetIFrame(triggerEventDesc)
|
|
} else if (!(triggerEvent in { interval: 1 })) {
|
|
logIgnored()
|
|
}
|
|
}
|
|
|
|
var currentHeight, currentWidth
|
|
|
|
if (isSizeChangeDetected() || 'init' === triggerEvent) {
|
|
lockTrigger()
|
|
resizeIFrame()
|
|
} else {
|
|
checkDownSizing()
|
|
}
|
|
}
|
|
|
|
var sizeIFrameThrottled = throttle(sizeIFrame)
|
|
|
|
function sendSize(triggerEvent, triggerEventDesc, customHeight, customWidth) {
|
|
function recordTrigger() {
|
|
if (!(triggerEvent in { reset: 1, resetPage: 1, init: 1 })) {
|
|
log('Trigger event: ' + triggerEventDesc)
|
|
}
|
|
}
|
|
|
|
function isDoubleFiredEvent() {
|
|
return triggerLocked && triggerEvent in doubleEventList
|
|
}
|
|
|
|
if (!isDoubleFiredEvent()) {
|
|
recordTrigger()
|
|
if (triggerEvent === 'init') {
|
|
sizeIFrame(triggerEvent, triggerEventDesc, customHeight, customWidth)
|
|
} else {
|
|
sizeIFrameThrottled(
|
|
triggerEvent,
|
|
triggerEventDesc,
|
|
customHeight,
|
|
customWidth
|
|
)
|
|
}
|
|
} else {
|
|
log('Trigger event cancelled: ' + triggerEvent)
|
|
}
|
|
}
|
|
|
|
function lockTrigger() {
|
|
if (!triggerLocked) {
|
|
triggerLocked = true
|
|
log('Trigger event lock on')
|
|
}
|
|
clearTimeout(triggerLockedTimer)
|
|
triggerLockedTimer = setTimeout(function() {
|
|
triggerLocked = false
|
|
log('Trigger event lock off')
|
|
log('--')
|
|
}, eventCancelTimer)
|
|
}
|
|
|
|
function triggerReset(triggerEvent) {
|
|
height = getHeight[heightCalcMode]()
|
|
width = getWidth[widthCalcMode]()
|
|
|
|
sendMsg(height, width, triggerEvent)
|
|
}
|
|
|
|
function resetIFrame(triggerEventDesc) {
|
|
var hcm = heightCalcMode
|
|
heightCalcMode = heightCalcModeDefault
|
|
|
|
log('Reset trigger event: ' + triggerEventDesc)
|
|
lockTrigger()
|
|
triggerReset('reset')
|
|
|
|
heightCalcMode = hcm
|
|
}
|
|
|
|
function sendMsg(height, width, triggerEvent, msg, targetOrigin) {
|
|
function setTargetOrigin() {
|
|
if (undefined === targetOrigin) {
|
|
targetOrigin = targetOriginDefault
|
|
} else {
|
|
log('Message targetOrigin: ' + targetOrigin)
|
|
}
|
|
}
|
|
|
|
function sendToParent() {
|
|
var size = height + ':' + width,
|
|
message =
|
|
myID +
|
|
':' +
|
|
size +
|
|
':' +
|
|
triggerEvent +
|
|
(undefined !== msg ? ':' + msg : '')
|
|
|
|
log('Sending message to host page (' + message + ')')
|
|
target.postMessage(msgID + message, targetOrigin)
|
|
}
|
|
|
|
if (true === sendPermit) {
|
|
setTargetOrigin()
|
|
sendToParent()
|
|
}
|
|
}
|
|
|
|
function receiver(event) {
|
|
var processRequestFromParent = {
|
|
init: function initFromParent() {
|
|
initMsg = event.data
|
|
target = event.source
|
|
|
|
init()
|
|
firstRun = false
|
|
setTimeout(function() {
|
|
initLock = false
|
|
}, eventCancelTimer)
|
|
},
|
|
|
|
reset: function resetFromParent() {
|
|
if (!initLock) {
|
|
log('Page size reset by host page')
|
|
triggerReset('resetPage')
|
|
} else {
|
|
log('Page reset ignored by init')
|
|
}
|
|
},
|
|
|
|
resize: function resizeFromParent() {
|
|
sendSize('resizeParent', 'Parent window requested size check')
|
|
},
|
|
|
|
moveToAnchor: function moveToAnchorF() {
|
|
inPageLinks.findTarget(getData())
|
|
},
|
|
inPageLink: function inPageLinkF() {
|
|
this.moveToAnchor()
|
|
}, // Backward compatability
|
|
|
|
pageInfo: function pageInfoFromParent() {
|
|
var msgBody = getData()
|
|
log('PageInfoFromParent called from parent: ' + msgBody)
|
|
onPageInfo(JSON.parse(msgBody))
|
|
log(' --')
|
|
},
|
|
|
|
message: function messageFromParent() {
|
|
var msgBody = getData()
|
|
|
|
log('onMessage called from parent: ' + msgBody)
|
|
// eslint-disable-next-line sonarjs/no-extra-arguments
|
|
onMessage(JSON.parse(msgBody))
|
|
log(' --')
|
|
}
|
|
}
|
|
|
|
function isMessageForUs() {
|
|
return msgID === ('' + event.data).substr(0, msgIdLen) // ''+ Protects against non-string messages
|
|
}
|
|
|
|
function getMessageType() {
|
|
return event.data.split(']')[1].split(':')[0]
|
|
}
|
|
|
|
function getData() {
|
|
return event.data.substr(event.data.indexOf(':') + 1)
|
|
}
|
|
|
|
function isMiddleTier() {
|
|
return (
|
|
(!(typeof module !== 'undefined' && module.exports) &&
|
|
'iFrameResize' in window) ||
|
|
('jQuery' in window && 'iFrameResize' in window.jQuery.prototype)
|
|
)
|
|
}
|
|
|
|
function isInitMsg() {
|
|
// Test if this message is from a child below us. This is an ugly test, however, updating
|
|
// the message format would break backwards compatibity.
|
|
return event.data.split(':')[2] in { true: 1, false: 1 }
|
|
}
|
|
|
|
function callFromParent() {
|
|
var messageType = getMessageType()
|
|
|
|
if (messageType in processRequestFromParent) {
|
|
processRequestFromParent[messageType]()
|
|
} else if (!isMiddleTier() && !isInitMsg()) {
|
|
warn('Unexpected message (' + event.data + ')')
|
|
}
|
|
}
|
|
|
|
function processMessage() {
|
|
if (false === firstRun) {
|
|
callFromParent()
|
|
} else if (isInitMsg()) {
|
|
processRequestFromParent.init()
|
|
} else {
|
|
log(
|
|
'Ignored message of type "' +
|
|
getMessageType() +
|
|
'". Received before initialization.'
|
|
)
|
|
}
|
|
}
|
|
|
|
if (isMessageForUs()) {
|
|
processMessage()
|
|
}
|
|
}
|
|
|
|
// Normally the parent kicks things off when it detects the iFrame has loaded.
|
|
// If this script is async-loaded, then tell parent page to retry init.
|
|
function chkLateLoaded() {
|
|
if ('loading' !== document.readyState) {
|
|
window.parent.postMessage('[iFrameResizerChild]Ready', '*')
|
|
}
|
|
}
|
|
|
|
addEventListener(window, 'message', receiver)
|
|
addEventListener(window, 'readystatechange', chkLateLoaded)
|
|
chkLateLoaded()
|
|
|
|
|
|
})();
|
|
|
|
|
|
/*!
|
|
* jQuery JavaScript Library v3.4.1
|
|
* https://jquery.com/
|
|
*
|
|
* Includes Sizzle.js
|
|
* https://sizzlejs.com/
|
|
*
|
|
* Copyright JS Foundation and other contributors
|
|
* Released under the MIT license
|
|
* https://jquery.org/license
|
|
*
|
|
* Date: 2019-05-01T21:04Z
|
|
*/
|
|
( function( global, factory ) {
|
|
|
|
"use strict";
|
|
|
|
if ( typeof module === "object" && typeof module.exports === "object" ) {
|
|
|
|
// For CommonJS and CommonJS-like environments where a proper `window`
|
|
// is present, execute the factory and get jQuery.
|
|
// For environments that do not have a `window` with a `document`
|
|
// (such as Node.js), expose a factory as module.exports.
|
|
// This accentuates the need for the creation of a real `window`.
|
|
// e.g. var jQuery = require("jquery")(window);
|
|
// See ticket #14549 for more info.
|
|
module.exports = global.document ?
|
|
factory( global, true ) :
|
|
function( w ) {
|
|
if ( !w.document ) {
|
|
throw new Error( "jQuery requires a window with a document" );
|
|
}
|
|
return factory( w );
|
|
};
|
|
} else {
|
|
factory( global );
|
|
}
|
|
|
|
// Pass this if window is not defined yet
|
|
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
|
|
|
|
// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
|
|
// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
|
|
// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
|
|
// enough that all such attempts are guarded in a try block.
|
|
"use strict";
|
|
|
|
var arr = [];
|
|
|
|
var document = window.document;
|
|
|
|
var getProto = Object.getPrototypeOf;
|
|
|
|
var slice = arr.slice;
|
|
|
|
var concat = arr.concat;
|
|
|
|
var push = arr.push;
|
|
|
|
var indexOf = arr.indexOf;
|
|
|
|
var class2type = {};
|
|
|
|
var toString = class2type.toString;
|
|
|
|
var hasOwn = class2type.hasOwnProperty;
|
|
|
|
var fnToString = hasOwn.toString;
|
|
|
|
var ObjectFunctionString = fnToString.call( Object );
|
|
|
|
var support = {};
|
|
|
|
var isFunction = function isFunction( obj ) {
|
|
|
|
// Support: Chrome <=57, Firefox <=52
|
|
// In some browsers, typeof returns "function" for HTML <object> elements
|
|
// (i.e., `typeof document.createElement( "object" ) === "function"`).
|
|
// We don't want to classify *any* DOM node as a function.
|
|
return typeof obj === "function" && typeof obj.nodeType !== "number";
|
|
};
|
|
|
|
|
|
var isWindow = function isWindow( obj ) {
|
|
return obj != null && obj === obj.window;
|
|
};
|
|
|
|
|
|
|
|
|
|
var preservedScriptAttributes = {
|
|
type: true,
|
|
src: true,
|
|
nonce: true,
|
|
noModule: true
|
|
};
|
|
|
|
function DOMEval( code, node, doc ) {
|
|
doc = doc || document;
|
|
|
|
var i, val,
|
|
script = doc.createElement( "script" );
|
|
|
|
script.text = code;
|
|
if ( node ) {
|
|
for ( i in preservedScriptAttributes ) {
|
|
|
|
// Support: Firefox 64+, Edge 18+
|
|
// Some browsers don't support the "nonce" property on scripts.
|
|
// On the other hand, just using `getAttribute` is not enough as
|
|
// the `nonce` attribute is reset to an empty string whenever it
|
|
// becomes browsing-context connected.
|
|
// See https://github.com/whatwg/html/issues/2369
|
|
// See https://html.spec.whatwg.org/#nonce-attributes
|
|
// The `node.getAttribute` check was added for the sake of
|
|
// `jQuery.globalEval` so that it can fake a nonce-containing node
|
|
// via an object.
|
|
val = node[ i ] || node.getAttribute && node.getAttribute( i );
|
|
if ( val ) {
|
|
script.setAttribute( i, val );
|
|
}
|
|
}
|
|
}
|
|
doc.head.appendChild( script ).parentNode.removeChild( script );
|
|
}
|
|
|
|
|
|
function toType( obj ) {
|
|
if ( obj == null ) {
|
|
return obj + "";
|
|
}
|
|
|
|
// Support: Android <=2.3 only (functionish RegExp)
|
|
return typeof obj === "object" || typeof obj === "function" ?
|
|
class2type[ toString.call( obj ) ] || "object" :
|
|
typeof obj;
|
|
}
|
|
/* global Symbol */
|
|
// Defining this global in .eslintrc.json would create a danger of using the global
|
|
// unguarded in another place, it seems safer to define global only for this module
|
|
|
|
|
|
|
|
var
|
|
version = "3.4.1",
|
|
|
|
// Define a local copy of jQuery
|
|
jQuery = function( selector, context ) {
|
|
|
|
// The jQuery object is actually just the init constructor 'enhanced'
|
|
// Need init if jQuery is called (just allow error to be thrown if not included)
|
|
return new jQuery.fn.init( selector, context );
|
|
},
|
|
|
|
// Support: Android <=4.0 only
|
|
// Make sure we trim BOM and NBSP
|
|
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
|
|
|
|
jQuery.fn = jQuery.prototype = {
|
|
|
|
// The current version of jQuery being used
|
|
jquery: version,
|
|
|
|
constructor: jQuery,
|
|
|
|
// The default length of a jQuery object is 0
|
|
length: 0,
|
|
|
|
toArray: function() {
|
|
return slice.call( this );
|
|
},
|
|
|
|
// Get the Nth element in the matched element set OR
|
|
// Get the whole matched element set as a clean array
|
|
get: function( num ) {
|
|
|
|
// Return all the elements in a clean array
|
|
if ( num == null ) {
|
|
return slice.call( this );
|
|
}
|
|
|
|
// Return just the one element from the set
|
|
return num < 0 ? this[ num + this.length ] : this[ num ];
|
|
},
|
|
|
|
// Take an array of elements and push it onto the stack
|
|
// (returning the new matched element set)
|
|
pushStack: function( elems ) {
|
|
|
|
// Build a new jQuery matched element set
|
|
var ret = jQuery.merge( this.constructor(), elems );
|
|
|
|
// Add the old object onto the stack (as a reference)
|
|
ret.prevObject = this;
|
|
|
|
// Return the newly-formed element set
|
|
return ret;
|
|
},
|
|
|
|
// Execute a callback for every element in the matched set.
|
|
each: function( callback ) {
|
|
return jQuery.each( this, callback );
|
|
},
|
|
|
|
map: function( callback ) {
|
|
return this.pushStack( jQuery.map( this, function( elem, i ) {
|
|
return callback.call( elem, i, elem );
|
|
} ) );
|
|
},
|
|
|
|
slice: function() {
|
|
return this.pushStack( slice.apply( this, arguments ) );
|
|
},
|
|
|
|
first: function() {
|
|
return this.eq( 0 );
|
|
},
|
|
|
|
last: function() {
|
|
return this.eq( -1 );
|
|
},
|
|
|
|
eq: function( i ) {
|
|
var len = this.length,
|
|
j = +i + ( i < 0 ? len : 0 );
|
|
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
|
|
},
|
|
|
|
end: function() {
|
|
return this.prevObject || this.constructor();
|
|
},
|
|
|
|
// For internal use only.
|
|
// Behaves like an Array's method, not like a jQuery method.
|
|
push: push,
|
|
sort: arr.sort,
|
|
splice: arr.splice
|
|
};
|
|
|
|
jQuery.extend = jQuery.fn.extend = function() {
|
|
var options, name, src, copy, copyIsArray, clone,
|
|
target = arguments[ 0 ] || {},
|
|
i = 1,
|
|
length = arguments.length,
|
|
deep = false;
|
|
|
|
// Handle a deep copy situation
|
|
if ( typeof target === "boolean" ) {
|
|
deep = target;
|
|
|
|
// Skip the boolean and the target
|
|
target = arguments[ i ] || {};
|
|
i++;
|
|
}
|
|
|
|
// Handle case when target is a string or something (possible in deep copy)
|
|
if ( typeof target !== "object" && !isFunction( target ) ) {
|
|
target = {};
|
|
}
|
|
|
|
// Extend jQuery itself if only one argument is passed
|
|
if ( i === length ) {
|
|
target = this;
|
|
i--;
|
|
}
|
|
|
|
for ( ; i < length; i++ ) {
|
|
|
|
// Only deal with non-null/undefined values
|
|
if ( ( options = arguments[ i ] ) != null ) {
|
|
|
|
// Extend the base object
|
|
for ( name in options ) {
|
|
copy = options[ name ];
|
|
|
|
// Prevent Object.prototype pollution
|
|
// Prevent never-ending loop
|
|
if ( name === "__proto__" || target === copy ) {
|
|
continue;
|
|
}
|
|
|
|
// Recurse if we're merging plain objects or arrays
|
|
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
|
|
( copyIsArray = Array.isArray( copy ) ) ) ) {
|
|
src = target[ name ];
|
|
|
|
// Ensure proper type for the source value
|
|
if ( copyIsArray && !Array.isArray( src ) ) {
|
|
clone = [];
|
|
} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
|
|
clone = {};
|
|
} else {
|
|
clone = src;
|
|
}
|
|
copyIsArray = false;
|
|
|
|
// Never move original objects, clone them
|
|
target[ name ] = jQuery.extend( deep, clone, copy );
|
|
|
|
// Don't bring in undefined values
|
|
} else if ( copy !== undefined ) {
|
|
target[ name ] = copy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the modified object
|
|
return target;
|
|
};
|
|
|
|
jQuery.extend( {
|
|
|
|
// Unique for each copy of jQuery on the page
|
|
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
|
|
|
|
// Assume jQuery is ready without the ready module
|
|
isReady: true,
|
|
|
|
error: function( msg ) {
|
|
throw new Error( msg );
|
|
},
|
|
|
|
noop: function() {},
|
|
|
|
isPlainObject: function( obj ) {
|
|
var proto, Ctor;
|
|
|
|
// Detect obvious negatives
|
|
// Use toString instead of jQuery.type to catch host objects
|
|
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
|
|
return false;
|
|
}
|
|
|
|
proto = getProto( obj );
|
|
|
|
// Objects with no prototype (e.g., `Object.create( null )`) are plain
|
|
if ( !proto ) {
|
|
return true;
|
|
}
|
|
|
|
// Objects with prototype are plain iff they were constructed by a global Object function
|
|
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
|
|
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
|
|
},
|
|
|
|
isEmptyObject: function( obj ) {
|
|
var name;
|
|
|
|
for ( name in obj ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
// Evaluates a script in a global context
|
|
globalEval: function( code, options ) {
|
|
DOMEval( code, { nonce: options && options.nonce } );
|
|
},
|
|
|
|
each: function( obj, callback ) {
|
|
var length, i = 0;
|
|
|
|
if ( isArrayLike( obj ) ) {
|
|
length = obj.length;
|
|
for ( ; i < length; i++ ) {
|
|
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for ( i in obj ) {
|
|
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
},
|
|
|
|
// Support: Android <=4.0 only
|
|
trim: function( text ) {
|
|
return text == null ?
|
|
"" :
|
|
( text + "" ).replace( rtrim, "" );
|
|
},
|
|
|
|
// results is for internal usage only
|
|
makeArray: function( arr, results ) {
|
|
var ret = results || [];
|
|
|
|
if ( arr != null ) {
|
|
if ( isArrayLike( Object( arr ) ) ) {
|
|
jQuery.merge( ret,
|
|
typeof arr === "string" ?
|
|
[ arr ] : arr
|
|
);
|
|
} else {
|
|
push.call( ret, arr );
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
|
|
inArray: function( elem, arr, i ) {
|
|
return arr == null ? -1 : indexOf.call( arr, elem, i );
|
|
},
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
merge: function( first, second ) {
|
|
var len = +second.length,
|
|
j = 0,
|
|
i = first.length;
|
|
|
|
for ( ; j < len; j++ ) {
|
|
first[ i++ ] = second[ j ];
|
|
}
|
|
|
|
first.length = i;
|
|
|
|
return first;
|
|
},
|
|
|
|
grep: function( elems, callback, invert ) {
|
|
var callbackInverse,
|
|
matches = [],
|
|
i = 0,
|
|
length = elems.length,
|
|
callbackExpect = !invert;
|
|
|
|
// Go through the array, only saving the items
|
|
// that pass the validator function
|
|
for ( ; i < length; i++ ) {
|
|
callbackInverse = !callback( elems[ i ], i );
|
|
if ( callbackInverse !== callbackExpect ) {
|
|
matches.push( elems[ i ] );
|
|
}
|
|
}
|
|
|
|
return matches;
|
|
},
|
|
|
|
// arg is for internal usage only
|
|
map: function( elems, callback, arg ) {
|
|
var length, value,
|
|
i = 0,
|
|
ret = [];
|
|
|
|
// Go through the array, translating each of the items to their new values
|
|
if ( isArrayLike( elems ) ) {
|
|
length = elems.length;
|
|
for ( ; i < length; i++ ) {
|
|
value = callback( elems[ i ], i, arg );
|
|
|
|
if ( value != null ) {
|
|
ret.push( value );
|
|
}
|
|
}
|
|
|
|
// Go through every key on the object,
|
|
} else {
|
|
for ( i in elems ) {
|
|
value = callback( elems[ i ], i, arg );
|
|
|
|
if ( value != null ) {
|
|
ret.push( value );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Flatten any nested arrays
|
|
return concat.apply( [], ret );
|
|
},
|
|
|
|
// A global GUID counter for objects
|
|
guid: 1,
|
|
|
|
// jQuery.support is not used in Core but other projects attach their
|
|
// properties to it so it needs to exist.
|
|
support: support
|
|
} );
|
|
|
|
if ( typeof Symbol === "function" ) {
|
|
jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
|
|
}
|
|
|
|
// Populate the class2type map
|
|
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
|
|
function( i, name ) {
|
|
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
|
} );
|
|
|
|
function isArrayLike( obj ) {
|
|
|
|
// Support: real iOS 8.2 only (not reproducible in simulator)
|
|
// `in` check used to prevent JIT error (gh-2145)
|
|
// hasOwn isn't used here due to false negatives
|
|
// regarding Nodelist length in IE
|
|
var length = !!obj && "length" in obj && obj.length,
|
|
type = toType( obj );
|
|
|
|
if ( isFunction( obj ) || isWindow( obj ) ) {
|
|
return false;
|
|
}
|
|
|
|
return type === "array" || length === 0 ||
|
|
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
|
|
}
|
|
var Sizzle =
|
|
/*!
|
|
* Sizzle CSS Selector Engine v2.3.4
|
|
* https://sizzlejs.com/
|
|
*
|
|
* Copyright JS Foundation and other contributors
|
|
* Released under the MIT license
|
|
* https://js.foundation/
|
|
*
|
|
* Date: 2019-04-08
|
|
*/
|
|
(function( window ) {
|
|
|
|
var i,
|
|
support,
|
|
Expr,
|
|
getText,
|
|
isXML,
|
|
tokenize,
|
|
compile,
|
|
select,
|
|
outermostContext,
|
|
sortInput,
|
|
hasDuplicate,
|
|
|
|
// Local document vars
|
|
setDocument,
|
|
document,
|
|
docElem,
|
|
documentIsHTML,
|
|
rbuggyQSA,
|
|
rbuggyMatches,
|
|
matches,
|
|
contains,
|
|
|
|
// Instance-specific data
|
|
expando = "sizzle" + 1 * new Date(),
|
|
preferredDoc = window.document,
|
|
dirruns = 0,
|
|
done = 0,
|
|
classCache = createCache(),
|
|
tokenCache = createCache(),
|
|
compilerCache = createCache(),
|
|
nonnativeSelectorCache = createCache(),
|
|
sortOrder = function( a, b ) {
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
}
|
|
return 0;
|
|
},
|
|
|
|
// Instance methods
|
|
hasOwn = ({}).hasOwnProperty,
|
|
arr = [],
|
|
pop = arr.pop,
|
|
push_native = arr.push,
|
|
push = arr.push,
|
|
slice = arr.slice,
|
|
// Use a stripped-down indexOf as it's faster than native
|
|
// https://jsperf.com/thor-indexof-vs-for/5
|
|
indexOf = function( list, elem ) {
|
|
var i = 0,
|
|
len = list.length;
|
|
for ( ; i < len; i++ ) {
|
|
if ( list[i] === elem ) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
|
|
booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
|
|
|
|
// Regular expressions
|
|
|
|
// http://www.w3.org/TR/css3-selectors/#whitespace
|
|
whitespace = "[\\x20\\t\\r\\n\\f]",
|
|
|
|
// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
|
|
identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
|
|
|
|
// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
|
|
attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
|
|
// Operator (capture 2)
|
|
"*([*^$|!~]?=)" + whitespace +
|
|
// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
|
|
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
|
|
"*\\]",
|
|
|
|
pseudos = ":(" + identifier + ")(?:\\((" +
|
|
// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
|
|
// 1. quoted (capture 3; capture 4 or capture 5)
|
|
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
|
|
// 2. simple (capture 6)
|
|
"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
|
|
// 3. anything else (capture 2)
|
|
".*" +
|
|
")\\)|)",
|
|
|
|
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
|
|
rwhitespace = new RegExp( whitespace + "+", "g" ),
|
|
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
|
|
|
|
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
|
|
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
|
|
rdescend = new RegExp( whitespace + "|>" ),
|
|
|
|
rpseudo = new RegExp( pseudos ),
|
|
ridentifier = new RegExp( "^" + identifier + "$" ),
|
|
|
|
matchExpr = {
|
|
"ID": new RegExp( "^#(" + identifier + ")" ),
|
|
"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
|
|
"TAG": new RegExp( "^(" + identifier + "|[*])" ),
|
|
"ATTR": new RegExp( "^" + attributes ),
|
|
"PSEUDO": new RegExp( "^" + pseudos ),
|
|
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
|
|
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
|
|
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
|
|
"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
|
|
// For use in libraries implementing .is()
|
|
// We use this for POS matching in `select`
|
|
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
|
|
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
|
|
},
|
|
|
|
rhtml = /HTML$/i,
|
|
rinputs = /^(?:input|select|textarea|button)$/i,
|
|
rheader = /^h\d$/i,
|
|
|
|
rnative = /^[^{]+\{\s*\[native \w/,
|
|
|
|
// Easily-parseable/retrievable ID or TAG or CLASS selectors
|
|
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
|
|
|
|
rsibling = /[+~]/,
|
|
|
|
// CSS escapes
|
|
// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
|
|
runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
|
|
funescape = function( _, escaped, escapedWhitespace ) {
|
|
var high = "0x" + escaped - 0x10000;
|
|
// NaN means non-codepoint
|
|
// Support: Firefox<24
|
|
// Workaround erroneous numeric interpretation of +"0x"
|
|
return high !== high || escapedWhitespace ?
|
|
escaped :
|
|
high < 0 ?
|
|
// BMP codepoint
|
|
String.fromCharCode( high + 0x10000 ) :
|
|
// Supplemental Plane codepoint (surrogate pair)
|
|
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
|
|
},
|
|
|
|
// CSS string/identifier serialization
|
|
// https://drafts.csswg.org/cssom/#common-serializing-idioms
|
|
rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
|
|
fcssescape = function( ch, asCodePoint ) {
|
|
if ( asCodePoint ) {
|
|
|
|
// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
|
|
if ( ch === "\0" ) {
|
|
return "\uFFFD";
|
|
}
|
|
|
|
// Control characters and (dependent upon position) numbers get escaped as code points
|
|
return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
|
|
}
|
|
|
|
// Other potentially-special ASCII characters get backslash-escaped
|
|
return "\\" + ch;
|
|
},
|
|
|
|
// Used for iframes
|
|
// See setDocument()
|
|
// Removing the function wrapper causes a "Permission Denied"
|
|
// error in IE
|
|
unloadHandler = function() {
|
|
setDocument();
|
|
},
|
|
|
|
inDisabledFieldset = addCombinator(
|
|
function( elem ) {
|
|
return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
|
|
},
|
|
{ dir: "parentNode", next: "legend" }
|
|
);
|
|
|
|
// Optimize for push.apply( _, NodeList )
|
|
try {
|
|
push.apply(
|
|
(arr = slice.call( preferredDoc.childNodes )),
|
|
preferredDoc.childNodes
|
|
);
|
|
// Support: Android<4.0
|
|
// Detect silently failing push.apply
|
|
arr[ preferredDoc.childNodes.length ].nodeType;
|
|
} catch ( e ) {
|
|
push = { apply: arr.length ?
|
|
|
|
// Leverage slice if possible
|
|
function( target, els ) {
|
|
push_native.apply( target, slice.call(els) );
|
|
} :
|
|
|
|
// Support: IE<9
|
|
// Otherwise append directly
|
|
function( target, els ) {
|
|
var j = target.length,
|
|
i = 0;
|
|
// Can't trust NodeList.length
|
|
while ( (target[j++] = els[i++]) ) {}
|
|
target.length = j - 1;
|
|
}
|
|
};
|
|
}
|
|
|
|
function Sizzle( selector, context, results, seed ) {
|
|
var m, i, elem, nid, match, groups, newSelector,
|
|
newContext = context && context.ownerDocument,
|
|
|
|
// nodeType defaults to 9, since context defaults to document
|
|
nodeType = context ? context.nodeType : 9;
|
|
|
|
results = results || [];
|
|
|
|
// Return early from calls with invalid selector or context
|
|
if ( typeof selector !== "string" || !selector ||
|
|
nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
|
|
|
|
return results;
|
|
}
|
|
|
|
// Try to shortcut find operations (as opposed to filters) in HTML documents
|
|
if ( !seed ) {
|
|
|
|
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
|
|
setDocument( context );
|
|
}
|
|
context = context || document;
|
|
|
|
if ( documentIsHTML ) {
|
|
|
|
// If the selector is sufficiently simple, try using a "get*By*" DOM method
|
|
// (excepting DocumentFragment context, where the methods don't exist)
|
|
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
|
|
|
|
// ID selector
|
|
if ( (m = match[1]) ) {
|
|
|
|
// Document context
|
|
if ( nodeType === 9 ) {
|
|
if ( (elem = context.getElementById( m )) ) {
|
|
|
|
// Support: IE, Opera, Webkit
|
|
// TODO: identify versions
|
|
// getElementById can match elements by name instead of ID
|
|
if ( elem.id === m ) {
|
|
results.push( elem );
|
|
return results;
|
|
}
|
|
} else {
|
|
return results;
|
|
}
|
|
|
|
// Element context
|
|
} else {
|
|
|
|
// Support: IE, Opera, Webkit
|
|
// TODO: identify versions
|
|
// getElementById can match elements by name instead of ID
|
|
if ( newContext && (elem = newContext.getElementById( m )) &&
|
|
contains( context, elem ) &&
|
|
elem.id === m ) {
|
|
|
|
results.push( elem );
|
|
return results;
|
|
}
|
|
}
|
|
|
|
// Type selector
|
|
} else if ( match[2] ) {
|
|
push.apply( results, context.getElementsByTagName( selector ) );
|
|
return results;
|
|
|
|
// Class selector
|
|
} else if ( (m = match[3]) && support.getElementsByClassName &&
|
|
context.getElementsByClassName ) {
|
|
|
|
push.apply( results, context.getElementsByClassName( m ) );
|
|
return results;
|
|
}
|
|
}
|
|
|
|
// Take advantage of querySelectorAll
|
|
if ( support.qsa &&
|
|
!nonnativeSelectorCache[ selector + " " ] &&
|
|
(!rbuggyQSA || !rbuggyQSA.test( selector )) &&
|
|
|
|
// Support: IE 8 only
|
|
// Exclude object elements
|
|
(nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
|
|
|
|
newSelector = selector;
|
|
newContext = context;
|
|
|
|
// qSA considers elements outside a scoping root when evaluating child or
|
|
// descendant combinators, which is not what we want.
|
|
// In such cases, we work around the behavior by prefixing every selector in the
|
|
// list with an ID selector referencing the scope context.
|
|
// Thanks to Andrew Dupont for this technique.
|
|
if ( nodeType === 1 && rdescend.test( selector ) ) {
|
|
|
|
// Capture the context ID, setting it first if necessary
|
|
if ( (nid = context.getAttribute( "id" )) ) {
|
|
nid = nid.replace( rcssescape, fcssescape );
|
|
} else {
|
|
context.setAttribute( "id", (nid = expando) );
|
|
}
|
|
|
|
// Prefix every selector in the list
|
|
groups = tokenize( selector );
|
|
i = groups.length;
|
|
while ( i-- ) {
|
|
groups[i] = "#" + nid + " " + toSelector( groups[i] );
|
|
}
|
|
newSelector = groups.join( "," );
|
|
|
|
// Expand context for sibling selectors
|
|
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
|
|
context;
|
|
}
|
|
|
|
try {
|
|
push.apply( results,
|
|
newContext.querySelectorAll( newSelector )
|
|
);
|
|
return results;
|
|
} catch ( qsaError ) {
|
|
nonnativeSelectorCache( selector, true );
|
|
} finally {
|
|
if ( nid === expando ) {
|
|
context.removeAttribute( "id" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// All others
|
|
return select( selector.replace( rtrim, "$1" ), context, results, seed );
|
|
}
|
|
|
|
/**
|
|
* Create key-value caches of limited size
|
|
* @returns {function(string, object)} Returns the Object data after storing it on itself with
|
|
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
|
|
* deleting the oldest entry
|
|
*/
|
|
function createCache() {
|
|
var keys = [];
|
|
|
|
function cache( key, value ) {
|
|
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
|
|
if ( keys.push( key + " " ) > Expr.cacheLength ) {
|
|
// Only keep the most recent entries
|
|
delete cache[ keys.shift() ];
|
|
}
|
|
return (cache[ key + " " ] = value);
|
|
}
|
|
return cache;
|
|
}
|
|
|
|
/**
|
|
* Mark a function for special use by Sizzle
|
|
* @param {Function} fn The function to mark
|
|
*/
|
|
function markFunction( fn ) {
|
|
fn[ expando ] = true;
|
|
return fn;
|
|
}
|
|
|
|
/**
|
|
* Support testing using an element
|
|
* @param {Function} fn Passed the created element and returns a boolean result
|
|
*/
|
|
function assert( fn ) {
|
|
var el = document.createElement("fieldset");
|
|
|
|
try {
|
|
return !!fn( el );
|
|
} catch (e) {
|
|
return false;
|
|
} finally {
|
|
// Remove from its parent by default
|
|
if ( el.parentNode ) {
|
|
el.parentNode.removeChild( el );
|
|
}
|
|
// release memory in IE
|
|
el = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds the same handler for all of the specified attrs
|
|
* @param {String} attrs Pipe-separated list of attributes
|
|
* @param {Function} handler The method that will be applied
|
|
*/
|
|
function addHandle( attrs, handler ) {
|
|
var arr = attrs.split("|"),
|
|
i = arr.length;
|
|
|
|
while ( i-- ) {
|
|
Expr.attrHandle[ arr[i] ] = handler;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks document order of two siblings
|
|
* @param {Element} a
|
|
* @param {Element} b
|
|
* @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
|
|
*/
|
|
function siblingCheck( a, b ) {
|
|
var cur = b && a,
|
|
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
|
|
a.sourceIndex - b.sourceIndex;
|
|
|
|
// Use IE sourceIndex if available on both nodes
|
|
if ( diff ) {
|
|
return diff;
|
|
}
|
|
|
|
// Check if b follows a
|
|
if ( cur ) {
|
|
while ( (cur = cur.nextSibling) ) {
|
|
if ( cur === b ) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return a ? 1 : -1;
|
|
}
|
|
|
|
/**
|
|
* Returns a function to use in pseudos for input types
|
|
* @param {String} type
|
|
*/
|
|
function createInputPseudo( type ) {
|
|
return function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === "input" && elem.type === type;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns a function to use in pseudos for buttons
|
|
* @param {String} type
|
|
*/
|
|
function createButtonPseudo( type ) {
|
|
return function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return (name === "input" || name === "button") && elem.type === type;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns a function to use in pseudos for :enabled/:disabled
|
|
* @param {Boolean} disabled true for :disabled; false for :enabled
|
|
*/
|
|
function createDisabledPseudo( disabled ) {
|
|
|
|
// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
|
|
return function( elem ) {
|
|
|
|
// Only certain elements can match :enabled or :disabled
|
|
// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
|
|
// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
|
|
if ( "form" in elem ) {
|
|
|
|
// Check for inherited disabledness on relevant non-disabled elements:
|
|
// * listed form-associated elements in a disabled fieldset
|
|
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
|
// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
|
|
// * option elements in a disabled optgroup
|
|
// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
|
|
// All such elements have a "form" property.
|
|
if ( elem.parentNode && elem.disabled === false ) {
|
|
|
|
// Option elements defer to a parent optgroup if present
|
|
if ( "label" in elem ) {
|
|
if ( "label" in elem.parentNode ) {
|
|
return elem.parentNode.disabled === disabled;
|
|
} else {
|
|
return elem.disabled === disabled;
|
|
}
|
|
}
|
|
|
|
// Support: IE 6 - 11
|
|
// Use the isDisabled shortcut property to check for disabled fieldset ancestors
|
|
return elem.isDisabled === disabled ||
|
|
|
|
// Where there is no isDisabled, check manually
|
|
/* jshint -W018 */
|
|
elem.isDisabled !== !disabled &&
|
|
inDisabledFieldset( elem ) === disabled;
|
|
}
|
|
|
|
return elem.disabled === disabled;
|
|
|
|
// Try to winnow out elements that can't be disabled before trusting the disabled property.
|
|
// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
|
|
// even exist on them, let alone have a boolean value.
|
|
} else if ( "label" in elem ) {
|
|
return elem.disabled === disabled;
|
|
}
|
|
|
|
// Remaining elements are neither :enabled nor :disabled
|
|
return false;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns a function to use in pseudos for positionals
|
|
* @param {Function} fn
|
|
*/
|
|
function createPositionalPseudo( fn ) {
|
|
return markFunction(function( argument ) {
|
|
argument = +argument;
|
|
return markFunction(function( seed, matches ) {
|
|
var j,
|
|
matchIndexes = fn( [], seed.length, argument ),
|
|
i = matchIndexes.length;
|
|
|
|
// Match elements found at the specified indexes
|
|
while ( i-- ) {
|
|
if ( seed[ (j = matchIndexes[i]) ] ) {
|
|
seed[j] = !(matches[j] = seed[j]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Checks a node for validity as a Sizzle context
|
|
* @param {Element|Object=} context
|
|
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
|
|
*/
|
|
function testContext( context ) {
|
|
return context && typeof context.getElementsByTagName !== "undefined" && context;
|
|
}
|
|
|
|
// Expose support vars for convenience
|
|
support = Sizzle.support = {};
|
|
|
|
/**
|
|
* Detects XML nodes
|
|
* @param {Element|Object} elem An element or a document
|
|
* @returns {Boolean} True iff elem is a non-HTML XML node
|
|
*/
|
|
isXML = Sizzle.isXML = function( elem ) {
|
|
var namespace = elem.namespaceURI,
|
|
docElem = (elem.ownerDocument || elem).documentElement;
|
|
|
|
// Support: IE <=8
|
|
// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
|
|
// https://bugs.jquery.com/ticket/4833
|
|
return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
|
|
};
|
|
|
|
/**
|
|
* Sets document-related variables once based on the current document
|
|
* @param {Element|Object} [doc] An element or document object to use to set the document
|
|
* @returns {Object} Returns the current document
|
|
*/
|
|
setDocument = Sizzle.setDocument = function( node ) {
|
|
var hasCompare, subWindow,
|
|
doc = node ? node.ownerDocument || node : preferredDoc;
|
|
|
|
// Return early if doc is invalid or already selected
|
|
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
|
|
return document;
|
|
}
|
|
|
|
// Update global variables
|
|
document = doc;
|
|
docElem = document.documentElement;
|
|
documentIsHTML = !isXML( document );
|
|
|
|
// Support: IE 9-11, Edge
|
|
// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
|
|
if ( preferredDoc !== document &&
|
|
(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
|
|
|
|
// Support: IE 11, Edge
|
|
if ( subWindow.addEventListener ) {
|
|
subWindow.addEventListener( "unload", unloadHandler, false );
|
|
|
|
// Support: IE 9 - 10 only
|
|
} else if ( subWindow.attachEvent ) {
|
|
subWindow.attachEvent( "onunload", unloadHandler );
|
|
}
|
|
}
|
|
|
|
/* Attributes
|
|
---------------------------------------------------------------------- */
|
|
|
|
// Support: IE<8
|
|
// Verify that getAttribute really returns attributes and not properties
|
|
// (excepting IE8 booleans)
|
|
support.attributes = assert(function( el ) {
|
|
el.className = "i";
|
|
return !el.getAttribute("className");
|
|
});
|
|
|
|
/* getElement(s)By*
|
|
---------------------------------------------------------------------- */
|
|
|
|
// Check if getElementsByTagName("*") returns only elements
|
|
support.getElementsByTagName = assert(function( el ) {
|
|
el.appendChild( document.createComment("") );
|
|
return !el.getElementsByTagName("*").length;
|
|
});
|
|
|
|
// Support: IE<9
|
|
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
|
|
|
|
// Support: IE<10
|
|
// Check if getElementById returns elements by name
|
|
// The broken getElementById methods don't pick up programmatically-set names,
|
|
// so use a roundabout getElementsByName test
|
|
support.getById = assert(function( el ) {
|
|
docElem.appendChild( el ).id = expando;
|
|
return !document.getElementsByName || !document.getElementsByName( expando ).length;
|
|
});
|
|
|
|
// ID filter and find
|
|
if ( support.getById ) {
|
|
Expr.filter["ID"] = function( id ) {
|
|
var attrId = id.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
return elem.getAttribute("id") === attrId;
|
|
};
|
|
};
|
|
Expr.find["ID"] = function( id, context ) {
|
|
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
|
|
var elem = context.getElementById( id );
|
|
return elem ? [ elem ] : [];
|
|
}
|
|
};
|
|
} else {
|
|
Expr.filter["ID"] = function( id ) {
|
|
var attrId = id.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
var node = typeof elem.getAttributeNode !== "undefined" &&
|
|
elem.getAttributeNode("id");
|
|
return node && node.value === attrId;
|
|
};
|
|
};
|
|
|
|
// Support: IE 6 - 7 only
|
|
// getElementById is not reliable as a find shortcut
|
|
Expr.find["ID"] = function( id, context ) {
|
|
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
|
|
var node, i, elems,
|
|
elem = context.getElementById( id );
|
|
|
|
if ( elem ) {
|
|
|
|
// Verify the id attribute
|
|
node = elem.getAttributeNode("id");
|
|
if ( node && node.value === id ) {
|
|
return [ elem ];
|
|
}
|
|
|
|
// Fall back on getElementsByName
|
|
elems = context.getElementsByName( id );
|
|
i = 0;
|
|
while ( (elem = elems[i++]) ) {
|
|
node = elem.getAttributeNode("id");
|
|
if ( node && node.value === id ) {
|
|
return [ elem ];
|
|
}
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
};
|
|
}
|
|
|
|
// Tag
|
|
Expr.find["TAG"] = support.getElementsByTagName ?
|
|
function( tag, context ) {
|
|
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
|
return context.getElementsByTagName( tag );
|
|
|
|
// DocumentFragment nodes don't have gEBTN
|
|
} else if ( support.qsa ) {
|
|
return context.querySelectorAll( tag );
|
|
}
|
|
} :
|
|
|
|
function( tag, context ) {
|
|
var elem,
|
|
tmp = [],
|
|
i = 0,
|
|
// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
|
|
results = context.getElementsByTagName( tag );
|
|
|
|
// Filter out possible comments
|
|
if ( tag === "*" ) {
|
|
while ( (elem = results[i++]) ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
tmp.push( elem );
|
|
}
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
return results;
|
|
};
|
|
|
|
// Class
|
|
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
|
|
if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
|
|
return context.getElementsByClassName( className );
|
|
}
|
|
};
|
|
|
|
/* QSA/matchesSelector
|
|
---------------------------------------------------------------------- */
|
|
|
|
// QSA and matchesSelector support
|
|
|
|
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
|
|
rbuggyMatches = [];
|
|
|
|
// qSa(:focus) reports false when true (Chrome 21)
|
|
// We allow this because of a bug in IE8/9 that throws an error
|
|
// whenever `document.activeElement` is accessed on an iframe
|
|
// So, we allow :focus to pass through QSA all the time to avoid the IE error
|
|
// See https://bugs.jquery.com/ticket/13378
|
|
rbuggyQSA = [];
|
|
|
|
if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
|
|
// Build QSA regex
|
|
// Regex strategy adopted from Diego Perini
|
|
assert(function( el ) {
|
|
// Select is set to empty string on purpose
|
|
// This is to test IE's treatment of not explicitly
|
|
// setting a boolean content attribute,
|
|
// since its presence should be enough
|
|
// https://bugs.jquery.com/ticket/12359
|
|
docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
|
|
"<select id='" + expando + "-\r\\' msallowcapture=''>" +
|
|
"<option selected=''></option></select>";
|
|
|
|
// Support: IE8, Opera 11-12.16
|
|
// Nothing should be selected when empty strings follow ^= or $= or *=
|
|
// The test attribute must be unknown in Opera but "safe" for WinRT
|
|
// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
|
|
if ( el.querySelectorAll("[msallowcapture^='']").length ) {
|
|
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
|
|
}
|
|
|
|
// Support: IE8
|
|
// Boolean attributes and "value" are not treated correctly
|
|
if ( !el.querySelectorAll("[selected]").length ) {
|
|
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
|
|
}
|
|
|
|
// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
|
|
if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
|
|
rbuggyQSA.push("~=");
|
|
}
|
|
|
|
// Webkit/Opera - :checked should return selected option elements
|
|
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
|
// IE8 throws error here and will not see later tests
|
|
if ( !el.querySelectorAll(":checked").length ) {
|
|
rbuggyQSA.push(":checked");
|
|
}
|
|
|
|
// Support: Safari 8+, iOS 8+
|
|
// https://bugs.webkit.org/show_bug.cgi?id=136851
|
|
// In-page `selector#id sibling-combinator selector` fails
|
|
if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
|
|
rbuggyQSA.push(".#.+[+~]");
|
|
}
|
|
});
|
|
|
|
assert(function( el ) {
|
|
el.innerHTML = "<a href='' disabled='disabled'></a>" +
|
|
"<select disabled='disabled'><option/></select>";
|
|
|
|
// Support: Windows 8 Native Apps
|
|
// The type and name attributes are restricted during .innerHTML assignment
|
|
var input = document.createElement("input");
|
|
input.setAttribute( "type", "hidden" );
|
|
el.appendChild( input ).setAttribute( "name", "D" );
|
|
|
|
// Support: IE8
|
|
// Enforce case-sensitivity of name attribute
|
|
if ( el.querySelectorAll("[name=d]").length ) {
|
|
rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
|
|
}
|
|
|
|
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
|
|
// IE8 throws error here and will not see later tests
|
|
if ( el.querySelectorAll(":enabled").length !== 2 ) {
|
|
rbuggyQSA.push( ":enabled", ":disabled" );
|
|
}
|
|
|
|
// Support: IE9-11+
|
|
// IE's :disabled selector does not pick up the children of disabled fieldsets
|
|
docElem.appendChild( el ).disabled = true;
|
|
if ( el.querySelectorAll(":disabled").length !== 2 ) {
|
|
rbuggyQSA.push( ":enabled", ":disabled" );
|
|
}
|
|
|
|
// Opera 10-11 does not throw on post-comma invalid pseudos
|
|
el.querySelectorAll("*,:x");
|
|
rbuggyQSA.push(",.*:");
|
|
});
|
|
}
|
|
|
|
if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
|
|
docElem.webkitMatchesSelector ||
|
|
docElem.mozMatchesSelector ||
|
|
docElem.oMatchesSelector ||
|
|
docElem.msMatchesSelector) )) ) {
|
|
|
|
assert(function( el ) {
|
|
// Check to see if it's possible to do matchesSelector
|
|
// on a disconnected node (IE 9)
|
|
support.disconnectedMatch = matches.call( el, "*" );
|
|
|
|
// This should fail with an exception
|
|
// Gecko does not error, returns false instead
|
|
matches.call( el, "[s!='']:x" );
|
|
rbuggyMatches.push( "!=", pseudos );
|
|
});
|
|
}
|
|
|
|
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
|
|
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
|
|
|
|
/* Contains
|
|
---------------------------------------------------------------------- */
|
|
hasCompare = rnative.test( docElem.compareDocumentPosition );
|
|
|
|
// Element contains another
|
|
// Purposefully self-exclusive
|
|
// As in, an element does not contain itself
|
|
contains = hasCompare || rnative.test( docElem.contains ) ?
|
|
function( a, b ) {
|
|
var adown = a.nodeType === 9 ? a.documentElement : a,
|
|
bup = b && b.parentNode;
|
|
return a === bup || !!( bup && bup.nodeType === 1 && (
|
|
adown.contains ?
|
|
adown.contains( bup ) :
|
|
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
|
));
|
|
} :
|
|
function( a, b ) {
|
|
if ( b ) {
|
|
while ( (b = b.parentNode) ) {
|
|
if ( b === a ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/* Sorting
|
|
---------------------------------------------------------------------- */
|
|
|
|
// Document order sorting
|
|
sortOrder = hasCompare ?
|
|
function( a, b ) {
|
|
|
|
// Flag for duplicate removal
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
|
|
// Sort on method existence if only one input has compareDocumentPosition
|
|
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
|
|
if ( compare ) {
|
|
return compare;
|
|
}
|
|
|
|
// Calculate position if both inputs belong to the same document
|
|
compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
|
|
a.compareDocumentPosition( b ) :
|
|
|
|
// Otherwise we know they are disconnected
|
|
1;
|
|
|
|
// Disconnected nodes
|
|
if ( compare & 1 ||
|
|
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
|
|
|
|
// Choose the first element that is related to our preferred document
|
|
if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
|
|
return -1;
|
|
}
|
|
if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
|
|
return 1;
|
|
}
|
|
|
|
// Maintain original order
|
|
return sortInput ?
|
|
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
|
|
0;
|
|
}
|
|
|
|
return compare & 4 ? -1 : 1;
|
|
} :
|
|
function( a, b ) {
|
|
// Exit early if the nodes are identical
|
|
if ( a === b ) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
|
|
var cur,
|
|
i = 0,
|
|
aup = a.parentNode,
|
|
bup = b.parentNode,
|
|
ap = [ a ],
|
|
bp = [ b ];
|
|
|
|
// Parentless nodes are either documents or disconnected
|
|
if ( !aup || !bup ) {
|
|
return a === document ? -1 :
|
|
b === document ? 1 :
|
|
aup ? -1 :
|
|
bup ? 1 :
|
|
sortInput ?
|
|
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
|
|
0;
|
|
|
|
// If the nodes are siblings, we can do a quick check
|
|
} else if ( aup === bup ) {
|
|
return siblingCheck( a, b );
|
|
}
|
|
|
|
// Otherwise we need full lists of their ancestors for comparison
|
|
cur = a;
|
|
while ( (cur = cur.parentNode) ) {
|
|
ap.unshift( cur );
|
|
}
|
|
cur = b;
|
|
while ( (cur = cur.parentNode) ) {
|
|
bp.unshift( cur );
|
|
}
|
|
|
|
// Walk down the tree looking for a discrepancy
|
|
while ( ap[i] === bp[i] ) {
|
|
i++;
|
|
}
|
|
|
|
return i ?
|
|
// Do a sibling check if the nodes have a common ancestor
|
|
siblingCheck( ap[i], bp[i] ) :
|
|
|
|
// Otherwise nodes in our document sort first
|
|
ap[i] === preferredDoc ? -1 :
|
|
bp[i] === preferredDoc ? 1 :
|
|
0;
|
|
};
|
|
|
|
return document;
|
|
};
|
|
|
|
Sizzle.matches = function( expr, elements ) {
|
|
return Sizzle( expr, null, null, elements );
|
|
};
|
|
|
|
Sizzle.matchesSelector = function( elem, expr ) {
|
|
// Set document vars if needed
|
|
if ( ( elem.ownerDocument || elem ) !== document ) {
|
|
setDocument( elem );
|
|
}
|
|
|
|
if ( support.matchesSelector && documentIsHTML &&
|
|
!nonnativeSelectorCache[ expr + " " ] &&
|
|
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
|
|
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
|
|
|
|
try {
|
|
var ret = matches.call( elem, expr );
|
|
|
|
// IE 9's matchesSelector returns false on disconnected nodes
|
|
if ( ret || support.disconnectedMatch ||
|
|
// As well, disconnected nodes are said to be in a document
|
|
// fragment in IE 9
|
|
elem.document && elem.document.nodeType !== 11 ) {
|
|
return ret;
|
|
}
|
|
} catch (e) {
|
|
nonnativeSelectorCache( expr, true );
|
|
}
|
|
}
|
|
|
|
return Sizzle( expr, document, null, [ elem ] ).length > 0;
|
|
};
|
|
|
|
Sizzle.contains = function( context, elem ) {
|
|
// Set document vars if needed
|
|
if ( ( context.ownerDocument || context ) !== document ) {
|
|
setDocument( context );
|
|
}
|
|
return contains( context, elem );
|
|
};
|
|
|
|
Sizzle.attr = function( elem, name ) {
|
|
// Set document vars if needed
|
|
if ( ( elem.ownerDocument || elem ) !== document ) {
|
|
setDocument( elem );
|
|
}
|
|
|
|
var fn = Expr.attrHandle[ name.toLowerCase() ],
|
|
// Don't get fooled by Object.prototype properties (jQuery #13807)
|
|
val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
|
|
fn( elem, name, !documentIsHTML ) :
|
|
undefined;
|
|
|
|
return val !== undefined ?
|
|
val :
|
|
support.attributes || !documentIsHTML ?
|
|
elem.getAttribute( name ) :
|
|
(val = elem.getAttributeNode(name)) && val.specified ?
|
|
val.value :
|
|
null;
|
|
};
|
|
|
|
Sizzle.escape = function( sel ) {
|
|
return (sel + "").replace( rcssescape, fcssescape );
|
|
};
|
|
|
|
Sizzle.error = function( msg ) {
|
|
throw new Error( "Syntax error, unrecognized expression: " + msg );
|
|
};
|
|
|
|
/**
|
|
* Document sorting and removing duplicates
|
|
* @param {ArrayLike} results
|
|
*/
|
|
Sizzle.uniqueSort = function( results ) {
|
|
var elem,
|
|
duplicates = [],
|
|
j = 0,
|
|
i = 0;
|
|
|
|
// Unless we *know* we can detect duplicates, assume their presence
|
|
hasDuplicate = !support.detectDuplicates;
|
|
sortInput = !support.sortStable && results.slice( 0 );
|
|
results.sort( sortOrder );
|
|
|
|
if ( hasDuplicate ) {
|
|
while ( (elem = results[i++]) ) {
|
|
if ( elem === results[ i ] ) {
|
|
j = duplicates.push( i );
|
|
}
|
|
}
|
|
while ( j-- ) {
|
|
results.splice( duplicates[ j ], 1 );
|
|
}
|
|
}
|
|
|
|
// Clear input after sorting to release objects
|
|
// See https://github.com/jquery/sizzle/pull/225
|
|
sortInput = null;
|
|
|
|
return results;
|
|
};
|
|
|
|
/**
|
|
* Utility function for retrieving the text value of an array of DOM nodes
|
|
* @param {Array|Element} elem
|
|
*/
|
|
getText = Sizzle.getText = function( elem ) {
|
|
var node,
|
|
ret = "",
|
|
i = 0,
|
|
nodeType = elem.nodeType;
|
|
|
|
if ( !nodeType ) {
|
|
// If no nodeType, this is expected to be an array
|
|
while ( (node = elem[i++]) ) {
|
|
// Do not traverse comment nodes
|
|
ret += getText( node );
|
|
}
|
|
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
|
|
// Use textContent for elements
|
|
// innerText usage removed for consistency of new lines (jQuery #11153)
|
|
if ( typeof elem.textContent === "string" ) {
|
|
return elem.textContent;
|
|
} else {
|
|
// Traverse its children
|
|
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
|
ret += getText( elem );
|
|
}
|
|
}
|
|
} else if ( nodeType === 3 || nodeType === 4 ) {
|
|
return elem.nodeValue;
|
|
}
|
|
// Do not include comment or processing instruction nodes
|
|
|
|
return ret;
|
|
};
|
|
|
|
Expr = Sizzle.selectors = {
|
|
|
|
// Can be adjusted by the user
|
|
cacheLength: 50,
|
|
|
|
createPseudo: markFunction,
|
|
|
|
match: matchExpr,
|
|
|
|
attrHandle: {},
|
|
|
|
find: {},
|
|
|
|
relative: {
|
|
">": { dir: "parentNode", first: true },
|
|
" ": { dir: "parentNode" },
|
|
"+": { dir: "previousSibling", first: true },
|
|
"~": { dir: "previousSibling" }
|
|
},
|
|
|
|
preFilter: {
|
|
"ATTR": function( match ) {
|
|
match[1] = match[1].replace( runescape, funescape );
|
|
|
|
// Move the given value to match[3] whether quoted or unquoted
|
|
match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
|
|
|
|
if ( match[2] === "~=" ) {
|
|
match[3] = " " + match[3] + " ";
|
|
}
|
|
|
|
return match.slice( 0, 4 );
|
|
},
|
|
|
|
"CHILD": function( match ) {
|
|
/* matches from matchExpr["CHILD"]
|
|
1 type (only|nth|...)
|
|
2 what (child|of-type)
|
|
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
|
|
4 xn-component of xn+y argument ([+-]?\d*n|)
|
|
5 sign of xn-component
|
|
6 x of xn-component
|
|
7 sign of y-component
|
|
8 y of y-component
|
|
*/
|
|
match[1] = match[1].toLowerCase();
|
|
|
|
if ( match[1].slice( 0, 3 ) === "nth" ) {
|
|
// nth-* requires argument
|
|
if ( !match[3] ) {
|
|
Sizzle.error( match[0] );
|
|
}
|
|
|
|
// numeric x and y parameters for Expr.filter.CHILD
|
|
// remember that false/true cast respectively to 0/1
|
|
match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
|
|
match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
|
|
|
|
// other types prohibit arguments
|
|
} else if ( match[3] ) {
|
|
Sizzle.error( match[0] );
|
|
}
|
|
|
|
return match;
|
|
},
|
|
|
|
"PSEUDO": function( match ) {
|
|
var excess,
|
|
unquoted = !match[6] && match[2];
|
|
|
|
if ( matchExpr["CHILD"].test( match[0] ) ) {
|
|
return null;
|
|
}
|
|
|
|
// Accept quoted arguments as-is
|
|
if ( match[3] ) {
|
|
match[2] = match[4] || match[5] || "";
|
|
|
|
// Strip excess characters from unquoted arguments
|
|
} else if ( unquoted && rpseudo.test( unquoted ) &&
|
|
// Get excess from tokenize (recursively)
|
|
(excess = tokenize( unquoted, true )) &&
|
|
// advance to the next closing parenthesis
|
|
(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
|
|
|
|
// excess is a negative index
|
|
match[0] = match[0].slice( 0, excess );
|
|
match[2] = unquoted.slice( 0, excess );
|
|
}
|
|
|
|
// Return only captures needed by the pseudo filter method (type and argument)
|
|
return match.slice( 0, 3 );
|
|
}
|
|
},
|
|
|
|
filter: {
|
|
|
|
"TAG": function( nodeNameSelector ) {
|
|
var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
|
|
return nodeNameSelector === "*" ?
|
|
function() { return true; } :
|
|
function( elem ) {
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
|
|
};
|
|
},
|
|
|
|
"CLASS": function( className ) {
|
|
var pattern = classCache[ className + " " ];
|
|
|
|
return pattern ||
|
|
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
|
|
classCache( className, function( elem ) {
|
|
return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
|
|
});
|
|
},
|
|
|
|
"ATTR": function( name, operator, check ) {
|
|
return function( elem ) {
|
|
var result = Sizzle.attr( elem, name );
|
|
|
|
if ( result == null ) {
|
|
return operator === "!=";
|
|
}
|
|
if ( !operator ) {
|
|
return true;
|
|
}
|
|
|
|
result += "";
|
|
|
|
return operator === "=" ? result === check :
|
|
operator === "!=" ? result !== check :
|
|
operator === "^=" ? check && result.indexOf( check ) === 0 :
|
|
operator === "*=" ? check && result.indexOf( check ) > -1 :
|
|
operator === "$=" ? check && result.slice( -check.length ) === check :
|
|
operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
|
|
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
|
|
false;
|
|
};
|
|
},
|
|
|
|
"CHILD": function( type, what, argument, first, last ) {
|
|
var simple = type.slice( 0, 3 ) !== "nth",
|
|
forward = type.slice( -4 ) !== "last",
|
|
ofType = what === "of-type";
|
|
|
|
return first === 1 && last === 0 ?
|
|
|
|
// Shortcut for :nth-*(n)
|
|
function( elem ) {
|
|
return !!elem.parentNode;
|
|
} :
|
|
|
|
function( elem, context, xml ) {
|
|
var cache, uniqueCache, outerCache, node, nodeIndex, start,
|
|
dir = simple !== forward ? "nextSibling" : "previousSibling",
|
|
parent = elem.parentNode,
|
|
name = ofType && elem.nodeName.toLowerCase(),
|
|
useCache = !xml && !ofType,
|
|
diff = false;
|
|
|
|
if ( parent ) {
|
|
|
|
// :(first|last|only)-(child|of-type)
|
|
if ( simple ) {
|
|
while ( dir ) {
|
|
node = elem;
|
|
while ( (node = node[ dir ]) ) {
|
|
if ( ofType ?
|
|
node.nodeName.toLowerCase() === name :
|
|
node.nodeType === 1 ) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
// Reverse direction for :only-* (if we haven't yet done so)
|
|
start = dir = type === "only" && !start && "nextSibling";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
start = [ forward ? parent.firstChild : parent.lastChild ];
|
|
|
|
// non-xml :nth-child(...) stores cache data on `parent`
|
|
if ( forward && useCache ) {
|
|
|
|
// Seek `elem` from a previously-cached index
|
|
|
|
// ...in a gzip-friendly way
|
|
node = parent;
|
|
outerCache = node[ expando ] || (node[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ node.uniqueID ] ||
|
|
(outerCache[ node.uniqueID ] = {});
|
|
|
|
cache = uniqueCache[ type ] || [];
|
|
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
|
|
diff = nodeIndex && cache[ 2 ];
|
|
node = nodeIndex && parent.childNodes[ nodeIndex ];
|
|
|
|
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
|
|
|
// Fallback to seeking `elem` from the start
|
|
(diff = nodeIndex = 0) || start.pop()) ) {
|
|
|
|
// When found, cache indexes on `parent` and break
|
|
if ( node.nodeType === 1 && ++diff && node === elem ) {
|
|
uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// Use previously-cached element index if available
|
|
if ( useCache ) {
|
|
// ...in a gzip-friendly way
|
|
node = elem;
|
|
outerCache = node[ expando ] || (node[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ node.uniqueID ] ||
|
|
(outerCache[ node.uniqueID ] = {});
|
|
|
|
cache = uniqueCache[ type ] || [];
|
|
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
|
|
diff = nodeIndex;
|
|
}
|
|
|
|
// xml :nth-child(...)
|
|
// or :nth-last-child(...) or :nth(-last)?-of-type(...)
|
|
if ( diff === false ) {
|
|
// Use the same loop as above to seek `elem` from the start
|
|
while ( (node = ++nodeIndex && node && node[ dir ] ||
|
|
(diff = nodeIndex = 0) || start.pop()) ) {
|
|
|
|
if ( ( ofType ?
|
|
node.nodeName.toLowerCase() === name :
|
|
node.nodeType === 1 ) &&
|
|
++diff ) {
|
|
|
|
// Cache the index of each encountered element
|
|
if ( useCache ) {
|
|
outerCache = node[ expando ] || (node[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ node.uniqueID ] ||
|
|
(outerCache[ node.uniqueID ] = {});
|
|
|
|
uniqueCache[ type ] = [ dirruns, diff ];
|
|
}
|
|
|
|
if ( node === elem ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Incorporate the offset, then check against cycle size
|
|
diff -= last;
|
|
return diff === first || ( diff % first === 0 && diff / first >= 0 );
|
|
}
|
|
};
|
|
},
|
|
|
|
"PSEUDO": function( pseudo, argument ) {
|
|
// pseudo-class names are case-insensitive
|
|
// http://www.w3.org/TR/selectors/#pseudo-classes
|
|
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
|
|
// Remember that setFilters inherits from pseudos
|
|
var args,
|
|
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
|
|
Sizzle.error( "unsupported pseudo: " + pseudo );
|
|
|
|
// The user may use createPseudo to indicate that
|
|
// arguments are needed to create the filter function
|
|
// just as Sizzle does
|
|
if ( fn[ expando ] ) {
|
|
return fn( argument );
|
|
}
|
|
|
|
// But maintain support for old signatures
|
|
if ( fn.length > 1 ) {
|
|
args = [ pseudo, pseudo, "", argument ];
|
|
return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
|
|
markFunction(function( seed, matches ) {
|
|
var idx,
|
|
matched = fn( seed, argument ),
|
|
i = matched.length;
|
|
while ( i-- ) {
|
|
idx = indexOf( seed, matched[i] );
|
|
seed[ idx ] = !( matches[ idx ] = matched[i] );
|
|
}
|
|
}) :
|
|
function( elem ) {
|
|
return fn( elem, 0, args );
|
|
};
|
|
}
|
|
|
|
return fn;
|
|
}
|
|
},
|
|
|
|
pseudos: {
|
|
// Potentially complex pseudos
|
|
"not": markFunction(function( selector ) {
|
|
// Trim the selector passed to compile
|
|
// to avoid treating leading and trailing
|
|
// spaces as combinators
|
|
var input = [],
|
|
results = [],
|
|
matcher = compile( selector.replace( rtrim, "$1" ) );
|
|
|
|
return matcher[ expando ] ?
|
|
markFunction(function( seed, matches, context, xml ) {
|
|
var elem,
|
|
unmatched = matcher( seed, null, xml, [] ),
|
|
i = seed.length;
|
|
|
|
// Match elements unmatched by `matcher`
|
|
while ( i-- ) {
|
|
if ( (elem = unmatched[i]) ) {
|
|
seed[i] = !(matches[i] = elem);
|
|
}
|
|
}
|
|
}) :
|
|
function( elem, context, xml ) {
|
|
input[0] = elem;
|
|
matcher( input, null, xml, results );
|
|
// Don't keep the element (issue #299)
|
|
input[0] = null;
|
|
return !results.pop();
|
|
};
|
|
}),
|
|
|
|
"has": markFunction(function( selector ) {
|
|
return function( elem ) {
|
|
return Sizzle( selector, elem ).length > 0;
|
|
};
|
|
}),
|
|
|
|
"contains": markFunction(function( text ) {
|
|
text = text.replace( runescape, funescape );
|
|
return function( elem ) {
|
|
return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
|
|
};
|
|
}),
|
|
|
|
// "Whether an element is represented by a :lang() selector
|
|
// is based solely on the element's language value
|
|
// being equal to the identifier C,
|
|
// or beginning with the identifier C immediately followed by "-".
|
|
// The matching of C against the element's language value is performed case-insensitively.
|
|
// The identifier C does not have to be a valid language name."
|
|
// http://www.w3.org/TR/selectors/#lang-pseudo
|
|
"lang": markFunction( function( lang ) {
|
|
// lang value must be a valid identifier
|
|
if ( !ridentifier.test(lang || "") ) {
|
|
Sizzle.error( "unsupported lang: " + lang );
|
|
}
|
|
lang = lang.replace( runescape, funescape ).toLowerCase();
|
|
return function( elem ) {
|
|
var elemLang;
|
|
do {
|
|
if ( (elemLang = documentIsHTML ?
|
|
elem.lang :
|
|
elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
|
|
|
|
elemLang = elemLang.toLowerCase();
|
|
return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
|
|
}
|
|
} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
|
|
return false;
|
|
};
|
|
}),
|
|
|
|
// Miscellaneous
|
|
"target": function( elem ) {
|
|
var hash = window.location && window.location.hash;
|
|
return hash && hash.slice( 1 ) === elem.id;
|
|
},
|
|
|
|
"root": function( elem ) {
|
|
return elem === docElem;
|
|
},
|
|
|
|
"focus": function( elem ) {
|
|
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
|
|
},
|
|
|
|
// Boolean properties
|
|
"enabled": createDisabledPseudo( false ),
|
|
"disabled": createDisabledPseudo( true ),
|
|
|
|
"checked": function( elem ) {
|
|
// In CSS3, :checked should return both checked and selected elements
|
|
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
|
|
var nodeName = elem.nodeName.toLowerCase();
|
|
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
|
|
},
|
|
|
|
"selected": function( elem ) {
|
|
// Accessing this property makes selected-by-default
|
|
// options in Safari work properly
|
|
if ( elem.parentNode ) {
|
|
elem.parentNode.selectedIndex;
|
|
}
|
|
|
|
return elem.selected === true;
|
|
},
|
|
|
|
// Contents
|
|
"empty": function( elem ) {
|
|
// http://www.w3.org/TR/selectors/#empty-pseudo
|
|
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
|
|
// but not by others (comment: 8; processing instruction: 7; etc.)
|
|
// nodeType < 6 works because attributes (2) do not appear as children
|
|
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
|
if ( elem.nodeType < 6 ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
"parent": function( elem ) {
|
|
return !Expr.pseudos["empty"]( elem );
|
|
},
|
|
|
|
// Element/input types
|
|
"header": function( elem ) {
|
|
return rheader.test( elem.nodeName );
|
|
},
|
|
|
|
"input": function( elem ) {
|
|
return rinputs.test( elem.nodeName );
|
|
},
|
|
|
|
"button": function( elem ) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === "input" && elem.type === "button" || name === "button";
|
|
},
|
|
|
|
"text": function( elem ) {
|
|
var attr;
|
|
return elem.nodeName.toLowerCase() === "input" &&
|
|
elem.type === "text" &&
|
|
|
|
// Support: IE<8
|
|
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
|
|
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
|
|
},
|
|
|
|
// Position-in-collection
|
|
"first": createPositionalPseudo(function() {
|
|
return [ 0 ];
|
|
}),
|
|
|
|
"last": createPositionalPseudo(function( matchIndexes, length ) {
|
|
return [ length - 1 ];
|
|
}),
|
|
|
|
"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
return [ argument < 0 ? argument + length : argument ];
|
|
}),
|
|
|
|
"even": createPositionalPseudo(function( matchIndexes, length ) {
|
|
var i = 0;
|
|
for ( ; i < length; i += 2 ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"odd": createPositionalPseudo(function( matchIndexes, length ) {
|
|
var i = 1;
|
|
for ( ; i < length; i += 2 ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
var i = argument < 0 ?
|
|
argument + length :
|
|
argument > length ?
|
|
length :
|
|
argument;
|
|
for ( ; --i >= 0; ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
|
|
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for ( ; ++i < length; ) {
|
|
matchIndexes.push( i );
|
|
}
|
|
return matchIndexes;
|
|
})
|
|
}
|
|
};
|
|
|
|
Expr.pseudos["nth"] = Expr.pseudos["eq"];
|
|
|
|
// Add button/input type pseudos
|
|
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
|
|
Expr.pseudos[ i ] = createInputPseudo( i );
|
|
}
|
|
for ( i in { submit: true, reset: true } ) {
|
|
Expr.pseudos[ i ] = createButtonPseudo( i );
|
|
}
|
|
|
|
// Easy API for creating new setFilters
|
|
function setFilters() {}
|
|
setFilters.prototype = Expr.filters = Expr.pseudos;
|
|
Expr.setFilters = new setFilters();
|
|
|
|
tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
|
|
var matched, match, tokens, type,
|
|
soFar, groups, preFilters,
|
|
cached = tokenCache[ selector + " " ];
|
|
|
|
if ( cached ) {
|
|
return parseOnly ? 0 : cached.slice( 0 );
|
|
}
|
|
|
|
soFar = selector;
|
|
groups = [];
|
|
preFilters = Expr.preFilter;
|
|
|
|
while ( soFar ) {
|
|
|
|
// Comma and first run
|
|
if ( !matched || (match = rcomma.exec( soFar )) ) {
|
|
if ( match ) {
|
|
// Don't consume trailing commas as valid
|
|
soFar = soFar.slice( match[0].length ) || soFar;
|
|
}
|
|
groups.push( (tokens = []) );
|
|
}
|
|
|
|
matched = false;
|
|
|
|
// Combinators
|
|
if ( (match = rcombinators.exec( soFar )) ) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
// Cast descendant combinators to space
|
|
type: match[0].replace( rtrim, " " )
|
|
});
|
|
soFar = soFar.slice( matched.length );
|
|
}
|
|
|
|
// Filters
|
|
for ( type in Expr.filter ) {
|
|
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
|
|
(match = preFilters[ type ]( match ))) ) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
type: type,
|
|
matches: match
|
|
});
|
|
soFar = soFar.slice( matched.length );
|
|
}
|
|
}
|
|
|
|
if ( !matched ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return the length of the invalid excess
|
|
// if we're just parsing
|
|
// Otherwise, throw an error or return tokens
|
|
return parseOnly ?
|
|
soFar.length :
|
|
soFar ?
|
|
Sizzle.error( selector ) :
|
|
// Cache the tokens
|
|
tokenCache( selector, groups ).slice( 0 );
|
|
};
|
|
|
|
function toSelector( tokens ) {
|
|
var i = 0,
|
|
len = tokens.length,
|
|
selector = "";
|
|
for ( ; i < len; i++ ) {
|
|
selector += tokens[i].value;
|
|
}
|
|
return selector;
|
|
}
|
|
|
|
function addCombinator( matcher, combinator, base ) {
|
|
var dir = combinator.dir,
|
|
skip = combinator.next,
|
|
key = skip || dir,
|
|
checkNonElements = base && key === "parentNode",
|
|
doneName = done++;
|
|
|
|
return combinator.first ?
|
|
// Check against closest ancestor/preceding element
|
|
function( elem, context, xml ) {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
return matcher( elem, context, xml );
|
|
}
|
|
}
|
|
return false;
|
|
} :
|
|
|
|
// Check against all ancestor/preceding elements
|
|
function( elem, context, xml ) {
|
|
var oldCache, uniqueCache, outerCache,
|
|
newCache = [ dirruns, doneName ];
|
|
|
|
// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
|
|
if ( xml ) {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
if ( matcher( elem, context, xml ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
while ( (elem = elem[ dir ]) ) {
|
|
if ( elem.nodeType === 1 || checkNonElements ) {
|
|
outerCache = elem[ expando ] || (elem[ expando ] = {});
|
|
|
|
// Support: IE <9 only
|
|
// Defend against cloned attroperties (jQuery gh-1709)
|
|
uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
|
|
|
|
if ( skip && skip === elem.nodeName.toLowerCase() ) {
|
|
elem = elem[ dir ] || elem;
|
|
} else if ( (oldCache = uniqueCache[ key ]) &&
|
|
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
|
|
|
|
// Assign to newCache so results back-propagate to previous elements
|
|
return (newCache[ 2 ] = oldCache[ 2 ]);
|
|
} else {
|
|
// Reuse newcache so results back-propagate to previous elements
|
|
uniqueCache[ key ] = newCache;
|
|
|
|
// A match means we're done; a fail means we have to keep checking
|
|
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
|
|
function elementMatcher( matchers ) {
|
|
return matchers.length > 1 ?
|
|
function( elem, context, xml ) {
|
|
var i = matchers.length;
|
|
while ( i-- ) {
|
|
if ( !matchers[i]( elem, context, xml ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} :
|
|
matchers[0];
|
|
}
|
|
|
|
function multipleContexts( selector, contexts, results ) {
|
|
var i = 0,
|
|
len = contexts.length;
|
|
for ( ; i < len; i++ ) {
|
|
Sizzle( selector, contexts[i], results );
|
|
}
|
|
return results;
|
|
}
|
|
|
|
function condense( unmatched, map, filter, context, xml ) {
|
|
var elem,
|
|
newUnmatched = [],
|
|
i = 0,
|
|
len = unmatched.length,
|
|
mapped = map != null;
|
|
|
|
for ( ; i < len; i++ ) {
|
|
if ( (elem = unmatched[i]) ) {
|
|
if ( !filter || filter( elem, context, xml ) ) {
|
|
newUnmatched.push( elem );
|
|
if ( mapped ) {
|
|
map.push( i );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return newUnmatched;
|
|
}
|
|
|
|
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
|
|
if ( postFilter && !postFilter[ expando ] ) {
|
|
postFilter = setMatcher( postFilter );
|
|
}
|
|
if ( postFinder && !postFinder[ expando ] ) {
|
|
postFinder = setMatcher( postFinder, postSelector );
|
|
}
|
|
return markFunction(function( seed, results, context, xml ) {
|
|
var temp, i, elem,
|
|
preMap = [],
|
|
postMap = [],
|
|
preexisting = results.length,
|
|
|
|
// Get initial elements from seed or context
|
|
elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
|
|
|
|
// Prefilter to get matcher input, preserving a map for seed-results synchronization
|
|
matcherIn = preFilter && ( seed || !selector ) ?
|
|
condense( elems, preMap, preFilter, context, xml ) :
|
|
elems,
|
|
|
|
matcherOut = matcher ?
|
|
// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
|
|
postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
|
|
|
|
// ...intermediate processing is necessary
|
|
[] :
|
|
|
|
// ...otherwise use results directly
|
|
results :
|
|
matcherIn;
|
|
|
|
// Find primary matches
|
|
if ( matcher ) {
|
|
matcher( matcherIn, matcherOut, context, xml );
|
|
}
|
|
|
|
// Apply postFilter
|
|
if ( postFilter ) {
|
|
temp = condense( matcherOut, postMap );
|
|
postFilter( temp, [], context, xml );
|
|
|
|
// Un-match failing elements by moving them back to matcherIn
|
|
i = temp.length;
|
|
while ( i-- ) {
|
|
if ( (elem = temp[i]) ) {
|
|
matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( seed ) {
|
|
if ( postFinder || preFilter ) {
|
|
if ( postFinder ) {
|
|
// Get the final matcherOut by condensing this intermediate into postFinder contexts
|
|
temp = [];
|
|
i = matcherOut.length;
|
|
while ( i-- ) {
|
|
if ( (elem = matcherOut[i]) ) {
|
|
// Restore matcherIn since elem is not yet a final match
|
|
temp.push( (matcherIn[i] = elem) );
|
|
}
|
|
}
|
|
postFinder( null, (matcherOut = []), temp, xml );
|
|
}
|
|
|
|
// Move matched elements from seed to results to keep them synchronized
|
|
i = matcherOut.length;
|
|
while ( i-- ) {
|
|
if ( (elem = matcherOut[i]) &&
|
|
(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
|
|
|
|
seed[temp] = !(results[temp] = elem);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add elements to results, through postFinder if defined
|
|
} else {
|
|
matcherOut = condense(
|
|
matcherOut === results ?
|
|
matcherOut.splice( preexisting, matcherOut.length ) :
|
|
matcherOut
|
|
);
|
|
if ( postFinder ) {
|
|
postFinder( null, results, matcherOut, xml );
|
|
} else {
|
|
push.apply( results, matcherOut );
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function matcherFromTokens( tokens ) {
|
|
var checkContext, matcher, j,
|
|
len = tokens.length,
|
|
leadingRelative = Expr.relative[ tokens[0].type ],
|
|
implicitRelative = leadingRelative || Expr.relative[" "],
|
|
i = leadingRelative ? 1 : 0,
|
|
|
|
// The foundational matcher ensures that elements are reachable from top-level context(s)
|
|
matchContext = addCombinator( function( elem ) {
|
|
return elem === checkContext;
|
|
}, implicitRelative, true ),
|
|
matchAnyContext = addCombinator( function( elem ) {
|
|
return indexOf( checkContext, elem ) > -1;
|
|
}, implicitRelative, true ),
|
|
matchers = [ function( elem, context, xml ) {
|
|
var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
|
|
(checkContext = context).nodeType ?
|
|
matchContext( elem, context, xml ) :
|
|
matchAnyContext( elem, context, xml ) );
|
|
// Avoid hanging onto element (issue #299)
|
|
checkContext = null;
|
|
return ret;
|
|
} ];
|
|
|
|
for ( ; i < len; i++ ) {
|
|
if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
|
|
matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
|
|
} else {
|
|
matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
|
|
|
|
// Return special upon seeing a positional matcher
|
|
if ( matcher[ expando ] ) {
|
|
// Find the next relative operator (if any) for proper handling
|
|
j = ++i;
|
|
for ( ; j < len; j++ ) {
|
|
if ( Expr.relative[ tokens[j].type ] ) {
|
|
break;
|
|
}
|
|
}
|
|
return setMatcher(
|
|
i > 1 && elementMatcher( matchers ),
|
|
i > 1 && toSelector(
|
|
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
|
|
tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
|
|
).replace( rtrim, "$1" ),
|
|
matcher,
|
|
i < j && matcherFromTokens( tokens.slice( i, j ) ),
|
|
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
|
|
j < len && toSelector( tokens )
|
|
);
|
|
}
|
|
matchers.push( matcher );
|
|
}
|
|
}
|
|
|
|
return elementMatcher( matchers );
|
|
}
|
|
|
|
function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
|
|
var bySet = setMatchers.length > 0,
|
|
byElement = elementMatchers.length > 0,
|
|
superMatcher = function( seed, context, xml, results, outermost ) {
|
|
var elem, j, matcher,
|
|
matchedCount = 0,
|
|
i = "0",
|
|
unmatched = seed && [],
|
|
setMatched = [],
|
|
contextBackup = outermostContext,
|
|
// We must always have either seed elements or outermost context
|
|
elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
|
|
// Use integer dirruns iff this is the outermost matcher
|
|
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
|
|
len = elems.length;
|
|
|
|
if ( outermost ) {
|
|
outermostContext = context === document || context || outermost;
|
|
}
|
|
|
|
// Add elements passing elementMatchers directly to results
|
|
// Support: IE<9, Safari
|
|
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
|
|
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
|
|
if ( byElement && elem ) {
|
|
j = 0;
|
|
if ( !context && elem.ownerDocument !== document ) {
|
|
setDocument( elem );
|
|
xml = !documentIsHTML;
|
|
}
|
|
while ( (matcher = elementMatchers[j++]) ) {
|
|
if ( matcher( elem, context || document, xml) ) {
|
|
results.push( elem );
|
|
break;
|
|
}
|
|
}
|
|
if ( outermost ) {
|
|
dirruns = dirrunsUnique;
|
|
}
|
|
}
|
|
|
|
// Track unmatched elements for set filters
|
|
if ( bySet ) {
|
|
// They will have gone through all possible matchers
|
|
if ( (elem = !matcher && elem) ) {
|
|
matchedCount--;
|
|
}
|
|
|
|
// Lengthen the array for every element, matched or not
|
|
if ( seed ) {
|
|
unmatched.push( elem );
|
|
}
|
|
}
|
|
}
|
|
|
|
// `i` is now the count of elements visited above, and adding it to `matchedCount`
|
|
// makes the latter nonnegative.
|
|
matchedCount += i;
|
|
|
|
// Apply set filters to unmatched elements
|
|
// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
|
|
// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
|
|
// no element matchers and no seed.
|
|
// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
|
|
// case, which will result in a "00" `matchedCount` that differs from `i` but is also
|
|
// numerically zero.
|
|
if ( bySet && i !== matchedCount ) {
|
|
j = 0;
|
|
while ( (matcher = setMatchers[j++]) ) {
|
|
matcher( unmatched, setMatched, context, xml );
|
|
}
|
|
|
|
if ( seed ) {
|
|
// Reintegrate element matches to eliminate the need for sorting
|
|
if ( matchedCount > 0 ) {
|
|
while ( i-- ) {
|
|
if ( !(unmatched[i] || setMatched[i]) ) {
|
|
setMatched[i] = pop.call( results );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Discard index placeholder values to get only actual matches
|
|
setMatched = condense( setMatched );
|
|
}
|
|
|
|
// Add matches to results
|
|
push.apply( results, setMatched );
|
|
|
|
// Seedless set matches succeeding multiple successful matchers stipulate sorting
|
|
if ( outermost && !seed && setMatched.length > 0 &&
|
|
( matchedCount + setMatchers.length ) > 1 ) {
|
|
|
|
Sizzle.uniqueSort( results );
|
|
}
|
|
}
|
|
|
|
// Override manipulation of globals by nested matchers
|
|
if ( outermost ) {
|
|
dirruns = dirrunsUnique;
|
|
outermostContext = contextBackup;
|
|
}
|
|
|
|
return unmatched;
|
|
};
|
|
|
|
return bySet ?
|
|
markFunction( superMatcher ) :
|
|
superMatcher;
|
|
}
|
|
|
|
compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
|
|
var i,
|
|
setMatchers = [],
|
|
elementMatchers = [],
|
|
cached = compilerCache[ selector + " " ];
|
|
|
|
if ( !cached ) {
|
|
// Generate a function of recursive functions that can be used to check each element
|
|
if ( !match ) {
|
|
match = tokenize( selector );
|
|
}
|
|
i = match.length;
|
|
while ( i-- ) {
|
|
cached = matcherFromTokens( match[i] );
|
|
if ( cached[ expando ] ) {
|
|
setMatchers.push( cached );
|
|
} else {
|
|
elementMatchers.push( cached );
|
|
}
|
|
}
|
|
|
|
// Cache the compiled function
|
|
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
|
|
|
|
// Save selector and tokenization
|
|
cached.selector = selector;
|
|
}
|
|
return cached;
|
|
};
|
|
|
|
/**
|
|
* A low-level selection function that works with Sizzle's compiled
|
|
* selector functions
|
|
* @param {String|Function} selector A selector or a pre-compiled
|
|
* selector function built with Sizzle.compile
|
|
* @param {Element} context
|
|
* @param {Array} [results]
|
|
* @param {Array} [seed] A set of elements to match against
|
|
*/
|
|
select = Sizzle.select = function( selector, context, results, seed ) {
|
|
var i, tokens, token, type, find,
|
|
compiled = typeof selector === "function" && selector,
|
|
match = !seed && tokenize( (selector = compiled.selector || selector) );
|
|
|
|
results = results || [];
|
|
|
|
// Try to minimize operations if there is only one selector in the list and no seed
|
|
// (the latter of which guarantees us context)
|
|
if ( match.length === 1 ) {
|
|
|
|
// Reduce context if the leading compound selector is an ID
|
|
tokens = match[0] = match[0].slice( 0 );
|
|
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
|
|
context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
|
|
|
|
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
|
|
if ( !context ) {
|
|
return results;
|
|
|
|
// Precompiled matchers will still verify ancestry, so step up a level
|
|
} else if ( compiled ) {
|
|
context = context.parentNode;
|
|
}
|
|
|
|
selector = selector.slice( tokens.shift().value.length );
|
|
}
|
|
|
|
// Fetch a seed set for right-to-left matching
|
|
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
|
|
while ( i-- ) {
|
|
token = tokens[i];
|
|
|
|
// Abort if we hit a combinator
|
|
if ( Expr.relative[ (type = token.type) ] ) {
|
|
break;
|
|
}
|
|
if ( (find = Expr.find[ type ]) ) {
|
|
// Search, expanding context for leading sibling combinators
|
|
if ( (seed = find(
|
|
token.matches[0].replace( runescape, funescape ),
|
|
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
|
|
)) ) {
|
|
|
|
// If seed is empty or no tokens remain, we can return early
|
|
tokens.splice( i, 1 );
|
|
selector = seed.length && toSelector( tokens );
|
|
if ( !selector ) {
|
|
push.apply( results, seed );
|
|
return results;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compile and execute a filtering function if one is not provided
|
|
// Provide `match` to avoid retokenization if we modified the selector above
|
|
( compiled || compile( selector, match ) )(
|
|
seed,
|
|
context,
|
|
!documentIsHTML,
|
|
results,
|
|
!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
|
|
);
|
|
return results;
|
|
};
|
|
|
|
// One-time assignments
|
|
|
|
// Sort stability
|
|
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
|
|
|
|
// Support: Chrome 14-35+
|
|
// Always assume duplicates if they aren't passed to the comparison function
|
|
support.detectDuplicates = !!hasDuplicate;
|
|
|
|
// Initialize against the default document
|
|
setDocument();
|
|
|
|
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
|
|
// Detached nodes confoundingly follow *each other*
|
|
support.sortDetached = assert(function( el ) {
|
|
// Should return 1, but returns 4 (following)
|
|
return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
|
|
});
|
|
|
|
// Support: IE<8
|
|
// Prevent attribute/property "interpolation"
|
|
// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
|
|
if ( !assert(function( el ) {
|
|
el.innerHTML = "<a href='#'></a>";
|
|
return el.firstChild.getAttribute("href") === "#" ;
|
|
}) ) {
|
|
addHandle( "type|href|height|width", function( elem, name, isXML ) {
|
|
if ( !isXML ) {
|
|
return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
|
|
}
|
|
});
|
|
}
|
|
|
|
// Support: IE<9
|
|
// Use defaultValue in place of getAttribute("value")
|
|
if ( !support.attributes || !assert(function( el ) {
|
|
el.innerHTML = "<input/>";
|
|
el.firstChild.setAttribute( "value", "" );
|
|
return el.firstChild.getAttribute( "value" ) === "";
|
|
}) ) {
|
|
addHandle( "value", function( elem, name, isXML ) {
|
|
if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
|
|
return elem.defaultValue;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Support: IE<9
|
|
// Use getAttributeNode to fetch booleans when getAttribute lies
|
|
if ( !assert(function( el ) {
|
|
return el.getAttribute("disabled") == null;
|
|
}) ) {
|
|
addHandle( booleans, function( elem, name, isXML ) {
|
|
var val;
|
|
if ( !isXML ) {
|
|
return elem[ name ] === true ? name.toLowerCase() :
|
|
(val = elem.getAttributeNode( name )) && val.specified ?
|
|
val.value :
|
|
null;
|
|
}
|
|
});
|
|
}
|
|
|
|
return Sizzle;
|
|
|
|
})( window );
|
|
|
|
|
|
|
|
jQuery.find = Sizzle;
|
|
jQuery.expr = Sizzle.selectors;
|
|
|
|
// Deprecated
|
|
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
|
|
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
|
|
jQuery.text = Sizzle.getText;
|
|
jQuery.isXMLDoc = Sizzle.isXML;
|
|
jQuery.contains = Sizzle.contains;
|
|
jQuery.escapeSelector = Sizzle.escape;
|
|
|
|
|
|
|
|
|
|
var dir = function( elem, dir, until ) {
|
|
var matched = [],
|
|
truncate = until !== undefined;
|
|
|
|
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
if ( truncate && jQuery( elem ).is( until ) ) {
|
|
break;
|
|
}
|
|
matched.push( elem );
|
|
}
|
|
}
|
|
return matched;
|
|
};
|
|
|
|
|
|
var siblings = function( n, elem ) {
|
|
var matched = [];
|
|
|
|
for ( ; n; n = n.nextSibling ) {
|
|
if ( n.nodeType === 1 && n !== elem ) {
|
|
matched.push( n );
|
|
}
|
|
}
|
|
|
|
return matched;
|
|
};
|
|
|
|
|
|
var rneedsContext = jQuery.expr.match.needsContext;
|
|
|
|
|
|
|
|
function nodeName( elem, name ) {
|
|
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
|
|
|
|
};
|
|
var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
|
|
|
|
|
|
|
|
// Implement the identical functionality for filter and not
|
|
function winnow( elements, qualifier, not ) {
|
|
if ( isFunction( qualifier ) ) {
|
|
return jQuery.grep( elements, function( elem, i ) {
|
|
return !!qualifier.call( elem, i, elem ) !== not;
|
|
} );
|
|
}
|
|
|
|
// Single element
|
|
if ( qualifier.nodeType ) {
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( elem === qualifier ) !== not;
|
|
} );
|
|
}
|
|
|
|
// Arraylike of elements (jQuery, arguments, Array)
|
|
if ( typeof qualifier !== "string" ) {
|
|
return jQuery.grep( elements, function( elem ) {
|
|
return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
|
|
} );
|
|
}
|
|
|
|
// Filtered directly for both simple and complex selectors
|
|
return jQuery.filter( qualifier, elements, not );
|
|
}
|
|
|
|
jQuery.filter = function( expr, elems, not ) {
|
|
var elem = elems[ 0 ];
|
|
|
|
if ( not ) {
|
|
expr = ":not(" + expr + ")";
|
|
}
|
|
|
|
if ( elems.length === 1 && elem.nodeType === 1 ) {
|
|
return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
|
|
}
|
|
|
|
return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
|
|
return elem.nodeType === 1;
|
|
} ) );
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
find: function( selector ) {
|
|
var i, ret,
|
|
len = this.length,
|
|
self = this;
|
|
|
|
if ( typeof selector !== "string" ) {
|
|
return this.pushStack( jQuery( selector ).filter( function() {
|
|
for ( i = 0; i < len; i++ ) {
|
|
if ( jQuery.contains( self[ i ], this ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
} ) );
|
|
}
|
|
|
|
ret = this.pushStack( [] );
|
|
|
|
for ( i = 0; i < len; i++ ) {
|
|
jQuery.find( selector, self[ i ], ret );
|
|
}
|
|
|
|
return len > 1 ? jQuery.uniqueSort( ret ) : ret;
|
|
},
|
|
filter: function( selector ) {
|
|
return this.pushStack( winnow( this, selector || [], false ) );
|
|
},
|
|
not: function( selector ) {
|
|
return this.pushStack( winnow( this, selector || [], true ) );
|
|
},
|
|
is: function( selector ) {
|
|
return !!winnow(
|
|
this,
|
|
|
|
// If this is a positional/relative selector, check membership in the returned set
|
|
// so $("p:first").is("p:last") won't return true for a doc with two "p".
|
|
typeof selector === "string" && rneedsContext.test( selector ) ?
|
|
jQuery( selector ) :
|
|
selector || [],
|
|
false
|
|
).length;
|
|
}
|
|
} );
|
|
|
|
|
|
// Initialize a jQuery object
|
|
|
|
|
|
// A central reference to the root jQuery(document)
|
|
var rootjQuery,
|
|
|
|
// A simple way to check for HTML strings
|
|
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
|
|
// Strict HTML recognition (#11290: must start with <)
|
|
// Shortcut simple #id case for speed
|
|
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
|
|
|
|
init = jQuery.fn.init = function( selector, context, root ) {
|
|
var match, elem;
|
|
|
|
// HANDLE: $(""), $(null), $(undefined), $(false)
|
|
if ( !selector ) {
|
|
return this;
|
|
}
|
|
|
|
// Method init() accepts an alternate rootjQuery
|
|
// so migrate can support jQuery.sub (gh-2101)
|
|
root = root || rootjQuery;
|
|
|
|
// Handle HTML strings
|
|
if ( typeof selector === "string" ) {
|
|
if ( selector[ 0 ] === "<" &&
|
|
selector[ selector.length - 1 ] === ">" &&
|
|
selector.length >= 3 ) {
|
|
|
|
// Assume that strings that start and end with <> are HTML and skip the regex check
|
|
match = [ null, selector, null ];
|
|
|
|
} else {
|
|
match = rquickExpr.exec( selector );
|
|
}
|
|
|
|
// Match html or make sure no context is specified for #id
|
|
if ( match && ( match[ 1 ] || !context ) ) {
|
|
|
|
// HANDLE: $(html) -> $(array)
|
|
if ( match[ 1 ] ) {
|
|
context = context instanceof jQuery ? context[ 0 ] : context;
|
|
|
|
// Option to run scripts is true for back-compat
|
|
// Intentionally let the error be thrown if parseHTML is not present
|
|
jQuery.merge( this, jQuery.parseHTML(
|
|
match[ 1 ],
|
|
context && context.nodeType ? context.ownerDocument || context : document,
|
|
true
|
|
) );
|
|
|
|
// HANDLE: $(html, props)
|
|
if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
|
|
for ( match in context ) {
|
|
|
|
// Properties of context are called as methods if possible
|
|
if ( isFunction( this[ match ] ) ) {
|
|
this[ match ]( context[ match ] );
|
|
|
|
// ...and otherwise set as attributes
|
|
} else {
|
|
this.attr( match, context[ match ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
|
|
// HANDLE: $(#id)
|
|
} else {
|
|
elem = document.getElementById( match[ 2 ] );
|
|
|
|
if ( elem ) {
|
|
|
|
// Inject the element directly into the jQuery object
|
|
this[ 0 ] = elem;
|
|
this.length = 1;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
// HANDLE: $(expr, $(...))
|
|
} else if ( !context || context.jquery ) {
|
|
return ( context || root ).find( selector );
|
|
|
|
// HANDLE: $(expr, context)
|
|
// (which is just equivalent to: $(context).find(expr)
|
|
} else {
|
|
return this.constructor( context ).find( selector );
|
|
}
|
|
|
|
// HANDLE: $(DOMElement)
|
|
} else if ( selector.nodeType ) {
|
|
this[ 0 ] = selector;
|
|
this.length = 1;
|
|
return this;
|
|
|
|
// HANDLE: $(function)
|
|
// Shortcut for document ready
|
|
} else if ( isFunction( selector ) ) {
|
|
return root.ready !== undefined ?
|
|
root.ready( selector ) :
|
|
|
|
// Execute immediately if ready is not present
|
|
selector( jQuery );
|
|
}
|
|
|
|
return jQuery.makeArray( selector, this );
|
|
};
|
|
|
|
// Give the init function the jQuery prototype for later instantiation
|
|
init.prototype = jQuery.fn;
|
|
|
|
// Initialize central reference
|
|
rootjQuery = jQuery( document );
|
|
|
|
|
|
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
|
|
|
|
// Methods guaranteed to produce a unique set when starting from a unique set
|
|
guaranteedUnique = {
|
|
children: true,
|
|
contents: true,
|
|
next: true,
|
|
prev: true
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
has: function( target ) {
|
|
var targets = jQuery( target, this ),
|
|
l = targets.length;
|
|
|
|
return this.filter( function() {
|
|
var i = 0;
|
|
for ( ; i < l; i++ ) {
|
|
if ( jQuery.contains( this, targets[ i ] ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
} );
|
|
},
|
|
|
|
closest: function( selectors, context ) {
|
|
var cur,
|
|
i = 0,
|
|
l = this.length,
|
|
matched = [],
|
|
targets = typeof selectors !== "string" && jQuery( selectors );
|
|
|
|
// Positional selectors never match, since there's no _selection_ context
|
|
if ( !rneedsContext.test( selectors ) ) {
|
|
for ( ; i < l; i++ ) {
|
|
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
|
|
|
|
// Always skip document fragments
|
|
if ( cur.nodeType < 11 && ( targets ?
|
|
targets.index( cur ) > -1 :
|
|
|
|
// Don't pass non-elements to Sizzle
|
|
cur.nodeType === 1 &&
|
|
jQuery.find.matchesSelector( cur, selectors ) ) ) {
|
|
|
|
matched.push( cur );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
|
|
},
|
|
|
|
// Determine the position of an element within the set
|
|
index: function( elem ) {
|
|
|
|
// No argument, return index in parent
|
|
if ( !elem ) {
|
|
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
|
|
}
|
|
|
|
// Index in selector
|
|
if ( typeof elem === "string" ) {
|
|
return indexOf.call( jQuery( elem ), this[ 0 ] );
|
|
}
|
|
|
|
// Locate the position of the desired element
|
|
return indexOf.call( this,
|
|
|
|
// If it receives a jQuery object, the first element is used
|
|
elem.jquery ? elem[ 0 ] : elem
|
|
);
|
|
},
|
|
|
|
add: function( selector, context ) {
|
|
return this.pushStack(
|
|
jQuery.uniqueSort(
|
|
jQuery.merge( this.get(), jQuery( selector, context ) )
|
|
)
|
|
);
|
|
},
|
|
|
|
addBack: function( selector ) {
|
|
return this.add( selector == null ?
|
|
this.prevObject : this.prevObject.filter( selector )
|
|
);
|
|
}
|
|
} );
|
|
|
|
function sibling( cur, dir ) {
|
|
while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
|
|
return cur;
|
|
}
|
|
|
|
jQuery.each( {
|
|
parent: function( elem ) {
|
|
var parent = elem.parentNode;
|
|
return parent && parent.nodeType !== 11 ? parent : null;
|
|
},
|
|
parents: function( elem ) {
|
|
return dir( elem, "parentNode" );
|
|
},
|
|
parentsUntil: function( elem, i, until ) {
|
|
return dir( elem, "parentNode", until );
|
|
},
|
|
next: function( elem ) {
|
|
return sibling( elem, "nextSibling" );
|
|
},
|
|
prev: function( elem ) {
|
|
return sibling( elem, "previousSibling" );
|
|
},
|
|
nextAll: function( elem ) {
|
|
return dir( elem, "nextSibling" );
|
|
},
|
|
prevAll: function( elem ) {
|
|
return dir( elem, "previousSibling" );
|
|
},
|
|
nextUntil: function( elem, i, until ) {
|
|
return dir( elem, "nextSibling", until );
|
|
},
|
|
prevUntil: function( elem, i, until ) {
|
|
return dir( elem, "previousSibling", until );
|
|
},
|
|
siblings: function( elem ) {
|
|
return siblings( ( elem.parentNode || {} ).firstChild, elem );
|
|
},
|
|
children: function( elem ) {
|
|
return siblings( elem.firstChild );
|
|
},
|
|
contents: function( elem ) {
|
|
if ( typeof elem.contentDocument !== "undefined" ) {
|
|
return elem.contentDocument;
|
|
}
|
|
|
|
// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
|
|
// Treat the template element as a regular one in browsers that
|
|
// don't support it.
|
|
if ( nodeName( elem, "template" ) ) {
|
|
elem = elem.content || elem;
|
|
}
|
|
|
|
return jQuery.merge( [], elem.childNodes );
|
|
}
|
|
}, function( name, fn ) {
|
|
jQuery.fn[ name ] = function( until, selector ) {
|
|
var matched = jQuery.map( this, fn, until );
|
|
|
|
if ( name.slice( -5 ) !== "Until" ) {
|
|
selector = until;
|
|
}
|
|
|
|
if ( selector && typeof selector === "string" ) {
|
|
matched = jQuery.filter( selector, matched );
|
|
}
|
|
|
|
if ( this.length > 1 ) {
|
|
|
|
// Remove duplicates
|
|
if ( !guaranteedUnique[ name ] ) {
|
|
jQuery.uniqueSort( matched );
|
|
}
|
|
|
|
// Reverse order for parents* and prev-derivatives
|
|
if ( rparentsprev.test( name ) ) {
|
|
matched.reverse();
|
|
}
|
|
}
|
|
|
|
return this.pushStack( matched );
|
|
};
|
|
} );
|
|
var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
|
|
|
|
|
|
|
|
// Convert String-formatted options into Object-formatted ones
|
|
function createOptions( options ) {
|
|
var object = {};
|
|
jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
|
|
object[ flag ] = true;
|
|
} );
|
|
return object;
|
|
}
|
|
|
|
/*
|
|
* Create a callback list using the following parameters:
|
|
*
|
|
* options: an optional list of space-separated options that will change how
|
|
* the callback list behaves or a more traditional option object
|
|
*
|
|
* By default a callback list will act like an event callback list and can be
|
|
* "fired" multiple times.
|
|
*
|
|
* Possible options:
|
|
*
|
|
* once: will ensure the callback list can only be fired once (like a Deferred)
|
|
*
|
|
* memory: will keep track of previous values and will call any callback added
|
|
* after the list has been fired right away with the latest "memorized"
|
|
* values (like a Deferred)
|
|
*
|
|
* unique: will ensure a callback can only be added once (no duplicate in the list)
|
|
*
|
|
* stopOnFalse: interrupt callings when a callback returns false
|
|
*
|
|
*/
|
|
jQuery.Callbacks = function( options ) {
|
|
|
|
// Convert options from String-formatted to Object-formatted if needed
|
|
// (we check in cache first)
|
|
options = typeof options === "string" ?
|
|
createOptions( options ) :
|
|
jQuery.extend( {}, options );
|
|
|
|
var // Flag to know if list is currently firing
|
|
firing,
|
|
|
|
// Last fire value for non-forgettable lists
|
|
memory,
|
|
|
|
// Flag to know if list was already fired
|
|
fired,
|
|
|
|
// Flag to prevent firing
|
|
locked,
|
|
|
|
// Actual callback list
|
|
list = [],
|
|
|
|
// Queue of execution data for repeatable lists
|
|
queue = [],
|
|
|
|
// Index of currently firing callback (modified by add/remove as needed)
|
|
firingIndex = -1,
|
|
|
|
// Fire callbacks
|
|
fire = function() {
|
|
|
|
// Enforce single-firing
|
|
locked = locked || options.once;
|
|
|
|
// Execute callbacks for all pending executions,
|
|
// respecting firingIndex overrides and runtime changes
|
|
fired = firing = true;
|
|
for ( ; queue.length; firingIndex = -1 ) {
|
|
memory = queue.shift();
|
|
while ( ++firingIndex < list.length ) {
|
|
|
|
// Run callback and check for early termination
|
|
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
|
|
options.stopOnFalse ) {
|
|
|
|
// Jump to end and forget the data so .add doesn't re-fire
|
|
firingIndex = list.length;
|
|
memory = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Forget the data if we're done with it
|
|
if ( !options.memory ) {
|
|
memory = false;
|
|
}
|
|
|
|
firing = false;
|
|
|
|
// Clean up if we're done firing for good
|
|
if ( locked ) {
|
|
|
|
// Keep an empty list if we have data for future add calls
|
|
if ( memory ) {
|
|
list = [];
|
|
|
|
// Otherwise, this object is spent
|
|
} else {
|
|
list = "";
|
|
}
|
|
}
|
|
},
|
|
|
|
// Actual Callbacks object
|
|
self = {
|
|
|
|
// Add a callback or a collection of callbacks to the list
|
|
add: function() {
|
|
if ( list ) {
|
|
|
|
// If we have memory from a past run, we should fire after adding
|
|
if ( memory && !firing ) {
|
|
firingIndex = list.length - 1;
|
|
queue.push( memory );
|
|
}
|
|
|
|
( function add( args ) {
|
|
jQuery.each( args, function( _, arg ) {
|
|
if ( isFunction( arg ) ) {
|
|
if ( !options.unique || !self.has( arg ) ) {
|
|
list.push( arg );
|
|
}
|
|
} else if ( arg && arg.length && toType( arg ) !== "string" ) {
|
|
|
|
// Inspect recursively
|
|
add( arg );
|
|
}
|
|
} );
|
|
} )( arguments );
|
|
|
|
if ( memory && !firing ) {
|
|
fire();
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Remove a callback from the list
|
|
remove: function() {
|
|
jQuery.each( arguments, function( _, arg ) {
|
|
var index;
|
|
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
|
|
list.splice( index, 1 );
|
|
|
|
// Handle firing indexes
|
|
if ( index <= firingIndex ) {
|
|
firingIndex--;
|
|
}
|
|
}
|
|
} );
|
|
return this;
|
|
},
|
|
|
|
// Check if a given callback is in the list.
|
|
// If no argument is given, return whether or not list has callbacks attached.
|
|
has: function( fn ) {
|
|
return fn ?
|
|
jQuery.inArray( fn, list ) > -1 :
|
|
list.length > 0;
|
|
},
|
|
|
|
// Remove all callbacks from the list
|
|
empty: function() {
|
|
if ( list ) {
|
|
list = [];
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Disable .fire and .add
|
|
// Abort any current/pending executions
|
|
// Clear all callbacks and values
|
|
disable: function() {
|
|
locked = queue = [];
|
|
list = memory = "";
|
|
return this;
|
|
},
|
|
disabled: function() {
|
|
return !list;
|
|
},
|
|
|
|
// Disable .fire
|
|
// Also disable .add unless we have memory (since it would have no effect)
|
|
// Abort any pending executions
|
|
lock: function() {
|
|
locked = queue = [];
|
|
if ( !memory && !firing ) {
|
|
list = memory = "";
|
|
}
|
|
return this;
|
|
},
|
|
locked: function() {
|
|
return !!locked;
|
|
},
|
|
|
|
// Call all callbacks with the given context and arguments
|
|
fireWith: function( context, args ) {
|
|
if ( !locked ) {
|
|
args = args || [];
|
|
args = [ context, args.slice ? args.slice() : args ];
|
|
queue.push( args );
|
|
if ( !firing ) {
|
|
fire();
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Call all the callbacks with the given arguments
|
|
fire: function() {
|
|
self.fireWith( this, arguments );
|
|
return this;
|
|
},
|
|
|
|
// To know if the callbacks have already been called at least once
|
|
fired: function() {
|
|
return !!fired;
|
|
}
|
|
};
|
|
|
|
return self;
|
|
};
|
|
|
|
|
|
function Identity( v ) {
|
|
return v;
|
|
}
|
|
function Thrower( ex ) {
|
|
throw ex;
|
|
}
|
|
|
|
function adoptValue( value, resolve, reject, noValue ) {
|
|
var method;
|
|
|
|
try {
|
|
|
|
// Check for promise aspect first to privilege synchronous behavior
|
|
if ( value && isFunction( ( method = value.promise ) ) ) {
|
|
method.call( value ).done( resolve ).fail( reject );
|
|
|
|
// Other thenables
|
|
} else if ( value && isFunction( ( method = value.then ) ) ) {
|
|
method.call( value, resolve, reject );
|
|
|
|
// Other non-thenables
|
|
} else {
|
|
|
|
// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
|
|
// * false: [ value ].slice( 0 ) => resolve( value )
|
|
// * true: [ value ].slice( 1 ) => resolve()
|
|
resolve.apply( undefined, [ value ].slice( noValue ) );
|
|
}
|
|
|
|
// For Promises/A+, convert exceptions into rejections
|
|
// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
|
|
// Deferred#then to conditionally suppress rejection.
|
|
} catch ( value ) {
|
|
|
|
// Support: Android 4.0 only
|
|
// Strict mode functions invoked without .call/.apply get global-object context
|
|
reject.apply( undefined, [ value ] );
|
|
}
|
|
}
|
|
|
|
jQuery.extend( {
|
|
|
|
Deferred: function( func ) {
|
|
var tuples = [
|
|
|
|
// action, add listener, callbacks,
|
|
// ... .then handlers, argument index, [final state]
|
|
[ "notify", "progress", jQuery.Callbacks( "memory" ),
|
|
jQuery.Callbacks( "memory" ), 2 ],
|
|
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
|
|
jQuery.Callbacks( "once memory" ), 0, "resolved" ],
|
|
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
|
|
jQuery.Callbacks( "once memory" ), 1, "rejected" ]
|
|
],
|
|
state = "pending",
|
|
promise = {
|
|
state: function() {
|
|
return state;
|
|
},
|
|
always: function() {
|
|
deferred.done( arguments ).fail( arguments );
|
|
return this;
|
|
},
|
|
"catch": function( fn ) {
|
|
return promise.then( null, fn );
|
|
},
|
|
|
|
// Keep pipe for back-compat
|
|
pipe: function( /* fnDone, fnFail, fnProgress */ ) {
|
|
var fns = arguments;
|
|
|
|
return jQuery.Deferred( function( newDefer ) {
|
|
jQuery.each( tuples, function( i, tuple ) {
|
|
|
|
// Map tuples (progress, done, fail) to arguments (done, fail, progress)
|
|
var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
|
|
|
|
// deferred.progress(function() { bind to newDefer or newDefer.notify })
|
|
// deferred.done(function() { bind to newDefer or newDefer.resolve })
|
|
// deferred.fail(function() { bind to newDefer or newDefer.reject })
|
|
deferred[ tuple[ 1 ] ]( function() {
|
|
var returned = fn && fn.apply( this, arguments );
|
|
if ( returned && isFunction( returned.promise ) ) {
|
|
returned.promise()
|
|
.progress( newDefer.notify )
|
|
.done( newDefer.resolve )
|
|
.fail( newDefer.reject );
|
|
} else {
|
|
newDefer[ tuple[ 0 ] + "With" ](
|
|
this,
|
|
fn ? [ returned ] : arguments
|
|
);
|
|
}
|
|
} );
|
|
} );
|
|
fns = null;
|
|
} ).promise();
|
|
},
|
|
then: function( onFulfilled, onRejected, onProgress ) {
|
|
var maxDepth = 0;
|
|
function resolve( depth, deferred, handler, special ) {
|
|
return function() {
|
|
var that = this,
|
|
args = arguments,
|
|
mightThrow = function() {
|
|
var returned, then;
|
|
|
|
// Support: Promises/A+ section 2.3.3.3.3
|
|
// https://promisesaplus.com/#point-59
|
|
// Ignore double-resolution attempts
|
|
if ( depth < maxDepth ) {
|
|
return;
|
|
}
|
|
|
|
returned = handler.apply( that, args );
|
|
|
|
// Support: Promises/A+ section 2.3.1
|
|
// https://promisesaplus.com/#point-48
|
|
if ( returned === deferred.promise() ) {
|
|
throw new TypeError( "Thenable self-resolution" );
|
|
}
|
|
|
|
// Support: Promises/A+ sections 2.3.3.1, 3.5
|
|
// https://promisesaplus.com/#point-54
|
|
// https://promisesaplus.com/#point-75
|
|
// Retrieve `then` only once
|
|
then = returned &&
|
|
|
|
// Support: Promises/A+ section 2.3.4
|
|
// https://promisesaplus.com/#point-64
|
|
// Only check objects and functions for thenability
|
|
( typeof returned === "object" ||
|
|
typeof returned === "function" ) &&
|
|
returned.then;
|
|
|
|
// Handle a returned thenable
|
|
if ( isFunction( then ) ) {
|
|
|
|
// Special processors (notify) just wait for resolution
|
|
if ( special ) {
|
|
then.call(
|
|
returned,
|
|
resolve( maxDepth, deferred, Identity, special ),
|
|
resolve( maxDepth, deferred, Thrower, special )
|
|
);
|
|
|
|
// Normal processors (resolve) also hook into progress
|
|
} else {
|
|
|
|
// ...and disregard older resolution values
|
|
maxDepth++;
|
|
|
|
then.call(
|
|
returned,
|
|
resolve( maxDepth, deferred, Identity, special ),
|
|
resolve( maxDepth, deferred, Thrower, special ),
|
|
resolve( maxDepth, deferred, Identity,
|
|
deferred.notifyWith )
|
|
);
|
|
}
|
|
|
|
// Handle all other returned values
|
|
} else {
|
|
|
|
// Only substitute handlers pass on context
|
|
// and multiple values (non-spec behavior)
|
|
if ( handler !== Identity ) {
|
|
that = undefined;
|
|
args = [ returned ];
|
|
}
|
|
|
|
// Process the value(s)
|
|
// Default process is resolve
|
|
( special || deferred.resolveWith )( that, args );
|
|
}
|
|
},
|
|
|
|
// Only normal processors (resolve) catch and reject exceptions
|
|
process = special ?
|
|
mightThrow :
|
|
function() {
|
|
try {
|
|
mightThrow();
|
|
} catch ( e ) {
|
|
|
|
if ( jQuery.Deferred.exceptionHook ) {
|
|
jQuery.Deferred.exceptionHook( e,
|
|
process.stackTrace );
|
|
}
|
|
|
|
// Support: Promises/A+ section 2.3.3.3.4.1
|
|
// https://promisesaplus.com/#point-61
|
|
// Ignore post-resolution exceptions
|
|
if ( depth + 1 >= maxDepth ) {
|
|
|
|
// Only substitute handlers pass on context
|
|
// and multiple values (non-spec behavior)
|
|
if ( handler !== Thrower ) {
|
|
that = undefined;
|
|
args = [ e ];
|
|
}
|
|
|
|
deferred.rejectWith( that, args );
|
|
}
|
|
}
|
|
};
|
|
|
|
// Support: Promises/A+ section 2.3.3.3.1
|
|
// https://promisesaplus.com/#point-57
|
|
// Re-resolve promises immediately to dodge false rejection from
|
|
// subsequent errors
|
|
if ( depth ) {
|
|
process();
|
|
} else {
|
|
|
|
// Call an optional hook to record the stack, in case of exception
|
|
// since it's otherwise lost when execution goes async
|
|
if ( jQuery.Deferred.getStackHook ) {
|
|
process.stackTrace = jQuery.Deferred.getStackHook();
|
|
}
|
|
window.setTimeout( process );
|
|
}
|
|
};
|
|
}
|
|
|
|
return jQuery.Deferred( function( newDefer ) {
|
|
|
|
// progress_handlers.add( ... )
|
|
tuples[ 0 ][ 3 ].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
isFunction( onProgress ) ?
|
|
onProgress :
|
|
Identity,
|
|
newDefer.notifyWith
|
|
)
|
|
);
|
|
|
|
// fulfilled_handlers.add( ... )
|
|
tuples[ 1 ][ 3 ].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
isFunction( onFulfilled ) ?
|
|
onFulfilled :
|
|
Identity
|
|
)
|
|
);
|
|
|
|
// rejected_handlers.add( ... )
|
|
tuples[ 2 ][ 3 ].add(
|
|
resolve(
|
|
0,
|
|
newDefer,
|
|
isFunction( onRejected ) ?
|
|
onRejected :
|
|
Thrower
|
|
)
|
|
);
|
|
} ).promise();
|
|
},
|
|
|
|
// Get a promise for this deferred
|
|
// If obj is provided, the promise aspect is added to the object
|
|
promise: function( obj ) {
|
|
return obj != null ? jQuery.extend( obj, promise ) : promise;
|
|
}
|
|
},
|
|
deferred = {};
|
|
|
|
// Add list-specific methods
|
|
jQuery.each( tuples, function( i, tuple ) {
|
|
var list = tuple[ 2 ],
|
|
stateString = tuple[ 5 ];
|
|
|
|
// promise.progress = list.add
|
|
// promise.done = list.add
|
|
// promise.fail = list.add
|
|
promise[ tuple[ 1 ] ] = list.add;
|
|
|
|
// Handle state
|
|
if ( stateString ) {
|
|
list.add(
|
|
function() {
|
|
|
|
// state = "resolved" (i.e., fulfilled)
|
|
// state = "rejected"
|
|
state = stateString;
|
|
},
|
|
|
|
// rejected_callbacks.disable
|
|
// fulfilled_callbacks.disable
|
|
tuples[ 3 - i ][ 2 ].disable,
|
|
|
|
// rejected_handlers.disable
|
|
// fulfilled_handlers.disable
|
|
tuples[ 3 - i ][ 3 ].disable,
|
|
|
|
// progress_callbacks.lock
|
|
tuples[ 0 ][ 2 ].lock,
|
|
|
|
// progress_handlers.lock
|
|
tuples[ 0 ][ 3 ].lock
|
|
);
|
|
}
|
|
|
|
// progress_handlers.fire
|
|
// fulfilled_handlers.fire
|
|
// rejected_handlers.fire
|
|
list.add( tuple[ 3 ].fire );
|
|
|
|
// deferred.notify = function() { deferred.notifyWith(...) }
|
|
// deferred.resolve = function() { deferred.resolveWith(...) }
|
|
// deferred.reject = function() { deferred.rejectWith(...) }
|
|
deferred[ tuple[ 0 ] ] = function() {
|
|
deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
|
|
return this;
|
|
};
|
|
|
|
// deferred.notifyWith = list.fireWith
|
|
// deferred.resolveWith = list.fireWith
|
|
// deferred.rejectWith = list.fireWith
|
|
deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
|
|
} );
|
|
|
|
// Make the deferred a promise
|
|
promise.promise( deferred );
|
|
|
|
// Call given func if any
|
|
if ( func ) {
|
|
func.call( deferred, deferred );
|
|
}
|
|
|
|
// All done!
|
|
return deferred;
|
|
},
|
|
|
|
// Deferred helper
|
|
when: function( singleValue ) {
|
|
var
|
|
|
|
// count of uncompleted subordinates
|
|
remaining = arguments.length,
|
|
|
|
// count of unprocessed arguments
|
|
i = remaining,
|
|
|
|
// subordinate fulfillment data
|
|
resolveContexts = Array( i ),
|
|
resolveValues = slice.call( arguments ),
|
|
|
|
// the master Deferred
|
|
master = jQuery.Deferred(),
|
|
|
|
// subordinate callback factory
|
|
updateFunc = function( i ) {
|
|
return function( value ) {
|
|
resolveContexts[ i ] = this;
|
|
resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
|
|
if ( !( --remaining ) ) {
|
|
master.resolveWith( resolveContexts, resolveValues );
|
|
}
|
|
};
|
|
};
|
|
|
|
// Single- and empty arguments are adopted like Promise.resolve
|
|
if ( remaining <= 1 ) {
|
|
adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
|
|
!remaining );
|
|
|
|
// Use .then() to unwrap secondary thenables (cf. gh-3000)
|
|
if ( master.state() === "pending" ||
|
|
isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
|
|
|
|
return master.then();
|
|
}
|
|
}
|
|
|
|
// Multiple arguments are aggregated like Promise.all array elements
|
|
while ( i-- ) {
|
|
adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
|
|
}
|
|
|
|
return master.promise();
|
|
}
|
|
} );
|
|
|
|
|
|
// These usually indicate a programmer mistake during development,
|
|
// warn about them ASAP rather than swallowing them by default.
|
|
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
|
|
|
|
jQuery.Deferred.exceptionHook = function( error, stack ) {
|
|
|
|
// Support: IE 8 - 9 only
|
|
// Console exists when dev tools are open, which can happen at any time
|
|
if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
|
|
window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
jQuery.readyException = function( error ) {
|
|
window.setTimeout( function() {
|
|
throw error;
|
|
} );
|
|
};
|
|
|
|
|
|
|
|
|
|
// The deferred used on DOM ready
|
|
var readyList = jQuery.Deferred();
|
|
|
|
jQuery.fn.ready = function( fn ) {
|
|
|
|
readyList
|
|
.then( fn )
|
|
|
|
// Wrap jQuery.readyException in a function so that the lookup
|
|
// happens at the time of error handling instead of callback
|
|
// registration.
|
|
.catch( function( error ) {
|
|
jQuery.readyException( error );
|
|
} );
|
|
|
|
return this;
|
|
};
|
|
|
|
jQuery.extend( {
|
|
|
|
// Is the DOM ready to be used? Set to true once it occurs.
|
|
isReady: false,
|
|
|
|
// A counter to track how many items to wait for before
|
|
// the ready event fires. See #6781
|
|
readyWait: 1,
|
|
|
|
// Handle when the DOM is ready
|
|
ready: function( wait ) {
|
|
|
|
// Abort if there are pending holds or we're already ready
|
|
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
|
|
return;
|
|
}
|
|
|
|
// Remember that the DOM is ready
|
|
jQuery.isReady = true;
|
|
|
|
// If a normal DOM Ready event fired, decrement, and wait if need be
|
|
if ( wait !== true && --jQuery.readyWait > 0 ) {
|
|
return;
|
|
}
|
|
|
|
// If there are functions bound, to execute
|
|
readyList.resolveWith( document, [ jQuery ] );
|
|
}
|
|
} );
|
|
|
|
jQuery.ready.then = readyList.then;
|
|
|
|
// The ready event handler and self cleanup method
|
|
function completed() {
|
|
document.removeEventListener( "DOMContentLoaded", completed );
|
|
window.removeEventListener( "load", completed );
|
|
jQuery.ready();
|
|
}
|
|
|
|
// Catch cases where $(document).ready() is called
|
|
// after the browser event has already occurred.
|
|
// Support: IE <=9 - 10 only
|
|
// Older IE sometimes signals "interactive" too soon
|
|
if ( document.readyState === "complete" ||
|
|
( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
|
|
|
|
// Handle it asynchronously to allow scripts the opportunity to delay ready
|
|
window.setTimeout( jQuery.ready );
|
|
|
|
} else {
|
|
|
|
// Use the handy event callback
|
|
document.addEventListener( "DOMContentLoaded", completed );
|
|
|
|
// A fallback to window.onload, that will always work
|
|
window.addEventListener( "load", completed );
|
|
}
|
|
|
|
|
|
|
|
|
|
// Multifunctional method to get and set values of a collection
|
|
// The value/s can optionally be executed if it's a function
|
|
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
|
|
var i = 0,
|
|
len = elems.length,
|
|
bulk = key == null;
|
|
|
|
// Sets many values
|
|
if ( toType( key ) === "object" ) {
|
|
chainable = true;
|
|
for ( i in key ) {
|
|
access( elems, fn, i, key[ i ], true, emptyGet, raw );
|
|
}
|
|
|
|
// Sets one value
|
|
} else if ( value !== undefined ) {
|
|
chainable = true;
|
|
|
|
if ( !isFunction( value ) ) {
|
|
raw = true;
|
|
}
|
|
|
|
if ( bulk ) {
|
|
|
|
// Bulk operations run against the entire set
|
|
if ( raw ) {
|
|
fn.call( elems, value );
|
|
fn = null;
|
|
|
|
// ...except when executing function values
|
|
} else {
|
|
bulk = fn;
|
|
fn = function( elem, key, value ) {
|
|
return bulk.call( jQuery( elem ), value );
|
|
};
|
|
}
|
|
}
|
|
|
|
if ( fn ) {
|
|
for ( ; i < len; i++ ) {
|
|
fn(
|
|
elems[ i ], key, raw ?
|
|
value :
|
|
value.call( elems[ i ], i, fn( elems[ i ], key ) )
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( chainable ) {
|
|
return elems;
|
|
}
|
|
|
|
// Gets
|
|
if ( bulk ) {
|
|
return fn.call( elems );
|
|
}
|
|
|
|
return len ? fn( elems[ 0 ], key ) : emptyGet;
|
|
};
|
|
|
|
|
|
// Matches dashed string for camelizing
|
|
var rmsPrefix = /^-ms-/,
|
|
rdashAlpha = /-([a-z])/g;
|
|
|
|
// Used by camelCase as callback to replace()
|
|
function fcamelCase( all, letter ) {
|
|
return letter.toUpperCase();
|
|
}
|
|
|
|
// Convert dashed to camelCase; used by the css and data modules
|
|
// Support: IE <=9 - 11, Edge 12 - 15
|
|
// Microsoft forgot to hump their vendor prefix (#9572)
|
|
function camelCase( string ) {
|
|
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
|
|
}
|
|
var acceptData = function( owner ) {
|
|
|
|
// Accepts only:
|
|
// - Node
|
|
// - Node.ELEMENT_NODE
|
|
// - Node.DOCUMENT_NODE
|
|
// - Object
|
|
// - Any
|
|
return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
|
|
};
|
|
|
|
|
|
|
|
|
|
function Data() {
|
|
this.expando = jQuery.expando + Data.uid++;
|
|
}
|
|
|
|
Data.uid = 1;
|
|
|
|
Data.prototype = {
|
|
|
|
cache: function( owner ) {
|
|
|
|
// Check if the owner object already has a cache
|
|
var value = owner[ this.expando ];
|
|
|
|
// If not, create one
|
|
if ( !value ) {
|
|
value = {};
|
|
|
|
// We can accept data for non-element nodes in modern browsers,
|
|
// but we should not, see #8335.
|
|
// Always return an empty object.
|
|
if ( acceptData( owner ) ) {
|
|
|
|
// If it is a node unlikely to be stringify-ed or looped over
|
|
// use plain assignment
|
|
if ( owner.nodeType ) {
|
|
owner[ this.expando ] = value;
|
|
|
|
// Otherwise secure it in a non-enumerable property
|
|
// configurable must be true to allow the property to be
|
|
// deleted when data is removed
|
|
} else {
|
|
Object.defineProperty( owner, this.expando, {
|
|
value: value,
|
|
configurable: true
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
|
|
return value;
|
|
},
|
|
set: function( owner, data, value ) {
|
|
var prop,
|
|
cache = this.cache( owner );
|
|
|
|
// Handle: [ owner, key, value ] args
|
|
// Always use camelCase key (gh-2257)
|
|
if ( typeof data === "string" ) {
|
|
cache[ camelCase( data ) ] = value;
|
|
|
|
// Handle: [ owner, { properties } ] args
|
|
} else {
|
|
|
|
// Copy the properties one-by-one to the cache object
|
|
for ( prop in data ) {
|
|
cache[ camelCase( prop ) ] = data[ prop ];
|
|
}
|
|
}
|
|
return cache;
|
|
},
|
|
get: function( owner, key ) {
|
|
return key === undefined ?
|
|
this.cache( owner ) :
|
|
|
|
// Always use camelCase key (gh-2257)
|
|
owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
|
|
},
|
|
access: function( owner, key, value ) {
|
|
|
|
// In cases where either:
|
|
//
|
|
// 1. No key was specified
|
|
// 2. A string key was specified, but no value provided
|
|
//
|
|
// Take the "read" path and allow the get method to determine
|
|
// which value to return, respectively either:
|
|
//
|
|
// 1. The entire cache object
|
|
// 2. The data stored at the key
|
|
//
|
|
if ( key === undefined ||
|
|
( ( key && typeof key === "string" ) && value === undefined ) ) {
|
|
|
|
return this.get( owner, key );
|
|
}
|
|
|
|
// When the key is not a string, or both a key and value
|
|
// are specified, set or extend (existing objects) with either:
|
|
//
|
|
// 1. An object of properties
|
|
// 2. A key and value
|
|
//
|
|
this.set( owner, key, value );
|
|
|
|
// Since the "set" path can have two possible entry points
|
|
// return the expected data based on which path was taken[*]
|
|
return value !== undefined ? value : key;
|
|
},
|
|
remove: function( owner, key ) {
|
|
var i,
|
|
cache = owner[ this.expando ];
|
|
|
|
if ( cache === undefined ) {
|
|
return;
|
|
}
|
|
|
|
if ( key !== undefined ) {
|
|
|
|
// Support array or space separated string of keys
|
|
if ( Array.isArray( key ) ) {
|
|
|
|
// If key is an array of keys...
|
|
// We always set camelCase keys, so remove that.
|
|
key = key.map( camelCase );
|
|
} else {
|
|
key = camelCase( key );
|
|
|
|
// If a key with the spaces exists, use it.
|
|
// Otherwise, create an array by matching non-whitespace
|
|
key = key in cache ?
|
|
[ key ] :
|
|
( key.match( rnothtmlwhite ) || [] );
|
|
}
|
|
|
|
i = key.length;
|
|
|
|
while ( i-- ) {
|
|
delete cache[ key[ i ] ];
|
|
}
|
|
}
|
|
|
|
// Remove the expando if there's no more data
|
|
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
|
|
|
|
// Support: Chrome <=35 - 45
|
|
// Webkit & Blink performance suffers when deleting properties
|
|
// from DOM nodes, so set to undefined instead
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
|
|
if ( owner.nodeType ) {
|
|
owner[ this.expando ] = undefined;
|
|
} else {
|
|
delete owner[ this.expando ];
|
|
}
|
|
}
|
|
},
|
|
hasData: function( owner ) {
|
|
var cache = owner[ this.expando ];
|
|
return cache !== undefined && !jQuery.isEmptyObject( cache );
|
|
}
|
|
};
|
|
var dataPriv = new Data();
|
|
|
|
var dataUser = new Data();
|
|
|
|
|
|
|
|
// Implementation Summary
|
|
//
|
|
// 1. Enforce API surface and semantic compatibility with 1.9.x branch
|
|
// 2. Improve the module's maintainability by reducing the storage
|
|
// paths to a single mechanism.
|
|
// 3. Use the same single mechanism to support "private" and "user" data.
|
|
// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
|
|
// 5. Avoid exposing implementation details on user objects (eg. expando properties)
|
|
// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
|
|
|
|
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
|
|
rmultiDash = /[A-Z]/g;
|
|
|
|
function getData( data ) {
|
|
if ( data === "true" ) {
|
|
return true;
|
|
}
|
|
|
|
if ( data === "false" ) {
|
|
return false;
|
|
}
|
|
|
|
if ( data === "null" ) {
|
|
return null;
|
|
}
|
|
|
|
// Only convert to a number if it doesn't change the string
|
|
if ( data === +data + "" ) {
|
|
return +data;
|
|
}
|
|
|
|
if ( rbrace.test( data ) ) {
|
|
return JSON.parse( data );
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
function dataAttr( elem, key, data ) {
|
|
var name;
|
|
|
|
// If nothing was found internally, try to fetch any
|
|
// data from the HTML5 data-* attribute
|
|
if ( data === undefined && elem.nodeType === 1 ) {
|
|
name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
|
|
data = elem.getAttribute( name );
|
|
|
|
if ( typeof data === "string" ) {
|
|
try {
|
|
data = getData( data );
|
|
} catch ( e ) {}
|
|
|
|
// Make sure we set the data so it isn't changed later
|
|
dataUser.set( elem, key, data );
|
|
} else {
|
|
data = undefined;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
jQuery.extend( {
|
|
hasData: function( elem ) {
|
|
return dataUser.hasData( elem ) || dataPriv.hasData( elem );
|
|
},
|
|
|
|
data: function( elem, name, data ) {
|
|
return dataUser.access( elem, name, data );
|
|
},
|
|
|
|
removeData: function( elem, name ) {
|
|
dataUser.remove( elem, name );
|
|
},
|
|
|
|
// TODO: Now that all calls to _data and _removeData have been replaced
|
|
// with direct calls to dataPriv methods, these can be deprecated.
|
|
_data: function( elem, name, data ) {
|
|
return dataPriv.access( elem, name, data );
|
|
},
|
|
|
|
_removeData: function( elem, name ) {
|
|
dataPriv.remove( elem, name );
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
data: function( key, value ) {
|
|
var i, name, data,
|
|
elem = this[ 0 ],
|
|
attrs = elem && elem.attributes;
|
|
|
|
// Gets all values
|
|
if ( key === undefined ) {
|
|
if ( this.length ) {
|
|
data = dataUser.get( elem );
|
|
|
|
if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
|
|
i = attrs.length;
|
|
while ( i-- ) {
|
|
|
|
// Support: IE 11 only
|
|
// The attrs elements can be null (#14894)
|
|
if ( attrs[ i ] ) {
|
|
name = attrs[ i ].name;
|
|
if ( name.indexOf( "data-" ) === 0 ) {
|
|
name = camelCase( name.slice( 5 ) );
|
|
dataAttr( elem, name, data[ name ] );
|
|
}
|
|
}
|
|
}
|
|
dataPriv.set( elem, "hasDataAttrs", true );
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// Sets multiple values
|
|
if ( typeof key === "object" ) {
|
|
return this.each( function() {
|
|
dataUser.set( this, key );
|
|
} );
|
|
}
|
|
|
|
return access( this, function( value ) {
|
|
var data;
|
|
|
|
// The calling jQuery object (element matches) is not empty
|
|
// (and therefore has an element appears at this[ 0 ]) and the
|
|
// `value` parameter was not undefined. An empty jQuery object
|
|
// will result in `undefined` for elem = this[ 0 ] which will
|
|
// throw an exception if an attempt to read a data cache is made.
|
|
if ( elem && value === undefined ) {
|
|
|
|
// Attempt to get data from the cache
|
|
// The key will always be camelCased in Data
|
|
data = dataUser.get( elem, key );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// Attempt to "discover" the data in
|
|
// HTML5 custom data-* attrs
|
|
data = dataAttr( elem, key );
|
|
if ( data !== undefined ) {
|
|
return data;
|
|
}
|
|
|
|
// We tried really hard, but the data doesn't exist.
|
|
return;
|
|
}
|
|
|
|
// Set the data...
|
|
this.each( function() {
|
|
|
|
// We always store the camelCased key
|
|
dataUser.set( this, key, value );
|
|
} );
|
|
}, null, value, arguments.length > 1, null, true );
|
|
},
|
|
|
|
removeData: function( key ) {
|
|
return this.each( function() {
|
|
dataUser.remove( this, key );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
|
|
jQuery.extend( {
|
|
queue: function( elem, type, data ) {
|
|
var queue;
|
|
|
|
if ( elem ) {
|
|
type = ( type || "fx" ) + "queue";
|
|
queue = dataPriv.get( elem, type );
|
|
|
|
// Speed up dequeue by getting out quickly if this is just a lookup
|
|
if ( data ) {
|
|
if ( !queue || Array.isArray( data ) ) {
|
|
queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
|
|
} else {
|
|
queue.push( data );
|
|
}
|
|
}
|
|
return queue || [];
|
|
}
|
|
},
|
|
|
|
dequeue: function( elem, type ) {
|
|
type = type || "fx";
|
|
|
|
var queue = jQuery.queue( elem, type ),
|
|
startLength = queue.length,
|
|
fn = queue.shift(),
|
|
hooks = jQuery._queueHooks( elem, type ),
|
|
next = function() {
|
|
jQuery.dequeue( elem, type );
|
|
};
|
|
|
|
// If the fx queue is dequeued, always remove the progress sentinel
|
|
if ( fn === "inprogress" ) {
|
|
fn = queue.shift();
|
|
startLength--;
|
|
}
|
|
|
|
if ( fn ) {
|
|
|
|
// Add a progress sentinel to prevent the fx queue from being
|
|
// automatically dequeued
|
|
if ( type === "fx" ) {
|
|
queue.unshift( "inprogress" );
|
|
}
|
|
|
|
// Clear up the last queue stop function
|
|
delete hooks.stop;
|
|
fn.call( elem, next, hooks );
|
|
}
|
|
|
|
if ( !startLength && hooks ) {
|
|
hooks.empty.fire();
|
|
}
|
|
},
|
|
|
|
// Not public - generate a queueHooks object, or return the current one
|
|
_queueHooks: function( elem, type ) {
|
|
var key = type + "queueHooks";
|
|
return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
|
|
empty: jQuery.Callbacks( "once memory" ).add( function() {
|
|
dataPriv.remove( elem, [ type + "queue", key ] );
|
|
} )
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
queue: function( type, data ) {
|
|
var setter = 2;
|
|
|
|
if ( typeof type !== "string" ) {
|
|
data = type;
|
|
type = "fx";
|
|
setter--;
|
|
}
|
|
|
|
if ( arguments.length < setter ) {
|
|
return jQuery.queue( this[ 0 ], type );
|
|
}
|
|
|
|
return data === undefined ?
|
|
this :
|
|
this.each( function() {
|
|
var queue = jQuery.queue( this, type, data );
|
|
|
|
// Ensure a hooks for this queue
|
|
jQuery._queueHooks( this, type );
|
|
|
|
if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
|
|
jQuery.dequeue( this, type );
|
|
}
|
|
} );
|
|
},
|
|
dequeue: function( type ) {
|
|
return this.each( function() {
|
|
jQuery.dequeue( this, type );
|
|
} );
|
|
},
|
|
clearQueue: function( type ) {
|
|
return this.queue( type || "fx", [] );
|
|
},
|
|
|
|
// Get a promise resolved when queues of a certain type
|
|
// are emptied (fx is the type by default)
|
|
promise: function( type, obj ) {
|
|
var tmp,
|
|
count = 1,
|
|
defer = jQuery.Deferred(),
|
|
elements = this,
|
|
i = this.length,
|
|
resolve = function() {
|
|
if ( !( --count ) ) {
|
|
defer.resolveWith( elements, [ elements ] );
|
|
}
|
|
};
|
|
|
|
if ( typeof type !== "string" ) {
|
|
obj = type;
|
|
type = undefined;
|
|
}
|
|
type = type || "fx";
|
|
|
|
while ( i-- ) {
|
|
tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
|
|
if ( tmp && tmp.empty ) {
|
|
count++;
|
|
tmp.empty.add( resolve );
|
|
}
|
|
}
|
|
resolve();
|
|
return defer.promise( obj );
|
|
}
|
|
} );
|
|
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
|
|
|
|
var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
|
|
|
|
|
|
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
|
|
|
|
var documentElement = document.documentElement;
|
|
|
|
|
|
|
|
var isAttached = function( elem ) {
|
|
return jQuery.contains( elem.ownerDocument, elem );
|
|
},
|
|
composed = { composed: true };
|
|
|
|
// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
|
|
// Check attachment across shadow DOM boundaries when possible (gh-3504)
|
|
// Support: iOS 10.0-10.2 only
|
|
// Early iOS 10 versions support `attachShadow` but not `getRootNode`,
|
|
// leading to errors. We need to check for `getRootNode`.
|
|
if ( documentElement.getRootNode ) {
|
|
isAttached = function( elem ) {
|
|
return jQuery.contains( elem.ownerDocument, elem ) ||
|
|
elem.getRootNode( composed ) === elem.ownerDocument;
|
|
};
|
|
}
|
|
var isHiddenWithinTree = function( elem, el ) {
|
|
|
|
// isHiddenWithinTree might be called from jQuery#filter function;
|
|
// in that case, element will be second argument
|
|
elem = el || elem;
|
|
|
|
// Inline style trumps all
|
|
return elem.style.display === "none" ||
|
|
elem.style.display === "" &&
|
|
|
|
// Otherwise, check computed style
|
|
// Support: Firefox <=43 - 45
|
|
// Disconnected elements can have computed display: none, so first confirm that elem is
|
|
// in the document.
|
|
isAttached( elem ) &&
|
|
|
|
jQuery.css( elem, "display" ) === "none";
|
|
};
|
|
|
|
var swap = function( elem, options, callback, args ) {
|
|
var ret, name,
|
|
old = {};
|
|
|
|
// Remember the old values, and insert the new ones
|
|
for ( name in options ) {
|
|
old[ name ] = elem.style[ name ];
|
|
elem.style[ name ] = options[ name ];
|
|
}
|
|
|
|
ret = callback.apply( elem, args || [] );
|
|
|
|
// Revert the old values
|
|
for ( name in options ) {
|
|
elem.style[ name ] = old[ name ];
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
|
|
|
|
|
|
function adjustCSS( elem, prop, valueParts, tween ) {
|
|
var adjusted, scale,
|
|
maxIterations = 20,
|
|
currentValue = tween ?
|
|
function() {
|
|
return tween.cur();
|
|
} :
|
|
function() {
|
|
return jQuery.css( elem, prop, "" );
|
|
},
|
|
initial = currentValue(),
|
|
unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
|
|
|
|
// Starting value computation is required for potential unit mismatches
|
|
initialInUnit = elem.nodeType &&
|
|
( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
|
|
rcssNum.exec( jQuery.css( elem, prop ) );
|
|
|
|
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
|
|
|
|
// Support: Firefox <=54
|
|
// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
|
|
initial = initial / 2;
|
|
|
|
// Trust units reported by jQuery.css
|
|
unit = unit || initialInUnit[ 3 ];
|
|
|
|
// Iteratively approximate from a nonzero starting point
|
|
initialInUnit = +initial || 1;
|
|
|
|
while ( maxIterations-- ) {
|
|
|
|
// Evaluate and update our best guess (doubling guesses that zero out).
|
|
// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
|
|
jQuery.style( elem, prop, initialInUnit + unit );
|
|
if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
|
|
maxIterations = 0;
|
|
}
|
|
initialInUnit = initialInUnit / scale;
|
|
|
|
}
|
|
|
|
initialInUnit = initialInUnit * 2;
|
|
jQuery.style( elem, prop, initialInUnit + unit );
|
|
|
|
// Make sure we update the tween properties later on
|
|
valueParts = valueParts || [];
|
|
}
|
|
|
|
if ( valueParts ) {
|
|
initialInUnit = +initialInUnit || +initial || 0;
|
|
|
|
// Apply relative offset (+=/-=) if specified
|
|
adjusted = valueParts[ 1 ] ?
|
|
initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
|
|
+valueParts[ 2 ];
|
|
if ( tween ) {
|
|
tween.unit = unit;
|
|
tween.start = initialInUnit;
|
|
tween.end = adjusted;
|
|
}
|
|
}
|
|
return adjusted;
|
|
}
|
|
|
|
|
|
var defaultDisplayMap = {};
|
|
|
|
function getDefaultDisplay( elem ) {
|
|
var temp,
|
|
doc = elem.ownerDocument,
|
|
nodeName = elem.nodeName,
|
|
display = defaultDisplayMap[ nodeName ];
|
|
|
|
if ( display ) {
|
|
return display;
|
|
}
|
|
|
|
temp = doc.body.appendChild( doc.createElement( nodeName ) );
|
|
display = jQuery.css( temp, "display" );
|
|
|
|
temp.parentNode.removeChild( temp );
|
|
|
|
if ( display === "none" ) {
|
|
display = "block";
|
|
}
|
|
defaultDisplayMap[ nodeName ] = display;
|
|
|
|
return display;
|
|
}
|
|
|
|
function showHide( elements, show ) {
|
|
var display, elem,
|
|
values = [],
|
|
index = 0,
|
|
length = elements.length;
|
|
|
|
// Determine new display value for elements that need to change
|
|
for ( ; index < length; index++ ) {
|
|
elem = elements[ index ];
|
|
if ( !elem.style ) {
|
|
continue;
|
|
}
|
|
|
|
display = elem.style.display;
|
|
if ( show ) {
|
|
|
|
// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
|
|
// check is required in this first loop unless we have a nonempty display value (either
|
|
// inline or about-to-be-restored)
|
|
if ( display === "none" ) {
|
|
values[ index ] = dataPriv.get( elem, "display" ) || null;
|
|
if ( !values[ index ] ) {
|
|
elem.style.display = "";
|
|
}
|
|
}
|
|
if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
|
|
values[ index ] = getDefaultDisplay( elem );
|
|
}
|
|
} else {
|
|
if ( display !== "none" ) {
|
|
values[ index ] = "none";
|
|
|
|
// Remember what we're overwriting
|
|
dataPriv.set( elem, "display", display );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the display of the elements in a second loop to avoid constant reflow
|
|
for ( index = 0; index < length; index++ ) {
|
|
if ( values[ index ] != null ) {
|
|
elements[ index ].style.display = values[ index ];
|
|
}
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
jQuery.fn.extend( {
|
|
show: function() {
|
|
return showHide( this, true );
|
|
},
|
|
hide: function() {
|
|
return showHide( this );
|
|
},
|
|
toggle: function( state ) {
|
|
if ( typeof state === "boolean" ) {
|
|
return state ? this.show() : this.hide();
|
|
}
|
|
|
|
return this.each( function() {
|
|
if ( isHiddenWithinTree( this ) ) {
|
|
jQuery( this ).show();
|
|
} else {
|
|
jQuery( this ).hide();
|
|
}
|
|
} );
|
|
}
|
|
} );
|
|
var rcheckableType = ( /^(?:checkbox|radio)$/i );
|
|
|
|
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
|
|
|
|
var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
|
|
|
|
|
|
|
|
// We have to close these tags to support XHTML (#13200)
|
|
var wrapMap = {
|
|
|
|
// Support: IE <=9 only
|
|
option: [ 1, "<select multiple='multiple'>", "</select>" ],
|
|
|
|
// XHTML parsers do not magically insert elements in the
|
|
// same way that tag soup parsers do. So we cannot shorten
|
|
// this by omitting <tbody> or other required elements.
|
|
thead: [ 1, "<table>", "</table>" ],
|
|
col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
|
|
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
|
|
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
|
|
|
|
_default: [ 0, "", "" ]
|
|
};
|
|
|
|
// Support: IE <=9 only
|
|
wrapMap.optgroup = wrapMap.option;
|
|
|
|
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
|
|
wrapMap.th = wrapMap.td;
|
|
|
|
|
|
function getAll( context, tag ) {
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
|
|
var ret;
|
|
|
|
if ( typeof context.getElementsByTagName !== "undefined" ) {
|
|
ret = context.getElementsByTagName( tag || "*" );
|
|
|
|
} else if ( typeof context.querySelectorAll !== "undefined" ) {
|
|
ret = context.querySelectorAll( tag || "*" );
|
|
|
|
} else {
|
|
ret = [];
|
|
}
|
|
|
|
if ( tag === undefined || tag && nodeName( context, tag ) ) {
|
|
return jQuery.merge( [ context ], ret );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
// Mark scripts as having already been evaluated
|
|
function setGlobalEval( elems, refElements ) {
|
|
var i = 0,
|
|
l = elems.length;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
dataPriv.set(
|
|
elems[ i ],
|
|
"globalEval",
|
|
!refElements || dataPriv.get( refElements[ i ], "globalEval" )
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
var rhtml = /<|&#?\w+;/;
|
|
|
|
function buildFragment( elems, context, scripts, selection, ignored ) {
|
|
var elem, tmp, tag, wrap, attached, j,
|
|
fragment = context.createDocumentFragment(),
|
|
nodes = [],
|
|
i = 0,
|
|
l = elems.length;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
elem = elems[ i ];
|
|
|
|
if ( elem || elem === 0 ) {
|
|
|
|
// Add nodes directly
|
|
if ( toType( elem ) === "object" ) {
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
|
|
|
|
// Convert non-html into a text node
|
|
} else if ( !rhtml.test( elem ) ) {
|
|
nodes.push( context.createTextNode( elem ) );
|
|
|
|
// Convert html into DOM nodes
|
|
} else {
|
|
tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
|
|
|
|
// Deserialize a standard representation
|
|
tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
|
|
wrap = wrapMap[ tag ] || wrapMap._default;
|
|
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
|
|
|
|
// Descend through wrappers to the right content
|
|
j = wrap[ 0 ];
|
|
while ( j-- ) {
|
|
tmp = tmp.lastChild;
|
|
}
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
jQuery.merge( nodes, tmp.childNodes );
|
|
|
|
// Remember the top-level container
|
|
tmp = fragment.firstChild;
|
|
|
|
// Ensure the created nodes are orphaned (#12392)
|
|
tmp.textContent = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove wrapper from fragment
|
|
fragment.textContent = "";
|
|
|
|
i = 0;
|
|
while ( ( elem = nodes[ i++ ] ) ) {
|
|
|
|
// Skip elements already in the context collection (trac-4087)
|
|
if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
|
|
if ( ignored ) {
|
|
ignored.push( elem );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
attached = isAttached( elem );
|
|
|
|
// Append to fragment
|
|
tmp = getAll( fragment.appendChild( elem ), "script" );
|
|
|
|
// Preserve script evaluation history
|
|
if ( attached ) {
|
|
setGlobalEval( tmp );
|
|
}
|
|
|
|
// Capture executables
|
|
if ( scripts ) {
|
|
j = 0;
|
|
while ( ( elem = tmp[ j++ ] ) ) {
|
|
if ( rscriptType.test( elem.type || "" ) ) {
|
|
scripts.push( elem );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fragment;
|
|
}
|
|
|
|
|
|
( function() {
|
|
var fragment = document.createDocumentFragment(),
|
|
div = fragment.appendChild( document.createElement( "div" ) ),
|
|
input = document.createElement( "input" );
|
|
|
|
// Support: Android 4.0 - 4.3 only
|
|
// Check state lost if the name is set (#11217)
|
|
// Support: Windows Web Apps (WWA)
|
|
// `name` and `type` must use .setAttribute for WWA (#14901)
|
|
input.setAttribute( "type", "radio" );
|
|
input.setAttribute( "checked", "checked" );
|
|
input.setAttribute( "name", "t" );
|
|
|
|
div.appendChild( input );
|
|
|
|
// Support: Android <=4.1 only
|
|
// Older WebKit doesn't clone checked state correctly in fragments
|
|
support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
|
|
|
// Support: IE <=11 only
|
|
// Make sure textarea (and checkbox) defaultValue is properly cloned
|
|
div.innerHTML = "<textarea>x</textarea>";
|
|
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
|
|
} )();
|
|
|
|
|
|
var
|
|
rkeyEvent = /^key/,
|
|
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
|
|
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
|
|
|
|
function returnTrue() {
|
|
return true;
|
|
}
|
|
|
|
function returnFalse() {
|
|
return false;
|
|
}
|
|
|
|
// Support: IE <=9 - 11+
|
|
// focus() and blur() are asynchronous, except when they are no-op.
|
|
// So expect focus to be synchronous when the element is already active,
|
|
// and blur to be synchronous when the element is not already active.
|
|
// (focus and blur are always synchronous in other supported browsers,
|
|
// this just defines when we can count on it).
|
|
function expectSync( elem, type ) {
|
|
return ( elem === safeActiveElement() ) === ( type === "focus" );
|
|
}
|
|
|
|
// Support: IE <=9 only
|
|
// Accessing document.activeElement can throw unexpectedly
|
|
// https://bugs.jquery.com/ticket/13393
|
|
function safeActiveElement() {
|
|
try {
|
|
return document.activeElement;
|
|
} catch ( err ) { }
|
|
}
|
|
|
|
function on( elem, types, selector, data, fn, one ) {
|
|
var origFn, type;
|
|
|
|
// Types can be a map of types/handlers
|
|
if ( typeof types === "object" ) {
|
|
|
|
// ( types-Object, selector, data )
|
|
if ( typeof selector !== "string" ) {
|
|
|
|
// ( types-Object, data )
|
|
data = data || selector;
|
|
selector = undefined;
|
|
}
|
|
for ( type in types ) {
|
|
on( elem, type, selector, data, types[ type ], one );
|
|
}
|
|
return elem;
|
|
}
|
|
|
|
if ( data == null && fn == null ) {
|
|
|
|
// ( types, fn )
|
|
fn = selector;
|
|
data = selector = undefined;
|
|
} else if ( fn == null ) {
|
|
if ( typeof selector === "string" ) {
|
|
|
|
// ( types, selector, fn )
|
|
fn = data;
|
|
data = undefined;
|
|
} else {
|
|
|
|
// ( types, data, fn )
|
|
fn = data;
|
|
data = selector;
|
|
selector = undefined;
|
|
}
|
|
}
|
|
if ( fn === false ) {
|
|
fn = returnFalse;
|
|
} else if ( !fn ) {
|
|
return elem;
|
|
}
|
|
|
|
if ( one === 1 ) {
|
|
origFn = fn;
|
|
fn = function( event ) {
|
|
|
|
// Can use an empty set, since event contains the info
|
|
jQuery().off( event );
|
|
return origFn.apply( this, arguments );
|
|
};
|
|
|
|
// Use same guid so caller can remove using origFn
|
|
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
|
|
}
|
|
return elem.each( function() {
|
|
jQuery.event.add( this, types, fn, data, selector );
|
|
} );
|
|
}
|
|
|
|
/*
|
|
* Helper functions for managing events -- not part of the public interface.
|
|
* Props to Dean Edwards' addEvent library for many of the ideas.
|
|
*/
|
|
jQuery.event = {
|
|
|
|
global: {},
|
|
|
|
add: function( elem, types, handler, data, selector ) {
|
|
|
|
var handleObjIn, eventHandle, tmp,
|
|
events, t, handleObj,
|
|
special, handlers, type, namespaces, origType,
|
|
elemData = dataPriv.get( elem );
|
|
|
|
// Don't attach events to noData or text/comment nodes (but allow plain objects)
|
|
if ( !elemData ) {
|
|
return;
|
|
}
|
|
|
|
// Caller can pass in an object of custom data in lieu of the handler
|
|
if ( handler.handler ) {
|
|
handleObjIn = handler;
|
|
handler = handleObjIn.handler;
|
|
selector = handleObjIn.selector;
|
|
}
|
|
|
|
// Ensure that invalid selectors throw exceptions at attach time
|
|
// Evaluate against documentElement in case elem is a non-element node (e.g., document)
|
|
if ( selector ) {
|
|
jQuery.find.matchesSelector( documentElement, selector );
|
|
}
|
|
|
|
// Make sure that the handler has a unique ID, used to find/remove it later
|
|
if ( !handler.guid ) {
|
|
handler.guid = jQuery.guid++;
|
|
}
|
|
|
|
// Init the element's event structure and main handler, if this is the first
|
|
if ( !( events = elemData.events ) ) {
|
|
events = elemData.events = {};
|
|
}
|
|
if ( !( eventHandle = elemData.handle ) ) {
|
|
eventHandle = elemData.handle = function( e ) {
|
|
|
|
// Discard the second event of a jQuery.event.trigger() and
|
|
// when an event is called after a page has unloaded
|
|
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
|
|
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
|
|
};
|
|
}
|
|
|
|
// Handle multiple events separated by a space
|
|
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
|
|
t = types.length;
|
|
while ( t-- ) {
|
|
tmp = rtypenamespace.exec( types[ t ] ) || [];
|
|
type = origType = tmp[ 1 ];
|
|
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
|
|
|
|
// There *must* be a type, no attaching namespace-only handlers
|
|
if ( !type ) {
|
|
continue;
|
|
}
|
|
|
|
// If event changes its type, use the special event handlers for the changed type
|
|
special = jQuery.event.special[ type ] || {};
|
|
|
|
// If selector defined, determine special event api type, otherwise given type
|
|
type = ( selector ? special.delegateType : special.bindType ) || type;
|
|
|
|
// Update special based on newly reset type
|
|
special = jQuery.event.special[ type ] || {};
|
|
|
|
// handleObj is passed to all event handlers
|
|
handleObj = jQuery.extend( {
|
|
type: type,
|
|
origType: origType,
|
|
data: data,
|
|
handler: handler,
|
|
guid: handler.guid,
|
|
selector: selector,
|
|
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
|
|
namespace: namespaces.join( "." )
|
|
}, handleObjIn );
|
|
|
|
// Init the event handler queue if we're the first
|
|
if ( !( handlers = events[ type ] ) ) {
|
|
handlers = events[ type ] = [];
|
|
handlers.delegateCount = 0;
|
|
|
|
// Only use addEventListener if the special events handler returns false
|
|
if ( !special.setup ||
|
|
special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
|
|
|
|
if ( elem.addEventListener ) {
|
|
elem.addEventListener( type, eventHandle );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( special.add ) {
|
|
special.add.call( elem, handleObj );
|
|
|
|
if ( !handleObj.handler.guid ) {
|
|
handleObj.handler.guid = handler.guid;
|
|
}
|
|
}
|
|
|
|
// Add to the element's handler list, delegates in front
|
|
if ( selector ) {
|
|
handlers.splice( handlers.delegateCount++, 0, handleObj );
|
|
} else {
|
|
handlers.push( handleObj );
|
|
}
|
|
|
|
// Keep track of which events have ever been used, for event optimization
|
|
jQuery.event.global[ type ] = true;
|
|
}
|
|
|
|
},
|
|
|
|
// Detach an event or set of events from an element
|
|
remove: function( elem, types, handler, selector, mappedTypes ) {
|
|
|
|
var j, origCount, tmp,
|
|
events, t, handleObj,
|
|
special, handlers, type, namespaces, origType,
|
|
elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
|
|
|
|
if ( !elemData || !( events = elemData.events ) ) {
|
|
return;
|
|
}
|
|
|
|
// Once for each type.namespace in types; type may be omitted
|
|
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
|
|
t = types.length;
|
|
while ( t-- ) {
|
|
tmp = rtypenamespace.exec( types[ t ] ) || [];
|
|
type = origType = tmp[ 1 ];
|
|
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
|
|
|
|
// Unbind all events (on this namespace, if provided) for the element
|
|
if ( !type ) {
|
|
for ( type in events ) {
|
|
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
|
|
}
|
|
continue;
|
|
}
|
|
|
|
special = jQuery.event.special[ type ] || {};
|
|
type = ( selector ? special.delegateType : special.bindType ) || type;
|
|
handlers = events[ type ] || [];
|
|
tmp = tmp[ 2 ] &&
|
|
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
|
|
|
|
// Remove matching events
|
|
origCount = j = handlers.length;
|
|
while ( j-- ) {
|
|
handleObj = handlers[ j ];
|
|
|
|
if ( ( mappedTypes || origType === handleObj.origType ) &&
|
|
( !handler || handler.guid === handleObj.guid ) &&
|
|
( !tmp || tmp.test( handleObj.namespace ) ) &&
|
|
( !selector || selector === handleObj.selector ||
|
|
selector === "**" && handleObj.selector ) ) {
|
|
handlers.splice( j, 1 );
|
|
|
|
if ( handleObj.selector ) {
|
|
handlers.delegateCount--;
|
|
}
|
|
if ( special.remove ) {
|
|
special.remove.call( elem, handleObj );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove generic event handler if we removed something and no more handlers exist
|
|
// (avoids potential for endless recursion during removal of special event handlers)
|
|
if ( origCount && !handlers.length ) {
|
|
if ( !special.teardown ||
|
|
special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
|
|
|
|
jQuery.removeEvent( elem, type, elemData.handle );
|
|
}
|
|
|
|
delete events[ type ];
|
|
}
|
|
}
|
|
|
|
// Remove data and the expando if it's no longer used
|
|
if ( jQuery.isEmptyObject( events ) ) {
|
|
dataPriv.remove( elem, "handle events" );
|
|
}
|
|
},
|
|
|
|
dispatch: function( nativeEvent ) {
|
|
|
|
// Make a writable jQuery.Event from the native event object
|
|
var event = jQuery.event.fix( nativeEvent );
|
|
|
|
var i, j, ret, matched, handleObj, handlerQueue,
|
|
args = new Array( arguments.length ),
|
|
handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
|
|
special = jQuery.event.special[ event.type ] || {};
|
|
|
|
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
|
args[ 0 ] = event;
|
|
|
|
for ( i = 1; i < arguments.length; i++ ) {
|
|
args[ i ] = arguments[ i ];
|
|
}
|
|
|
|
event.delegateTarget = this;
|
|
|
|
// Call the preDispatch hook for the mapped type, and let it bail if desired
|
|
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
|
|
return;
|
|
}
|
|
|
|
// Determine handlers
|
|
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
|
|
|
|
// Run delegates first; they may want to stop propagation beneath us
|
|
i = 0;
|
|
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
|
|
event.currentTarget = matched.elem;
|
|
|
|
j = 0;
|
|
while ( ( handleObj = matched.handlers[ j++ ] ) &&
|
|
!event.isImmediatePropagationStopped() ) {
|
|
|
|
// If the event is namespaced, then each handler is only invoked if it is
|
|
// specially universal or its namespaces are a superset of the event's.
|
|
if ( !event.rnamespace || handleObj.namespace === false ||
|
|
event.rnamespace.test( handleObj.namespace ) ) {
|
|
|
|
event.handleObj = handleObj;
|
|
event.data = handleObj.data;
|
|
|
|
ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
|
|
handleObj.handler ).apply( matched.elem, args );
|
|
|
|
if ( ret !== undefined ) {
|
|
if ( ( event.result = ret ) === false ) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Call the postDispatch hook for the mapped type
|
|
if ( special.postDispatch ) {
|
|
special.postDispatch.call( this, event );
|
|
}
|
|
|
|
return event.result;
|
|
},
|
|
|
|
handlers: function( event, handlers ) {
|
|
var i, handleObj, sel, matchedHandlers, matchedSelectors,
|
|
handlerQueue = [],
|
|
delegateCount = handlers.delegateCount,
|
|
cur = event.target;
|
|
|
|
// Find delegate handlers
|
|
if ( delegateCount &&
|
|
|
|
// Support: IE <=9
|
|
// Black-hole SVG <use> instance trees (trac-13180)
|
|
cur.nodeType &&
|
|
|
|
// Support: Firefox <=42
|
|
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
|
|
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
|
|
// Support: IE 11 only
|
|
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
|
|
!( event.type === "click" && event.button >= 1 ) ) {
|
|
|
|
for ( ; cur !== this; cur = cur.parentNode || this ) {
|
|
|
|
// Don't check non-elements (#13208)
|
|
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
|
|
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
|
|
matchedHandlers = [];
|
|
matchedSelectors = {};
|
|
for ( i = 0; i < delegateCount; i++ ) {
|
|
handleObj = handlers[ i ];
|
|
|
|
// Don't conflict with Object.prototype properties (#13203)
|
|
sel = handleObj.selector + " ";
|
|
|
|
if ( matchedSelectors[ sel ] === undefined ) {
|
|
matchedSelectors[ sel ] = handleObj.needsContext ?
|
|
jQuery( sel, this ).index( cur ) > -1 :
|
|
jQuery.find( sel, this, null, [ cur ] ).length;
|
|
}
|
|
if ( matchedSelectors[ sel ] ) {
|
|
matchedHandlers.push( handleObj );
|
|
}
|
|
}
|
|
if ( matchedHandlers.length ) {
|
|
handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the remaining (directly-bound) handlers
|
|
cur = this;
|
|
if ( delegateCount < handlers.length ) {
|
|
handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
|
|
}
|
|
|
|
return handlerQueue;
|
|
},
|
|
|
|
addProp: function( name, hook ) {
|
|
Object.defineProperty( jQuery.Event.prototype, name, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
|
|
get: isFunction( hook ) ?
|
|
function() {
|
|
if ( this.originalEvent ) {
|
|
return hook( this.originalEvent );
|
|
}
|
|
} :
|
|
function() {
|
|
if ( this.originalEvent ) {
|
|
return this.originalEvent[ name ];
|
|
}
|
|
},
|
|
|
|
set: function( value ) {
|
|
Object.defineProperty( this, name, {
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true,
|
|
value: value
|
|
} );
|
|
}
|
|
} );
|
|
},
|
|
|
|
fix: function( originalEvent ) {
|
|
return originalEvent[ jQuery.expando ] ?
|
|
originalEvent :
|
|
new jQuery.Event( originalEvent );
|
|
},
|
|
|
|
special: {
|
|
load: {
|
|
|
|
// Prevent triggered image.load events from bubbling to window.load
|
|
noBubble: true
|
|
},
|
|
click: {
|
|
|
|
// Utilize native event to ensure correct state for checkable inputs
|
|
setup: function( data ) {
|
|
|
|
// For mutual compressibility with _default, replace `this` access with a local var.
|
|
// `|| data` is dead code meant only to preserve the variable through minification.
|
|
var el = this || data;
|
|
|
|
// Claim the first handler
|
|
if ( rcheckableType.test( el.type ) &&
|
|
el.click && nodeName( el, "input" ) ) {
|
|
|
|
// dataPriv.set( el, "click", ... )
|
|
leverageNative( el, "click", returnTrue );
|
|
}
|
|
|
|
// Return false to allow normal processing in the caller
|
|
return false;
|
|
},
|
|
trigger: function( data ) {
|
|
|
|
// For mutual compressibility with _default, replace `this` access with a local var.
|
|
// `|| data` is dead code meant only to preserve the variable through minification.
|
|
var el = this || data;
|
|
|
|
// Force setup before triggering a click
|
|
if ( rcheckableType.test( el.type ) &&
|
|
el.click && nodeName( el, "input" ) ) {
|
|
|
|
leverageNative( el, "click" );
|
|
}
|
|
|
|
// Return non-false to allow normal event-path propagation
|
|
return true;
|
|
},
|
|
|
|
// For cross-browser consistency, suppress native .click() on links
|
|
// Also prevent it if we're currently inside a leveraged native-event stack
|
|
_default: function( event ) {
|
|
var target = event.target;
|
|
return rcheckableType.test( target.type ) &&
|
|
target.click && nodeName( target, "input" ) &&
|
|
dataPriv.get( target, "click" ) ||
|
|
nodeName( target, "a" );
|
|
}
|
|
},
|
|
|
|
beforeunload: {
|
|
postDispatch: function( event ) {
|
|
|
|
// Support: Firefox 20+
|
|
// Firefox doesn't alert if the returnValue field is not set.
|
|
if ( event.result !== undefined && event.originalEvent ) {
|
|
event.originalEvent.returnValue = event.result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Ensure the presence of an event listener that handles manually-triggered
|
|
// synthetic events by interrupting progress until reinvoked in response to
|
|
// *native* events that it fires directly, ensuring that state changes have
|
|
// already occurred before other listeners are invoked.
|
|
function leverageNative( el, type, expectSync ) {
|
|
|
|
// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
|
|
if ( !expectSync ) {
|
|
if ( dataPriv.get( el, type ) === undefined ) {
|
|
jQuery.event.add( el, type, returnTrue );
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Register the controller as a special universal handler for all event namespaces
|
|
dataPriv.set( el, type, false );
|
|
jQuery.event.add( el, type, {
|
|
namespace: false,
|
|
handler: function( event ) {
|
|
var notAsync, result,
|
|
saved = dataPriv.get( this, type );
|
|
|
|
if ( ( event.isTrigger & 1 ) && this[ type ] ) {
|
|
|
|
// Interrupt processing of the outer synthetic .trigger()ed event
|
|
// Saved data should be false in such cases, but might be a leftover capture object
|
|
// from an async native handler (gh-4350)
|
|
if ( !saved.length ) {
|
|
|
|
// Store arguments for use when handling the inner native event
|
|
// There will always be at least one argument (an event object), so this array
|
|
// will not be confused with a leftover capture object.
|
|
saved = slice.call( arguments );
|
|
dataPriv.set( this, type, saved );
|
|
|
|
// Trigger the native event and capture its result
|
|
// Support: IE <=9 - 11+
|
|
// focus() and blur() are asynchronous
|
|
notAsync = expectSync( this, type );
|
|
this[ type ]();
|
|
result = dataPriv.get( this, type );
|
|
if ( saved !== result || notAsync ) {
|
|
dataPriv.set( this, type, false );
|
|
} else {
|
|
result = {};
|
|
}
|
|
if ( saved !== result ) {
|
|
|
|
// Cancel the outer synthetic event
|
|
event.stopImmediatePropagation();
|
|
event.preventDefault();
|
|
return result.value;
|
|
}
|
|
|
|
// If this is an inner synthetic event for an event with a bubbling surrogate
|
|
// (focus or blur), assume that the surrogate already propagated from triggering the
|
|
// native event and prevent that from happening again here.
|
|
// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
|
|
// bubbling surrogate propagates *after* the non-bubbling base), but that seems
|
|
// less bad than duplication.
|
|
} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
|
|
event.stopPropagation();
|
|
}
|
|
|
|
// If this is a native event triggered above, everything is now in order
|
|
// Fire an inner synthetic event with the original arguments
|
|
} else if ( saved.length ) {
|
|
|
|
// ...and capture the result
|
|
dataPriv.set( this, type, {
|
|
value: jQuery.event.trigger(
|
|
|
|
// Support: IE <=9 - 11+
|
|
// Extend with the prototype to reset the above stopImmediatePropagation()
|
|
jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
|
|
saved.slice( 1 ),
|
|
this
|
|
)
|
|
} );
|
|
|
|
// Abort handling of the native event
|
|
event.stopImmediatePropagation();
|
|
}
|
|
}
|
|
} );
|
|
}
|
|
|
|
jQuery.removeEvent = function( elem, type, handle ) {
|
|
|
|
// This "if" is needed for plain objects
|
|
if ( elem.removeEventListener ) {
|
|
elem.removeEventListener( type, handle );
|
|
}
|
|
};
|
|
|
|
jQuery.Event = function( src, props ) {
|
|
|
|
// Allow instantiation without the 'new' keyword
|
|
if ( !( this instanceof jQuery.Event ) ) {
|
|
return new jQuery.Event( src, props );
|
|
}
|
|
|
|
// Event object
|
|
if ( src && src.type ) {
|
|
this.originalEvent = src;
|
|
this.type = src.type;
|
|
|
|
// Events bubbling up the document may have been marked as prevented
|
|
// by a handler lower down the tree; reflect the correct value.
|
|
this.isDefaultPrevented = src.defaultPrevented ||
|
|
src.defaultPrevented === undefined &&
|
|
|
|
// Support: Android <=2.3 only
|
|
src.returnValue === false ?
|
|
returnTrue :
|
|
returnFalse;
|
|
|
|
// Create target properties
|
|
// Support: Safari <=6 - 7 only
|
|
// Target should not be a text node (#504, #13143)
|
|
this.target = ( src.target && src.target.nodeType === 3 ) ?
|
|
src.target.parentNode :
|
|
src.target;
|
|
|
|
this.currentTarget = src.currentTarget;
|
|
this.relatedTarget = src.relatedTarget;
|
|
|
|
// Event type
|
|
} else {
|
|
this.type = src;
|
|
}
|
|
|
|
// Put explicitly provided properties onto the event object
|
|
if ( props ) {
|
|
jQuery.extend( this, props );
|
|
}
|
|
|
|
// Create a timestamp if incoming event doesn't have one
|
|
this.timeStamp = src && src.timeStamp || Date.now();
|
|
|
|
// Mark it as fixed
|
|
this[ jQuery.expando ] = true;
|
|
};
|
|
|
|
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
|
|
// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
|
|
jQuery.Event.prototype = {
|
|
constructor: jQuery.Event,
|
|
isDefaultPrevented: returnFalse,
|
|
isPropagationStopped: returnFalse,
|
|
isImmediatePropagationStopped: returnFalse,
|
|
isSimulated: false,
|
|
|
|
preventDefault: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isDefaultPrevented = returnTrue;
|
|
|
|
if ( e && !this.isSimulated ) {
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
stopPropagation: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isPropagationStopped = returnTrue;
|
|
|
|
if ( e && !this.isSimulated ) {
|
|
e.stopPropagation();
|
|
}
|
|
},
|
|
stopImmediatePropagation: function() {
|
|
var e = this.originalEvent;
|
|
|
|
this.isImmediatePropagationStopped = returnTrue;
|
|
|
|
if ( e && !this.isSimulated ) {
|
|
e.stopImmediatePropagation();
|
|
}
|
|
|
|
this.stopPropagation();
|
|
}
|
|
};
|
|
|
|
// Includes all common event props including KeyEvent and MouseEvent specific props
|
|
jQuery.each( {
|
|
altKey: true,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
changedTouches: true,
|
|
ctrlKey: true,
|
|
detail: true,
|
|
eventPhase: true,
|
|
metaKey: true,
|
|
pageX: true,
|
|
pageY: true,
|
|
shiftKey: true,
|
|
view: true,
|
|
"char": true,
|
|
code: true,
|
|
charCode: true,
|
|
key: true,
|
|
keyCode: true,
|
|
button: true,
|
|
buttons: true,
|
|
clientX: true,
|
|
clientY: true,
|
|
offsetX: true,
|
|
offsetY: true,
|
|
pointerId: true,
|
|
pointerType: true,
|
|
screenX: true,
|
|
screenY: true,
|
|
targetTouches: true,
|
|
toElement: true,
|
|
touches: true,
|
|
|
|
which: function( event ) {
|
|
var button = event.button;
|
|
|
|
// Add which for key events
|
|
if ( event.which == null && rkeyEvent.test( event.type ) ) {
|
|
return event.charCode != null ? event.charCode : event.keyCode;
|
|
}
|
|
|
|
// Add which for click: 1 === left; 2 === middle; 3 === right
|
|
if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
|
|
if ( button & 1 ) {
|
|
return 1;
|
|
}
|
|
|
|
if ( button & 2 ) {
|
|
return 3;
|
|
}
|
|
|
|
if ( button & 4 ) {
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return event.which;
|
|
}
|
|
}, jQuery.event.addProp );
|
|
|
|
jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
|
|
jQuery.event.special[ type ] = {
|
|
|
|
// Utilize native event if possible so blur/focus sequence is correct
|
|
setup: function() {
|
|
|
|
// Claim the first handler
|
|
// dataPriv.set( this, "focus", ... )
|
|
// dataPriv.set( this, "blur", ... )
|
|
leverageNative( this, type, expectSync );
|
|
|
|
// Return false to allow normal processing in the caller
|
|
return false;
|
|
},
|
|
trigger: function() {
|
|
|
|
// Force setup before trigger
|
|
leverageNative( this, type );
|
|
|
|
// Return non-false to allow normal event-path propagation
|
|
return true;
|
|
},
|
|
|
|
delegateType: delegateType
|
|
};
|
|
} );
|
|
|
|
// Create mouseenter/leave events using mouseover/out and event-time checks
|
|
// so that event delegation works in jQuery.
|
|
// Do the same for pointerenter/pointerleave and pointerover/pointerout
|
|
//
|
|
// Support: Safari 7 only
|
|
// Safari sends mouseenter too often; see:
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
|
|
// for the description of the bug (it existed in older Chrome versions as well).
|
|
jQuery.each( {
|
|
mouseenter: "mouseover",
|
|
mouseleave: "mouseout",
|
|
pointerenter: "pointerover",
|
|
pointerleave: "pointerout"
|
|
}, function( orig, fix ) {
|
|
jQuery.event.special[ orig ] = {
|
|
delegateType: fix,
|
|
bindType: fix,
|
|
|
|
handle: function( event ) {
|
|
var ret,
|
|
target = this,
|
|
related = event.relatedTarget,
|
|
handleObj = event.handleObj;
|
|
|
|
// For mouseenter/leave call the handler if related is outside the target.
|
|
// NB: No relatedTarget if the mouse left/entered the browser window
|
|
if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
|
|
event.type = handleObj.origType;
|
|
ret = handleObj.handler.apply( this, arguments );
|
|
event.type = fix;
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
on: function( types, selector, data, fn ) {
|
|
return on( this, types, selector, data, fn );
|
|
},
|
|
one: function( types, selector, data, fn ) {
|
|
return on( this, types, selector, data, fn, 1 );
|
|
},
|
|
off: function( types, selector, fn ) {
|
|
var handleObj, type;
|
|
if ( types && types.preventDefault && types.handleObj ) {
|
|
|
|
// ( event ) dispatched jQuery.Event
|
|
handleObj = types.handleObj;
|
|
jQuery( types.delegateTarget ).off(
|
|
handleObj.namespace ?
|
|
handleObj.origType + "." + handleObj.namespace :
|
|
handleObj.origType,
|
|
handleObj.selector,
|
|
handleObj.handler
|
|
);
|
|
return this;
|
|
}
|
|
if ( typeof types === "object" ) {
|
|
|
|
// ( types-object [, selector] )
|
|
for ( type in types ) {
|
|
this.off( type, selector, types[ type ] );
|
|
}
|
|
return this;
|
|
}
|
|
if ( selector === false || typeof selector === "function" ) {
|
|
|
|
// ( types [, fn] )
|
|
fn = selector;
|
|
selector = undefined;
|
|
}
|
|
if ( fn === false ) {
|
|
fn = returnFalse;
|
|
}
|
|
return this.each( function() {
|
|
jQuery.event.remove( this, types, fn, selector );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
|
|
var
|
|
|
|
/* eslint-disable max-len */
|
|
|
|
// See https://github.com/eslint/eslint/issues/3229
|
|
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
|
|
|
|
/* eslint-enable */
|
|
|
|
// Support: IE <=10 - 11, Edge 12 - 13 only
|
|
// In IE/Edge using regex groups here causes severe slowdowns.
|
|
// See https://connect.microsoft.com/IE/feedback/details/1736512/
|
|
rnoInnerhtml = /<script|<style|<link/i,
|
|
|
|
// checked="checked" or checked
|
|
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
|
|
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
|
|
|
|
// Prefer a tbody over its parent table for containing new rows
|
|
function manipulationTarget( elem, content ) {
|
|
if ( nodeName( elem, "table" ) &&
|
|
nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
|
|
|
|
return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
// Replace/restore the type attribute of script elements for safe DOM manipulation
|
|
function disableScript( elem ) {
|
|
elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
|
|
return elem;
|
|
}
|
|
function restoreScript( elem ) {
|
|
if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
|
|
elem.type = elem.type.slice( 5 );
|
|
} else {
|
|
elem.removeAttribute( "type" );
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
function cloneCopyEvent( src, dest ) {
|
|
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
|
|
|
|
if ( dest.nodeType !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
// 1. Copy private data: events, handlers, etc.
|
|
if ( dataPriv.hasData( src ) ) {
|
|
pdataOld = dataPriv.access( src );
|
|
pdataCur = dataPriv.set( dest, pdataOld );
|
|
events = pdataOld.events;
|
|
|
|
if ( events ) {
|
|
delete pdataCur.handle;
|
|
pdataCur.events = {};
|
|
|
|
for ( type in events ) {
|
|
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
|
jQuery.event.add( dest, type, events[ type ][ i ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Copy user data
|
|
if ( dataUser.hasData( src ) ) {
|
|
udataOld = dataUser.access( src );
|
|
udataCur = jQuery.extend( {}, udataOld );
|
|
|
|
dataUser.set( dest, udataCur );
|
|
}
|
|
}
|
|
|
|
// Fix IE bugs, see support tests
|
|
function fixInput( src, dest ) {
|
|
var nodeName = dest.nodeName.toLowerCase();
|
|
|
|
// Fails to persist the checked state of a cloned checkbox or radio button.
|
|
if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
|
|
dest.checked = src.checked;
|
|
|
|
// Fails to return the selected option to the default selected state when cloning options
|
|
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
|
dest.defaultValue = src.defaultValue;
|
|
}
|
|
}
|
|
|
|
function domManip( collection, args, callback, ignored ) {
|
|
|
|
// Flatten any nested arrays
|
|
args = concat.apply( [], args );
|
|
|
|
var fragment, first, scripts, hasScripts, node, doc,
|
|
i = 0,
|
|
l = collection.length,
|
|
iNoClone = l - 1,
|
|
value = args[ 0 ],
|
|
valueIsFunction = isFunction( value );
|
|
|
|
// We can't cloneNode fragments that contain checked, in WebKit
|
|
if ( valueIsFunction ||
|
|
( l > 1 && typeof value === "string" &&
|
|
!support.checkClone && rchecked.test( value ) ) ) {
|
|
return collection.each( function( index ) {
|
|
var self = collection.eq( index );
|
|
if ( valueIsFunction ) {
|
|
args[ 0 ] = value.call( this, index, self.html() );
|
|
}
|
|
domManip( self, args, callback, ignored );
|
|
} );
|
|
}
|
|
|
|
if ( l ) {
|
|
fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
|
|
first = fragment.firstChild;
|
|
|
|
if ( fragment.childNodes.length === 1 ) {
|
|
fragment = first;
|
|
}
|
|
|
|
// Require either new content or an interest in ignored elements to invoke the callback
|
|
if ( first || ignored ) {
|
|
scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
|
|
hasScripts = scripts.length;
|
|
|
|
// Use the original fragment for the last item
|
|
// instead of the first because it can end up
|
|
// being emptied incorrectly in certain situations (#8070).
|
|
for ( ; i < l; i++ ) {
|
|
node = fragment;
|
|
|
|
if ( i !== iNoClone ) {
|
|
node = jQuery.clone( node, true, true );
|
|
|
|
// Keep references to cloned scripts for later restoration
|
|
if ( hasScripts ) {
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// push.apply(_, arraylike) throws on ancient WebKit
|
|
jQuery.merge( scripts, getAll( node, "script" ) );
|
|
}
|
|
}
|
|
|
|
callback.call( collection[ i ], node, i );
|
|
}
|
|
|
|
if ( hasScripts ) {
|
|
doc = scripts[ scripts.length - 1 ].ownerDocument;
|
|
|
|
// Reenable scripts
|
|
jQuery.map( scripts, restoreScript );
|
|
|
|
// Evaluate executable scripts on first document insertion
|
|
for ( i = 0; i < hasScripts; i++ ) {
|
|
node = scripts[ i ];
|
|
if ( rscriptType.test( node.type || "" ) &&
|
|
!dataPriv.access( node, "globalEval" ) &&
|
|
jQuery.contains( doc, node ) ) {
|
|
|
|
if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
|
|
|
|
// Optional AJAX dependency, but won't run scripts if not present
|
|
if ( jQuery._evalUrl && !node.noModule ) {
|
|
jQuery._evalUrl( node.src, {
|
|
nonce: node.nonce || node.getAttribute( "nonce" )
|
|
} );
|
|
}
|
|
} else {
|
|
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return collection;
|
|
}
|
|
|
|
function remove( elem, selector, keepData ) {
|
|
var node,
|
|
nodes = selector ? jQuery.filter( selector, elem ) : elem,
|
|
i = 0;
|
|
|
|
for ( ; ( node = nodes[ i ] ) != null; i++ ) {
|
|
if ( !keepData && node.nodeType === 1 ) {
|
|
jQuery.cleanData( getAll( node ) );
|
|
}
|
|
|
|
if ( node.parentNode ) {
|
|
if ( keepData && isAttached( node ) ) {
|
|
setGlobalEval( getAll( node, "script" ) );
|
|
}
|
|
node.parentNode.removeChild( node );
|
|
}
|
|
}
|
|
|
|
return elem;
|
|
}
|
|
|
|
jQuery.extend( {
|
|
htmlPrefilter: function( html ) {
|
|
return html.replace( rxhtmlTag, "<$1></$2>" );
|
|
},
|
|
|
|
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
|
|
var i, l, srcElements, destElements,
|
|
clone = elem.cloneNode( true ),
|
|
inPage = isAttached( elem );
|
|
|
|
// Fix IE cloning issues
|
|
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
|
|
!jQuery.isXMLDoc( elem ) ) {
|
|
|
|
// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
|
|
destElements = getAll( clone );
|
|
srcElements = getAll( elem );
|
|
|
|
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
|
fixInput( srcElements[ i ], destElements[ i ] );
|
|
}
|
|
}
|
|
|
|
// Copy the events from the original to the clone
|
|
if ( dataAndEvents ) {
|
|
if ( deepDataAndEvents ) {
|
|
srcElements = srcElements || getAll( elem );
|
|
destElements = destElements || getAll( clone );
|
|
|
|
for ( i = 0, l = srcElements.length; i < l; i++ ) {
|
|
cloneCopyEvent( srcElements[ i ], destElements[ i ] );
|
|
}
|
|
} else {
|
|
cloneCopyEvent( elem, clone );
|
|
}
|
|
}
|
|
|
|
// Preserve script evaluation history
|
|
destElements = getAll( clone, "script" );
|
|
if ( destElements.length > 0 ) {
|
|
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
|
|
}
|
|
|
|
// Return the cloned set
|
|
return clone;
|
|
},
|
|
|
|
cleanData: function( elems ) {
|
|
var data, elem, type,
|
|
special = jQuery.event.special,
|
|
i = 0;
|
|
|
|
for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
|
|
if ( acceptData( elem ) ) {
|
|
if ( ( data = elem[ dataPriv.expando ] ) ) {
|
|
if ( data.events ) {
|
|
for ( type in data.events ) {
|
|
if ( special[ type ] ) {
|
|
jQuery.event.remove( elem, type );
|
|
|
|
// This is a shortcut to avoid jQuery.event.remove's overhead
|
|
} else {
|
|
jQuery.removeEvent( elem, type, data.handle );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Support: Chrome <=35 - 45+
|
|
// Assign undefined instead of using delete, see Data#remove
|
|
elem[ dataPriv.expando ] = undefined;
|
|
}
|
|
if ( elem[ dataUser.expando ] ) {
|
|
|
|
// Support: Chrome <=35 - 45+
|
|
// Assign undefined instead of using delete, see Data#remove
|
|
elem[ dataUser.expando ] = undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
detach: function( selector ) {
|
|
return remove( this, selector, true );
|
|
},
|
|
|
|
remove: function( selector ) {
|
|
return remove( this, selector );
|
|
},
|
|
|
|
text: function( value ) {
|
|
return access( this, function( value ) {
|
|
return value === undefined ?
|
|
jQuery.text( this ) :
|
|
this.empty().each( function() {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
this.textContent = value;
|
|
}
|
|
} );
|
|
}, null, value, arguments.length );
|
|
},
|
|
|
|
append: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
var target = manipulationTarget( this, elem );
|
|
target.appendChild( elem );
|
|
}
|
|
} );
|
|
},
|
|
|
|
prepend: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
|
|
var target = manipulationTarget( this, elem );
|
|
target.insertBefore( elem, target.firstChild );
|
|
}
|
|
} );
|
|
},
|
|
|
|
before: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.parentNode ) {
|
|
this.parentNode.insertBefore( elem, this );
|
|
}
|
|
} );
|
|
},
|
|
|
|
after: function() {
|
|
return domManip( this, arguments, function( elem ) {
|
|
if ( this.parentNode ) {
|
|
this.parentNode.insertBefore( elem, this.nextSibling );
|
|
}
|
|
} );
|
|
},
|
|
|
|
empty: function() {
|
|
var elem,
|
|
i = 0;
|
|
|
|
for ( ; ( elem = this[ i ] ) != null; i++ ) {
|
|
if ( elem.nodeType === 1 ) {
|
|
|
|
// Prevent memory leaks
|
|
jQuery.cleanData( getAll( elem, false ) );
|
|
|
|
// Remove any remaining nodes
|
|
elem.textContent = "";
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
clone: function( dataAndEvents, deepDataAndEvents ) {
|
|
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
|
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
|
|
|
return this.map( function() {
|
|
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
|
|
} );
|
|
},
|
|
|
|
html: function( value ) {
|
|
return access( this, function( value ) {
|
|
var elem = this[ 0 ] || {},
|
|
i = 0,
|
|
l = this.length;
|
|
|
|
if ( value === undefined && elem.nodeType === 1 ) {
|
|
return elem.innerHTML;
|
|
}
|
|
|
|
// See if we can take a shortcut and just use innerHTML
|
|
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
|
|
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
|
|
|
|
value = jQuery.htmlPrefilter( value );
|
|
|
|
try {
|
|
for ( ; i < l; i++ ) {
|
|
elem = this[ i ] || {};
|
|
|
|
// Remove element nodes and prevent memory leaks
|
|
if ( elem.nodeType === 1 ) {
|
|
jQuery.cleanData( getAll( elem, false ) );
|
|
elem.innerHTML = value;
|
|
}
|
|
}
|
|
|
|
elem = 0;
|
|
|
|
// If using innerHTML throws an exception, use the fallback method
|
|
} catch ( e ) {}
|
|
}
|
|
|
|
if ( elem ) {
|
|
this.empty().append( value );
|
|
}
|
|
}, null, value, arguments.length );
|
|
},
|
|
|
|
replaceWith: function() {
|
|
var ignored = [];
|
|
|
|
// Make the changes, replacing each non-ignored context element with the new content
|
|
return domManip( this, arguments, function( elem ) {
|
|
var parent = this.parentNode;
|
|
|
|
if ( jQuery.inArray( this, ignored ) < 0 ) {
|
|
jQuery.cleanData( getAll( this ) );
|
|
if ( parent ) {
|
|
parent.replaceChild( elem, this );
|
|
}
|
|
}
|
|
|
|
// Force callback invocation
|
|
}, ignored );
|
|
}
|
|
} );
|
|
|
|
jQuery.each( {
|
|
appendTo: "append",
|
|
prependTo: "prepend",
|
|
insertBefore: "before",
|
|
insertAfter: "after",
|
|
replaceAll: "replaceWith"
|
|
}, function( name, original ) {
|
|
jQuery.fn[ name ] = function( selector ) {
|
|
var elems,
|
|
ret = [],
|
|
insert = jQuery( selector ),
|
|
last = insert.length - 1,
|
|
i = 0;
|
|
|
|
for ( ; i <= last; i++ ) {
|
|
elems = i === last ? this : this.clone( true );
|
|
jQuery( insert[ i ] )[ original ]( elems );
|
|
|
|
// Support: Android <=4.0 only, PhantomJS 1 only
|
|
// .get() because push.apply(_, arraylike) throws on ancient WebKit
|
|
push.apply( ret, elems.get() );
|
|
}
|
|
|
|
return this.pushStack( ret );
|
|
};
|
|
} );
|
|
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
|
|
|
|
var getStyles = function( elem ) {
|
|
|
|
// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
|
|
// IE throws on elements created in popups
|
|
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
|
|
var view = elem.ownerDocument.defaultView;
|
|
|
|
if ( !view || !view.opener ) {
|
|
view = window;
|
|
}
|
|
|
|
return view.getComputedStyle( elem );
|
|
};
|
|
|
|
var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
|
|
|
|
|
|
|
|
( function() {
|
|
|
|
// Executing both pixelPosition & boxSizingReliable tests require only one layout
|
|
// so they're executed at the same time to save the second computation.
|
|
function computeStyleTests() {
|
|
|
|
// This is a singleton, we need to execute it only once
|
|
if ( !div ) {
|
|
return;
|
|
}
|
|
|
|
container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
|
|
"margin-top:1px;padding:0;border:0";
|
|
div.style.cssText =
|
|
"position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
|
|
"margin:auto;border:1px;padding:1px;" +
|
|
"width:60%;top:1%";
|
|
documentElement.appendChild( container ).appendChild( div );
|
|
|
|
var divStyle = window.getComputedStyle( div );
|
|
pixelPositionVal = divStyle.top !== "1%";
|
|
|
|
// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
|
|
reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
|
|
|
|
// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
|
|
// Some styles come back with percentage values, even though they shouldn't
|
|
div.style.right = "60%";
|
|
pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
|
|
|
|
// Support: IE 9 - 11 only
|
|
// Detect misreporting of content dimensions for box-sizing:border-box elements
|
|
boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
|
|
|
|
// Support: IE 9 only
|
|
// Detect overflow:scroll screwiness (gh-3699)
|
|
// Support: Chrome <=64
|
|
// Don't get tricked when zoom affects offsetWidth (gh-4029)
|
|
div.style.position = "absolute";
|
|
scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
|
|
|
|
documentElement.removeChild( container );
|
|
|
|
// Nullify the div so it wouldn't be stored in the memory and
|
|
// it will also be a sign that checks already performed
|
|
div = null;
|
|
}
|
|
|
|
function roundPixelMeasures( measure ) {
|
|
return Math.round( parseFloat( measure ) );
|
|
}
|
|
|
|
var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
|
|
reliableMarginLeftVal,
|
|
container = document.createElement( "div" ),
|
|
div = document.createElement( "div" );
|
|
|
|
// Finish early in limited (non-browser) environments
|
|
if ( !div.style ) {
|
|
return;
|
|
}
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// Style of cloned element affects source element cloned (#8908)
|
|
div.style.backgroundClip = "content-box";
|
|
div.cloneNode( true ).style.backgroundClip = "";
|
|
support.clearCloneStyle = div.style.backgroundClip === "content-box";
|
|
|
|
jQuery.extend( support, {
|
|
boxSizingReliable: function() {
|
|
computeStyleTests();
|
|
return boxSizingReliableVal;
|
|
},
|
|
pixelBoxStyles: function() {
|
|
computeStyleTests();
|
|
return pixelBoxStylesVal;
|
|
},
|
|
pixelPosition: function() {
|
|
computeStyleTests();
|
|
return pixelPositionVal;
|
|
},
|
|
reliableMarginLeft: function() {
|
|
computeStyleTests();
|
|
return reliableMarginLeftVal;
|
|
},
|
|
scrollboxSize: function() {
|
|
computeStyleTests();
|
|
return scrollboxSizeVal;
|
|
}
|
|
} );
|
|
} )();
|
|
|
|
|
|
function curCSS( elem, name, computed ) {
|
|
var width, minWidth, maxWidth, ret,
|
|
|
|
// Support: Firefox 51+
|
|
// Retrieving style before computed somehow
|
|
// fixes an issue with getting wrong values
|
|
// on detached elements
|
|
style = elem.style;
|
|
|
|
computed = computed || getStyles( elem );
|
|
|
|
// getPropertyValue is needed for:
|
|
// .css('filter') (IE 9 only, #12537)
|
|
// .css('--customProperty) (#3144)
|
|
if ( computed ) {
|
|
ret = computed.getPropertyValue( name ) || computed[ name ];
|
|
|
|
if ( ret === "" && !isAttached( elem ) ) {
|
|
ret = jQuery.style( elem, name );
|
|
}
|
|
|
|
// A tribute to the "awesome hack by Dean Edwards"
|
|
// Android Browser returns percentage for some values,
|
|
// but width seems to be reliably pixels.
|
|
// This is against the CSSOM draft spec:
|
|
// https://drafts.csswg.org/cssom/#resolved-values
|
|
if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
|
|
|
|
// Remember the original values
|
|
width = style.width;
|
|
minWidth = style.minWidth;
|
|
maxWidth = style.maxWidth;
|
|
|
|
// Put in the new values to get a computed value out
|
|
style.minWidth = style.maxWidth = style.width = ret;
|
|
ret = computed.width;
|
|
|
|
// Revert the changed values
|
|
style.width = width;
|
|
style.minWidth = minWidth;
|
|
style.maxWidth = maxWidth;
|
|
}
|
|
}
|
|
|
|
return ret !== undefined ?
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// IE returns zIndex value as an integer.
|
|
ret + "" :
|
|
ret;
|
|
}
|
|
|
|
|
|
function addGetHookIf( conditionFn, hookFn ) {
|
|
|
|
// Define the hook, we'll check on the first run if it's really needed.
|
|
return {
|
|
get: function() {
|
|
if ( conditionFn() ) {
|
|
|
|
// Hook not needed (or it's not possible to use it due
|
|
// to missing dependency), remove it.
|
|
delete this.get;
|
|
return;
|
|
}
|
|
|
|
// Hook needed; redefine it so that the support test is not executed again.
|
|
return ( this.get = hookFn ).apply( this, arguments );
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
var cssPrefixes = [ "Webkit", "Moz", "ms" ],
|
|
emptyStyle = document.createElement( "div" ).style,
|
|
vendorProps = {};
|
|
|
|
// Return a vendor-prefixed property or undefined
|
|
function vendorPropName( name ) {
|
|
|
|
// Check for vendor prefixed names
|
|
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
|
|
i = cssPrefixes.length;
|
|
|
|
while ( i-- ) {
|
|
name = cssPrefixes[ i ] + capName;
|
|
if ( name in emptyStyle ) {
|
|
return name;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
|
|
function finalPropName( name ) {
|
|
var final = jQuery.cssProps[ name ] || vendorProps[ name ];
|
|
|
|
if ( final ) {
|
|
return final;
|
|
}
|
|
if ( name in emptyStyle ) {
|
|
return name;
|
|
}
|
|
return vendorProps[ name ] = vendorPropName( name ) || name;
|
|
}
|
|
|
|
|
|
var
|
|
|
|
// Swappable if display is none or starts with table
|
|
// except "table", "table-cell", or "table-caption"
|
|
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
|
|
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
|
|
rcustomProp = /^--/,
|
|
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
|
|
cssNormalTransform = {
|
|
letterSpacing: "0",
|
|
fontWeight: "400"
|
|
};
|
|
|
|
function setPositiveNumber( elem, value, subtract ) {
|
|
|
|
// Any relative (+/-) values have already been
|
|
// normalized at this point
|
|
var matches = rcssNum.exec( value );
|
|
return matches ?
|
|
|
|
// Guard against undefined "subtract", e.g., when used as in cssHooks
|
|
Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
|
|
value;
|
|
}
|
|
|
|
function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
|
|
var i = dimension === "width" ? 1 : 0,
|
|
extra = 0,
|
|
delta = 0;
|
|
|
|
// Adjustment may not be necessary
|
|
if ( box === ( isBorderBox ? "border" : "content" ) ) {
|
|
return 0;
|
|
}
|
|
|
|
for ( ; i < 4; i += 2 ) {
|
|
|
|
// Both box models exclude margin
|
|
if ( box === "margin" ) {
|
|
delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
|
|
}
|
|
|
|
// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
|
|
if ( !isBorderBox ) {
|
|
|
|
// Add padding
|
|
delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
|
|
|
// For "border" or "margin", add border
|
|
if ( box !== "padding" ) {
|
|
delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
|
|
// But still keep track of it otherwise
|
|
} else {
|
|
extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
}
|
|
|
|
// If we get here with a border-box (content + padding + border), we're seeking "content" or
|
|
// "padding" or "margin"
|
|
} else {
|
|
|
|
// For "content", subtract padding
|
|
if ( box === "content" ) {
|
|
delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
|
|
}
|
|
|
|
// For "content" or "padding", subtract border
|
|
if ( box !== "margin" ) {
|
|
delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Account for positive content-box scroll gutter when requested by providing computedVal
|
|
if ( !isBorderBox && computedVal >= 0 ) {
|
|
|
|
// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
|
|
// Assuming integer scroll gutter, subtract the rest and round down
|
|
delta += Math.max( 0, Math.ceil(
|
|
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
|
|
computedVal -
|
|
delta -
|
|
extra -
|
|
0.5
|
|
|
|
// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
|
|
// Use an explicit zero to avoid NaN (gh-3964)
|
|
) ) || 0;
|
|
}
|
|
|
|
return delta;
|
|
}
|
|
|
|
function getWidthOrHeight( elem, dimension, extra ) {
|
|
|
|
// Start with computed style
|
|
var styles = getStyles( elem ),
|
|
|
|
// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
|
|
// Fake content-box until we know it's needed to know the true value.
|
|
boxSizingNeeded = !support.boxSizingReliable() || extra,
|
|
isBorderBox = boxSizingNeeded &&
|
|
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
|
|
valueIsBorderBox = isBorderBox,
|
|
|
|
val = curCSS( elem, dimension, styles ),
|
|
offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
|
|
|
|
// Support: Firefox <=54
|
|
// Return a confounding non-pixel value or feign ignorance, as appropriate.
|
|
if ( rnumnonpx.test( val ) ) {
|
|
if ( !extra ) {
|
|
return val;
|
|
}
|
|
val = "auto";
|
|
}
|
|
|
|
|
|
// Fall back to offsetWidth/offsetHeight when value is "auto"
|
|
// This happens for inline elements with no explicit setting (gh-3571)
|
|
// Support: Android <=4.1 - 4.3 only
|
|
// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
|
|
// Support: IE 9-11 only
|
|
// Also use offsetWidth/offsetHeight for when box sizing is unreliable
|
|
// We use getClientRects() to check for hidden/disconnected.
|
|
// In those cases, the computed value can be trusted to be border-box
|
|
if ( ( !support.boxSizingReliable() && isBorderBox ||
|
|
val === "auto" ||
|
|
!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
|
|
elem.getClientRects().length ) {
|
|
|
|
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
|
|
|
|
// Where available, offsetWidth/offsetHeight approximate border box dimensions.
|
|
// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
|
|
// retrieved value as a content box dimension.
|
|
valueIsBorderBox = offsetProp in elem;
|
|
if ( valueIsBorderBox ) {
|
|
val = elem[ offsetProp ];
|
|
}
|
|
}
|
|
|
|
// Normalize "" and auto
|
|
val = parseFloat( val ) || 0;
|
|
|
|
// Adjust for the element's box model
|
|
return ( val +
|
|
boxModelAdjustment(
|
|
elem,
|
|
dimension,
|
|
extra || ( isBorderBox ? "border" : "content" ),
|
|
valueIsBorderBox,
|
|
styles,
|
|
|
|
// Provide the current computed size to request scroll gutter calculation (gh-3589)
|
|
val
|
|
)
|
|
) + "px";
|
|
}
|
|
|
|
jQuery.extend( {
|
|
|
|
// Add in style property hooks for overriding the default
|
|
// behavior of getting and setting a style property
|
|
cssHooks: {
|
|
opacity: {
|
|
get: function( elem, computed ) {
|
|
if ( computed ) {
|
|
|
|
// We should always get a number back from opacity
|
|
var ret = curCSS( elem, "opacity" );
|
|
return ret === "" ? "1" : ret;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// Don't automatically add "px" to these possibly-unitless properties
|
|
cssNumber: {
|
|
"animationIterationCount": true,
|
|
"columnCount": true,
|
|
"fillOpacity": true,
|
|
"flexGrow": true,
|
|
"flexShrink": true,
|
|
"fontWeight": true,
|
|
"gridArea": true,
|
|
"gridColumn": true,
|
|
"gridColumnEnd": true,
|
|
"gridColumnStart": true,
|
|
"gridRow": true,
|
|
"gridRowEnd": true,
|
|
"gridRowStart": true,
|
|
"lineHeight": true,
|
|
"opacity": true,
|
|
"order": true,
|
|
"orphans": true,
|
|
"widows": true,
|
|
"zIndex": true,
|
|
"zoom": true
|
|
},
|
|
|
|
// Add in properties whose names you wish to fix before
|
|
// setting or getting the value
|
|
cssProps: {},
|
|
|
|
// Get and set the style property on a DOM Node
|
|
style: function( elem, name, value, extra ) {
|
|
|
|
// Don't set styles on text and comment nodes
|
|
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
|
|
return;
|
|
}
|
|
|
|
// Make sure that we're working with the right name
|
|
var ret, type, hooks,
|
|
origName = camelCase( name ),
|
|
isCustomProp = rcustomProp.test( name ),
|
|
style = elem.style;
|
|
|
|
// Make sure that we're working with the right name. We don't
|
|
// want to query the value if it is a CSS custom property
|
|
// since they are user-defined.
|
|
if ( !isCustomProp ) {
|
|
name = finalPropName( origName );
|
|
}
|
|
|
|
// Gets hook for the prefixed version, then unprefixed version
|
|
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
|
|
|
// Check if we're setting a value
|
|
if ( value !== undefined ) {
|
|
type = typeof value;
|
|
|
|
// Convert "+=" or "-=" to relative numbers (#7345)
|
|
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
|
|
value = adjustCSS( elem, name, ret );
|
|
|
|
// Fixes bug #9237
|
|
type = "number";
|
|
}
|
|
|
|
// Make sure that null and NaN values aren't set (#7116)
|
|
if ( value == null || value !== value ) {
|
|
return;
|
|
}
|
|
|
|
// If a number was passed in, add the unit (except for certain CSS properties)
|
|
// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
|
|
// "px" to a few hardcoded values.
|
|
if ( type === "number" && !isCustomProp ) {
|
|
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
|
|
}
|
|
|
|
// background-* props affect original clone's values
|
|
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
|
|
style[ name ] = "inherit";
|
|
}
|
|
|
|
// If a hook was provided, use that value, otherwise just set the specified value
|
|
if ( !hooks || !( "set" in hooks ) ||
|
|
( value = hooks.set( elem, value, extra ) ) !== undefined ) {
|
|
|
|
if ( isCustomProp ) {
|
|
style.setProperty( name, value );
|
|
} else {
|
|
style[ name ] = value;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
// If a hook was provided get the non-computed value from there
|
|
if ( hooks && "get" in hooks &&
|
|
( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
|
|
|
|
return ret;
|
|
}
|
|
|
|
// Otherwise just get the value from the style object
|
|
return style[ name ];
|
|
}
|
|
},
|
|
|
|
css: function( elem, name, extra, styles ) {
|
|
var val, num, hooks,
|
|
origName = camelCase( name ),
|
|
isCustomProp = rcustomProp.test( name );
|
|
|
|
// Make sure that we're working with the right name. We don't
|
|
// want to modify the value if it is a CSS custom property
|
|
// since they are user-defined.
|
|
if ( !isCustomProp ) {
|
|
name = finalPropName( origName );
|
|
}
|
|
|
|
// Try prefixed name followed by the unprefixed name
|
|
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
|
|
|
|
// If a hook was provided get the computed value from there
|
|
if ( hooks && "get" in hooks ) {
|
|
val = hooks.get( elem, true, extra );
|
|
}
|
|
|
|
// Otherwise, if a way to get the computed value exists, use that
|
|
if ( val === undefined ) {
|
|
val = curCSS( elem, name, styles );
|
|
}
|
|
|
|
// Convert "normal" to computed value
|
|
if ( val === "normal" && name in cssNormalTransform ) {
|
|
val = cssNormalTransform[ name ];
|
|
}
|
|
|
|
// Make numeric if forced or a qualifier was provided and val looks numeric
|
|
if ( extra === "" || extra ) {
|
|
num = parseFloat( val );
|
|
return extra === true || isFinite( num ) ? num || 0 : val;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
} );
|
|
|
|
jQuery.each( [ "height", "width" ], function( i, dimension ) {
|
|
jQuery.cssHooks[ dimension ] = {
|
|
get: function( elem, computed, extra ) {
|
|
if ( computed ) {
|
|
|
|
// Certain elements can have dimension info if we invisibly show them
|
|
// but it must have a current display style that would benefit
|
|
return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
|
|
|
|
// Support: Safari 8+
|
|
// Table columns in Safari have non-zero offsetWidth & zero
|
|
// getBoundingClientRect().width unless display is changed.
|
|
// Support: IE <=11 only
|
|
// Running getBoundingClientRect on a disconnected node
|
|
// in IE throws an error.
|
|
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
|
|
swap( elem, cssShow, function() {
|
|
return getWidthOrHeight( elem, dimension, extra );
|
|
} ) :
|
|
getWidthOrHeight( elem, dimension, extra );
|
|
}
|
|
},
|
|
|
|
set: function( elem, value, extra ) {
|
|
var matches,
|
|
styles = getStyles( elem ),
|
|
|
|
// Only read styles.position if the test has a chance to fail
|
|
// to avoid forcing a reflow.
|
|
scrollboxSizeBuggy = !support.scrollboxSize() &&
|
|
styles.position === "absolute",
|
|
|
|
// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
|
|
boxSizingNeeded = scrollboxSizeBuggy || extra,
|
|
isBorderBox = boxSizingNeeded &&
|
|
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
|
|
subtract = extra ?
|
|
boxModelAdjustment(
|
|
elem,
|
|
dimension,
|
|
extra,
|
|
isBorderBox,
|
|
styles
|
|
) :
|
|
0;
|
|
|
|
// Account for unreliable border-box dimensions by comparing offset* to computed and
|
|
// faking a content-box to get border and padding (gh-3699)
|
|
if ( isBorderBox && scrollboxSizeBuggy ) {
|
|
subtract -= Math.ceil(
|
|
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
|
|
parseFloat( styles[ dimension ] ) -
|
|
boxModelAdjustment( elem, dimension, "border", false, styles ) -
|
|
0.5
|
|
);
|
|
}
|
|
|
|
// Convert to pixels if value adjustment is needed
|
|
if ( subtract && ( matches = rcssNum.exec( value ) ) &&
|
|
( matches[ 3 ] || "px" ) !== "px" ) {
|
|
|
|
elem.style[ dimension ] = value;
|
|
value = jQuery.css( elem, dimension );
|
|
}
|
|
|
|
return setPositiveNumber( elem, value, subtract );
|
|
}
|
|
};
|
|
} );
|
|
|
|
jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
|
|
function( elem, computed ) {
|
|
if ( computed ) {
|
|
return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
|
|
elem.getBoundingClientRect().left -
|
|
swap( elem, { marginLeft: 0 }, function() {
|
|
return elem.getBoundingClientRect().left;
|
|
} )
|
|
) + "px";
|
|
}
|
|
}
|
|
);
|
|
|
|
// These hooks are used by animate to expand properties
|
|
jQuery.each( {
|
|
margin: "",
|
|
padding: "",
|
|
border: "Width"
|
|
}, function( prefix, suffix ) {
|
|
jQuery.cssHooks[ prefix + suffix ] = {
|
|
expand: function( value ) {
|
|
var i = 0,
|
|
expanded = {},
|
|
|
|
// Assumes a single number if not a string
|
|
parts = typeof value === "string" ? value.split( " " ) : [ value ];
|
|
|
|
for ( ; i < 4; i++ ) {
|
|
expanded[ prefix + cssExpand[ i ] + suffix ] =
|
|
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
|
|
}
|
|
|
|
return expanded;
|
|
}
|
|
};
|
|
|
|
if ( prefix !== "margin" ) {
|
|
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
|
|
}
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
css: function( name, value ) {
|
|
return access( this, function( elem, name, value ) {
|
|
var styles, len,
|
|
map = {},
|
|
i = 0;
|
|
|
|
if ( Array.isArray( name ) ) {
|
|
styles = getStyles( elem );
|
|
len = name.length;
|
|
|
|
for ( ; i < len; i++ ) {
|
|
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
return value !== undefined ?
|
|
jQuery.style( elem, name, value ) :
|
|
jQuery.css( elem, name );
|
|
}, name, value, arguments.length > 1 );
|
|
}
|
|
} );
|
|
|
|
|
|
function Tween( elem, options, prop, end, easing ) {
|
|
return new Tween.prototype.init( elem, options, prop, end, easing );
|
|
}
|
|
jQuery.Tween = Tween;
|
|
|
|
Tween.prototype = {
|
|
constructor: Tween,
|
|
init: function( elem, options, prop, end, easing, unit ) {
|
|
this.elem = elem;
|
|
this.prop = prop;
|
|
this.easing = easing || jQuery.easing._default;
|
|
this.options = options;
|
|
this.start = this.now = this.cur();
|
|
this.end = end;
|
|
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
|
|
},
|
|
cur: function() {
|
|
var hooks = Tween.propHooks[ this.prop ];
|
|
|
|
return hooks && hooks.get ?
|
|
hooks.get( this ) :
|
|
Tween.propHooks._default.get( this );
|
|
},
|
|
run: function( percent ) {
|
|
var eased,
|
|
hooks = Tween.propHooks[ this.prop ];
|
|
|
|
if ( this.options.duration ) {
|
|
this.pos = eased = jQuery.easing[ this.easing ](
|
|
percent, this.options.duration * percent, 0, 1, this.options.duration
|
|
);
|
|
} else {
|
|
this.pos = eased = percent;
|
|
}
|
|
this.now = ( this.end - this.start ) * eased + this.start;
|
|
|
|
if ( this.options.step ) {
|
|
this.options.step.call( this.elem, this.now, this );
|
|
}
|
|
|
|
if ( hooks && hooks.set ) {
|
|
hooks.set( this );
|
|
} else {
|
|
Tween.propHooks._default.set( this );
|
|
}
|
|
return this;
|
|
}
|
|
};
|
|
|
|
Tween.prototype.init.prototype = Tween.prototype;
|
|
|
|
Tween.propHooks = {
|
|
_default: {
|
|
get: function( tween ) {
|
|
var result;
|
|
|
|
// Use a property on the element directly when it is not a DOM element,
|
|
// or when there is no matching style property that exists.
|
|
if ( tween.elem.nodeType !== 1 ||
|
|
tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
|
|
return tween.elem[ tween.prop ];
|
|
}
|
|
|
|
// Passing an empty string as a 3rd parameter to .css will automatically
|
|
// attempt a parseFloat and fallback to a string if the parse fails.
|
|
// Simple values such as "10px" are parsed to Float;
|
|
// complex values such as "rotate(1rad)" are returned as-is.
|
|
result = jQuery.css( tween.elem, tween.prop, "" );
|
|
|
|
// Empty strings, null, undefined and "auto" are converted to 0.
|
|
return !result || result === "auto" ? 0 : result;
|
|
},
|
|
set: function( tween ) {
|
|
|
|
// Use step hook for back compat.
|
|
// Use cssHook if its there.
|
|
// Use .style if available and use plain properties where available.
|
|
if ( jQuery.fx.step[ tween.prop ] ) {
|
|
jQuery.fx.step[ tween.prop ]( tween );
|
|
} else if ( tween.elem.nodeType === 1 && (
|
|
jQuery.cssHooks[ tween.prop ] ||
|
|
tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
|
|
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
|
|
} else {
|
|
tween.elem[ tween.prop ] = tween.now;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Support: IE <=9 only
|
|
// Panic based approach to setting things on disconnected nodes
|
|
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
|
|
set: function( tween ) {
|
|
if ( tween.elem.nodeType && tween.elem.parentNode ) {
|
|
tween.elem[ tween.prop ] = tween.now;
|
|
}
|
|
}
|
|
};
|
|
|
|
jQuery.easing = {
|
|
linear: function( p ) {
|
|
return p;
|
|
},
|
|
swing: function( p ) {
|
|
return 0.5 - Math.cos( p * Math.PI ) / 2;
|
|
},
|
|
_default: "swing"
|
|
};
|
|
|
|
jQuery.fx = Tween.prototype.init;
|
|
|
|
// Back compat <1.8 extension point
|
|
jQuery.fx.step = {};
|
|
|
|
|
|
|
|
|
|
var
|
|
fxNow, inProgress,
|
|
rfxtypes = /^(?:toggle|show|hide)$/,
|
|
rrun = /queueHooks$/;
|
|
|
|
function schedule() {
|
|
if ( inProgress ) {
|
|
if ( document.hidden === false && window.requestAnimationFrame ) {
|
|
window.requestAnimationFrame( schedule );
|
|
} else {
|
|
window.setTimeout( schedule, jQuery.fx.interval );
|
|
}
|
|
|
|
jQuery.fx.tick();
|
|
}
|
|
}
|
|
|
|
// Animations created synchronously will run synchronously
|
|
function createFxNow() {
|
|
window.setTimeout( function() {
|
|
fxNow = undefined;
|
|
} );
|
|
return ( fxNow = Date.now() );
|
|
}
|
|
|
|
// Generate parameters to create a standard animation
|
|
function genFx( type, includeWidth ) {
|
|
var which,
|
|
i = 0,
|
|
attrs = { height: type };
|
|
|
|
// If we include width, step value is 1 to do all cssExpand values,
|
|
// otherwise step value is 2 to skip over Left and Right
|
|
includeWidth = includeWidth ? 1 : 0;
|
|
for ( ; i < 4; i += 2 - includeWidth ) {
|
|
which = cssExpand[ i ];
|
|
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
|
|
}
|
|
|
|
if ( includeWidth ) {
|
|
attrs.opacity = attrs.width = type;
|
|
}
|
|
|
|
return attrs;
|
|
}
|
|
|
|
function createTween( value, prop, animation ) {
|
|
var tween,
|
|
collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
|
|
index = 0,
|
|
length = collection.length;
|
|
for ( ; index < length; index++ ) {
|
|
if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
|
|
|
|
// We're done with this property
|
|
return tween;
|
|
}
|
|
}
|
|
}
|
|
|
|
function defaultPrefilter( elem, props, opts ) {
|
|
var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
|
|
isBox = "width" in props || "height" in props,
|
|
anim = this,
|
|
orig = {},
|
|
style = elem.style,
|
|
hidden = elem.nodeType && isHiddenWithinTree( elem ),
|
|
dataShow = dataPriv.get( elem, "fxshow" );
|
|
|
|
// Queue-skipping animations hijack the fx hooks
|
|
if ( !opts.queue ) {
|
|
hooks = jQuery._queueHooks( elem, "fx" );
|
|
if ( hooks.unqueued == null ) {
|
|
hooks.unqueued = 0;
|
|
oldfire = hooks.empty.fire;
|
|
hooks.empty.fire = function() {
|
|
if ( !hooks.unqueued ) {
|
|
oldfire();
|
|
}
|
|
};
|
|
}
|
|
hooks.unqueued++;
|
|
|
|
anim.always( function() {
|
|
|
|
// Ensure the complete handler is called before this completes
|
|
anim.always( function() {
|
|
hooks.unqueued--;
|
|
if ( !jQuery.queue( elem, "fx" ).length ) {
|
|
hooks.empty.fire();
|
|
}
|
|
} );
|
|
} );
|
|
}
|
|
|
|
// Detect show/hide animations
|
|
for ( prop in props ) {
|
|
value = props[ prop ];
|
|
if ( rfxtypes.test( value ) ) {
|
|
delete props[ prop ];
|
|
toggle = toggle || value === "toggle";
|
|
if ( value === ( hidden ? "hide" : "show" ) ) {
|
|
|
|
// Pretend to be hidden if this is a "show" and
|
|
// there is still data from a stopped show/hide
|
|
if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
|
|
hidden = true;
|
|
|
|
// Ignore all other no-op show/hide data
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
|
|
}
|
|
}
|
|
|
|
// Bail out if this is a no-op like .hide().hide()
|
|
propTween = !jQuery.isEmptyObject( props );
|
|
if ( !propTween && jQuery.isEmptyObject( orig ) ) {
|
|
return;
|
|
}
|
|
|
|
// Restrict "overflow" and "display" styles during box animations
|
|
if ( isBox && elem.nodeType === 1 ) {
|
|
|
|
// Support: IE <=9 - 11, Edge 12 - 15
|
|
// Record all 3 overflow attributes because IE does not infer the shorthand
|
|
// from identically-valued overflowX and overflowY and Edge just mirrors
|
|
// the overflowX value there.
|
|
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
|
|
|
|
// Identify a display type, preferring old show/hide data over the CSS cascade
|
|
restoreDisplay = dataShow && dataShow.display;
|
|
if ( restoreDisplay == null ) {
|
|
restoreDisplay = dataPriv.get( elem, "display" );
|
|
}
|
|
display = jQuery.css( elem, "display" );
|
|
if ( display === "none" ) {
|
|
if ( restoreDisplay ) {
|
|
display = restoreDisplay;
|
|
} else {
|
|
|
|
// Get nonempty value(s) by temporarily forcing visibility
|
|
showHide( [ elem ], true );
|
|
restoreDisplay = elem.style.display || restoreDisplay;
|
|
display = jQuery.css( elem, "display" );
|
|
showHide( [ elem ] );
|
|
}
|
|
}
|
|
|
|
// Animate inline elements as inline-block
|
|
if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
|
|
if ( jQuery.css( elem, "float" ) === "none" ) {
|
|
|
|
// Restore the original display value at the end of pure show/hide animations
|
|
if ( !propTween ) {
|
|
anim.done( function() {
|
|
style.display = restoreDisplay;
|
|
} );
|
|
if ( restoreDisplay == null ) {
|
|
display = style.display;
|
|
restoreDisplay = display === "none" ? "" : display;
|
|
}
|
|
}
|
|
style.display = "inline-block";
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( opts.overflow ) {
|
|
style.overflow = "hidden";
|
|
anim.always( function() {
|
|
style.overflow = opts.overflow[ 0 ];
|
|
style.overflowX = opts.overflow[ 1 ];
|
|
style.overflowY = opts.overflow[ 2 ];
|
|
} );
|
|
}
|
|
|
|
// Implement show/hide animations
|
|
propTween = false;
|
|
for ( prop in orig ) {
|
|
|
|
// General show/hide setup for this element animation
|
|
if ( !propTween ) {
|
|
if ( dataShow ) {
|
|
if ( "hidden" in dataShow ) {
|
|
hidden = dataShow.hidden;
|
|
}
|
|
} else {
|
|
dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
|
|
}
|
|
|
|
// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
|
|
if ( toggle ) {
|
|
dataShow.hidden = !hidden;
|
|
}
|
|
|
|
// Show elements before animating them
|
|
if ( hidden ) {
|
|
showHide( [ elem ], true );
|
|
}
|
|
|
|
/* eslint-disable no-loop-func */
|
|
|
|
anim.done( function() {
|
|
|
|
/* eslint-enable no-loop-func */
|
|
|
|
// The final step of a "hide" animation is actually hiding the element
|
|
if ( !hidden ) {
|
|
showHide( [ elem ] );
|
|
}
|
|
dataPriv.remove( elem, "fxshow" );
|
|
for ( prop in orig ) {
|
|
jQuery.style( elem, prop, orig[ prop ] );
|
|
}
|
|
} );
|
|
}
|
|
|
|
// Per-property setup
|
|
propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
|
|
if ( !( prop in dataShow ) ) {
|
|
dataShow[ prop ] = propTween.start;
|
|
if ( hidden ) {
|
|
propTween.end = propTween.start;
|
|
propTween.start = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function propFilter( props, specialEasing ) {
|
|
var index, name, easing, value, hooks;
|
|
|
|
// camelCase, specialEasing and expand cssHook pass
|
|
for ( index in props ) {
|
|
name = camelCase( index );
|
|
easing = specialEasing[ name ];
|
|
value = props[ index ];
|
|
if ( Array.isArray( value ) ) {
|
|
easing = value[ 1 ];
|
|
value = props[ index ] = value[ 0 ];
|
|
}
|
|
|
|
if ( index !== name ) {
|
|
props[ name ] = value;
|
|
delete props[ index ];
|
|
}
|
|
|
|
hooks = jQuery.cssHooks[ name ];
|
|
if ( hooks && "expand" in hooks ) {
|
|
value = hooks.expand( value );
|
|
delete props[ name ];
|
|
|
|
// Not quite $.extend, this won't overwrite existing keys.
|
|
// Reusing 'index' because we have the correct "name"
|
|
for ( index in value ) {
|
|
if ( !( index in props ) ) {
|
|
props[ index ] = value[ index ];
|
|
specialEasing[ index ] = easing;
|
|
}
|
|
}
|
|
} else {
|
|
specialEasing[ name ] = easing;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Animation( elem, properties, options ) {
|
|
var result,
|
|
stopped,
|
|
index = 0,
|
|
length = Animation.prefilters.length,
|
|
deferred = jQuery.Deferred().always( function() {
|
|
|
|
// Don't match elem in the :animated selector
|
|
delete tick.elem;
|
|
} ),
|
|
tick = function() {
|
|
if ( stopped ) {
|
|
return false;
|
|
}
|
|
var currentTime = fxNow || createFxNow(),
|
|
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
|
|
|
|
// Support: Android 2.3 only
|
|
// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
|
|
temp = remaining / animation.duration || 0,
|
|
percent = 1 - temp,
|
|
index = 0,
|
|
length = animation.tweens.length;
|
|
|
|
for ( ; index < length; index++ ) {
|
|
animation.tweens[ index ].run( percent );
|
|
}
|
|
|
|
deferred.notifyWith( elem, [ animation, percent, remaining ] );
|
|
|
|
// If there's more to do, yield
|
|
if ( percent < 1 && length ) {
|
|
return remaining;
|
|
}
|
|
|
|
// If this was an empty animation, synthesize a final progress notification
|
|
if ( !length ) {
|
|
deferred.notifyWith( elem, [ animation, 1, 0 ] );
|
|
}
|
|
|
|
// Resolve the animation and report its conclusion
|
|
deferred.resolveWith( elem, [ animation ] );
|
|
return false;
|
|
},
|
|
animation = deferred.promise( {
|
|
elem: elem,
|
|
props: jQuery.extend( {}, properties ),
|
|
opts: jQuery.extend( true, {
|
|
specialEasing: {},
|
|
easing: jQuery.easing._default
|
|
}, options ),
|
|
originalProperties: properties,
|
|
originalOptions: options,
|
|
startTime: fxNow || createFxNow(),
|
|
duration: options.duration,
|
|
tweens: [],
|
|
createTween: function( prop, end ) {
|
|
var tween = jQuery.Tween( elem, animation.opts, prop, end,
|
|
animation.opts.specialEasing[ prop ] || animation.opts.easing );
|
|
animation.tweens.push( tween );
|
|
return tween;
|
|
},
|
|
stop: function( gotoEnd ) {
|
|
var index = 0,
|
|
|
|
// If we are going to the end, we want to run all the tweens
|
|
// otherwise we skip this part
|
|
length = gotoEnd ? animation.tweens.length : 0;
|
|
if ( stopped ) {
|
|
return this;
|
|
}
|
|
stopped = true;
|
|
for ( ; index < length; index++ ) {
|
|
animation.tweens[ index ].run( 1 );
|
|
}
|
|
|
|
// Resolve when we played the last frame; otherwise, reject
|
|
if ( gotoEnd ) {
|
|
deferred.notifyWith( elem, [ animation, 1, 0 ] );
|
|
deferred.resolveWith( elem, [ animation, gotoEnd ] );
|
|
} else {
|
|
deferred.rejectWith( elem, [ animation, gotoEnd ] );
|
|
}
|
|
return this;
|
|
}
|
|
} ),
|
|
props = animation.props;
|
|
|
|
propFilter( props, animation.opts.specialEasing );
|
|
|
|
for ( ; index < length; index++ ) {
|
|
result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
|
|
if ( result ) {
|
|
if ( isFunction( result.stop ) ) {
|
|
jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
|
|
result.stop.bind( result );
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
jQuery.map( props, createTween, animation );
|
|
|
|
if ( isFunction( animation.opts.start ) ) {
|
|
animation.opts.start.call( elem, animation );
|
|
}
|
|
|
|
// Attach callbacks from options
|
|
animation
|
|
.progress( animation.opts.progress )
|
|
.done( animation.opts.done, animation.opts.complete )
|
|
.fail( animation.opts.fail )
|
|
.always( animation.opts.always );
|
|
|
|
jQuery.fx.timer(
|
|
jQuery.extend( tick, {
|
|
elem: elem,
|
|
anim: animation,
|
|
queue: animation.opts.queue
|
|
} )
|
|
);
|
|
|
|
return animation;
|
|
}
|
|
|
|
jQuery.Animation = jQuery.extend( Animation, {
|
|
|
|
tweeners: {
|
|
"*": [ function( prop, value ) {
|
|
var tween = this.createTween( prop, value );
|
|
adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
|
|
return tween;
|
|
} ]
|
|
},
|
|
|
|
tweener: function( props, callback ) {
|
|
if ( isFunction( props ) ) {
|
|
callback = props;
|
|
props = [ "*" ];
|
|
} else {
|
|
props = props.match( rnothtmlwhite );
|
|
}
|
|
|
|
var prop,
|
|
index = 0,
|
|
length = props.length;
|
|
|
|
for ( ; index < length; index++ ) {
|
|
prop = props[ index ];
|
|
Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
|
|
Animation.tweeners[ prop ].unshift( callback );
|
|
}
|
|
},
|
|
|
|
prefilters: [ defaultPrefilter ],
|
|
|
|
prefilter: function( callback, prepend ) {
|
|
if ( prepend ) {
|
|
Animation.prefilters.unshift( callback );
|
|
} else {
|
|
Animation.prefilters.push( callback );
|
|
}
|
|
}
|
|
} );
|
|
|
|
jQuery.speed = function( speed, easing, fn ) {
|
|
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
|
|
complete: fn || !fn && easing ||
|
|
isFunction( speed ) && speed,
|
|
duration: speed,
|
|
easing: fn && easing || easing && !isFunction( easing ) && easing
|
|
};
|
|
|
|
// Go to the end state if fx are off
|
|
if ( jQuery.fx.off ) {
|
|
opt.duration = 0;
|
|
|
|
} else {
|
|
if ( typeof opt.duration !== "number" ) {
|
|
if ( opt.duration in jQuery.fx.speeds ) {
|
|
opt.duration = jQuery.fx.speeds[ opt.duration ];
|
|
|
|
} else {
|
|
opt.duration = jQuery.fx.speeds._default;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Normalize opt.queue - true/undefined/null -> "fx"
|
|
if ( opt.queue == null || opt.queue === true ) {
|
|
opt.queue = "fx";
|
|
}
|
|
|
|
// Queueing
|
|
opt.old = opt.complete;
|
|
|
|
opt.complete = function() {
|
|
if ( isFunction( opt.old ) ) {
|
|
opt.old.call( this );
|
|
}
|
|
|
|
if ( opt.queue ) {
|
|
jQuery.dequeue( this, opt.queue );
|
|
}
|
|
};
|
|
|
|
return opt;
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
fadeTo: function( speed, to, easing, callback ) {
|
|
|
|
// Show any hidden elements after setting opacity to 0
|
|
return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
|
|
|
|
// Animate to the value specified
|
|
.end().animate( { opacity: to }, speed, easing, callback );
|
|
},
|
|
animate: function( prop, speed, easing, callback ) {
|
|
var empty = jQuery.isEmptyObject( prop ),
|
|
optall = jQuery.speed( speed, easing, callback ),
|
|
doAnimation = function() {
|
|
|
|
// Operate on a copy of prop so per-property easing won't be lost
|
|
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
|
|
|
|
// Empty animations, or finishing resolves immediately
|
|
if ( empty || dataPriv.get( this, "finish" ) ) {
|
|
anim.stop( true );
|
|
}
|
|
};
|
|
doAnimation.finish = doAnimation;
|
|
|
|
return empty || optall.queue === false ?
|
|
this.each( doAnimation ) :
|
|
this.queue( optall.queue, doAnimation );
|
|
},
|
|
stop: function( type, clearQueue, gotoEnd ) {
|
|
var stopQueue = function( hooks ) {
|
|
var stop = hooks.stop;
|
|
delete hooks.stop;
|
|
stop( gotoEnd );
|
|
};
|
|
|
|
if ( typeof type !== "string" ) {
|
|
gotoEnd = clearQueue;
|
|
clearQueue = type;
|
|
type = undefined;
|
|
}
|
|
if ( clearQueue && type !== false ) {
|
|
this.queue( type || "fx", [] );
|
|
}
|
|
|
|
return this.each( function() {
|
|
var dequeue = true,
|
|
index = type != null && type + "queueHooks",
|
|
timers = jQuery.timers,
|
|
data = dataPriv.get( this );
|
|
|
|
if ( index ) {
|
|
if ( data[ index ] && data[ index ].stop ) {
|
|
stopQueue( data[ index ] );
|
|
}
|
|
} else {
|
|
for ( index in data ) {
|
|
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
|
|
stopQueue( data[ index ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( index = timers.length; index--; ) {
|
|
if ( timers[ index ].elem === this &&
|
|
( type == null || timers[ index ].queue === type ) ) {
|
|
|
|
timers[ index ].anim.stop( gotoEnd );
|
|
dequeue = false;
|
|
timers.splice( index, 1 );
|
|
}
|
|
}
|
|
|
|
// Start the next in the queue if the last step wasn't forced.
|
|
// Timers currently will call their complete callbacks, which
|
|
// will dequeue but only if they were gotoEnd.
|
|
if ( dequeue || !gotoEnd ) {
|
|
jQuery.dequeue( this, type );
|
|
}
|
|
} );
|
|
},
|
|
finish: function( type ) {
|
|
if ( type !== false ) {
|
|
type = type || "fx";
|
|
}
|
|
return this.each( function() {
|
|
var index,
|
|
data = dataPriv.get( this ),
|
|
queue = data[ type + "queue" ],
|
|
hooks = data[ type + "queueHooks" ],
|
|
timers = jQuery.timers,
|
|
length = queue ? queue.length : 0;
|
|
|
|
// Enable finishing flag on private data
|
|
data.finish = true;
|
|
|
|
// Empty the queue first
|
|
jQuery.queue( this, type, [] );
|
|
|
|
if ( hooks && hooks.stop ) {
|
|
hooks.stop.call( this, true );
|
|
}
|
|
|
|
// Look for any active animations, and finish them
|
|
for ( index = timers.length; index--; ) {
|
|
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
|
|
timers[ index ].anim.stop( true );
|
|
timers.splice( index, 1 );
|
|
}
|
|
}
|
|
|
|
// Look for any animations in the old queue and finish them
|
|
for ( index = 0; index < length; index++ ) {
|
|
if ( queue[ index ] && queue[ index ].finish ) {
|
|
queue[ index ].finish.call( this );
|
|
}
|
|
}
|
|
|
|
// Turn off finishing flag
|
|
delete data.finish;
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
|
|
var cssFn = jQuery.fn[ name ];
|
|
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
|
return speed == null || typeof speed === "boolean" ?
|
|
cssFn.apply( this, arguments ) :
|
|
this.animate( genFx( name, true ), speed, easing, callback );
|
|
};
|
|
} );
|
|
|
|
// Generate shortcuts for custom animations
|
|
jQuery.each( {
|
|
slideDown: genFx( "show" ),
|
|
slideUp: genFx( "hide" ),
|
|
slideToggle: genFx( "toggle" ),
|
|
fadeIn: { opacity: "show" },
|
|
fadeOut: { opacity: "hide" },
|
|
fadeToggle: { opacity: "toggle" }
|
|
}, function( name, props ) {
|
|
jQuery.fn[ name ] = function( speed, easing, callback ) {
|
|
return this.animate( props, speed, easing, callback );
|
|
};
|
|
} );
|
|
|
|
jQuery.timers = [];
|
|
jQuery.fx.tick = function() {
|
|
var timer,
|
|
i = 0,
|
|
timers = jQuery.timers;
|
|
|
|
fxNow = Date.now();
|
|
|
|
for ( ; i < timers.length; i++ ) {
|
|
timer = timers[ i ];
|
|
|
|
// Run the timer and safely remove it when done (allowing for external removal)
|
|
if ( !timer() && timers[ i ] === timer ) {
|
|
timers.splice( i--, 1 );
|
|
}
|
|
}
|
|
|
|
if ( !timers.length ) {
|
|
jQuery.fx.stop();
|
|
}
|
|
fxNow = undefined;
|
|
};
|
|
|
|
jQuery.fx.timer = function( timer ) {
|
|
jQuery.timers.push( timer );
|
|
jQuery.fx.start();
|
|
};
|
|
|
|
jQuery.fx.interval = 13;
|
|
jQuery.fx.start = function() {
|
|
if ( inProgress ) {
|
|
return;
|
|
}
|
|
|
|
inProgress = true;
|
|
schedule();
|
|
};
|
|
|
|
jQuery.fx.stop = function() {
|
|
inProgress = null;
|
|
};
|
|
|
|
jQuery.fx.speeds = {
|
|
slow: 600,
|
|
fast: 200,
|
|
|
|
// Default speed
|
|
_default: 400
|
|
};
|
|
|
|
|
|
// Based off of the plugin by Clint Helfers, with permission.
|
|
// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
|
|
jQuery.fn.delay = function( time, type ) {
|
|
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
|
|
type = type || "fx";
|
|
|
|
return this.queue( type, function( next, hooks ) {
|
|
var timeout = window.setTimeout( next, time );
|
|
hooks.stop = function() {
|
|
window.clearTimeout( timeout );
|
|
};
|
|
} );
|
|
};
|
|
|
|
|
|
( function() {
|
|
var input = document.createElement( "input" ),
|
|
select = document.createElement( "select" ),
|
|
opt = select.appendChild( document.createElement( "option" ) );
|
|
|
|
input.type = "checkbox";
|
|
|
|
// Support: Android <=4.3 only
|
|
// Default value for a checkbox should be "on"
|
|
support.checkOn = input.value !== "";
|
|
|
|
// Support: IE <=11 only
|
|
// Must access selectedIndex to make default options select
|
|
support.optSelected = opt.selected;
|
|
|
|
// Support: IE <=11 only
|
|
// An input loses its value after becoming a radio
|
|
input = document.createElement( "input" );
|
|
input.value = "t";
|
|
input.type = "radio";
|
|
support.radioValue = input.value === "t";
|
|
} )();
|
|
|
|
|
|
var boolHook,
|
|
attrHandle = jQuery.expr.attrHandle;
|
|
|
|
jQuery.fn.extend( {
|
|
attr: function( name, value ) {
|
|
return access( this, jQuery.attr, name, value, arguments.length > 1 );
|
|
},
|
|
|
|
removeAttr: function( name ) {
|
|
return this.each( function() {
|
|
jQuery.removeAttr( this, name );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.extend( {
|
|
attr: function( elem, name, value ) {
|
|
var ret, hooks,
|
|
nType = elem.nodeType;
|
|
|
|
// Don't get/set attributes on text, comment and attribute nodes
|
|
if ( nType === 3 || nType === 8 || nType === 2 ) {
|
|
return;
|
|
}
|
|
|
|
// Fallback to prop when attributes are not supported
|
|
if ( typeof elem.getAttribute === "undefined" ) {
|
|
return jQuery.prop( elem, name, value );
|
|
}
|
|
|
|
// Attribute hooks are determined by the lowercase version
|
|
// Grab necessary hook if one is defined
|
|
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
|
hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
|
|
( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
|
|
}
|
|
|
|
if ( value !== undefined ) {
|
|
if ( value === null ) {
|
|
jQuery.removeAttr( elem, name );
|
|
return;
|
|
}
|
|
|
|
if ( hooks && "set" in hooks &&
|
|
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
|
|
return ret;
|
|
}
|
|
|
|
elem.setAttribute( name, value + "" );
|
|
return value;
|
|
}
|
|
|
|
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
|
|
return ret;
|
|
}
|
|
|
|
ret = jQuery.find.attr( elem, name );
|
|
|
|
// Non-existent attributes return null, we normalize to undefined
|
|
return ret == null ? undefined : ret;
|
|
},
|
|
|
|
attrHooks: {
|
|
type: {
|
|
set: function( elem, value ) {
|
|
if ( !support.radioValue && value === "radio" &&
|
|
nodeName( elem, "input" ) ) {
|
|
var val = elem.value;
|
|
elem.setAttribute( "type", value );
|
|
if ( val ) {
|
|
elem.value = val;
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
removeAttr: function( elem, value ) {
|
|
var name,
|
|
i = 0,
|
|
|
|
// Attribute names can contain non-HTML whitespace characters
|
|
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
attrNames = value && value.match( rnothtmlwhite );
|
|
|
|
if ( attrNames && elem.nodeType === 1 ) {
|
|
while ( ( name = attrNames[ i++ ] ) ) {
|
|
elem.removeAttribute( name );
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
|
|
// Hooks for boolean attributes
|
|
boolHook = {
|
|
set: function( elem, value, name ) {
|
|
if ( value === false ) {
|
|
|
|
// Remove boolean attributes when set to false
|
|
jQuery.removeAttr( elem, name );
|
|
} else {
|
|
elem.setAttribute( name, name );
|
|
}
|
|
return name;
|
|
}
|
|
};
|
|
|
|
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
|
|
var getter = attrHandle[ name ] || jQuery.find.attr;
|
|
|
|
attrHandle[ name ] = function( elem, name, isXML ) {
|
|
var ret, handle,
|
|
lowercaseName = name.toLowerCase();
|
|
|
|
if ( !isXML ) {
|
|
|
|
// Avoid an infinite loop by temporarily removing this function from the getter
|
|
handle = attrHandle[ lowercaseName ];
|
|
attrHandle[ lowercaseName ] = ret;
|
|
ret = getter( elem, name, isXML ) != null ?
|
|
lowercaseName :
|
|
null;
|
|
attrHandle[ lowercaseName ] = handle;
|
|
}
|
|
return ret;
|
|
};
|
|
} );
|
|
|
|
|
|
|
|
|
|
var rfocusable = /^(?:input|select|textarea|button)$/i,
|
|
rclickable = /^(?:a|area)$/i;
|
|
|
|
jQuery.fn.extend( {
|
|
prop: function( name, value ) {
|
|
return access( this, jQuery.prop, name, value, arguments.length > 1 );
|
|
},
|
|
|
|
removeProp: function( name ) {
|
|
return this.each( function() {
|
|
delete this[ jQuery.propFix[ name ] || name ];
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.extend( {
|
|
prop: function( elem, name, value ) {
|
|
var ret, hooks,
|
|
nType = elem.nodeType;
|
|
|
|
// Don't get/set properties on text, comment and attribute nodes
|
|
if ( nType === 3 || nType === 8 || nType === 2 ) {
|
|
return;
|
|
}
|
|
|
|
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
|
|
|
|
// Fix name and attach hooks
|
|
name = jQuery.propFix[ name ] || name;
|
|
hooks = jQuery.propHooks[ name ];
|
|
}
|
|
|
|
if ( value !== undefined ) {
|
|
if ( hooks && "set" in hooks &&
|
|
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
|
|
return ret;
|
|
}
|
|
|
|
return ( elem[ name ] = value );
|
|
}
|
|
|
|
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
|
|
return ret;
|
|
}
|
|
|
|
return elem[ name ];
|
|
},
|
|
|
|
propHooks: {
|
|
tabIndex: {
|
|
get: function( elem ) {
|
|
|
|
// Support: IE <=9 - 11 only
|
|
// elem.tabIndex doesn't always return the
|
|
// correct value when it hasn't been explicitly set
|
|
// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
|
|
// Use proper attribute retrieval(#12072)
|
|
var tabindex = jQuery.find.attr( elem, "tabindex" );
|
|
|
|
if ( tabindex ) {
|
|
return parseInt( tabindex, 10 );
|
|
}
|
|
|
|
if (
|
|
rfocusable.test( elem.nodeName ) ||
|
|
rclickable.test( elem.nodeName ) &&
|
|
elem.href
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
},
|
|
|
|
propFix: {
|
|
"for": "htmlFor",
|
|
"class": "className"
|
|
}
|
|
} );
|
|
|
|
// Support: IE <=11 only
|
|
// Accessing the selectedIndex property
|
|
// forces the browser to respect setting selected
|
|
// on the option
|
|
// The getter ensures a default option is selected
|
|
// when in an optgroup
|
|
// eslint rule "no-unused-expressions" is disabled for this code
|
|
// since it considers such accessions noop
|
|
if ( !support.optSelected ) {
|
|
jQuery.propHooks.selected = {
|
|
get: function( elem ) {
|
|
|
|
/* eslint no-unused-expressions: "off" */
|
|
|
|
var parent = elem.parentNode;
|
|
if ( parent && parent.parentNode ) {
|
|
parent.parentNode.selectedIndex;
|
|
}
|
|
return null;
|
|
},
|
|
set: function( elem ) {
|
|
|
|
/* eslint no-unused-expressions: "off" */
|
|
|
|
var parent = elem.parentNode;
|
|
if ( parent ) {
|
|
parent.selectedIndex;
|
|
|
|
if ( parent.parentNode ) {
|
|
parent.parentNode.selectedIndex;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
jQuery.each( [
|
|
"tabIndex",
|
|
"readOnly",
|
|
"maxLength",
|
|
"cellSpacing",
|
|
"cellPadding",
|
|
"rowSpan",
|
|
"colSpan",
|
|
"useMap",
|
|
"frameBorder",
|
|
"contentEditable"
|
|
], function() {
|
|
jQuery.propFix[ this.toLowerCase() ] = this;
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Strip and collapse whitespace according to HTML spec
|
|
// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
|
|
function stripAndCollapse( value ) {
|
|
var tokens = value.match( rnothtmlwhite ) || [];
|
|
return tokens.join( " " );
|
|
}
|
|
|
|
|
|
function getClass( elem ) {
|
|
return elem.getAttribute && elem.getAttribute( "class" ) || "";
|
|
}
|
|
|
|
function classesToArray( value ) {
|
|
if ( Array.isArray( value ) ) {
|
|
return value;
|
|
}
|
|
if ( typeof value === "string" ) {
|
|
return value.match( rnothtmlwhite ) || [];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
jQuery.fn.extend( {
|
|
addClass: function( value ) {
|
|
var classes, elem, cur, curValue, clazz, j, finalValue,
|
|
i = 0;
|
|
|
|
if ( isFunction( value ) ) {
|
|
return this.each( function( j ) {
|
|
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
|
|
} );
|
|
}
|
|
|
|
classes = classesToArray( value );
|
|
|
|
if ( classes.length ) {
|
|
while ( ( elem = this[ i++ ] ) ) {
|
|
curValue = getClass( elem );
|
|
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
|
|
|
if ( cur ) {
|
|
j = 0;
|
|
while ( ( clazz = classes[ j++ ] ) ) {
|
|
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
|
|
cur += clazz + " ";
|
|
}
|
|
}
|
|
|
|
// Only assign if different to avoid unneeded rendering.
|
|
finalValue = stripAndCollapse( cur );
|
|
if ( curValue !== finalValue ) {
|
|
elem.setAttribute( "class", finalValue );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
removeClass: function( value ) {
|
|
var classes, elem, cur, curValue, clazz, j, finalValue,
|
|
i = 0;
|
|
|
|
if ( isFunction( value ) ) {
|
|
return this.each( function( j ) {
|
|
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
|
|
} );
|
|
}
|
|
|
|
if ( !arguments.length ) {
|
|
return this.attr( "class", "" );
|
|
}
|
|
|
|
classes = classesToArray( value );
|
|
|
|
if ( classes.length ) {
|
|
while ( ( elem = this[ i++ ] ) ) {
|
|
curValue = getClass( elem );
|
|
|
|
// This expression is here for better compressibility (see addClass)
|
|
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
|
|
|
|
if ( cur ) {
|
|
j = 0;
|
|
while ( ( clazz = classes[ j++ ] ) ) {
|
|
|
|
// Remove *all* instances
|
|
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
|
|
cur = cur.replace( " " + clazz + " ", " " );
|
|
}
|
|
}
|
|
|
|
// Only assign if different to avoid unneeded rendering.
|
|
finalValue = stripAndCollapse( cur );
|
|
if ( curValue !== finalValue ) {
|
|
elem.setAttribute( "class", finalValue );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
toggleClass: function( value, stateVal ) {
|
|
var type = typeof value,
|
|
isValidValue = type === "string" || Array.isArray( value );
|
|
|
|
if ( typeof stateVal === "boolean" && isValidValue ) {
|
|
return stateVal ? this.addClass( value ) : this.removeClass( value );
|
|
}
|
|
|
|
if ( isFunction( value ) ) {
|
|
return this.each( function( i ) {
|
|
jQuery( this ).toggleClass(
|
|
value.call( this, i, getClass( this ), stateVal ),
|
|
stateVal
|
|
);
|
|
} );
|
|
}
|
|
|
|
return this.each( function() {
|
|
var className, i, self, classNames;
|
|
|
|
if ( isValidValue ) {
|
|
|
|
// Toggle individual class names
|
|
i = 0;
|
|
self = jQuery( this );
|
|
classNames = classesToArray( value );
|
|
|
|
while ( ( className = classNames[ i++ ] ) ) {
|
|
|
|
// Check each className given, space separated list
|
|
if ( self.hasClass( className ) ) {
|
|
self.removeClass( className );
|
|
} else {
|
|
self.addClass( className );
|
|
}
|
|
}
|
|
|
|
// Toggle whole class name
|
|
} else if ( value === undefined || type === "boolean" ) {
|
|
className = getClass( this );
|
|
if ( className ) {
|
|
|
|
// Store className if set
|
|
dataPriv.set( this, "__className__", className );
|
|
}
|
|
|
|
// If the element has a class name or if we're passed `false`,
|
|
// then remove the whole classname (if there was one, the above saved it).
|
|
// Otherwise bring back whatever was previously saved (if anything),
|
|
// falling back to the empty string if nothing was stored.
|
|
if ( this.setAttribute ) {
|
|
this.setAttribute( "class",
|
|
className || value === false ?
|
|
"" :
|
|
dataPriv.get( this, "__className__" ) || ""
|
|
);
|
|
}
|
|
}
|
|
} );
|
|
},
|
|
|
|
hasClass: function( selector ) {
|
|
var className, elem,
|
|
i = 0;
|
|
|
|
className = " " + selector + " ";
|
|
while ( ( elem = this[ i++ ] ) ) {
|
|
if ( elem.nodeType === 1 &&
|
|
( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
var rreturn = /\r/g;
|
|
|
|
jQuery.fn.extend( {
|
|
val: function( value ) {
|
|
var hooks, ret, valueIsFunction,
|
|
elem = this[ 0 ];
|
|
|
|
if ( !arguments.length ) {
|
|
if ( elem ) {
|
|
hooks = jQuery.valHooks[ elem.type ] ||
|
|
jQuery.valHooks[ elem.nodeName.toLowerCase() ];
|
|
|
|
if ( hooks &&
|
|
"get" in hooks &&
|
|
( ret = hooks.get( elem, "value" ) ) !== undefined
|
|
) {
|
|
return ret;
|
|
}
|
|
|
|
ret = elem.value;
|
|
|
|
// Handle most common string cases
|
|
if ( typeof ret === "string" ) {
|
|
return ret.replace( rreturn, "" );
|
|
}
|
|
|
|
// Handle cases where value is null/undef or number
|
|
return ret == null ? "" : ret;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
valueIsFunction = isFunction( value );
|
|
|
|
return this.each( function( i ) {
|
|
var val;
|
|
|
|
if ( this.nodeType !== 1 ) {
|
|
return;
|
|
}
|
|
|
|
if ( valueIsFunction ) {
|
|
val = value.call( this, i, jQuery( this ).val() );
|
|
} else {
|
|
val = value;
|
|
}
|
|
|
|
// Treat null/undefined as ""; convert numbers to string
|
|
if ( val == null ) {
|
|
val = "";
|
|
|
|
} else if ( typeof val === "number" ) {
|
|
val += "";
|
|
|
|
} else if ( Array.isArray( val ) ) {
|
|
val = jQuery.map( val, function( value ) {
|
|
return value == null ? "" : value + "";
|
|
} );
|
|
}
|
|
|
|
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
|
|
|
|
// If set returns undefined, fall back to normal setting
|
|
if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
|
|
this.value = val;
|
|
}
|
|
} );
|
|
}
|
|
} );
|
|
|
|
jQuery.extend( {
|
|
valHooks: {
|
|
option: {
|
|
get: function( elem ) {
|
|
|
|
var val = jQuery.find.attr( elem, "value" );
|
|
return val != null ?
|
|
val :
|
|
|
|
// Support: IE <=10 - 11 only
|
|
// option.text throws exceptions (#14686, #14858)
|
|
// Strip and collapse whitespace
|
|
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
|
|
stripAndCollapse( jQuery.text( elem ) );
|
|
}
|
|
},
|
|
select: {
|
|
get: function( elem ) {
|
|
var value, option, i,
|
|
options = elem.options,
|
|
index = elem.selectedIndex,
|
|
one = elem.type === "select-one",
|
|
values = one ? null : [],
|
|
max = one ? index + 1 : options.length;
|
|
|
|
if ( index < 0 ) {
|
|
i = max;
|
|
|
|
} else {
|
|
i = one ? index : 0;
|
|
}
|
|
|
|
// Loop through all the selected options
|
|
for ( ; i < max; i++ ) {
|
|
option = options[ i ];
|
|
|
|
// Support: IE <=9 only
|
|
// IE8-9 doesn't update selected after form reset (#2551)
|
|
if ( ( option.selected || i === index ) &&
|
|
|
|
// Don't return options that are disabled or in a disabled optgroup
|
|
!option.disabled &&
|
|
( !option.parentNode.disabled ||
|
|
!nodeName( option.parentNode, "optgroup" ) ) ) {
|
|
|
|
// Get the specific value for the option
|
|
value = jQuery( option ).val();
|
|
|
|
// We don't need an array for one selects
|
|
if ( one ) {
|
|
return value;
|
|
}
|
|
|
|
// Multi-Selects return an array
|
|
values.push( value );
|
|
}
|
|
}
|
|
|
|
return values;
|
|
},
|
|
|
|
set: function( elem, value ) {
|
|
var optionSet, option,
|
|
options = elem.options,
|
|
values = jQuery.makeArray( value ),
|
|
i = options.length;
|
|
|
|
while ( i-- ) {
|
|
option = options[ i ];
|
|
|
|
/* eslint-disable no-cond-assign */
|
|
|
|
if ( option.selected =
|
|
jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
|
|
) {
|
|
optionSet = true;
|
|
}
|
|
|
|
/* eslint-enable no-cond-assign */
|
|
}
|
|
|
|
// Force browsers to behave consistently when non-matching value is set
|
|
if ( !optionSet ) {
|
|
elem.selectedIndex = -1;
|
|
}
|
|
return values;
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
|
|
// Radios and checkboxes getter/setter
|
|
jQuery.each( [ "radio", "checkbox" ], function() {
|
|
jQuery.valHooks[ this ] = {
|
|
set: function( elem, value ) {
|
|
if ( Array.isArray( value ) ) {
|
|
return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
|
|
}
|
|
}
|
|
};
|
|
if ( !support.checkOn ) {
|
|
jQuery.valHooks[ this ].get = function( elem ) {
|
|
return elem.getAttribute( "value" ) === null ? "on" : elem.value;
|
|
};
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Return jQuery for attributes-only inclusion
|
|
|
|
|
|
support.focusin = "onfocusin" in window;
|
|
|
|
|
|
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
|
|
stopPropagationCallback = function( e ) {
|
|
e.stopPropagation();
|
|
};
|
|
|
|
jQuery.extend( jQuery.event, {
|
|
|
|
trigger: function( event, data, elem, onlyHandlers ) {
|
|
|
|
var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
|
|
eventPath = [ elem || document ],
|
|
type = hasOwn.call( event, "type" ) ? event.type : event,
|
|
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
|
|
|
|
cur = lastElement = tmp = elem = elem || document;
|
|
|
|
// Don't do events on text and comment nodes
|
|
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
|
|
return;
|
|
}
|
|
|
|
// focus/blur morphs to focusin/out; ensure we're not firing them right now
|
|
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( type.indexOf( "." ) > -1 ) {
|
|
|
|
// Namespaced trigger; create a regexp to match event type in handle()
|
|
namespaces = type.split( "." );
|
|
type = namespaces.shift();
|
|
namespaces.sort();
|
|
}
|
|
ontype = type.indexOf( ":" ) < 0 && "on" + type;
|
|
|
|
// Caller can pass in a jQuery.Event object, Object, or just an event type string
|
|
event = event[ jQuery.expando ] ?
|
|
event :
|
|
new jQuery.Event( type, typeof event === "object" && event );
|
|
|
|
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
|
|
event.isTrigger = onlyHandlers ? 2 : 3;
|
|
event.namespace = namespaces.join( "." );
|
|
event.rnamespace = event.namespace ?
|
|
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
|
|
null;
|
|
|
|
// Clean up the event in case it is being reused
|
|
event.result = undefined;
|
|
if ( !event.target ) {
|
|
event.target = elem;
|
|
}
|
|
|
|
// Clone any incoming data and prepend the event, creating the handler arg list
|
|
data = data == null ?
|
|
[ event ] :
|
|
jQuery.makeArray( data, [ event ] );
|
|
|
|
// Allow special events to draw outside the lines
|
|
special = jQuery.event.special[ type ] || {};
|
|
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
|
|
return;
|
|
}
|
|
|
|
// Determine event propagation path in advance, per W3C events spec (#9951)
|
|
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
|
|
if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
|
|
|
|
bubbleType = special.delegateType || type;
|
|
if ( !rfocusMorph.test( bubbleType + type ) ) {
|
|
cur = cur.parentNode;
|
|
}
|
|
for ( ; cur; cur = cur.parentNode ) {
|
|
eventPath.push( cur );
|
|
tmp = cur;
|
|
}
|
|
|
|
// Only add window if we got to document (e.g., not plain obj or detached DOM)
|
|
if ( tmp === ( elem.ownerDocument || document ) ) {
|
|
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
|
|
}
|
|
}
|
|
|
|
// Fire handlers on the event path
|
|
i = 0;
|
|
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
|
|
lastElement = cur;
|
|
event.type = i > 1 ?
|
|
bubbleType :
|
|
special.bindType || type;
|
|
|
|
// jQuery handler
|
|
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
|
|
dataPriv.get( cur, "handle" );
|
|
if ( handle ) {
|
|
handle.apply( cur, data );
|
|
}
|
|
|
|
// Native handler
|
|
handle = ontype && cur[ ontype ];
|
|
if ( handle && handle.apply && acceptData( cur ) ) {
|
|
event.result = handle.apply( cur, data );
|
|
if ( event.result === false ) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
event.type = type;
|
|
|
|
// If nobody prevented the default action, do it now
|
|
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
|
|
|
|
if ( ( !special._default ||
|
|
special._default.apply( eventPath.pop(), data ) === false ) &&
|
|
acceptData( elem ) ) {
|
|
|
|
// Call a native DOM method on the target with the same name as the event.
|
|
// Don't do default actions on window, that's where global variables be (#6170)
|
|
if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
|
|
|
|
// Don't re-trigger an onFOO event when we call its FOO() method
|
|
tmp = elem[ ontype ];
|
|
|
|
if ( tmp ) {
|
|
elem[ ontype ] = null;
|
|
}
|
|
|
|
// Prevent re-triggering of the same event, since we already bubbled it above
|
|
jQuery.event.triggered = type;
|
|
|
|
if ( event.isPropagationStopped() ) {
|
|
lastElement.addEventListener( type, stopPropagationCallback );
|
|
}
|
|
|
|
elem[ type ]();
|
|
|
|
if ( event.isPropagationStopped() ) {
|
|
lastElement.removeEventListener( type, stopPropagationCallback );
|
|
}
|
|
|
|
jQuery.event.triggered = undefined;
|
|
|
|
if ( tmp ) {
|
|
elem[ ontype ] = tmp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return event.result;
|
|
},
|
|
|
|
// Piggyback on a donor event to simulate a different one
|
|
// Used only for `focus(in | out)` events
|
|
simulate: function( type, elem, event ) {
|
|
var e = jQuery.extend(
|
|
new jQuery.Event(),
|
|
event,
|
|
{
|
|
type: type,
|
|
isSimulated: true
|
|
}
|
|
);
|
|
|
|
jQuery.event.trigger( e, null, elem );
|
|
}
|
|
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
trigger: function( type, data ) {
|
|
return this.each( function() {
|
|
jQuery.event.trigger( type, data, this );
|
|
} );
|
|
},
|
|
triggerHandler: function( type, data ) {
|
|
var elem = this[ 0 ];
|
|
if ( elem ) {
|
|
return jQuery.event.trigger( type, data, elem, true );
|
|
}
|
|
}
|
|
} );
|
|
|
|
|
|
// Support: Firefox <=44
|
|
// Firefox doesn't have focus(in | out) events
|
|
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
|
|
//
|
|
// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
|
|
// focus(in | out) events fire after focus & blur events,
|
|
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
|
|
// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
|
|
if ( !support.focusin ) {
|
|
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
|
|
|
|
// Attach a single capturing handler on the document while someone wants focusin/focusout
|
|
var handler = function( event ) {
|
|
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
|
|
};
|
|
|
|
jQuery.event.special[ fix ] = {
|
|
setup: function() {
|
|
var doc = this.ownerDocument || this,
|
|
attaches = dataPriv.access( doc, fix );
|
|
|
|
if ( !attaches ) {
|
|
doc.addEventListener( orig, handler, true );
|
|
}
|
|
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
|
|
},
|
|
teardown: function() {
|
|
var doc = this.ownerDocument || this,
|
|
attaches = dataPriv.access( doc, fix ) - 1;
|
|
|
|
if ( !attaches ) {
|
|
doc.removeEventListener( orig, handler, true );
|
|
dataPriv.remove( doc, fix );
|
|
|
|
} else {
|
|
dataPriv.access( doc, fix, attaches );
|
|
}
|
|
}
|
|
};
|
|
} );
|
|
}
|
|
var location = window.location;
|
|
|
|
var nonce = Date.now();
|
|
|
|
var rquery = ( /\?/ );
|
|
|
|
|
|
|
|
// Cross-browser xml parsing
|
|
jQuery.parseXML = function( data ) {
|
|
var xml;
|
|
if ( !data || typeof data !== "string" ) {
|
|
return null;
|
|
}
|
|
|
|
// Support: IE 9 - 11 only
|
|
// IE throws on parseFromString with invalid input.
|
|
try {
|
|
xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
|
|
} catch ( e ) {
|
|
xml = undefined;
|
|
}
|
|
|
|
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
|
|
jQuery.error( "Invalid XML: " + data );
|
|
}
|
|
return xml;
|
|
};
|
|
|
|
|
|
var
|
|
rbracket = /\[\]$/,
|
|
rCRLF = /\r?\n/g,
|
|
rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
|
|
rsubmittable = /^(?:input|select|textarea|keygen)/i;
|
|
|
|
function buildParams( prefix, obj, traditional, add ) {
|
|
var name;
|
|
|
|
if ( Array.isArray( obj ) ) {
|
|
|
|
// Serialize array item.
|
|
jQuery.each( obj, function( i, v ) {
|
|
if ( traditional || rbracket.test( prefix ) ) {
|
|
|
|
// Treat each array item as a scalar.
|
|
add( prefix, v );
|
|
|
|
} else {
|
|
|
|
// Item is non-scalar (array or object), encode its numeric index.
|
|
buildParams(
|
|
prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
|
|
v,
|
|
traditional,
|
|
add
|
|
);
|
|
}
|
|
} );
|
|
|
|
} else if ( !traditional && toType( obj ) === "object" ) {
|
|
|
|
// Serialize object item.
|
|
for ( name in obj ) {
|
|
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
|
|
}
|
|
|
|
} else {
|
|
|
|
// Serialize scalar item.
|
|
add( prefix, obj );
|
|
}
|
|
}
|
|
|
|
// Serialize an array of form elements or a set of
|
|
// key/values into a query string
|
|
jQuery.param = function( a, traditional ) {
|
|
var prefix,
|
|
s = [],
|
|
add = function( key, valueOrFunction ) {
|
|
|
|
// If value is a function, invoke it and use its return value
|
|
var value = isFunction( valueOrFunction ) ?
|
|
valueOrFunction() :
|
|
valueOrFunction;
|
|
|
|
s[ s.length ] = encodeURIComponent( key ) + "=" +
|
|
encodeURIComponent( value == null ? "" : value );
|
|
};
|
|
|
|
if ( a == null ) {
|
|
return "";
|
|
}
|
|
|
|
// If an array was passed in, assume that it is an array of form elements.
|
|
if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
|
|
|
|
// Serialize the form elements
|
|
jQuery.each( a, function() {
|
|
add( this.name, this.value );
|
|
} );
|
|
|
|
} else {
|
|
|
|
// If traditional, encode the "old" way (the way 1.3.2 or older
|
|
// did it), otherwise encode params recursively.
|
|
for ( prefix in a ) {
|
|
buildParams( prefix, a[ prefix ], traditional, add );
|
|
}
|
|
}
|
|
|
|
// Return the resulting serialization
|
|
return s.join( "&" );
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
serialize: function() {
|
|
return jQuery.param( this.serializeArray() );
|
|
},
|
|
serializeArray: function() {
|
|
return this.map( function() {
|
|
|
|
// Can add propHook for "elements" to filter or add form elements
|
|
var elements = jQuery.prop( this, "elements" );
|
|
return elements ? jQuery.makeArray( elements ) : this;
|
|
} )
|
|
.filter( function() {
|
|
var type = this.type;
|
|
|
|
// Use .is( ":disabled" ) so that fieldset[disabled] works
|
|
return this.name && !jQuery( this ).is( ":disabled" ) &&
|
|
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
|
|
( this.checked || !rcheckableType.test( type ) );
|
|
} )
|
|
.map( function( i, elem ) {
|
|
var val = jQuery( this ).val();
|
|
|
|
if ( val == null ) {
|
|
return null;
|
|
}
|
|
|
|
if ( Array.isArray( val ) ) {
|
|
return jQuery.map( val, function( val ) {
|
|
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
|
} );
|
|
}
|
|
|
|
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
|
|
} ).get();
|
|
}
|
|
} );
|
|
|
|
|
|
var
|
|
r20 = /%20/g,
|
|
rhash = /#.*$/,
|
|
rantiCache = /([?&])_=[^&]*/,
|
|
rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
|
|
|
|
// #7653, #8125, #8152: local protocol detection
|
|
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
|
|
rnoContent = /^(?:GET|HEAD)$/,
|
|
rprotocol = /^\/\//,
|
|
|
|
/* Prefilters
|
|
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
|
|
* 2) These are called:
|
|
* - BEFORE asking for a transport
|
|
* - AFTER param serialization (s.data is a string if s.processData is true)
|
|
* 3) key is the dataType
|
|
* 4) the catchall symbol "*" can be used
|
|
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
|
|
*/
|
|
prefilters = {},
|
|
|
|
/* Transports bindings
|
|
* 1) key is the dataType
|
|
* 2) the catchall symbol "*" can be used
|
|
* 3) selection will start with transport dataType and THEN go to "*" if needed
|
|
*/
|
|
transports = {},
|
|
|
|
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
|
|
allTypes = "*/".concat( "*" ),
|
|
|
|
// Anchor tag for parsing the document origin
|
|
originAnchor = document.createElement( "a" );
|
|
originAnchor.href = location.href;
|
|
|
|
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
|
|
function addToPrefiltersOrTransports( structure ) {
|
|
|
|
// dataTypeExpression is optional and defaults to "*"
|
|
return function( dataTypeExpression, func ) {
|
|
|
|
if ( typeof dataTypeExpression !== "string" ) {
|
|
func = dataTypeExpression;
|
|
dataTypeExpression = "*";
|
|
}
|
|
|
|
var dataType,
|
|
i = 0,
|
|
dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
|
|
|
|
if ( isFunction( func ) ) {
|
|
|
|
// For each dataType in the dataTypeExpression
|
|
while ( ( dataType = dataTypes[ i++ ] ) ) {
|
|
|
|
// Prepend if requested
|
|
if ( dataType[ 0 ] === "+" ) {
|
|
dataType = dataType.slice( 1 ) || "*";
|
|
( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
|
|
|
|
// Otherwise append
|
|
} else {
|
|
( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Base inspection function for prefilters and transports
|
|
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
|
|
|
|
var inspected = {},
|
|
seekingTransport = ( structure === transports );
|
|
|
|
function inspect( dataType ) {
|
|
var selected;
|
|
inspected[ dataType ] = true;
|
|
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
|
|
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
|
|
if ( typeof dataTypeOrTransport === "string" &&
|
|
!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
|
|
|
|
options.dataTypes.unshift( dataTypeOrTransport );
|
|
inspect( dataTypeOrTransport );
|
|
return false;
|
|
} else if ( seekingTransport ) {
|
|
return !( selected = dataTypeOrTransport );
|
|
}
|
|
} );
|
|
return selected;
|
|
}
|
|
|
|
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
|
|
}
|
|
|
|
// A special extend for ajax options
|
|
// that takes "flat" options (not to be deep extended)
|
|
// Fixes #9887
|
|
function ajaxExtend( target, src ) {
|
|
var key, deep,
|
|
flatOptions = jQuery.ajaxSettings.flatOptions || {};
|
|
|
|
for ( key in src ) {
|
|
if ( src[ key ] !== undefined ) {
|
|
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
|
|
}
|
|
}
|
|
if ( deep ) {
|
|
jQuery.extend( true, target, deep );
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
/* Handles responses to an ajax request:
|
|
* - finds the right dataType (mediates between content-type and expected dataType)
|
|
* - returns the corresponding response
|
|
*/
|
|
function ajaxHandleResponses( s, jqXHR, responses ) {
|
|
|
|
var ct, type, finalDataType, firstDataType,
|
|
contents = s.contents,
|
|
dataTypes = s.dataTypes;
|
|
|
|
// Remove auto dataType and get content-type in the process
|
|
while ( dataTypes[ 0 ] === "*" ) {
|
|
dataTypes.shift();
|
|
if ( ct === undefined ) {
|
|
ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
|
|
}
|
|
}
|
|
|
|
// Check if we're dealing with a known content-type
|
|
if ( ct ) {
|
|
for ( type in contents ) {
|
|
if ( contents[ type ] && contents[ type ].test( ct ) ) {
|
|
dataTypes.unshift( type );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check to see if we have a response for the expected dataType
|
|
if ( dataTypes[ 0 ] in responses ) {
|
|
finalDataType = dataTypes[ 0 ];
|
|
} else {
|
|
|
|
// Try convertible dataTypes
|
|
for ( type in responses ) {
|
|
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
|
|
finalDataType = type;
|
|
break;
|
|
}
|
|
if ( !firstDataType ) {
|
|
firstDataType = type;
|
|
}
|
|
}
|
|
|
|
// Or just use first one
|
|
finalDataType = finalDataType || firstDataType;
|
|
}
|
|
|
|
// If we found a dataType
|
|
// We add the dataType to the list if needed
|
|
// and return the corresponding response
|
|
if ( finalDataType ) {
|
|
if ( finalDataType !== dataTypes[ 0 ] ) {
|
|
dataTypes.unshift( finalDataType );
|
|
}
|
|
return responses[ finalDataType ];
|
|
}
|
|
}
|
|
|
|
/* Chain conversions given the request and the original response
|
|
* Also sets the responseXXX fields on the jqXHR instance
|
|
*/
|
|
function ajaxConvert( s, response, jqXHR, isSuccess ) {
|
|
var conv2, current, conv, tmp, prev,
|
|
converters = {},
|
|
|
|
// Work with a copy of dataTypes in case we need to modify it for conversion
|
|
dataTypes = s.dataTypes.slice();
|
|
|
|
// Create converters map with lowercased keys
|
|
if ( dataTypes[ 1 ] ) {
|
|
for ( conv in s.converters ) {
|
|
converters[ conv.toLowerCase() ] = s.converters[ conv ];
|
|
}
|
|
}
|
|
|
|
current = dataTypes.shift();
|
|
|
|
// Convert to each sequential dataType
|
|
while ( current ) {
|
|
|
|
if ( s.responseFields[ current ] ) {
|
|
jqXHR[ s.responseFields[ current ] ] = response;
|
|
}
|
|
|
|
// Apply the dataFilter if provided
|
|
if ( !prev && isSuccess && s.dataFilter ) {
|
|
response = s.dataFilter( response, s.dataType );
|
|
}
|
|
|
|
prev = current;
|
|
current = dataTypes.shift();
|
|
|
|
if ( current ) {
|
|
|
|
// There's only work to do if current dataType is non-auto
|
|
if ( current === "*" ) {
|
|
|
|
current = prev;
|
|
|
|
// Convert response if prev dataType is non-auto and differs from current
|
|
} else if ( prev !== "*" && prev !== current ) {
|
|
|
|
// Seek a direct converter
|
|
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
|
|
|
|
// If none found, seek a pair
|
|
if ( !conv ) {
|
|
for ( conv2 in converters ) {
|
|
|
|
// If conv2 outputs current
|
|
tmp = conv2.split( " " );
|
|
if ( tmp[ 1 ] === current ) {
|
|
|
|
// If prev can be converted to accepted input
|
|
conv = converters[ prev + " " + tmp[ 0 ] ] ||
|
|
converters[ "* " + tmp[ 0 ] ];
|
|
if ( conv ) {
|
|
|
|
// Condense equivalence converters
|
|
if ( conv === true ) {
|
|
conv = converters[ conv2 ];
|
|
|
|
// Otherwise, insert the intermediate dataType
|
|
} else if ( converters[ conv2 ] !== true ) {
|
|
current = tmp[ 0 ];
|
|
dataTypes.unshift( tmp[ 1 ] );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply converter (if not an equivalence)
|
|
if ( conv !== true ) {
|
|
|
|
// Unless errors are allowed to bubble, catch and return them
|
|
if ( conv && s.throws ) {
|
|
response = conv( response );
|
|
} else {
|
|
try {
|
|
response = conv( response );
|
|
} catch ( e ) {
|
|
return {
|
|
state: "parsererror",
|
|
error: conv ? e : "No conversion from " + prev + " to " + current
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return { state: "success", data: response };
|
|
}
|
|
|
|
jQuery.extend( {
|
|
|
|
// Counter for holding the number of active queries
|
|
active: 0,
|
|
|
|
// Last-Modified header cache for next request
|
|
lastModified: {},
|
|
etag: {},
|
|
|
|
ajaxSettings: {
|
|
url: location.href,
|
|
type: "GET",
|
|
isLocal: rlocalProtocol.test( location.protocol ),
|
|
global: true,
|
|
processData: true,
|
|
async: true,
|
|
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
|
|
|
/*
|
|
timeout: 0,
|
|
data: null,
|
|
dataType: null,
|
|
username: null,
|
|
password: null,
|
|
cache: null,
|
|
throws: false,
|
|
traditional: false,
|
|
headers: {},
|
|
*/
|
|
|
|
accepts: {
|
|
"*": allTypes,
|
|
text: "text/plain",
|
|
html: "text/html",
|
|
xml: "application/xml, text/xml",
|
|
json: "application/json, text/javascript"
|
|
},
|
|
|
|
contents: {
|
|
xml: /\bxml\b/,
|
|
html: /\bhtml/,
|
|
json: /\bjson\b/
|
|
},
|
|
|
|
responseFields: {
|
|
xml: "responseXML",
|
|
text: "responseText",
|
|
json: "responseJSON"
|
|
},
|
|
|
|
// Data converters
|
|
// Keys separate source (or catchall "*") and destination types with a single space
|
|
converters: {
|
|
|
|
// Convert anything to text
|
|
"* text": String,
|
|
|
|
// Text to html (true = no transformation)
|
|
"text html": true,
|
|
|
|
// Evaluate text as a json expression
|
|
"text json": JSON.parse,
|
|
|
|
// Parse text as xml
|
|
"text xml": jQuery.parseXML
|
|
},
|
|
|
|
// For options that shouldn't be deep extended:
|
|
// you can add your own custom options here if
|
|
// and when you create one that shouldn't be
|
|
// deep extended (see ajaxExtend)
|
|
flatOptions: {
|
|
url: true,
|
|
context: true
|
|
}
|
|
},
|
|
|
|
// Creates a full fledged settings object into target
|
|
// with both ajaxSettings and settings fields.
|
|
// If target is omitted, writes into ajaxSettings.
|
|
ajaxSetup: function( target, settings ) {
|
|
return settings ?
|
|
|
|
// Building a settings object
|
|
ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
|
|
|
|
// Extending ajaxSettings
|
|
ajaxExtend( jQuery.ajaxSettings, target );
|
|
},
|
|
|
|
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
|
|
ajaxTransport: addToPrefiltersOrTransports( transports ),
|
|
|
|
// Main method
|
|
ajax: function( url, options ) {
|
|
|
|
// If url is an object, simulate pre-1.5 signature
|
|
if ( typeof url === "object" ) {
|
|
options = url;
|
|
url = undefined;
|
|
}
|
|
|
|
// Force options to be an object
|
|
options = options || {};
|
|
|
|
var transport,
|
|
|
|
// URL without anti-cache param
|
|
cacheURL,
|
|
|
|
// Response headers
|
|
responseHeadersString,
|
|
responseHeaders,
|
|
|
|
// timeout handle
|
|
timeoutTimer,
|
|
|
|
// Url cleanup var
|
|
urlAnchor,
|
|
|
|
// Request state (becomes false upon send and true upon completion)
|
|
completed,
|
|
|
|
// To know if global events are to be dispatched
|
|
fireGlobals,
|
|
|
|
// Loop variable
|
|
i,
|
|
|
|
// uncached part of the url
|
|
uncached,
|
|
|
|
// Create the final options object
|
|
s = jQuery.ajaxSetup( {}, options ),
|
|
|
|
// Callbacks context
|
|
callbackContext = s.context || s,
|
|
|
|
// Context for global events is callbackContext if it is a DOM node or jQuery collection
|
|
globalEventContext = s.context &&
|
|
( callbackContext.nodeType || callbackContext.jquery ) ?
|
|
jQuery( callbackContext ) :
|
|
jQuery.event,
|
|
|
|
// Deferreds
|
|
deferred = jQuery.Deferred(),
|
|
completeDeferred = jQuery.Callbacks( "once memory" ),
|
|
|
|
// Status-dependent callbacks
|
|
statusCode = s.statusCode || {},
|
|
|
|
// Headers (they are sent all at once)
|
|
requestHeaders = {},
|
|
requestHeadersNames = {},
|
|
|
|
// Default abort message
|
|
strAbort = "canceled",
|
|
|
|
// Fake xhr
|
|
jqXHR = {
|
|
readyState: 0,
|
|
|
|
// Builds headers hashtable if needed
|
|
getResponseHeader: function( key ) {
|
|
var match;
|
|
if ( completed ) {
|
|
if ( !responseHeaders ) {
|
|
responseHeaders = {};
|
|
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
|
|
responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
|
|
( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
|
|
.concat( match[ 2 ] );
|
|
}
|
|
}
|
|
match = responseHeaders[ key.toLowerCase() + " " ];
|
|
}
|
|
return match == null ? null : match.join( ", " );
|
|
},
|
|
|
|
// Raw string
|
|
getAllResponseHeaders: function() {
|
|
return completed ? responseHeadersString : null;
|
|
},
|
|
|
|
// Caches the header
|
|
setRequestHeader: function( name, value ) {
|
|
if ( completed == null ) {
|
|
name = requestHeadersNames[ name.toLowerCase() ] =
|
|
requestHeadersNames[ name.toLowerCase() ] || name;
|
|
requestHeaders[ name ] = value;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Overrides response content-type header
|
|
overrideMimeType: function( type ) {
|
|
if ( completed == null ) {
|
|
s.mimeType = type;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Status-dependent callbacks
|
|
statusCode: function( map ) {
|
|
var code;
|
|
if ( map ) {
|
|
if ( completed ) {
|
|
|
|
// Execute the appropriate callbacks
|
|
jqXHR.always( map[ jqXHR.status ] );
|
|
} else {
|
|
|
|
// Lazy-add the new callbacks in a way that preserves old ones
|
|
for ( code in map ) {
|
|
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// Cancel the request
|
|
abort: function( statusText ) {
|
|
var finalText = statusText || strAbort;
|
|
if ( transport ) {
|
|
transport.abort( finalText );
|
|
}
|
|
done( 0, finalText );
|
|
return this;
|
|
}
|
|
};
|
|
|
|
// Attach deferreds
|
|
deferred.promise( jqXHR );
|
|
|
|
// Add protocol if not provided (prefilters might expect it)
|
|
// Handle falsy url in the settings object (#10093: consistency with old signature)
|
|
// We also use the url parameter if available
|
|
s.url = ( ( url || s.url || location.href ) + "" )
|
|
.replace( rprotocol, location.protocol + "//" );
|
|
|
|
// Alias method option to type as per ticket #12004
|
|
s.type = options.method || options.type || s.method || s.type;
|
|
|
|
// Extract dataTypes list
|
|
s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
|
|
|
|
// A cross-domain request is in order when the origin doesn't match the current origin.
|
|
if ( s.crossDomain == null ) {
|
|
urlAnchor = document.createElement( "a" );
|
|
|
|
// Support: IE <=8 - 11, Edge 12 - 15
|
|
// IE throws exception on accessing the href property if url is malformed,
|
|
// e.g. http://example.com:80x/
|
|
try {
|
|
urlAnchor.href = s.url;
|
|
|
|
// Support: IE <=8 - 11 only
|
|
// Anchor's host property isn't correctly set when s.url is relative
|
|
urlAnchor.href = urlAnchor.href;
|
|
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
|
|
urlAnchor.protocol + "//" + urlAnchor.host;
|
|
} catch ( e ) {
|
|
|
|
// If there is an error parsing the URL, assume it is crossDomain,
|
|
// it can be rejected by the transport if it is invalid
|
|
s.crossDomain = true;
|
|
}
|
|
}
|
|
|
|
// Convert data if not already a string
|
|
if ( s.data && s.processData && typeof s.data !== "string" ) {
|
|
s.data = jQuery.param( s.data, s.traditional );
|
|
}
|
|
|
|
// Apply prefilters
|
|
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
|
|
|
|
// If request was aborted inside a prefilter, stop there
|
|
if ( completed ) {
|
|
return jqXHR;
|
|
}
|
|
|
|
// We can fire global events as of now if asked to
|
|
// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
|
|
fireGlobals = jQuery.event && s.global;
|
|
|
|
// Watch for a new set of requests
|
|
if ( fireGlobals && jQuery.active++ === 0 ) {
|
|
jQuery.event.trigger( "ajaxStart" );
|
|
}
|
|
|
|
// Uppercase the type
|
|
s.type = s.type.toUpperCase();
|
|
|
|
// Determine if request has content
|
|
s.hasContent = !rnoContent.test( s.type );
|
|
|
|
// Save the URL in case we're toying with the If-Modified-Since
|
|
// and/or If-None-Match header later on
|
|
// Remove hash to simplify url manipulation
|
|
cacheURL = s.url.replace( rhash, "" );
|
|
|
|
// More options handling for requests with no content
|
|
if ( !s.hasContent ) {
|
|
|
|
// Remember the hash so we can put it back
|
|
uncached = s.url.slice( cacheURL.length );
|
|
|
|
// If data is available and should be processed, append data to url
|
|
if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
|
|
cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
|
|
|
|
// #9682: remove data so that it's not used in an eventual retry
|
|
delete s.data;
|
|
}
|
|
|
|
// Add or update anti-cache param if needed
|
|
if ( s.cache === false ) {
|
|
cacheURL = cacheURL.replace( rantiCache, "$1" );
|
|
uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
|
|
}
|
|
|
|
// Put hash and anti-cache on the URL that will be requested (gh-1732)
|
|
s.url = cacheURL + uncached;
|
|
|
|
// Change '%20' to '+' if this is encoded form body content (gh-2658)
|
|
} else if ( s.data && s.processData &&
|
|
( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
|
|
s.data = s.data.replace( r20, "+" );
|
|
}
|
|
|
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
|
if ( s.ifModified ) {
|
|
if ( jQuery.lastModified[ cacheURL ] ) {
|
|
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
|
|
}
|
|
if ( jQuery.etag[ cacheURL ] ) {
|
|
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
|
|
}
|
|
}
|
|
|
|
// Set the correct header, if data is being sent
|
|
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
|
|
jqXHR.setRequestHeader( "Content-Type", s.contentType );
|
|
}
|
|
|
|
// Set the Accepts header for the server, depending on the dataType
|
|
jqXHR.setRequestHeader(
|
|
"Accept",
|
|
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
|
|
s.accepts[ s.dataTypes[ 0 ] ] +
|
|
( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
|
|
s.accepts[ "*" ]
|
|
);
|
|
|
|
// Check for headers option
|
|
for ( i in s.headers ) {
|
|
jqXHR.setRequestHeader( i, s.headers[ i ] );
|
|
}
|
|
|
|
// Allow custom headers/mimetypes and early abort
|
|
if ( s.beforeSend &&
|
|
( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
|
|
|
|
// Abort if not done already and return
|
|
return jqXHR.abort();
|
|
}
|
|
|
|
// Aborting is no longer a cancellation
|
|
strAbort = "abort";
|
|
|
|
// Install callbacks on deferreds
|
|
completeDeferred.add( s.complete );
|
|
jqXHR.done( s.success );
|
|
jqXHR.fail( s.error );
|
|
|
|
// Get transport
|
|
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
|
|
|
|
// If no transport, we auto-abort
|
|
if ( !transport ) {
|
|
done( -1, "No Transport" );
|
|
} else {
|
|
jqXHR.readyState = 1;
|
|
|
|
// Send global event
|
|
if ( fireGlobals ) {
|
|
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
|
|
}
|
|
|
|
// If request was aborted inside ajaxSend, stop there
|
|
if ( completed ) {
|
|
return jqXHR;
|
|
}
|
|
|
|
// Timeout
|
|
if ( s.async && s.timeout > 0 ) {
|
|
timeoutTimer = window.setTimeout( function() {
|
|
jqXHR.abort( "timeout" );
|
|
}, s.timeout );
|
|
}
|
|
|
|
try {
|
|
completed = false;
|
|
transport.send( requestHeaders, done );
|
|
} catch ( e ) {
|
|
|
|
// Rethrow post-completion exceptions
|
|
if ( completed ) {
|
|
throw e;
|
|
}
|
|
|
|
// Propagate others as results
|
|
done( -1, e );
|
|
}
|
|
}
|
|
|
|
// Callback for when everything is done
|
|
function done( status, nativeStatusText, responses, headers ) {
|
|
var isSuccess, success, error, response, modified,
|
|
statusText = nativeStatusText;
|
|
|
|
// Ignore repeat invocations
|
|
if ( completed ) {
|
|
return;
|
|
}
|
|
|
|
completed = true;
|
|
|
|
// Clear timeout if it exists
|
|
if ( timeoutTimer ) {
|
|
window.clearTimeout( timeoutTimer );
|
|
}
|
|
|
|
// Dereference transport for early garbage collection
|
|
// (no matter how long the jqXHR object will be used)
|
|
transport = undefined;
|
|
|
|
// Cache response headers
|
|
responseHeadersString = headers || "";
|
|
|
|
// Set readyState
|
|
jqXHR.readyState = status > 0 ? 4 : 0;
|
|
|
|
// Determine if successful
|
|
isSuccess = status >= 200 && status < 300 || status === 304;
|
|
|
|
// Get response data
|
|
if ( responses ) {
|
|
response = ajaxHandleResponses( s, jqXHR, responses );
|
|
}
|
|
|
|
// Convert no matter what (that way responseXXX fields are always set)
|
|
response = ajaxConvert( s, response, jqXHR, isSuccess );
|
|
|
|
// If successful, handle type chaining
|
|
if ( isSuccess ) {
|
|
|
|
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
|
|
if ( s.ifModified ) {
|
|
modified = jqXHR.getResponseHeader( "Last-Modified" );
|
|
if ( modified ) {
|
|
jQuery.lastModified[ cacheURL ] = modified;
|
|
}
|
|
modified = jqXHR.getResponseHeader( "etag" );
|
|
if ( modified ) {
|
|
jQuery.etag[ cacheURL ] = modified;
|
|
}
|
|
}
|
|
|
|
// if no content
|
|
if ( status === 204 || s.type === "HEAD" ) {
|
|
statusText = "nocontent";
|
|
|
|
// if not modified
|
|
} else if ( status === 304 ) {
|
|
statusText = "notmodified";
|
|
|
|
// If we have data, let's convert it
|
|
} else {
|
|
statusText = response.state;
|
|
success = response.data;
|
|
error = response.error;
|
|
isSuccess = !error;
|
|
}
|
|
} else {
|
|
|
|
// Extract error from statusText and normalize for non-aborts
|
|
error = statusText;
|
|
if ( status || !statusText ) {
|
|
statusText = "error";
|
|
if ( status < 0 ) {
|
|
status = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set data for the fake xhr object
|
|
jqXHR.status = status;
|
|
jqXHR.statusText = ( nativeStatusText || statusText ) + "";
|
|
|
|
// Success/Error
|
|
if ( isSuccess ) {
|
|
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
|
|
} else {
|
|
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
|
|
}
|
|
|
|
// Status-dependent callbacks
|
|
jqXHR.statusCode( statusCode );
|
|
statusCode = undefined;
|
|
|
|
if ( fireGlobals ) {
|
|
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
|
|
[ jqXHR, s, isSuccess ? success : error ] );
|
|
}
|
|
|
|
// Complete
|
|
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
|
|
|
|
if ( fireGlobals ) {
|
|
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
|
|
|
|
// Handle the global AJAX counter
|
|
if ( !( --jQuery.active ) ) {
|
|
jQuery.event.trigger( "ajaxStop" );
|
|
}
|
|
}
|
|
}
|
|
|
|
return jqXHR;
|
|
},
|
|
|
|
getJSON: function( url, data, callback ) {
|
|
return jQuery.get( url, data, callback, "json" );
|
|
},
|
|
|
|
getScript: function( url, callback ) {
|
|
return jQuery.get( url, undefined, callback, "script" );
|
|
}
|
|
} );
|
|
|
|
jQuery.each( [ "get", "post" ], function( i, method ) {
|
|
jQuery[ method ] = function( url, data, callback, type ) {
|
|
|
|
// Shift arguments if data argument was omitted
|
|
if ( isFunction( data ) ) {
|
|
type = type || callback;
|
|
callback = data;
|
|
data = undefined;
|
|
}
|
|
|
|
// The url can be an options object (which then must have .url)
|
|
return jQuery.ajax( jQuery.extend( {
|
|
url: url,
|
|
type: method,
|
|
dataType: type,
|
|
data: data,
|
|
success: callback
|
|
}, jQuery.isPlainObject( url ) && url ) );
|
|
};
|
|
} );
|
|
|
|
|
|
jQuery._evalUrl = function( url, options ) {
|
|
return jQuery.ajax( {
|
|
url: url,
|
|
|
|
// Make this explicit, since user can override this through ajaxSetup (#11264)
|
|
type: "GET",
|
|
dataType: "script",
|
|
cache: true,
|
|
async: false,
|
|
global: false,
|
|
|
|
// Only evaluate the response if it is successful (gh-4126)
|
|
// dataFilter is not invoked for failure responses, so using it instead
|
|
// of the default converter is kludgy but it works.
|
|
converters: {
|
|
"text script": function() {}
|
|
},
|
|
dataFilter: function( response ) {
|
|
jQuery.globalEval( response, options );
|
|
}
|
|
} );
|
|
};
|
|
|
|
|
|
jQuery.fn.extend( {
|
|
wrapAll: function( html ) {
|
|
var wrap;
|
|
|
|
if ( this[ 0 ] ) {
|
|
if ( isFunction( html ) ) {
|
|
html = html.call( this[ 0 ] );
|
|
}
|
|
|
|
// The elements to wrap the target around
|
|
wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
|
|
|
|
if ( this[ 0 ].parentNode ) {
|
|
wrap.insertBefore( this[ 0 ] );
|
|
}
|
|
|
|
wrap.map( function() {
|
|
var elem = this;
|
|
|
|
while ( elem.firstElementChild ) {
|
|
elem = elem.firstElementChild;
|
|
}
|
|
|
|
return elem;
|
|
} ).append( this );
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
wrapInner: function( html ) {
|
|
if ( isFunction( html ) ) {
|
|
return this.each( function( i ) {
|
|
jQuery( this ).wrapInner( html.call( this, i ) );
|
|
} );
|
|
}
|
|
|
|
return this.each( function() {
|
|
var self = jQuery( this ),
|
|
contents = self.contents();
|
|
|
|
if ( contents.length ) {
|
|
contents.wrapAll( html );
|
|
|
|
} else {
|
|
self.append( html );
|
|
}
|
|
} );
|
|
},
|
|
|
|
wrap: function( html ) {
|
|
var htmlIsFunction = isFunction( html );
|
|
|
|
return this.each( function( i ) {
|
|
jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
|
|
} );
|
|
},
|
|
|
|
unwrap: function( selector ) {
|
|
this.parent( selector ).not( "body" ).each( function() {
|
|
jQuery( this ).replaceWith( this.childNodes );
|
|
} );
|
|
return this;
|
|
}
|
|
} );
|
|
|
|
|
|
jQuery.expr.pseudos.hidden = function( elem ) {
|
|
return !jQuery.expr.pseudos.visible( elem );
|
|
};
|
|
jQuery.expr.pseudos.visible = function( elem ) {
|
|
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
|
|
};
|
|
|
|
|
|
|
|
|
|
jQuery.ajaxSettings.xhr = function() {
|
|
try {
|
|
return new window.XMLHttpRequest();
|
|
} catch ( e ) {}
|
|
};
|
|
|
|
var xhrSuccessStatus = {
|
|
|
|
// File protocol always yields status code 0, assume 200
|
|
0: 200,
|
|
|
|
// Support: IE <=9 only
|
|
// #1450: sometimes IE returns 1223 when it should be 204
|
|
1223: 204
|
|
},
|
|
xhrSupported = jQuery.ajaxSettings.xhr();
|
|
|
|
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
|
|
support.ajax = xhrSupported = !!xhrSupported;
|
|
|
|
jQuery.ajaxTransport( function( options ) {
|
|
var callback, errorCallback;
|
|
|
|
// Cross domain only allowed if supported through XMLHttpRequest
|
|
if ( support.cors || xhrSupported && !options.crossDomain ) {
|
|
return {
|
|
send: function( headers, complete ) {
|
|
var i,
|
|
xhr = options.xhr();
|
|
|
|
xhr.open(
|
|
options.type,
|
|
options.url,
|
|
options.async,
|
|
options.username,
|
|
options.password
|
|
);
|
|
|
|
// Apply custom fields if provided
|
|
if ( options.xhrFields ) {
|
|
for ( i in options.xhrFields ) {
|
|
xhr[ i ] = options.xhrFields[ i ];
|
|
}
|
|
}
|
|
|
|
// Override mime type if needed
|
|
if ( options.mimeType && xhr.overrideMimeType ) {
|
|
xhr.overrideMimeType( options.mimeType );
|
|
}
|
|
|
|
// X-Requested-With header
|
|
// For cross-domain requests, seeing as conditions for a preflight are
|
|
// akin to a jigsaw puzzle, we simply never set it to be sure.
|
|
// (it can always be set on a per-request basis or even using ajaxSetup)
|
|
// For same-domain requests, won't change header if already provided.
|
|
if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
|
|
headers[ "X-Requested-With" ] = "XMLHttpRequest";
|
|
}
|
|
|
|
// Set headers
|
|
for ( i in headers ) {
|
|
xhr.setRequestHeader( i, headers[ i ] );
|
|
}
|
|
|
|
// Callback
|
|
callback = function( type ) {
|
|
return function() {
|
|
if ( callback ) {
|
|
callback = errorCallback = xhr.onload =
|
|
xhr.onerror = xhr.onabort = xhr.ontimeout =
|
|
xhr.onreadystatechange = null;
|
|
|
|
if ( type === "abort" ) {
|
|
xhr.abort();
|
|
} else if ( type === "error" ) {
|
|
|
|
// Support: IE <=9 only
|
|
// On a manual native abort, IE9 throws
|
|
// errors on any property access that is not readyState
|
|
if ( typeof xhr.status !== "number" ) {
|
|
complete( 0, "error" );
|
|
} else {
|
|
complete(
|
|
|
|
// File: protocol always yields status 0; see #8605, #14207
|
|
xhr.status,
|
|
xhr.statusText
|
|
);
|
|
}
|
|
} else {
|
|
complete(
|
|
xhrSuccessStatus[ xhr.status ] || xhr.status,
|
|
xhr.statusText,
|
|
|
|
// Support: IE <=9 only
|
|
// IE9 has no XHR2 but throws on binary (trac-11426)
|
|
// For XHR2 non-text, let the caller handle it (gh-2498)
|
|
( xhr.responseType || "text" ) !== "text" ||
|
|
typeof xhr.responseText !== "string" ?
|
|
{ binary: xhr.response } :
|
|
{ text: xhr.responseText },
|
|
xhr.getAllResponseHeaders()
|
|
);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
// Listen to events
|
|
xhr.onload = callback();
|
|
errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
|
|
|
|
// Support: IE 9 only
|
|
// Use onreadystatechange to replace onabort
|
|
// to handle uncaught aborts
|
|
if ( xhr.onabort !== undefined ) {
|
|
xhr.onabort = errorCallback;
|
|
} else {
|
|
xhr.onreadystatechange = function() {
|
|
|
|
// Check readyState before timeout as it changes
|
|
if ( xhr.readyState === 4 ) {
|
|
|
|
// Allow onerror to be called first,
|
|
// but that will not handle a native abort
|
|
// Also, save errorCallback to a variable
|
|
// as xhr.onerror cannot be accessed
|
|
window.setTimeout( function() {
|
|
if ( callback ) {
|
|
errorCallback();
|
|
}
|
|
} );
|
|
}
|
|
};
|
|
}
|
|
|
|
// Create the abort callback
|
|
callback = callback( "abort" );
|
|
|
|
try {
|
|
|
|
// Do send the request (this may raise an exception)
|
|
xhr.send( options.hasContent && options.data || null );
|
|
} catch ( e ) {
|
|
|
|
// #14683: Only rethrow if this hasn't been notified as an error yet
|
|
if ( callback ) {
|
|
throw e;
|
|
}
|
|
}
|
|
},
|
|
|
|
abort: function() {
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
|
|
jQuery.ajaxPrefilter( function( s ) {
|
|
if ( s.crossDomain ) {
|
|
s.contents.script = false;
|
|
}
|
|
} );
|
|
|
|
// Install script dataType
|
|
jQuery.ajaxSetup( {
|
|
accepts: {
|
|
script: "text/javascript, application/javascript, " +
|
|
"application/ecmascript, application/x-ecmascript"
|
|
},
|
|
contents: {
|
|
script: /\b(?:java|ecma)script\b/
|
|
},
|
|
converters: {
|
|
"text script": function( text ) {
|
|
jQuery.globalEval( text );
|
|
return text;
|
|
}
|
|
}
|
|
} );
|
|
|
|
// Handle cache's special case and crossDomain
|
|
jQuery.ajaxPrefilter( "script", function( s ) {
|
|
if ( s.cache === undefined ) {
|
|
s.cache = false;
|
|
}
|
|
if ( s.crossDomain ) {
|
|
s.type = "GET";
|
|
}
|
|
} );
|
|
|
|
// Bind script tag hack transport
|
|
jQuery.ajaxTransport( "script", function( s ) {
|
|
|
|
// This transport only deals with cross domain or forced-by-attrs requests
|
|
if ( s.crossDomain || s.scriptAttrs ) {
|
|
var script, callback;
|
|
return {
|
|
send: function( _, complete ) {
|
|
script = jQuery( "<script>" )
|
|
.attr( s.scriptAttrs || {} )
|
|
.prop( { charset: s.scriptCharset, src: s.url } )
|
|
.on( "load error", callback = function( evt ) {
|
|
script.remove();
|
|
callback = null;
|
|
if ( evt ) {
|
|
complete( evt.type === "error" ? 404 : 200, evt.type );
|
|
}
|
|
} );
|
|
|
|
// Use native DOM manipulation to avoid our domManip AJAX trickery
|
|
document.head.appendChild( script[ 0 ] );
|
|
},
|
|
abort: function() {
|
|
if ( callback ) {
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
var oldCallbacks = [],
|
|
rjsonp = /(=)\?(?=&|$)|\?\?/;
|
|
|
|
// Default jsonp settings
|
|
jQuery.ajaxSetup( {
|
|
jsonp: "callback",
|
|
jsonpCallback: function() {
|
|
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
|
|
this[ callback ] = true;
|
|
return callback;
|
|
}
|
|
} );
|
|
|
|
// Detect, normalize options and install callbacks for jsonp requests
|
|
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
|
|
|
|
var callbackName, overwritten, responseContainer,
|
|
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
|
|
"url" :
|
|
typeof s.data === "string" &&
|
|
( s.contentType || "" )
|
|
.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
|
|
rjsonp.test( s.data ) && "data"
|
|
);
|
|
|
|
// Handle iff the expected data type is "jsonp" or we have a parameter to set
|
|
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
|
|
|
|
// Get callback name, remembering preexisting value associated with it
|
|
callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
|
|
s.jsonpCallback() :
|
|
s.jsonpCallback;
|
|
|
|
// Insert callback into url or form data
|
|
if ( jsonProp ) {
|
|
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
|
|
} else if ( s.jsonp !== false ) {
|
|
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
|
|
}
|
|
|
|
// Use data converter to retrieve json after script execution
|
|
s.converters[ "script json" ] = function() {
|
|
if ( !responseContainer ) {
|
|
jQuery.error( callbackName + " was not called" );
|
|
}
|
|
return responseContainer[ 0 ];
|
|
};
|
|
|
|
// Force json dataType
|
|
s.dataTypes[ 0 ] = "json";
|
|
|
|
// Install callback
|
|
overwritten = window[ callbackName ];
|
|
window[ callbackName ] = function() {
|
|
responseContainer = arguments;
|
|
};
|
|
|
|
// Clean-up function (fires after converters)
|
|
jqXHR.always( function() {
|
|
|
|
// If previous value didn't exist - remove it
|
|
if ( overwritten === undefined ) {
|
|
jQuery( window ).removeProp( callbackName );
|
|
|
|
// Otherwise restore preexisting value
|
|
} else {
|
|
window[ callbackName ] = overwritten;
|
|
}
|
|
|
|
// Save back as free
|
|
if ( s[ callbackName ] ) {
|
|
|
|
// Make sure that re-using the options doesn't screw things around
|
|
s.jsonpCallback = originalSettings.jsonpCallback;
|
|
|
|
// Save the callback name for future use
|
|
oldCallbacks.push( callbackName );
|
|
}
|
|
|
|
// Call if it was a function and we have a response
|
|
if ( responseContainer && isFunction( overwritten ) ) {
|
|
overwritten( responseContainer[ 0 ] );
|
|
}
|
|
|
|
responseContainer = overwritten = undefined;
|
|
} );
|
|
|
|
// Delegate to script
|
|
return "script";
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Support: Safari 8 only
|
|
// In Safari 8 documents created via document.implementation.createHTMLDocument
|
|
// collapse sibling forms: the second one becomes a child of the first one.
|
|
// Because of that, this security measure has to be disabled in Safari 8.
|
|
// https://bugs.webkit.org/show_bug.cgi?id=137337
|
|
support.createHTMLDocument = ( function() {
|
|
var body = document.implementation.createHTMLDocument( "" ).body;
|
|
body.innerHTML = "<form></form><form></form>";
|
|
return body.childNodes.length === 2;
|
|
} )();
|
|
|
|
|
|
// Argument "data" should be string of html
|
|
// context (optional): If specified, the fragment will be created in this context,
|
|
// defaults to document
|
|
// keepScripts (optional): If true, will include scripts passed in the html string
|
|
jQuery.parseHTML = function( data, context, keepScripts ) {
|
|
if ( typeof data !== "string" ) {
|
|
return [];
|
|
}
|
|
if ( typeof context === "boolean" ) {
|
|
keepScripts = context;
|
|
context = false;
|
|
}
|
|
|
|
var base, parsed, scripts;
|
|
|
|
if ( !context ) {
|
|
|
|
// Stop scripts or inline event handlers from being executed immediately
|
|
// by using document.implementation
|
|
if ( support.createHTMLDocument ) {
|
|
context = document.implementation.createHTMLDocument( "" );
|
|
|
|
// Set the base href for the created document
|
|
// so any parsed elements with URLs
|
|
// are based on the document's URL (gh-2965)
|
|
base = context.createElement( "base" );
|
|
base.href = document.location.href;
|
|
context.head.appendChild( base );
|
|
} else {
|
|
context = document;
|
|
}
|
|
}
|
|
|
|
parsed = rsingleTag.exec( data );
|
|
scripts = !keepScripts && [];
|
|
|
|
// Single tag
|
|
if ( parsed ) {
|
|
return [ context.createElement( parsed[ 1 ] ) ];
|
|
}
|
|
|
|
parsed = buildFragment( [ data ], context, scripts );
|
|
|
|
if ( scripts && scripts.length ) {
|
|
jQuery( scripts ).remove();
|
|
}
|
|
|
|
return jQuery.merge( [], parsed.childNodes );
|
|
};
|
|
|
|
|
|
/**
|
|
* Load a url into a page
|
|
*/
|
|
jQuery.fn.load = function( url, params, callback ) {
|
|
var selector, type, response,
|
|
self = this,
|
|
off = url.indexOf( " " );
|
|
|
|
if ( off > -1 ) {
|
|
selector = stripAndCollapse( url.slice( off ) );
|
|
url = url.slice( 0, off );
|
|
}
|
|
|
|
// If it's a function
|
|
if ( isFunction( params ) ) {
|
|
|
|
// We assume that it's the callback
|
|
callback = params;
|
|
params = undefined;
|
|
|
|
// Otherwise, build a param string
|
|
} else if ( params && typeof params === "object" ) {
|
|
type = "POST";
|
|
}
|
|
|
|
// If we have elements to modify, make the request
|
|
if ( self.length > 0 ) {
|
|
jQuery.ajax( {
|
|
url: url,
|
|
|
|
// If "type" variable is undefined, then "GET" method will be used.
|
|
// Make value of this field explicit since
|
|
// user can override it through ajaxSetup method
|
|
type: type || "GET",
|
|
dataType: "html",
|
|
data: params
|
|
} ).done( function( responseText ) {
|
|
|
|
// Save response for use in complete callback
|
|
response = arguments;
|
|
|
|
self.html( selector ?
|
|
|
|
// If a selector was specified, locate the right elements in a dummy div
|
|
// Exclude scripts to avoid IE 'Permission Denied' errors
|
|
jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
|
|
|
|
// Otherwise use the full result
|
|
responseText );
|
|
|
|
// If the request succeeds, this function gets "data", "status", "jqXHR"
|
|
// but they are ignored because response was set above.
|
|
// If it fails, this function gets "jqXHR", "status", "error"
|
|
} ).always( callback && function( jqXHR, status ) {
|
|
self.each( function() {
|
|
callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
|
|
} );
|
|
} );
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
|
|
|
|
|
|
// Attach a bunch of functions for handling common AJAX events
|
|
jQuery.each( [
|
|
"ajaxStart",
|
|
"ajaxStop",
|
|
"ajaxComplete",
|
|
"ajaxError",
|
|
"ajaxSuccess",
|
|
"ajaxSend"
|
|
], function( i, type ) {
|
|
jQuery.fn[ type ] = function( fn ) {
|
|
return this.on( type, fn );
|
|
};
|
|
} );
|
|
|
|
|
|
|
|
|
|
jQuery.expr.pseudos.animated = function( elem ) {
|
|
return jQuery.grep( jQuery.timers, function( fn ) {
|
|
return elem === fn.elem;
|
|
} ).length;
|
|
};
|
|
|
|
|
|
|
|
|
|
jQuery.offset = {
|
|
setOffset: function( elem, options, i ) {
|
|
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
|
|
position = jQuery.css( elem, "position" ),
|
|
curElem = jQuery( elem ),
|
|
props = {};
|
|
|
|
// Set position first, in-case top/left are set even on static elem
|
|
if ( position === "static" ) {
|
|
elem.style.position = "relative";
|
|
}
|
|
|
|
curOffset = curElem.offset();
|
|
curCSSTop = jQuery.css( elem, "top" );
|
|
curCSSLeft = jQuery.css( elem, "left" );
|
|
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
|
|
( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
|
|
|
|
// Need to be able to calculate position if either
|
|
// top or left is auto and position is either absolute or fixed
|
|
if ( calculatePosition ) {
|
|
curPosition = curElem.position();
|
|
curTop = curPosition.top;
|
|
curLeft = curPosition.left;
|
|
|
|
} else {
|
|
curTop = parseFloat( curCSSTop ) || 0;
|
|
curLeft = parseFloat( curCSSLeft ) || 0;
|
|
}
|
|
|
|
if ( isFunction( options ) ) {
|
|
|
|
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
|
|
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
|
|
}
|
|
|
|
if ( options.top != null ) {
|
|
props.top = ( options.top - curOffset.top ) + curTop;
|
|
}
|
|
if ( options.left != null ) {
|
|
props.left = ( options.left - curOffset.left ) + curLeft;
|
|
}
|
|
|
|
if ( "using" in options ) {
|
|
options.using.call( elem, props );
|
|
|
|
} else {
|
|
curElem.css( props );
|
|
}
|
|
}
|
|
};
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
// offset() relates an element's border box to the document origin
|
|
offset: function( options ) {
|
|
|
|
// Preserve chaining for setter
|
|
if ( arguments.length ) {
|
|
return options === undefined ?
|
|
this :
|
|
this.each( function( i ) {
|
|
jQuery.offset.setOffset( this, options, i );
|
|
} );
|
|
}
|
|
|
|
var rect, win,
|
|
elem = this[ 0 ];
|
|
|
|
if ( !elem ) {
|
|
return;
|
|
}
|
|
|
|
// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
|
|
// Support: IE <=11 only
|
|
// Running getBoundingClientRect on a
|
|
// disconnected node in IE throws an error
|
|
if ( !elem.getClientRects().length ) {
|
|
return { top: 0, left: 0 };
|
|
}
|
|
|
|
// Get document-relative position by adding viewport scroll to viewport-relative gBCR
|
|
rect = elem.getBoundingClientRect();
|
|
win = elem.ownerDocument.defaultView;
|
|
return {
|
|
top: rect.top + win.pageYOffset,
|
|
left: rect.left + win.pageXOffset
|
|
};
|
|
},
|
|
|
|
// position() relates an element's margin box to its offset parent's padding box
|
|
// This corresponds to the behavior of CSS absolute positioning
|
|
position: function() {
|
|
if ( !this[ 0 ] ) {
|
|
return;
|
|
}
|
|
|
|
var offsetParent, offset, doc,
|
|
elem = this[ 0 ],
|
|
parentOffset = { top: 0, left: 0 };
|
|
|
|
// position:fixed elements are offset from the viewport, which itself always has zero offset
|
|
if ( jQuery.css( elem, "position" ) === "fixed" ) {
|
|
|
|
// Assume position:fixed implies availability of getBoundingClientRect
|
|
offset = elem.getBoundingClientRect();
|
|
|
|
} else {
|
|
offset = this.offset();
|
|
|
|
// Account for the *real* offset parent, which can be the document or its root element
|
|
// when a statically positioned element is identified
|
|
doc = elem.ownerDocument;
|
|
offsetParent = elem.offsetParent || doc.documentElement;
|
|
while ( offsetParent &&
|
|
( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
|
|
jQuery.css( offsetParent, "position" ) === "static" ) {
|
|
|
|
offsetParent = offsetParent.parentNode;
|
|
}
|
|
if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
|
|
|
|
// Incorporate borders into its offset, since they are outside its content origin
|
|
parentOffset = jQuery( offsetParent ).offset();
|
|
parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
|
|
parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
|
|
}
|
|
}
|
|
|
|
// Subtract parent offsets and element margins
|
|
return {
|
|
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
|
|
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
|
|
};
|
|
},
|
|
|
|
// This method will return documentElement in the following cases:
|
|
// 1) For the element inside the iframe without offsetParent, this method will return
|
|
// documentElement of the parent window
|
|
// 2) For the hidden or detached element
|
|
// 3) For body or html element, i.e. in case of the html node - it will return itself
|
|
//
|
|
// but those exceptions were never presented as a real life use-cases
|
|
// and might be considered as more preferable results.
|
|
//
|
|
// This logic, however, is not guaranteed and can change at any point in the future
|
|
offsetParent: function() {
|
|
return this.map( function() {
|
|
var offsetParent = this.offsetParent;
|
|
|
|
while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
|
|
offsetParent = offsetParent.offsetParent;
|
|
}
|
|
|
|
return offsetParent || documentElement;
|
|
} );
|
|
}
|
|
} );
|
|
|
|
// Create scrollLeft and scrollTop methods
|
|
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
|
|
var top = "pageYOffset" === prop;
|
|
|
|
jQuery.fn[ method ] = function( val ) {
|
|
return access( this, function( elem, method, val ) {
|
|
|
|
// Coalesce documents and windows
|
|
var win;
|
|
if ( isWindow( elem ) ) {
|
|
win = elem;
|
|
} else if ( elem.nodeType === 9 ) {
|
|
win = elem.defaultView;
|
|
}
|
|
|
|
if ( val === undefined ) {
|
|
return win ? win[ prop ] : elem[ method ];
|
|
}
|
|
|
|
if ( win ) {
|
|
win.scrollTo(
|
|
!top ? val : win.pageXOffset,
|
|
top ? val : win.pageYOffset
|
|
);
|
|
|
|
} else {
|
|
elem[ method ] = val;
|
|
}
|
|
}, method, val, arguments.length );
|
|
};
|
|
} );
|
|
|
|
// Support: Safari <=7 - 9.1, Chrome <=37 - 49
|
|
// Add the top/left cssHooks using jQuery.fn.position
|
|
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
|
|
// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
|
|
// getComputedStyle returns percent when specified for top/left/bottom/right;
|
|
// rather than make the css module depend on the offset module, just check for it here
|
|
jQuery.each( [ "top", "left" ], function( i, prop ) {
|
|
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
|
|
function( elem, computed ) {
|
|
if ( computed ) {
|
|
computed = curCSS( elem, prop );
|
|
|
|
// If curCSS returns percentage, fallback to offset
|
|
return rnumnonpx.test( computed ) ?
|
|
jQuery( elem ).position()[ prop ] + "px" :
|
|
computed;
|
|
}
|
|
}
|
|
);
|
|
} );
|
|
|
|
|
|
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
|
|
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
|
|
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
|
|
function( defaultExtra, funcName ) {
|
|
|
|
// Margin is only for outerHeight, outerWidth
|
|
jQuery.fn[ funcName ] = function( margin, value ) {
|
|
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
|
|
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
|
|
|
|
return access( this, function( elem, type, value ) {
|
|
var doc;
|
|
|
|
if ( isWindow( elem ) ) {
|
|
|
|
// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
|
|
return funcName.indexOf( "outer" ) === 0 ?
|
|
elem[ "inner" + name ] :
|
|
elem.document.documentElement[ "client" + name ];
|
|
}
|
|
|
|
// Get document width or height
|
|
if ( elem.nodeType === 9 ) {
|
|
doc = elem.documentElement;
|
|
|
|
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
|
|
// whichever is greatest
|
|
return Math.max(
|
|
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
|
|
elem.body[ "offset" + name ], doc[ "offset" + name ],
|
|
doc[ "client" + name ]
|
|
);
|
|
}
|
|
|
|
return value === undefined ?
|
|
|
|
// Get width or height on the element, requesting but not forcing parseFloat
|
|
jQuery.css( elem, type, extra ) :
|
|
|
|
// Set width or height on the element
|
|
jQuery.style( elem, type, value, extra );
|
|
}, type, chainable ? margin : undefined, chainable );
|
|
};
|
|
} );
|
|
} );
|
|
|
|
|
|
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
|
|
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
|
|
"change select submit keydown keypress keyup contextmenu" ).split( " " ),
|
|
function( i, name ) {
|
|
|
|
// Handle event binding
|
|
jQuery.fn[ name ] = function( data, fn ) {
|
|
return arguments.length > 0 ?
|
|
this.on( name, null, data, fn ) :
|
|
this.trigger( name );
|
|
};
|
|
} );
|
|
|
|
jQuery.fn.extend( {
|
|
hover: function( fnOver, fnOut ) {
|
|
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
|
|
}
|
|
} );
|
|
|
|
|
|
|
|
|
|
jQuery.fn.extend( {
|
|
|
|
bind: function( types, data, fn ) {
|
|
return this.on( types, null, data, fn );
|
|
},
|
|
unbind: function( types, fn ) {
|
|
return this.off( types, null, fn );
|
|
},
|
|
|
|
delegate: function( selector, types, data, fn ) {
|
|
return this.on( types, selector, data, fn );
|
|
},
|
|
undelegate: function( selector, types, fn ) {
|
|
|
|
// ( namespace ) or ( selector, types [, fn] )
|
|
return arguments.length === 1 ?
|
|
this.off( selector, "**" ) :
|
|
this.off( types, selector || "**", fn );
|
|
}
|
|
} );
|
|
|
|
// Bind a function to a context, optionally partially applying any
|
|
// arguments.
|
|
// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
|
|
// However, it is not slated for removal any time soon
|
|
jQuery.proxy = function( fn, context ) {
|
|
var tmp, args, proxy;
|
|
|
|
if ( typeof context === "string" ) {
|
|
tmp = fn[ context ];
|
|
context = fn;
|
|
fn = tmp;
|
|
}
|
|
|
|
// Quick check to determine if target is callable, in the spec
|
|
// this throws a TypeError, but we will just return undefined.
|
|
if ( !isFunction( fn ) ) {
|
|
return undefined;
|
|
}
|
|
|
|
// Simulated bind
|
|
args = slice.call( arguments, 2 );
|
|
proxy = function() {
|
|
return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
|
|
};
|
|
|
|
// Set the guid of unique handler to the same of original handler, so it can be removed
|
|
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
|
|
|
|
return proxy;
|
|
};
|
|
|
|
jQuery.holdReady = function( hold ) {
|
|
if ( hold ) {
|
|
jQuery.readyWait++;
|
|
} else {
|
|
jQuery.ready( true );
|
|
}
|
|
};
|
|
jQuery.isArray = Array.isArray;
|
|
jQuery.parseJSON = JSON.parse;
|
|
jQuery.nodeName = nodeName;
|
|
jQuery.isFunction = isFunction;
|
|
jQuery.isWindow = isWindow;
|
|
jQuery.camelCase = camelCase;
|
|
jQuery.type = toType;
|
|
|
|
jQuery.now = Date.now;
|
|
|
|
jQuery.isNumeric = function( obj ) {
|
|
|
|
// As of jQuery 3.0, isNumeric is limited to
|
|
// strings and numbers (primitives or objects)
|
|
// that can be coerced to finite numbers (gh-2662)
|
|
var type = jQuery.type( obj );
|
|
return ( type === "number" || type === "string" ) &&
|
|
|
|
// parseFloat NaNs numeric-cast false positives ("")
|
|
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
|
|
// subtraction forces infinities to NaN
|
|
!isNaN( obj - parseFloat( obj ) );
|
|
};
|
|
|
|
|
|
|
|
|
|
// Register as a named AMD module, since jQuery can be concatenated with other
|
|
// files that may use define, but not via a proper concatenation script that
|
|
// understands anonymous AMD modules. A named AMD is safest and most robust
|
|
// way to register. Lowercase jquery is used because AMD module names are
|
|
// derived from file names, and jQuery is normally delivered in a lowercase
|
|
// file name. Do this after creating the global so that if an AMD module wants
|
|
// to call noConflict to hide this version of jQuery, it will work.
|
|
|
|
// Note that for maximum portability, libraries that are not jQuery should
|
|
// declare themselves as anonymous modules, and avoid setting a global if an
|
|
// AMD loader is present. jQuery is a special case. For more information, see
|
|
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
|
|
|
|
if ( typeof define === "function" && define.amd ) {
|
|
define( "jquery", [], function() {
|
|
return jQuery;
|
|
} );
|
|
}
|
|
|
|
|
|
|
|
|
|
var
|
|
|
|
// Map over jQuery in case of overwrite
|
|
_jQuery = window.jQuery,
|
|
|
|
// Map over the $ in case of overwrite
|
|
_$ = window.$;
|
|
|
|
jQuery.noConflict = function( deep ) {
|
|
if ( window.$ === jQuery ) {
|
|
window.$ = _$;
|
|
}
|
|
|
|
if ( deep && window.jQuery === jQuery ) {
|
|
window.jQuery = _jQuery;
|
|
}
|
|
|
|
return jQuery;
|
|
};
|
|
|
|
// Expose jQuery and $ identifiers, even in AMD
|
|
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
|
|
// and CommonJS for browser emulators (#13566)
|
|
if ( !noGlobal ) {
|
|
window.jQuery = window.$ = jQuery;
|
|
}
|
|
|
|
|
|
|
|
|
|
return jQuery;
|
|
} );
|
|
(function($, undefined) {
|
|
|
|
/**
|
|
* Unobtrusive scripting adapter for jQuery
|
|
* https://github.com/rails/jquery-ujs
|
|
*
|
|
* Requires jQuery 1.8.0 or later.
|
|
*
|
|
* Released under the MIT license
|
|
*
|
|
*/
|
|
|
|
// Cut down on the number of issues from people inadvertently including jquery_ujs twice
|
|
// by detecting and raising an error when it happens.
|
|
'use strict';
|
|
|
|
if ( $.rails !== undefined ) {
|
|
$.error('jquery-ujs has already been loaded!');
|
|
}
|
|
|
|
// Shorthand to make it a little easier to call public rails functions from within rails.js
|
|
var rails;
|
|
var $document = $(document);
|
|
|
|
$.rails = rails = {
|
|
// Link elements bound by jquery-ujs
|
|
linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]',
|
|
|
|
// Button elements bound by jquery-ujs
|
|
buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)',
|
|
|
|
// Select elements bound by jquery-ujs
|
|
inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
|
|
|
|
// Form elements bound by jquery-ujs
|
|
formSubmitSelector: 'form',
|
|
|
|
// Form input elements bound by jquery-ujs
|
|
formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])',
|
|
|
|
// Form input elements disabled during form submission
|
|
disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled',
|
|
|
|
// Form input elements re-enabled after form submission
|
|
enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled',
|
|
|
|
// Form required input elements
|
|
requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])',
|
|
|
|
// Form file input elements
|
|
fileInputSelector: 'input[name][type=file]:not([disabled])',
|
|
|
|
// Link onClick disable selector with possible reenable after remote submission
|
|
linkDisableSelector: 'a[data-disable-with], a[data-disable]',
|
|
|
|
// Button onClick disable selector with possible reenable after remote submission
|
|
buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]',
|
|
|
|
// Up-to-date Cross-Site Request Forgery token
|
|
csrfToken: function() {
|
|
return $('meta[name=csrf-token]').attr('content');
|
|
},
|
|
|
|
// URL param that must contain the CSRF token
|
|
csrfParam: function() {
|
|
return $('meta[name=csrf-param]').attr('content');
|
|
},
|
|
|
|
// Make sure that every Ajax request sends the CSRF token
|
|
CSRFProtection: function(xhr) {
|
|
var token = rails.csrfToken();
|
|
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
|
|
},
|
|
|
|
// Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
|
|
refreshCSRFTokens: function(){
|
|
$('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken());
|
|
},
|
|
|
|
// Triggers an event on an element and returns false if the event result is false
|
|
fire: function(obj, name, data) {
|
|
var event = $.Event(name);
|
|
obj.trigger(event, data);
|
|
return event.result !== false;
|
|
},
|
|
|
|
// Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
|
|
confirm: function(message) {
|
|
return confirm(message);
|
|
},
|
|
|
|
// Default ajax function, may be overridden with custom function in $.rails.ajax
|
|
ajax: function(options) {
|
|
return $.ajax(options);
|
|
},
|
|
|
|
// Default way to get an element's href. May be overridden at $.rails.href.
|
|
href: function(element) {
|
|
return element[0].href;
|
|
},
|
|
|
|
// Checks "data-remote" if true to handle the request through a XHR request.
|
|
isRemote: function(element) {
|
|
return element.data('remote') !== undefined && element.data('remote') !== false;
|
|
},
|
|
|
|
// Submits "remote" forms and links with ajax
|
|
handleRemote: function(element) {
|
|
var method, url, data, withCredentials, dataType, options;
|
|
|
|
if (rails.fire(element, 'ajax:before')) {
|
|
withCredentials = element.data('with-credentials') || null;
|
|
dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
|
|
|
|
if (element.is('form')) {
|
|
method = element.data('ujs:submit-button-formmethod') || element.attr('method');
|
|
url = element.data('ujs:submit-button-formaction') || element.attr('action');
|
|
data = $(element[0]).serializeArray();
|
|
// memoized value from clicked submit button
|
|
var button = element.data('ujs:submit-button');
|
|
if (button) {
|
|
data.push(button);
|
|
element.data('ujs:submit-button', null);
|
|
}
|
|
element.data('ujs:submit-button-formmethod', null);
|
|
element.data('ujs:submit-button-formaction', null);
|
|
} else if (element.is(rails.inputChangeSelector)) {
|
|
method = element.data('method');
|
|
url = element.data('url');
|
|
data = element.serialize();
|
|
if (element.data('params')) data = data + '&' + element.data('params');
|
|
} else if (element.is(rails.buttonClickSelector)) {
|
|
method = element.data('method') || 'get';
|
|
url = element.data('url');
|
|
data = element.serialize();
|
|
if (element.data('params')) data = data + '&' + element.data('params');
|
|
} else {
|
|
method = element.data('method');
|
|
url = rails.href(element);
|
|
data = element.data('params') || null;
|
|
}
|
|
|
|
options = {
|
|
type: method || 'GET', data: data, dataType: dataType,
|
|
// stopping the "ajax:beforeSend" event will cancel the ajax request
|
|
beforeSend: function(xhr, settings) {
|
|
if (settings.dataType === undefined) {
|
|
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
|
|
}
|
|
if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) {
|
|
element.trigger('ajax:send', xhr);
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
success: function(data, status, xhr) {
|
|
element.trigger('ajax:success', [data, status, xhr]);
|
|
},
|
|
complete: function(xhr, status) {
|
|
element.trigger('ajax:complete', [xhr, status]);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
element.trigger('ajax:error', [xhr, status, error]);
|
|
},
|
|
crossDomain: rails.isCrossDomain(url)
|
|
};
|
|
|
|
// There is no withCredentials for IE6-8 when
|
|
// "Enable native XMLHTTP support" is disabled
|
|
if (withCredentials) {
|
|
options.xhrFields = {
|
|
withCredentials: withCredentials
|
|
};
|
|
}
|
|
|
|
// Only pass url to `ajax` options if not blank
|
|
if (url) { options.url = url; }
|
|
|
|
return rails.ajax(options);
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
// Determines if the request is a cross domain request.
|
|
isCrossDomain: function(url) {
|
|
var originAnchor = document.createElement('a');
|
|
originAnchor.href = location.href;
|
|
var urlAnchor = document.createElement('a');
|
|
|
|
try {
|
|
urlAnchor.href = url;
|
|
// This is a workaround to a IE bug.
|
|
urlAnchor.href = urlAnchor.href;
|
|
|
|
// If URL protocol is false or is a string containing a single colon
|
|
// *and* host are false, assume it is not a cross-domain request
|
|
// (should only be the case for IE7 and IE compatibility mode).
|
|
// Otherwise, evaluate protocol and host of the URL against the origin
|
|
// protocol and host.
|
|
return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) ||
|
|
(originAnchor.protocol + '//' + originAnchor.host ===
|
|
urlAnchor.protocol + '//' + urlAnchor.host));
|
|
} catch (e) {
|
|
// If there is an error parsing the URL, assume it is crossDomain.
|
|
return true;
|
|
}
|
|
},
|
|
|
|
// Handles "data-method" on links such as:
|
|
// <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
|
|
handleMethod: function(link) {
|
|
var href = rails.href(link),
|
|
method = link.data('method'),
|
|
target = link.attr('target'),
|
|
csrfToken = rails.csrfToken(),
|
|
csrfParam = rails.csrfParam(),
|
|
form = $('<form method="post" action="' + href + '"></form>'),
|
|
metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
|
|
|
|
if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) {
|
|
metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
|
|
}
|
|
|
|
if (target) { form.attr('target', target); }
|
|
|
|
form.hide().append(metadataInput).appendTo('body');
|
|
form.submit();
|
|
},
|
|
|
|
// Helper function that returns form elements that match the specified CSS selector
|
|
// If form is actually a "form" element this will return associated elements outside the from that have
|
|
// the html form attribute set
|
|
formElements: function(form, selector) {
|
|
return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector);
|
|
},
|
|
|
|
/* Disables form elements:
|
|
- Caches element value in 'ujs:enable-with' data store
|
|
- Replaces element text with value of 'data-disable-with' attribute
|
|
- Sets disabled property to true
|
|
*/
|
|
disableFormElements: function(form) {
|
|
rails.formElements(form, rails.disableSelector).each(function() {
|
|
rails.disableFormElement($(this));
|
|
});
|
|
},
|
|
|
|
disableFormElement: function(element) {
|
|
var method, replacement;
|
|
|
|
method = element.is('button') ? 'html' : 'val';
|
|
replacement = element.data('disable-with');
|
|
|
|
if (replacement !== undefined) {
|
|
element.data('ujs:enable-with', element[method]());
|
|
element[method](replacement);
|
|
}
|
|
|
|
element.prop('disabled', true);
|
|
element.data('ujs:disabled', true);
|
|
},
|
|
|
|
/* Re-enables disabled form elements:
|
|
- Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
|
|
- Sets disabled property to false
|
|
*/
|
|
enableFormElements: function(form) {
|
|
rails.formElements(form, rails.enableSelector).each(function() {
|
|
rails.enableFormElement($(this));
|
|
});
|
|
},
|
|
|
|
enableFormElement: function(element) {
|
|
var method = element.is('button') ? 'html' : 'val';
|
|
if (element.data('ujs:enable-with') !== undefined) {
|
|
element[method](element.data('ujs:enable-with'));
|
|
element.removeData('ujs:enable-with'); // clean up cache
|
|
}
|
|
element.prop('disabled', false);
|
|
element.removeData('ujs:disabled');
|
|
},
|
|
|
|
/* For 'data-confirm' attribute:
|
|
- Fires `confirm` event
|
|
- Shows the confirmation dialog
|
|
- Fires the `confirm:complete` event
|
|
|
|
Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
|
|
Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
|
|
Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
|
|
return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
|
|
*/
|
|
allowAction: function(element) {
|
|
var message = element.data('confirm'),
|
|
answer = false, callback;
|
|
if (!message) { return true; }
|
|
|
|
if (rails.fire(element, 'confirm')) {
|
|
try {
|
|
answer = rails.confirm(message);
|
|
} catch (e) {
|
|
(console.error || console.log).call(console, e.stack || e);
|
|
}
|
|
callback = rails.fire(element, 'confirm:complete', [answer]);
|
|
}
|
|
return answer && callback;
|
|
},
|
|
|
|
// Helper function which checks for blank inputs in a form that match the specified CSS selector
|
|
blankInputs: function(form, specifiedSelector, nonBlank) {
|
|
var foundInputs = $(),
|
|
input,
|
|
valueToCheck,
|
|
radiosForNameWithNoneSelected,
|
|
radioName,
|
|
selector = specifiedSelector || 'input,textarea',
|
|
requiredInputs = form.find(selector),
|
|
checkedRadioButtonNames = {};
|
|
|
|
requiredInputs.each(function() {
|
|
input = $(this);
|
|
if (input.is('input[type=radio]')) {
|
|
|
|
// Don't count unchecked required radio as blank if other radio with same name is checked,
|
|
// regardless of whether same-name radio input has required attribute or not. The spec
|
|
// states https://www.w3.org/TR/html5/forms.html#the-required-attribute
|
|
radioName = input.attr('name');
|
|
|
|
// Skip if we've already seen the radio with this name.
|
|
if (!checkedRadioButtonNames[radioName]) {
|
|
|
|
// If none checked
|
|
if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) {
|
|
radiosForNameWithNoneSelected = form.find(
|
|
'input[type=radio][name="' + radioName + '"]');
|
|
foundInputs = foundInputs.add(radiosForNameWithNoneSelected);
|
|
}
|
|
|
|
// We only need to check each name once.
|
|
checkedRadioButtonNames[radioName] = radioName;
|
|
}
|
|
} else {
|
|
valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val();
|
|
if (valueToCheck === nonBlank) {
|
|
foundInputs = foundInputs.add(input);
|
|
}
|
|
}
|
|
});
|
|
return foundInputs.length ? foundInputs : false;
|
|
},
|
|
|
|
// Helper function which checks for non-blank inputs in a form that match the specified CSS selector
|
|
nonBlankInputs: function(form, specifiedSelector) {
|
|
return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
|
|
},
|
|
|
|
// Helper function, needed to provide consistent behavior in IE
|
|
stopEverything: function(e) {
|
|
$(e.target).trigger('ujs:everythingStopped');
|
|
e.stopImmediatePropagation();
|
|
return false;
|
|
},
|
|
|
|
// Replace element's html with the 'data-disable-with' after storing original html
|
|
// and prevent clicking on it
|
|
disableElement: function(element) {
|
|
var replacement = element.data('disable-with');
|
|
|
|
if (replacement !== undefined) {
|
|
element.data('ujs:enable-with', element.html()); // store enabled state
|
|
element.html(replacement);
|
|
}
|
|
|
|
element.bind('click.railsDisable', function(e) { // prevent further clicking
|
|
return rails.stopEverything(e);
|
|
});
|
|
element.data('ujs:disabled', true);
|
|
},
|
|
|
|
// Restore element to its original state which was disabled by 'disableElement' above
|
|
enableElement: function(element) {
|
|
if (element.data('ujs:enable-with') !== undefined) {
|
|
element.html(element.data('ujs:enable-with')); // set to old enabled state
|
|
element.removeData('ujs:enable-with'); // clean up cache
|
|
}
|
|
element.unbind('click.railsDisable'); // enable element
|
|
element.removeData('ujs:disabled');
|
|
}
|
|
};
|
|
|
|
if (rails.fire($document, 'rails:attachBindings')) {
|
|
|
|
$.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
|
|
|
|
// This event works the same as the load event, except that it fires every
|
|
// time the page is loaded.
|
|
//
|
|
// See https://github.com/rails/jquery-ujs/issues/357
|
|
// See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
|
|
$(window).on('pageshow.rails', function () {
|
|
$($.rails.enableSelector).each(function () {
|
|
var element = $(this);
|
|
|
|
if (element.data('ujs:disabled')) {
|
|
$.rails.enableFormElement(element);
|
|
}
|
|
});
|
|
|
|
$($.rails.linkDisableSelector).each(function () {
|
|
var element = $(this);
|
|
|
|
if (element.data('ujs:disabled')) {
|
|
$.rails.enableElement(element);
|
|
}
|
|
});
|
|
});
|
|
|
|
$document.on('ajax:complete', rails.linkDisableSelector, function() {
|
|
rails.enableElement($(this));
|
|
});
|
|
|
|
$document.on('ajax:complete', rails.buttonDisableSelector, function() {
|
|
rails.enableFormElement($(this));
|
|
});
|
|
|
|
$document.on('click.rails', rails.linkClickSelector, function(e) {
|
|
var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
|
|
if (!rails.allowAction(link)) return rails.stopEverything(e);
|
|
|
|
if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link);
|
|
|
|
if (rails.isRemote(link)) {
|
|
if (metaClick && (!method || method === 'GET') && !data) { return true; }
|
|
|
|
var handleRemote = rails.handleRemote(link);
|
|
// Response from rails.handleRemote() will either be false or a deferred object promise.
|
|
if (handleRemote === false) {
|
|
rails.enableElement(link);
|
|
} else {
|
|
handleRemote.fail( function() { rails.enableElement(link); } );
|
|
}
|
|
return false;
|
|
|
|
} else if (method) {
|
|
rails.handleMethod(link);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
$document.on('click.rails', rails.buttonClickSelector, function(e) {
|
|
var button = $(this);
|
|
|
|
if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e);
|
|
|
|
if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button);
|
|
|
|
var handleRemote = rails.handleRemote(button);
|
|
// Response from rails.handleRemote() will either be false or a deferred object promise.
|
|
if (handleRemote === false) {
|
|
rails.enableFormElement(button);
|
|
} else {
|
|
handleRemote.fail( function() { rails.enableFormElement(button); } );
|
|
}
|
|
return false;
|
|
});
|
|
|
|
$document.on('change.rails', rails.inputChangeSelector, function(e) {
|
|
var link = $(this);
|
|
if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e);
|
|
|
|
rails.handleRemote(link);
|
|
return false;
|
|
});
|
|
|
|
$document.on('submit.rails', rails.formSubmitSelector, function(e) {
|
|
var form = $(this),
|
|
remote = rails.isRemote(form),
|
|
blankRequiredInputs,
|
|
nonBlankFileInputs;
|
|
|
|
if (!rails.allowAction(form)) return rails.stopEverything(e);
|
|
|
|
// Skip other logic when required values are missing or file upload is present
|
|
if (form.attr('novalidate') === undefined) {
|
|
if (form.data('ujs:formnovalidate-button') === undefined) {
|
|
blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false);
|
|
if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
|
|
return rails.stopEverything(e);
|
|
}
|
|
} else {
|
|
// Clear the formnovalidate in case the next button click is not on a formnovalidate button
|
|
// Not strictly necessary to do here, since it is also reset on each button click, but just to be certain
|
|
form.data('ujs:formnovalidate-button', undefined);
|
|
}
|
|
}
|
|
|
|
if (remote) {
|
|
nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
|
|
if (nonBlankFileInputs) {
|
|
// Slight timeout so that the submit button gets properly serialized
|
|
// (make it easy for event handler to serialize form without disabled values)
|
|
setTimeout(function(){ rails.disableFormElements(form); }, 13);
|
|
var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
|
|
|
|
// Re-enable form elements if event bindings return false (canceling normal form submission)
|
|
if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); }
|
|
|
|
return aborted;
|
|
}
|
|
|
|
rails.handleRemote(form);
|
|
return false;
|
|
|
|
} else {
|
|
// Slight timeout so that the submit button gets properly serialized
|
|
setTimeout(function(){ rails.disableFormElements(form); }, 13);
|
|
}
|
|
});
|
|
|
|
$document.on('click.rails', rails.formInputClickSelector, function(event) {
|
|
var button = $(this);
|
|
|
|
if (!rails.allowAction(button)) return rails.stopEverything(event);
|
|
|
|
// Register the pressed submit button
|
|
var name = button.attr('name'),
|
|
data = name ? {name:name, value:button.val()} : null;
|
|
|
|
var form = button.closest('form');
|
|
if (form.length === 0) {
|
|
form = $('#' + button.attr('form'));
|
|
}
|
|
form.data('ujs:submit-button', data);
|
|
|
|
// Save attributes from button
|
|
form.data('ujs:formnovalidate-button', button.attr('formnovalidate'));
|
|
form.data('ujs:submit-button-formaction', button.attr('formaction'));
|
|
form.data('ujs:submit-button-formmethod', button.attr('formmethod'));
|
|
});
|
|
|
|
$document.on('ajax:send.rails', rails.formSubmitSelector, function(event) {
|
|
if (this === event.target) rails.disableFormElements($(this));
|
|
});
|
|
|
|
$document.on('ajax:complete.rails', rails.formSubmitSelector, function(event) {
|
|
if (this === event.target) rails.enableFormElements($(this));
|
|
});
|
|
|
|
$(function(){
|
|
rails.refreshCSRFTokens();
|
|
});
|
|
}
|
|
|
|
})( jQuery );
|
|
/**
|
|
*
|
|
* jquery.sparkline.js
|
|
*
|
|
* v2.1.3
|
|
* (c) Splunk, Inc
|
|
* Contact: Gareth Watts (gareth@splunk.com)
|
|
* http://omnipotent.net/jquery.sparkline/
|
|
*
|
|
* Generates inline sparkline charts from data supplied either to the method
|
|
* or inline in HTML
|
|
*
|
|
* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag
|
|
* (Firefox 2.0+, Safari, Opera, etc)
|
|
*
|
|
* License: New BSD License
|
|
*
|
|
* Copyright (c) 2012, Splunk Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* * Neither the name of Splunk Inc nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*
|
|
* Usage:
|
|
* $(selector).sparkline(values, options)
|
|
*
|
|
* If values is undefined or set to 'html' then the data values are read from the specified tag:
|
|
* <p>Sparkline: <span class="sparkline">1,4,6,6,8,5,3,5</span></p>
|
|
* $('.sparkline').sparkline();
|
|
* There must be no spaces in the enclosed data set
|
|
*
|
|
* Otherwise values must be an array of numbers or null values
|
|
* <p>Sparkline: <span id="sparkline1">This text replaced if the browser is compatible</span></p>
|
|
* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])
|
|
* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])
|
|
*
|
|
* Values can also be specified in an HTML comment, or as a values attribute:
|
|
* <p>Sparkline: <span class="sparkline"><!--1,4,6,6,8,5,3,5 --></span></p>
|
|
* <p>Sparkline: <span class="sparkline" values="1,4,6,6,8,5,3,5"></span></p>
|
|
* $('.sparkline').sparkline();
|
|
*
|
|
* For line charts, x values can also be specified:
|
|
* <p>Sparkline: <span class="sparkline">1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5</span></p>
|
|
* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])
|
|
*
|
|
* By default, options should be passed in as the second argument to the sparkline function:
|
|
* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})
|
|
*
|
|
* Options can also be set by passing them on the tag itself. This feature is disabled by default though
|
|
* as there's a slight performance overhead:
|
|
* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})
|
|
* <p>Sparkline: <span class="sparkline" sparkType="bar" sparkBarColor="red">loading</span></p>
|
|
* Prefix all options supplied as tag attribute with "spark" (configurable by setting tagOptionsPrefix)
|
|
*
|
|
* Supported options:
|
|
* lineColor - Color of the line used for the chart
|
|
* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart
|
|
* width - Width of the chart - Defaults to 3 times the number of values in pixels
|
|
* height - Height of the chart - Defaults to the height of the containing element
|
|
* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied
|
|
* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied
|
|
* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax
|
|
* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied
|
|
* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied
|
|
* composite - If true then don't erase any existing chart attached to the tag, but draw
|
|
* another chart over the top - Note that width and height are ignored if an
|
|
* existing chart is detected.
|
|
* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'
|
|
* enableTagOptions - Whether to check tags for sparkline options
|
|
* tagOptionsPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'
|
|
* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a
|
|
* hidden dom element, avoding a browser reflow
|
|
* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,
|
|
* making the plugin perform much like it did in 1.x
|
|
* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)
|
|
* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled
|
|
* defaults to false (highlights enabled)
|
|
* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase
|
|
* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body
|
|
* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied
|
|
* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis
|
|
* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis
|
|
* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip
|
|
* callback is given arguments of (sparkline, options, fields)
|
|
* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title
|
|
* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)
|
|
* to control the format of the tooltip
|
|
* tooltipPrefix - A string to prepend to each field displayed in a tooltip
|
|
* tooltipSuffix - A string to append to each field displayed in a tooltip
|
|
* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)
|
|
* tooltipValueLookups - An object or range map to map field values to tooltip strings
|
|
* (eg. to map -1 to "Lost", 0 to "Draw", and 1 to "Win")
|
|
* numberFormatter - Optional callback for formatting numbers in tooltips
|
|
* numberDigitGroupSep - Character to use for group separator in numbers "1,234" - Defaults to ","
|
|
* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to "."
|
|
* numberDigitGroupCount - Number of digits between group separator - Defaults to 3
|
|
*
|
|
* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default),
|
|
* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'
|
|
* line - Line chart. Options:
|
|
* spotColor - Set to '' to not end each line in a circular spot
|
|
* minSpotColor - If set, color of spot at minimum value
|
|
* maxSpotColor - If set, color of spot at maximum value
|
|
* spotRadius - Radius in pixels
|
|
* lineWidth - Width of line in pixels
|
|
* normalRangeMin
|
|
* normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal"
|
|
* or expected range of values
|
|
* normalRangeColor - Color to use for the above bar
|
|
* drawNormalOnTop - Draw the normal range above the chart fill color if true
|
|
* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart
|
|
* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable
|
|
* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable
|
|
* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map
|
|
*
|
|
* bar - Bar chart. Options:
|
|
* barColor - Color of bars for postive values
|
|
* negBarColor - Color of bars for negative values
|
|
* zeroColor - Color of bars with zero values
|
|
* nullColor - Color of bars with null values - Defaults to omitting the bar entirely
|
|
* barWidth - Width of bars in pixels
|
|
* colorMap - Optional mappnig of values to colors to override the *BarColor values above
|
|
* can be an Array of values to control the color of individual bars or a range map
|
|
* to specify colors for individual ranges of values
|
|
* barSpacing - Gap between bars in pixels
|
|
* zeroAxis - Centers the y-axis around zero if true
|
|
*
|
|
* tristate - Charts values of win (>0), lose (<0) or draw (=0)
|
|
* posBarColor - Color of win values
|
|
* negBarColor - Color of lose values
|
|
* zeroBarColor - Color of draw values
|
|
* barWidth - Width of bars in pixels
|
|
* barSpacing - Gap between bars in pixels
|
|
* colorMap - Optional mappnig of values to colors to override the *BarColor values above
|
|
* can be an Array of values to control the color of individual bars or a range map
|
|
* to specify colors for individual ranges of values
|
|
*
|
|
* discrete - Options:
|
|
* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height
|
|
* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor
|
|
* thresholdColor
|
|
*
|
|
* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...
|
|
* options:
|
|
* targetColor - The color of the vertical target marker
|
|
* targetWidth - The width of the target marker in pixels
|
|
* performanceColor - The color of the performance measure horizontal bar
|
|
* rangeColors - Colors to use for each qualitative range background color
|
|
*
|
|
* pie - Pie chart. Options:
|
|
* sliceColors - An array of colors to use for pie slices
|
|
* offset - Angle in degrees to offset the first slice - Try -90 or +90
|
|
* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)
|
|
* borderColor - Color to use for the pie chart border - Defaults to #000
|
|
*
|
|
* box - Box plot. Options:
|
|
* raw - Set to true to supply pre-computed plot points as values
|
|
* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier
|
|
* When set to false you can supply any number of values and the box plot will
|
|
* be computed for you. Default is false.
|
|
* showOutliers - Set to true (default) to display outliers as circles
|
|
* outlierIQR - Interquartile range used to determine outliers. Default 1.5
|
|
* boxLineColor - Outline color of the box
|
|
* boxFillColor - Fill color for the box
|
|
* whiskerColor - Line color used for whiskers
|
|
* outlierLineColor - Outline color of outlier circles
|
|
* outlierFillColor - Fill color of the outlier circles
|
|
* spotRadius - Radius of outlier circles
|
|
* medianColor - Line color of the median line
|
|
* target - Draw a target cross hair at the supplied value (default undefined)
|
|
*
|
|
*
|
|
*
|
|
* Examples:
|
|
* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });
|
|
* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });
|
|
* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):
|
|
* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });
|
|
* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });
|
|
* $('#pie').sparkline([1,1,2], { type:'pie' });
|
|
*/
|
|
|
|
/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
|
|
|
|
(function(document, Math, undefined) { // performance/minified-size optimization
|
|
(function(factory) {
|
|
if(typeof define === 'function' && define.amd) {
|
|
define(['jquery'], factory);
|
|
} else if (jQuery && !jQuery.fn.sparkline) {
|
|
factory(jQuery);
|
|
}
|
|
}
|
|
(function($) {
|
|
'use strict';
|
|
|
|
var UNSET_OPTION = {},
|
|
getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,
|
|
remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,
|
|
MouseHandler, Tooltip, barHighlightMixin,
|
|
line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,
|
|
VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
|
|
|
|
/**
|
|
* Default configuration settings
|
|
*/
|
|
getDefaults = function () {
|
|
return {
|
|
// Settings common to most/all chart types
|
|
common: {
|
|
type: 'line',
|
|
lineColor: '#00f',
|
|
fillColor: '#cdf',
|
|
defaultPixelsPerValue: 3,
|
|
width: 'auto',
|
|
height: 'auto',
|
|
composite: false,
|
|
tagValuesAttribute: 'values',
|
|
tagOptionsPrefix: 'spark',
|
|
enableTagOptions: false,
|
|
enableHighlight: true,
|
|
highlightLighten: 1.4,
|
|
tooltipSkipNull: true,
|
|
tooltipPrefix: '',
|
|
tooltipSuffix: '',
|
|
disableHiddenCheck: false,
|
|
numberFormatter: false,
|
|
numberDigitGroupCount: 3,
|
|
numberDigitGroupSep: ',',
|
|
numberDecimalMark: '.',
|
|
disableTooltips: false,
|
|
disableInteraction: false
|
|
},
|
|
// Defaults for line charts
|
|
line: {
|
|
spotColor: '#f80',
|
|
highlightSpotColor: '#5f5',
|
|
highlightLineColor: '#f22',
|
|
spotRadius: 1.5,
|
|
minSpotColor: '#f80',
|
|
maxSpotColor: '#f80',
|
|
lineWidth: 1,
|
|
normalRangeMin: undefined,
|
|
normalRangeMax: undefined,
|
|
normalRangeColor: '#ccc',
|
|
drawNormalOnTop: false,
|
|
chartRangeMin: undefined,
|
|
chartRangeMax: undefined,
|
|
chartRangeMinX: undefined,
|
|
chartRangeMaxX: undefined,
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{prefix}}{{y}}{{suffix}}')
|
|
},
|
|
// Defaults for bar charts
|
|
bar: {
|
|
barColor: '#3366cc',
|
|
negBarColor: '#f44',
|
|
stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
|
|
'#dd4477', '#0099c6', '#990099'],
|
|
zeroColor: undefined,
|
|
nullColor: undefined,
|
|
zeroAxis: true,
|
|
barWidth: 4,
|
|
barSpacing: 1,
|
|
chartRangeMax: undefined,
|
|
chartRangeMin: undefined,
|
|
chartRangeClip: false,
|
|
colorMap: undefined,
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{prefix}}{{value}}{{suffix}}')
|
|
},
|
|
// Defaults for tristate charts
|
|
tristate: {
|
|
barWidth: 4,
|
|
barSpacing: 1,
|
|
posBarColor: '#6f6',
|
|
negBarColor: '#f44',
|
|
zeroBarColor: '#999',
|
|
colorMap: {},
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{value:map}}'),
|
|
tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }
|
|
},
|
|
// Defaults for discrete charts
|
|
discrete: {
|
|
lineHeight: 'auto',
|
|
thresholdColor: undefined,
|
|
thresholdValue: 0,
|
|
chartRangeMax: undefined,
|
|
chartRangeMin: undefined,
|
|
chartRangeClip: false,
|
|
tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')
|
|
},
|
|
// Defaults for bullet charts
|
|
bullet: {
|
|
targetColor: '#f33',
|
|
targetWidth: 3, // width of the target bar in pixels
|
|
performanceColor: '#33f',
|
|
rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],
|
|
base: undefined, // set this to a number to change the base start number
|
|
tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),
|
|
tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }
|
|
},
|
|
// Defaults for pie charts
|
|
pie: {
|
|
offset: 0,
|
|
sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
|
|
'#dd4477', '#0099c6', '#990099'],
|
|
borderWidth: 0,
|
|
borderColor: '#000',
|
|
tooltipFormat: new SPFormat('<span style="color: {{color}}">●</span> {{value}} ({{percent.1}}%)')
|
|
},
|
|
// Defaults for box plots
|
|
box: {
|
|
raw: false,
|
|
boxLineColor: '#000',
|
|
boxFillColor: '#cdf',
|
|
whiskerColor: '#000',
|
|
outlierLineColor: '#333',
|
|
outlierFillColor: '#fff',
|
|
medianColor: '#f00',
|
|
showOutliers: true,
|
|
outlierIQR: 1.5,
|
|
spotRadius: 1.5,
|
|
target: undefined,
|
|
targetColor: '#4a2',
|
|
chartRangeMax: undefined,
|
|
chartRangeMin: undefined,
|
|
tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),
|
|
tooltipFormatFieldlistKey: 'field',
|
|
tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',
|
|
uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',
|
|
lw: 'Left Whisker', rw: 'Right Whisker'} }
|
|
}
|
|
};
|
|
};
|
|
|
|
// You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname
|
|
defaultStyles = '.jqstooltip { ' +
|
|
'position: absolute;' +
|
|
'left: 0px;' +
|
|
'top: 0px;' +
|
|
'visibility: hidden;' +
|
|
'background: rgb(0, 0, 0) transparent;' +
|
|
'background-color: rgba(0,0,0,0.6);' +
|
|
'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +
|
|
'-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";' +
|
|
'color: white;' +
|
|
'font: 10px arial, san serif;' +
|
|
'text-align: left;' +
|
|
'white-space: nowrap;' +
|
|
'padding: 5px;' +
|
|
'border: 1px solid white;' +
|
|
'box-sizing: content-box;' +
|
|
'z-index: 10000;' +
|
|
'}' +
|
|
'.jqsfield { ' +
|
|
'color: white;' +
|
|
'font: 10px arial, san serif;' +
|
|
'text-align: left;' +
|
|
'}';
|
|
|
|
/**
|
|
* Utilities
|
|
*/
|
|
|
|
createClass = function (/* [baseclass, [mixin, ...]], definition */) {
|
|
var Class, args;
|
|
Class = function () {
|
|
this.init.apply(this, arguments);
|
|
};
|
|
if (arguments.length > 1) {
|
|
if (arguments[0]) {
|
|
Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);
|
|
Class._super = arguments[0].prototype;
|
|
} else {
|
|
Class.prototype = arguments[arguments.length - 1];
|
|
}
|
|
if (arguments.length > 2) {
|
|
args = Array.prototype.slice.call(arguments, 1, -1);
|
|
args.unshift(Class.prototype);
|
|
$.extend.apply($, args);
|
|
}
|
|
} else {
|
|
Class.prototype = arguments[0];
|
|
}
|
|
Class.prototype.cls = Class;
|
|
return Class;
|
|
};
|
|
|
|
/**
|
|
* Wraps a format string for tooltips
|
|
* {{x}}
|
|
* {{x.2}
|
|
* {{x:months}}
|
|
*/
|
|
$.SPFormatClass = SPFormat = createClass({
|
|
fre: /\{\{([\w.]+?)(:(.+?))?\}\}/g,
|
|
precre: /(\w+)\.(\d+)/,
|
|
|
|
init: function (format, fclass) {
|
|
this.format = format;
|
|
this.fclass = fclass;
|
|
},
|
|
|
|
render: function (fieldset, lookups, options) {
|
|
var self = this,
|
|
fields = fieldset,
|
|
match, token, lookupkey, fieldvalue, prec;
|
|
return this.format.replace(this.fre, function () {
|
|
var lookup;
|
|
token = arguments[1];
|
|
lookupkey = arguments[3];
|
|
match = self.precre.exec(token);
|
|
if (match) {
|
|
prec = match[2];
|
|
token = match[1];
|
|
} else {
|
|
prec = false;
|
|
}
|
|
fieldvalue = fields[token];
|
|
if (fieldvalue === undefined) {
|
|
return '';
|
|
}
|
|
if (lookupkey && lookups && lookups[lookupkey]) {
|
|
lookup = lookups[lookupkey];
|
|
if (lookup.get) { // RangeMap
|
|
return lookups[lookupkey].get(fieldvalue) || fieldvalue;
|
|
} else {
|
|
return lookups[lookupkey][fieldvalue] || fieldvalue;
|
|
}
|
|
}
|
|
if (isNumber(fieldvalue)) {
|
|
if (options.get('numberFormatter')) {
|
|
fieldvalue = options.get('numberFormatter')(fieldvalue);
|
|
} else {
|
|
fieldvalue = formatNumber(fieldvalue, prec,
|
|
options.get('numberDigitGroupCount'),
|
|
options.get('numberDigitGroupSep'),
|
|
options.get('numberDecimalMark'));
|
|
}
|
|
}
|
|
return fieldvalue;
|
|
});
|
|
}
|
|
});
|
|
|
|
// convience method to avoid needing the new operator
|
|
$.spformat = function(format, fclass) {
|
|
return new SPFormat(format, fclass);
|
|
};
|
|
|
|
clipval = function (val, min, max) {
|
|
if (val < min) {
|
|
return min;
|
|
}
|
|
if (val > max) {
|
|
return max;
|
|
}
|
|
return val;
|
|
};
|
|
|
|
quartile = function (values, q) {
|
|
var vl;
|
|
if (q === 2) {
|
|
vl = Math.floor(values.length / 2);
|
|
return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;
|
|
} else {
|
|
if (values.length % 2 ) { // odd
|
|
vl = (values.length * q + q) / 4;
|
|
return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
|
|
} else { //even
|
|
vl = (values.length * q + 2) / 4;
|
|
return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
normalizeValue = function (val) {
|
|
var nf;
|
|
switch (val) {
|
|
case 'undefined':
|
|
val = undefined;
|
|
break;
|
|
case 'null':
|
|
val = null;
|
|
break;
|
|
case 'true':
|
|
val = true;
|
|
break;
|
|
case 'false':
|
|
val = false;
|
|
break;
|
|
default:
|
|
nf = parseFloat(val);
|
|
if (val == nf) {
|
|
val = nf;
|
|
}
|
|
}
|
|
return val;
|
|
};
|
|
|
|
normalizeValues = function (vals) {
|
|
var i, result = [];
|
|
for (i = vals.length; i--;) {
|
|
result[i] = normalizeValue(vals[i]);
|
|
}
|
|
return result;
|
|
};
|
|
|
|
remove = function (vals, filter) {
|
|
var i, vl, result = [];
|
|
for (i = 0, vl = vals.length; i < vl; i++) {
|
|
if (vals[i] !== filter) {
|
|
result.push(vals[i]);
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
isNumber = function (num) {
|
|
return !isNaN(parseFloat(num)) && isFinite(num);
|
|
};
|
|
|
|
formatNumber = function (num, prec, groupsize, groupsep, decsep) {
|
|
var p, i;
|
|
num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');
|
|
p = (p = $.inArray('.', num)) < 0 ? num.length : p;
|
|
if (p < num.length) {
|
|
num[p] = decsep;
|
|
}
|
|
for (i = p - groupsize; i > 0; i -= groupsize) {
|
|
num.splice(i, 0, groupsep);
|
|
}
|
|
return num.join('');
|
|
};
|
|
|
|
// determine if all values of an array match a value
|
|
// returns true if the array is empty
|
|
all = function (val, arr, ignoreNull) {
|
|
var i;
|
|
for (i = arr.length; i--; ) {
|
|
if (ignoreNull && arr[i] === null) continue;
|
|
if (arr[i] !== val) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// sums the numeric values in an array, ignoring other values
|
|
sum = function (vals) {
|
|
var total = 0, i;
|
|
for (i = vals.length; i--;) {
|
|
total += typeof vals[i] === 'number' ? vals[i] : 0;
|
|
}
|
|
return total;
|
|
};
|
|
|
|
ensureArray = function (val) {
|
|
return $.isArray(val) ? val : [val];
|
|
};
|
|
|
|
// http://paulirish.com/2008/bookmarklet-inject-new-css-rules/
|
|
addCSS = function(css) {
|
|
var tag, iefail;
|
|
if (document.createStyleSheet) {
|
|
try {
|
|
document.createStyleSheet().cssText = css;
|
|
return;
|
|
} catch (e) {
|
|
// IE <= 9 maxes out at 31 stylesheets; inject into page instead.
|
|
iefail = true;
|
|
}
|
|
}
|
|
tag = document.createElement('style');
|
|
tag.type = 'text/css';
|
|
document.getElementsByTagName('head')[0].appendChild(tag);
|
|
if (iefail) {
|
|
document.styleSheets[document.styleSheets.length - 1].cssText = css;
|
|
} else {
|
|
tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;
|
|
}
|
|
};
|
|
|
|
// Provide a cross-browser interface to a few simple drawing primitives
|
|
$.fn.simpledraw = function (width, height, useExisting, interact) {
|
|
var target, mhandler;
|
|
if (useExisting && (target = this.data('_jqs_vcanvas'))) {
|
|
return target;
|
|
}
|
|
|
|
if ($.fn.sparkline.canvas === false) {
|
|
// We've already determined that neither Canvas nor VML are available
|
|
return false;
|
|
|
|
} else if ($.fn.sparkline.canvas === undefined) {
|
|
// No function defined yet -- need to see if we support Canvas or VML
|
|
var el = document.createElement('canvas');
|
|
if (!!(el.getContext && el.getContext('2d'))) {
|
|
// Canvas is available
|
|
$.fn.sparkline.canvas = function(width, height, target, interact) {
|
|
return new VCanvas_canvas(width, height, target, interact);
|
|
};
|
|
} else if (document.namespaces && !document.namespaces.v) {
|
|
// VML is available
|
|
document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
|
|
$.fn.sparkline.canvas = function(width, height, target, interact) {
|
|
return new VCanvas_vml(width, height, target);
|
|
};
|
|
} else {
|
|
// Neither Canvas nor VML are available
|
|
$.fn.sparkline.canvas = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (width === undefined) {
|
|
width = $(this).innerWidth();
|
|
}
|
|
if (height === undefined) {
|
|
height = $(this).innerHeight();
|
|
}
|
|
|
|
target = $.fn.sparkline.canvas(width, height, this, interact);
|
|
|
|
mhandler = $(this).data('_jqs_mhandler');
|
|
if (mhandler) {
|
|
mhandler.registerCanvas(target);
|
|
}
|
|
return target;
|
|
};
|
|
|
|
$.fn.cleardraw = function () {
|
|
var target = this.data('_jqs_vcanvas');
|
|
if (target) {
|
|
target.reset();
|
|
}
|
|
};
|
|
|
|
$.RangeMapClass = RangeMap = createClass({
|
|
init: function (map) {
|
|
var key, range, rangelist = [];
|
|
for (key in map) {
|
|
if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {
|
|
range = key.split(':');
|
|
range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);
|
|
range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);
|
|
range[2] = map[key];
|
|
rangelist.push(range);
|
|
}
|
|
}
|
|
this.map = map;
|
|
this.rangelist = rangelist || false;
|
|
},
|
|
|
|
get: function (value) {
|
|
var rangelist = this.rangelist,
|
|
i, range, result;
|
|
if ((result = this.map[value]) !== undefined) {
|
|
return result;
|
|
}
|
|
if (rangelist) {
|
|
for (i = rangelist.length; i--;) {
|
|
range = rangelist[i];
|
|
if (range[0] <= value && range[1] >= value) {
|
|
return range[2];
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
});
|
|
|
|
// Convenience function
|
|
$.range_map = function(map) {
|
|
return new RangeMap(map);
|
|
};
|
|
|
|
MouseHandler = createClass({
|
|
init: function (el, options) {
|
|
var $el = $(el);
|
|
this.$el = $el;
|
|
this.options = options;
|
|
this.currentPageX = 0;
|
|
this.currentPageY = 0;
|
|
this.el = el;
|
|
this.splist = [];
|
|
this.tooltip = null;
|
|
this.over = false;
|
|
this.displayTooltips = !options.get('disableTooltips');
|
|
this.highlightEnabled = !options.get('disableHighlight');
|
|
},
|
|
|
|
registerSparkline: function (sp) {
|
|
this.splist.push(sp);
|
|
if (this.over) {
|
|
this.updateDisplay();
|
|
}
|
|
},
|
|
|
|
registerCanvas: function (canvas) {
|
|
var $canvas = $(canvas.canvas);
|
|
this.canvas = canvas;
|
|
this.$canvas = $canvas;
|
|
$canvas.mouseenter($.proxy(this.mouseenter, this));
|
|
$canvas.mouseleave($.proxy(this.mouseleave, this));
|
|
$canvas.click($.proxy(this.mouseclick, this));
|
|
},
|
|
|
|
reset: function (removeTooltip) {
|
|
this.splist = [];
|
|
if (this.tooltip && removeTooltip) {
|
|
this.tooltip.remove();
|
|
this.tooltip = undefined;
|
|
}
|
|
},
|
|
|
|
mouseclick: function (e) {
|
|
var clickEvent = $.Event('sparklineClick');
|
|
clickEvent.originalEvent = e;
|
|
clickEvent.sparklines = this.splist;
|
|
this.$el.trigger(clickEvent);
|
|
},
|
|
|
|
mouseenter: function (e) {
|
|
$(document.body).unbind('mousemove.jqs');
|
|
$(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));
|
|
this.over = true;
|
|
this.currentPageX = e.pageX;
|
|
this.currentPageY = e.pageY;
|
|
this.currentEl = e.target;
|
|
if (!this.tooltip && this.displayTooltips) {
|
|
this.tooltip = new Tooltip(this.options);
|
|
this.tooltip.updatePosition(e.pageX, e.pageY);
|
|
}
|
|
this.updateDisplay();
|
|
},
|
|
|
|
mouseleave: function () {
|
|
$(document.body).unbind('mousemove.jqs');
|
|
var splist = this.splist,
|
|
spcount = splist.length,
|
|
needsRefresh = false,
|
|
sp, i;
|
|
this.over = false;
|
|
this.currentEl = null;
|
|
|
|
if (this.tooltip) {
|
|
this.tooltip.remove();
|
|
this.tooltip = null;
|
|
}
|
|
|
|
for (i = 0; i < spcount; i++) {
|
|
sp = splist[i];
|
|
if (sp.clearRegionHighlight()) {
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
|
|
if (needsRefresh) {
|
|
this.canvas.render();
|
|
}
|
|
},
|
|
|
|
mousemove: function (e) {
|
|
this.currentPageX = e.pageX;
|
|
this.currentPageY = e.pageY;
|
|
this.currentEl = e.target;
|
|
if (this.tooltip) {
|
|
this.tooltip.updatePosition(e.pageX, e.pageY);
|
|
}
|
|
this.updateDisplay();
|
|
},
|
|
|
|
updateDisplay: function () {
|
|
var splist = this.splist,
|
|
spcount = splist.length,
|
|
needsRefresh = false,
|
|
offset = this.$canvas.offset(),
|
|
localX = this.currentPageX - offset.left,
|
|
localY = this.currentPageY - offset.top,
|
|
tooltiphtml, sp, i, result, changeEvent;
|
|
if (!this.over) {
|
|
return;
|
|
}
|
|
for (i = 0; i < spcount; i++) {
|
|
sp = splist[i];
|
|
result = sp.setRegionHighlight(this.currentEl, localX, localY);
|
|
if (result) {
|
|
needsRefresh = true;
|
|
}
|
|
}
|
|
if (needsRefresh) {
|
|
changeEvent = $.Event('sparklineRegionChange');
|
|
changeEvent.sparklines = this.splist;
|
|
this.$el.trigger(changeEvent);
|
|
if (this.tooltip) {
|
|
tooltiphtml = '';
|
|
for (i = 0; i < spcount; i++) {
|
|
sp = splist[i];
|
|
tooltiphtml += sp.getCurrentRegionTooltip();
|
|
}
|
|
this.tooltip.setContent(tooltiphtml);
|
|
}
|
|
if (!this.disableHighlight) {
|
|
this.canvas.render();
|
|
}
|
|
}
|
|
if (result === null) {
|
|
this.mouseleave();
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
Tooltip = createClass({
|
|
sizeStyle: 'position: static !important;' +
|
|
'display: block !important;' +
|
|
'visibility: hidden !important;' +
|
|
'float: left !important;',
|
|
|
|
init: function (options) {
|
|
var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),
|
|
sizetipStyle = this.sizeStyle,
|
|
offset;
|
|
this.container = options.get('tooltipContainer') || document.body;
|
|
this.tooltipOffsetX = options.get('tooltipOffsetX', 10);
|
|
this.tooltipOffsetY = options.get('tooltipOffsetY', 12);
|
|
// remove any previous lingering tooltip
|
|
$('#jqssizetip').remove();
|
|
$('#jqstooltip').remove();
|
|
this.sizetip = $('<div/>', {
|
|
id: 'jqssizetip',
|
|
style: sizetipStyle,
|
|
'class': tooltipClassname
|
|
});
|
|
this.tooltip = $('<div/>', {
|
|
id: 'jqstooltip',
|
|
'class': tooltipClassname
|
|
}).appendTo(this.container);
|
|
// account for the container's location
|
|
offset = this.tooltip.offset();
|
|
this.offsetLeft = offset.left;
|
|
this.offsetTop = offset.top;
|
|
this.hidden = true;
|
|
$(window).unbind('resize.jqs scroll.jqs');
|
|
$(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));
|
|
this.updateWindowDims();
|
|
},
|
|
|
|
updateWindowDims: function () {
|
|
this.scrollTop = $(window).scrollTop();
|
|
this.scrollLeft = $(window).scrollLeft();
|
|
this.scrollRight = this.scrollLeft + $(window).width();
|
|
this.updatePosition();
|
|
},
|
|
|
|
getSize: function (content) {
|
|
this.sizetip.html(content).appendTo(this.container);
|
|
this.width = this.sizetip.width() + 1;
|
|
this.height = this.sizetip.height();
|
|
this.sizetip.remove();
|
|
},
|
|
|
|
setContent: function (content) {
|
|
if (!content) {
|
|
this.tooltip.css('visibility', 'hidden');
|
|
this.hidden = true;
|
|
return;
|
|
}
|
|
this.getSize(content);
|
|
this.tooltip.html(content)
|
|
.css({
|
|
'width': this.width,
|
|
'height': this.height,
|
|
'visibility': 'visible'
|
|
});
|
|
if (this.hidden) {
|
|
this.hidden = false;
|
|
this.updatePosition();
|
|
}
|
|
},
|
|
|
|
updatePosition: function (x, y) {
|
|
if (x === undefined) {
|
|
if (this.mousex === undefined) {
|
|
return;
|
|
}
|
|
x = this.mousex - this.offsetLeft;
|
|
y = this.mousey - this.offsetTop;
|
|
|
|
} else {
|
|
this.mousex = x = x - this.offsetLeft;
|
|
this.mousey = y = y - this.offsetTop;
|
|
}
|
|
if (!this.height || !this.width || this.hidden) {
|
|
return;
|
|
}
|
|
|
|
y -= this.height + this.tooltipOffsetY;
|
|
x += this.tooltipOffsetX;
|
|
|
|
if (y < this.scrollTop) {
|
|
y = this.scrollTop;
|
|
}
|
|
if (x < this.scrollLeft) {
|
|
x = this.scrollLeft;
|
|
} else if (x + this.width > this.scrollRight) {
|
|
x = this.scrollRight - this.width;
|
|
}
|
|
|
|
this.tooltip.css({
|
|
'left': x,
|
|
'top': y
|
|
});
|
|
},
|
|
|
|
remove: function () {
|
|
this.tooltip.remove();
|
|
this.sizetip.remove();
|
|
this.sizetip = this.tooltip = undefined;
|
|
$(window).unbind('resize.jqs scroll.jqs');
|
|
}
|
|
});
|
|
|
|
initStyles = function() {
|
|
addCSS(defaultStyles);
|
|
};
|
|
|
|
$(initStyles);
|
|
|
|
pending = [];
|
|
$.fn.sparkline = function (userValues, userOptions) {
|
|
return this.each(function () {
|
|
var options = new $.fn.sparkline.options(this, userOptions),
|
|
$this = $(this),
|
|
render, i;
|
|
render = function () {
|
|
var values, width, height, tmp, mhandler, sp, vals;
|
|
if (userValues === 'html' || userValues === undefined) {
|
|
vals = this.getAttribute(options.get('tagValuesAttribute'));
|
|
if (vals === undefined || vals === null) {
|
|
vals = $this.html();
|
|
}
|
|
values = vals.replace(/(^\s*<!--)|(-->\s*$)|\s+/g, '').split(',');
|
|
} else {
|
|
values = userValues;
|
|
}
|
|
|
|
width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');
|
|
if (options.get('height') === 'auto') {
|
|
if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {
|
|
// must be a better way to get the line height
|
|
tmp = document.createElement('span');
|
|
tmp.innerHTML = 'a';
|
|
$this.html(tmp);
|
|
height = $(tmp).innerHeight() || $(tmp).height();
|
|
$(tmp).remove();
|
|
tmp = null;
|
|
}
|
|
} else {
|
|
height = options.get('height');
|
|
}
|
|
|
|
if (!options.get('disableInteraction')) {
|
|
mhandler = $.data(this, '_jqs_mhandler');
|
|
if (!mhandler) {
|
|
mhandler = new MouseHandler(this, options);
|
|
$.data(this, '_jqs_mhandler', mhandler);
|
|
} else if (!options.get('composite')) {
|
|
mhandler.reset();
|
|
}
|
|
} else {
|
|
mhandler = false;
|
|
}
|
|
|
|
if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {
|
|
if (!$.data(this, '_jqs_errnotify')) {
|
|
alert('Attempted to attach a composite sparkline to an element with no existing sparkline');
|
|
$.data(this, '_jqs_errnotify', true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);
|
|
|
|
sp.render();
|
|
|
|
if (mhandler) {
|
|
mhandler.registerSparkline(sp);
|
|
}
|
|
};
|
|
if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {
|
|
if (!options.get('composite') && $.data(this, '_jqs_pending')) {
|
|
// remove any existing references to the element
|
|
for (i = pending.length; i; i--) {
|
|
if (pending[i - 1][0] == this) {
|
|
pending.splice(i - 1, 1);
|
|
}
|
|
}
|
|
}
|
|
pending.push([this, render]);
|
|
$.data(this, '_jqs_pending', true);
|
|
} else {
|
|
render.call(this);
|
|
}
|
|
});
|
|
};
|
|
|
|
$.fn.sparkline.defaults = getDefaults();
|
|
|
|
|
|
$.sparkline_display_visible = function () {
|
|
var el, i, pl;
|
|
var done = [];
|
|
for (i = 0, pl = pending.length; i < pl; i++) {
|
|
el = pending[i][0];
|
|
if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {
|
|
pending[i][1].call(el);
|
|
$.data(pending[i][0], '_jqs_pending', false);
|
|
done.push(i);
|
|
} else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {
|
|
// element has been inserted and removed from the DOM
|
|
// If it was not yet inserted into the dom then the .data request
|
|
// will return true.
|
|
// removing from the dom causes the data to be removed.
|
|
$.data(pending[i][0], '_jqs_pending', false);
|
|
done.push(i);
|
|
}
|
|
}
|
|
for (i = done.length; i; i--) {
|
|
pending.splice(done[i - 1], 1);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* User option handler
|
|
*/
|
|
$.fn.sparkline.options = createClass({
|
|
init: function (tag, userOptions) {
|
|
var extendedOptions, defaults, base, tagOptionType;
|
|
this.userOptions = userOptions = userOptions || {};
|
|
this.tag = tag;
|
|
this.tagValCache = {};
|
|
defaults = $.fn.sparkline.defaults;
|
|
base = defaults.common;
|
|
this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);
|
|
|
|
tagOptionType = this.getTagSetting('type');
|
|
if (tagOptionType === UNSET_OPTION) {
|
|
extendedOptions = defaults[userOptions.type || base.type];
|
|
} else {
|
|
extendedOptions = defaults[tagOptionType];
|
|
}
|
|
this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);
|
|
},
|
|
|
|
|
|
getTagSetting: function (key) {
|
|
var prefix = this.tagOptionsPrefix,
|
|
val, i, pairs, keyval;
|
|
if (prefix === false || prefix === undefined) {
|
|
return UNSET_OPTION;
|
|
}
|
|
if (this.tagValCache.hasOwnProperty(key)) {
|
|
val = this.tagValCache.key;
|
|
} else {
|
|
val = this.tag.getAttribute(prefix + key);
|
|
if (val === undefined || val === null) {
|
|
val = UNSET_OPTION;
|
|
} else if (val.substr(0, 1) === '[') {
|
|
val = val.substr(1, val.length - 2).split(',');
|
|
for (i = val.length; i--;) {
|
|
val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, ''));
|
|
}
|
|
} else if (val.substr(0, 1) === '{') {
|
|
pairs = val.substr(1, val.length - 2).split(',');
|
|
val = {};
|
|
for (i = pairs.length; i--;) {
|
|
keyval = pairs[i].split(':', 2);
|
|
val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, ''));
|
|
}
|
|
} else {
|
|
val = normalizeValue(val);
|
|
}
|
|
this.tagValCache.key = val;
|
|
}
|
|
return val;
|
|
},
|
|
|
|
get: function (key, defaultval) {
|
|
var tagOption = this.getTagSetting(key),
|
|
result;
|
|
if (tagOption !== UNSET_OPTION) {
|
|
return tagOption;
|
|
}
|
|
return (result = this.mergedOptions[key]) === undefined ? defaultval : result;
|
|
}
|
|
});
|
|
|
|
|
|
$.fn.sparkline._base = createClass({
|
|
disabled: false,
|
|
|
|
init: function (el, values, options, width, height) {
|
|
this.el = el;
|
|
this.$el = $(el);
|
|
this.values = values;
|
|
this.options = options;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.currentRegion = undefined;
|
|
},
|
|
|
|
/**
|
|
* Setup the canvas
|
|
*/
|
|
initTarget: function () {
|
|
var interactive = !this.options.get('disableInteraction');
|
|
if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {
|
|
this.disabled = true;
|
|
} else {
|
|
this.canvasWidth = this.target.pixelWidth;
|
|
this.canvasHeight = this.target.pixelHeight;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Actually render the chart to the canvas
|
|
*/
|
|
render: function () {
|
|
if (this.disabled) {
|
|
this.el.innerHTML = '';
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Return a region id for a given x/y co-ordinate
|
|
*/
|
|
getRegion: function (x, y) {
|
|
},
|
|
|
|
/**
|
|
* Highlight an item based on the moused-over x,y co-ordinate
|
|
*/
|
|
setRegionHighlight: function (el, x, y) {
|
|
var currentRegion = this.currentRegion,
|
|
highlightEnabled = !this.options.get('disableHighlight'),
|
|
newRegion;
|
|
if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {
|
|
return null;
|
|
}
|
|
newRegion = this.getRegion(el, x, y);
|
|
if (currentRegion !== newRegion) {
|
|
if (currentRegion !== undefined && highlightEnabled) {
|
|
this.removeHighlight();
|
|
}
|
|
this.currentRegion = newRegion;
|
|
if (newRegion !== undefined && highlightEnabled) {
|
|
this.renderHighlight();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Reset any currently highlighted item
|
|
*/
|
|
clearRegionHighlight: function () {
|
|
if (this.currentRegion !== undefined) {
|
|
this.removeHighlight();
|
|
this.currentRegion = undefined;
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
renderHighlight: function () {
|
|
this.changeHighlight(true);
|
|
},
|
|
|
|
removeHighlight: function () {
|
|
this.changeHighlight(false);
|
|
},
|
|
|
|
changeHighlight: function (highlight) {},
|
|
|
|
/**
|
|
* Fetch the HTML to display as a tooltip
|
|
*/
|
|
getCurrentRegionTooltip: function () {
|
|
var options = this.options,
|
|
header = '',
|
|
entries = [],
|
|
fields, formats, formatlen, fclass, text, i,
|
|
showFields, showFieldsKey, newFields, fv,
|
|
formatter, format, fieldlen, j;
|
|
if (this.currentRegion === undefined) {
|
|
return '';
|
|
}
|
|
fields = this.getCurrentRegionFields();
|
|
formatter = options.get('tooltipFormatter');
|
|
if (formatter) {
|
|
return formatter(this, options, fields);
|
|
}
|
|
if (options.get('tooltipChartTitle')) {
|
|
header += '<div class="jqs jqstitle">' + options.get('tooltipChartTitle') + '</div>\n';
|
|
}
|
|
formats = this.options.get('tooltipFormat');
|
|
if (!formats) {
|
|
return '';
|
|
}
|
|
if (!$.isArray(formats)) {
|
|
formats = [formats];
|
|
}
|
|
if (!$.isArray(fields)) {
|
|
fields = [fields];
|
|
}
|
|
showFields = this.options.get('tooltipFormatFieldlist');
|
|
showFieldsKey = this.options.get('tooltipFormatFieldlistKey');
|
|
if (showFields && showFieldsKey) {
|
|
// user-selected ordering of fields
|
|
newFields = [];
|
|
for (i = fields.length; i--;) {
|
|
fv = fields[i][showFieldsKey];
|
|
if ((j = $.inArray(fv, showFields)) != -1) {
|
|
newFields[j] = fields[i];
|
|
}
|
|
}
|
|
fields = newFields;
|
|
}
|
|
formatlen = formats.length;
|
|
fieldlen = fields.length;
|
|
for (i = 0; i < formatlen; i++) {
|
|
format = formats[i];
|
|
if (typeof format === 'string') {
|
|
format = new SPFormat(format);
|
|
}
|
|
fclass = format.fclass || 'jqsfield';
|
|
for (j = 0; j < fieldlen; j++) {
|
|
if (!fields[j].isNull || !options.get('tooltipSkipNull')) {
|
|
$.extend(fields[j], {
|
|
prefix: options.get('tooltipPrefix'),
|
|
suffix: options.get('tooltipSuffix')
|
|
});
|
|
text = format.render(fields[j], options.get('tooltipValueLookups'), options);
|
|
entries.push('<div class="' + fclass + '">' + text + '</div>');
|
|
}
|
|
}
|
|
}
|
|
if (entries.length) {
|
|
return header + entries.join('\n');
|
|
}
|
|
return '';
|
|
},
|
|
|
|
getCurrentRegionFields: function () {},
|
|
|
|
calcHighlightColor: function (color, options) {
|
|
var highlightColor = options.get('highlightColor'),
|
|
lighten = options.get('highlightLighten'),
|
|
parse, mult, rgbnew, i;
|
|
if (highlightColor) {
|
|
return highlightColor;
|
|
}
|
|
if (lighten) {
|
|
// extract RGB values
|
|
parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
|
|
if (parse) {
|
|
rgbnew = [];
|
|
mult = color.length === 4 ? 16 : 1;
|
|
for (i = 0; i < 3; i++) {
|
|
rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);
|
|
}
|
|
return 'rgb(' + rgbnew.join(',') + ')';
|
|
}
|
|
|
|
}
|
|
return color;
|
|
}
|
|
|
|
});
|
|
|
|
barHighlightMixin = {
|
|
changeHighlight: function (highlight) {
|
|
var currentRegion = this.currentRegion,
|
|
target = this.target,
|
|
shapeids = this.regionShapes[currentRegion],
|
|
newShapes;
|
|
// will be null if the region value was null
|
|
if (shapeids) {
|
|
newShapes = this.renderRegion(currentRegion, highlight);
|
|
if ($.isArray(newShapes) || $.isArray(shapeids)) {
|
|
target.replaceWithShapes(shapeids, newShapes);
|
|
this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {
|
|
return newShape.id;
|
|
});
|
|
} else {
|
|
target.replaceWithShape(shapeids, newShapes);
|
|
this.regionShapes[currentRegion] = newShapes.id;
|
|
}
|
|
}
|
|
},
|
|
|
|
render: function () {
|
|
var values = this.values,
|
|
target = this.target,
|
|
regionShapes = this.regionShapes,
|
|
shapes, ids, i, j;
|
|
|
|
if (!this.cls._super.render.call(this)) {
|
|
return;
|
|
}
|
|
for (i = values.length; i--;) {
|
|
shapes = this.renderRegion(i);
|
|
if (shapes) {
|
|
if ($.isArray(shapes)) {
|
|
ids = [];
|
|
for (j = shapes.length; j--;) {
|
|
shapes[j].append();
|
|
ids.push(shapes[j].id);
|
|
}
|
|
regionShapes[i] = ids;
|
|
} else {
|
|
shapes.append();
|
|
regionShapes[i] = shapes.id; // store just the shapeid
|
|
}
|
|
} else {
|
|
// null value
|
|
regionShapes[i] = null;
|
|
}
|
|
}
|
|
target.render();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Line charts
|
|
*/
|
|
$.fn.sparkline.line = line = createClass($.fn.sparkline._base, {
|
|
type: 'line',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
line._super.init.call(this, el, values, options, width, height);
|
|
this.vertices = [];
|
|
this.regionMap = [];
|
|
this.xvalues = [];
|
|
this.yvalues = [];
|
|
this.yminmax = [];
|
|
this.hightlightSpotId = null;
|
|
this.lastShapeId = null;
|
|
this.initTarget();
|
|
},
|
|
|
|
getRegion: function (el, x, y) {
|
|
var i,
|
|
regionMap = this.regionMap; // maps regions to value positions
|
|
for (i = regionMap.length; i--;) {
|
|
if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
|
|
return regionMap[i][2];
|
|
}
|
|
}
|
|
return undefined;
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.yvalues[currentRegion] === null,
|
|
x: this.xvalues[currentRegion],
|
|
y: this.yvalues[currentRegion],
|
|
color: this.options.get('lineColor'),
|
|
fillColor: this.options.get('fillColor'),
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
|
|
renderHighlight: function () {
|
|
var currentRegion = this.currentRegion,
|
|
target = this.target,
|
|
vertex = this.vertices[currentRegion],
|
|
options = this.options,
|
|
spotRadius = options.get('spotRadius'),
|
|
highlightSpotColor = options.get('highlightSpotColor'),
|
|
highlightLineColor = options.get('highlightLineColor'),
|
|
highlightSpot, highlightLine;
|
|
|
|
if (!vertex) {
|
|
return;
|
|
}
|
|
if (spotRadius && highlightSpotColor) {
|
|
highlightSpot = target.drawCircle(vertex[0], vertex[1],
|
|
spotRadius, undefined, highlightSpotColor);
|
|
this.highlightSpotId = highlightSpot.id;
|
|
target.insertAfterShape(this.lastShapeId, highlightSpot);
|
|
}
|
|
if (highlightLineColor) {
|
|
highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],
|
|
this.canvasTop + this.canvasHeight, highlightLineColor);
|
|
this.highlightLineId = highlightLine.id;
|
|
target.insertAfterShape(this.lastShapeId, highlightLine);
|
|
}
|
|
},
|
|
|
|
removeHighlight: function () {
|
|
var target = this.target;
|
|
if (this.highlightSpotId) {
|
|
target.removeShapeId(this.highlightSpotId);
|
|
this.highlightSpotId = null;
|
|
}
|
|
if (this.highlightLineId) {
|
|
target.removeShapeId(this.highlightLineId);
|
|
this.highlightLineId = null;
|
|
}
|
|
},
|
|
|
|
scanValues: function () {
|
|
var values = this.values,
|
|
valcount = values.length,
|
|
xvalues = this.xvalues,
|
|
yvalues = this.yvalues,
|
|
yminmax = this.yminmax,
|
|
i, val, isStr, isArray, sp;
|
|
for (i = 0; i < valcount; i++) {
|
|
val = values[i];
|
|
isStr = typeof(values[i]) === 'string';
|
|
isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;
|
|
sp = isStr && values[i].split(':');
|
|
if (isStr && sp.length === 2) { // x:y
|
|
xvalues.push(Number(sp[0]));
|
|
yvalues.push(Number(sp[1]));
|
|
yminmax.push(Number(sp[1]));
|
|
} else if (isArray) {
|
|
xvalues.push(val[0]);
|
|
yvalues.push(val[1]);
|
|
yminmax.push(val[1]);
|
|
} else {
|
|
xvalues.push(i);
|
|
if (values[i] === null || values[i] === 'null') {
|
|
yvalues.push(null);
|
|
} else {
|
|
yvalues.push(Number(val));
|
|
yminmax.push(Number(val));
|
|
}
|
|
}
|
|
}
|
|
if (this.options.get('xvalues')) {
|
|
xvalues = this.options.get('xvalues');
|
|
}
|
|
|
|
this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);
|
|
this.miny = this.minyorg = Math.min.apply(Math, yminmax);
|
|
|
|
this.maxx = Math.max.apply(Math, xvalues);
|
|
this.minx = Math.min.apply(Math, xvalues);
|
|
|
|
this.xvalues = xvalues;
|
|
this.yvalues = yvalues;
|
|
this.yminmax = yminmax;
|
|
|
|
},
|
|
|
|
processRangeOptions: function () {
|
|
var options = this.options,
|
|
normalRangeMin = options.get('normalRangeMin'),
|
|
normalRangeMax = options.get('normalRangeMax');
|
|
|
|
if (normalRangeMin !== undefined) {
|
|
if (normalRangeMin < this.miny) {
|
|
this.miny = normalRangeMin;
|
|
}
|
|
if (normalRangeMax > this.maxy) {
|
|
this.maxy = normalRangeMax;
|
|
}
|
|
}
|
|
if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {
|
|
this.miny = options.get('chartRangeMin');
|
|
}
|
|
if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {
|
|
this.maxy = options.get('chartRangeMax');
|
|
}
|
|
if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {
|
|
this.minx = options.get('chartRangeMinX');
|
|
}
|
|
if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {
|
|
this.maxx = options.get('chartRangeMaxX');
|
|
}
|
|
|
|
},
|
|
|
|
drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
|
|
var normalRangeMin = this.options.get('normalRangeMin'),
|
|
normalRangeMax = this.options.get('normalRangeMax'),
|
|
ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),
|
|
height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);
|
|
this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();
|
|
},
|
|
|
|
render: function () {
|
|
var options = this.options,
|
|
target = this.target,
|
|
canvasWidth = this.canvasWidth,
|
|
canvasHeight = this.canvasHeight,
|
|
vertices = this.vertices,
|
|
spotRadius = options.get('spotRadius'),
|
|
regionMap = this.regionMap,
|
|
rangex, rangey, yvallast,
|
|
canvasTop, canvasLeft,
|
|
vertex, path, paths, x, y, xnext, xpos, xposnext,
|
|
last, next, yvalcount, lineShapes, fillShapes, plen,
|
|
valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
|
|
|
|
if (!line._super.render.call(this)) {
|
|
return;
|
|
}
|
|
|
|
this.scanValues();
|
|
this.processRangeOptions();
|
|
|
|
xvalues = this.xvalues;
|
|
yvalues = this.yvalues;
|
|
|
|
if (!this.yminmax.length || this.yvalues.length < 2) {
|
|
// empty or all null valuess
|
|
return;
|
|
}
|
|
|
|
canvasTop = canvasLeft = 0;
|
|
|
|
rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
|
|
rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
|
|
yvallast = this.yvalues.length - 1;
|
|
|
|
if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {
|
|
spotRadius = 0;
|
|
}
|
|
if (spotRadius) {
|
|
// adjust the canvas size as required so that spots will fit
|
|
hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');
|
|
if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {
|
|
canvasHeight -= Math.ceil(spotRadius);
|
|
}
|
|
if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {
|
|
canvasHeight -= Math.ceil(spotRadius);
|
|
canvasTop += Math.ceil(spotRadius);
|
|
}
|
|
if (hlSpotsEnabled ||
|
|
((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {
|
|
canvasLeft += Math.ceil(spotRadius);
|
|
canvasWidth -= Math.ceil(spotRadius);
|
|
}
|
|
if (hlSpotsEnabled || options.get('spotColor') ||
|
|
(options.get('minSpotColor') || options.get('maxSpotColor') &&
|
|
(yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
|
|
canvasWidth -= Math.ceil(spotRadius);
|
|
}
|
|
}
|
|
|
|
|
|
canvasHeight--;
|
|
|
|
if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {
|
|
this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
|
|
}
|
|
|
|
path = [];
|
|
paths = [path];
|
|
last = next = null;
|
|
yvalcount = yvalues.length;
|
|
for (i = 0; i < yvalcount; i++) {
|
|
x = xvalues[i];
|
|
xnext = xvalues[i + 1];
|
|
y = yvalues[i];
|
|
xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));
|
|
xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
|
|
next = xpos + ((xposnext - xpos) / 2);
|
|
regionMap[i] = [last || 0, next, i];
|
|
last = next;
|
|
if (y === null) {
|
|
if (i) {
|
|
if (yvalues[i - 1] !== null) {
|
|
path = [];
|
|
paths.push(path);
|
|
}
|
|
vertices.push(null);
|
|
}
|
|
} else {
|
|
if (y < this.miny) {
|
|
y = this.miny;
|
|
}
|
|
if (y > this.maxy) {
|
|
y = this.maxy;
|
|
}
|
|
if (!path.length) {
|
|
// previous value was null
|
|
path.push([xpos, canvasTop + canvasHeight]);
|
|
}
|
|
vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];
|
|
path.push(vertex);
|
|
vertices.push(vertex);
|
|
}
|
|
}
|
|
|
|
lineShapes = [];
|
|
fillShapes = [];
|
|
plen = paths.length;
|
|
for (i = 0; i < plen; i++) {
|
|
path = paths[i];
|
|
if (path.length) {
|
|
if (options.get('fillColor')) {
|
|
path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);
|
|
fillShapes.push(path.slice(0));
|
|
path.pop();
|
|
}
|
|
// if there's only a single point in this path, then we want to display it
|
|
// as a vertical line which means we keep path[0] as is
|
|
if (path.length > 2) {
|
|
// else we want the first value
|
|
path[0] = [path[0][0], path[1][1]];
|
|
}
|
|
lineShapes.push(path);
|
|
}
|
|
}
|
|
|
|
// draw the fill first, then optionally the normal range, then the line on top of that
|
|
plen = fillShapes.length;
|
|
for (i = 0; i < plen; i++) {
|
|
target.drawShape(fillShapes[i],
|
|
options.get('fillColor'), options.get('fillColor')).append();
|
|
}
|
|
|
|
if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {
|
|
this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
|
|
}
|
|
|
|
plen = lineShapes.length;
|
|
for (i = 0; i < plen; i++) {
|
|
target.drawShape(lineShapes[i], options.get('lineColor'), undefined,
|
|
options.get('lineWidth')).append();
|
|
}
|
|
|
|
if (spotRadius && options.get('valueSpots')) {
|
|
valueSpots = options.get('valueSpots');
|
|
if (valueSpots.get === undefined) {
|
|
valueSpots = new RangeMap(valueSpots);
|
|
}
|
|
for (i = 0; i < yvalcount; i++) {
|
|
color = valueSpots.get(yvalues[i]);
|
|
if (color) {
|
|
target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),
|
|
spotRadius, undefined,
|
|
color).append();
|
|
}
|
|
}
|
|
|
|
}
|
|
if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {
|
|
target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),
|
|
spotRadius, undefined,
|
|
options.get('spotColor')).append();
|
|
}
|
|
if (this.maxy !== this.minyorg) {
|
|
if (spotRadius && options.get('minSpotColor')) {
|
|
x = xvalues[$.inArray(this.minyorg, yvalues)];
|
|
target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),
|
|
spotRadius, undefined,
|
|
options.get('minSpotColor')).append();
|
|
}
|
|
if (spotRadius && options.get('maxSpotColor')) {
|
|
x = xvalues[$.inArray(this.maxyorg, yvalues)];
|
|
target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
|
|
canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),
|
|
spotRadius, undefined,
|
|
options.get('maxSpotColor')).append();
|
|
}
|
|
}
|
|
|
|
this.lastShapeId = target.getLastShapeId();
|
|
this.canvasTop = canvasTop;
|
|
target.render();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Bar charts
|
|
*/
|
|
$.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {
|
|
type: 'bar',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
var barWidth = parseInt(options.get('barWidth'), 10),
|
|
barSpacing = parseInt(options.get('barSpacing'), 10),
|
|
chartRangeMin = options.get('chartRangeMin'),
|
|
chartRangeMax = options.get('chartRangeMax'),
|
|
chartRangeClip = options.get('chartRangeClip'),
|
|
stackMin = Infinity,
|
|
stackMax = -Infinity,
|
|
isStackString, groupMin, groupMax, stackRanges,
|
|
numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,
|
|
stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;
|
|
bar._super.init.call(this, el, values, options, width, height);
|
|
|
|
// scan values to determine whether to stack bars
|
|
for (i = 0, vlen = values.length; i < vlen; i++) {
|
|
val = values[i];
|
|
isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;
|
|
if (isStackString || $.isArray(val)) {
|
|
stacked = true;
|
|
if (isStackString) {
|
|
val = values[i] = normalizeValues(val.split(':'));
|
|
}
|
|
val = remove(val, null); // min/max will treat null as zero
|
|
groupMin = Math.min.apply(Math, val);
|
|
groupMax = Math.max.apply(Math, val);
|
|
if (groupMin < stackMin) {
|
|
stackMin = groupMin;
|
|
}
|
|
if (groupMax > stackMax) {
|
|
stackMax = groupMax;
|
|
}
|
|
}
|
|
}
|
|
|
|
this.stacked = stacked;
|
|
this.regionShapes = {};
|
|
this.barWidth = barWidth;
|
|
this.barSpacing = barSpacing;
|
|
this.totalBarWidth = barWidth + barSpacing;
|
|
this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
|
|
|
|
this.initTarget();
|
|
|
|
if (chartRangeClip) {
|
|
clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;
|
|
clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;
|
|
}
|
|
|
|
numValues = [];
|
|
stackRanges = stacked ? [] : numValues;
|
|
var stackTotals = [];
|
|
var stackRangesNeg = [];
|
|
for (i = 0, vlen = values.length; i < vlen; i++) {
|
|
if (stacked) {
|
|
vlist = values[i];
|
|
values[i] = svals = [];
|
|
stackTotals[i] = 0;
|
|
stackRanges[i] = stackRangesNeg[i] = 0;
|
|
for (j = 0, slen = vlist.length; j < slen; j++) {
|
|
val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];
|
|
if (val !== null) {
|
|
if (val > 0) {
|
|
stackTotals[i] += val;
|
|
}
|
|
if (stackMin < 0 && stackMax > 0) {
|
|
if (val < 0) {
|
|
stackRangesNeg[i] += Math.abs(val);
|
|
} else {
|
|
stackRanges[i] += val;
|
|
}
|
|
} else {
|
|
stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));
|
|
}
|
|
numValues.push(val);
|
|
}
|
|
}
|
|
} else {
|
|
val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];
|
|
val = values[i] = normalizeValue(val);
|
|
if (val !== null) {
|
|
numValues.push(val);
|
|
}
|
|
}
|
|
}
|
|
this.max = max = Math.max.apply(Math, numValues);
|
|
this.min = min = Math.min.apply(Math, numValues);
|
|
this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;
|
|
this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;
|
|
|
|
if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {
|
|
min = options.get('chartRangeMin');
|
|
}
|
|
if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {
|
|
max = options.get('chartRangeMax');
|
|
}
|
|
|
|
this.zeroAxis = zeroAxis = options.get('zeroAxis', true);
|
|
if (min <= 0 && max >= 0 && zeroAxis) {
|
|
xaxisOffset = 0;
|
|
} else if (zeroAxis == false) {
|
|
xaxisOffset = min;
|
|
} else if (min > 0) {
|
|
xaxisOffset = min;
|
|
} else {
|
|
xaxisOffset = max;
|
|
}
|
|
this.xaxisOffset = xaxisOffset;
|
|
|
|
range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;
|
|
|
|
// as we plot zero/min values a single pixel line, we add a pixel to all other
|
|
// values - Reduce the effective canvas size to suit
|
|
this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;
|
|
|
|
if (min < xaxisOffset) {
|
|
yMaxCalc = (stacked && max >= 0) ? stackMax : max;
|
|
yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;
|
|
if (yoffset !== Math.ceil(yoffset)) {
|
|
this.canvasHeightEf -= 2;
|
|
yoffset = Math.ceil(yoffset);
|
|
}
|
|
} else {
|
|
yoffset = this.canvasHeight;
|
|
}
|
|
this.yoffset = yoffset;
|
|
|
|
if ($.isArray(options.get('colorMap'))) {
|
|
this.colorMapByIndex = options.get('colorMap');
|
|
this.colorMapByValue = null;
|
|
} else {
|
|
this.colorMapByIndex = null;
|
|
this.colorMapByValue = options.get('colorMap');
|
|
if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
|
|
this.colorMapByValue = new RangeMap(this.colorMapByValue);
|
|
}
|
|
}
|
|
|
|
this.range = range;
|
|
},
|
|
|
|
getRegion: function (el, x, y) {
|
|
var result = Math.floor(x / this.totalBarWidth);
|
|
return (result < 0 || result >= this.values.length) ? undefined : result;
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var currentRegion = this.currentRegion,
|
|
values = ensureArray(this.values[currentRegion]),
|
|
result = [],
|
|
value, i;
|
|
for (i = values.length; i--;) {
|
|
value = values[i];
|
|
result.push({
|
|
isNull: value === null,
|
|
value: value,
|
|
color: this.calcColor(i, value, currentRegion),
|
|
offset: currentRegion
|
|
});
|
|
}
|
|
return result;
|
|
},
|
|
|
|
calcColor: function (stacknum, value, valuenum) {
|
|
var colorMapByIndex = this.colorMapByIndex,
|
|
colorMapByValue = this.colorMapByValue,
|
|
options = this.options,
|
|
color, newColor;
|
|
if (this.stacked) {
|
|
color = options.get('stackedBarColor');
|
|
} else {
|
|
color = (value < 0) ? options.get('negBarColor') : options.get('barColor');
|
|
}
|
|
if (value === 0 && options.get('zeroColor') !== undefined) {
|
|
color = options.get('zeroColor');
|
|
}
|
|
if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
|
|
color = newColor;
|
|
} else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
|
|
color = colorMapByIndex[valuenum];
|
|
}
|
|
return $.isArray(color) ? color[stacknum % color.length] : color;
|
|
},
|
|
|
|
/**
|
|
* Render bar(s) for a region
|
|
*/
|
|
renderRegion: function (valuenum, highlight) {
|
|
var vals = this.values[valuenum],
|
|
options = this.options,
|
|
xaxisOffset = this.xaxisOffset,
|
|
result = [],
|
|
range = this.range,
|
|
stacked = this.stacked,
|
|
target = this.target,
|
|
x = valuenum * this.totalBarWidth,
|
|
canvasHeightEf = this.canvasHeightEf,
|
|
yoffset = this.yoffset,
|
|
y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;
|
|
|
|
vals = $.isArray(vals) ? vals : [vals];
|
|
valcount = vals.length;
|
|
val = vals[0];
|
|
isNull = all(null, vals);
|
|
allMin = all(xaxisOffset, vals, true);
|
|
|
|
if (isNull) {
|
|
if (options.get('nullColor')) {
|
|
color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);
|
|
y = (yoffset > 0) ? yoffset - 1 : yoffset;
|
|
return target.drawRect(x, y, this.barWidth - 1, 0, color, color);
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
yoffsetNeg = yoffset;
|
|
for (i = 0; i < valcount; i++) {
|
|
val = vals[i];
|
|
|
|
if (stacked && val === xaxisOffset) {
|
|
if (!allMin || minPlotted) {
|
|
continue;
|
|
}
|
|
minPlotted = true;
|
|
}
|
|
|
|
if (range > 0) {
|
|
height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;
|
|
} else {
|
|
height = 1;
|
|
}
|
|
if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {
|
|
y = yoffsetNeg;
|
|
yoffsetNeg += height;
|
|
} else {
|
|
y = yoffset - height;
|
|
yoffset -= height;
|
|
}
|
|
color = this.calcColor(i, val, valuenum);
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));
|
|
}
|
|
if (result.length === 1) {
|
|
return result[0];
|
|
}
|
|
return result;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Tristate charts
|
|
*/
|
|
$.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {
|
|
type: 'tristate',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
var barWidth = parseInt(options.get('barWidth'), 10),
|
|
barSpacing = parseInt(options.get('barSpacing'), 10);
|
|
tristate._super.init.call(this, el, values, options, width, height);
|
|
|
|
this.regionShapes = {};
|
|
this.barWidth = barWidth;
|
|
this.barSpacing = barSpacing;
|
|
this.totalBarWidth = barWidth + barSpacing;
|
|
this.values = $.map(values, Number);
|
|
this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
|
|
|
|
if ($.isArray(options.get('colorMap'))) {
|
|
this.colorMapByIndex = options.get('colorMap');
|
|
this.colorMapByValue = null;
|
|
} else {
|
|
this.colorMapByIndex = null;
|
|
this.colorMapByValue = options.get('colorMap');
|
|
if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
|
|
this.colorMapByValue = new RangeMap(this.colorMapByValue);
|
|
}
|
|
}
|
|
this.initTarget();
|
|
},
|
|
|
|
getRegion: function (el, x, y) {
|
|
return Math.floor(x / this.totalBarWidth);
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.values[currentRegion] === undefined,
|
|
value: this.values[currentRegion],
|
|
color: this.calcColor(this.values[currentRegion], currentRegion),
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
|
|
calcColor: function (value, valuenum) {
|
|
var values = this.values,
|
|
options = this.options,
|
|
colorMapByIndex = this.colorMapByIndex,
|
|
colorMapByValue = this.colorMapByValue,
|
|
color, newColor;
|
|
|
|
if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
|
|
color = newColor;
|
|
} else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
|
|
color = colorMapByIndex[valuenum];
|
|
} else if (values[valuenum] < 0) {
|
|
color = options.get('negBarColor');
|
|
} else if (values[valuenum] > 0) {
|
|
color = options.get('posBarColor');
|
|
} else {
|
|
color = options.get('zeroBarColor');
|
|
}
|
|
return color;
|
|
},
|
|
|
|
renderRegion: function (valuenum, highlight) {
|
|
var values = this.values,
|
|
options = this.options,
|
|
target = this.target,
|
|
canvasHeight, height, halfHeight,
|
|
x, y, color;
|
|
|
|
canvasHeight = target.pixelHeight;
|
|
halfHeight = Math.round(canvasHeight / 2);
|
|
|
|
x = valuenum * this.totalBarWidth;
|
|
if (values[valuenum] < 0) {
|
|
y = halfHeight;
|
|
height = halfHeight - 1;
|
|
} else if (values[valuenum] > 0) {
|
|
y = 0;
|
|
height = halfHeight - 1;
|
|
} else {
|
|
y = halfHeight - 1;
|
|
height = 2;
|
|
}
|
|
color = this.calcColor(values[valuenum], valuenum);
|
|
if (color === null) {
|
|
return;
|
|
}
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Discrete charts
|
|
*/
|
|
$.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {
|
|
type: 'discrete',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
discrete._super.init.call(this, el, values, options, width, height);
|
|
|
|
this.regionShapes = {};
|
|
this.values = values = $.map(values, Number);
|
|
this.min = Math.min.apply(Math, values);
|
|
this.max = Math.max.apply(Math, values);
|
|
this.range = this.max - this.min;
|
|
this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;
|
|
this.interval = Math.floor(width / values.length);
|
|
this.itemWidth = width / values.length;
|
|
if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {
|
|
this.min = options.get('chartRangeMin');
|
|
}
|
|
if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {
|
|
this.max = options.get('chartRangeMax');
|
|
}
|
|
this.initTarget();
|
|
if (this.target) {
|
|
this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');
|
|
}
|
|
},
|
|
|
|
getRegion: function (el, x, y) {
|
|
return Math.floor(x / this.itemWidth);
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.values[currentRegion] === undefined,
|
|
value: this.values[currentRegion],
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
|
|
renderRegion: function (valuenum, highlight) {
|
|
var values = this.values,
|
|
options = this.options,
|
|
min = this.min,
|
|
max = this.max,
|
|
range = this.range,
|
|
interval = this.interval,
|
|
target = this.target,
|
|
canvasHeight = this.canvasHeight,
|
|
lineHeight = this.lineHeight,
|
|
pheight = canvasHeight - lineHeight,
|
|
ytop, val, color, x;
|
|
|
|
val = clipval(values[valuenum], min, max);
|
|
x = valuenum * interval;
|
|
ytop = Math.round(pheight - pheight * ((val - min) / range));
|
|
color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
return target.drawLine(x, ytop, x, ytop + lineHeight, color);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Bullet charts
|
|
*/
|
|
$.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {
|
|
type: 'bullet',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
var min, max, vals;
|
|
bullet._super.init.call(this, el, values, options, width, height);
|
|
|
|
// values: target, performance, range1, range2, range3
|
|
this.values = values = normalizeValues(values);
|
|
// target or performance could be null
|
|
vals = values.slice();
|
|
vals[0] = vals[0] === null ? vals[2] : vals[0];
|
|
vals[1] = values[1] === null ? vals[2] : vals[1];
|
|
min = Math.min.apply(Math, values);
|
|
max = Math.max.apply(Math, values);
|
|
if (options.get('base') === undefined) {
|
|
min = min < 0 ? min : 0;
|
|
} else {
|
|
min = options.get('base');
|
|
}
|
|
this.min = min;
|
|
this.max = max;
|
|
this.range = max - min;
|
|
this.shapes = {};
|
|
this.valueShapes = {};
|
|
this.regiondata = {};
|
|
this.width = width = options.get('width') === 'auto' ? '4.0em' : width;
|
|
this.target = this.$el.simpledraw(width, height, options.get('composite'));
|
|
if (!values.length) {
|
|
this.disabled = true;
|
|
}
|
|
this.initTarget();
|
|
},
|
|
|
|
getRegion: function (el, x, y) {
|
|
var shapeid = this.target.getShapeAt(el, x, y);
|
|
return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
fieldkey: currentRegion.substr(0, 1),
|
|
value: this.values[currentRegion.substr(1)],
|
|
region: currentRegion
|
|
};
|
|
},
|
|
|
|
changeHighlight: function (highlight) {
|
|
var currentRegion = this.currentRegion,
|
|
shapeid = this.valueShapes[currentRegion],
|
|
shape;
|
|
delete this.shapes[shapeid];
|
|
switch (currentRegion.substr(0, 1)) {
|
|
case 'r':
|
|
shape = this.renderRange(currentRegion.substr(1), highlight);
|
|
break;
|
|
case 'p':
|
|
shape = this.renderPerformance(highlight);
|
|
break;
|
|
case 't':
|
|
shape = this.renderTarget(highlight);
|
|
break;
|
|
}
|
|
this.valueShapes[currentRegion] = shape.id;
|
|
this.shapes[shape.id] = currentRegion;
|
|
this.target.replaceWithShape(shapeid, shape);
|
|
},
|
|
|
|
renderRange: function (rn, highlight) {
|
|
var rangeval = this.values[rn],
|
|
rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),
|
|
color = this.options.get('rangeColors')[rn - 2];
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, this.options);
|
|
}
|
|
return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
|
|
},
|
|
|
|
renderPerformance: function (highlight) {
|
|
var perfval = this.values[1],
|
|
perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),
|
|
color = this.options.get('performanceColor');
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, this.options);
|
|
}
|
|
return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,
|
|
Math.round(this.canvasHeight * 0.4) - 1, color, color);
|
|
},
|
|
|
|
renderTarget: function (highlight) {
|
|
var targetval = this.values[0],
|
|
x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),
|
|
targettop = Math.round(this.canvasHeight * 0.10),
|
|
targetheight = this.canvasHeight - (targettop * 2),
|
|
color = this.options.get('targetColor');
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, this.options);
|
|
}
|
|
return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);
|
|
},
|
|
|
|
render: function () {
|
|
var vlen = this.values.length,
|
|
target = this.target,
|
|
i, shape;
|
|
if (!bullet._super.render.call(this)) {
|
|
return;
|
|
}
|
|
for (i = 2; i < vlen; i++) {
|
|
shape = this.renderRange(i).append();
|
|
this.shapes[shape.id] = 'r' + i;
|
|
this.valueShapes['r' + i] = shape.id;
|
|
}
|
|
if (this.values[1] !== null) {
|
|
shape = this.renderPerformance().append();
|
|
this.shapes[shape.id] = 'p1';
|
|
this.valueShapes.p1 = shape.id;
|
|
}
|
|
if (this.values[0] !== null) {
|
|
shape = this.renderTarget().append();
|
|
this.shapes[shape.id] = 't0';
|
|
this.valueShapes.t0 = shape.id;
|
|
}
|
|
target.render();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Pie charts
|
|
*/
|
|
$.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {
|
|
type: 'pie',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
var total = 0, i;
|
|
|
|
pie._super.init.call(this, el, values, options, width, height);
|
|
|
|
this.shapes = {}; // map shape ids to value offsets
|
|
this.valueShapes = {}; // maps value offsets to shape ids
|
|
this.values = values = $.map(values, Number);
|
|
|
|
if (options.get('width') === 'auto') {
|
|
this.width = this.height;
|
|
}
|
|
|
|
if (values.length > 0) {
|
|
for (i = values.length; i--;) {
|
|
total += values[i];
|
|
}
|
|
}
|
|
this.total = total;
|
|
this.initTarget();
|
|
this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);
|
|
},
|
|
|
|
getRegion: function (el, x, y) {
|
|
var shapeid = this.target.getShapeAt(el, x, y);
|
|
return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var currentRegion = this.currentRegion;
|
|
return {
|
|
isNull: this.values[currentRegion] === undefined,
|
|
value: this.values[currentRegion],
|
|
percent: this.values[currentRegion] / this.total * 100,
|
|
color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],
|
|
offset: currentRegion
|
|
};
|
|
},
|
|
|
|
changeHighlight: function (highlight) {
|
|
var currentRegion = this.currentRegion,
|
|
newslice = this.renderSlice(currentRegion, highlight),
|
|
shapeid = this.valueShapes[currentRegion];
|
|
delete this.shapes[shapeid];
|
|
this.target.replaceWithShape(shapeid, newslice);
|
|
this.valueShapes[currentRegion] = newslice.id;
|
|
this.shapes[newslice.id] = currentRegion;
|
|
},
|
|
|
|
renderSlice: function (valuenum, highlight) {
|
|
var target = this.target,
|
|
options = this.options,
|
|
radius = this.radius,
|
|
borderWidth = options.get('borderWidth'),
|
|
offset = options.get('offset'),
|
|
circle = 2 * Math.PI,
|
|
values = this.values,
|
|
total = this.total,
|
|
next = offset ? (2*Math.PI)*(offset/360) : 0,
|
|
start, end, i, vlen, color;
|
|
|
|
vlen = values.length;
|
|
for (i = 0; i < vlen; i++) {
|
|
start = next;
|
|
end = next;
|
|
if (total > 0) { // avoid divide by zero
|
|
end = next + (circle * (values[i] / total));
|
|
}
|
|
if (valuenum === i) {
|
|
color = options.get('sliceColors')[i % options.get('sliceColors').length];
|
|
if (highlight) {
|
|
color = this.calcHighlightColor(color, options);
|
|
}
|
|
|
|
return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);
|
|
}
|
|
next = end;
|
|
}
|
|
},
|
|
|
|
render: function () {
|
|
var target = this.target,
|
|
values = this.values,
|
|
options = this.options,
|
|
radius = this.radius,
|
|
borderWidth = options.get('borderWidth'),
|
|
shape, i;
|
|
|
|
if (!pie._super.render.call(this)) {
|
|
return;
|
|
}
|
|
if (borderWidth) {
|
|
target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),
|
|
options.get('borderColor'), undefined, borderWidth).append();
|
|
}
|
|
for (i = values.length; i--;) {
|
|
if (values[i]) { // don't render zero values
|
|
shape = this.renderSlice(i).append();
|
|
this.valueShapes[i] = shape.id; // store just the shapeid
|
|
this.shapes[shape.id] = i;
|
|
}
|
|
}
|
|
target.render();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Box plots
|
|
*/
|
|
$.fn.sparkline.box = box = createClass($.fn.sparkline._base, {
|
|
type: 'box',
|
|
|
|
init: function (el, values, options, width, height) {
|
|
box._super.init.call(this, el, values, options, width, height);
|
|
this.values = $.map(values, Number);
|
|
this.width = options.get('width') === 'auto' ? '4.0em' : width;
|
|
this.initTarget();
|
|
if (!this.values.length) {
|
|
this.disabled = 1;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Simulate a single region
|
|
*/
|
|
getRegion: function () {
|
|
return 1;
|
|
},
|
|
|
|
getCurrentRegionFields: function () {
|
|
var result = [
|
|
{ field: 'lq', value: this.quartiles[0] },
|
|
{ field: 'med', value: this.quartiles[1] },
|
|
{ field: 'uq', value: this.quartiles[2] }
|
|
];
|
|
if (this.loutlier !== undefined) {
|
|
result.push({ field: 'lo', value: this.loutlier});
|
|
}
|
|
if (this.routlier !== undefined) {
|
|
result.push({ field: 'ro', value: this.routlier});
|
|
}
|
|
if (this.lwhisker !== undefined) {
|
|
result.push({ field: 'lw', value: this.lwhisker});
|
|
}
|
|
if (this.rwhisker !== undefined) {
|
|
result.push({ field: 'rw', value: this.rwhisker});
|
|
}
|
|
return result;
|
|
},
|
|
|
|
render: function () {
|
|
var target = this.target,
|
|
values = this.values,
|
|
vlen = values.length,
|
|
options = this.options,
|
|
canvasWidth = this.canvasWidth,
|
|
canvasHeight = this.canvasHeight,
|
|
minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),
|
|
maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),
|
|
canvasLeft = 0,
|
|
lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,
|
|
size, unitSize;
|
|
|
|
if (!box._super.render.call(this)) {
|
|
return;
|
|
}
|
|
|
|
if (options.get('raw')) {
|
|
if (options.get('showOutliers') && values.length > 5) {
|
|
loutlier = values[0];
|
|
lwhisker = values[1];
|
|
q1 = values[2];
|
|
q2 = values[3];
|
|
q3 = values[4];
|
|
rwhisker = values[5];
|
|
routlier = values[6];
|
|
} else {
|
|
lwhisker = values[0];
|
|
q1 = values[1];
|
|
q2 = values[2];
|
|
q3 = values[3];
|
|
rwhisker = values[4];
|
|
}
|
|
} else {
|
|
values.sort(function (a, b) { return a - b; });
|
|
q1 = quartile(values, 1);
|
|
q2 = quartile(values, 2);
|
|
q3 = quartile(values, 3);
|
|
iqr = q3 - q1;
|
|
if (options.get('showOutliers')) {
|
|
lwhisker = rwhisker = undefined;
|
|
for (i = 0; i < vlen; i++) {
|
|
if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {
|
|
lwhisker = values[i];
|
|
}
|
|
if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {
|
|
rwhisker = values[i];
|
|
}
|
|
}
|
|
loutlier = values[0];
|
|
routlier = values[vlen - 1];
|
|
} else {
|
|
lwhisker = values[0];
|
|
rwhisker = values[vlen - 1];
|
|
}
|
|
}
|
|
this.quartiles = [q1, q2, q3];
|
|
this.lwhisker = lwhisker;
|
|
this.rwhisker = rwhisker;
|
|
this.loutlier = loutlier;
|
|
this.routlier = routlier;
|
|
|
|
unitSize = canvasWidth / (maxValue - minValue + 1);
|
|
if (options.get('showOutliers')) {
|
|
canvasLeft = Math.ceil(options.get('spotRadius'));
|
|
canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));
|
|
unitSize = canvasWidth / (maxValue - minValue + 1);
|
|
if (loutlier < lwhisker) {
|
|
target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,
|
|
canvasHeight / 2,
|
|
options.get('spotRadius'),
|
|
options.get('outlierLineColor'),
|
|
options.get('outlierFillColor')).append();
|
|
}
|
|
if (routlier > rwhisker) {
|
|
target.drawCircle((routlier - minValue) * unitSize + canvasLeft,
|
|
canvasHeight / 2,
|
|
options.get('spotRadius'),
|
|
options.get('outlierLineColor'),
|
|
options.get('outlierFillColor')).append();
|
|
}
|
|
}
|
|
|
|
// box
|
|
target.drawRect(
|
|
Math.round((q1 - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight * 0.1),
|
|
Math.round((q3 - q1) * unitSize),
|
|
Math.round(canvasHeight * 0.8),
|
|
options.get('boxLineColor'),
|
|
options.get('boxFillColor')).append();
|
|
// left whisker
|
|
target.drawLine(
|
|
Math.round((lwhisker - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight / 2),
|
|
Math.round((q1 - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight / 2),
|
|
options.get('lineColor')).append();
|
|
target.drawLine(
|
|
Math.round((lwhisker - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight / 4),
|
|
Math.round((lwhisker - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight - canvasHeight / 4),
|
|
options.get('whiskerColor')).append();
|
|
// right whisker
|
|
target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight / 2),
|
|
Math.round((q3 - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight / 2),
|
|
options.get('lineColor')).append();
|
|
target.drawLine(
|
|
Math.round((rwhisker - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight / 4),
|
|
Math.round((rwhisker - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight - canvasHeight / 4),
|
|
options.get('whiskerColor')).append();
|
|
// median line
|
|
target.drawLine(
|
|
Math.round((q2 - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight * 0.1),
|
|
Math.round((q2 - minValue) * unitSize + canvasLeft),
|
|
Math.round(canvasHeight * 0.9),
|
|
options.get('medianColor')).append();
|
|
if (options.get('target')) {
|
|
size = Math.ceil(options.get('spotRadius'));
|
|
target.drawLine(
|
|
Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
|
|
Math.round((canvasHeight / 2) - size),
|
|
Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
|
|
Math.round((canvasHeight / 2) + size),
|
|
options.get('targetColor')).append();
|
|
target.drawLine(
|
|
Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),
|
|
Math.round(canvasHeight / 2),
|
|
Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),
|
|
Math.round(canvasHeight / 2),
|
|
options.get('targetColor')).append();
|
|
}
|
|
target.render();
|
|
}
|
|
});
|
|
|
|
// Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
|
|
// This is accessible as $(foo).simpledraw()
|
|
|
|
VShape = createClass({
|
|
init: function (target, id, type, args) {
|
|
this.target = target;
|
|
this.id = id;
|
|
this.type = type;
|
|
this.args = args;
|
|
},
|
|
append: function () {
|
|
this.target.appendShape(this);
|
|
return this;
|
|
}
|
|
});
|
|
|
|
VCanvas_base = createClass({
|
|
_pxregex: /(\d+)(px)?\s*$/i,
|
|
|
|
init: function (width, height, target) {
|
|
if (!width) {
|
|
return;
|
|
}
|
|
this.width = width;
|
|
this.height = height;
|
|
this.target = target;
|
|
this.lastShapeId = null;
|
|
if (target[0]) {
|
|
target = target[0];
|
|
}
|
|
$.data(target, '_jqs_vcanvas', this);
|
|
},
|
|
|
|
drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {
|
|
return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);
|
|
},
|
|
|
|
drawShape: function (path, lineColor, fillColor, lineWidth) {
|
|
return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);
|
|
},
|
|
|
|
drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {
|
|
return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);
|
|
},
|
|
|
|
drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {
|
|
return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);
|
|
},
|
|
|
|
drawRect: function (x, y, width, height, lineColor, fillColor) {
|
|
return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);
|
|
},
|
|
|
|
getElement: function () {
|
|
return this.canvas;
|
|
},
|
|
|
|
/**
|
|
* Return the most recently inserted shape id
|
|
*/
|
|
getLastShapeId: function () {
|
|
return this.lastShapeId;
|
|
},
|
|
|
|
/**
|
|
* Clear and reset the canvas
|
|
*/
|
|
reset: function () {
|
|
alert('reset not implemented');
|
|
},
|
|
|
|
_insert: function (el, target) {
|
|
$(target).html(el);
|
|
},
|
|
|
|
/**
|
|
* Calculate the pixel dimensions of the canvas
|
|
*/
|
|
_calculatePixelDims: function (width, height, canvas) {
|
|
// XXX This should probably be a configurable option
|
|
var match;
|
|
match = this._pxregex.exec(height);
|
|
if (match) {
|
|
this.pixelHeight = match[1];
|
|
} else {
|
|
this.pixelHeight = $(canvas).height();
|
|
}
|
|
match = this._pxregex.exec(width);
|
|
if (match) {
|
|
this.pixelWidth = match[1];
|
|
} else {
|
|
this.pixelWidth = $(canvas).width();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Generate a shape object and id for later rendering
|
|
*/
|
|
_genShape: function (shapetype, shapeargs) {
|
|
var id = shapeCount++;
|
|
shapeargs.unshift(id);
|
|
return new VShape(this, id, shapetype, shapeargs);
|
|
},
|
|
|
|
/**
|
|
* Add a shape to the end of the render queue
|
|
*/
|
|
appendShape: function (shape) {
|
|
alert('appendShape not implemented');
|
|
},
|
|
|
|
/**
|
|
* Replace one shape with another
|
|
*/
|
|
replaceWithShape: function (shapeid, shape) {
|
|
alert('replaceWithShape not implemented');
|
|
},
|
|
|
|
/**
|
|
* Insert one shape after another in the render queue
|
|
*/
|
|
insertAfterShape: function (shapeid, shape) {
|
|
alert('insertAfterShape not implemented');
|
|
},
|
|
|
|
/**
|
|
* Remove a shape from the queue
|
|
*/
|
|
removeShapeId: function (shapeid) {
|
|
alert('removeShapeId not implemented');
|
|
},
|
|
|
|
/**
|
|
* Find a shape at the specified x/y co-ordinates
|
|
*/
|
|
getShapeAt: function (el, x, y) {
|
|
alert('getShapeAt not implemented');
|
|
},
|
|
|
|
/**
|
|
* Render all queued shapes onto the canvas
|
|
*/
|
|
render: function () {
|
|
alert('render not implemented');
|
|
}
|
|
});
|
|
|
|
VCanvas_canvas = createClass(VCanvas_base, {
|
|
init: function (width, height, target, interact) {
|
|
VCanvas_canvas._super.init.call(this, width, height, target);
|
|
this.canvas = document.createElement('canvas');
|
|
if (target[0]) {
|
|
target = target[0];
|
|
}
|
|
$.data(target, '_jqs_vcanvas', this);
|
|
$(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });
|
|
this._insert(this.canvas, target);
|
|
this._calculatePixelDims(width, height, this.canvas);
|
|
this.canvas.width = this.pixelWidth;
|
|
this.canvas.height = this.pixelHeight;
|
|
this.interact = interact;
|
|
this.shapes = {};
|
|
this.shapeseq = [];
|
|
this.currentTargetShapeId = undefined;
|
|
$(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});
|
|
},
|
|
|
|
_getContext: function (lineColor, fillColor, lineWidth) {
|
|
var context = this.canvas.getContext('2d');
|
|
if (lineColor !== undefined) {
|
|
context.strokeStyle = lineColor;
|
|
}
|
|
context.lineWidth = lineWidth === undefined ? 1 : lineWidth;
|
|
if (fillColor !== undefined) {
|
|
context.fillStyle = fillColor;
|
|
}
|
|
return context;
|
|
},
|
|
|
|
reset: function () {
|
|
var context = this._getContext();
|
|
context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
|
|
this.shapes = {};
|
|
this.shapeseq = [];
|
|
this.currentTargetShapeId = undefined;
|
|
},
|
|
|
|
_drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
|
|
var context = this._getContext(lineColor, fillColor, lineWidth),
|
|
i, plen;
|
|
context.beginPath();
|
|
context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);
|
|
for (i = 1, plen = path.length; i < plen; i++) {
|
|
context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines
|
|
}
|
|
if (lineColor !== undefined) {
|
|
context.stroke();
|
|
}
|
|
if (fillColor !== undefined) {
|
|
context.fill();
|
|
}
|
|
if (this.targetX !== undefined && this.targetY !== undefined &&
|
|
context.isPointInPath(this.targetX, this.targetY)) {
|
|
this.currentTargetShapeId = shapeid;
|
|
}
|
|
},
|
|
|
|
_drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
|
|
var context = this._getContext(lineColor, fillColor, lineWidth);
|
|
context.beginPath();
|
|
context.arc(x, y, radius, 0, 2 * Math.PI, false);
|
|
if (this.targetX !== undefined && this.targetY !== undefined &&
|
|
context.isPointInPath(this.targetX, this.targetY)) {
|
|
this.currentTargetShapeId = shapeid;
|
|
}
|
|
if (lineColor !== undefined) {
|
|
context.stroke();
|
|
}
|
|
if (fillColor !== undefined) {
|
|
context.fill();
|
|
}
|
|
},
|
|
|
|
_drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
|
|
var context = this._getContext(lineColor, fillColor);
|
|
context.beginPath();
|
|
context.moveTo(x, y);
|
|
context.arc(x, y, radius, startAngle, endAngle, false);
|
|
context.lineTo(x, y);
|
|
context.closePath();
|
|
if (lineColor !== undefined) {
|
|
context.stroke();
|
|
}
|
|
if (fillColor) {
|
|
context.fill();
|
|
}
|
|
if (this.targetX !== undefined && this.targetY !== undefined &&
|
|
context.isPointInPath(this.targetX, this.targetY)) {
|
|
this.currentTargetShapeId = shapeid;
|
|
}
|
|
},
|
|
|
|
_drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
|
|
return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);
|
|
},
|
|
|
|
appendShape: function (shape) {
|
|
this.shapes[shape.id] = shape;
|
|
this.shapeseq.push(shape.id);
|
|
this.lastShapeId = shape.id;
|
|
return shape.id;
|
|
},
|
|
|
|
replaceWithShape: function (shapeid, shape) {
|
|
var shapeseq = this.shapeseq,
|
|
i;
|
|
this.shapes[shape.id] = shape;
|
|
for (i = shapeseq.length; i--;) {
|
|
if (shapeseq[i] == shapeid) {
|
|
shapeseq[i] = shape.id;
|
|
}
|
|
}
|
|
delete this.shapes[shapeid];
|
|
},
|
|
|
|
replaceWithShapes: function (shapeids, shapes) {
|
|
var shapeseq = this.shapeseq,
|
|
shapemap = {},
|
|
sid, i, first;
|
|
|
|
for (i = shapeids.length; i--;) {
|
|
shapemap[shapeids[i]] = true;
|
|
}
|
|
for (i = shapeseq.length; i--;) {
|
|
sid = shapeseq[i];
|
|
if (shapemap[sid]) {
|
|
shapeseq.splice(i, 1);
|
|
delete this.shapes[sid];
|
|
first = i;
|
|
}
|
|
}
|
|
for (i = shapes.length; i--;) {
|
|
shapeseq.splice(first, 0, shapes[i].id);
|
|
this.shapes[shapes[i].id] = shapes[i];
|
|
}
|
|
|
|
},
|
|
|
|
insertAfterShape: function (shapeid, shape) {
|
|
var shapeseq = this.shapeseq,
|
|
i;
|
|
for (i = shapeseq.length; i--;) {
|
|
if (shapeseq[i] === shapeid) {
|
|
shapeseq.splice(i + 1, 0, shape.id);
|
|
this.shapes[shape.id] = shape;
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
|
|
removeShapeId: function (shapeid) {
|
|
var shapeseq = this.shapeseq,
|
|
i;
|
|
for (i = shapeseq.length; i--;) {
|
|
if (shapeseq[i] === shapeid) {
|
|
shapeseq.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
delete this.shapes[shapeid];
|
|
},
|
|
|
|
getShapeAt: function (el, x, y) {
|
|
this.targetX = x;
|
|
this.targetY = y;
|
|
this.render();
|
|
return this.currentTargetShapeId;
|
|
},
|
|
|
|
render: function () {
|
|
var shapeseq = this.shapeseq,
|
|
shapes = this.shapes,
|
|
shapeCount = shapeseq.length,
|
|
context = this._getContext(),
|
|
shapeid, shape, i;
|
|
context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
|
|
for (i = 0; i < shapeCount; i++) {
|
|
shapeid = shapeseq[i];
|
|
shape = shapes[shapeid];
|
|
this['_draw' + shape.type].apply(this, shape.args);
|
|
}
|
|
if (!this.interact) {
|
|
// not interactive so no need to keep the shapes array
|
|
this.shapes = {};
|
|
this.shapeseq = [];
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
VCanvas_vml = createClass(VCanvas_base, {
|
|
init: function (width, height, target) {
|
|
var groupel;
|
|
VCanvas_vml._super.init.call(this, width, height, target);
|
|
if (target[0]) {
|
|
target = target[0];
|
|
}
|
|
$.data(target, '_jqs_vcanvas', this);
|
|
this.canvas = document.createElement('span');
|
|
$(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});
|
|
this._insert(this.canvas, target);
|
|
this._calculatePixelDims(width, height, this.canvas);
|
|
this.canvas.width = this.pixelWidth;
|
|
this.canvas.height = this.pixelHeight;
|
|
groupel = '<v:group coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '"' +
|
|
' style="position:absolute;top:0;left:0;width:' + this.pixelWidth + 'px;height=' + this.pixelHeight + 'px;"></v:group>';
|
|
this.canvas.insertAdjacentHTML('beforeEnd', groupel);
|
|
this.group = $(this.canvas).children()[0];
|
|
this.rendered = false;
|
|
this.prerender = '';
|
|
},
|
|
|
|
_drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
|
|
var vpath = [],
|
|
initial, stroke, fill, closed, vel, plen, i;
|
|
for (i = 0, plen = path.length; i < plen; i++) {
|
|
vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);
|
|
}
|
|
initial = vpath.splice(0, 1);
|
|
lineWidth = lineWidth === undefined ? 1 : lineWidth;
|
|
stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
|
|
fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
|
|
closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';
|
|
vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
|
|
' id="jqsshape' + shapeid + '" ' +
|
|
stroke +
|
|
fill +
|
|
' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
|
|
' path="m ' + initial + ' l ' + vpath.join(', ') + ' ' + closed + 'e">' +
|
|
' </v:shape>';
|
|
return vel;
|
|
},
|
|
|
|
_drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
|
|
var stroke, fill, vel;
|
|
x -= radius;
|
|
y -= radius;
|
|
stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
|
|
fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
|
|
vel = '<v:oval ' +
|
|
' id="jqsshape' + shapeid + '" ' +
|
|
stroke +
|
|
fill +
|
|
' style="position:absolute;top:' + y + 'px; left:' + x + 'px; width:' + (radius * 2) + 'px; height:' + (radius * 2) + 'px"></v:oval>';
|
|
return vel;
|
|
|
|
},
|
|
|
|
_drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
|
|
var vpath, startx, starty, endx, endy, stroke, fill, vel;
|
|
if (startAngle === endAngle) {
|
|
return ''; // VML seems to have problem when start angle equals end angle.
|
|
}
|
|
if ((endAngle - startAngle) === (2 * Math.PI)) {
|
|
startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0
|
|
endAngle = (2 * Math.PI);
|
|
}
|
|
|
|
startx = x + Math.round(Math.cos(startAngle) * radius);
|
|
starty = y + Math.round(Math.sin(startAngle) * radius);
|
|
endx = x + Math.round(Math.cos(endAngle) * radius);
|
|
endy = y + Math.round(Math.sin(endAngle) * radius);
|
|
|
|
if (startx === endx && starty === endy) {
|
|
if ((endAngle - startAngle) < Math.PI) {
|
|
// Prevent very small slices from being mistaken as a whole pie
|
|
return '';
|
|
}
|
|
// essentially going to be the entire circle, so ignore startAngle
|
|
startx = endx = x + radius;
|
|
starty = endy = y;
|
|
}
|
|
|
|
if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {
|
|
return '';
|
|
}
|
|
|
|
vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
|
|
stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '" ';
|
|
fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
|
|
vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
|
|
' id="jqsshape' + shapeid + '" ' +
|
|
stroke +
|
|
fill +
|
|
' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
|
|
' path="m ' + x + ',' + y + ' wa ' + vpath.join(', ') + ' x e">' +
|
|
' </v:shape>';
|
|
return vel;
|
|
},
|
|
|
|
_drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
|
|
return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);
|
|
},
|
|
|
|
reset: function () {
|
|
this.group.innerHTML = '';
|
|
},
|
|
|
|
appendShape: function (shape) {
|
|
var vel = this['_draw' + shape.type].apply(this, shape.args);
|
|
if (this.rendered) {
|
|
this.group.insertAdjacentHTML('beforeEnd', vel);
|
|
} else {
|
|
this.prerender += vel;
|
|
}
|
|
this.lastShapeId = shape.id;
|
|
return shape.id;
|
|
},
|
|
|
|
replaceWithShape: function (shapeid, shape) {
|
|
var existing = $('#jqsshape' + shapeid),
|
|
vel = this['_draw' + shape.type].apply(this, shape.args);
|
|
existing[0].outerHTML = vel;
|
|
},
|
|
|
|
replaceWithShapes: function (shapeids, shapes) {
|
|
// replace the first shapeid with all the new shapes then toast the remaining old shapes
|
|
var existing = $('#jqsshape' + shapeids[0]),
|
|
replace = '',
|
|
slen = shapes.length,
|
|
i;
|
|
for (i = 0; i < slen; i++) {
|
|
replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);
|
|
}
|
|
existing[0].outerHTML = replace;
|
|
for (i = 1; i < shapeids.length; i++) {
|
|
$('#jqsshape' + shapeids[i]).remove();
|
|
}
|
|
},
|
|
|
|
insertAfterShape: function (shapeid, shape) {
|
|
var existing = $('#jqsshape' + shapeid),
|
|
vel = this['_draw' + shape.type].apply(this, shape.args);
|
|
existing[0].insertAdjacentHTML('afterEnd', vel);
|
|
},
|
|
|
|
removeShapeId: function (shapeid) {
|
|
var existing = $('#jqsshape' + shapeid);
|
|
this.group.removeChild(existing[0]);
|
|
},
|
|
|
|
getShapeAt: function (el, x, y) {
|
|
var shapeid = el.id.substr(8);
|
|
return shapeid;
|
|
},
|
|
|
|
render: function () {
|
|
if (!this.rendered) {
|
|
// batch the intial render into a single repaint
|
|
this.group.innerHTML = this.prerender;
|
|
this.rendered = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
}))}(document, Math));
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [ "jquery" ], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
} ( function( $ ) {
|
|
|
|
$.ui = $.ui || {};
|
|
|
|
return $.ui.version = "1.12.1";
|
|
|
|
} ) );
|
|
|
|
|
|
/*!
|
|
* jQuery UI Keycode 1.12.1
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*/
|
|
|
|
//>>label: Keycode
|
|
//>>group: Core
|
|
//>>description: Provide keycodes as keynames
|
|
//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [ "jquery", "./version" ], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
} ( function( $ ) {
|
|
return $.ui.keyCode = {
|
|
BACKSPACE: 8,
|
|
COMMA: 188,
|
|
DELETE: 46,
|
|
DOWN: 40,
|
|
END: 35,
|
|
ENTER: 13,
|
|
ESCAPE: 27,
|
|
HOME: 36,
|
|
LEFT: 37,
|
|
PAGE_DOWN: 34,
|
|
PAGE_UP: 33,
|
|
PERIOD: 190,
|
|
RIGHT: 39,
|
|
SPACE: 32,
|
|
TAB: 9,
|
|
UP: 38
|
|
};
|
|
|
|
} ) );
|
|
|
|
|
|
/*!
|
|
* jQuery UI Position 1.12.1
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*
|
|
* http://api.jqueryui.com/position/
|
|
*/
|
|
|
|
//>>label: Position
|
|
//>>group: Core
|
|
//>>description: Positions elements relative to other elements.
|
|
//>>docs: http://api.jqueryui.com/position/
|
|
//>>demos: http://jqueryui.com/position/
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [ "jquery", "./version" ], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
}( function( $ ) {
|
|
( function() {
|
|
var cachedScrollbarWidth,
|
|
max = Math.max,
|
|
abs = Math.abs,
|
|
rhorizontal = /left|center|right/,
|
|
rvertical = /top|center|bottom/,
|
|
roffset = /[\+\-]\d+(\.[\d]+)?%?/,
|
|
rposition = /^\w+/,
|
|
rpercent = /%$/,
|
|
_position = $.fn.position;
|
|
|
|
function getOffsets( offsets, width, height ) {
|
|
return [
|
|
parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
|
|
parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
|
|
];
|
|
}
|
|
|
|
function parseCss( element, property ) {
|
|
return parseInt( $.css( element, property ), 10 ) || 0;
|
|
}
|
|
|
|
function getDimensions( elem ) {
|
|
var raw = elem[ 0 ];
|
|
if ( raw.nodeType === 9 ) {
|
|
return {
|
|
width: elem.width(),
|
|
height: elem.height(),
|
|
offset: { top: 0, left: 0 }
|
|
};
|
|
}
|
|
if ( $.isWindow( raw ) ) {
|
|
return {
|
|
width: elem.width(),
|
|
height: elem.height(),
|
|
offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
|
|
};
|
|
}
|
|
if ( raw.preventDefault ) {
|
|
return {
|
|
width: 0,
|
|
height: 0,
|
|
offset: { top: raw.pageY, left: raw.pageX }
|
|
};
|
|
}
|
|
return {
|
|
width: elem.outerWidth(),
|
|
height: elem.outerHeight(),
|
|
offset: elem.offset()
|
|
};
|
|
}
|
|
|
|
$.position = {
|
|
scrollbarWidth: function() {
|
|
if ( cachedScrollbarWidth !== undefined ) {
|
|
return cachedScrollbarWidth;
|
|
}
|
|
var w1, w2,
|
|
div = $( "<div " +
|
|
"style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
|
|
"<div style='height:100px;width:auto;'></div></div>" ),
|
|
innerDiv = div.children()[ 0 ];
|
|
|
|
$( "body" ).append( div );
|
|
w1 = innerDiv.offsetWidth;
|
|
div.css( "overflow", "scroll" );
|
|
|
|
w2 = innerDiv.offsetWidth;
|
|
|
|
if ( w1 === w2 ) {
|
|
w2 = div[ 0 ].clientWidth;
|
|
}
|
|
|
|
div.remove();
|
|
|
|
return ( cachedScrollbarWidth = w1 - w2 );
|
|
},
|
|
getScrollInfo: function( within ) {
|
|
var overflowX = within.isWindow || within.isDocument ? "" :
|
|
within.element.css( "overflow-x" ),
|
|
overflowY = within.isWindow || within.isDocument ? "" :
|
|
within.element.css( "overflow-y" ),
|
|
hasOverflowX = overflowX === "scroll" ||
|
|
( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
|
|
hasOverflowY = overflowY === "scroll" ||
|
|
( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
|
|
return {
|
|
width: hasOverflowY ? $.position.scrollbarWidth() : 0,
|
|
height: hasOverflowX ? $.position.scrollbarWidth() : 0
|
|
};
|
|
},
|
|
getWithinInfo: function( element ) {
|
|
var withinElement = $( element || window ),
|
|
isWindow = $.isWindow( withinElement[ 0 ] ),
|
|
isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
|
|
hasOffset = !isWindow && !isDocument;
|
|
return {
|
|
element: withinElement,
|
|
isWindow: isWindow,
|
|
isDocument: isDocument,
|
|
offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
|
|
scrollLeft: withinElement.scrollLeft(),
|
|
scrollTop: withinElement.scrollTop(),
|
|
width: withinElement.outerWidth(),
|
|
height: withinElement.outerHeight()
|
|
};
|
|
}
|
|
};
|
|
|
|
$.fn.position = function( options ) {
|
|
if ( !options || !options.of ) {
|
|
return _position.apply( this, arguments );
|
|
}
|
|
|
|
// Make a copy, we don't want to modify arguments
|
|
options = $.extend( {}, options );
|
|
|
|
var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
|
|
target = $( options.of ),
|
|
within = $.position.getWithinInfo( options.within ),
|
|
scrollInfo = $.position.getScrollInfo( within ),
|
|
collision = ( options.collision || "flip" ).split( " " ),
|
|
offsets = {};
|
|
|
|
dimensions = getDimensions( target );
|
|
if ( target[ 0 ].preventDefault ) {
|
|
|
|
// Force left top to allow flipping
|
|
options.at = "left top";
|
|
}
|
|
targetWidth = dimensions.width;
|
|
targetHeight = dimensions.height;
|
|
targetOffset = dimensions.offset;
|
|
|
|
// Clone to reuse original targetOffset later
|
|
basePosition = $.extend( {}, targetOffset );
|
|
|
|
// Force my and at to have valid horizontal and vertical positions
|
|
// if a value is missing or invalid, it will be converted to center
|
|
$.each( [ "my", "at" ], function() {
|
|
var pos = ( options[ this ] || "" ).split( " " ),
|
|
horizontalOffset,
|
|
verticalOffset;
|
|
|
|
if ( pos.length === 1 ) {
|
|
pos = rhorizontal.test( pos[ 0 ] ) ?
|
|
pos.concat( [ "center" ] ) :
|
|
rvertical.test( pos[ 0 ] ) ?
|
|
[ "center" ].concat( pos ) :
|
|
[ "center", "center" ];
|
|
}
|
|
pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
|
|
pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
|
|
|
|
// Calculate offsets
|
|
horizontalOffset = roffset.exec( pos[ 0 ] );
|
|
verticalOffset = roffset.exec( pos[ 1 ] );
|
|
offsets[ this ] = [
|
|
horizontalOffset ? horizontalOffset[ 0 ] : 0,
|
|
verticalOffset ? verticalOffset[ 0 ] : 0
|
|
];
|
|
|
|
// Reduce to just the positions without the offsets
|
|
options[ this ] = [
|
|
rposition.exec( pos[ 0 ] )[ 0 ],
|
|
rposition.exec( pos[ 1 ] )[ 0 ]
|
|
];
|
|
} );
|
|
|
|
// Normalize collision option
|
|
if ( collision.length === 1 ) {
|
|
collision[ 1 ] = collision[ 0 ];
|
|
}
|
|
|
|
if ( options.at[ 0 ] === "right" ) {
|
|
basePosition.left += targetWidth;
|
|
} else if ( options.at[ 0 ] === "center" ) {
|
|
basePosition.left += targetWidth / 2;
|
|
}
|
|
|
|
if ( options.at[ 1 ] === "bottom" ) {
|
|
basePosition.top += targetHeight;
|
|
} else if ( options.at[ 1 ] === "center" ) {
|
|
basePosition.top += targetHeight / 2;
|
|
}
|
|
|
|
atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
|
|
basePosition.left += atOffset[ 0 ];
|
|
basePosition.top += atOffset[ 1 ];
|
|
|
|
return this.each( function() {
|
|
var collisionPosition, using,
|
|
elem = $( this ),
|
|
elemWidth = elem.outerWidth(),
|
|
elemHeight = elem.outerHeight(),
|
|
marginLeft = parseCss( this, "marginLeft" ),
|
|
marginTop = parseCss( this, "marginTop" ),
|
|
collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
|
|
scrollInfo.width,
|
|
collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
|
|
scrollInfo.height,
|
|
position = $.extend( {}, basePosition ),
|
|
myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
|
|
|
|
if ( options.my[ 0 ] === "right" ) {
|
|
position.left -= elemWidth;
|
|
} else if ( options.my[ 0 ] === "center" ) {
|
|
position.left -= elemWidth / 2;
|
|
}
|
|
|
|
if ( options.my[ 1 ] === "bottom" ) {
|
|
position.top -= elemHeight;
|
|
} else if ( options.my[ 1 ] === "center" ) {
|
|
position.top -= elemHeight / 2;
|
|
}
|
|
|
|
position.left += myOffset[ 0 ];
|
|
position.top += myOffset[ 1 ];
|
|
|
|
collisionPosition = {
|
|
marginLeft: marginLeft,
|
|
marginTop: marginTop
|
|
};
|
|
|
|
$.each( [ "left", "top" ], function( i, dir ) {
|
|
if ( $.ui.position[ collision[ i ] ] ) {
|
|
$.ui.position[ collision[ i ] ][ dir ]( position, {
|
|
targetWidth: targetWidth,
|
|
targetHeight: targetHeight,
|
|
elemWidth: elemWidth,
|
|
elemHeight: elemHeight,
|
|
collisionPosition: collisionPosition,
|
|
collisionWidth: collisionWidth,
|
|
collisionHeight: collisionHeight,
|
|
offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
|
|
my: options.my,
|
|
at: options.at,
|
|
within: within,
|
|
elem: elem
|
|
} );
|
|
}
|
|
} );
|
|
|
|
if ( options.using ) {
|
|
|
|
// Adds feedback as second argument to using callback, if present
|
|
using = function( props ) {
|
|
var left = targetOffset.left - position.left,
|
|
right = left + targetWidth - elemWidth,
|
|
top = targetOffset.top - position.top,
|
|
bottom = top + targetHeight - elemHeight,
|
|
feedback = {
|
|
target: {
|
|
element: target,
|
|
left: targetOffset.left,
|
|
top: targetOffset.top,
|
|
width: targetWidth,
|
|
height: targetHeight
|
|
},
|
|
element: {
|
|
element: elem,
|
|
left: position.left,
|
|
top: position.top,
|
|
width: elemWidth,
|
|
height: elemHeight
|
|
},
|
|
horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
|
|
vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
|
|
};
|
|
if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
|
|
feedback.horizontal = "center";
|
|
}
|
|
if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
|
|
feedback.vertical = "middle";
|
|
}
|
|
if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
|
|
feedback.important = "horizontal";
|
|
} else {
|
|
feedback.important = "vertical";
|
|
}
|
|
options.using.call( this, props, feedback );
|
|
};
|
|
}
|
|
|
|
elem.offset( $.extend( position, { using: using } ) );
|
|
} );
|
|
};
|
|
|
|
$.ui.position = {
|
|
fit: {
|
|
left: function( position, data ) {
|
|
var within = data.within,
|
|
withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
|
|
outerWidth = within.width,
|
|
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
|
|
overLeft = withinOffset - collisionPosLeft,
|
|
overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
|
|
newOverRight;
|
|
|
|
// Element is wider than within
|
|
if ( data.collisionWidth > outerWidth ) {
|
|
|
|
// Element is initially over the left side of within
|
|
if ( overLeft > 0 && overRight <= 0 ) {
|
|
newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
|
|
withinOffset;
|
|
position.left += overLeft - newOverRight;
|
|
|
|
// Element is initially over right side of within
|
|
} else if ( overRight > 0 && overLeft <= 0 ) {
|
|
position.left = withinOffset;
|
|
|
|
// Element is initially over both left and right sides of within
|
|
} else {
|
|
if ( overLeft > overRight ) {
|
|
position.left = withinOffset + outerWidth - data.collisionWidth;
|
|
} else {
|
|
position.left = withinOffset;
|
|
}
|
|
}
|
|
|
|
// Too far left -> align with left edge
|
|
} else if ( overLeft > 0 ) {
|
|
position.left += overLeft;
|
|
|
|
// Too far right -> align with right edge
|
|
} else if ( overRight > 0 ) {
|
|
position.left -= overRight;
|
|
|
|
// Adjust based on position and margin
|
|
} else {
|
|
position.left = max( position.left - collisionPosLeft, position.left );
|
|
}
|
|
},
|
|
top: function( position, data ) {
|
|
var within = data.within,
|
|
withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
|
|
outerHeight = data.within.height,
|
|
collisionPosTop = position.top - data.collisionPosition.marginTop,
|
|
overTop = withinOffset - collisionPosTop,
|
|
overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
|
|
newOverBottom;
|
|
|
|
// Element is taller than within
|
|
if ( data.collisionHeight > outerHeight ) {
|
|
|
|
// Element is initially over the top of within
|
|
if ( overTop > 0 && overBottom <= 0 ) {
|
|
newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
|
|
withinOffset;
|
|
position.top += overTop - newOverBottom;
|
|
|
|
// Element is initially over bottom of within
|
|
} else if ( overBottom > 0 && overTop <= 0 ) {
|
|
position.top = withinOffset;
|
|
|
|
// Element is initially over both top and bottom of within
|
|
} else {
|
|
if ( overTop > overBottom ) {
|
|
position.top = withinOffset + outerHeight - data.collisionHeight;
|
|
} else {
|
|
position.top = withinOffset;
|
|
}
|
|
}
|
|
|
|
// Too far up -> align with top
|
|
} else if ( overTop > 0 ) {
|
|
position.top += overTop;
|
|
|
|
// Too far down -> align with bottom edge
|
|
} else if ( overBottom > 0 ) {
|
|
position.top -= overBottom;
|
|
|
|
// Adjust based on position and margin
|
|
} else {
|
|
position.top = max( position.top - collisionPosTop, position.top );
|
|
}
|
|
}
|
|
},
|
|
flip: {
|
|
left: function( position, data ) {
|
|
var within = data.within,
|
|
withinOffset = within.offset.left + within.scrollLeft,
|
|
outerWidth = within.width,
|
|
offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
|
|
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
|
|
overLeft = collisionPosLeft - offsetLeft,
|
|
overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
|
|
myOffset = data.my[ 0 ] === "left" ?
|
|
-data.elemWidth :
|
|
data.my[ 0 ] === "right" ?
|
|
data.elemWidth :
|
|
0,
|
|
atOffset = data.at[ 0 ] === "left" ?
|
|
data.targetWidth :
|
|
data.at[ 0 ] === "right" ?
|
|
-data.targetWidth :
|
|
0,
|
|
offset = -2 * data.offset[ 0 ],
|
|
newOverRight,
|
|
newOverLeft;
|
|
|
|
if ( overLeft < 0 ) {
|
|
newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
|
|
outerWidth - withinOffset;
|
|
if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
|
|
position.left += myOffset + atOffset + offset;
|
|
}
|
|
} else if ( overRight > 0 ) {
|
|
newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
|
|
atOffset + offset - offsetLeft;
|
|
if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
|
|
position.left += myOffset + atOffset + offset;
|
|
}
|
|
}
|
|
},
|
|
top: function( position, data ) {
|
|
var within = data.within,
|
|
withinOffset = within.offset.top + within.scrollTop,
|
|
outerHeight = within.height,
|
|
offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
|
|
collisionPosTop = position.top - data.collisionPosition.marginTop,
|
|
overTop = collisionPosTop - offsetTop,
|
|
overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
|
|
top = data.my[ 1 ] === "top",
|
|
myOffset = top ?
|
|
-data.elemHeight :
|
|
data.my[ 1 ] === "bottom" ?
|
|
data.elemHeight :
|
|
0,
|
|
atOffset = data.at[ 1 ] === "top" ?
|
|
data.targetHeight :
|
|
data.at[ 1 ] === "bottom" ?
|
|
-data.targetHeight :
|
|
0,
|
|
offset = -2 * data.offset[ 1 ],
|
|
newOverTop,
|
|
newOverBottom;
|
|
if ( overTop < 0 ) {
|
|
newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
|
|
outerHeight - withinOffset;
|
|
if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
|
|
position.top += myOffset + atOffset + offset;
|
|
}
|
|
} else if ( overBottom > 0 ) {
|
|
newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
|
|
offset - offsetTop;
|
|
if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
|
|
position.top += myOffset + atOffset + offset;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
flipfit: {
|
|
left: function() {
|
|
$.ui.position.flip.left.apply( this, arguments );
|
|
$.ui.position.fit.left.apply( this, arguments );
|
|
},
|
|
top: function() {
|
|
$.ui.position.flip.top.apply( this, arguments );
|
|
$.ui.position.fit.top.apply( this, arguments );
|
|
}
|
|
}
|
|
};
|
|
|
|
} )();
|
|
|
|
return $.ui.position;
|
|
|
|
} ) );
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [ "jquery", "./version" ], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
} ( function( $ ) {
|
|
return $.ui.safeActiveElement = function( document ) {
|
|
var activeElement;
|
|
|
|
// Support: IE 9 only
|
|
// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
|
|
try {
|
|
activeElement = document.activeElement;
|
|
} catch ( error ) {
|
|
activeElement = document.body;
|
|
}
|
|
|
|
// Support: IE 9 - 11 only
|
|
// IE may return null instead of an element
|
|
// Interestingly, this only seems to occur when NOT in an iframe
|
|
if ( !activeElement ) {
|
|
activeElement = document.body;
|
|
}
|
|
|
|
// Support: IE 11 only
|
|
// IE11 returns a seemingly empty object in some cases when accessing
|
|
// document.activeElement from an <iframe>
|
|
if ( !activeElement.nodeName ) {
|
|
activeElement = document.body;
|
|
}
|
|
|
|
return activeElement;
|
|
};
|
|
|
|
} ) );
|
|
|
|
|
|
/*!
|
|
* jQuery UI Unique ID 1.12.1
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*/
|
|
|
|
//>>label: uniqueId
|
|
//>>group: Core
|
|
//>>description: Functions to generate and remove uniqueId's
|
|
//>>docs: http://api.jqueryui.com/uniqueId/
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [ "jquery", "./version" ], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
} ( function( $ ) {
|
|
|
|
return $.fn.extend( {
|
|
uniqueId: ( function() {
|
|
var uuid = 0;
|
|
|
|
return function() {
|
|
return this.each( function() {
|
|
if ( !this.id ) {
|
|
this.id = "ui-id-" + ( ++uuid );
|
|
}
|
|
} );
|
|
};
|
|
} )(),
|
|
|
|
removeUniqueId: function() {
|
|
return this.each( function() {
|
|
if ( /^ui-id-\d+$/.test( this.id ) ) {
|
|
$( this ).removeAttr( "id" );
|
|
}
|
|
} );
|
|
}
|
|
} );
|
|
|
|
} ) );
|
|
|
|
|
|
/*!
|
|
* jQuery UI Widget 1.12.1
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*/
|
|
|
|
//>>label: Widget
|
|
//>>group: Core
|
|
//>>description: Provides a factory for creating stateful widgets with a common API.
|
|
//>>docs: http://api.jqueryui.com/jQuery.widget/
|
|
//>>demos: http://jqueryui.com/widget/
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [ "jquery", "./version" ], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
}( function( $ ) {
|
|
|
|
var widgetUuid = 0;
|
|
var widgetSlice = Array.prototype.slice;
|
|
|
|
$.cleanData = ( function( orig ) {
|
|
return function( elems ) {
|
|
var events, elem, i;
|
|
for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
|
|
try {
|
|
|
|
// Only trigger remove when necessary to save time
|
|
events = $._data( elem, "events" );
|
|
if ( events && events.remove ) {
|
|
$( elem ).triggerHandler( "remove" );
|
|
}
|
|
|
|
// Http://bugs.jquery.com/ticket/8235
|
|
} catch ( e ) {}
|
|
}
|
|
orig( elems );
|
|
};
|
|
} )( $.cleanData );
|
|
|
|
$.widget = function( name, base, prototype ) {
|
|
var existingConstructor, constructor, basePrototype;
|
|
|
|
// ProxiedPrototype allows the provided prototype to remain unmodified
|
|
// so that it can be used as a mixin for multiple widgets (#8876)
|
|
var proxiedPrototype = {};
|
|
|
|
var namespace = name.split( "." )[ 0 ];
|
|
name = name.split( "." )[ 1 ];
|
|
var fullName = namespace + "-" + name;
|
|
|
|
if ( !prototype ) {
|
|
prototype = base;
|
|
base = $.Widget;
|
|
}
|
|
|
|
if ( $.isArray( prototype ) ) {
|
|
prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
|
|
}
|
|
|
|
// Create selector for plugin
|
|
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
|
|
return !!$.data( elem, fullName );
|
|
};
|
|
|
|
$[ namespace ] = $[ namespace ] || {};
|
|
existingConstructor = $[ namespace ][ name ];
|
|
constructor = $[ namespace ][ name ] = function( options, element ) {
|
|
|
|
// Allow instantiation without "new" keyword
|
|
if ( !this._createWidget ) {
|
|
return new constructor( options, element );
|
|
}
|
|
|
|
// Allow instantiation without initializing for simple inheritance
|
|
// must use "new" keyword (the code above always passes args)
|
|
if ( arguments.length ) {
|
|
this._createWidget( options, element );
|
|
}
|
|
};
|
|
|
|
// Extend with the existing constructor to carry over any static properties
|
|
$.extend( constructor, existingConstructor, {
|
|
version: prototype.version,
|
|
|
|
// Copy the object used to create the prototype in case we need to
|
|
// redefine the widget later
|
|
_proto: $.extend( {}, prototype ),
|
|
|
|
// Track widgets that inherit from this widget in case this widget is
|
|
// redefined after a widget inherits from it
|
|
_childConstructors: []
|
|
} );
|
|
|
|
basePrototype = new base();
|
|
|
|
// We need to make the options hash a property directly on the new instance
|
|
// otherwise we'll modify the options hash on the prototype that we're
|
|
// inheriting from
|
|
basePrototype.options = $.widget.extend( {}, basePrototype.options );
|
|
$.each( prototype, function( prop, value ) {
|
|
if ( !$.isFunction( value ) ) {
|
|
proxiedPrototype[ prop ] = value;
|
|
return;
|
|
}
|
|
proxiedPrototype[ prop ] = ( function() {
|
|
function _super() {
|
|
return base.prototype[ prop ].apply( this, arguments );
|
|
}
|
|
|
|
function _superApply( args ) {
|
|
return base.prototype[ prop ].apply( this, args );
|
|
}
|
|
|
|
return function() {
|
|
var __super = this._super;
|
|
var __superApply = this._superApply;
|
|
var returnValue;
|
|
|
|
this._super = _super;
|
|
this._superApply = _superApply;
|
|
|
|
returnValue = value.apply( this, arguments );
|
|
|
|
this._super = __super;
|
|
this._superApply = __superApply;
|
|
|
|
return returnValue;
|
|
};
|
|
} )();
|
|
} );
|
|
constructor.prototype = $.widget.extend( basePrototype, {
|
|
|
|
// TODO: remove support for widgetEventPrefix
|
|
// always use the name + a colon as the prefix, e.g., draggable:start
|
|
// don't prefix for widgets that aren't DOM-based
|
|
widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
|
|
}, proxiedPrototype, {
|
|
constructor: constructor,
|
|
namespace: namespace,
|
|
widgetName: name,
|
|
widgetFullName: fullName
|
|
} );
|
|
|
|
// If this widget is being redefined then we need to find all widgets that
|
|
// are inheriting from it and redefine all of them so that they inherit from
|
|
// the new version of this widget. We're essentially trying to replace one
|
|
// level in the prototype chain.
|
|
if ( existingConstructor ) {
|
|
$.each( existingConstructor._childConstructors, function( i, child ) {
|
|
var childPrototype = child.prototype;
|
|
|
|
// Redefine the child widget using the same prototype that was
|
|
// originally used, but inherit from the new version of the base
|
|
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
|
|
child._proto );
|
|
} );
|
|
|
|
// Remove the list of existing child constructors from the old constructor
|
|
// so the old child constructors can be garbage collected
|
|
delete existingConstructor._childConstructors;
|
|
} else {
|
|
base._childConstructors.push( constructor );
|
|
}
|
|
|
|
$.widget.bridge( name, constructor );
|
|
|
|
return constructor;
|
|
};
|
|
|
|
$.widget.extend = function( target ) {
|
|
var input = widgetSlice.call( arguments, 1 );
|
|
var inputIndex = 0;
|
|
var inputLength = input.length;
|
|
var key;
|
|
var value;
|
|
|
|
for ( ; inputIndex < inputLength; inputIndex++ ) {
|
|
for ( key in input[ inputIndex ] ) {
|
|
value = input[ inputIndex ][ key ];
|
|
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
|
|
|
|
// Clone objects
|
|
if ( $.isPlainObject( value ) ) {
|
|
target[ key ] = $.isPlainObject( target[ key ] ) ?
|
|
$.widget.extend( {}, target[ key ], value ) :
|
|
|
|
// Don't extend strings, arrays, etc. with objects
|
|
$.widget.extend( {}, value );
|
|
|
|
// Copy everything else by reference
|
|
} else {
|
|
target[ key ] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
};
|
|
|
|
$.widget.bridge = function( name, object ) {
|
|
var fullName = object.prototype.widgetFullName || name;
|
|
$.fn[ name ] = function( options ) {
|
|
var isMethodCall = typeof options === "string";
|
|
var args = widgetSlice.call( arguments, 1 );
|
|
var returnValue = this;
|
|
|
|
if ( isMethodCall ) {
|
|
|
|
// If this is an empty collection, we need to have the instance method
|
|
// return undefined instead of the jQuery instance
|
|
if ( !this.length && options === "instance" ) {
|
|
returnValue = undefined;
|
|
} else {
|
|
this.each( function() {
|
|
var methodValue;
|
|
var instance = $.data( this, fullName );
|
|
|
|
if ( options === "instance" ) {
|
|
returnValue = instance;
|
|
return false;
|
|
}
|
|
|
|
if ( !instance ) {
|
|
return $.error( "cannot call methods on " + name +
|
|
" prior to initialization; " +
|
|
"attempted to call method '" + options + "'" );
|
|
}
|
|
|
|
if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
|
|
return $.error( "no such method '" + options + "' for " + name +
|
|
" widget instance" );
|
|
}
|
|
|
|
methodValue = instance[ options ].apply( instance, args );
|
|
|
|
if ( methodValue !== instance && methodValue !== undefined ) {
|
|
returnValue = methodValue && methodValue.jquery ?
|
|
returnValue.pushStack( methodValue.get() ) :
|
|
methodValue;
|
|
return false;
|
|
}
|
|
} );
|
|
}
|
|
} else {
|
|
|
|
// Allow multiple hashes to be passed on init
|
|
if ( args.length ) {
|
|
options = $.widget.extend.apply( null, [ options ].concat( args ) );
|
|
}
|
|
|
|
this.each( function() {
|
|
var instance = $.data( this, fullName );
|
|
if ( instance ) {
|
|
instance.option( options || {} );
|
|
if ( instance._init ) {
|
|
instance._init();
|
|
}
|
|
} else {
|
|
$.data( this, fullName, new object( options, this ) );
|
|
}
|
|
} );
|
|
}
|
|
|
|
return returnValue;
|
|
};
|
|
};
|
|
|
|
$.Widget = function( /* options, element */ ) {};
|
|
$.Widget._childConstructors = [];
|
|
|
|
$.Widget.prototype = {
|
|
widgetName: "widget",
|
|
widgetEventPrefix: "",
|
|
defaultElement: "<div>",
|
|
|
|
options: {
|
|
classes: {},
|
|
disabled: false,
|
|
|
|
// Callbacks
|
|
create: null
|
|
},
|
|
|
|
_createWidget: function( options, element ) {
|
|
element = $( element || this.defaultElement || this )[ 0 ];
|
|
this.element = $( element );
|
|
this.uuid = widgetUuid++;
|
|
this.eventNamespace = "." + this.widgetName + this.uuid;
|
|
|
|
this.bindings = $();
|
|
this.hoverable = $();
|
|
this.focusable = $();
|
|
this.classesElementLookup = {};
|
|
|
|
if ( element !== this ) {
|
|
$.data( element, this.widgetFullName, this );
|
|
this._on( true, this.element, {
|
|
remove: function( event ) {
|
|
if ( event.target === element ) {
|
|
this.destroy();
|
|
}
|
|
}
|
|
} );
|
|
this.document = $( element.style ?
|
|
|
|
// Element within the document
|
|
element.ownerDocument :
|
|
|
|
// Element is window or document
|
|
element.document || element );
|
|
this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
|
|
}
|
|
|
|
this.options = $.widget.extend( {},
|
|
this.options,
|
|
this._getCreateOptions(),
|
|
options );
|
|
|
|
this._create();
|
|
|
|
if ( this.options.disabled ) {
|
|
this._setOptionDisabled( this.options.disabled );
|
|
}
|
|
|
|
this._trigger( "create", null, this._getCreateEventData() );
|
|
this._init();
|
|
},
|
|
|
|
_getCreateOptions: function() {
|
|
return {};
|
|
},
|
|
|
|
_getCreateEventData: $.noop,
|
|
|
|
_create: $.noop,
|
|
|
|
_init: $.noop,
|
|
|
|
destroy: function() {
|
|
var that = this;
|
|
|
|
this._destroy();
|
|
$.each( this.classesElementLookup, function( key, value ) {
|
|
that._removeClass( value, key );
|
|
} );
|
|
|
|
// We can probably remove the unbind calls in 2.0
|
|
// all event bindings should go through this._on()
|
|
this.element
|
|
.off( this.eventNamespace )
|
|
.removeData( this.widgetFullName );
|
|
this.widget()
|
|
.off( this.eventNamespace )
|
|
.removeAttr( "aria-disabled" );
|
|
|
|
// Clean up events and states
|
|
this.bindings.off( this.eventNamespace );
|
|
},
|
|
|
|
_destroy: $.noop,
|
|
|
|
widget: function() {
|
|
return this.element;
|
|
},
|
|
|
|
option: function( key, value ) {
|
|
var options = key;
|
|
var parts;
|
|
var curOption;
|
|
var i;
|
|
|
|
if ( arguments.length === 0 ) {
|
|
|
|
// Don't return a reference to the internal hash
|
|
return $.widget.extend( {}, this.options );
|
|
}
|
|
|
|
if ( typeof key === "string" ) {
|
|
|
|
// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
|
|
options = {};
|
|
parts = key.split( "." );
|
|
key = parts.shift();
|
|
if ( parts.length ) {
|
|
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
|
|
for ( i = 0; i < parts.length - 1; i++ ) {
|
|
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
|
|
curOption = curOption[ parts[ i ] ];
|
|
}
|
|
key = parts.pop();
|
|
if ( arguments.length === 1 ) {
|
|
return curOption[ key ] === undefined ? null : curOption[ key ];
|
|
}
|
|
curOption[ key ] = value;
|
|
} else {
|
|
if ( arguments.length === 1 ) {
|
|
return this.options[ key ] === undefined ? null : this.options[ key ];
|
|
}
|
|
options[ key ] = value;
|
|
}
|
|
}
|
|
|
|
this._setOptions( options );
|
|
|
|
return this;
|
|
},
|
|
|
|
_setOptions: function( options ) {
|
|
var key;
|
|
|
|
for ( key in options ) {
|
|
this._setOption( key, options[ key ] );
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
_setOption: function( key, value ) {
|
|
if ( key === "classes" ) {
|
|
this._setOptionClasses( value );
|
|
}
|
|
|
|
this.options[ key ] = value;
|
|
|
|
if ( key === "disabled" ) {
|
|
this._setOptionDisabled( value );
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
_setOptionClasses: function( value ) {
|
|
var classKey, elements, currentElements;
|
|
|
|
for ( classKey in value ) {
|
|
currentElements = this.classesElementLookup[ classKey ];
|
|
if ( value[ classKey ] === this.options.classes[ classKey ] ||
|
|
!currentElements ||
|
|
!currentElements.length ) {
|
|
continue;
|
|
}
|
|
|
|
// We are doing this to create a new jQuery object because the _removeClass() call
|
|
// on the next line is going to destroy the reference to the current elements being
|
|
// tracked. We need to save a copy of this collection so that we can add the new classes
|
|
// below.
|
|
elements = $( currentElements.get() );
|
|
this._removeClass( currentElements, classKey );
|
|
|
|
// We don't use _addClass() here, because that uses this.options.classes
|
|
// for generating the string of classes. We want to use the value passed in from
|
|
// _setOption(), this is the new value of the classes option which was passed to
|
|
// _setOption(). We pass this value directly to _classes().
|
|
elements.addClass( this._classes( {
|
|
element: elements,
|
|
keys: classKey,
|
|
classes: value,
|
|
add: true
|
|
} ) );
|
|
}
|
|
},
|
|
|
|
_setOptionDisabled: function( value ) {
|
|
this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
|
|
|
|
// If the widget is becoming disabled, then nothing is interactive
|
|
if ( value ) {
|
|
this._removeClass( this.hoverable, null, "ui-state-hover" );
|
|
this._removeClass( this.focusable, null, "ui-state-focus" );
|
|
}
|
|
},
|
|
|
|
enable: function() {
|
|
return this._setOptions( { disabled: false } );
|
|
},
|
|
|
|
disable: function() {
|
|
return this._setOptions( { disabled: true } );
|
|
},
|
|
|
|
_classes: function( options ) {
|
|
var full = [];
|
|
var that = this;
|
|
|
|
options = $.extend( {
|
|
element: this.element,
|
|
classes: this.options.classes || {}
|
|
}, options );
|
|
|
|
function processClassString( classes, checkOption ) {
|
|
var current, i;
|
|
for ( i = 0; i < classes.length; i++ ) {
|
|
current = that.classesElementLookup[ classes[ i ] ] || $();
|
|
if ( options.add ) {
|
|
current = $( $.unique( current.get().concat( options.element.get() ) ) );
|
|
} else {
|
|
current = $( current.not( options.element ).get() );
|
|
}
|
|
that.classesElementLookup[ classes[ i ] ] = current;
|
|
full.push( classes[ i ] );
|
|
if ( checkOption && options.classes[ classes[ i ] ] ) {
|
|
full.push( options.classes[ classes[ i ] ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
this._on( options.element, {
|
|
"remove": "_untrackClassesElement"
|
|
} );
|
|
|
|
if ( options.keys ) {
|
|
processClassString( options.keys.match( /\S+/g ) || [], true );
|
|
}
|
|
if ( options.extra ) {
|
|
processClassString( options.extra.match( /\S+/g ) || [] );
|
|
}
|
|
|
|
return full.join( " " );
|
|
},
|
|
|
|
_untrackClassesElement: function( event ) {
|
|
var that = this;
|
|
$.each( that.classesElementLookup, function( key, value ) {
|
|
if ( $.inArray( event.target, value ) !== -1 ) {
|
|
that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
|
|
}
|
|
} );
|
|
},
|
|
|
|
_removeClass: function( element, keys, extra ) {
|
|
return this._toggleClass( element, keys, extra, false );
|
|
},
|
|
|
|
_addClass: function( element, keys, extra ) {
|
|
return this._toggleClass( element, keys, extra, true );
|
|
},
|
|
|
|
_toggleClass: function( element, keys, extra, add ) {
|
|
add = ( typeof add === "boolean" ) ? add : extra;
|
|
var shift = ( typeof element === "string" || element === null ),
|
|
options = {
|
|
extra: shift ? keys : extra,
|
|
keys: shift ? element : keys,
|
|
element: shift ? this.element : element,
|
|
add: add
|
|
};
|
|
options.element.toggleClass( this._classes( options ), add );
|
|
return this;
|
|
},
|
|
|
|
_on: function( suppressDisabledCheck, element, handlers ) {
|
|
var delegateElement;
|
|
var instance = this;
|
|
|
|
// No suppressDisabledCheck flag, shuffle arguments
|
|
if ( typeof suppressDisabledCheck !== "boolean" ) {
|
|
handlers = element;
|
|
element = suppressDisabledCheck;
|
|
suppressDisabledCheck = false;
|
|
}
|
|
|
|
// No element argument, shuffle and use this.element
|
|
if ( !handlers ) {
|
|
handlers = element;
|
|
element = this.element;
|
|
delegateElement = this.widget();
|
|
} else {
|
|
element = delegateElement = $( element );
|
|
this.bindings = this.bindings.add( element );
|
|
}
|
|
|
|
$.each( handlers, function( event, handler ) {
|
|
function handlerProxy() {
|
|
|
|
// Allow widgets to customize the disabled handling
|
|
// - disabled as an array instead of boolean
|
|
// - disabled class as method for disabling individual parts
|
|
if ( !suppressDisabledCheck &&
|
|
( instance.options.disabled === true ||
|
|
$( this ).hasClass( "ui-state-disabled" ) ) ) {
|
|
return;
|
|
}
|
|
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
|
.apply( instance, arguments );
|
|
}
|
|
|
|
// Copy the guid so direct unbinding works
|
|
if ( typeof handler !== "string" ) {
|
|
handlerProxy.guid = handler.guid =
|
|
handler.guid || handlerProxy.guid || $.guid++;
|
|
}
|
|
|
|
var match = event.match( /^([\w:-]*)\s*(.*)$/ );
|
|
var eventName = match[ 1 ] + instance.eventNamespace;
|
|
var selector = match[ 2 ];
|
|
|
|
if ( selector ) {
|
|
delegateElement.on( eventName, selector, handlerProxy );
|
|
} else {
|
|
element.on( eventName, handlerProxy );
|
|
}
|
|
} );
|
|
},
|
|
|
|
_off: function( element, eventName ) {
|
|
eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
|
|
this.eventNamespace;
|
|
element.off( eventName ).off( eventName );
|
|
|
|
// Clear the stack to avoid memory leaks (#10056)
|
|
this.bindings = $( this.bindings.not( element ).get() );
|
|
this.focusable = $( this.focusable.not( element ).get() );
|
|
this.hoverable = $( this.hoverable.not( element ).get() );
|
|
},
|
|
|
|
_delay: function( handler, delay ) {
|
|
function handlerProxy() {
|
|
return ( typeof handler === "string" ? instance[ handler ] : handler )
|
|
.apply( instance, arguments );
|
|
}
|
|
var instance = this;
|
|
return setTimeout( handlerProxy, delay || 0 );
|
|
},
|
|
|
|
_hoverable: function( element ) {
|
|
this.hoverable = this.hoverable.add( element );
|
|
this._on( element, {
|
|
mouseenter: function( event ) {
|
|
this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
|
|
},
|
|
mouseleave: function( event ) {
|
|
this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
|
|
}
|
|
} );
|
|
},
|
|
|
|
_focusable: function( element ) {
|
|
this.focusable = this.focusable.add( element );
|
|
this._on( element, {
|
|
focusin: function( event ) {
|
|
this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
|
|
},
|
|
focusout: function( event ) {
|
|
this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
|
|
}
|
|
} );
|
|
},
|
|
|
|
_trigger: function( type, event, data ) {
|
|
var prop, orig;
|
|
var callback = this.options[ type ];
|
|
|
|
data = data || {};
|
|
event = $.Event( event );
|
|
event.type = ( type === this.widgetEventPrefix ?
|
|
type :
|
|
this.widgetEventPrefix + type ).toLowerCase();
|
|
|
|
// The original event may come from any element
|
|
// so we need to reset the target on the new event
|
|
event.target = this.element[ 0 ];
|
|
|
|
// Copy original event properties over to the new event
|
|
orig = event.originalEvent;
|
|
if ( orig ) {
|
|
for ( prop in orig ) {
|
|
if ( !( prop in event ) ) {
|
|
event[ prop ] = orig[ prop ];
|
|
}
|
|
}
|
|
}
|
|
|
|
this.element.trigger( event, data );
|
|
return !( $.isFunction( callback ) &&
|
|
callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
|
|
event.isDefaultPrevented() );
|
|
}
|
|
};
|
|
|
|
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
|
|
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
|
|
if ( typeof options === "string" ) {
|
|
options = { effect: options };
|
|
}
|
|
|
|
var hasOptions;
|
|
var effectName = !options ?
|
|
method :
|
|
options === true || typeof options === "number" ?
|
|
defaultEffect :
|
|
options.effect || defaultEffect;
|
|
|
|
options = options || {};
|
|
if ( typeof options === "number" ) {
|
|
options = { duration: options };
|
|
}
|
|
|
|
hasOptions = !$.isEmptyObject( options );
|
|
options.complete = callback;
|
|
|
|
if ( options.delay ) {
|
|
element.delay( options.delay );
|
|
}
|
|
|
|
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
|
|
element[ method ]( options );
|
|
} else if ( effectName !== method && element[ effectName ] ) {
|
|
element[ effectName ]( options.duration, options.easing, callback );
|
|
} else {
|
|
element.queue( function( next ) {
|
|
$( this )[ method ]();
|
|
if ( callback ) {
|
|
callback.call( element[ 0 ] );
|
|
}
|
|
next();
|
|
} );
|
|
}
|
|
};
|
|
} );
|
|
|
|
return $.widget;
|
|
|
|
} ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
* jQuery UI Menu 1.12.1
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*/
|
|
|
|
//>>label: Menu
|
|
//>>group: Widgets
|
|
//>>description: Creates nestable menus.
|
|
//>>docs: http://api.jqueryui.com/menu/
|
|
//>>demos: http://jqueryui.com/menu/
|
|
//>>css.structure: ../../themes/base/core.css
|
|
//>>css.structure: ../../themes/base/menu.css
|
|
//>>css.theme: ../../themes/base/theme.css
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [
|
|
"jquery",
|
|
"../keycode",
|
|
"../position",
|
|
"../safe-active-element",
|
|
"../unique-id",
|
|
"../version",
|
|
"../widget"
|
|
], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
}( function( $ ) {
|
|
|
|
return $.widget( "ui.menu", {
|
|
version: "1.12.1",
|
|
defaultElement: "<ul>",
|
|
delay: 300,
|
|
options: {
|
|
icons: {
|
|
submenu: "ui-icon-caret-1-e"
|
|
},
|
|
items: "> *",
|
|
menus: "ul",
|
|
position: {
|
|
my: "left top",
|
|
at: "right top"
|
|
},
|
|
role: "menu",
|
|
|
|
// Callbacks
|
|
blur: null,
|
|
focus: null,
|
|
select: null
|
|
},
|
|
|
|
_create: function() {
|
|
this.activeMenu = this.element;
|
|
|
|
// Flag used to prevent firing of the click handler
|
|
// as the event bubbles up through nested menus
|
|
this.mouseHandled = false;
|
|
this.element
|
|
.uniqueId()
|
|
.attr( {
|
|
role: this.options.role,
|
|
tabIndex: 0
|
|
} );
|
|
|
|
this._addClass( "ui-menu", "ui-widget ui-widget-content" );
|
|
this._on( {
|
|
|
|
// Prevent focus from sticking to links inside menu after clicking
|
|
// them (focus should always stay on UL during navigation).
|
|
"mousedown .ui-menu-item": function( event ) {
|
|
event.preventDefault();
|
|
},
|
|
"click .ui-menu-item": function( event ) {
|
|
var target = $( event.target );
|
|
var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
|
|
if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
|
|
this.select( event );
|
|
|
|
// Only set the mouseHandled flag if the event will bubble, see #9469.
|
|
if ( !event.isPropagationStopped() ) {
|
|
this.mouseHandled = true;
|
|
}
|
|
|
|
// Open submenu on click
|
|
if ( target.has( ".ui-menu" ).length ) {
|
|
this.expand( event );
|
|
} else if ( !this.element.is( ":focus" ) &&
|
|
active.closest( ".ui-menu" ).length ) {
|
|
|
|
// Redirect focus to the menu
|
|
this.element.trigger( "focus", [ true ] );
|
|
|
|
// If the active item is on the top level, let it stay active.
|
|
// Otherwise, blur the active item since it is no longer visible.
|
|
if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
|
|
clearTimeout( this.timer );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"mouseenter .ui-menu-item": function( event ) {
|
|
|
|
// Ignore mouse events while typeahead is active, see #10458.
|
|
// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
|
|
// is over an item in the menu
|
|
if ( this.previousFilter ) {
|
|
return;
|
|
}
|
|
|
|
var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
|
|
target = $( event.currentTarget );
|
|
|
|
// Ignore bubbled events on parent items, see #11641
|
|
if ( actualTarget[ 0 ] !== target[ 0 ] ) {
|
|
return;
|
|
}
|
|
|
|
// Remove ui-state-active class from siblings of the newly focused menu item
|
|
// to avoid a jump caused by adjacent elements both having a class with a border
|
|
this._removeClass( target.siblings().children( ".ui-state-active" ),
|
|
null, "ui-state-active" );
|
|
this.focus( event, target );
|
|
},
|
|
mouseleave: "collapseAll",
|
|
"mouseleave .ui-menu": "collapseAll",
|
|
focus: function( event, keepActiveItem ) {
|
|
|
|
// If there's already an active item, keep it active
|
|
// If not, activate the first item
|
|
var item = this.active || this.element.find( this.options.items ).eq( 0 );
|
|
|
|
if ( !keepActiveItem ) {
|
|
this.focus( event, item );
|
|
}
|
|
},
|
|
blur: function( event ) {
|
|
this._delay( function() {
|
|
var notContained = !$.contains(
|
|
this.element[ 0 ],
|
|
$.ui.safeActiveElement( this.document[ 0 ] )
|
|
);
|
|
if ( notContained ) {
|
|
this.collapseAll( event );
|
|
}
|
|
} );
|
|
},
|
|
keydown: "_keydown"
|
|
} );
|
|
|
|
this.refresh();
|
|
|
|
// Clicks outside of a menu collapse any open menus
|
|
this._on( this.document, {
|
|
click: function( event ) {
|
|
if ( this._closeOnDocumentClick( event ) ) {
|
|
this.collapseAll( event );
|
|
}
|
|
|
|
// Reset the mouseHandled flag
|
|
this.mouseHandled = false;
|
|
}
|
|
} );
|
|
},
|
|
|
|
_destroy: function() {
|
|
var items = this.element.find( ".ui-menu-item" )
|
|
.removeAttr( "role aria-disabled" ),
|
|
submenus = items.children( ".ui-menu-item-wrapper" )
|
|
.removeUniqueId()
|
|
.removeAttr( "tabIndex role aria-haspopup" );
|
|
|
|
// Destroy (sub)menus
|
|
this.element
|
|
.removeAttr( "aria-activedescendant" )
|
|
.find( ".ui-menu" ).addBack()
|
|
.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
|
|
"tabIndex" )
|
|
.removeUniqueId()
|
|
.show();
|
|
|
|
submenus.children().each( function() {
|
|
var elem = $( this );
|
|
if ( elem.data( "ui-menu-submenu-caret" ) ) {
|
|
elem.remove();
|
|
}
|
|
} );
|
|
},
|
|
|
|
_keydown: function( event ) {
|
|
var match, prev, character, skip,
|
|
preventDefault = true;
|
|
|
|
switch ( event.keyCode ) {
|
|
case $.ui.keyCode.PAGE_UP:
|
|
this.previousPage( event );
|
|
break;
|
|
case $.ui.keyCode.PAGE_DOWN:
|
|
this.nextPage( event );
|
|
break;
|
|
case $.ui.keyCode.HOME:
|
|
this._move( "first", "first", event );
|
|
break;
|
|
case $.ui.keyCode.END:
|
|
this._move( "last", "last", event );
|
|
break;
|
|
case $.ui.keyCode.UP:
|
|
this.previous( event );
|
|
break;
|
|
case $.ui.keyCode.DOWN:
|
|
this.next( event );
|
|
break;
|
|
case $.ui.keyCode.LEFT:
|
|
this.collapse( event );
|
|
break;
|
|
case $.ui.keyCode.RIGHT:
|
|
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
|
|
this.expand( event );
|
|
}
|
|
break;
|
|
case $.ui.keyCode.ENTER:
|
|
case $.ui.keyCode.SPACE:
|
|
this._activate( event );
|
|
break;
|
|
case $.ui.keyCode.ESCAPE:
|
|
this.collapse( event );
|
|
break;
|
|
default:
|
|
preventDefault = false;
|
|
prev = this.previousFilter || "";
|
|
skip = false;
|
|
|
|
// Support number pad values
|
|
character = event.keyCode >= 96 && event.keyCode <= 105 ?
|
|
( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
|
|
|
|
clearTimeout( this.filterTimer );
|
|
|
|
if ( character === prev ) {
|
|
skip = true;
|
|
} else {
|
|
character = prev + character;
|
|
}
|
|
|
|
match = this._filterMenuItems( character );
|
|
match = skip && match.index( this.active.next() ) !== -1 ?
|
|
this.active.nextAll( ".ui-menu-item" ) :
|
|
match;
|
|
|
|
// If no matches on the current filter, reset to the last character pressed
|
|
// to move down the menu to the first item that starts with that character
|
|
if ( !match.length ) {
|
|
character = String.fromCharCode( event.keyCode );
|
|
match = this._filterMenuItems( character );
|
|
}
|
|
|
|
if ( match.length ) {
|
|
this.focus( event, match );
|
|
this.previousFilter = character;
|
|
this.filterTimer = this._delay( function() {
|
|
delete this.previousFilter;
|
|
}, 1000 );
|
|
} else {
|
|
delete this.previousFilter;
|
|
}
|
|
}
|
|
|
|
if ( preventDefault ) {
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
|
|
_activate: function( event ) {
|
|
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
|
|
if ( this.active.children( "[aria-haspopup='true']" ).length ) {
|
|
this.expand( event );
|
|
} else {
|
|
this.select( event );
|
|
}
|
|
}
|
|
},
|
|
|
|
refresh: function() {
|
|
var menus, items, newSubmenus, newItems, newWrappers,
|
|
that = this,
|
|
icon = this.options.icons.submenu,
|
|
submenus = this.element.find( this.options.menus );
|
|
|
|
this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
|
|
|
|
// Initialize nested menus
|
|
newSubmenus = submenus.filter( ":not(.ui-menu)" )
|
|
.hide()
|
|
.attr( {
|
|
role: this.options.role,
|
|
"aria-hidden": "true",
|
|
"aria-expanded": "false"
|
|
} )
|
|
.each( function() {
|
|
var menu = $( this ),
|
|
item = menu.prev(),
|
|
submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
|
|
|
|
that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
|
|
item
|
|
.attr( "aria-haspopup", "true" )
|
|
.prepend( submenuCaret );
|
|
menu.attr( "aria-labelledby", item.attr( "id" ) );
|
|
} );
|
|
|
|
this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
|
|
|
|
menus = submenus.add( this.element );
|
|
items = menus.find( this.options.items );
|
|
|
|
// Initialize menu-items containing spaces and/or dashes only as dividers
|
|
items.not( ".ui-menu-item" ).each( function() {
|
|
var item = $( this );
|
|
if ( that._isDivider( item ) ) {
|
|
that._addClass( item, "ui-menu-divider", "ui-widget-content" );
|
|
}
|
|
} );
|
|
|
|
// Don't refresh list items that are already adapted
|
|
newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
|
|
newWrappers = newItems.children()
|
|
.not( ".ui-menu" )
|
|
.uniqueId()
|
|
.attr( {
|
|
tabIndex: -1,
|
|
role: this._itemRole()
|
|
} );
|
|
this._addClass( newItems, "ui-menu-item" )
|
|
._addClass( newWrappers, "ui-menu-item-wrapper" );
|
|
|
|
// Add aria-disabled attribute to any disabled menu item
|
|
items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
|
|
|
|
// If the active item has been removed, blur the menu
|
|
if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
|
|
this.blur();
|
|
}
|
|
},
|
|
|
|
_itemRole: function() {
|
|
return {
|
|
menu: "menuitem",
|
|
listbox: "option"
|
|
}[ this.options.role ];
|
|
},
|
|
|
|
_setOption: function( key, value ) {
|
|
if ( key === "icons" ) {
|
|
var icons = this.element.find( ".ui-menu-icon" );
|
|
this._removeClass( icons, null, this.options.icons.submenu )
|
|
._addClass( icons, null, value.submenu );
|
|
}
|
|
this._super( key, value );
|
|
},
|
|
|
|
_setOptionDisabled: function( value ) {
|
|
this._super( value );
|
|
|
|
this.element.attr( "aria-disabled", String( value ) );
|
|
this._toggleClass( null, "ui-state-disabled", !!value );
|
|
},
|
|
|
|
focus: function( event, item ) {
|
|
var nested, focused, activeParent;
|
|
this.blur( event, event && event.type === "focus" );
|
|
|
|
this._scrollIntoView( item );
|
|
|
|
this.active = item.first();
|
|
|
|
focused = this.active.children( ".ui-menu-item-wrapper" );
|
|
this._addClass( focused, null, "ui-state-active" );
|
|
|
|
// Only update aria-activedescendant if there's a role
|
|
// otherwise we assume focus is managed elsewhere
|
|
if ( this.options.role ) {
|
|
this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
|
|
}
|
|
|
|
// Highlight active parent menu item, if any
|
|
activeParent = this.active
|
|
.parent()
|
|
.closest( ".ui-menu-item" )
|
|
.children( ".ui-menu-item-wrapper" );
|
|
this._addClass( activeParent, null, "ui-state-active" );
|
|
|
|
if ( event && event.type === "keydown" ) {
|
|
this._close();
|
|
} else {
|
|
this.timer = this._delay( function() {
|
|
this._close();
|
|
}, this.delay );
|
|
}
|
|
|
|
nested = item.children( ".ui-menu" );
|
|
if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
|
|
this._startOpening( nested );
|
|
}
|
|
this.activeMenu = item.parent();
|
|
|
|
this._trigger( "focus", event, { item: item } );
|
|
},
|
|
|
|
_scrollIntoView: function( item ) {
|
|
var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
|
|
if ( this._hasScroll() ) {
|
|
borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
|
|
paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
|
|
offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
|
|
scroll = this.activeMenu.scrollTop();
|
|
elementHeight = this.activeMenu.height();
|
|
itemHeight = item.outerHeight();
|
|
|
|
if ( offset < 0 ) {
|
|
this.activeMenu.scrollTop( scroll + offset );
|
|
} else if ( offset + itemHeight > elementHeight ) {
|
|
this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
|
|
}
|
|
}
|
|
},
|
|
|
|
blur: function( event, fromFocus ) {
|
|
if ( !fromFocus ) {
|
|
clearTimeout( this.timer );
|
|
}
|
|
|
|
if ( !this.active ) {
|
|
return;
|
|
}
|
|
|
|
this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
|
|
null, "ui-state-active" );
|
|
|
|
this._trigger( "blur", event, { item: this.active } );
|
|
this.active = null;
|
|
},
|
|
|
|
_startOpening: function( submenu ) {
|
|
clearTimeout( this.timer );
|
|
|
|
// Don't open if already open fixes a Firefox bug that caused a .5 pixel
|
|
// shift in the submenu position when mousing over the caret icon
|
|
if ( submenu.attr( "aria-hidden" ) !== "true" ) {
|
|
return;
|
|
}
|
|
|
|
this.timer = this._delay( function() {
|
|
this._close();
|
|
this._open( submenu );
|
|
}, this.delay );
|
|
},
|
|
|
|
_open: function( submenu ) {
|
|
var position = $.extend( {
|
|
of: this.active
|
|
}, this.options.position );
|
|
|
|
clearTimeout( this.timer );
|
|
this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
|
|
.hide()
|
|
.attr( "aria-hidden", "true" );
|
|
|
|
submenu
|
|
.show()
|
|
.removeAttr( "aria-hidden" )
|
|
.attr( "aria-expanded", "true" )
|
|
.position( position );
|
|
},
|
|
|
|
collapseAll: function( event, all ) {
|
|
clearTimeout( this.timer );
|
|
this.timer = this._delay( function() {
|
|
|
|
// If we were passed an event, look for the submenu that contains the event
|
|
var currentMenu = all ? this.element :
|
|
$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
|
|
|
|
// If we found no valid submenu ancestor, use the main menu to close all
|
|
// sub menus anyway
|
|
if ( !currentMenu.length ) {
|
|
currentMenu = this.element;
|
|
}
|
|
|
|
this._close( currentMenu );
|
|
|
|
this.blur( event );
|
|
|
|
// Work around active item staying active after menu is blurred
|
|
this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
|
|
|
|
this.activeMenu = currentMenu;
|
|
}, this.delay );
|
|
},
|
|
|
|
// With no arguments, closes the currently active menu - if nothing is active
|
|
// it closes all menus. If passed an argument, it will search for menus BELOW
|
|
_close: function( startMenu ) {
|
|
if ( !startMenu ) {
|
|
startMenu = this.active ? this.active.parent() : this.element;
|
|
}
|
|
|
|
startMenu.find( ".ui-menu" )
|
|
.hide()
|
|
.attr( "aria-hidden", "true" )
|
|
.attr( "aria-expanded", "false" );
|
|
},
|
|
|
|
_closeOnDocumentClick: function( event ) {
|
|
return !$( event.target ).closest( ".ui-menu" ).length;
|
|
},
|
|
|
|
_isDivider: function( item ) {
|
|
|
|
// Match hyphen, em dash, en dash
|
|
return !/[^\-\u2014\u2013\s]/.test( item.text() );
|
|
},
|
|
|
|
collapse: function( event ) {
|
|
var newItem = this.active &&
|
|
this.active.parent().closest( ".ui-menu-item", this.element );
|
|
if ( newItem && newItem.length ) {
|
|
this._close();
|
|
this.focus( event, newItem );
|
|
}
|
|
},
|
|
|
|
expand: function( event ) {
|
|
var newItem = this.active &&
|
|
this.active
|
|
.children( ".ui-menu " )
|
|
.find( this.options.items )
|
|
.first();
|
|
|
|
if ( newItem && newItem.length ) {
|
|
this._open( newItem.parent() );
|
|
|
|
// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
|
|
this._delay( function() {
|
|
this.focus( event, newItem );
|
|
} );
|
|
}
|
|
},
|
|
|
|
next: function( event ) {
|
|
this._move( "next", "first", event );
|
|
},
|
|
|
|
previous: function( event ) {
|
|
this._move( "prev", "last", event );
|
|
},
|
|
|
|
isFirstItem: function() {
|
|
return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
|
|
},
|
|
|
|
isLastItem: function() {
|
|
return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
|
|
},
|
|
|
|
_move: function( direction, filter, event ) {
|
|
var next;
|
|
if ( this.active ) {
|
|
if ( direction === "first" || direction === "last" ) {
|
|
next = this.active
|
|
[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
|
|
.eq( -1 );
|
|
} else {
|
|
next = this.active
|
|
[ direction + "All" ]( ".ui-menu-item" )
|
|
.eq( 0 );
|
|
}
|
|
}
|
|
if ( !next || !next.length || !this.active ) {
|
|
next = this.activeMenu.find( this.options.items )[ filter ]();
|
|
}
|
|
|
|
this.focus( event, next );
|
|
},
|
|
|
|
nextPage: function( event ) {
|
|
var item, base, height;
|
|
|
|
if ( !this.active ) {
|
|
this.next( event );
|
|
return;
|
|
}
|
|
if ( this.isLastItem() ) {
|
|
return;
|
|
}
|
|
if ( this._hasScroll() ) {
|
|
base = this.active.offset().top;
|
|
height = this.element.height();
|
|
this.active.nextAll( ".ui-menu-item" ).each( function() {
|
|
item = $( this );
|
|
return item.offset().top - base - height < 0;
|
|
} );
|
|
|
|
this.focus( event, item );
|
|
} else {
|
|
this.focus( event, this.activeMenu.find( this.options.items )
|
|
[ !this.active ? "first" : "last" ]() );
|
|
}
|
|
},
|
|
|
|
previousPage: function( event ) {
|
|
var item, base, height;
|
|
if ( !this.active ) {
|
|
this.next( event );
|
|
return;
|
|
}
|
|
if ( this.isFirstItem() ) {
|
|
return;
|
|
}
|
|
if ( this._hasScroll() ) {
|
|
base = this.active.offset().top;
|
|
height = this.element.height();
|
|
this.active.prevAll( ".ui-menu-item" ).each( function() {
|
|
item = $( this );
|
|
return item.offset().top - base + height > 0;
|
|
} );
|
|
|
|
this.focus( event, item );
|
|
} else {
|
|
this.focus( event, this.activeMenu.find( this.options.items ).first() );
|
|
}
|
|
},
|
|
|
|
_hasScroll: function() {
|
|
return this.element.outerHeight() < this.element.prop( "scrollHeight" );
|
|
},
|
|
|
|
select: function( event ) {
|
|
|
|
// TODO: It should never be possible to not have an active item at this
|
|
// point, but the tests don't trigger mouseenter before click.
|
|
this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
|
|
var ui = { item: this.active };
|
|
if ( !this.active.has( ".ui-menu" ).length ) {
|
|
this.collapseAll( event, true );
|
|
}
|
|
this._trigger( "select", event, ui );
|
|
},
|
|
|
|
_filterMenuItems: function( character ) {
|
|
var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
|
|
regex = new RegExp( "^" + escapedCharacter, "i" );
|
|
|
|
return this.activeMenu
|
|
.find( this.options.items )
|
|
|
|
// Only match on items, not dividers or other content (#10571)
|
|
.filter( ".ui-menu-item" )
|
|
.filter( function() {
|
|
return regex.test(
|
|
$.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
} ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
* jQuery UI Autocomplete 1.12.1
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*/
|
|
|
|
//>>label: Autocomplete
|
|
//>>group: Widgets
|
|
//>>description: Lists suggested words as the user is typing.
|
|
//>>docs: http://api.jqueryui.com/autocomplete/
|
|
//>>demos: http://jqueryui.com/autocomplete/
|
|
//>>css.structure: ../../themes/base/core.css
|
|
//>>css.structure: ../../themes/base/autocomplete.css
|
|
//>>css.theme: ../../themes/base/theme.css
|
|
|
|
( function( factory ) {
|
|
if ( typeof define === "function" && define.amd ) {
|
|
|
|
// AMD. Register as an anonymous module.
|
|
define( [
|
|
"jquery",
|
|
"./menu",
|
|
"../keycode",
|
|
"../position",
|
|
"../safe-active-element",
|
|
"../version",
|
|
"../widget"
|
|
], factory );
|
|
} else {
|
|
|
|
// Browser globals
|
|
factory( jQuery );
|
|
}
|
|
}( function( $ ) {
|
|
|
|
$.widget( "ui.autocomplete", {
|
|
version: "1.12.1",
|
|
defaultElement: "<input>",
|
|
options: {
|
|
appendTo: null,
|
|
autoFocus: false,
|
|
delay: 300,
|
|
minLength: 1,
|
|
position: {
|
|
my: "left top",
|
|
at: "left bottom",
|
|
collision: "none"
|
|
},
|
|
source: null,
|
|
|
|
// Callbacks
|
|
change: null,
|
|
close: null,
|
|
focus: null,
|
|
open: null,
|
|
response: null,
|
|
search: null,
|
|
select: null
|
|
},
|
|
|
|
requestIndex: 0,
|
|
pending: 0,
|
|
|
|
_create: function() {
|
|
|
|
// Some browsers only repeat keydown events, not keypress events,
|
|
// so we use the suppressKeyPress flag to determine if we've already
|
|
// handled the keydown event. #7269
|
|
// Unfortunately the code for & in keypress is the same as the up arrow,
|
|
// so we use the suppressKeyPressRepeat flag to avoid handling keypress
|
|
// events when we know the keydown event was used to modify the
|
|
// search term. #7799
|
|
var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
|
|
nodeName = this.element[ 0 ].nodeName.toLowerCase(),
|
|
isTextarea = nodeName === "textarea",
|
|
isInput = nodeName === "input";
|
|
|
|
// Textareas are always multi-line
|
|
// Inputs are always single-line, even if inside a contentEditable element
|
|
// IE also treats inputs as contentEditable
|
|
// All other element types are determined by whether or not they're contentEditable
|
|
this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
|
|
|
|
this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
|
|
this.isNewMenu = true;
|
|
|
|
this._addClass( "ui-autocomplete-input" );
|
|
this.element.attr( "autocomplete", "off" );
|
|
|
|
this._on( this.element, {
|
|
keydown: function( event ) {
|
|
if ( this.element.prop( "readOnly" ) ) {
|
|
suppressKeyPress = true;
|
|
suppressInput = true;
|
|
suppressKeyPressRepeat = true;
|
|
return;
|
|
}
|
|
|
|
suppressKeyPress = false;
|
|
suppressInput = false;
|
|
suppressKeyPressRepeat = false;
|
|
var keyCode = $.ui.keyCode;
|
|
switch ( event.keyCode ) {
|
|
case keyCode.PAGE_UP:
|
|
suppressKeyPress = true;
|
|
this._move( "previousPage", event );
|
|
break;
|
|
case keyCode.PAGE_DOWN:
|
|
suppressKeyPress = true;
|
|
this._move( "nextPage", event );
|
|
break;
|
|
case keyCode.UP:
|
|
suppressKeyPress = true;
|
|
this._keyEvent( "previous", event );
|
|
break;
|
|
case keyCode.DOWN:
|
|
suppressKeyPress = true;
|
|
this._keyEvent( "next", event );
|
|
break;
|
|
case keyCode.ENTER:
|
|
|
|
// when menu is open and has focus
|
|
if ( this.menu.active ) {
|
|
|
|
// #6055 - Opera still allows the keypress to occur
|
|
// which causes forms to submit
|
|
suppressKeyPress = true;
|
|
event.preventDefault();
|
|
this.menu.select( event );
|
|
}
|
|
break;
|
|
case keyCode.TAB:
|
|
if ( this.menu.active ) {
|
|
this.menu.select( event );
|
|
}
|
|
break;
|
|
case keyCode.ESCAPE:
|
|
if ( this.menu.element.is( ":visible" ) ) {
|
|
if ( !this.isMultiLine ) {
|
|
this._value( this.term );
|
|
}
|
|
this.close( event );
|
|
|
|
// Different browsers have different default behavior for escape
|
|
// Single press can mean undo or clear
|
|
// Double press in IE means clear the whole form
|
|
event.preventDefault();
|
|
}
|
|
break;
|
|
default:
|
|
suppressKeyPressRepeat = true;
|
|
|
|
// search timeout should be triggered before the input value is changed
|
|
this._searchTimeout( event );
|
|
break;
|
|
}
|
|
},
|
|
keypress: function( event ) {
|
|
if ( suppressKeyPress ) {
|
|
suppressKeyPress = false;
|
|
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
|
|
event.preventDefault();
|
|
}
|
|
return;
|
|
}
|
|
if ( suppressKeyPressRepeat ) {
|
|
return;
|
|
}
|
|
|
|
// Replicate some key handlers to allow them to repeat in Firefox and Opera
|
|
var keyCode = $.ui.keyCode;
|
|
switch ( event.keyCode ) {
|
|
case keyCode.PAGE_UP:
|
|
this._move( "previousPage", event );
|
|
break;
|
|
case keyCode.PAGE_DOWN:
|
|
this._move( "nextPage", event );
|
|
break;
|
|
case keyCode.UP:
|
|
this._keyEvent( "previous", event );
|
|
break;
|
|
case keyCode.DOWN:
|
|
this._keyEvent( "next", event );
|
|
break;
|
|
}
|
|
},
|
|
input: function( event ) {
|
|
if ( suppressInput ) {
|
|
suppressInput = false;
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
this._searchTimeout( event );
|
|
},
|
|
focus: function() {
|
|
this.selectedItem = null;
|
|
this.previous = this._value();
|
|
},
|
|
blur: function( event ) {
|
|
if ( this.cancelBlur ) {
|
|
delete this.cancelBlur;
|
|
return;
|
|
}
|
|
|
|
clearTimeout( this.searching );
|
|
this.close( event );
|
|
this._change( event );
|
|
}
|
|
} );
|
|
|
|
this._initSource();
|
|
this.menu = $( "<ul>" )
|
|
.appendTo( this._appendTo() )
|
|
.menu( {
|
|
|
|
// disable ARIA support, the live region takes care of that
|
|
role: null
|
|
} )
|
|
.hide()
|
|
.menu( "instance" );
|
|
|
|
this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
|
|
this._on( this.menu.element, {
|
|
mousedown: function( event ) {
|
|
|
|
// prevent moving focus out of the text field
|
|
event.preventDefault();
|
|
|
|
// IE doesn't prevent moving focus even with event.preventDefault()
|
|
// so we set a flag to know when we should ignore the blur event
|
|
this.cancelBlur = true;
|
|
this._delay( function() {
|
|
delete this.cancelBlur;
|
|
|
|
// Support: IE 8 only
|
|
// Right clicking a menu item or selecting text from the menu items will
|
|
// result in focus moving out of the input. However, we've already received
|
|
// and ignored the blur event because of the cancelBlur flag set above. So
|
|
// we restore focus to ensure that the menu closes properly based on the user's
|
|
// next actions.
|
|
if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
|
|
this.element.trigger( "focus" );
|
|
}
|
|
} );
|
|
},
|
|
menufocus: function( event, ui ) {
|
|
var label, item;
|
|
|
|
// support: Firefox
|
|
// Prevent accidental activation of menu items in Firefox (#7024 #9118)
|
|
if ( this.isNewMenu ) {
|
|
this.isNewMenu = false;
|
|
if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
|
|
this.menu.blur();
|
|
|
|
this.document.one( "mousemove", function() {
|
|
$( event.target ).trigger( event.originalEvent );
|
|
} );
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
item = ui.item.data( "ui-autocomplete-item" );
|
|
if ( false !== this._trigger( "focus", event, { item: item } ) ) {
|
|
|
|
// use value to match what will end up in the input, if it was a key event
|
|
if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
|
|
this._value( item.value );
|
|
}
|
|
}
|
|
|
|
// Announce the value in the liveRegion
|
|
label = ui.item.attr( "aria-label" ) || item.value;
|
|
if ( label && $.trim( label ).length ) {
|
|
this.liveRegion.children().hide();
|
|
$( "<div>" ).text( label ).appendTo( this.liveRegion );
|
|
}
|
|
},
|
|
menuselect: function( event, ui ) {
|
|
var item = ui.item.data( "ui-autocomplete-item" ),
|
|
previous = this.previous;
|
|
|
|
// Only trigger when focus was lost (click on menu)
|
|
if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
|
|
this.element.trigger( "focus" );
|
|
this.previous = previous;
|
|
|
|
// #6109 - IE triggers two focus events and the second
|
|
// is asynchronous, so we need to reset the previous
|
|
// term synchronously and asynchronously :-(
|
|
this._delay( function() {
|
|
this.previous = previous;
|
|
this.selectedItem = item;
|
|
} );
|
|
}
|
|
|
|
if ( false !== this._trigger( "select", event, { item: item } ) ) {
|
|
this._value( item.value );
|
|
}
|
|
|
|
// reset the term after the select event
|
|
// this allows custom select handling to work properly
|
|
this.term = this._value();
|
|
|
|
this.close( event );
|
|
this.selectedItem = item;
|
|
}
|
|
} );
|
|
|
|
this.liveRegion = $( "<div>", {
|
|
role: "status",
|
|
"aria-live": "assertive",
|
|
"aria-relevant": "additions"
|
|
} )
|
|
.appendTo( this.document[ 0 ].body );
|
|
|
|
this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
|
|
|
|
// Turning off autocomplete prevents the browser from remembering the
|
|
// value when navigating through history, so we re-enable autocomplete
|
|
// if the page is unloaded before the widget is destroyed. #7790
|
|
this._on( this.window, {
|
|
beforeunload: function() {
|
|
this.element.removeAttr( "autocomplete" );
|
|
}
|
|
} );
|
|
},
|
|
|
|
_destroy: function() {
|
|
clearTimeout( this.searching );
|
|
this.element.removeAttr( "autocomplete" );
|
|
this.menu.element.remove();
|
|
this.liveRegion.remove();
|
|
},
|
|
|
|
_setOption: function( key, value ) {
|
|
this._super( key, value );
|
|
if ( key === "source" ) {
|
|
this._initSource();
|
|
}
|
|
if ( key === "appendTo" ) {
|
|
this.menu.element.appendTo( this._appendTo() );
|
|
}
|
|
if ( key === "disabled" && value && this.xhr ) {
|
|
this.xhr.abort();
|
|
}
|
|
},
|
|
|
|
_isEventTargetInWidget: function( event ) {
|
|
var menuElement = this.menu.element[ 0 ];
|
|
|
|
return event.target === this.element[ 0 ] ||
|
|
event.target === menuElement ||
|
|
$.contains( menuElement, event.target );
|
|
},
|
|
|
|
_closeOnClickOutside: function( event ) {
|
|
if ( !this._isEventTargetInWidget( event ) ) {
|
|
this.close();
|
|
}
|
|
},
|
|
|
|
_appendTo: function() {
|
|
var element = this.options.appendTo;
|
|
|
|
if ( element ) {
|
|
element = element.jquery || element.nodeType ?
|
|
$( element ) :
|
|
this.document.find( element ).eq( 0 );
|
|
}
|
|
|
|
if ( !element || !element[ 0 ] ) {
|
|
element = this.element.closest( ".ui-front, dialog" );
|
|
}
|
|
|
|
if ( !element.length ) {
|
|
element = this.document[ 0 ].body;
|
|
}
|
|
|
|
return element;
|
|
},
|
|
|
|
_initSource: function() {
|
|
var array, url,
|
|
that = this;
|
|
if ( $.isArray( this.options.source ) ) {
|
|
array = this.options.source;
|
|
this.source = function( request, response ) {
|
|
response( $.ui.autocomplete.filter( array, request.term ) );
|
|
};
|
|
} else if ( typeof this.options.source === "string" ) {
|
|
url = this.options.source;
|
|
this.source = function( request, response ) {
|
|
if ( that.xhr ) {
|
|
that.xhr.abort();
|
|
}
|
|
that.xhr = $.ajax( {
|
|
url: url,
|
|
data: request,
|
|
dataType: "json",
|
|
success: function( data ) {
|
|
response( data );
|
|
},
|
|
error: function() {
|
|
response( [] );
|
|
}
|
|
} );
|
|
};
|
|
} else {
|
|
this.source = this.options.source;
|
|
}
|
|
},
|
|
|
|
_searchTimeout: function( event ) {
|
|
clearTimeout( this.searching );
|
|
this.searching = this._delay( function() {
|
|
|
|
// Search if the value has changed, or if the user retypes the same value (see #7434)
|
|
var equalValues = this.term === this._value(),
|
|
menuVisible = this.menu.element.is( ":visible" ),
|
|
modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
|
|
if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
|
|
this.selectedItem = null;
|
|
this.search( null, event );
|
|
}
|
|
}, this.options.delay );
|
|
},
|
|
|
|
search: function( value, event ) {
|
|
value = value != null ? value : this._value();
|
|
|
|
// Always save the actual value, not the one passed as an argument
|
|
this.term = this._value();
|
|
|
|
if ( value.length < this.options.minLength ) {
|
|
return this.close( event );
|
|
}
|
|
|
|
if ( this._trigger( "search", event ) === false ) {
|
|
return;
|
|
}
|
|
|
|
return this._search( value );
|
|
},
|
|
|
|
_search: function( value ) {
|
|
this.pending++;
|
|
this._addClass( "ui-autocomplete-loading" );
|
|
this.cancelSearch = false;
|
|
|
|
this.source( { term: value }, this._response() );
|
|
},
|
|
|
|
_response: function() {
|
|
var index = ++this.requestIndex;
|
|
|
|
return $.proxy( function( content ) {
|
|
if ( index === this.requestIndex ) {
|
|
this.__response( content );
|
|
}
|
|
|
|
this.pending--;
|
|
if ( !this.pending ) {
|
|
this._removeClass( "ui-autocomplete-loading" );
|
|
}
|
|
}, this );
|
|
},
|
|
|
|
__response: function( content ) {
|
|
if ( content ) {
|
|
content = this._normalize( content );
|
|
}
|
|
this._trigger( "response", null, { content: content } );
|
|
if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
|
|
this._suggest( content );
|
|
this._trigger( "open" );
|
|
} else {
|
|
|
|
// use ._close() instead of .close() so we don't cancel future searches
|
|
this._close();
|
|
}
|
|
},
|
|
|
|
close: function( event ) {
|
|
this.cancelSearch = true;
|
|
this._close( event );
|
|
},
|
|
|
|
_close: function( event ) {
|
|
|
|
// Remove the handler that closes the menu on outside clicks
|
|
this._off( this.document, "mousedown" );
|
|
|
|
if ( this.menu.element.is( ":visible" ) ) {
|
|
this.menu.element.hide();
|
|
this.menu.blur();
|
|
this.isNewMenu = true;
|
|
this._trigger( "close", event );
|
|
}
|
|
},
|
|
|
|
_change: function( event ) {
|
|
if ( this.previous !== this._value() ) {
|
|
this._trigger( "change", event, { item: this.selectedItem } );
|
|
}
|
|
},
|
|
|
|
_normalize: function( items ) {
|
|
|
|
// assume all items have the right format when the first item is complete
|
|
if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
|
|
return items;
|
|
}
|
|
return $.map( items, function( item ) {
|
|
if ( typeof item === "string" ) {
|
|
return {
|
|
label: item,
|
|
value: item
|
|
};
|
|
}
|
|
return $.extend( {}, item, {
|
|
label: item.label || item.value,
|
|
value: item.value || item.label
|
|
} );
|
|
} );
|
|
},
|
|
|
|
_suggest: function( items ) {
|
|
var ul = this.menu.element.empty();
|
|
this._renderMenu( ul, items );
|
|
this.isNewMenu = true;
|
|
this.menu.refresh();
|
|
|
|
// Size and position menu
|
|
ul.show();
|
|
this._resizeMenu();
|
|
ul.position( $.extend( {
|
|
of: this.element
|
|
}, this.options.position ) );
|
|
|
|
if ( this.options.autoFocus ) {
|
|
this.menu.next();
|
|
}
|
|
|
|
// Listen for interactions outside of the widget (#6642)
|
|
this._on( this.document, {
|
|
mousedown: "_closeOnClickOutside"
|
|
} );
|
|
},
|
|
|
|
_resizeMenu: function() {
|
|
var ul = this.menu.element;
|
|
ul.outerWidth( Math.max(
|
|
|
|
// Firefox wraps long text (possibly a rounding bug)
|
|
// so we add 1px to avoid the wrapping (#7513)
|
|
ul.width( "" ).outerWidth() + 1,
|
|
this.element.outerWidth()
|
|
) );
|
|
},
|
|
|
|
_renderMenu: function( ul, items ) {
|
|
var that = this;
|
|
$.each( items, function( index, item ) {
|
|
that._renderItemData( ul, item );
|
|
} );
|
|
},
|
|
|
|
_renderItemData: function( ul, item ) {
|
|
return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
|
|
},
|
|
|
|
_renderItem: function( ul, item ) {
|
|
return $( "<li>" )
|
|
.append( $( "<div>" ).text( item.label ) )
|
|
.appendTo( ul );
|
|
},
|
|
|
|
_move: function( direction, event ) {
|
|
if ( !this.menu.element.is( ":visible" ) ) {
|
|
this.search( null, event );
|
|
return;
|
|
}
|
|
if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
|
|
this.menu.isLastItem() && /^next/.test( direction ) ) {
|
|
|
|
if ( !this.isMultiLine ) {
|
|
this._value( this.term );
|
|
}
|
|
|
|
this.menu.blur();
|
|
return;
|
|
}
|
|
this.menu[ direction ]( event );
|
|
},
|
|
|
|
widget: function() {
|
|
return this.menu.element;
|
|
},
|
|
|
|
_value: function() {
|
|
return this.valueMethod.apply( this.element, arguments );
|
|
},
|
|
|
|
_keyEvent: function( keyEvent, event ) {
|
|
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
|
|
this._move( keyEvent, event );
|
|
|
|
// Prevents moving cursor to beginning/end of the text field in some browsers
|
|
event.preventDefault();
|
|
}
|
|
},
|
|
|
|
// Support: Chrome <=50
|
|
// We should be able to just use this.element.prop( "isContentEditable" )
|
|
// but hidden elements always report false in Chrome.
|
|
// https://code.google.com/p/chromium/issues/detail?id=313082
|
|
_isContentEditable: function( element ) {
|
|
if ( !element.length ) {
|
|
return false;
|
|
}
|
|
|
|
var editable = element.prop( "contentEditable" );
|
|
|
|
if ( editable === "inherit" ) {
|
|
return this._isContentEditable( element.parent() );
|
|
}
|
|
|
|
return editable === "true";
|
|
}
|
|
} );
|
|
|
|
$.extend( $.ui.autocomplete, {
|
|
escapeRegex: function( value ) {
|
|
return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
|
|
},
|
|
filter: function( array, term ) {
|
|
var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
|
|
return $.grep( array, function( value ) {
|
|
return matcher.test( value.label || value.value || value );
|
|
} );
|
|
}
|
|
} );
|
|
|
|
// Live region extension, adding a `messages` option
|
|
// NOTE: This is an experimental API. We are still investigating
|
|
// a full solution for string manipulation and internationalization.
|
|
$.widget( "ui.autocomplete", $.ui.autocomplete, {
|
|
options: {
|
|
messages: {
|
|
noResults: "No search results.",
|
|
results: function( amount ) {
|
|
return amount + ( amount > 1 ? " results are" : " result is" ) +
|
|
" available, use up and down arrow keys to navigate.";
|
|
}
|
|
}
|
|
},
|
|
|
|
__response: function( content ) {
|
|
var message;
|
|
this._superApply( arguments );
|
|
if ( this.options.disabled || this.cancelSearch ) {
|
|
return;
|
|
}
|
|
if ( content && content.length ) {
|
|
message = this.options.messages.results( content.length );
|
|
} else {
|
|
message = this.options.messages.noResults;
|
|
}
|
|
this.liveRegion.children().hide();
|
|
$( "<div>" ).text( message ).appendTo( this.liveRegion );
|
|
}
|
|
} );
|
|
|
|
return $.ui.autocomplete;
|
|
|
|
} ) );
|
|
/*
|
|
|
|
jQuery Tags Input Plugin 1.3.3
|
|
|
|
Copyright (c) 2011 XOXCO, Inc
|
|
|
|
Documentation for this plugin lives here:
|
|
http://xoxco.com/clickable/jquery-tags-input
|
|
|
|
Licensed under the MIT license:
|
|
http://www.opensource.org/licenses/mit-license.php
|
|
|
|
ben@xoxco.com
|
|
|
|
*/
|
|
|
|
(function($) {
|
|
|
|
var delimiter = new Array();
|
|
var tags_callbacks = new Array();
|
|
$.fn.doAutosize = function(o){
|
|
var minWidth = $(this).data('minwidth'),
|
|
maxWidth = $(this).data('maxwidth'),
|
|
val = '',
|
|
input = $(this),
|
|
testSubject = $('#'+$(this).data('tester_id'));
|
|
|
|
if (val === (val = input.val())) {return;}
|
|
|
|
// Enter new content into testSubject
|
|
var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
|
|
testSubject.html(escaped);
|
|
// Calculate new width + whether to change
|
|
var testerWidth = testSubject.width(),
|
|
newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
|
|
currentWidth = input.width(),
|
|
isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
|
|
|| (newWidth > minWidth && newWidth < maxWidth);
|
|
|
|
// Animate width
|
|
if (isValidWidthChange) {
|
|
input.width(newWidth);
|
|
}
|
|
|
|
|
|
};
|
|
$.fn.resetAutosize = function(options){
|
|
// alert(JSON.stringify(options));
|
|
var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(),
|
|
maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding),
|
|
val = '',
|
|
input = $(this),
|
|
testSubject = $('<tester/>').css({
|
|
position: 'absolute',
|
|
top: -9999,
|
|
left: -9999,
|
|
width: 'auto',
|
|
fontSize: input.css('fontSize'),
|
|
fontFamily: input.css('fontFamily'),
|
|
fontWeight: input.css('fontWeight'),
|
|
letterSpacing: input.css('letterSpacing'),
|
|
whiteSpace: 'nowrap'
|
|
}),
|
|
testerId = $(this).attr('id')+'_autosize_tester';
|
|
if(! $('#'+testerId).length > 0){
|
|
testSubject.attr('id', testerId);
|
|
testSubject.appendTo('body');
|
|
}
|
|
|
|
input.data('minwidth', minWidth);
|
|
input.data('maxwidth', maxWidth);
|
|
input.data('tester_id', testerId);
|
|
input.css('width', minWidth);
|
|
};
|
|
|
|
$.fn.addTag = function(value,options) {
|
|
options = jQuery.extend({focus:false,callback:true},options);
|
|
this.each(function() {
|
|
var id = $(this).attr('id');
|
|
|
|
var tagslist = $(this).val().split(delimiter[id]);
|
|
if (tagslist[0] == '') {
|
|
tagslist = new Array();
|
|
}
|
|
|
|
value = jQuery.trim(value);
|
|
|
|
if (options.unique) {
|
|
var skipTag = $(this).tagExist(value);
|
|
if(skipTag == true) {
|
|
//Marks fake input as not_valid to let styling it
|
|
$('#'+id+'_tag').addClass('not_valid');
|
|
}
|
|
} else {
|
|
var skipTag = false;
|
|
}
|
|
|
|
if (value !='' && skipTag != true) {
|
|
$('<span>').addClass('tag').append(
|
|
$('<span>').text(value).append(' '),
|
|
$('<a>', {
|
|
href : '#',
|
|
title : 'Removing tag',
|
|
text : 'x'
|
|
}).click(function () {
|
|
return $('#' + id).removeTag(escape(value));
|
|
})
|
|
).insertBefore('#' + id + '_addTag');
|
|
|
|
tagslist.push(value);
|
|
|
|
$('#'+id+'_tag').val('');
|
|
if (options.focus) {
|
|
$('#'+id+'_tag').focus();
|
|
} else {
|
|
$('#'+id+'_tag').blur();
|
|
}
|
|
|
|
$.fn.tagsInput.updateTagsField(this,tagslist);
|
|
|
|
if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) {
|
|
var f = tags_callbacks[id]['onAddTag'];
|
|
f.call(this, value);
|
|
}
|
|
if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
|
|
{
|
|
var i = tagslist.length;
|
|
var f = tags_callbacks[id]['onChange'];
|
|
f.call(this, $(this), tagslist[i-1]);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
return false;
|
|
};
|
|
|
|
$.fn.removeTag = function(value) {
|
|
value = unescape(value);
|
|
this.each(function() {
|
|
var id = $(this).attr('id');
|
|
|
|
var old = $(this).val().split(delimiter[id]);
|
|
|
|
$('#'+id+'_tagsinput .tag').remove();
|
|
str = '';
|
|
for (i=0; i< old.length; i++) {
|
|
if (old[i]!=value) {
|
|
str = str + delimiter[id] +old[i];
|
|
}
|
|
}
|
|
|
|
$.fn.tagsInput.importTags(this,str);
|
|
|
|
if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) {
|
|
var f = tags_callbacks[id]['onRemoveTag'];
|
|
f.call(this, value);
|
|
}
|
|
});
|
|
|
|
return false;
|
|
};
|
|
|
|
$.fn.tagExist = function(val) {
|
|
var id = $(this).attr('id');
|
|
var tagslist = $(this).val().split(delimiter[id]);
|
|
return (jQuery.inArray(val, tagslist) >= 0); //true when tag exists, false when not
|
|
};
|
|
|
|
// clear all existing tags and import new ones from a string
|
|
$.fn.importTags = function(str) {
|
|
var id = $(this).attr('id');
|
|
$('#'+id+'_tagsinput .tag').remove();
|
|
$.fn.tagsInput.importTags(this,str);
|
|
}
|
|
|
|
$.fn.tagsInput = function(options) {
|
|
var settings = jQuery.extend({
|
|
interactive:true,
|
|
defaultText:'add a tag',
|
|
minChars:0,
|
|
width:'300px',
|
|
height:'100px',
|
|
autocomplete: {selectFirst: false },
|
|
hide:true,
|
|
delimiter: ',',
|
|
unique:true,
|
|
removeWithBackspace:true,
|
|
placeholderColor:'#666666',
|
|
autosize: true,
|
|
comfortZone: 20,
|
|
inputPadding: 6*2
|
|
},options);
|
|
|
|
var uniqueIdCounter = 0;
|
|
|
|
this.each(function() {
|
|
// If we have already initialized the field, do not do it again
|
|
if (typeof $(this).attr('data-tagsinput-init') !== 'undefined') {
|
|
return;
|
|
}
|
|
|
|
// Mark the field as having been initialized
|
|
$(this).attr('data-tagsinput-init', true);
|
|
|
|
if (settings.hide) {
|
|
$(this).hide();
|
|
}
|
|
var id = $(this).attr('id');
|
|
if (!id || delimiter[$(this).attr('id')]) {
|
|
id = $(this).attr('id', 'tags' + new Date().getTime() + (uniqueIdCounter++)).attr('id');
|
|
}
|
|
|
|
var data = jQuery.extend({
|
|
pid:id,
|
|
real_input: '#'+id,
|
|
holder: '#'+id+'_tagsinput',
|
|
input_wrapper: '#'+id+'_addTag',
|
|
fake_input: '#'+id+'_tag'
|
|
},settings);
|
|
|
|
delimiter[id] = data.delimiter;
|
|
|
|
if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
|
|
tags_callbacks[id] = new Array();
|
|
tags_callbacks[id]['onAddTag'] = settings.onAddTag;
|
|
tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
|
|
tags_callbacks[id]['onChange'] = settings.onChange;
|
|
}
|
|
|
|
var markup = '<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag">';
|
|
|
|
if (settings.interactive) {
|
|
markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />';
|
|
}
|
|
|
|
markup = markup + '</div><div class="tags_clear"></div></div>';
|
|
|
|
$(markup).insertAfter(this);
|
|
|
|
$(data.holder).css('width',settings.width);
|
|
$(data.holder).css('min-height',settings.height);
|
|
$(data.holder).css('height',settings.height);
|
|
|
|
if ($(data.real_input).val()!='') {
|
|
$.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());
|
|
}
|
|
if (settings.interactive) {
|
|
$(data.fake_input).val($(data.fake_input).attr('data-default'));
|
|
$(data.fake_input).css('color',settings.placeholderColor);
|
|
$(data.fake_input).resetAutosize(settings);
|
|
|
|
$(data.holder).bind('click',data,function(event) {
|
|
$(event.data.fake_input).focus();
|
|
});
|
|
|
|
$(data.fake_input).bind('focus',data,function(event) {
|
|
if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) {
|
|
$(event.data.fake_input).val('');
|
|
}
|
|
$(event.data.fake_input).css('color','#000000');
|
|
});
|
|
|
|
if (settings.autocomplete_url != undefined) {
|
|
autocomplete_options = {source: settings.autocomplete_url};
|
|
for (attrname in settings.autocomplete) {
|
|
autocomplete_options[attrname] = settings.autocomplete[attrname];
|
|
}
|
|
|
|
if (jQuery.Autocompleter !== undefined) {
|
|
$(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete);
|
|
$(data.fake_input).bind('result',data,function(event,data,formatted) {
|
|
if (data) {
|
|
$('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)});
|
|
}
|
|
});
|
|
} else if (jQuery.ui.autocomplete !== undefined) {
|
|
$(data.fake_input).autocomplete(autocomplete_options);
|
|
$(data.fake_input).bind('autocompleteselect',data,function(event,ui) {
|
|
$(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)});
|
|
return false;
|
|
});
|
|
}
|
|
|
|
|
|
} else {
|
|
// if a user tabs out of the field, create a new tag
|
|
// this is only available if autocomplete is not used.
|
|
$(data.fake_input).bind('blur',data,function(event) {
|
|
var d = $(this).attr('data-default');
|
|
if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {
|
|
if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
|
|
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
|
|
} else {
|
|
$(event.data.fake_input).val($(event.data.fake_input).attr('data-default'));
|
|
$(event.data.fake_input).css('color',settings.placeholderColor);
|
|
}
|
|
return false;
|
|
});
|
|
|
|
}
|
|
// if user types a default delimiter like comma,semicolon and then create a new tag
|
|
$(data.fake_input).bind('keypress',data,function(event) {
|
|
if (_checkDelimiter(event)) {
|
|
event.preventDefault();
|
|
if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
|
|
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
|
|
$(event.data.fake_input).resetAutosize(settings);
|
|
return false;
|
|
} else if (event.data.autosize) {
|
|
$(event.data.fake_input).doAutosize(settings);
|
|
|
|
}
|
|
});
|
|
//Delete last tag on backspace
|
|
data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event)
|
|
{
|
|
if(event.keyCode == 8 && $(this).val() == '')
|
|
{
|
|
event.preventDefault();
|
|
var last_tag = $(this).closest('.tagsinput').find('.tag:last').text();
|
|
var id = $(this).attr('id').replace(/_tag$/, '');
|
|
last_tag = last_tag.replace(/[\s]+x$/, '');
|
|
$('#' + id).removeTag(escape(last_tag));
|
|
$(this).trigger('focus');
|
|
}
|
|
});
|
|
$(data.fake_input).blur();
|
|
|
|
//Removes the not_valid class when user changes the value of the fake input
|
|
if(data.unique) {
|
|
$(data.fake_input).keydown(function(event){
|
|
if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/)) {
|
|
$(this).removeClass('not_valid');
|
|
}
|
|
});
|
|
}
|
|
} // if settings.interactive
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
$.fn.tagsInput.updateTagsField = function(obj,tagslist) {
|
|
var id = $(obj).attr('id');
|
|
$(obj).val(tagslist.join(delimiter[id]));
|
|
};
|
|
|
|
$.fn.tagsInput.importTags = function(obj,val) {
|
|
$(obj).val('');
|
|
var id = $(obj).attr('id');
|
|
var tags = val.split(delimiter[id]);
|
|
for (i=0; i<tags.length; i++) {
|
|
$(obj).addTag(tags[i],{focus:false,callback:false});
|
|
}
|
|
if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
|
|
{
|
|
var f = tags_callbacks[id]['onChange'];
|
|
f.call(obj, obj, tags[i]);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* check delimiter Array
|
|
* @param event
|
|
* @returns {boolean}
|
|
* @private
|
|
*/
|
|
var _checkDelimiter = function(event){
|
|
var found = false;
|
|
if (event.which == 13) {
|
|
return true;
|
|
}
|
|
|
|
if (typeof event.data.delimiter === 'string') {
|
|
if (event.which == event.data.delimiter.charCodeAt(0)) {
|
|
found = true;
|
|
}
|
|
} else {
|
|
$.each(event.data.delimiter, function(index, delimiter) {
|
|
if (event.which == delimiter.charCodeAt(0)) {
|
|
found = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
return found;
|
|
}
|
|
})(jQuery);
|
|
(function($){
|
|
|
|
/**
|
|
* Copyright 2012, Digital Fusion
|
|
* Licensed under the MIT license.
|
|
* http://teamdf.com/jquery-plugins/license/
|
|
*
|
|
* @author Sam Sehnert
|
|
* @desc A small plugin that checks whether elements are within
|
|
* the user visible viewport of a web browser.
|
|
* only accounts for vertical position, not horizontal.
|
|
*/
|
|
var $w = $(window);
|
|
$.fn.visible = function(partial,hidden,direction){
|
|
|
|
if (this.length < 1)
|
|
return;
|
|
|
|
var $t = this.length > 1 ? this.eq(0) : this,
|
|
t = $t.get(0),
|
|
vpWidth = $w.width(),
|
|
vpHeight = $w.height(),
|
|
direction = (direction) ? direction : 'both',
|
|
clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;
|
|
|
|
if (typeof t.getBoundingClientRect === 'function'){
|
|
|
|
// Use this native browser method, if available.
|
|
var rec = t.getBoundingClientRect(),
|
|
tViz = rec.top >= 0 && rec.top < vpHeight,
|
|
bViz = rec.bottom > 0 && rec.bottom <= vpHeight,
|
|
lViz = rec.left >= 0 && rec.left < vpWidth,
|
|
rViz = rec.right > 0 && rec.right <= vpWidth,
|
|
vVisible = partial ? tViz || bViz : tViz && bViz,
|
|
hVisible = partial ? lViz || rViz : lViz && rViz;
|
|
|
|
if(direction === 'both')
|
|
return clientSize && vVisible && hVisible;
|
|
else if(direction === 'vertical')
|
|
return clientSize && vVisible;
|
|
else if(direction === 'horizontal')
|
|
return clientSize && hVisible;
|
|
} else {
|
|
|
|
var viewTop = $w.scrollTop(),
|
|
viewBottom = viewTop + vpHeight,
|
|
viewLeft = $w.scrollLeft(),
|
|
viewRight = viewLeft + vpWidth,
|
|
offset = $t.offset(),
|
|
_top = offset.top,
|
|
_bottom = _top + $t.height(),
|
|
_left = offset.left,
|
|
_right = _left + $t.width(),
|
|
compareTop = partial === true ? _bottom : _top,
|
|
compareBottom = partial === true ? _top : _bottom,
|
|
compareLeft = partial === true ? _right : _left,
|
|
compareRight = partial === true ? _left : _right;
|
|
|
|
if(direction === 'both')
|
|
return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
|
|
else if(direction === 'vertical')
|
|
return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
|
|
else if(direction === 'horizontal')
|
|
return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
|
|
}
|
|
};
|
|
|
|
})(jQuery);
|
|
/*
|
|
Turbolinks 5.2.0
|
|
Copyright © 2018 Basecamp, LLC
|
|
*/
|
|
(function(){var t=this;(function(){(function(){this.Turbolinks={supported:function(){return null!=window.history.pushState&&null!=window.requestAnimationFrame&&null!=window.addEventListener}(),visit:function(t,r){return e.controller.visit(t,r)},clearCache:function(){return e.controller.clearCache()},setProgressBarDelay:function(t){return e.controller.setProgressBarDelay(t)}}}).call(this)}).call(t);var e=t.Turbolinks;(function(){(function(){var t,r,n,o=[].slice;e.copyObject=function(t){var e,r,n;r={};for(e in t)n=t[e],r[e]=n;return r},e.closest=function(e,r){return t.call(e,r)},t=function(){var t,e;return t=document.documentElement,null!=(e=t.closest)?e:function(t){var e;for(e=this;e;){if(e.nodeType===Node.ELEMENT_NODE&&r.call(e,t))return e;e=e.parentNode}}}(),e.defer=function(t){return setTimeout(t,1)},e.throttle=function(t){var e;return e=null,function(){var r;return r=1<=arguments.length?o.call(arguments,0):[],null!=e?e:e=requestAnimationFrame(function(n){return function(){return e=null,t.apply(n,r)}}(this))}},e.dispatch=function(t,e){var r,o,i,s,a,u;return a=null!=e?e:{},u=a.target,r=a.cancelable,o=a.data,i=document.createEvent("Events"),i.initEvent(t,!0,r===!0),i.data=null!=o?o:{},i.cancelable&&!n&&(s=i.preventDefault,i.preventDefault=function(){return this.defaultPrevented||Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}}),s.call(this)}),(null!=u?u:document).dispatchEvent(i),i},n=function(){var t;return t=document.createEvent("Events"),t.initEvent("test",!0,!0),t.preventDefault(),t.defaultPrevented}(),e.match=function(t,e){return r.call(t,e)},r=function(){var t,e,r,n;return t=document.documentElement,null!=(e=null!=(r=null!=(n=t.matchesSelector)?n:t.webkitMatchesSelector)?r:t.msMatchesSelector)?e:t.mozMatchesSelector}(),e.uuid=function(){var t,e,r;for(r="",t=e=1;36>=e;t=++e)r+=9===t||14===t||19===t||24===t?"-":15===t?"4":20===t?(Math.floor(4*Math.random())+8).toString(16):Math.floor(15*Math.random()).toString(16);return r}}).call(this),function(){e.Location=function(){function t(t){var e,r;null==t&&(t=""),r=document.createElement("a"),r.href=t.toString(),this.absoluteURL=r.href,e=r.hash.length,2>e?this.requestURL=this.absoluteURL:(this.requestURL=this.absoluteURL.slice(0,-e),this.anchor=r.hash.slice(1))}var e,r,n,o;return t.wrap=function(t){return t instanceof this?t:new this(t)},t.prototype.getOrigin=function(){return this.absoluteURL.split("/",3).join("/")},t.prototype.getPath=function(){var t,e;return null!=(t=null!=(e=this.requestURL.match(/\/\/[^\/]*(\/[^?;]*)/))?e[1]:void 0)?t:"/"},t.prototype.getPathComponents=function(){return this.getPath().split("/").slice(1)},t.prototype.getLastPathComponent=function(){return this.getPathComponents().slice(-1)[0]},t.prototype.getExtension=function(){var t,e;return null!=(t=null!=(e=this.getLastPathComponent().match(/\.[^.]*$/))?e[0]:void 0)?t:""},t.prototype.isHTML=function(){return this.getExtension().match(/^(?:|\.(?:htm|html|xhtml))$/)},t.prototype.isPrefixedBy=function(t){var e;return e=r(t),this.isEqualTo(t)||o(this.absoluteURL,e)},t.prototype.isEqualTo=function(t){return this.absoluteURL===(null!=t?t.absoluteURL:void 0)},t.prototype.toCacheKey=function(){return this.requestURL},t.prototype.toJSON=function(){return this.absoluteURL},t.prototype.toString=function(){return this.absoluteURL},t.prototype.valueOf=function(){return this.absoluteURL},r=function(t){return e(t.getOrigin()+t.getPath())},e=function(t){return n(t,"/")?t:t+"/"},o=function(t,e){return t.slice(0,e.length)===e},n=function(t,e){return t.slice(-e.length)===e},t}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.HttpRequest=function(){function r(r,n,o){this.delegate=r,this.requestCanceled=t(this.requestCanceled,this),this.requestTimedOut=t(this.requestTimedOut,this),this.requestFailed=t(this.requestFailed,this),this.requestLoaded=t(this.requestLoaded,this),this.requestProgressed=t(this.requestProgressed,this),this.url=e.Location.wrap(n).requestURL,this.referrer=e.Location.wrap(o).absoluteURL,this.createXHR()}return r.NETWORK_FAILURE=0,r.TIMEOUT_FAILURE=-1,r.timeout=60,r.prototype.send=function(){var t;return this.xhr&&!this.sent?(this.notifyApplicationBeforeRequestStart(),this.setProgress(0),this.xhr.send(),this.sent=!0,"function"==typeof(t=this.delegate).requestStarted?t.requestStarted():void 0):void 0},r.prototype.cancel=function(){return this.xhr&&this.sent?this.xhr.abort():void 0},r.prototype.requestProgressed=function(t){return t.lengthComputable?this.setProgress(t.loaded/t.total):void 0},r.prototype.requestLoaded=function(){return this.endRequest(function(t){return function(){var e;return 200<=(e=t.xhr.status)&&300>e?t.delegate.requestCompletedWithResponse(t.xhr.responseText,t.xhr.getResponseHeader("Turbolinks-Location")):(t.failed=!0,t.delegate.requestFailedWithStatusCode(t.xhr.status,t.xhr.responseText))}}(this))},r.prototype.requestFailed=function(){return this.endRequest(function(t){return function(){return t.failed=!0,t.delegate.requestFailedWithStatusCode(t.constructor.NETWORK_FAILURE)}}(this))},r.prototype.requestTimedOut=function(){return this.endRequest(function(t){return function(){return t.failed=!0,t.delegate.requestFailedWithStatusCode(t.constructor.TIMEOUT_FAILURE)}}(this))},r.prototype.requestCanceled=function(){return this.endRequest()},r.prototype.notifyApplicationBeforeRequestStart=function(){return e.dispatch("turbolinks:request-start",{data:{url:this.url,xhr:this.xhr}})},r.prototype.notifyApplicationAfterRequestEnd=function(){return e.dispatch("turbolinks:request-end",{data:{url:this.url,xhr:this.xhr}})},r.prototype.createXHR=function(){return this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url,!0),this.xhr.timeout=1e3*this.constructor.timeout,this.xhr.setRequestHeader("Accept","text/html, application/xhtml+xml"),this.xhr.setRequestHeader("Turbolinks-Referrer",this.referrer),this.xhr.onprogress=this.requestProgressed,this.xhr.onload=this.requestLoaded,this.xhr.onerror=this.requestFailed,this.xhr.ontimeout=this.requestTimedOut,this.xhr.onabort=this.requestCanceled},r.prototype.endRequest=function(t){return this.xhr?(this.notifyApplicationAfterRequestEnd(),null!=t&&t.call(this),this.destroy()):void 0},r.prototype.setProgress=function(t){var e;return this.progress=t,"function"==typeof(e=this.delegate).requestProgressed?e.requestProgressed(this.progress):void 0},r.prototype.destroy=function(){var t;return this.setProgress(1),"function"==typeof(t=this.delegate).requestFinished&&t.requestFinished(),this.delegate=null,this.xhr=null},r}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.ProgressBar=function(){function e(){this.trickle=t(this.trickle,this),this.stylesheetElement=this.createStylesheetElement(),this.progressElement=this.createProgressElement()}var r;return r=300,e.defaultCSS=".turbolinks-progress-bar {\n position: fixed;\n display: block;\n top: 0;\n left: 0;\n height: 3px;\n background: #0076ff;\n z-index: 9999;\n transition: width "+r+"ms ease-out, opacity "+r/2+"ms "+r/2+"ms ease-in;\n transform: translate3d(0, 0, 0);\n}",e.prototype.show=function(){return this.visible?void 0:(this.visible=!0,this.installStylesheetElement(),this.installProgressElement(),this.startTrickling())},e.prototype.hide=function(){return this.visible&&!this.hiding?(this.hiding=!0,this.fadeProgressElement(function(t){return function(){return t.uninstallProgressElement(),t.stopTrickling(),t.visible=!1,t.hiding=!1}}(this))):void 0},e.prototype.setValue=function(t){return this.value=t,this.refresh()},e.prototype.installStylesheetElement=function(){return document.head.insertBefore(this.stylesheetElement,document.head.firstChild)},e.prototype.installProgressElement=function(){return this.progressElement.style.width=0,this.progressElement.style.opacity=1,document.documentElement.insertBefore(this.progressElement,document.body),this.refresh()},e.prototype.fadeProgressElement=function(t){return this.progressElement.style.opacity=0,setTimeout(t,1.5*r)},e.prototype.uninstallProgressElement=function(){return this.progressElement.parentNode?document.documentElement.removeChild(this.progressElement):void 0},e.prototype.startTrickling=function(){return null!=this.trickleInterval?this.trickleInterval:this.trickleInterval=setInterval(this.trickle,r)},e.prototype.stopTrickling=function(){return clearInterval(this.trickleInterval),this.trickleInterval=null},e.prototype.trickle=function(){return this.setValue(this.value+Math.random()/100)},e.prototype.refresh=function(){return requestAnimationFrame(function(t){return function(){return t.progressElement.style.width=10+90*t.value+"%"}}(this))},e.prototype.createStylesheetElement=function(){var t;return t=document.createElement("style"),t.type="text/css",t.textContent=this.constructor.defaultCSS,t},e.prototype.createProgressElement=function(){var t;return t=document.createElement("div"),t.className="turbolinks-progress-bar",t},e}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.BrowserAdapter=function(){function r(r){this.controller=r,this.showProgressBar=t(this.showProgressBar,this),this.progressBar=new e.ProgressBar}var n,o,i;return i=e.HttpRequest,n=i.NETWORK_FAILURE,o=i.TIMEOUT_FAILURE,r.prototype.visitProposedToLocationWithAction=function(t,e){return this.controller.startVisitToLocationWithAction(t,e)},r.prototype.visitStarted=function(t){return t.issueRequest(),t.changeHistory(),t.loadCachedSnapshot()},r.prototype.visitRequestStarted=function(t){return this.progressBar.setValue(0),t.hasCachedSnapshot()||"restore"!==t.action?this.showProgressBarAfterDelay():this.showProgressBar()},r.prototype.visitRequestProgressed=function(t){return this.progressBar.setValue(t.progress)},r.prototype.visitRequestCompleted=function(t){return t.loadResponse()},r.prototype.visitRequestFailedWithStatusCode=function(t,e){switch(e){case n:case o:return this.reload();default:return t.loadResponse()}},r.prototype.visitRequestFinished=function(t){return this.hideProgressBar()},r.prototype.visitCompleted=function(t){return t.followRedirect()},r.prototype.pageInvalidated=function(){return this.reload()},r.prototype.showProgressBarAfterDelay=function(){return this.progressBarTimeout=setTimeout(this.showProgressBar,this.controller.progressBarDelay)},r.prototype.showProgressBar=function(){return this.progressBar.show()},r.prototype.hideProgressBar=function(){return this.progressBar.hide(),clearTimeout(this.progressBarTimeout)},r.prototype.reload=function(){return window.location.reload()},r}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.History=function(){function r(e){this.delegate=e,this.onPageLoad=t(this.onPageLoad,this),this.onPopState=t(this.onPopState,this)}return r.prototype.start=function(){return this.started?void 0:(addEventListener("popstate",this.onPopState,!1),addEventListener("load",this.onPageLoad,!1),this.started=!0)},r.prototype.stop=function(){return this.started?(removeEventListener("popstate",this.onPopState,!1),removeEventListener("load",this.onPageLoad,!1),this.started=!1):void 0},r.prototype.push=function(t,r){return t=e.Location.wrap(t),this.update("push",t,r)},r.prototype.replace=function(t,r){return t=e.Location.wrap(t),this.update("replace",t,r)},r.prototype.onPopState=function(t){var r,n,o,i;return this.shouldHandlePopState()&&(i=null!=(n=t.state)?n.turbolinks:void 0)?(r=e.Location.wrap(window.location),o=i.restorationIdentifier,this.delegate.historyPoppedToLocationWithRestorationIdentifier(r,o)):void 0},r.prototype.onPageLoad=function(t){return e.defer(function(t){return function(){return t.pageLoaded=!0}}(this))},r.prototype.shouldHandlePopState=function(){return this.pageIsLoaded()},r.prototype.pageIsLoaded=function(){return this.pageLoaded||"complete"===document.readyState},r.prototype.update=function(t,e,r){var n;return n={turbolinks:{restorationIdentifier:r}},history[t+"State"](n,null,e)},r}()}.call(this),function(){e.HeadDetails=function(){function t(t){var e,r,n,s,a,u;for(this.elements={},n=0,a=t.length;a>n;n++)u=t[n],u.nodeType===Node.ELEMENT_NODE&&(s=u.outerHTML,r=null!=(e=this.elements)[s]?e[s]:e[s]={type:i(u),tracked:o(u),elements:[]},r.elements.push(u))}var e,r,n,o,i;return t.fromHeadElement=function(t){var e;return new this(null!=(e=null!=t?t.childNodes:void 0)?e:[])},t.prototype.hasElementWithKey=function(t){return t in this.elements},t.prototype.getTrackedElementSignature=function(){var t,e;return function(){var r,n;r=this.elements,n=[];for(t in r)e=r[t].tracked,e&&n.push(t);return n}.call(this).join("")},t.prototype.getScriptElementsNotInDetails=function(t){return this.getElementsMatchingTypeNotInDetails("script",t)},t.prototype.getStylesheetElementsNotInDetails=function(t){return this.getElementsMatchingTypeNotInDetails("stylesheet",t)},t.prototype.getElementsMatchingTypeNotInDetails=function(t,e){var r,n,o,i,s,a;o=this.elements,s=[];for(n in o)i=o[n],a=i.type,r=i.elements,a!==t||e.hasElementWithKey(n)||s.push(r[0]);return s},t.prototype.getProvisionalElements=function(){var t,e,r,n,o,i,s;r=[],n=this.elements;for(e in n)o=n[e],s=o.type,i=o.tracked,t=o.elements,null!=s||i?t.length>1&&r.push.apply(r,t.slice(1)):r.push.apply(r,t);return r},t.prototype.getMetaValue=function(t){var e;return null!=(e=this.findMetaElementByName(t))?e.getAttribute("content"):void 0},t.prototype.findMetaElementByName=function(t){var r,n,o,i;r=void 0,i=this.elements;for(o in i)n=i[o].elements,e(n[0],t)&&(r=n[0]);return r},i=function(t){return r(t)?"script":n(t)?"stylesheet":void 0},o=function(t){return"reload"===t.getAttribute("data-turbolinks-track")},r=function(t){var e;return e=t.tagName.toLowerCase(),"script"===e},n=function(t){var e;return e=t.tagName.toLowerCase(),"style"===e||"link"===e&&"stylesheet"===t.getAttribute("rel")},e=function(t,e){var r;return r=t.tagName.toLowerCase(),"meta"===r&&t.getAttribute("name")===e},t}()}.call(this),function(){e.Snapshot=function(){function t(t,e){this.headDetails=t,this.bodyElement=e}return t.wrap=function(t){return t instanceof this?t:"string"==typeof t?this.fromHTMLString(t):this.fromHTMLElement(t)},t.fromHTMLString=function(t){var e;return e=document.createElement("html"),e.innerHTML=t,this.fromHTMLElement(e)},t.fromHTMLElement=function(t){var r,n,o,i;return o=t.querySelector("head"),r=null!=(i=t.querySelector("body"))?i:document.createElement("body"),n=e.HeadDetails.fromHeadElement(o),new this(n,r)},t.prototype.clone=function(){return new this.constructor(this.headDetails,this.bodyElement.cloneNode(!0))},t.prototype.getRootLocation=function(){var t,r;return r=null!=(t=this.getSetting("root"))?t:"/",new e.Location(r)},t.prototype.getCacheControlValue=function(){return this.getSetting("cache-control")},t.prototype.getElementForAnchor=function(t){try{return this.bodyElement.querySelector("[id='"+t+"'], a[name='"+t+"']")}catch(e){}},t.prototype.getPermanentElements=function(){return this.bodyElement.querySelectorAll("[id][data-turbolinks-permanent]")},t.prototype.getPermanentElementById=function(t){return this.bodyElement.querySelector("#"+t+"[data-turbolinks-permanent]")},t.prototype.getPermanentElementsPresentInSnapshot=function(t){var e,r,n,o,i;for(o=this.getPermanentElements(),i=[],r=0,n=o.length;n>r;r++)e=o[r],t.getPermanentElementById(e.id)&&i.push(e);return i},t.prototype.findFirstAutofocusableElement=function(){return this.bodyElement.querySelector("[autofocus]")},t.prototype.hasAnchor=function(t){return null!=this.getElementForAnchor(t)},t.prototype.isPreviewable=function(){return"no-preview"!==this.getCacheControlValue()},t.prototype.isCacheable=function(){return"no-cache"!==this.getCacheControlValue()},t.prototype.isVisitable=function(){return"reload"!==this.getSetting("visit-control")},t.prototype.getSetting=function(t){return this.headDetails.getMetaValue("turbolinks-"+t)},t}()}.call(this),function(){var t=[].slice;e.Renderer=function(){function e(){}var r;return e.render=function(){var e,r,n,o;return n=arguments[0],r=arguments[1],e=3<=arguments.length?t.call(arguments,2):[],o=function(t,e,r){r.prototype=t.prototype;var n=new r,o=t.apply(n,e);return Object(o)===o?o:n}(this,e,function(){}),o.delegate=n,o.render(r),o},e.prototype.renderView=function(t){return this.delegate.viewWillRender(this.newBody),t(),this.delegate.viewRendered(this.newBody)},e.prototype.invalidateView=function(){return this.delegate.viewInvalidated()},e.prototype.createScriptElement=function(t){var e;return"false"===t.getAttribute("data-turbolinks-eval")?t:(e=document.createElement("script"),e.textContent=t.textContent,e.async=!1,r(e,t),e)},r=function(t,e){var r,n,o,i,s,a,u;for(i=e.attributes,a=[],r=0,n=i.length;n>r;r++)s=i[r],o=s.name,u=s.value,a.push(t.setAttribute(o,u));return a},e}()}.call(this),function(){var t,r,n=function(t,e){function r(){this.constructor=t}for(var n in e)o.call(e,n)&&(t[n]=e[n]);return r.prototype=e.prototype,t.prototype=new r,t.__super__=e.prototype,t},o={}.hasOwnProperty;e.SnapshotRenderer=function(e){function o(t,e,r){this.currentSnapshot=t,this.newSnapshot=e,this.isPreview=r,this.currentHeadDetails=this.currentSnapshot.headDetails,this.newHeadDetails=this.newSnapshot.headDetails,this.currentBody=this.currentSnapshot.bodyElement,this.newBody=this.newSnapshot.bodyElement}return n(o,e),o.prototype.render=function(t){return this.shouldRender()?(this.mergeHead(),this.renderView(function(e){return function(){return e.replaceBody(),e.isPreview||e.focusFirstAutofocusableElement(),t()}}(this))):this.invalidateView()},o.prototype.mergeHead=function(){return this.copyNewHeadStylesheetElements(),this.copyNewHeadScriptElements(),this.removeCurrentHeadProvisionalElements(),this.copyNewHeadProvisionalElements()},o.prototype.replaceBody=function(){var t;return t=this.relocateCurrentBodyPermanentElements(),this.activateNewBodyScriptElements(),this.assignNewBody(),this.replacePlaceholderElementsWithClonedPermanentElements(t)},o.prototype.shouldRender=function(){return this.newSnapshot.isVisitable()&&this.trackedElementsAreIdentical()},o.prototype.trackedElementsAreIdentical=function(){return this.currentHeadDetails.getTrackedElementSignature()===this.newHeadDetails.getTrackedElementSignature()},o.prototype.copyNewHeadStylesheetElements=function(){var t,e,r,n,o;for(n=this.getNewHeadStylesheetElements(),o=[],e=0,r=n.length;r>e;e++)t=n[e],o.push(document.head.appendChild(t));return o},o.prototype.copyNewHeadScriptElements=function(){var t,e,r,n,o;for(n=this.getNewHeadScriptElements(),o=[],e=0,r=n.length;r>e;e++)t=n[e],o.push(document.head.appendChild(this.createScriptElement(t)));return o},o.prototype.removeCurrentHeadProvisionalElements=function(){var t,e,r,n,o;for(n=this.getCurrentHeadProvisionalElements(),o=[],e=0,r=n.length;r>e;e++)t=n[e],o.push(document.head.removeChild(t));return o},o.prototype.copyNewHeadProvisionalElements=function(){var t,e,r,n,o;for(n=this.getNewHeadProvisionalElements(),o=[],e=0,r=n.length;r>e;e++)t=n[e],o.push(document.head.appendChild(t));return o},o.prototype.relocateCurrentBodyPermanentElements=function(){var e,n,o,i,s,a,u;for(a=this.getCurrentBodyPermanentElements(),u=[],e=0,n=a.length;n>e;e++)i=a[e],s=t(i),o=this.newSnapshot.getPermanentElementById(i.id),r(i,s.element),r(o,i),u.push(s);return u},o.prototype.replacePlaceholderElementsWithClonedPermanentElements=function(t){var e,n,o,i,s,a,u;for(u=[],o=0,i=t.length;i>o;o++)a=t[o],n=a.element,s=a.permanentElement,e=s.cloneNode(!0),u.push(r(n,e));return u},o.prototype.activateNewBodyScriptElements=function(){var t,e,n,o,i,s;for(i=this.getNewBodyScriptElements(),s=[],e=0,o=i.length;o>e;e++)n=i[e],t=this.createScriptElement(n),s.push(r(n,t));return s},o.prototype.assignNewBody=function(){return document.body=this.newBody},o.prototype.focusFirstAutofocusableElement=function(){var t;return null!=(t=this.newSnapshot.findFirstAutofocusableElement())?t.focus():void 0},o.prototype.getNewHeadStylesheetElements=function(){return this.newHeadDetails.getStylesheetElementsNotInDetails(this.currentHeadDetails)},o.prototype.getNewHeadScriptElements=function(){return this.newHeadDetails.getScriptElementsNotInDetails(this.currentHeadDetails)},o.prototype.getCurrentHeadProvisionalElements=function(){return this.currentHeadDetails.getProvisionalElements()},o.prototype.getNewHeadProvisionalElements=function(){return this.newHeadDetails.getProvisionalElements()},o.prototype.getCurrentBodyPermanentElements=function(){return this.currentSnapshot.getPermanentElementsPresentInSnapshot(this.newSnapshot)},o.prototype.getNewBodyScriptElements=function(){return this.newBody.querySelectorAll("script")},o}(e.Renderer),t=function(t){var e;return e=document.createElement("meta"),e.setAttribute("name","turbolinks-permanent-placeholder"),e.setAttribute("content",t.id),{element:e,permanentElement:t}},r=function(t,e){var r;return(r=t.parentNode)?r.replaceChild(e,t):void 0}}.call(this),function(){var t=function(t,e){function n(){this.constructor=t}for(var o in e)r.call(e,o)&&(t[o]=e[o]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t},r={}.hasOwnProperty;e.ErrorRenderer=function(e){function r(t){var e;e=document.createElement("html"),e.innerHTML=t,this.newHead=e.querySelector("head"),this.newBody=e.querySelector("body")}return t(r,e),r.prototype.render=function(t){return this.renderView(function(e){return function(){return e.replaceHeadAndBody(),e.activateBodyScriptElements(),t()}}(this))},r.prototype.replaceHeadAndBody=function(){var t,e;return e=document.head,t=document.body,e.parentNode.replaceChild(this.newHead,e),t.parentNode.replaceChild(this.newBody,t)},r.prototype.activateBodyScriptElements=function(){var t,e,r,n,o,i;for(n=this.getScriptElements(),i=[],e=0,r=n.length;r>e;e++)o=n[e],t=this.createScriptElement(o),i.push(o.parentNode.replaceChild(t,o));return i},r.prototype.getScriptElements=function(){return document.documentElement.querySelectorAll("script")},r}(e.Renderer)}.call(this),function(){e.View=function(){function t(t){this.delegate=t,this.htmlElement=document.documentElement}return t.prototype.getRootLocation=function(){return this.getSnapshot().getRootLocation()},t.prototype.getElementForAnchor=function(t){return this.getSnapshot().getElementForAnchor(t)},t.prototype.getSnapshot=function(){return e.Snapshot.fromHTMLElement(this.htmlElement)},t.prototype.render=function(t,e){var r,n,o;return o=t.snapshot,r=t.error,n=t.isPreview,this.markAsPreview(n),null!=o?this.renderSnapshot(o,n,e):this.renderError(r,e)},t.prototype.markAsPreview=function(t){return t?this.htmlElement.setAttribute("data-turbolinks-preview",""):this.htmlElement.removeAttribute("data-turbolinks-preview")},t.prototype.renderSnapshot=function(t,r,n){return e.SnapshotRenderer.render(this.delegate,n,this.getSnapshot(),e.Snapshot.wrap(t),r)},t.prototype.renderError=function(t,r){return e.ErrorRenderer.render(this.delegate,r,t)},t}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.ScrollManager=function(){function r(r){this.delegate=r,this.onScroll=t(this.onScroll,this),this.onScroll=e.throttle(this.onScroll)}return r.prototype.start=function(){return this.started?void 0:(addEventListener("scroll",this.onScroll,!1),this.onScroll(),this.started=!0)},r.prototype.stop=function(){return this.started?(removeEventListener("scroll",this.onScroll,!1),this.started=!1):void 0},r.prototype.scrollToElement=function(t){return t.scrollIntoView()},r.prototype.scrollToPosition=function(t){var e,r;return e=t.x,r=t.y,window.scrollTo(e,r)},r.prototype.onScroll=function(t){return this.updatePosition({x:window.pageXOffset,y:window.pageYOffset})},r.prototype.updatePosition=function(t){var e;return this.position=t,null!=(e=this.delegate)?e.scrollPositionChanged(this.position):void 0},r}()}.call(this),function(){e.SnapshotCache=function(){function t(t){this.size=t,this.keys=[],this.snapshots={}}var r;return t.prototype.has=function(t){var e;return e=r(t),e in this.snapshots},t.prototype.get=function(t){var e;if(this.has(t))return e=this.read(t),this.touch(t),e},t.prototype.put=function(t,e){return this.write(t,e),this.touch(t),e},t.prototype.read=function(t){var e;return e=r(t),this.snapshots[e]},t.prototype.write=function(t,e){var n;return n=r(t),this.snapshots[n]=e},t.prototype.touch=function(t){var e,n;return n=r(t),e=this.keys.indexOf(n),e>-1&&this.keys.splice(e,1),this.keys.unshift(n),this.trim()},t.prototype.trim=function(){var t,e,r,n,o;for(n=this.keys.splice(this.size),o=[],t=0,r=n.length;r>t;t++)e=n[t],o.push(delete this.snapshots[e]);return o},r=function(t){return e.Location.wrap(t).toCacheKey()},t}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.Visit=function(){function r(r,n,o){this.controller=r,this.action=o,this.performScroll=t(this.performScroll,this),this.identifier=e.uuid(),this.location=e.Location.wrap(n),this.adapter=this.controller.adapter,this.state="initialized",this.timingMetrics={}}var n;return r.prototype.start=function(){return"initialized"===this.state?(this.recordTimingMetric("visitStart"),this.state="started",this.adapter.visitStarted(this)):void 0},r.prototype.cancel=function(){var t;return"started"===this.state?(null!=(t=this.request)&&t.cancel(),this.cancelRender(),this.state="canceled"):void 0},r.prototype.complete=function(){var t;return"started"===this.state?(this.recordTimingMetric("visitEnd"),this.state="completed","function"==typeof(t=this.adapter).visitCompleted&&t.visitCompleted(this),this.controller.visitCompleted(this)):void 0},r.prototype.fail=function(){var t;return"started"===this.state?(this.state="failed","function"==typeof(t=this.adapter).visitFailed?t.visitFailed(this):void 0):void 0},r.prototype.changeHistory=function(){var t,e;return this.historyChanged?void 0:(t=this.location.isEqualTo(this.referrer)?"replace":this.action,e=n(t),this.controller[e](this.location,this.restorationIdentifier),this.historyChanged=!0)},r.prototype.issueRequest=function(){return this.shouldIssueRequest()&&null==this.request?(this.progress=0,this.request=new e.HttpRequest(this,this.location,this.referrer),this.request.send()):void 0},r.prototype.getCachedSnapshot=function(){var t;return!(t=this.controller.getCachedSnapshotForLocation(this.location))||null!=this.location.anchor&&!t.hasAnchor(this.location.anchor)||"restore"!==this.action&&!t.isPreviewable()?void 0:t},r.prototype.hasCachedSnapshot=function(){return null!=this.getCachedSnapshot()},r.prototype.loadCachedSnapshot=function(){var t,e;return(e=this.getCachedSnapshot())?(t=this.shouldIssueRequest(),this.render(function(){var r;return this.cacheSnapshot(),this.controller.render({snapshot:e,isPreview:t},this.performScroll),"function"==typeof(r=this.adapter).visitRendered&&r.visitRendered(this),t?void 0:this.complete()})):void 0},r.prototype.loadResponse=function(){return null!=this.response?this.render(function(){var t,e;return this.cacheSnapshot(),this.request.failed?(this.controller.render({error:this.response},this.performScroll),"function"==typeof(t=this.adapter).visitRendered&&t.visitRendered(this),this.fail()):(this.controller.render({snapshot:this.response},this.performScroll),"function"==typeof(e=this.adapter).visitRendered&&e.visitRendered(this),this.complete())}):void 0},r.prototype.followRedirect=function(){return this.redirectedToLocation&&!this.followedRedirect?(this.location=this.redirectedToLocation,this.controller.replaceHistoryWithLocationAndRestorationIdentifier(this.redirectedToLocation,this.restorationIdentifier),this.followedRedirect=!0):void 0},r.prototype.requestStarted=function(){var t;return this.recordTimingMetric("requestStart"),"function"==typeof(t=this.adapter).visitRequestStarted?t.visitRequestStarted(this):void 0},r.prototype.requestProgressed=function(t){var e;return this.progress=t,"function"==typeof(e=this.adapter).visitRequestProgressed?e.visitRequestProgressed(this):void 0},r.prototype.requestCompletedWithResponse=function(t,r){return this.response=t,null!=r&&(this.redirectedToLocation=e.Location.wrap(r)),this.adapter.visitRequestCompleted(this)},r.prototype.requestFailedWithStatusCode=function(t,e){return this.response=e,this.adapter.visitRequestFailedWithStatusCode(this,t)},r.prototype.requestFinished=function(){var t;return this.recordTimingMetric("requestEnd"),"function"==typeof(t=this.adapter).visitRequestFinished?t.visitRequestFinished(this):void 0},r.prototype.performScroll=function(){return this.scrolled?void 0:("restore"===this.action?this.scrollToRestoredPosition()||this.scrollToTop():this.scrollToAnchor()||this.scrollToTop(),this.scrolled=!0)},r.prototype.scrollToRestoredPosition=function(){var t,e;return t=null!=(e=this.restorationData)?e.scrollPosition:void 0,null!=t?(this.controller.scrollToPosition(t),!0):void 0},r.prototype.scrollToAnchor=function(){return null!=this.location.anchor?(this.controller.scrollToAnchor(this.location.anchor),!0):void 0},r.prototype.scrollToTop=function(){return this.controller.scrollToPosition({x:0,y:0})},r.prototype.recordTimingMetric=function(t){var e;return null!=(e=this.timingMetrics)[t]?e[t]:e[t]=(new Date).getTime()},r.prototype.getTimingMetrics=function(){return e.copyObject(this.timingMetrics)},n=function(t){switch(t){case"replace":return"replaceHistoryWithLocationAndRestorationIdentifier";case"advance":case"restore":return"pushHistoryWithLocationAndRestorationIdentifier"}},r.prototype.shouldIssueRequest=function(){return"restore"===this.action?!this.hasCachedSnapshot():!0},r.prototype.cacheSnapshot=function(){return this.snapshotCached?void 0:(this.controller.cacheSnapshot(),this.snapshotCached=!0)},r.prototype.render=function(t){return this.cancelRender(),this.frame=requestAnimationFrame(function(e){return function(){return e.frame=null,t.call(e)}}(this))},r.prototype.cancelRender=function(){return this.frame?cancelAnimationFrame(this.frame):void 0},r}()}.call(this),function(){var t=function(t,e){return function(){return t.apply(e,arguments)}};e.Controller=function(){function r(){this.clickBubbled=t(this.clickBubbled,this),this.clickCaptured=t(this.clickCaptured,this),this.pageLoaded=t(this.pageLoaded,this),this.history=new e.History(this),this.view=new e.View(this),this.scrollManager=new e.ScrollManager(this),this.restorationData={},this.clearCache(),this.setProgressBarDelay(500)}return r.prototype.start=function(){return e.supported&&!this.started?(addEventListener("click",this.clickCaptured,!0),addEventListener("DOMContentLoaded",this.pageLoaded,!1),this.scrollManager.start(),this.startHistory(),this.started=!0,this.enabled=!0):void 0},r.prototype.disable=function(){return this.enabled=!1},r.prototype.stop=function(){return this.started?(removeEventListener("click",this.clickCaptured,!0),removeEventListener("DOMContentLoaded",this.pageLoaded,!1),this.scrollManager.stop(),this.stopHistory(),this.started=!1):void 0},r.prototype.clearCache=function(){return this.cache=new e.SnapshotCache(10)},r.prototype.visit=function(t,r){var n,o;return null==r&&(r={}),t=e.Location.wrap(t),this.applicationAllowsVisitingLocation(t)?this.locationIsVisitable(t)?(n=null!=(o=r.action)?o:"advance",this.adapter.visitProposedToLocationWithAction(t,n)):window.location=t:void 0},r.prototype.startVisitToLocationWithAction=function(t,r,n){var o;return e.supported?(o=this.getRestorationDataForIdentifier(n),this.startVisit(t,r,{restorationData:o})):window.location=t},r.prototype.setProgressBarDelay=function(t){return this.progressBarDelay=t},r.prototype.startHistory=function(){return this.location=e.Location.wrap(window.location),this.restorationIdentifier=e.uuid(),this.history.start(),this.history.replace(this.location,this.restorationIdentifier)},r.prototype.stopHistory=function(){return this.history.stop()},r.prototype.pushHistoryWithLocationAndRestorationIdentifier=function(t,r){return this.restorationIdentifier=r,this.location=e.Location.wrap(t),this.history.push(this.location,this.restorationIdentifier)},r.prototype.replaceHistoryWithLocationAndRestorationIdentifier=function(t,r){return this.restorationIdentifier=r,this.location=e.Location.wrap(t),this.history.replace(this.location,this.restorationIdentifier)},r.prototype.historyPoppedToLocationWithRestorationIdentifier=function(t,r){var n;return this.restorationIdentifier=r,this.enabled?(n=this.getRestorationDataForIdentifier(this.restorationIdentifier),this.startVisit(t,"restore",{restorationIdentifier:this.restorationIdentifier,restorationData:n,historyChanged:!0}),this.location=e.Location.wrap(t)):this.adapter.pageInvalidated()},r.prototype.getCachedSnapshotForLocation=function(t){var e;return null!=(e=this.cache.get(t))?e.clone():void 0},r.prototype.shouldCacheSnapshot=function(){return this.view.getSnapshot().isCacheable();
|
|
},r.prototype.cacheSnapshot=function(){var t,r;return this.shouldCacheSnapshot()?(this.notifyApplicationBeforeCachingSnapshot(),r=this.view.getSnapshot(),t=this.lastRenderedLocation,e.defer(function(e){return function(){return e.cache.put(t,r.clone())}}(this))):void 0},r.prototype.scrollToAnchor=function(t){var e;return(e=this.view.getElementForAnchor(t))?this.scrollToElement(e):this.scrollToPosition({x:0,y:0})},r.prototype.scrollToElement=function(t){return this.scrollManager.scrollToElement(t)},r.prototype.scrollToPosition=function(t){return this.scrollManager.scrollToPosition(t)},r.prototype.scrollPositionChanged=function(t){var e;return e=this.getCurrentRestorationData(),e.scrollPosition=t},r.prototype.render=function(t,e){return this.view.render(t,e)},r.prototype.viewInvalidated=function(){return this.adapter.pageInvalidated()},r.prototype.viewWillRender=function(t){return this.notifyApplicationBeforeRender(t)},r.prototype.viewRendered=function(){return this.lastRenderedLocation=this.currentVisit.location,this.notifyApplicationAfterRender()},r.prototype.pageLoaded=function(){return this.lastRenderedLocation=this.location,this.notifyApplicationAfterPageLoad()},r.prototype.clickCaptured=function(){return removeEventListener("click",this.clickBubbled,!1),addEventListener("click",this.clickBubbled,!1)},r.prototype.clickBubbled=function(t){var e,r,n;return this.enabled&&this.clickEventIsSignificant(t)&&(r=this.getVisitableLinkForNode(t.target))&&(n=this.getVisitableLocationForLink(r))&&this.applicationAllowsFollowingLinkToLocation(r,n)?(t.preventDefault(),e=this.getActionForLink(r),this.visit(n,{action:e})):void 0},r.prototype.applicationAllowsFollowingLinkToLocation=function(t,e){var r;return r=this.notifyApplicationAfterClickingLinkToLocation(t,e),!r.defaultPrevented},r.prototype.applicationAllowsVisitingLocation=function(t){var e;return e=this.notifyApplicationBeforeVisitingLocation(t),!e.defaultPrevented},r.prototype.notifyApplicationAfterClickingLinkToLocation=function(t,r){return e.dispatch("turbolinks:click",{target:t,data:{url:r.absoluteURL},cancelable:!0})},r.prototype.notifyApplicationBeforeVisitingLocation=function(t){return e.dispatch("turbolinks:before-visit",{data:{url:t.absoluteURL},cancelable:!0})},r.prototype.notifyApplicationAfterVisitingLocation=function(t){return e.dispatch("turbolinks:visit",{data:{url:t.absoluteURL}})},r.prototype.notifyApplicationBeforeCachingSnapshot=function(){return e.dispatch("turbolinks:before-cache")},r.prototype.notifyApplicationBeforeRender=function(t){return e.dispatch("turbolinks:before-render",{data:{newBody:t}})},r.prototype.notifyApplicationAfterRender=function(){return e.dispatch("turbolinks:render")},r.prototype.notifyApplicationAfterPageLoad=function(t){return null==t&&(t={}),e.dispatch("turbolinks:load",{data:{url:this.location.absoluteURL,timing:t}})},r.prototype.startVisit=function(t,e,r){var n;return null!=(n=this.currentVisit)&&n.cancel(),this.currentVisit=this.createVisit(t,e,r),this.currentVisit.start(),this.notifyApplicationAfterVisitingLocation(t)},r.prototype.createVisit=function(t,r,n){var o,i,s,a,u;return i=null!=n?n:{},a=i.restorationIdentifier,s=i.restorationData,o=i.historyChanged,u=new e.Visit(this,t,r),u.restorationIdentifier=null!=a?a:e.uuid(),u.restorationData=e.copyObject(s),u.historyChanged=o,u.referrer=this.location,u},r.prototype.visitCompleted=function(t){return this.notifyApplicationAfterPageLoad(t.getTimingMetrics())},r.prototype.clickEventIsSignificant=function(t){return!(t.defaultPrevented||t.target.isContentEditable||t.which>1||t.altKey||t.ctrlKey||t.metaKey||t.shiftKey)},r.prototype.getVisitableLinkForNode=function(t){return this.nodeIsVisitable(t)?e.closest(t,"a[href]:not([target]):not([download])"):void 0},r.prototype.getVisitableLocationForLink=function(t){var r;return r=new e.Location(t.getAttribute("href")),this.locationIsVisitable(r)?r:void 0},r.prototype.getActionForLink=function(t){var e;return null!=(e=t.getAttribute("data-turbolinks-action"))?e:"advance"},r.prototype.nodeIsVisitable=function(t){var r;return(r=e.closest(t,"[data-turbolinks]"))?"false"!==r.getAttribute("data-turbolinks"):!0},r.prototype.locationIsVisitable=function(t){return t.isPrefixedBy(this.view.getRootLocation())&&t.isHTML()},r.prototype.getCurrentRestorationData=function(){return this.getRestorationDataForIdentifier(this.restorationIdentifier)},r.prototype.getRestorationDataForIdentifier=function(t){var e;return null!=(e=this.restorationData)[t]?e[t]:e[t]={}},r}()}.call(this),function(){!function(){var t,e;if((t=e=document.currentScript)&&!e.hasAttribute("data-turbolinks-suppress-warning"))for(;t=t.parentNode;)if(t===document.body)return console.warn("You are loading Turbolinks from a <script> element inside the <body> element. This is probably not what you meant to do!\n\nLoad your application\u2019s JavaScript bundle inside the <head> element instead. <script> elements in <body> are evaluated with each page change.\n\nFor more information, see: https://github.com/turbolinks/turbolinks#working-with-script-elements\n\n\u2014\u2014\nSuppress this warning by adding a `data-turbolinks-suppress-warning` attribute to: %s",e.outerHTML)}()}.call(this),function(){var t,r,n;e.start=function(){return r()?(null==e.controller&&(e.controller=t()),e.controller.start()):void 0},r=function(){return null==window.Turbolinks&&(window.Turbolinks=e),n()},t=function(){var t;return t=new e.Controller,t.adapter=new e.BrowserAdapter(t),t},n=function(){return window.Turbolinks===e},n()&&e.start()}.call(this)}).call(this),"object"==typeof module&&module.exports?module.exports=e:"function"==typeof define&&define.amd&&define(e)}).call(this);
|
|
window.TinyMCERails = {
|
|
configuration: {
|
|
default: {}
|
|
},
|
|
|
|
initialize: function(config, options) {
|
|
if (typeof tinyMCE != 'undefined') {
|
|
// Merge the custom options with the given configuration
|
|
var configuration = TinyMCERails.configuration[config || 'default'];
|
|
configuration = TinyMCERails._merge(configuration, options);
|
|
|
|
tinyMCE.init(configuration);
|
|
} else {
|
|
// Wait until TinyMCE is loaded
|
|
setTimeout(function() {
|
|
TinyMCERails.initialize(config, options);
|
|
}, 50);
|
|
}
|
|
},
|
|
|
|
setupTurbolinks: function() {
|
|
// Remove all TinyMCE instances before rendering
|
|
document.addEventListener('turbolinks:before-render', function() {
|
|
tinymce.remove();
|
|
});
|
|
},
|
|
|
|
_merge: function() {
|
|
var result = {};
|
|
|
|
for (var i = 0; i < arguments.length; ++i) {
|
|
var source = arguments[i];
|
|
|
|
for (var key in source) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
if (Object.prototype.toString.call(source[key]) === '[object Object]') {
|
|
result[key] = TinyMCERails._merge(result[key], source[key]);
|
|
} else {
|
|
result[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
if (typeof Turbolinks != 'undefined' && Turbolinks.supported) {
|
|
TinyMCERails.setupTurbolinks();
|
|
};
|
|
window.tinymce = window.tinymce || {
|
|
base: '/assets/tinymce',
|
|
suffix: ''
|
|
};
|
|
/**
|
|
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
|
* Licensed under the LGPL or a commercial license.
|
|
* For LGPL see License.txt in the project root for license information.
|
|
* For commercial licenses see https://www.tiny.cloud/
|
|
*
|
|
* Version: 5.1.4 (2019-12-11)
|
|
*/
|
|
(function (domGlobals) {
|
|
'use strict';
|
|
|
|
var noop = function () {
|
|
};
|
|
var compose = function (fa, fb) {
|
|
return function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
return fa(fb.apply(null, args));
|
|
};
|
|
};
|
|
var constant = function (value) {
|
|
return function () {
|
|
return value;
|
|
};
|
|
};
|
|
var identity = function (x) {
|
|
return x;
|
|
};
|
|
function curry(fn) {
|
|
var initialArgs = [];
|
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
initialArgs[_i - 1] = arguments[_i];
|
|
}
|
|
return function () {
|
|
var restArgs = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
restArgs[_i] = arguments[_i];
|
|
}
|
|
var all = initialArgs.concat(restArgs);
|
|
return fn.apply(null, all);
|
|
};
|
|
}
|
|
var not = function (f) {
|
|
return function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
return !f.apply(null, args);
|
|
};
|
|
};
|
|
var die = function (msg) {
|
|
return function () {
|
|
throw new Error(msg);
|
|
};
|
|
};
|
|
var never = constant(false);
|
|
var always = constant(true);
|
|
|
|
var none = function () {
|
|
return NONE;
|
|
};
|
|
var NONE = function () {
|
|
var eq = function (o) {
|
|
return o.isNone();
|
|
};
|
|
var call = function (thunk) {
|
|
return thunk();
|
|
};
|
|
var id = function (n) {
|
|
return n;
|
|
};
|
|
var me = {
|
|
fold: function (n, s) {
|
|
return n();
|
|
},
|
|
is: never,
|
|
isSome: never,
|
|
isNone: always,
|
|
getOr: id,
|
|
getOrThunk: call,
|
|
getOrDie: function (msg) {
|
|
throw new Error(msg || 'error: getOrDie called on none.');
|
|
},
|
|
getOrNull: constant(null),
|
|
getOrUndefined: constant(undefined),
|
|
or: id,
|
|
orThunk: call,
|
|
map: none,
|
|
each: noop,
|
|
bind: none,
|
|
exists: never,
|
|
forall: always,
|
|
filter: none,
|
|
equals: eq,
|
|
equals_: eq,
|
|
toArray: function () {
|
|
return [];
|
|
},
|
|
toString: constant('none()')
|
|
};
|
|
if (Object.freeze) {
|
|
Object.freeze(me);
|
|
}
|
|
return me;
|
|
}();
|
|
var some = function (a) {
|
|
var constant_a = constant(a);
|
|
var self = function () {
|
|
return me;
|
|
};
|
|
var bind = function (f) {
|
|
return f(a);
|
|
};
|
|
var me = {
|
|
fold: function (n, s) {
|
|
return s(a);
|
|
},
|
|
is: function (v) {
|
|
return a === v;
|
|
},
|
|
isSome: always,
|
|
isNone: never,
|
|
getOr: constant_a,
|
|
getOrThunk: constant_a,
|
|
getOrDie: constant_a,
|
|
getOrNull: constant_a,
|
|
getOrUndefined: constant_a,
|
|
or: self,
|
|
orThunk: self,
|
|
map: function (f) {
|
|
return some(f(a));
|
|
},
|
|
each: function (f) {
|
|
f(a);
|
|
},
|
|
bind: bind,
|
|
exists: bind,
|
|
forall: bind,
|
|
filter: function (f) {
|
|
return f(a) ? me : NONE;
|
|
},
|
|
toArray: function () {
|
|
return [a];
|
|
},
|
|
toString: function () {
|
|
return 'some(' + a + ')';
|
|
},
|
|
equals: function (o) {
|
|
return o.is(a);
|
|
},
|
|
equals_: function (o, elementEq) {
|
|
return o.fold(never, function (b) {
|
|
return elementEq(a, b);
|
|
});
|
|
}
|
|
};
|
|
return me;
|
|
};
|
|
var from = function (value) {
|
|
return value === null || value === undefined ? NONE : some(value);
|
|
};
|
|
var Option = {
|
|
some: some,
|
|
none: none,
|
|
from: from
|
|
};
|
|
|
|
var typeOf = function (x) {
|
|
if (x === null) {
|
|
return 'null';
|
|
}
|
|
var t = typeof x;
|
|
if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
|
|
return 'array';
|
|
}
|
|
if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
|
|
return 'string';
|
|
}
|
|
return t;
|
|
};
|
|
var isType = function (type) {
|
|
return function (value) {
|
|
return typeOf(value) === type;
|
|
};
|
|
};
|
|
var isString = isType('string');
|
|
var isObject = isType('object');
|
|
var isArray = isType('array');
|
|
var isNull = isType('null');
|
|
var isBoolean = isType('boolean');
|
|
var isFunction = isType('function');
|
|
var isNumber = isType('number');
|
|
|
|
var nativeSlice = Array.prototype.slice;
|
|
var nativeIndexOf = Array.prototype.indexOf;
|
|
var nativePush = Array.prototype.push;
|
|
var rawIndexOf = function (ts, t) {
|
|
return nativeIndexOf.call(ts, t);
|
|
};
|
|
var indexOf = function (xs, x) {
|
|
var r = rawIndexOf(xs, x);
|
|
return r === -1 ? Option.none() : Option.some(r);
|
|
};
|
|
var contains = function (xs, x) {
|
|
return rawIndexOf(xs, x) > -1;
|
|
};
|
|
var exists = function (xs, pred) {
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
if (pred(x, i)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var map = function (xs, f) {
|
|
var len = xs.length;
|
|
var r = new Array(len);
|
|
for (var i = 0; i < len; i++) {
|
|
var x = xs[i];
|
|
r[i] = f(x, i);
|
|
}
|
|
return r;
|
|
};
|
|
var each = function (xs, f) {
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
f(x, i);
|
|
}
|
|
};
|
|
var eachr = function (xs, f) {
|
|
for (var i = xs.length - 1; i >= 0; i--) {
|
|
var x = xs[i];
|
|
f(x, i);
|
|
}
|
|
};
|
|
var partition = function (xs, pred) {
|
|
var pass = [];
|
|
var fail = [];
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
var arr = pred(x, i) ? pass : fail;
|
|
arr.push(x);
|
|
}
|
|
return {
|
|
pass: pass,
|
|
fail: fail
|
|
};
|
|
};
|
|
var filter = function (xs, pred) {
|
|
var r = [];
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
if (pred(x, i)) {
|
|
r.push(x);
|
|
}
|
|
}
|
|
return r;
|
|
};
|
|
var foldr = function (xs, f, acc) {
|
|
eachr(xs, function (x) {
|
|
acc = f(acc, x);
|
|
});
|
|
return acc;
|
|
};
|
|
var foldl = function (xs, f, acc) {
|
|
each(xs, function (x) {
|
|
acc = f(acc, x);
|
|
});
|
|
return acc;
|
|
};
|
|
var find = function (xs, pred) {
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
if (pred(x, i)) {
|
|
return Option.some(x);
|
|
}
|
|
}
|
|
return Option.none();
|
|
};
|
|
var findIndex = function (xs, pred) {
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
if (pred(x, i)) {
|
|
return Option.some(i);
|
|
}
|
|
}
|
|
return Option.none();
|
|
};
|
|
var flatten = function (xs) {
|
|
var r = [];
|
|
for (var i = 0, len = xs.length; i < len; ++i) {
|
|
if (!isArray(xs[i])) {
|
|
throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
|
|
}
|
|
nativePush.apply(r, xs[i]);
|
|
}
|
|
return r;
|
|
};
|
|
var bind = function (xs, f) {
|
|
var output = map(xs, f);
|
|
return flatten(output);
|
|
};
|
|
var forall = function (xs, pred) {
|
|
for (var i = 0, len = xs.length; i < len; ++i) {
|
|
var x = xs[i];
|
|
if (pred(x, i) !== true) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
var reverse = function (xs) {
|
|
var r = nativeSlice.call(xs, 0);
|
|
r.reverse();
|
|
return r;
|
|
};
|
|
var difference = function (a1, a2) {
|
|
return filter(a1, function (x) {
|
|
return !contains(a2, x);
|
|
});
|
|
};
|
|
var mapToObject = function (xs, f) {
|
|
var r = {};
|
|
for (var i = 0, len = xs.length; i < len; i++) {
|
|
var x = xs[i];
|
|
r[String(x)] = f(x, i);
|
|
}
|
|
return r;
|
|
};
|
|
var sort = function (xs, comparator) {
|
|
var copy = nativeSlice.call(xs, 0);
|
|
copy.sort(comparator);
|
|
return copy;
|
|
};
|
|
var head = function (xs) {
|
|
return xs.length === 0 ? Option.none() : Option.some(xs[0]);
|
|
};
|
|
var last = function (xs) {
|
|
return xs.length === 0 ? Option.none() : Option.some(xs[xs.length - 1]);
|
|
};
|
|
var from$1 = isFunction(Array.from) ? Array.from : function (x) {
|
|
return nativeSlice.call(x);
|
|
};
|
|
|
|
var __assign = function () {
|
|
__assign = Object.assign || function __assign(t) {
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
s = arguments[i];
|
|
for (var p in s)
|
|
if (Object.prototype.hasOwnProperty.call(s, p))
|
|
t[p] = s[p];
|
|
}
|
|
return t;
|
|
};
|
|
return __assign.apply(this, arguments);
|
|
};
|
|
function __rest(s, e) {
|
|
var t = {};
|
|
for (var p in s)
|
|
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
t[p] = s[p];
|
|
if (s != null && typeof Object.getOwnPropertySymbols === 'function')
|
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
t[p[i]] = s[p[i]];
|
|
}
|
|
return t;
|
|
}
|
|
|
|
var isNodeType = function (type) {
|
|
return function (node) {
|
|
return !!node && node.nodeType === type;
|
|
};
|
|
};
|
|
var isRestrictedNode = function (node) {
|
|
return !!node && !Object.getPrototypeOf(node);
|
|
};
|
|
var isElement = isNodeType(1);
|
|
var matchNodeNames = function (names) {
|
|
var lowercasedNames = names.map(function (s) {
|
|
return s.toLowerCase();
|
|
});
|
|
return function (node) {
|
|
if (node && node.nodeName) {
|
|
var nodeName = node.nodeName.toLowerCase();
|
|
return contains(lowercasedNames, nodeName);
|
|
}
|
|
return false;
|
|
};
|
|
};
|
|
var matchStyleValues = function (name, values) {
|
|
var items = values.toLowerCase().split(' ');
|
|
return function (node) {
|
|
var i, cssValue;
|
|
if (isElement(node)) {
|
|
for (i = 0; i < items.length; i++) {
|
|
var computed = node.ownerDocument.defaultView.getComputedStyle(node, null);
|
|
cssValue = computed ? computed.getPropertyValue(name) : null;
|
|
if (cssValue === items[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
};
|
|
var hasPropValue = function (propName, propValue) {
|
|
return function (node) {
|
|
return isElement(node) && node[propName] === propValue;
|
|
};
|
|
};
|
|
var hasAttribute = function (attrName, attrValue) {
|
|
return function (node) {
|
|
return isElement(node) && node.hasAttribute(attrName);
|
|
};
|
|
};
|
|
var hasAttributeValue = function (attrName, attrValue) {
|
|
return function (node) {
|
|
return isElement(node) && node.getAttribute(attrName) === attrValue;
|
|
};
|
|
};
|
|
var isBogus = function (node) {
|
|
return isElement(node) && node.hasAttribute('data-mce-bogus');
|
|
};
|
|
var isBogusAll = function (node) {
|
|
return isElement(node) && node.getAttribute('data-mce-bogus') === 'all';
|
|
};
|
|
var isTable = function (node) {
|
|
return isElement(node) && node.tagName === 'TABLE';
|
|
};
|
|
var hasContentEditableState = function (value) {
|
|
return function (node) {
|
|
if (isElement(node)) {
|
|
if (node.contentEditable === value) {
|
|
return true;
|
|
}
|
|
if (node.getAttribute('data-mce-contenteditable') === value) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
};
|
|
var isTextareaOrInput = matchNodeNames([
|
|
'textarea',
|
|
'input'
|
|
]);
|
|
var isText = isNodeType(3);
|
|
var isComment = isNodeType(8);
|
|
var isDocument = isNodeType(9);
|
|
var isDocumentFragment = isNodeType(11);
|
|
var isBr = matchNodeNames(['br']);
|
|
var isContentEditableTrue = hasContentEditableState('true');
|
|
var isContentEditableFalse = hasContentEditableState('false');
|
|
var NodeType = {
|
|
isText: isText,
|
|
isElement: isElement,
|
|
isComment: isComment,
|
|
isDocument: isDocument,
|
|
isDocumentFragment: isDocumentFragment,
|
|
isBr: isBr,
|
|
isContentEditableTrue: isContentEditableTrue,
|
|
isContentEditableFalse: isContentEditableFalse,
|
|
isRestrictedNode: isRestrictedNode,
|
|
matchNodeNames: matchNodeNames,
|
|
hasPropValue: hasPropValue,
|
|
hasAttribute: hasAttribute,
|
|
hasAttributeValue: hasAttributeValue,
|
|
matchStyleValues: matchStyleValues,
|
|
isBogus: isBogus,
|
|
isBogusAll: isBogusAll,
|
|
isTable: isTable,
|
|
isTextareaOrInput: isTextareaOrInput
|
|
};
|
|
|
|
var Cell = function (initial) {
|
|
var value = initial;
|
|
var get = function () {
|
|
return value;
|
|
};
|
|
var set = function (v) {
|
|
value = v;
|
|
};
|
|
var clone = function () {
|
|
return Cell(get());
|
|
};
|
|
return {
|
|
get: get,
|
|
set: set,
|
|
clone: clone
|
|
};
|
|
};
|
|
|
|
var firstMatch = function (regexes, s) {
|
|
for (var i = 0; i < regexes.length; i++) {
|
|
var x = regexes[i];
|
|
if (x.test(s)) {
|
|
return x;
|
|
}
|
|
}
|
|
return undefined;
|
|
};
|
|
var find$1 = function (regexes, agent) {
|
|
var r = firstMatch(regexes, agent);
|
|
if (!r) {
|
|
return {
|
|
major: 0,
|
|
minor: 0
|
|
};
|
|
}
|
|
var group = function (i) {
|
|
return Number(agent.replace(r, '$' + i));
|
|
};
|
|
return nu(group(1), group(2));
|
|
};
|
|
var detect = function (versionRegexes, agent) {
|
|
var cleanedAgent = String(agent).toLowerCase();
|
|
if (versionRegexes.length === 0) {
|
|
return unknown();
|
|
}
|
|
return find$1(versionRegexes, cleanedAgent);
|
|
};
|
|
var unknown = function () {
|
|
return nu(0, 0);
|
|
};
|
|
var nu = function (major, minor) {
|
|
return {
|
|
major: major,
|
|
minor: minor
|
|
};
|
|
};
|
|
var Version = {
|
|
nu: nu,
|
|
detect: detect,
|
|
unknown: unknown
|
|
};
|
|
|
|
var edge = 'Edge';
|
|
var chrome = 'Chrome';
|
|
var ie = 'IE';
|
|
var opera = 'Opera';
|
|
var firefox = 'Firefox';
|
|
var safari = 'Safari';
|
|
var isBrowser = function (name, current) {
|
|
return function () {
|
|
return current === name;
|
|
};
|
|
};
|
|
var unknown$1 = function () {
|
|
return nu$1({
|
|
current: undefined,
|
|
version: Version.unknown()
|
|
});
|
|
};
|
|
var nu$1 = function (info) {
|
|
var current = info.current;
|
|
var version = info.version;
|
|
return {
|
|
current: current,
|
|
version: version,
|
|
isEdge: isBrowser(edge, current),
|
|
isChrome: isBrowser(chrome, current),
|
|
isIE: isBrowser(ie, current),
|
|
isOpera: isBrowser(opera, current),
|
|
isFirefox: isBrowser(firefox, current),
|
|
isSafari: isBrowser(safari, current)
|
|
};
|
|
};
|
|
var Browser = {
|
|
unknown: unknown$1,
|
|
nu: nu$1,
|
|
edge: constant(edge),
|
|
chrome: constant(chrome),
|
|
ie: constant(ie),
|
|
opera: constant(opera),
|
|
firefox: constant(firefox),
|
|
safari: constant(safari)
|
|
};
|
|
|
|
var windows = 'Windows';
|
|
var ios = 'iOS';
|
|
var android = 'Android';
|
|
var linux = 'Linux';
|
|
var osx = 'OSX';
|
|
var solaris = 'Solaris';
|
|
var freebsd = 'FreeBSD';
|
|
var isOS = function (name, current) {
|
|
return function () {
|
|
return current === name;
|
|
};
|
|
};
|
|
var unknown$2 = function () {
|
|
return nu$2({
|
|
current: undefined,
|
|
version: Version.unknown()
|
|
});
|
|
};
|
|
var nu$2 = function (info) {
|
|
var current = info.current;
|
|
var version = info.version;
|
|
return {
|
|
current: current,
|
|
version: version,
|
|
isWindows: isOS(windows, current),
|
|
isiOS: isOS(ios, current),
|
|
isAndroid: isOS(android, current),
|
|
isOSX: isOS(osx, current),
|
|
isLinux: isOS(linux, current),
|
|
isSolaris: isOS(solaris, current),
|
|
isFreeBSD: isOS(freebsd, current)
|
|
};
|
|
};
|
|
var OperatingSystem = {
|
|
unknown: unknown$2,
|
|
nu: nu$2,
|
|
windows: constant(windows),
|
|
ios: constant(ios),
|
|
android: constant(android),
|
|
linux: constant(linux),
|
|
osx: constant(osx),
|
|
solaris: constant(solaris),
|
|
freebsd: constant(freebsd)
|
|
};
|
|
|
|
var DeviceType = function (os, browser, userAgent, mediaMatch) {
|
|
var isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
|
|
var isiPhone = os.isiOS() && !isiPad;
|
|
var isMobile = os.isiOS() || os.isAndroid();
|
|
var isTouch = isMobile || mediaMatch('(pointer:coarse)');
|
|
var isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
|
|
var isPhone = isiPhone || isMobile && !isTablet;
|
|
var iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
|
|
var isDesktop = !isPhone && !isTablet && !iOSwebview;
|
|
return {
|
|
isiPad: constant(isiPad),
|
|
isiPhone: constant(isiPhone),
|
|
isTablet: constant(isTablet),
|
|
isPhone: constant(isPhone),
|
|
isTouch: constant(isTouch),
|
|
isAndroid: os.isAndroid,
|
|
isiOS: os.isiOS,
|
|
isWebView: constant(iOSwebview),
|
|
isDesktop: constant(isDesktop)
|
|
};
|
|
};
|
|
|
|
var detect$1 = function (candidates, userAgent) {
|
|
var agent = String(userAgent).toLowerCase();
|
|
return find(candidates, function (candidate) {
|
|
return candidate.search(agent);
|
|
});
|
|
};
|
|
var detectBrowser = function (browsers, userAgent) {
|
|
return detect$1(browsers, userAgent).map(function (browser) {
|
|
var version = Version.detect(browser.versionRegexes, userAgent);
|
|
return {
|
|
current: browser.name,
|
|
version: version
|
|
};
|
|
});
|
|
};
|
|
var detectOs = function (oses, userAgent) {
|
|
return detect$1(oses, userAgent).map(function (os) {
|
|
var version = Version.detect(os.versionRegexes, userAgent);
|
|
return {
|
|
current: os.name,
|
|
version: version
|
|
};
|
|
});
|
|
};
|
|
var UaString = {
|
|
detectBrowser: detectBrowser,
|
|
detectOs: detectOs
|
|
};
|
|
|
|
var checkRange = function (str, substr, start) {
|
|
if (substr === '') {
|
|
return true;
|
|
}
|
|
if (str.length < substr.length) {
|
|
return false;
|
|
}
|
|
var x = str.substr(start, start + substr.length);
|
|
return x === substr;
|
|
};
|
|
var contains$1 = function (str, substr) {
|
|
return str.indexOf(substr) !== -1;
|
|
};
|
|
var startsWith = function (str, prefix) {
|
|
return checkRange(str, prefix, 0);
|
|
};
|
|
var trim = function (str) {
|
|
return str.replace(/^\s+|\s+$/g, '');
|
|
};
|
|
var lTrim = function (str) {
|
|
return str.replace(/^\s+/g, '');
|
|
};
|
|
var rTrim = function (str) {
|
|
return str.replace(/\s+$/g, '');
|
|
};
|
|
|
|
var normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
|
|
var checkContains = function (target) {
|
|
return function (uastring) {
|
|
return contains$1(uastring, target);
|
|
};
|
|
};
|
|
var browsers = [
|
|
{
|
|
name: 'Edge',
|
|
versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
|
|
search: function (uastring) {
|
|
return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
|
|
}
|
|
},
|
|
{
|
|
name: 'Chrome',
|
|
versionRegexes: [
|
|
/.*?chrome\/([0-9]+)\.([0-9]+).*/,
|
|
normalVersionRegex
|
|
],
|
|
search: function (uastring) {
|
|
return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
|
|
}
|
|
},
|
|
{
|
|
name: 'IE',
|
|
versionRegexes: [
|
|
/.*?msie\ ?([0-9]+)\.([0-9]+).*/,
|
|
/.*?rv:([0-9]+)\.([0-9]+).*/
|
|
],
|
|
search: function (uastring) {
|
|
return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
|
|
}
|
|
},
|
|
{
|
|
name: 'Opera',
|
|
versionRegexes: [
|
|
normalVersionRegex,
|
|
/.*?opera\/([0-9]+)\.([0-9]+).*/
|
|
],
|
|
search: checkContains('opera')
|
|
},
|
|
{
|
|
name: 'Firefox',
|
|
versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
|
|
search: checkContains('firefox')
|
|
},
|
|
{
|
|
name: 'Safari',
|
|
versionRegexes: [
|
|
normalVersionRegex,
|
|
/.*?cpu os ([0-9]+)_([0-9]+).*/
|
|
],
|
|
search: function (uastring) {
|
|
return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
|
|
}
|
|
}
|
|
];
|
|
var oses = [
|
|
{
|
|
name: 'Windows',
|
|
search: checkContains('win'),
|
|
versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
|
|
},
|
|
{
|
|
name: 'iOS',
|
|
search: function (uastring) {
|
|
return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
|
|
},
|
|
versionRegexes: [
|
|
/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
|
|
/.*cpu os ([0-9]+)_([0-9]+).*/,
|
|
/.*cpu iphone os ([0-9]+)_([0-9]+).*/
|
|
]
|
|
},
|
|
{
|
|
name: 'Android',
|
|
search: checkContains('android'),
|
|
versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
|
|
},
|
|
{
|
|
name: 'OSX',
|
|
search: checkContains('os x'),
|
|
versionRegexes: [/.*?os\ x\ ?([0-9]+)_([0-9]+).*/]
|
|
},
|
|
{
|
|
name: 'Linux',
|
|
search: checkContains('linux'),
|
|
versionRegexes: []
|
|
},
|
|
{
|
|
name: 'Solaris',
|
|
search: checkContains('sunos'),
|
|
versionRegexes: []
|
|
},
|
|
{
|
|
name: 'FreeBSD',
|
|
search: checkContains('freebsd'),
|
|
versionRegexes: []
|
|
}
|
|
];
|
|
var PlatformInfo = {
|
|
browsers: constant(browsers),
|
|
oses: constant(oses)
|
|
};
|
|
|
|
var detect$2 = function (userAgent, mediaMatch) {
|
|
var browsers = PlatformInfo.browsers();
|
|
var oses = PlatformInfo.oses();
|
|
var browser = UaString.detectBrowser(browsers, userAgent).fold(Browser.unknown, Browser.nu);
|
|
var os = UaString.detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
|
|
var deviceType = DeviceType(os, browser, userAgent, mediaMatch);
|
|
return {
|
|
browser: browser,
|
|
os: os,
|
|
deviceType: deviceType
|
|
};
|
|
};
|
|
var PlatformDetection = { detect: detect$2 };
|
|
|
|
var mediaMatch = function (query) {
|
|
return domGlobals.window.matchMedia(query).matches;
|
|
};
|
|
var platform = Cell(PlatformDetection.detect(domGlobals.navigator.userAgent, mediaMatch));
|
|
var detect$3 = function () {
|
|
return platform.get();
|
|
};
|
|
|
|
var fromHtml = function (html, scope) {
|
|
var doc = scope || domGlobals.document;
|
|
var div = doc.createElement('div');
|
|
div.innerHTML = html;
|
|
if (!div.hasChildNodes() || div.childNodes.length > 1) {
|
|
domGlobals.console.error('HTML does not have a single root node', html);
|
|
throw new Error('HTML must have a single root node');
|
|
}
|
|
return fromDom(div.childNodes[0]);
|
|
};
|
|
var fromTag = function (tag, scope) {
|
|
var doc = scope || domGlobals.document;
|
|
var node = doc.createElement(tag);
|
|
return fromDom(node);
|
|
};
|
|
var fromText = function (text, scope) {
|
|
var doc = scope || domGlobals.document;
|
|
var node = doc.createTextNode(text);
|
|
return fromDom(node);
|
|
};
|
|
var fromDom = function (node) {
|
|
if (node === null || node === undefined) {
|
|
throw new Error('Node cannot be null or undefined');
|
|
}
|
|
return { dom: constant(node) };
|
|
};
|
|
var fromPoint = function (docElm, x, y) {
|
|
var doc = docElm.dom();
|
|
return Option.from(doc.elementFromPoint(x, y)).map(fromDom);
|
|
};
|
|
var Element = {
|
|
fromHtml: fromHtml,
|
|
fromTag: fromTag,
|
|
fromText: fromText,
|
|
fromDom: fromDom,
|
|
fromPoint: fromPoint
|
|
};
|
|
|
|
var ATTRIBUTE = domGlobals.Node.ATTRIBUTE_NODE;
|
|
var CDATA_SECTION = domGlobals.Node.CDATA_SECTION_NODE;
|
|
var COMMENT = domGlobals.Node.COMMENT_NODE;
|
|
var DOCUMENT = domGlobals.Node.DOCUMENT_NODE;
|
|
var DOCUMENT_TYPE = domGlobals.Node.DOCUMENT_TYPE_NODE;
|
|
var DOCUMENT_FRAGMENT = domGlobals.Node.DOCUMENT_FRAGMENT_NODE;
|
|
var ELEMENT = domGlobals.Node.ELEMENT_NODE;
|
|
var TEXT = domGlobals.Node.TEXT_NODE;
|
|
var PROCESSING_INSTRUCTION = domGlobals.Node.PROCESSING_INSTRUCTION_NODE;
|
|
var ENTITY_REFERENCE = domGlobals.Node.ENTITY_REFERENCE_NODE;
|
|
var ENTITY = domGlobals.Node.ENTITY_NODE;
|
|
var NOTATION = domGlobals.Node.NOTATION_NODE;
|
|
|
|
var Global = typeof domGlobals.window !== 'undefined' ? domGlobals.window : Function('return this;')();
|
|
|
|
var name = function (element) {
|
|
var r = element.dom().nodeName;
|
|
return r.toLowerCase();
|
|
};
|
|
var type = function (element) {
|
|
return element.dom().nodeType;
|
|
};
|
|
var isType$1 = function (t) {
|
|
return function (element) {
|
|
return type(element) === t;
|
|
};
|
|
};
|
|
var isElement$1 = isType$1(ELEMENT);
|
|
var isText$1 = isType$1(TEXT);
|
|
|
|
var keys = Object.keys;
|
|
var hasOwnProperty = Object.hasOwnProperty;
|
|
var each$1 = function (obj, f) {
|
|
var props = keys(obj);
|
|
for (var k = 0, len = props.length; k < len; k++) {
|
|
var i = props[k];
|
|
var x = obj[i];
|
|
f(x, i);
|
|
}
|
|
};
|
|
var map$1 = function (obj, f) {
|
|
return tupleMap(obj, function (x, i) {
|
|
return {
|
|
k: i,
|
|
v: f(x, i)
|
|
};
|
|
});
|
|
};
|
|
var tupleMap = function (obj, f) {
|
|
var r = {};
|
|
each$1(obj, function (x, i) {
|
|
var tuple = f(x, i);
|
|
r[tuple.k] = tuple.v;
|
|
});
|
|
return r;
|
|
};
|
|
var bifilter = function (obj, pred) {
|
|
var t = {};
|
|
var f = {};
|
|
each$1(obj, function (x, i) {
|
|
var branch = pred(x, i) ? t : f;
|
|
branch[i] = x;
|
|
});
|
|
return {
|
|
t: t,
|
|
f: f
|
|
};
|
|
};
|
|
var get = function (obj, key) {
|
|
return has(obj, key) ? Option.from(obj[key]) : Option.none();
|
|
};
|
|
var has = function (obj, key) {
|
|
return hasOwnProperty.call(obj, key);
|
|
};
|
|
|
|
var isSupported = function (dom) {
|
|
return dom.style !== undefined && isFunction(dom.style.getPropertyValue);
|
|
};
|
|
|
|
var inBody = function (element) {
|
|
var dom = isText$1(element) ? element.dom().parentNode : element.dom();
|
|
return dom !== undefined && dom !== null && dom.ownerDocument.body.contains(dom);
|
|
};
|
|
|
|
var rawSet = function (dom, key, value) {
|
|
if (isString(value) || isBoolean(value) || isNumber(value)) {
|
|
dom.setAttribute(key, value + '');
|
|
} else {
|
|
domGlobals.console.error('Invalid call to Attr.set. Key ', key, ':: Value ', value, ':: Element ', dom);
|
|
throw new Error('Attribute value was not simple');
|
|
}
|
|
};
|
|
var set = function (element, key, value) {
|
|
rawSet(element.dom(), key, value);
|
|
};
|
|
var setAll = function (element, attrs) {
|
|
var dom = element.dom();
|
|
each$1(attrs, function (v, k) {
|
|
rawSet(dom, k, v);
|
|
});
|
|
};
|
|
var get$1 = function (element, key) {
|
|
var v = element.dom().getAttribute(key);
|
|
return v === null ? undefined : v;
|
|
};
|
|
var has$1 = function (element, key) {
|
|
var dom = element.dom();
|
|
return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
|
|
};
|
|
var remove = function (element, key) {
|
|
element.dom().removeAttribute(key);
|
|
};
|
|
|
|
var get$2 = function (element, property) {
|
|
var dom = element.dom();
|
|
var styles = domGlobals.window.getComputedStyle(dom);
|
|
var r = styles.getPropertyValue(property);
|
|
var v = r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
|
|
return v === null ? undefined : v;
|
|
};
|
|
var getUnsafeProperty = function (dom, property) {
|
|
return isSupported(dom) ? dom.style.getPropertyValue(property) : '';
|
|
};
|
|
var getRaw = function (element, property) {
|
|
var dom = element.dom();
|
|
var raw = getUnsafeProperty(dom, property);
|
|
return Option.from(raw).filter(function (r) {
|
|
return r.length > 0;
|
|
});
|
|
};
|
|
var reflow = function (e) {
|
|
return e.dom().offsetWidth;
|
|
};
|
|
|
|
var Immutable = function () {
|
|
var fields = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
fields[_i] = arguments[_i];
|
|
}
|
|
return function () {
|
|
var values = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
values[_i] = arguments[_i];
|
|
}
|
|
if (fields.length !== values.length) {
|
|
throw new Error('Wrong number of arguments to struct. Expected "[' + fields.length + ']", got ' + values.length + ' arguments');
|
|
}
|
|
var struct = {};
|
|
each(fields, function (name, i) {
|
|
struct[name] = constant(values[i]);
|
|
});
|
|
return struct;
|
|
};
|
|
};
|
|
|
|
var toArray = function (target, f) {
|
|
var r = [];
|
|
var recurse = function (e) {
|
|
r.push(e);
|
|
return f(e);
|
|
};
|
|
var cur = f(target);
|
|
do {
|
|
cur = cur.bind(recurse);
|
|
} while (cur.isSome());
|
|
return r;
|
|
};
|
|
var Recurse = { toArray: toArray };
|
|
|
|
var compareDocumentPosition = function (a, b, match) {
|
|
return (a.compareDocumentPosition(b) & match) !== 0;
|
|
};
|
|
var documentPositionPreceding = function (a, b) {
|
|
return compareDocumentPosition(a, b, domGlobals.Node.DOCUMENT_POSITION_PRECEDING);
|
|
};
|
|
var documentPositionContainedBy = function (a, b) {
|
|
return compareDocumentPosition(a, b, domGlobals.Node.DOCUMENT_POSITION_CONTAINED_BY);
|
|
};
|
|
var Node = {
|
|
documentPositionPreceding: documentPositionPreceding,
|
|
documentPositionContainedBy: documentPositionContainedBy
|
|
};
|
|
|
|
var ELEMENT$1 = ELEMENT;
|
|
var DOCUMENT$1 = DOCUMENT;
|
|
var is = function (element, selector) {
|
|
var dom = element.dom();
|
|
if (dom.nodeType !== ELEMENT$1) {
|
|
return false;
|
|
} else {
|
|
var elem = dom;
|
|
if (elem.matches !== undefined) {
|
|
return elem.matches(selector);
|
|
} else if (elem.msMatchesSelector !== undefined) {
|
|
return elem.msMatchesSelector(selector);
|
|
} else if (elem.webkitMatchesSelector !== undefined) {
|
|
return elem.webkitMatchesSelector(selector);
|
|
} else if (elem.mozMatchesSelector !== undefined) {
|
|
return elem.mozMatchesSelector(selector);
|
|
} else {
|
|
throw new Error('Browser lacks native selectors');
|
|
}
|
|
}
|
|
};
|
|
var bypassSelector = function (dom) {
|
|
return dom.nodeType !== ELEMENT$1 && dom.nodeType !== DOCUMENT$1 || dom.childElementCount === 0;
|
|
};
|
|
var all = function (selector, scope) {
|
|
var base = scope === undefined ? domGlobals.document : scope.dom();
|
|
return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), Element.fromDom);
|
|
};
|
|
var one = function (selector, scope) {
|
|
var base = scope === undefined ? domGlobals.document : scope.dom();
|
|
return bypassSelector(base) ? Option.none() : Option.from(base.querySelector(selector)).map(Element.fromDom);
|
|
};
|
|
|
|
var eq = function (e1, e2) {
|
|
return e1.dom() === e2.dom();
|
|
};
|
|
var regularContains = function (e1, e2) {
|
|
var d1 = e1.dom();
|
|
var d2 = e2.dom();
|
|
return d1 === d2 ? false : d1.contains(d2);
|
|
};
|
|
var ieContains = function (e1, e2) {
|
|
return Node.documentPositionContainedBy(e1.dom(), e2.dom());
|
|
};
|
|
var browser = detect$3().browser;
|
|
var contains$2 = browser.isIE() ? ieContains : regularContains;
|
|
|
|
var owner = function (element) {
|
|
return Element.fromDom(element.dom().ownerDocument);
|
|
};
|
|
var documentElement = function (element) {
|
|
return Element.fromDom(element.dom().ownerDocument.documentElement);
|
|
};
|
|
var defaultView = function (element) {
|
|
return Element.fromDom(element.dom().ownerDocument.defaultView);
|
|
};
|
|
var parent = function (element) {
|
|
return Option.from(element.dom().parentNode).map(Element.fromDom);
|
|
};
|
|
var parents = function (element, isRoot) {
|
|
var stop = isFunction(isRoot) ? isRoot : never;
|
|
var dom = element.dom();
|
|
var ret = [];
|
|
while (dom.parentNode !== null && dom.parentNode !== undefined) {
|
|
var rawParent = dom.parentNode;
|
|
var p = Element.fromDom(rawParent);
|
|
ret.push(p);
|
|
if (stop(p) === true) {
|
|
break;
|
|
} else {
|
|
dom = rawParent;
|
|
}
|
|
}
|
|
return ret;
|
|
};
|
|
var prevSibling = function (element) {
|
|
return Option.from(element.dom().previousSibling).map(Element.fromDom);
|
|
};
|
|
var nextSibling = function (element) {
|
|
return Option.from(element.dom().nextSibling).map(Element.fromDom);
|
|
};
|
|
var prevSiblings = function (element) {
|
|
return reverse(Recurse.toArray(element, prevSibling));
|
|
};
|
|
var nextSiblings = function (element) {
|
|
return Recurse.toArray(element, nextSibling);
|
|
};
|
|
var children = function (element) {
|
|
return map(element.dom().childNodes, Element.fromDom);
|
|
};
|
|
var child = function (element, index) {
|
|
var cs = element.dom().childNodes;
|
|
return Option.from(cs[index]).map(Element.fromDom);
|
|
};
|
|
var firstChild = function (element) {
|
|
return child(element, 0);
|
|
};
|
|
var lastChild = function (element) {
|
|
return child(element, element.dom().childNodes.length - 1);
|
|
};
|
|
var childNodesCount = function (element) {
|
|
return element.dom().childNodes.length;
|
|
};
|
|
var spot = Immutable('element', 'offset');
|
|
|
|
var browser$1 = detect$3().browser;
|
|
var firstElement = function (nodes) {
|
|
return find(nodes, isElement$1);
|
|
};
|
|
var getTableCaptionDeltaY = function (elm) {
|
|
if (browser$1.isFirefox() && name(elm) === 'table') {
|
|
return firstElement(children(elm)).filter(function (elm) {
|
|
return name(elm) === 'caption';
|
|
}).bind(function (caption) {
|
|
return firstElement(nextSiblings(caption)).map(function (body) {
|
|
var bodyTop = body.dom().offsetTop;
|
|
var captionTop = caption.dom().offsetTop;
|
|
var captionHeight = caption.dom().offsetHeight;
|
|
return bodyTop <= captionTop ? -captionHeight : 0;
|
|
});
|
|
}).getOr(0);
|
|
} else {
|
|
return 0;
|
|
}
|
|
};
|
|
var hasChild = function (elm, child) {
|
|
return elm.children && contains(elm.children, child);
|
|
};
|
|
var getPos = function (body, elm, rootElm) {
|
|
var x = 0, y = 0, offsetParent;
|
|
var doc = body.ownerDocument;
|
|
var pos;
|
|
rootElm = rootElm ? rootElm : body;
|
|
if (elm) {
|
|
if (rootElm === body && elm.getBoundingClientRect && get$2(Element.fromDom(body), 'position') === 'static') {
|
|
pos = elm.getBoundingClientRect();
|
|
x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
|
|
y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
|
|
return {
|
|
x: x,
|
|
y: y
|
|
};
|
|
}
|
|
offsetParent = elm;
|
|
while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
|
|
x += offsetParent.offsetLeft || 0;
|
|
y += offsetParent.offsetTop || 0;
|
|
offsetParent = offsetParent.offsetParent;
|
|
}
|
|
offsetParent = elm.parentNode;
|
|
while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
|
|
x -= offsetParent.scrollLeft || 0;
|
|
y -= offsetParent.scrollTop || 0;
|
|
offsetParent = offsetParent.parentNode;
|
|
}
|
|
y += getTableCaptionDeltaY(Element.fromDom(elm));
|
|
}
|
|
return {
|
|
x: x,
|
|
y: y
|
|
};
|
|
};
|
|
var Position = { getPos: getPos };
|
|
|
|
var exports$1 = {}, module$1 = { exports: exports$1 };
|
|
(function (define, exports, module, require) {
|
|
(function (f) {
|
|
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
|
module.exports = f();
|
|
} else if (typeof define === 'function' && define.amd) {
|
|
define([], f);
|
|
} else {
|
|
var g;
|
|
if (typeof window !== 'undefined') {
|
|
g = window;
|
|
} else if (typeof global !== 'undefined') {
|
|
g = global;
|
|
} else if (typeof self !== 'undefined') {
|
|
g = self;
|
|
} else {
|
|
g = this;
|
|
}
|
|
g.EphoxContactWrapper = f();
|
|
}
|
|
}(function () {
|
|
return function () {
|
|
function r(e, n, t) {
|
|
function o(i, f) {
|
|
if (!n[i]) {
|
|
if (!e[i]) {
|
|
var c = 'function' == typeof require && require;
|
|
if (!f && c)
|
|
return c(i, !0);
|
|
if (u)
|
|
return u(i, !0);
|
|
var a = new Error('Cannot find module \'' + i + '\'');
|
|
throw a.code = 'MODULE_NOT_FOUND', a;
|
|
}
|
|
var p = n[i] = { exports: {} };
|
|
e[i][0].call(p.exports, function (r) {
|
|
var n = e[i][1][r];
|
|
return o(n || r);
|
|
}, p, p.exports, r, e, n, t);
|
|
}
|
|
return n[i].exports;
|
|
}
|
|
for (var u = 'function' == typeof require && require, i = 0; i < t.length; i++)
|
|
o(t[i]);
|
|
return o;
|
|
}
|
|
return r;
|
|
}()({
|
|
1: [
|
|
function (require, module, exports) {
|
|
var process = module.exports = {};
|
|
var cachedSetTimeout;
|
|
var cachedClearTimeout;
|
|
function defaultSetTimout() {
|
|
throw new Error('setTimeout has not been defined');
|
|
}
|
|
function defaultClearTimeout() {
|
|
throw new Error('clearTimeout has not been defined');
|
|
}
|
|
(function () {
|
|
try {
|
|
if (typeof setTimeout === 'function') {
|
|
cachedSetTimeout = setTimeout;
|
|
} else {
|
|
cachedSetTimeout = defaultSetTimout;
|
|
}
|
|
} catch (e) {
|
|
cachedSetTimeout = defaultSetTimout;
|
|
}
|
|
try {
|
|
if (typeof clearTimeout === 'function') {
|
|
cachedClearTimeout = clearTimeout;
|
|
} else {
|
|
cachedClearTimeout = defaultClearTimeout;
|
|
}
|
|
} catch (e) {
|
|
cachedClearTimeout = defaultClearTimeout;
|
|
}
|
|
}());
|
|
function runTimeout(fun) {
|
|
if (cachedSetTimeout === setTimeout) {
|
|
return setTimeout(fun, 0);
|
|
}
|
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
|
cachedSetTimeout = setTimeout;
|
|
return setTimeout(fun, 0);
|
|
}
|
|
try {
|
|
return cachedSetTimeout(fun, 0);
|
|
} catch (e) {
|
|
try {
|
|
return cachedSetTimeout.call(null, fun, 0);
|
|
} catch (e) {
|
|
return cachedSetTimeout.call(this, fun, 0);
|
|
}
|
|
}
|
|
}
|
|
function runClearTimeout(marker) {
|
|
if (cachedClearTimeout === clearTimeout) {
|
|
return clearTimeout(marker);
|
|
}
|
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
|
cachedClearTimeout = clearTimeout;
|
|
return clearTimeout(marker);
|
|
}
|
|
try {
|
|
return cachedClearTimeout(marker);
|
|
} catch (e) {
|
|
try {
|
|
return cachedClearTimeout.call(null, marker);
|
|
} catch (e) {
|
|
return cachedClearTimeout.call(this, marker);
|
|
}
|
|
}
|
|
}
|
|
var queue = [];
|
|
var draining = false;
|
|
var currentQueue;
|
|
var queueIndex = -1;
|
|
function cleanUpNextTick() {
|
|
if (!draining || !currentQueue) {
|
|
return;
|
|
}
|
|
draining = false;
|
|
if (currentQueue.length) {
|
|
queue = currentQueue.concat(queue);
|
|
} else {
|
|
queueIndex = -1;
|
|
}
|
|
if (queue.length) {
|
|
drainQueue();
|
|
}
|
|
}
|
|
function drainQueue() {
|
|
if (draining) {
|
|
return;
|
|
}
|
|
var timeout = runTimeout(cleanUpNextTick);
|
|
draining = true;
|
|
var len = queue.length;
|
|
while (len) {
|
|
currentQueue = queue;
|
|
queue = [];
|
|
while (++queueIndex < len) {
|
|
if (currentQueue) {
|
|
currentQueue[queueIndex].run();
|
|
}
|
|
}
|
|
queueIndex = -1;
|
|
len = queue.length;
|
|
}
|
|
currentQueue = null;
|
|
draining = false;
|
|
runClearTimeout(timeout);
|
|
}
|
|
process.nextTick = function (fun) {
|
|
var args = new Array(arguments.length - 1);
|
|
if (arguments.length > 1) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
args[i - 1] = arguments[i];
|
|
}
|
|
}
|
|
queue.push(new Item(fun, args));
|
|
if (queue.length === 1 && !draining) {
|
|
runTimeout(drainQueue);
|
|
}
|
|
};
|
|
function Item(fun, array) {
|
|
this.fun = fun;
|
|
this.array = array;
|
|
}
|
|
Item.prototype.run = function () {
|
|
this.fun.apply(null, this.array);
|
|
};
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
process.version = '';
|
|
process.versions = {};
|
|
function noop() {
|
|
}
|
|
process.on = noop;
|
|
process.addListener = noop;
|
|
process.once = noop;
|
|
process.off = noop;
|
|
process.removeListener = noop;
|
|
process.removeAllListeners = noop;
|
|
process.emit = noop;
|
|
process.prependListener = noop;
|
|
process.prependOnceListener = noop;
|
|
process.listeners = function (name) {
|
|
return [];
|
|
};
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
};
|
|
process.cwd = function () {
|
|
return '/';
|
|
};
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
process.umask = function () {
|
|
return 0;
|
|
};
|
|
},
|
|
{}
|
|
],
|
|
2: [
|
|
function (require, module, exports) {
|
|
(function (setImmediate) {
|
|
(function (root) {
|
|
var setTimeoutFunc = setTimeout;
|
|
function noop() {
|
|
}
|
|
function bind(fn, thisArg) {
|
|
return function () {
|
|
fn.apply(thisArg, arguments);
|
|
};
|
|
}
|
|
function Promise(fn) {
|
|
if (typeof this !== 'object')
|
|
throw new TypeError('Promises must be constructed via new');
|
|
if (typeof fn !== 'function')
|
|
throw new TypeError('not a function');
|
|
this._state = 0;
|
|
this._handled = false;
|
|
this._value = undefined;
|
|
this._deferreds = [];
|
|
doResolve(fn, this);
|
|
}
|
|
function handle(self, deferred) {
|
|
while (self._state === 3) {
|
|
self = self._value;
|
|
}
|
|
if (self._state === 0) {
|
|
self._deferreds.push(deferred);
|
|
return;
|
|
}
|
|
self._handled = true;
|
|
Promise._immediateFn(function () {
|
|
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
|
|
if (cb === null) {
|
|
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
|
|
return;
|
|
}
|
|
var ret;
|
|
try {
|
|
ret = cb(self._value);
|
|
} catch (e) {
|
|
reject(deferred.promise, e);
|
|
return;
|
|
}
|
|
resolve(deferred.promise, ret);
|
|
});
|
|
}
|
|
function resolve(self, newValue) {
|
|
try {
|
|
if (newValue === self)
|
|
throw new TypeError('A promise cannot be resolved with itself.');
|
|
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
|
|
var then = newValue.then;
|
|
if (newValue instanceof Promise) {
|
|
self._state = 3;
|
|
self._value = newValue;
|
|
finale(self);
|
|
return;
|
|
} else if (typeof then === 'function') {
|
|
doResolve(bind(then, newValue), self);
|
|
return;
|
|
}
|
|
}
|
|
self._state = 1;
|
|
self._value = newValue;
|
|
finale(self);
|
|
} catch (e) {
|
|
reject(self, e);
|
|
}
|
|
}
|
|
function reject(self, newValue) {
|
|
self._state = 2;
|
|
self._value = newValue;
|
|
finale(self);
|
|
}
|
|
function finale(self) {
|
|
if (self._state === 2 && self._deferreds.length === 0) {
|
|
Promise._immediateFn(function () {
|
|
if (!self._handled) {
|
|
Promise._unhandledRejectionFn(self._value);
|
|
}
|
|
});
|
|
}
|
|
for (var i = 0, len = self._deferreds.length; i < len; i++) {
|
|
handle(self, self._deferreds[i]);
|
|
}
|
|
self._deferreds = null;
|
|
}
|
|
function Handler(onFulfilled, onRejected, promise) {
|
|
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
|
|
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
|
|
this.promise = promise;
|
|
}
|
|
function doResolve(fn, self) {
|
|
var done = false;
|
|
try {
|
|
fn(function (value) {
|
|
if (done)
|
|
return;
|
|
done = true;
|
|
resolve(self, value);
|
|
}, function (reason) {
|
|
if (done)
|
|
return;
|
|
done = true;
|
|
reject(self, reason);
|
|
});
|
|
} catch (ex) {
|
|
if (done)
|
|
return;
|
|
done = true;
|
|
reject(self, ex);
|
|
}
|
|
}
|
|
Promise.prototype['catch'] = function (onRejected) {
|
|
return this.then(null, onRejected);
|
|
};
|
|
Promise.prototype.then = function (onFulfilled, onRejected) {
|
|
var prom = new this.constructor(noop);
|
|
handle(this, new Handler(onFulfilled, onRejected, prom));
|
|
return prom;
|
|
};
|
|
Promise.all = function (arr) {
|
|
var args = Array.prototype.slice.call(arr);
|
|
return new Promise(function (resolve, reject) {
|
|
if (args.length === 0)
|
|
return resolve([]);
|
|
var remaining = args.length;
|
|
function res(i, val) {
|
|
try {
|
|
if (val && (typeof val === 'object' || typeof val === 'function')) {
|
|
var then = val.then;
|
|
if (typeof then === 'function') {
|
|
then.call(val, function (val) {
|
|
res(i, val);
|
|
}, reject);
|
|
return;
|
|
}
|
|
}
|
|
args[i] = val;
|
|
if (--remaining === 0) {
|
|
resolve(args);
|
|
}
|
|
} catch (ex) {
|
|
reject(ex);
|
|
}
|
|
}
|
|
for (var i = 0; i < args.length; i++) {
|
|
res(i, args[i]);
|
|
}
|
|
});
|
|
};
|
|
Promise.resolve = function (value) {
|
|
if (value && typeof value === 'object' && value.constructor === Promise) {
|
|
return value;
|
|
}
|
|
return new Promise(function (resolve) {
|
|
resolve(value);
|
|
});
|
|
};
|
|
Promise.reject = function (value) {
|
|
return new Promise(function (resolve, reject) {
|
|
reject(value);
|
|
});
|
|
};
|
|
Promise.race = function (values) {
|
|
return new Promise(function (resolve, reject) {
|
|
for (var i = 0, len = values.length; i < len; i++) {
|
|
values[i].then(resolve, reject);
|
|
}
|
|
});
|
|
};
|
|
Promise._immediateFn = typeof setImmediate === 'function' ? function (fn) {
|
|
setImmediate(fn);
|
|
} : function (fn) {
|
|
setTimeoutFunc(fn, 0);
|
|
};
|
|
Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
|
|
if (typeof console !== 'undefined' && console) {
|
|
console.warn('Possible Unhandled Promise Rejection:', err);
|
|
}
|
|
};
|
|
Promise._setImmediateFn = function _setImmediateFn(fn) {
|
|
Promise._immediateFn = fn;
|
|
};
|
|
Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
|
|
Promise._unhandledRejectionFn = fn;
|
|
};
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = Promise;
|
|
} else if (!root.Promise) {
|
|
root.Promise = Promise;
|
|
}
|
|
}(this));
|
|
}.call(this, require('timers').setImmediate));
|
|
},
|
|
{ 'timers': 3 }
|
|
],
|
|
3: [
|
|
function (require, module, exports) {
|
|
(function (setImmediate, clearImmediate) {
|
|
var nextTick = require('process/browser.js').nextTick;
|
|
var apply = Function.prototype.apply;
|
|
var slice = Array.prototype.slice;
|
|
var immediateIds = {};
|
|
var nextImmediateId = 0;
|
|
exports.setTimeout = function () {
|
|
return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);
|
|
};
|
|
exports.setInterval = function () {
|
|
return new Timeout(apply.call(setInterval, window, arguments), clearInterval);
|
|
};
|
|
exports.clearTimeout = exports.clearInterval = function (timeout) {
|
|
timeout.close();
|
|
};
|
|
function Timeout(id, clearFn) {
|
|
this._id = id;
|
|
this._clearFn = clearFn;
|
|
}
|
|
Timeout.prototype.unref = Timeout.prototype.ref = function () {
|
|
};
|
|
Timeout.prototype.close = function () {
|
|
this._clearFn.call(window, this._id);
|
|
};
|
|
exports.enroll = function (item, msecs) {
|
|
clearTimeout(item._idleTimeoutId);
|
|
item._idleTimeout = msecs;
|
|
};
|
|
exports.unenroll = function (item) {
|
|
clearTimeout(item._idleTimeoutId);
|
|
item._idleTimeout = -1;
|
|
};
|
|
exports._unrefActive = exports.active = function (item) {
|
|
clearTimeout(item._idleTimeoutId);
|
|
var msecs = item._idleTimeout;
|
|
if (msecs >= 0) {
|
|
item._idleTimeoutId = setTimeout(function onTimeout() {
|
|
if (item._onTimeout)
|
|
item._onTimeout();
|
|
}, msecs);
|
|
}
|
|
};
|
|
exports.setImmediate = typeof setImmediate === 'function' ? setImmediate : function (fn) {
|
|
var id = nextImmediateId++;
|
|
var args = arguments.length < 2 ? false : slice.call(arguments, 1);
|
|
immediateIds[id] = true;
|
|
nextTick(function onNextTick() {
|
|
if (immediateIds[id]) {
|
|
if (args) {
|
|
fn.apply(null, args);
|
|
} else {
|
|
fn.call(null);
|
|
}
|
|
exports.clearImmediate(id);
|
|
}
|
|
});
|
|
return id;
|
|
};
|
|
exports.clearImmediate = typeof clearImmediate === 'function' ? clearImmediate : function (id) {
|
|
delete immediateIds[id];
|
|
};
|
|
}.call(this, require('timers').setImmediate, require('timers').clearImmediate));
|
|
},
|
|
{
|
|
'process/browser.js': 1,
|
|
'timers': 3
|
|
}
|
|
],
|
|
4: [
|
|
function (require, module, exports) {
|
|
var promisePolyfill = require('promise-polyfill');
|
|
var Global = function () {
|
|
if (typeof window !== 'undefined') {
|
|
return window;
|
|
} else {
|
|
return Function('return this;')();
|
|
}
|
|
}();
|
|
module.exports = { boltExport: Global.Promise || promisePolyfill };
|
|
},
|
|
{ 'promise-polyfill': 2 }
|
|
]
|
|
}, {}, [4])(4);
|
|
}));
|
|
}(undefined, exports$1, module$1, undefined));
|
|
var Promise = module$1.exports.boltExport;
|
|
|
|
var nu$3 = function (baseFn) {
|
|
var data = Option.none();
|
|
var callbacks = [];
|
|
var map = function (f) {
|
|
return nu$3(function (nCallback) {
|
|
get(function (data) {
|
|
nCallback(f(data));
|
|
});
|
|
});
|
|
};
|
|
var get = function (nCallback) {
|
|
if (isReady()) {
|
|
call(nCallback);
|
|
} else {
|
|
callbacks.push(nCallback);
|
|
}
|
|
};
|
|
var set = function (x) {
|
|
data = Option.some(x);
|
|
run(callbacks);
|
|
callbacks = [];
|
|
};
|
|
var isReady = function () {
|
|
return data.isSome();
|
|
};
|
|
var run = function (cbs) {
|
|
each(cbs, call);
|
|
};
|
|
var call = function (cb) {
|
|
data.each(function (x) {
|
|
domGlobals.setTimeout(function () {
|
|
cb(x);
|
|
}, 0);
|
|
});
|
|
};
|
|
baseFn(set);
|
|
return {
|
|
get: get,
|
|
map: map,
|
|
isReady: isReady
|
|
};
|
|
};
|
|
var pure = function (a) {
|
|
return nu$3(function (callback) {
|
|
callback(a);
|
|
});
|
|
};
|
|
var LazyValue = {
|
|
nu: nu$3,
|
|
pure: pure
|
|
};
|
|
|
|
var errorReporter = function (err) {
|
|
domGlobals.setTimeout(function () {
|
|
throw err;
|
|
}, 0);
|
|
};
|
|
var make = function (run) {
|
|
var get = function (callback) {
|
|
run().then(callback, errorReporter);
|
|
};
|
|
var map = function (fab) {
|
|
return make(function () {
|
|
return run().then(fab);
|
|
});
|
|
};
|
|
var bind = function (aFutureB) {
|
|
return make(function () {
|
|
return run().then(function (v) {
|
|
return aFutureB(v).toPromise();
|
|
});
|
|
});
|
|
};
|
|
var anonBind = function (futureB) {
|
|
return make(function () {
|
|
return run().then(function () {
|
|
return futureB.toPromise();
|
|
});
|
|
});
|
|
};
|
|
var toLazy = function () {
|
|
return LazyValue.nu(get);
|
|
};
|
|
var toCached = function () {
|
|
var cache = null;
|
|
return make(function () {
|
|
if (cache === null) {
|
|
cache = run();
|
|
}
|
|
return cache;
|
|
});
|
|
};
|
|
var toPromise = run;
|
|
return {
|
|
map: map,
|
|
bind: bind,
|
|
anonBind: anonBind,
|
|
toLazy: toLazy,
|
|
toCached: toCached,
|
|
toPromise: toPromise,
|
|
get: get
|
|
};
|
|
};
|
|
var nu$4 = function (baseFn) {
|
|
return make(function () {
|
|
return new Promise(baseFn);
|
|
});
|
|
};
|
|
var pure$1 = function (a) {
|
|
return make(function () {
|
|
return Promise.resolve(a);
|
|
});
|
|
};
|
|
var Future = {
|
|
nu: nu$4,
|
|
pure: pure$1
|
|
};
|
|
|
|
var par = function (asyncValues, nu) {
|
|
return nu(function (callback) {
|
|
var r = [];
|
|
var count = 0;
|
|
var cb = function (i) {
|
|
return function (value) {
|
|
r[i] = value;
|
|
count++;
|
|
if (count >= asyncValues.length) {
|
|
callback(r);
|
|
}
|
|
};
|
|
};
|
|
if (asyncValues.length === 0) {
|
|
callback([]);
|
|
} else {
|
|
each(asyncValues, function (asyncValue, i) {
|
|
asyncValue.get(cb(i));
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
var par$1 = function (futures) {
|
|
return par(futures, Future.nu);
|
|
};
|
|
|
|
var value = function (o) {
|
|
var is = function (v) {
|
|
return o === v;
|
|
};
|
|
var or = function (opt) {
|
|
return value(o);
|
|
};
|
|
var orThunk = function (f) {
|
|
return value(o);
|
|
};
|
|
var map = function (f) {
|
|
return value(f(o));
|
|
};
|
|
var mapError = function (f) {
|
|
return value(o);
|
|
};
|
|
var each = function (f) {
|
|
f(o);
|
|
};
|
|
var bind = function (f) {
|
|
return f(o);
|
|
};
|
|
var fold = function (_, onValue) {
|
|
return onValue(o);
|
|
};
|
|
var exists = function (f) {
|
|
return f(o);
|
|
};
|
|
var forall = function (f) {
|
|
return f(o);
|
|
};
|
|
var toOption = function () {
|
|
return Option.some(o);
|
|
};
|
|
return {
|
|
is: is,
|
|
isValue: always,
|
|
isError: never,
|
|
getOr: constant(o),
|
|
getOrThunk: constant(o),
|
|
getOrDie: constant(o),
|
|
or: or,
|
|
orThunk: orThunk,
|
|
fold: fold,
|
|
map: map,
|
|
mapError: mapError,
|
|
each: each,
|
|
bind: bind,
|
|
exists: exists,
|
|
forall: forall,
|
|
toOption: toOption
|
|
};
|
|
};
|
|
var error = function (message) {
|
|
var getOrThunk = function (f) {
|
|
return f();
|
|
};
|
|
var getOrDie = function () {
|
|
return die(String(message))();
|
|
};
|
|
var or = function (opt) {
|
|
return opt;
|
|
};
|
|
var orThunk = function (f) {
|
|
return f();
|
|
};
|
|
var map = function (f) {
|
|
return error(message);
|
|
};
|
|
var mapError = function (f) {
|
|
return error(f(message));
|
|
};
|
|
var bind = function (f) {
|
|
return error(message);
|
|
};
|
|
var fold = function (onError, _) {
|
|
return onError(message);
|
|
};
|
|
return {
|
|
is: never,
|
|
isValue: never,
|
|
isError: always,
|
|
getOr: identity,
|
|
getOrThunk: getOrThunk,
|
|
getOrDie: getOrDie,
|
|
or: or,
|
|
orThunk: orThunk,
|
|
fold: fold,
|
|
map: map,
|
|
mapError: mapError,
|
|
each: noop,
|
|
bind: bind,
|
|
exists: never,
|
|
forall: always,
|
|
toOption: Option.none
|
|
};
|
|
};
|
|
var fromOption = function (opt, err) {
|
|
return opt.fold(function () {
|
|
return error(err);
|
|
}, value);
|
|
};
|
|
var Result = {
|
|
value: value,
|
|
error: error,
|
|
fromOption: fromOption
|
|
};
|
|
|
|
var promise = function () {
|
|
function bind(fn, thisArg) {
|
|
return function () {
|
|
fn.apply(thisArg, arguments);
|
|
};
|
|
}
|
|
var isArray = Array.isArray || function (value) {
|
|
return Object.prototype.toString.call(value) === '[object Array]';
|
|
};
|
|
var Promise = function (fn) {
|
|
if (typeof this !== 'object') {
|
|
throw new TypeError('Promises must be constructed via new');
|
|
}
|
|
if (typeof fn !== 'function') {
|
|
throw new TypeError('not a function');
|
|
}
|
|
this._state = null;
|
|
this._value = null;
|
|
this._deferreds = [];
|
|
doResolve(fn, bind(resolve, this), bind(reject, this));
|
|
};
|
|
var asap = Promise.immediateFn || typeof domGlobals.setImmediate === 'function' && domGlobals.setImmediate || function (fn) {
|
|
domGlobals.setTimeout(fn, 1);
|
|
};
|
|
function handle(deferred) {
|
|
var me = this;
|
|
if (this._state === null) {
|
|
this._deferreds.push(deferred);
|
|
return;
|
|
}
|
|
asap(function () {
|
|
var cb = me._state ? deferred.onFulfilled : deferred.onRejected;
|
|
if (cb === null) {
|
|
(me._state ? deferred.resolve : deferred.reject)(me._value);
|
|
return;
|
|
}
|
|
var ret;
|
|
try {
|
|
ret = cb(me._value);
|
|
} catch (e) {
|
|
deferred.reject(e);
|
|
return;
|
|
}
|
|
deferred.resolve(ret);
|
|
});
|
|
}
|
|
function resolve(newValue) {
|
|
try {
|
|
if (newValue === this) {
|
|
throw new TypeError('A promise cannot be resolved with itself.');
|
|
}
|
|
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
|
|
var then = newValue.then;
|
|
if (typeof then === 'function') {
|
|
doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
|
|
return;
|
|
}
|
|
}
|
|
this._state = true;
|
|
this._value = newValue;
|
|
finale.call(this);
|
|
} catch (e) {
|
|
reject.call(this, e);
|
|
}
|
|
}
|
|
function reject(newValue) {
|
|
this._state = false;
|
|
this._value = newValue;
|
|
finale.call(this);
|
|
}
|
|
function finale() {
|
|
for (var i = 0, len = this._deferreds.length; i < len; i++) {
|
|
handle.call(this, this._deferreds[i]);
|
|
}
|
|
this._deferreds = null;
|
|
}
|
|
function Handler(onFulfilled, onRejected, resolve, reject) {
|
|
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
|
|
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
|
|
this.resolve = resolve;
|
|
this.reject = reject;
|
|
}
|
|
function doResolve(fn, onFulfilled, onRejected) {
|
|
var done = false;
|
|
try {
|
|
fn(function (value) {
|
|
if (done) {
|
|
return;
|
|
}
|
|
done = true;
|
|
onFulfilled(value);
|
|
}, function (reason) {
|
|
if (done) {
|
|
return;
|
|
}
|
|
done = true;
|
|
onRejected(reason);
|
|
});
|
|
} catch (ex) {
|
|
if (done) {
|
|
return;
|
|
}
|
|
done = true;
|
|
onRejected(ex);
|
|
}
|
|
}
|
|
Promise.prototype.catch = function (onRejected) {
|
|
return this.then(null, onRejected);
|
|
};
|
|
Promise.prototype.then = function (onFulfilled, onRejected) {
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
|
|
});
|
|
};
|
|
Promise.all = function () {
|
|
var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
|
|
return new Promise(function (resolve, reject) {
|
|
if (args.length === 0) {
|
|
return resolve([]);
|
|
}
|
|
var remaining = args.length;
|
|
function res(i, val) {
|
|
try {
|
|
if (val && (typeof val === 'object' || typeof val === 'function')) {
|
|
var then = val.then;
|
|
if (typeof then === 'function') {
|
|
then.call(val, function (val) {
|
|
res(i, val);
|
|
}, reject);
|
|
return;
|
|
}
|
|
}
|
|
args[i] = val;
|
|
if (--remaining === 0) {
|
|
resolve(args);
|
|
}
|
|
} catch (ex) {
|
|
reject(ex);
|
|
}
|
|
}
|
|
for (var i = 0; i < args.length; i++) {
|
|
res(i, args[i]);
|
|
}
|
|
});
|
|
};
|
|
Promise.resolve = function (value) {
|
|
if (value && typeof value === 'object' && value.constructor === Promise) {
|
|
return value;
|
|
}
|
|
return new Promise(function (resolve) {
|
|
resolve(value);
|
|
});
|
|
};
|
|
Promise.reject = function (value) {
|
|
return new Promise(function (resolve, reject) {
|
|
reject(value);
|
|
});
|
|
};
|
|
Promise.race = function (values) {
|
|
return new Promise(function (resolve, reject) {
|
|
for (var i = 0, len = values.length; i < len; i++) {
|
|
values[i].then(resolve, reject);
|
|
}
|
|
});
|
|
};
|
|
return Promise;
|
|
};
|
|
var promiseObj = window.Promise ? window.Promise : promise();
|
|
|
|
var requestAnimationFramePromise;
|
|
var requestAnimationFrame = function (callback, element) {
|
|
var i, requestAnimationFrameFunc = domGlobals.window.requestAnimationFrame;
|
|
var vendors = [
|
|
'ms',
|
|
'moz',
|
|
'webkit'
|
|
];
|
|
var featurefill = function (callback) {
|
|
domGlobals.window.setTimeout(callback, 0);
|
|
};
|
|
for (i = 0; i < vendors.length && !requestAnimationFrameFunc; i++) {
|
|
requestAnimationFrameFunc = domGlobals.window[vendors[i] + 'RequestAnimationFrame'];
|
|
}
|
|
if (!requestAnimationFrameFunc) {
|
|
requestAnimationFrameFunc = featurefill;
|
|
}
|
|
requestAnimationFrameFunc(callback, element);
|
|
};
|
|
var wrappedSetTimeout = function (callback, time) {
|
|
if (typeof time !== 'number') {
|
|
time = 0;
|
|
}
|
|
return domGlobals.setTimeout(callback, time);
|
|
};
|
|
var wrappedSetInterval = function (callback, time) {
|
|
if (typeof time !== 'number') {
|
|
time = 1;
|
|
}
|
|
return domGlobals.setInterval(callback, time);
|
|
};
|
|
var wrappedClearTimeout = function (id) {
|
|
return domGlobals.clearTimeout(id);
|
|
};
|
|
var wrappedClearInterval = function (id) {
|
|
return domGlobals.clearInterval(id);
|
|
};
|
|
var debounce = function (callback, time) {
|
|
var timer, func;
|
|
func = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
domGlobals.clearTimeout(timer);
|
|
timer = wrappedSetTimeout(function () {
|
|
callback.apply(this, args);
|
|
}, time);
|
|
};
|
|
func.stop = function () {
|
|
domGlobals.clearTimeout(timer);
|
|
};
|
|
return func;
|
|
};
|
|
var Delay = {
|
|
requestAnimationFrame: function (callback, element) {
|
|
if (requestAnimationFramePromise) {
|
|
requestAnimationFramePromise.then(callback);
|
|
return;
|
|
}
|
|
requestAnimationFramePromise = new promiseObj(function (resolve) {
|
|
if (!element) {
|
|
element = domGlobals.document.body;
|
|
}
|
|
requestAnimationFrame(resolve, element);
|
|
}).then(callback);
|
|
},
|
|
setTimeout: wrappedSetTimeout,
|
|
setInterval: wrappedSetInterval,
|
|
setEditorTimeout: function (editor, callback, time) {
|
|
return wrappedSetTimeout(function () {
|
|
if (!editor.removed) {
|
|
callback();
|
|
}
|
|
}, time);
|
|
},
|
|
setEditorInterval: function (editor, callback, time) {
|
|
var timer;
|
|
timer = wrappedSetInterval(function () {
|
|
if (!editor.removed) {
|
|
callback();
|
|
} else {
|
|
domGlobals.clearInterval(timer);
|
|
}
|
|
}, time);
|
|
return timer;
|
|
},
|
|
debounce: debounce,
|
|
throttle: debounce,
|
|
clearInterval: wrappedClearInterval,
|
|
clearTimeout: wrappedClearTimeout
|
|
};
|
|
|
|
var userAgent = domGlobals.navigator.userAgent;
|
|
var platform$1 = detect$3();
|
|
var browser$2 = platform$1.browser;
|
|
var os = platform$1.os;
|
|
var deviceType = platform$1.deviceType;
|
|
var webkit = /WebKit/.test(userAgent) && !browser$2.isEdge();
|
|
var fileApi = 'FormData' in domGlobals.window && 'FileReader' in domGlobals.window && 'URL' in domGlobals.window && !!domGlobals.URL.createObjectURL;
|
|
var windowsPhone = userAgent.indexOf('Windows Phone') !== -1;
|
|
var Env = {
|
|
opera: browser$2.isOpera(),
|
|
webkit: webkit,
|
|
ie: browser$2.isIE() || browser$2.isEdge() ? browser$2.version.major : false,
|
|
gecko: browser$2.isFirefox(),
|
|
mac: os.isOSX() || os.isiOS(),
|
|
iOS: deviceType.isiPad() || deviceType.isiPhone(),
|
|
android: os.isAndroid(),
|
|
contentEditable: true,
|
|
transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
|
|
caretAfter: true,
|
|
range: domGlobals.window.getSelection && 'Range' in domGlobals.window,
|
|
documentMode: browser$2.isIE() ? domGlobals.document.documentMode || 7 : 10,
|
|
fileApi: fileApi,
|
|
ceFalse: true,
|
|
cacheSuffix: null,
|
|
container: null,
|
|
experimentalShadowDom: false,
|
|
canHaveCSP: !browser$2.isIE(),
|
|
desktop: deviceType.isDesktop(),
|
|
windowsPhone: windowsPhone,
|
|
browser: {
|
|
current: browser$2.current,
|
|
version: browser$2.version,
|
|
isChrome: browser$2.isChrome,
|
|
isEdge: browser$2.isEdge,
|
|
isFirefox: browser$2.isFirefox,
|
|
isIE: browser$2.isIE,
|
|
isOpera: browser$2.isOpera,
|
|
isSafari: browser$2.isSafari
|
|
},
|
|
os: {
|
|
current: os.current,
|
|
version: os.version,
|
|
isAndroid: os.isAndroid,
|
|
isFreeBSD: os.isFreeBSD,
|
|
isiOS: os.isiOS,
|
|
isLinux: os.isLinux,
|
|
isOSX: os.isOSX,
|
|
isSolaris: os.isSolaris,
|
|
isWindows: os.isWindows
|
|
},
|
|
deviceType: {
|
|
isDesktop: deviceType.isDesktop,
|
|
isiPad: deviceType.isiPad,
|
|
isiPhone: deviceType.isiPhone,
|
|
isPhone: deviceType.isPhone,
|
|
isTablet: deviceType.isTablet,
|
|
isTouch: deviceType.isTouch,
|
|
isWebView: deviceType.isWebView
|
|
}
|
|
};
|
|
|
|
var isArray$1 = Array.isArray;
|
|
var toArray$1 = function (obj) {
|
|
var array = obj, i, l;
|
|
if (!isArray$1(obj)) {
|
|
array = [];
|
|
for (i = 0, l = obj.length; i < l; i++) {
|
|
array[i] = obj[i];
|
|
}
|
|
}
|
|
return array;
|
|
};
|
|
var each$2 = function (o, cb, s) {
|
|
var n, l;
|
|
if (!o) {
|
|
return 0;
|
|
}
|
|
s = s || o;
|
|
if (o.length !== undefined) {
|
|
for (n = 0, l = o.length; n < l; n++) {
|
|
if (cb.call(s, o[n], n, o) === false) {
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
for (n in o) {
|
|
if (o.hasOwnProperty(n)) {
|
|
if (cb.call(s, o[n], n, o) === false) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
};
|
|
var map$2 = function (array, callback) {
|
|
var out = [];
|
|
each$2(array, function (item, index) {
|
|
out.push(callback(item, index, array));
|
|
});
|
|
return out;
|
|
};
|
|
var filter$1 = function (a, f) {
|
|
var o = [];
|
|
each$2(a, function (v, index) {
|
|
if (!f || f(v, index, a)) {
|
|
o.push(v);
|
|
}
|
|
});
|
|
return o;
|
|
};
|
|
var indexOf$1 = function (a, v) {
|
|
var i, l;
|
|
if (a) {
|
|
for (i = 0, l = a.length; i < l; i++) {
|
|
if (a[i] === v) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
var reduce = function (collection, iteratee, accumulator, thisArg) {
|
|
var i = 0;
|
|
if (arguments.length < 3) {
|
|
accumulator = collection[0];
|
|
}
|
|
for (; i < collection.length; i++) {
|
|
accumulator = iteratee.call(thisArg, accumulator, collection[i], i);
|
|
}
|
|
return accumulator;
|
|
};
|
|
var findIndex$1 = function (array, predicate, thisArg) {
|
|
var i, l;
|
|
for (i = 0, l = array.length; i < l; i++) {
|
|
if (predicate.call(thisArg, array[i], i, array)) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
var find$2 = function (array, predicate, thisArg) {
|
|
var idx = findIndex$1(array, predicate, thisArg);
|
|
if (idx !== -1) {
|
|
return array[idx];
|
|
}
|
|
return undefined;
|
|
};
|
|
var last$1 = function (collection) {
|
|
return collection[collection.length - 1];
|
|
};
|
|
var ArrUtils = {
|
|
isArray: isArray$1,
|
|
toArray: toArray$1,
|
|
each: each$2,
|
|
map: map$2,
|
|
filter: filter$1,
|
|
indexOf: indexOf$1,
|
|
reduce: reduce,
|
|
findIndex: findIndex$1,
|
|
find: find$2,
|
|
last: last$1
|
|
};
|
|
|
|
var whiteSpaceRegExp = /^\s*|\s*$/g;
|
|
var trim$1 = function (str) {
|
|
return str === null || str === undefined ? '' : ('' + str).replace(whiteSpaceRegExp, '');
|
|
};
|
|
var is$1 = function (obj, type) {
|
|
if (!type) {
|
|
return obj !== undefined;
|
|
}
|
|
if (type === 'array' && ArrUtils.isArray(obj)) {
|
|
return true;
|
|
}
|
|
return typeof obj === type;
|
|
};
|
|
var makeMap = function (items, delim, map) {
|
|
var i;
|
|
items = items || [];
|
|
delim = delim || ',';
|
|
if (typeof items === 'string') {
|
|
items = items.split(delim);
|
|
}
|
|
map = map || {};
|
|
i = items.length;
|
|
while (i--) {
|
|
map[items[i]] = {};
|
|
}
|
|
return map;
|
|
};
|
|
var hasOwnProperty$1 = function (obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
};
|
|
var create = function (s, p, root) {
|
|
var self = this;
|
|
var sp, ns, cn, scn, c, de = 0;
|
|
s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
|
|
cn = s[3].match(/(^|\.)(\w+)$/i)[2];
|
|
ns = self.createNS(s[3].replace(/\.\w+$/, ''), root);
|
|
if (ns[cn]) {
|
|
return;
|
|
}
|
|
if (s[2] === 'static') {
|
|
ns[cn] = p;
|
|
if (this.onCreate) {
|
|
this.onCreate(s[2], s[3], ns[cn]);
|
|
}
|
|
return;
|
|
}
|
|
if (!p[cn]) {
|
|
p[cn] = function () {
|
|
};
|
|
de = 1;
|
|
}
|
|
ns[cn] = p[cn];
|
|
self.extend(ns[cn].prototype, p);
|
|
if (s[5]) {
|
|
sp = self.resolve(s[5]).prototype;
|
|
scn = s[5].match(/\.(\w+)$/i)[1];
|
|
c = ns[cn];
|
|
if (de) {
|
|
ns[cn] = function () {
|
|
return sp[scn].apply(this, arguments);
|
|
};
|
|
} else {
|
|
ns[cn] = function () {
|
|
this.parent = sp[scn];
|
|
return c.apply(this, arguments);
|
|
};
|
|
}
|
|
ns[cn].prototype[cn] = ns[cn];
|
|
self.each(sp, function (f, n) {
|
|
ns[cn].prototype[n] = sp[n];
|
|
});
|
|
self.each(p, function (f, n) {
|
|
if (sp[n]) {
|
|
ns[cn].prototype[n] = function () {
|
|
this.parent = sp[n];
|
|
return f.apply(this, arguments);
|
|
};
|
|
} else {
|
|
if (n !== cn) {
|
|
ns[cn].prototype[n] = f;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
self.each(p.static, function (f, n) {
|
|
ns[cn][n] = f;
|
|
});
|
|
};
|
|
var extend = function (obj, ext) {
|
|
var x = [];
|
|
for (var _i = 2; _i < arguments.length; _i++) {
|
|
x[_i - 2] = arguments[_i];
|
|
}
|
|
var i, l, name;
|
|
var args = arguments;
|
|
var value;
|
|
for (i = 1, l = args.length; i < l; i++) {
|
|
ext = args[i];
|
|
for (name in ext) {
|
|
if (ext.hasOwnProperty(name)) {
|
|
value = ext[name];
|
|
if (value !== undefined) {
|
|
obj[name] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
};
|
|
var walk = function (o, f, n, s) {
|
|
s = s || this;
|
|
if (o) {
|
|
if (n) {
|
|
o = o[n];
|
|
}
|
|
ArrUtils.each(o, function (o, i) {
|
|
if (f.call(s, o, i, n) === false) {
|
|
return false;
|
|
}
|
|
walk(o, f, n, s);
|
|
});
|
|
}
|
|
};
|
|
var createNS = function (n, o) {
|
|
var i, v;
|
|
o = o || domGlobals.window;
|
|
n = n.split('.');
|
|
for (i = 0; i < n.length; i++) {
|
|
v = n[i];
|
|
if (!o[v]) {
|
|
o[v] = {};
|
|
}
|
|
o = o[v];
|
|
}
|
|
return o;
|
|
};
|
|
var resolve = function (n, o) {
|
|
var i, l;
|
|
o = o || domGlobals.window;
|
|
n = n.split('.');
|
|
for (i = 0, l = n.length; i < l; i++) {
|
|
o = o[n[i]];
|
|
if (!o) {
|
|
break;
|
|
}
|
|
}
|
|
return o;
|
|
};
|
|
var explode = function (s, d) {
|
|
if (!s || is$1(s, 'array')) {
|
|
return s;
|
|
}
|
|
return ArrUtils.map(s.split(d || ','), trim$1);
|
|
};
|
|
var _addCacheSuffix = function (url) {
|
|
var cacheSuffix = Env.cacheSuffix;
|
|
if (cacheSuffix) {
|
|
url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
|
|
}
|
|
return url;
|
|
};
|
|
var Tools = {
|
|
trim: trim$1,
|
|
isArray: ArrUtils.isArray,
|
|
is: is$1,
|
|
toArray: ArrUtils.toArray,
|
|
makeMap: makeMap,
|
|
each: ArrUtils.each,
|
|
map: ArrUtils.map,
|
|
grep: ArrUtils.filter,
|
|
inArray: ArrUtils.indexOf,
|
|
hasOwn: hasOwnProperty$1,
|
|
extend: extend,
|
|
create: create,
|
|
walk: walk,
|
|
createNS: createNS,
|
|
resolve: resolve,
|
|
explode: explode,
|
|
_addCacheSuffix: _addCacheSuffix
|
|
};
|
|
|
|
function StyleSheetLoader(document, settings) {
|
|
if (settings === void 0) {
|
|
settings = {};
|
|
}
|
|
var idCount = 0;
|
|
var loadedStates = {};
|
|
var maxLoadTime;
|
|
maxLoadTime = settings.maxLoadTime || 5000;
|
|
var _setReferrerPolicy = function (referrerPolicy) {
|
|
settings.referrerPolicy = referrerPolicy;
|
|
};
|
|
var appendToHead = function (node) {
|
|
document.getElementsByTagName('head')[0].appendChild(node);
|
|
};
|
|
var load = function (url, loadedCallback, errorCallback) {
|
|
var link, style, startTime, state;
|
|
var resolve = function (status) {
|
|
state.status = status;
|
|
state.passed = [];
|
|
state.failed = [];
|
|
if (link) {
|
|
link.onload = null;
|
|
link.onerror = null;
|
|
link = null;
|
|
}
|
|
};
|
|
var passed = function () {
|
|
var callbacks = state.passed;
|
|
var i = callbacks.length;
|
|
while (i--) {
|
|
callbacks[i]();
|
|
}
|
|
resolve(2);
|
|
};
|
|
var failed = function () {
|
|
var callbacks = state.failed;
|
|
var i = callbacks.length;
|
|
while (i--) {
|
|
callbacks[i]();
|
|
}
|
|
resolve(3);
|
|
};
|
|
var isOldWebKit = function () {
|
|
var webKitChunks = domGlobals.navigator.userAgent.match(/WebKit\/(\d*)/);
|
|
return !!(webKitChunks && parseInt(webKitChunks[1], 10) < 536);
|
|
};
|
|
var wait = function (testCallback, waitCallback) {
|
|
if (!testCallback()) {
|
|
if (new Date().getTime() - startTime < maxLoadTime) {
|
|
Delay.setTimeout(waitCallback);
|
|
} else {
|
|
failed();
|
|
}
|
|
}
|
|
};
|
|
var waitForWebKitLinkLoaded = function () {
|
|
wait(function () {
|
|
var styleSheets = document.styleSheets;
|
|
var styleSheet, i = styleSheets.length, owner;
|
|
while (i--) {
|
|
styleSheet = styleSheets[i];
|
|
owner = styleSheet.ownerNode ? styleSheet.ownerNode : styleSheet.owningElement;
|
|
if (owner && owner.id === link.id) {
|
|
passed();
|
|
return true;
|
|
}
|
|
}
|
|
}, waitForWebKitLinkLoaded);
|
|
};
|
|
var waitForGeckoLinkLoaded = function () {
|
|
wait(function () {
|
|
try {
|
|
var cssRules = style.sheet.cssRules;
|
|
passed();
|
|
return !!cssRules;
|
|
} catch (ex) {
|
|
}
|
|
}, waitForGeckoLinkLoaded);
|
|
};
|
|
url = Tools._addCacheSuffix(url);
|
|
if (!loadedStates[url]) {
|
|
state = {
|
|
passed: [],
|
|
failed: []
|
|
};
|
|
loadedStates[url] = state;
|
|
} else {
|
|
state = loadedStates[url];
|
|
}
|
|
if (loadedCallback) {
|
|
state.passed.push(loadedCallback);
|
|
}
|
|
if (errorCallback) {
|
|
state.failed.push(errorCallback);
|
|
}
|
|
if (state.status === 1) {
|
|
return;
|
|
}
|
|
if (state.status === 2) {
|
|
passed();
|
|
return;
|
|
}
|
|
if (state.status === 3) {
|
|
failed();
|
|
return;
|
|
}
|
|
state.status = 1;
|
|
link = document.createElement('link');
|
|
link.rel = 'stylesheet';
|
|
link.type = 'text/css';
|
|
link.id = 'u' + idCount++;
|
|
link.async = false;
|
|
link.defer = false;
|
|
startTime = new Date().getTime();
|
|
if (settings.contentCssCors) {
|
|
link.crossOrigin = 'anonymous';
|
|
}
|
|
if (settings.referrerPolicy) {
|
|
set(Element.fromDom(link), 'referrerpolicy', settings.referrerPolicy);
|
|
}
|
|
if ('onload' in link && !isOldWebKit()) {
|
|
link.onload = waitForWebKitLinkLoaded;
|
|
link.onerror = failed;
|
|
} else {
|
|
if (domGlobals.navigator.userAgent.indexOf('Firefox') > 0) {
|
|
style = document.createElement('style');
|
|
style.textContent = '@import "' + url + '"';
|
|
waitForGeckoLinkLoaded();
|
|
appendToHead(style);
|
|
return;
|
|
}
|
|
waitForWebKitLinkLoaded();
|
|
}
|
|
appendToHead(link);
|
|
link.href = url;
|
|
};
|
|
var loadF = function (url) {
|
|
return Future.nu(function (resolve) {
|
|
load(url, compose(resolve, constant(Result.value(url))), compose(resolve, constant(Result.error(url))));
|
|
});
|
|
};
|
|
var unbox = function (result) {
|
|
return result.fold(identity, identity);
|
|
};
|
|
var loadAll = function (urls, success, failure) {
|
|
par$1(map(urls, loadF)).get(function (result) {
|
|
var parts = partition(result, function (r) {
|
|
return r.isValue();
|
|
});
|
|
if (parts.fail.length > 0) {
|
|
failure(parts.fail.map(unbox));
|
|
} else {
|
|
success(parts.pass.map(unbox));
|
|
}
|
|
});
|
|
};
|
|
return {
|
|
load: load,
|
|
loadAll: loadAll,
|
|
_setReferrerPolicy: _setReferrerPolicy
|
|
};
|
|
}
|
|
|
|
var blocks = [
|
|
'article',
|
|
'aside',
|
|
'details',
|
|
'div',
|
|
'dt',
|
|
'figcaption',
|
|
'footer',
|
|
'form',
|
|
'fieldset',
|
|
'header',
|
|
'hgroup',
|
|
'html',
|
|
'main',
|
|
'nav',
|
|
'section',
|
|
'summary',
|
|
'body',
|
|
'p',
|
|
'dl',
|
|
'multicol',
|
|
'dd',
|
|
'figure',
|
|
'address',
|
|
'center',
|
|
'blockquote',
|
|
'h1',
|
|
'h2',
|
|
'h3',
|
|
'h4',
|
|
'h5',
|
|
'h6',
|
|
'listing',
|
|
'xmp',
|
|
'pre',
|
|
'plaintext',
|
|
'menu',
|
|
'dir',
|
|
'ul',
|
|
'ol',
|
|
'li',
|
|
'hr',
|
|
'table',
|
|
'tbody',
|
|
'thead',
|
|
'tfoot',
|
|
'th',
|
|
'tr',
|
|
'td',
|
|
'caption'
|
|
];
|
|
var voids = [
|
|
'area',
|
|
'base',
|
|
'basefont',
|
|
'br',
|
|
'col',
|
|
'frame',
|
|
'hr',
|
|
'img',
|
|
'input',
|
|
'isindex',
|
|
'link',
|
|
'meta',
|
|
'param',
|
|
'embed',
|
|
'source',
|
|
'wbr',
|
|
'track'
|
|
];
|
|
var tableCells = [
|
|
'td',
|
|
'th'
|
|
];
|
|
var tableSections = [
|
|
'thead',
|
|
'tbody',
|
|
'tfoot'
|
|
];
|
|
var textBlocks = [
|
|
'h1',
|
|
'h2',
|
|
'h3',
|
|
'h4',
|
|
'h5',
|
|
'h6',
|
|
'p',
|
|
'div',
|
|
'address',
|
|
'pre',
|
|
'form',
|
|
'blockquote',
|
|
'center',
|
|
'dir',
|
|
'fieldset',
|
|
'header',
|
|
'footer',
|
|
'article',
|
|
'section',
|
|
'hgroup',
|
|
'aside',
|
|
'nav',
|
|
'figure'
|
|
];
|
|
var headings = [
|
|
'h1',
|
|
'h2',
|
|
'h3',
|
|
'h4',
|
|
'h5',
|
|
'h6'
|
|
];
|
|
var listItems = [
|
|
'li',
|
|
'dd',
|
|
'dt'
|
|
];
|
|
var lists = [
|
|
'ul',
|
|
'ol',
|
|
'dl'
|
|
];
|
|
var wsElements = [
|
|
'pre',
|
|
'script',
|
|
'textarea',
|
|
'style'
|
|
];
|
|
var lazyLookup = function (items) {
|
|
var lookup;
|
|
return function (node) {
|
|
lookup = lookup ? lookup : mapToObject(items, constant(true));
|
|
return lookup.hasOwnProperty(name(node));
|
|
};
|
|
};
|
|
var isHeading = lazyLookup(headings);
|
|
var isBlock = lazyLookup(blocks);
|
|
var isTable$1 = function (node) {
|
|
return name(node) === 'table';
|
|
};
|
|
var isInline = function (node) {
|
|
return isElement$1(node) && !isBlock(node);
|
|
};
|
|
var isBr$1 = function (node) {
|
|
return isElement$1(node) && name(node) === 'br';
|
|
};
|
|
var isTextBlock = lazyLookup(textBlocks);
|
|
var isList = lazyLookup(lists);
|
|
var isListItem = lazyLookup(listItems);
|
|
var isVoid = lazyLookup(voids);
|
|
var isTableSection = lazyLookup(tableSections);
|
|
var isTableCell = lazyLookup(tableCells);
|
|
var isWsPreserveElement = lazyLookup(wsElements);
|
|
|
|
var surroundedBySpans = function (node) {
|
|
var previousIsSpan = node.previousSibling && node.previousSibling.nodeName === 'SPAN';
|
|
var nextIsSpan = node.nextSibling && node.nextSibling.nodeName === 'SPAN';
|
|
return previousIsSpan && nextIsSpan;
|
|
};
|
|
var isBookmarkNode = function (node) {
|
|
return node && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
|
|
};
|
|
var trimNode = function (dom, node) {
|
|
var i, children = node.childNodes;
|
|
if (NodeType.isElement(node) && isBookmarkNode(node)) {
|
|
return;
|
|
}
|
|
for (i = children.length - 1; i >= 0; i--) {
|
|
trimNode(dom, children[i]);
|
|
}
|
|
if (NodeType.isDocument(node) === false) {
|
|
if (NodeType.isText(node) && node.nodeValue.length > 0) {
|
|
var trimmedLength = Tools.trim(node.nodeValue).length;
|
|
if (dom.isBlock(node.parentNode) || trimmedLength > 0) {
|
|
return;
|
|
}
|
|
if (trimmedLength === 0 && surroundedBySpans(node)) {
|
|
return;
|
|
}
|
|
} else if (NodeType.isElement(node)) {
|
|
children = node.childNodes;
|
|
if (children.length === 1 && isBookmarkNode(children[0])) {
|
|
node.parentNode.insertBefore(children[0], node);
|
|
}
|
|
if (children.length || isVoid(Element.fromDom(node))) {
|
|
return;
|
|
}
|
|
}
|
|
dom.remove(node);
|
|
}
|
|
return node;
|
|
};
|
|
var TrimNode = { trimNode: trimNode };
|
|
|
|
var makeMap$1 = Tools.makeMap;
|
|
var namedEntities, baseEntities, reverseEntities;
|
|
var attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
var textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
var rawCharsRegExp = /[<>&\"\']/g;
|
|
var entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
|
|
var asciiMap = {
|
|
128: '\u20AC',
|
|
130: '\u201A',
|
|
131: '\u0192',
|
|
132: '\u201E',
|
|
133: '\u2026',
|
|
134: '\u2020',
|
|
135: '\u2021',
|
|
136: '\u02c6',
|
|
137: '\u2030',
|
|
138: '\u0160',
|
|
139: '\u2039',
|
|
140: '\u0152',
|
|
142: '\u017d',
|
|
145: '\u2018',
|
|
146: '\u2019',
|
|
147: '\u201C',
|
|
148: '\u201D',
|
|
149: '\u2022',
|
|
150: '\u2013',
|
|
151: '\u2014',
|
|
152: '\u02DC',
|
|
153: '\u2122',
|
|
154: '\u0161',
|
|
155: '\u203A',
|
|
156: '\u0153',
|
|
158: '\u017e',
|
|
159: '\u0178'
|
|
};
|
|
baseEntities = {
|
|
'"': '"',
|
|
'\'': ''',
|
|
'<': '<',
|
|
'>': '>',
|
|
'&': '&',
|
|
'`': '`'
|
|
};
|
|
reverseEntities = {
|
|
'<': '<',
|
|
'>': '>',
|
|
'&': '&',
|
|
'"': '"',
|
|
''': '\''
|
|
};
|
|
var nativeDecode = function (text) {
|
|
var elm;
|
|
elm = Element.fromTag('div').dom();
|
|
elm.innerHTML = text;
|
|
return elm.textContent || elm.innerText || text;
|
|
};
|
|
var buildEntitiesLookup = function (items, radix) {
|
|
var i, chr, entity;
|
|
var lookup = {};
|
|
if (items) {
|
|
items = items.split(',');
|
|
radix = radix || 10;
|
|
for (i = 0; i < items.length; i += 2) {
|
|
chr = String.fromCharCode(parseInt(items[i], radix));
|
|
if (!baseEntities[chr]) {
|
|
entity = '&' + items[i + 1] + ';';
|
|
lookup[chr] = entity;
|
|
lookup[entity] = chr;
|
|
}
|
|
}
|
|
return lookup;
|
|
}
|
|
};
|
|
namedEntities = buildEntitiesLookup('50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
|
|
var encodeRaw = function (text, attr) {
|
|
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
|
|
return baseEntities[chr] || chr;
|
|
});
|
|
};
|
|
var encodeAllRaw = function (text) {
|
|
return ('' + text).replace(rawCharsRegExp, function (chr) {
|
|
return baseEntities[chr] || chr;
|
|
});
|
|
};
|
|
var encodeNumeric = function (text, attr) {
|
|
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
|
|
if (chr.length > 1) {
|
|
return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
|
|
}
|
|
return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
|
|
});
|
|
};
|
|
var encodeNamed = function (text, attr, entities) {
|
|
entities = entities || namedEntities;
|
|
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
|
|
return baseEntities[chr] || entities[chr] || chr;
|
|
});
|
|
};
|
|
var getEncodeFunc = function (name, entities) {
|
|
var entitiesMap = buildEntitiesLookup(entities) || namedEntities;
|
|
var encodeNamedAndNumeric = function (text, attr) {
|
|
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function (chr) {
|
|
if (baseEntities[chr] !== undefined) {
|
|
return baseEntities[chr];
|
|
}
|
|
if (entitiesMap[chr] !== undefined) {
|
|
return entitiesMap[chr];
|
|
}
|
|
if (chr.length > 1) {
|
|
return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
|
|
}
|
|
return '&#' + chr.charCodeAt(0) + ';';
|
|
});
|
|
};
|
|
var encodeCustomNamed = function (text, attr) {
|
|
return encodeNamed(text, attr, entitiesMap);
|
|
};
|
|
var nameMap = makeMap$1(name.replace(/\+/g, ','));
|
|
if (nameMap.named && nameMap.numeric) {
|
|
return encodeNamedAndNumeric;
|
|
}
|
|
if (nameMap.named) {
|
|
if (entities) {
|
|
return encodeCustomNamed;
|
|
}
|
|
return encodeNamed;
|
|
}
|
|
if (nameMap.numeric) {
|
|
return encodeNumeric;
|
|
}
|
|
return encodeRaw;
|
|
};
|
|
var decode = function (text) {
|
|
return text.replace(entityRegExp, function (all, numeric) {
|
|
if (numeric) {
|
|
if (numeric.charAt(0).toLowerCase() === 'x') {
|
|
numeric = parseInt(numeric.substr(1), 16);
|
|
} else {
|
|
numeric = parseInt(numeric, 10);
|
|
}
|
|
if (numeric > 65535) {
|
|
numeric -= 65536;
|
|
return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
|
|
}
|
|
return asciiMap[numeric] || String.fromCharCode(numeric);
|
|
}
|
|
return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
|
|
});
|
|
};
|
|
var Entities = {
|
|
encodeRaw: encodeRaw,
|
|
encodeAllRaw: encodeAllRaw,
|
|
encodeNumeric: encodeNumeric,
|
|
encodeNamed: encodeNamed,
|
|
getEncodeFunc: getEncodeFunc,
|
|
decode: decode
|
|
};
|
|
|
|
var mapCache = {}, dummyObj = {};
|
|
var makeMap$2 = Tools.makeMap, each$3 = Tools.each, extend$1 = Tools.extend, explode$1 = Tools.explode, inArray = Tools.inArray;
|
|
var split = function (items, delim) {
|
|
items = Tools.trim(items);
|
|
return items ? items.split(delim || ' ') : [];
|
|
};
|
|
var compileSchema = function (type) {
|
|
var schema = {};
|
|
var globalAttributes, blockContent;
|
|
var phrasingContent, flowContent, html4BlockContent, html4PhrasingContent;
|
|
var add = function (name, attributes, children) {
|
|
var ni, attributesOrder, element;
|
|
var arrayToMap = function (array, obj) {
|
|
var map = {};
|
|
var i, l;
|
|
for (i = 0, l = array.length; i < l; i++) {
|
|
map[array[i]] = obj || {};
|
|
}
|
|
return map;
|
|
};
|
|
children = children || [];
|
|
attributes = attributes || '';
|
|
if (typeof children === 'string') {
|
|
children = split(children);
|
|
}
|
|
name = split(name);
|
|
ni = name.length;
|
|
while (ni--) {
|
|
attributesOrder = split([
|
|
globalAttributes,
|
|
attributes
|
|
].join(' '));
|
|
element = {
|
|
attributes: arrayToMap(attributesOrder),
|
|
attributesOrder: attributesOrder,
|
|
children: arrayToMap(children, dummyObj)
|
|
};
|
|
schema[name[ni]] = element;
|
|
}
|
|
};
|
|
var addAttrs = function (name, attributes) {
|
|
var ni, schemaItem, i, l;
|
|
name = split(name);
|
|
ni = name.length;
|
|
attributes = split(attributes);
|
|
while (ni--) {
|
|
schemaItem = schema[name[ni]];
|
|
for (i = 0, l = attributes.length; i < l; i++) {
|
|
schemaItem.attributes[attributes[i]] = {};
|
|
schemaItem.attributesOrder.push(attributes[i]);
|
|
}
|
|
}
|
|
};
|
|
if (mapCache[type]) {
|
|
return mapCache[type];
|
|
}
|
|
globalAttributes = 'id accesskey class dir lang style tabindex title role';
|
|
blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
|
|
phrasingContent = 'a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd ' + 'label map noscript object q s samp script select small span strong sub sup ' + 'textarea u var #text #comment';
|
|
if (type !== 'html4') {
|
|
globalAttributes += ' contenteditable contextmenu draggable dropzone ' + 'hidden spellcheck translate';
|
|
blockContent += ' article aside details dialog figure main header footer hgroup section nav';
|
|
phrasingContent += ' audio canvas command datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen';
|
|
}
|
|
if (type !== 'html5-strict') {
|
|
globalAttributes += ' xml:lang';
|
|
html4PhrasingContent = 'acronym applet basefont big font strike tt';
|
|
phrasingContent = [
|
|
phrasingContent,
|
|
html4PhrasingContent
|
|
].join(' ');
|
|
each$3(split(html4PhrasingContent), function (name) {
|
|
add(name, '', phrasingContent);
|
|
});
|
|
html4BlockContent = 'center dir isindex noframes';
|
|
blockContent = [
|
|
blockContent,
|
|
html4BlockContent
|
|
].join(' ');
|
|
flowContent = [
|
|
blockContent,
|
|
phrasingContent
|
|
].join(' ');
|
|
each$3(split(html4BlockContent), function (name) {
|
|
add(name, '', flowContent);
|
|
});
|
|
}
|
|
flowContent = flowContent || [
|
|
blockContent,
|
|
phrasingContent
|
|
].join(' ');
|
|
add('html', 'manifest', 'head body');
|
|
add('head', '', 'base command link meta noscript script style title');
|
|
add('title hr noscript br');
|
|
add('base', 'href target');
|
|
add('link', 'href rel media hreflang type sizes hreflang');
|
|
add('meta', 'name http-equiv content charset');
|
|
add('style', 'media type scoped');
|
|
add('script', 'src async defer type charset');
|
|
add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
|
|
add('address dt dd div caption', '', flowContent);
|
|
add('h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent);
|
|
add('blockquote', 'cite', flowContent);
|
|
add('ol', 'reversed start type', 'li');
|
|
add('ul', '', 'li');
|
|
add('li', 'value', flowContent);
|
|
add('dl', '', 'dt dd');
|
|
add('a', 'href target rel media hreflang type', phrasingContent);
|
|
add('q', 'cite', phrasingContent);
|
|
add('ins del', 'cite datetime', flowContent);
|
|
add('img', 'src sizes srcset alt usemap ismap width height');
|
|
add('iframe', 'src name width height', flowContent);
|
|
add('embed', 'src type width height');
|
|
add('object', 'data type typemustmatch name usemap form width height', [
|
|
flowContent,
|
|
'param'
|
|
].join(' '));
|
|
add('param', 'name value');
|
|
add('map', 'name', [
|
|
flowContent,
|
|
'area'
|
|
].join(' '));
|
|
add('area', 'alt coords shape href target rel media hreflang type');
|
|
add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
|
|
add('colgroup', 'span', 'col');
|
|
add('col', 'span');
|
|
add('tbody thead tfoot', '', 'tr');
|
|
add('tr', '', 'td th');
|
|
add('td', 'colspan rowspan headers', flowContent);
|
|
add('th', 'colspan rowspan headers scope abbr', flowContent);
|
|
add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
|
|
add('fieldset', 'disabled form name', [
|
|
flowContent,
|
|
'legend'
|
|
].join(' '));
|
|
add('label', 'form for', phrasingContent);
|
|
add('input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' + 'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width');
|
|
add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
|
|
add('select', 'disabled form multiple name required size', 'option optgroup');
|
|
add('optgroup', 'disabled label', 'option');
|
|
add('option', 'disabled label selected value');
|
|
add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
|
|
add('menu', 'type label', [
|
|
flowContent,
|
|
'li'
|
|
].join(' '));
|
|
add('noscript', '', flowContent);
|
|
if (type !== 'html4') {
|
|
add('wbr');
|
|
add('ruby', '', [
|
|
phrasingContent,
|
|
'rt rp'
|
|
].join(' '));
|
|
add('figcaption', '', flowContent);
|
|
add('mark rt rp summary bdi', '', phrasingContent);
|
|
add('canvas', 'width height', flowContent);
|
|
add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
|
|
flowContent,
|
|
'track source'
|
|
].join(' '));
|
|
add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
|
|
flowContent,
|
|
'track source'
|
|
].join(' '));
|
|
add('picture', '', 'img source');
|
|
add('source', 'src srcset type media sizes');
|
|
add('track', 'kind src srclang label default');
|
|
add('datalist', '', [
|
|
phrasingContent,
|
|
'option'
|
|
].join(' '));
|
|
add('article section nav aside main header footer', '', flowContent);
|
|
add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
|
|
add('figure', '', [
|
|
flowContent,
|
|
'figcaption'
|
|
].join(' '));
|
|
add('time', 'datetime', phrasingContent);
|
|
add('dialog', 'open', flowContent);
|
|
add('command', 'type label icon disabled checked radiogroup command');
|
|
add('output', 'for form name', phrasingContent);
|
|
add('progress', 'value max', phrasingContent);
|
|
add('meter', 'value min max low high optimum', phrasingContent);
|
|
add('details', 'open', [
|
|
flowContent,
|
|
'summary'
|
|
].join(' '));
|
|
add('keygen', 'autofocus challenge disabled form keytype name');
|
|
}
|
|
if (type !== 'html5-strict') {
|
|
addAttrs('script', 'language xml:space');
|
|
addAttrs('style', 'xml:space');
|
|
addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
|
|
addAttrs('embed', 'align name hspace vspace');
|
|
addAttrs('param', 'valuetype type');
|
|
addAttrs('a', 'charset name rev shape coords');
|
|
addAttrs('br', 'clear');
|
|
addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
|
|
addAttrs('img', 'name longdesc align border hspace vspace');
|
|
addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
|
|
addAttrs('font basefont', 'size color face');
|
|
addAttrs('input', 'usemap align');
|
|
addAttrs('select', 'onchange');
|
|
addAttrs('textarea');
|
|
addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
|
|
addAttrs('ul', 'type compact');
|
|
addAttrs('li', 'type');
|
|
addAttrs('ol dl menu dir', 'compact');
|
|
addAttrs('pre', 'width xml:space');
|
|
addAttrs('hr', 'align noshade size width');
|
|
addAttrs('isindex', 'prompt');
|
|
addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
|
|
addAttrs('col', 'width align char charoff valign');
|
|
addAttrs('colgroup', 'width align char charoff valign');
|
|
addAttrs('thead', 'align char charoff valign');
|
|
addAttrs('tr', 'align char charoff valign bgcolor');
|
|
addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
|
|
addAttrs('form', 'accept');
|
|
addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
|
|
addAttrs('tfoot', 'align char charoff valign');
|
|
addAttrs('tbody', 'align char charoff valign');
|
|
addAttrs('area', 'nohref');
|
|
addAttrs('body', 'background bgcolor text link vlink alink');
|
|
}
|
|
if (type !== 'html4') {
|
|
addAttrs('input button select textarea', 'autofocus');
|
|
addAttrs('input textarea', 'placeholder');
|
|
addAttrs('a', 'download');
|
|
addAttrs('link script img', 'crossorigin');
|
|
addAttrs('iframe', 'sandbox seamless allowfullscreen');
|
|
}
|
|
each$3(split('a form meter progress dfn'), function (name) {
|
|
if (schema[name]) {
|
|
delete schema[name].children[name];
|
|
}
|
|
});
|
|
delete schema.caption.children.table;
|
|
delete schema.script;
|
|
mapCache[type] = schema;
|
|
return schema;
|
|
};
|
|
var compileElementMap = function (value, mode) {
|
|
var styles;
|
|
if (value) {
|
|
styles = {};
|
|
if (typeof value === 'string') {
|
|
value = { '*': value };
|
|
}
|
|
each$3(value, function (value, key) {
|
|
styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$1(value, /[, ]/);
|
|
});
|
|
}
|
|
return styles;
|
|
};
|
|
function Schema(settings) {
|
|
var elements = {};
|
|
var children = {};
|
|
var patternElements = [];
|
|
var validStyles;
|
|
var invalidStyles;
|
|
var schemaItems;
|
|
var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap, validClasses;
|
|
var blockElementsMap, nonEmptyElementsMap, moveCaretBeforeOnEnterElementsMap, textBlockElementsMap, textInlineElementsMap;
|
|
var customElementsMap = {}, specialElements = {};
|
|
var createLookupTable = function (option, defaultValue, extendWith) {
|
|
var value = settings[option];
|
|
if (!value) {
|
|
value = mapCache[option];
|
|
if (!value) {
|
|
value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
|
|
value = extend$1(value, extendWith);
|
|
mapCache[option] = value;
|
|
}
|
|
} else {
|
|
value = makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
|
|
}
|
|
return value;
|
|
};
|
|
settings = settings || {};
|
|
schemaItems = compileSchema(settings.schema);
|
|
if (settings.verify_html === false) {
|
|
settings.valid_elements = '*[*]';
|
|
}
|
|
validStyles = compileElementMap(settings.valid_styles);
|
|
invalidStyles = compileElementMap(settings.invalid_styles, 'map');
|
|
validClasses = compileElementMap(settings.valid_classes, 'map');
|
|
whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
|
|
selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
|
|
shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
|
|
boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls');
|
|
nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object ' + 'script pre code', shortEndedElementsMap);
|
|
moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', 'table', nonEmptyElementsMap);
|
|
textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' + 'blockquote center dir fieldset header footer article section hgroup aside main nav figure');
|
|
blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' + 'th tr td li ol ul caption dl dt dd noscript menu isindex option ' + 'datalist select optgroup figcaption details summary', textBlockElementsMap);
|
|
textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font strike u var cite ' + 'dfn code mark q sup sub samp');
|
|
each$3((settings.special || 'script noscript noframes noembed title style textarea xmp').split(' '), function (name) {
|
|
specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
|
|
});
|
|
var patternToRegExp = function (str) {
|
|
return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
|
|
};
|
|
var addValidElements = function (validElements) {
|
|
var ei, el, ai, al, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder, prefix, outputName, globalAttributes, globalAttributesOrder, key, value;
|
|
var elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/, attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=:<]+)?(?:([=:<])(.*))?$/, hasPatternsRegExp = /[*?+]/;
|
|
if (validElements) {
|
|
validElements = split(validElements, ',');
|
|
if (elements['@']) {
|
|
globalAttributes = elements['@'].attributes;
|
|
globalAttributesOrder = elements['@'].attributesOrder;
|
|
}
|
|
for (ei = 0, el = validElements.length; ei < el; ei++) {
|
|
matches = elementRuleRegExp.exec(validElements[ei]);
|
|
if (matches) {
|
|
prefix = matches[1];
|
|
elementName = matches[2];
|
|
outputName = matches[3];
|
|
attrData = matches[5];
|
|
attributes = {};
|
|
attributesOrder = [];
|
|
element = {
|
|
attributes: attributes,
|
|
attributesOrder: attributesOrder
|
|
};
|
|
if (prefix === '#') {
|
|
element.paddEmpty = true;
|
|
}
|
|
if (prefix === '-') {
|
|
element.removeEmpty = true;
|
|
}
|
|
if (matches[4] === '!') {
|
|
element.removeEmptyAttrs = true;
|
|
}
|
|
if (globalAttributes) {
|
|
for (key in globalAttributes) {
|
|
attributes[key] = globalAttributes[key];
|
|
}
|
|
attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
|
|
}
|
|
if (attrData) {
|
|
attrData = split(attrData, '|');
|
|
for (ai = 0, al = attrData.length; ai < al; ai++) {
|
|
matches = attrRuleRegExp.exec(attrData[ai]);
|
|
if (matches) {
|
|
attr = {};
|
|
attrType = matches[1];
|
|
attrName = matches[2].replace(/[\\:]:/g, ':');
|
|
prefix = matches[3];
|
|
value = matches[4];
|
|
if (attrType === '!') {
|
|
element.attributesRequired = element.attributesRequired || [];
|
|
element.attributesRequired.push(attrName);
|
|
attr.required = true;
|
|
}
|
|
if (attrType === '-') {
|
|
delete attributes[attrName];
|
|
attributesOrder.splice(inArray(attributesOrder, attrName), 1);
|
|
continue;
|
|
}
|
|
if (prefix) {
|
|
if (prefix === '=') {
|
|
element.attributesDefault = element.attributesDefault || [];
|
|
element.attributesDefault.push({
|
|
name: attrName,
|
|
value: value
|
|
});
|
|
attr.defaultValue = value;
|
|
}
|
|
if (prefix === ':') {
|
|
element.attributesForced = element.attributesForced || [];
|
|
element.attributesForced.push({
|
|
name: attrName,
|
|
value: value
|
|
});
|
|
attr.forcedValue = value;
|
|
}
|
|
if (prefix === '<') {
|
|
attr.validValues = makeMap$2(value, '?');
|
|
}
|
|
}
|
|
if (hasPatternsRegExp.test(attrName)) {
|
|
element.attributePatterns = element.attributePatterns || [];
|
|
attr.pattern = patternToRegExp(attrName);
|
|
element.attributePatterns.push(attr);
|
|
} else {
|
|
if (!attributes[attrName]) {
|
|
attributesOrder.push(attrName);
|
|
}
|
|
attributes[attrName] = attr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!globalAttributes && elementName === '@') {
|
|
globalAttributes = attributes;
|
|
globalAttributesOrder = attributesOrder;
|
|
}
|
|
if (outputName) {
|
|
element.outputName = elementName;
|
|
elements[outputName] = element;
|
|
}
|
|
if (hasPatternsRegExp.test(elementName)) {
|
|
element.pattern = patternToRegExp(elementName);
|
|
patternElements.push(element);
|
|
} else {
|
|
elements[elementName] = element;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var setValidElements = function (validElements) {
|
|
elements = {};
|
|
patternElements = [];
|
|
addValidElements(validElements);
|
|
each$3(schemaItems, function (element, name) {
|
|
children[name] = element.children;
|
|
});
|
|
};
|
|
var addCustomElements = function (customElements) {
|
|
var customElementRegExp = /^(~)?(.+)$/;
|
|
if (customElements) {
|
|
mapCache.text_block_elements = mapCache.block_elements = null;
|
|
each$3(split(customElements, ','), function (rule) {
|
|
var matches = customElementRegExp.exec(rule), inline = matches[1] === '~', cloneName = inline ? 'span' : 'div', name = matches[2];
|
|
children[name] = children[cloneName];
|
|
customElementsMap[name] = cloneName;
|
|
if (!inline) {
|
|
blockElementsMap[name.toUpperCase()] = {};
|
|
blockElementsMap[name] = {};
|
|
}
|
|
if (!elements[name]) {
|
|
var customRule = elements[cloneName];
|
|
customRule = extend$1({}, customRule);
|
|
delete customRule.removeEmptyAttrs;
|
|
delete customRule.removeEmpty;
|
|
elements[name] = customRule;
|
|
}
|
|
each$3(children, function (element, elmName) {
|
|
if (element[cloneName]) {
|
|
children[elmName] = element = extend$1({}, children[elmName]);
|
|
element[name] = element[cloneName];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
var addValidChildren = function (validChildren) {
|
|
var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
|
|
mapCache[settings.schema] = null;
|
|
if (validChildren) {
|
|
each$3(split(validChildren, ','), function (rule) {
|
|
var matches = childRuleRegExp.exec(rule);
|
|
var parent, prefix;
|
|
if (matches) {
|
|
prefix = matches[1];
|
|
if (prefix) {
|
|
parent = children[matches[2]];
|
|
} else {
|
|
parent = children[matches[2]] = { '#comment': {} };
|
|
}
|
|
parent = children[matches[2]];
|
|
each$3(split(matches[3], '|'), function (child) {
|
|
if (prefix === '-') {
|
|
delete parent[child];
|
|
} else {
|
|
parent[child] = {};
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var getElementRule = function (name) {
|
|
var element = elements[name], i;
|
|
if (element) {
|
|
return element;
|
|
}
|
|
i = patternElements.length;
|
|
while (i--) {
|
|
element = patternElements[i];
|
|
if (element.pattern.test(name)) {
|
|
return element;
|
|
}
|
|
}
|
|
};
|
|
if (!settings.valid_elements) {
|
|
each$3(schemaItems, function (element, name) {
|
|
elements[name] = {
|
|
attributes: element.attributes,
|
|
attributesOrder: element.attributesOrder
|
|
};
|
|
children[name] = element.children;
|
|
});
|
|
if (settings.schema !== 'html5') {
|
|
each$3(split('strong/b em/i'), function (item) {
|
|
item = split(item, '/');
|
|
elements[item[1]].outputName = item[0];
|
|
});
|
|
}
|
|
each$3(split('ol ul sub sup blockquote span font a table tbody tr strong em b i'), function (name) {
|
|
if (elements[name]) {
|
|
elements[name].removeEmpty = true;
|
|
}
|
|
});
|
|
each$3(split('p h1 h2 h3 h4 h5 h6 th td pre div address caption li'), function (name) {
|
|
elements[name].paddEmpty = true;
|
|
});
|
|
each$3(split('span'), function (name) {
|
|
elements[name].removeEmptyAttrs = true;
|
|
});
|
|
} else {
|
|
setValidElements(settings.valid_elements);
|
|
}
|
|
addCustomElements(settings.custom_elements);
|
|
addValidChildren(settings.valid_children);
|
|
addValidElements(settings.extended_valid_elements);
|
|
addValidChildren('+ol[ul|ol],+ul[ul|ol]');
|
|
each$3({
|
|
dd: 'dl',
|
|
dt: 'dl',
|
|
li: 'ul ol',
|
|
td: 'tr',
|
|
th: 'tr',
|
|
tr: 'tbody thead tfoot',
|
|
tbody: 'table',
|
|
thead: 'table',
|
|
tfoot: 'table',
|
|
legend: 'fieldset',
|
|
area: 'map',
|
|
param: 'video audio object'
|
|
}, function (parents, item) {
|
|
if (elements[item]) {
|
|
elements[item].parentsRequired = split(parents);
|
|
}
|
|
});
|
|
if (settings.invalid_elements) {
|
|
each$3(explode$1(settings.invalid_elements), function (item) {
|
|
if (elements[item]) {
|
|
delete elements[item];
|
|
}
|
|
});
|
|
}
|
|
if (!getElementRule('span')) {
|
|
addValidElements('span[!data-mce-type|*]');
|
|
}
|
|
var getValidStyles = function () {
|
|
return validStyles;
|
|
};
|
|
var getInvalidStyles = function () {
|
|
return invalidStyles;
|
|
};
|
|
var getValidClasses = function () {
|
|
return validClasses;
|
|
};
|
|
var getBoolAttrs = function () {
|
|
return boolAttrMap;
|
|
};
|
|
var getBlockElements = function () {
|
|
return blockElementsMap;
|
|
};
|
|
var getTextBlockElements = function () {
|
|
return textBlockElementsMap;
|
|
};
|
|
var getTextInlineElements = function () {
|
|
return textInlineElementsMap;
|
|
};
|
|
var getShortEndedElements = function () {
|
|
return shortEndedElementsMap;
|
|
};
|
|
var getSelfClosingElements = function () {
|
|
return selfClosingElementsMap;
|
|
};
|
|
var getNonEmptyElements = function () {
|
|
return nonEmptyElementsMap;
|
|
};
|
|
var getMoveCaretBeforeOnEnterElements = function () {
|
|
return moveCaretBeforeOnEnterElementsMap;
|
|
};
|
|
var getWhiteSpaceElements = function () {
|
|
return whiteSpaceElementsMap;
|
|
};
|
|
var getSpecialElements = function () {
|
|
return specialElements;
|
|
};
|
|
var isValidChild = function (name, child) {
|
|
var parent = children[name.toLowerCase()];
|
|
return !!(parent && parent[child.toLowerCase()]);
|
|
};
|
|
var isValid = function (name, attr) {
|
|
var attrPatterns, i;
|
|
var rule = getElementRule(name);
|
|
if (rule) {
|
|
if (attr) {
|
|
if (rule.attributes[attr]) {
|
|
return true;
|
|
}
|
|
attrPatterns = rule.attributePatterns;
|
|
if (attrPatterns) {
|
|
i = attrPatterns.length;
|
|
while (i--) {
|
|
if (attrPatterns[i].pattern.test(name)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var getCustomElements = function () {
|
|
return customElementsMap;
|
|
};
|
|
return {
|
|
children: children,
|
|
elements: elements,
|
|
getValidStyles: getValidStyles,
|
|
getValidClasses: getValidClasses,
|
|
getBlockElements: getBlockElements,
|
|
getInvalidStyles: getInvalidStyles,
|
|
getShortEndedElements: getShortEndedElements,
|
|
getTextBlockElements: getTextBlockElements,
|
|
getTextInlineElements: getTextInlineElements,
|
|
getBoolAttrs: getBoolAttrs,
|
|
getElementRule: getElementRule,
|
|
getSelfClosingElements: getSelfClosingElements,
|
|
getNonEmptyElements: getNonEmptyElements,
|
|
getMoveCaretBeforeOnEnterElements: getMoveCaretBeforeOnEnterElements,
|
|
getWhiteSpaceElements: getWhiteSpaceElements,
|
|
getSpecialElements: getSpecialElements,
|
|
isValidChild: isValidChild,
|
|
isValid: isValid,
|
|
getCustomElements: getCustomElements,
|
|
addValidElements: addValidElements,
|
|
setValidElements: setValidElements,
|
|
addCustomElements: addCustomElements,
|
|
addValidChildren: addValidChildren
|
|
};
|
|
}
|
|
|
|
var toHex = function (match, r, g, b) {
|
|
var hex = function (val) {
|
|
val = parseInt(val, 10).toString(16);
|
|
return val.length > 1 ? val : '0' + val;
|
|
};
|
|
return '#' + hex(r) + hex(g) + hex(b);
|
|
};
|
|
var Styles = function (settings, schema) {
|
|
var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
|
|
var urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
|
|
var styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
|
|
var trimRightRegExp = /\s+$/;
|
|
var i;
|
|
var encodingLookup = {};
|
|
var encodingItems;
|
|
var validStyles;
|
|
var invalidStyles;
|
|
var invisibleChar = '\uFEFF';
|
|
settings = settings || {};
|
|
if (schema) {
|
|
validStyles = schema.getValidStyles();
|
|
invalidStyles = schema.getInvalidStyles();
|
|
}
|
|
encodingItems = ('\\" \\\' \\; \\: ; : ' + invisibleChar).split(' ');
|
|
for (i = 0; i < encodingItems.length; i++) {
|
|
encodingLookup[encodingItems[i]] = invisibleChar + i;
|
|
encodingLookup[invisibleChar + i] = encodingItems[i];
|
|
}
|
|
return {
|
|
toHex: function (color) {
|
|
return color.replace(rgbRegExp, toHex);
|
|
},
|
|
parse: function (css) {
|
|
var styles = {};
|
|
var matches, name, value, isEncoded;
|
|
var urlConverter = settings.url_converter;
|
|
var urlConverterScope = settings.url_converter_scope || this;
|
|
var compress = function (prefix, suffix, noJoin) {
|
|
var top, right, bottom, left;
|
|
top = styles[prefix + '-top' + suffix];
|
|
if (!top) {
|
|
return;
|
|
}
|
|
right = styles[prefix + '-right' + suffix];
|
|
if (!right) {
|
|
return;
|
|
}
|
|
bottom = styles[prefix + '-bottom' + suffix];
|
|
if (!bottom) {
|
|
return;
|
|
}
|
|
left = styles[prefix + '-left' + suffix];
|
|
if (!left) {
|
|
return;
|
|
}
|
|
var box = [
|
|
top,
|
|
right,
|
|
bottom,
|
|
left
|
|
];
|
|
i = box.length - 1;
|
|
while (i--) {
|
|
if (box[i] !== box[i + 1]) {
|
|
break;
|
|
}
|
|
}
|
|
if (i > -1 && noJoin) {
|
|
return;
|
|
}
|
|
styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
|
|
delete styles[prefix + '-top' + suffix];
|
|
delete styles[prefix + '-right' + suffix];
|
|
delete styles[prefix + '-bottom' + suffix];
|
|
delete styles[prefix + '-left' + suffix];
|
|
};
|
|
var canCompress = function (key) {
|
|
var value = styles[key], i;
|
|
if (!value) {
|
|
return;
|
|
}
|
|
value = value.split(' ');
|
|
i = value.length;
|
|
while (i--) {
|
|
if (value[i] !== value[0]) {
|
|
return false;
|
|
}
|
|
}
|
|
styles[key] = value[0];
|
|
return true;
|
|
};
|
|
var compress2 = function (target, a, b, c) {
|
|
if (!canCompress(a)) {
|
|
return;
|
|
}
|
|
if (!canCompress(b)) {
|
|
return;
|
|
}
|
|
if (!canCompress(c)) {
|
|
return;
|
|
}
|
|
styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
|
|
delete styles[a];
|
|
delete styles[b];
|
|
delete styles[c];
|
|
};
|
|
var encode = function (str) {
|
|
isEncoded = true;
|
|
return encodingLookup[str];
|
|
};
|
|
var decode = function (str, keepSlashes) {
|
|
if (isEncoded) {
|
|
str = str.replace(/\uFEFF[0-9]/g, function (str) {
|
|
return encodingLookup[str];
|
|
});
|
|
}
|
|
if (!keepSlashes) {
|
|
str = str.replace(/\\([\'\";:])/g, '$1');
|
|
}
|
|
return str;
|
|
};
|
|
var decodeSingleHexSequence = function (escSeq) {
|
|
return String.fromCharCode(parseInt(escSeq.slice(1), 16));
|
|
};
|
|
var decodeHexSequences = function (value) {
|
|
return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
|
|
};
|
|
var processUrl = function (match, url, url2, url3, str, str2) {
|
|
str = str || str2;
|
|
if (str) {
|
|
str = decode(str);
|
|
return '\'' + str.replace(/\'/g, '\\\'') + '\'';
|
|
}
|
|
url = decode(url || url2 || url3);
|
|
if (!settings.allow_script_urls) {
|
|
var scriptUrl = url.replace(/[\s\r\n]+/g, '');
|
|
if (/(java|vb)script:/i.test(scriptUrl)) {
|
|
return '';
|
|
}
|
|
if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
|
|
return '';
|
|
}
|
|
}
|
|
if (urlConverter) {
|
|
url = urlConverter.call(urlConverterScope, url, 'style');
|
|
}
|
|
return 'url(\'' + url.replace(/\'/g, '\\\'') + '\')';
|
|
};
|
|
if (css) {
|
|
css = css.replace(/[\u0000-\u001F]/g, '');
|
|
css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function (str) {
|
|
return str.replace(/[;:]/g, encode);
|
|
});
|
|
while (matches = styleRegExp.exec(css)) {
|
|
styleRegExp.lastIndex = matches.index + matches[0].length;
|
|
name = matches[1].replace(trimRightRegExp, '').toLowerCase();
|
|
value = matches[2].replace(trimRightRegExp, '');
|
|
if (name && value) {
|
|
name = decodeHexSequences(name);
|
|
value = decodeHexSequences(value);
|
|
if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
|
|
continue;
|
|
}
|
|
if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
|
|
continue;
|
|
}
|
|
if (name === 'font-weight' && value === '700') {
|
|
value = 'bold';
|
|
} else if (name === 'color' || name === 'background-color') {
|
|
value = value.toLowerCase();
|
|
}
|
|
value = value.replace(rgbRegExp, toHex);
|
|
value = value.replace(urlOrStrRegExp, processUrl);
|
|
styles[name] = isEncoded ? decode(value, true) : value;
|
|
}
|
|
}
|
|
compress('border', '', true);
|
|
compress('border', '-width');
|
|
compress('border', '-color');
|
|
compress('border', '-style');
|
|
compress('padding', '');
|
|
compress('margin', '');
|
|
compress2('border', 'border-width', 'border-style', 'border-color');
|
|
if (styles.border === 'medium none') {
|
|
delete styles.border;
|
|
}
|
|
if (styles['border-image'] === 'none') {
|
|
delete styles['border-image'];
|
|
}
|
|
}
|
|
return styles;
|
|
},
|
|
serialize: function (styles, elementName) {
|
|
var css = '', name, value;
|
|
var serializeStyles = function (name) {
|
|
var styleList, i, l, value;
|
|
styleList = validStyles[name];
|
|
if (styleList) {
|
|
for (i = 0, l = styleList.length; i < l; i++) {
|
|
name = styleList[i];
|
|
value = styles[name];
|
|
if (value) {
|
|
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var isValid = function (name, elementName) {
|
|
var styleMap;
|
|
styleMap = invalidStyles['*'];
|
|
if (styleMap && styleMap[name]) {
|
|
return false;
|
|
}
|
|
styleMap = invalidStyles[elementName];
|
|
if (styleMap && styleMap[name]) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
if (elementName && validStyles) {
|
|
serializeStyles('*');
|
|
serializeStyles(elementName);
|
|
} else {
|
|
for (name in styles) {
|
|
value = styles[name];
|
|
if (value && (!invalidStyles || isValid(name, elementName))) {
|
|
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
|
}
|
|
}
|
|
}
|
|
return css;
|
|
}
|
|
};
|
|
};
|
|
|
|
var eventExpandoPrefix = 'mce-data-';
|
|
var mouseEventRe = /^(?:mouse|contextmenu)|click/;
|
|
var deprecated = {
|
|
keyLocation: 1,
|
|
layerX: 1,
|
|
layerY: 1,
|
|
returnValue: 1,
|
|
webkitMovementX: 1,
|
|
webkitMovementY: 1,
|
|
keyIdentifier: 1,
|
|
mozPressure: 1
|
|
};
|
|
var hasIsDefaultPrevented = function (event) {
|
|
return event.isDefaultPrevented === returnTrue || event.isDefaultPrevented === returnFalse;
|
|
};
|
|
var returnFalse = function () {
|
|
return false;
|
|
};
|
|
var returnTrue = function () {
|
|
return true;
|
|
};
|
|
var addEvent = function (target, name, callback, capture) {
|
|
if (target.addEventListener) {
|
|
target.addEventListener(name, callback, capture || false);
|
|
} else if (target.attachEvent) {
|
|
target.attachEvent('on' + name, callback);
|
|
}
|
|
};
|
|
var removeEvent = function (target, name, callback, capture) {
|
|
if (target.removeEventListener) {
|
|
target.removeEventListener(name, callback, capture || false);
|
|
} else if (target.detachEvent) {
|
|
target.detachEvent('on' + name, callback);
|
|
}
|
|
};
|
|
var getTargetFromShadowDom = function (event, defaultTarget) {
|
|
if (event.composedPath) {
|
|
var composedPath = event.composedPath();
|
|
if (composedPath && composedPath.length > 0) {
|
|
return composedPath[0];
|
|
}
|
|
}
|
|
return defaultTarget;
|
|
};
|
|
var fix = function (originalEvent, data) {
|
|
var name;
|
|
var event = data || {};
|
|
for (name in originalEvent) {
|
|
if (!deprecated[name]) {
|
|
event[name] = originalEvent[name];
|
|
}
|
|
}
|
|
if (!event.target) {
|
|
event.target = event.srcElement || domGlobals.document;
|
|
}
|
|
if (Env.experimentalShadowDom) {
|
|
event.target = getTargetFromShadowDom(originalEvent, event.target);
|
|
}
|
|
if (originalEvent && mouseEventRe.test(originalEvent.type) && originalEvent.pageX === undefined && originalEvent.clientX !== undefined) {
|
|
var eventDoc = event.target.ownerDocument || domGlobals.document;
|
|
var doc = eventDoc.documentElement;
|
|
var body = eventDoc.body;
|
|
event.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
|
|
event.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
|
|
}
|
|
event.preventDefault = function () {
|
|
event.isDefaultPrevented = returnTrue;
|
|
if (originalEvent) {
|
|
if (originalEvent.preventDefault) {
|
|
originalEvent.preventDefault();
|
|
} else {
|
|
originalEvent.returnValue = false;
|
|
}
|
|
}
|
|
};
|
|
event.stopPropagation = function () {
|
|
event.isPropagationStopped = returnTrue;
|
|
if (originalEvent) {
|
|
if (originalEvent.stopPropagation) {
|
|
originalEvent.stopPropagation();
|
|
} else {
|
|
originalEvent.cancelBubble = true;
|
|
}
|
|
}
|
|
};
|
|
event.stopImmediatePropagation = function () {
|
|
event.isImmediatePropagationStopped = returnTrue;
|
|
event.stopPropagation();
|
|
};
|
|
if (hasIsDefaultPrevented(event) === false) {
|
|
event.isDefaultPrevented = returnFalse;
|
|
event.isPropagationStopped = returnFalse;
|
|
event.isImmediatePropagationStopped = returnFalse;
|
|
}
|
|
if (typeof event.metaKey === 'undefined') {
|
|
event.metaKey = false;
|
|
}
|
|
return event;
|
|
};
|
|
var bindOnReady = function (win, callback, eventUtils) {
|
|
var doc = win.document, event = { type: 'ready' };
|
|
if (eventUtils.domLoaded) {
|
|
callback(event);
|
|
return;
|
|
}
|
|
var isDocReady = function () {
|
|
return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
|
|
};
|
|
var readyHandler = function () {
|
|
removeEvent(win, 'DOMContentLoaded', readyHandler);
|
|
removeEvent(win, 'load', readyHandler);
|
|
if (!eventUtils.domLoaded) {
|
|
eventUtils.domLoaded = true;
|
|
callback(event);
|
|
}
|
|
};
|
|
if (isDocReady()) {
|
|
readyHandler();
|
|
} else {
|
|
addEvent(win, 'DOMContentLoaded', readyHandler);
|
|
}
|
|
addEvent(win, 'load', readyHandler);
|
|
};
|
|
var EventUtils = function () {
|
|
function EventUtils() {
|
|
this.domLoaded = false;
|
|
this.events = {};
|
|
this.count = 1;
|
|
this.expando = eventExpandoPrefix + (+new Date()).toString(32);
|
|
this.hasMouseEnterLeave = 'onmouseenter' in domGlobals.document.documentElement;
|
|
this.hasFocusIn = 'onfocusin' in domGlobals.document.documentElement;
|
|
this.count = 1;
|
|
}
|
|
EventUtils.prototype.bind = function (target, names, callback, scope) {
|
|
var self = this;
|
|
var id, callbackList, i, name, fakeName, nativeHandler, capture;
|
|
var win = domGlobals.window;
|
|
var defaultNativeHandler = function (evt) {
|
|
self.executeHandlers(fix(evt || win.event), id);
|
|
};
|
|
if (!target || target.nodeType === 3 || target.nodeType === 8) {
|
|
return;
|
|
}
|
|
if (!target[self.expando]) {
|
|
id = self.count++;
|
|
target[self.expando] = id;
|
|
self.events[id] = {};
|
|
} else {
|
|
id = target[self.expando];
|
|
}
|
|
scope = scope || target;
|
|
var namesList = names.split(' ');
|
|
i = namesList.length;
|
|
while (i--) {
|
|
name = namesList[i];
|
|
nativeHandler = defaultNativeHandler;
|
|
fakeName = capture = false;
|
|
if (name === 'DOMContentLoaded') {
|
|
name = 'ready';
|
|
}
|
|
if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
|
|
callback.call(scope, fix({ type: name }));
|
|
continue;
|
|
}
|
|
if (!self.hasMouseEnterLeave) {
|
|
fakeName = self.mouseEnterLeave[name];
|
|
if (fakeName) {
|
|
nativeHandler = function (evt) {
|
|
var current, related;
|
|
current = evt.currentTarget;
|
|
related = evt.relatedTarget;
|
|
if (related && current.contains) {
|
|
related = current.contains(related);
|
|
} else {
|
|
while (related && related !== current) {
|
|
related = related.parentNode;
|
|
}
|
|
}
|
|
if (!related) {
|
|
evt = fix(evt || win.event);
|
|
evt.type = evt.type === 'mouseout' ? 'mouseleave' : 'mouseenter';
|
|
evt.target = current;
|
|
self.executeHandlers(evt, id);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
|
|
capture = true;
|
|
fakeName = name === 'focusin' ? 'focus' : 'blur';
|
|
nativeHandler = function (evt) {
|
|
evt = fix(evt || win.event);
|
|
evt.type = evt.type === 'focus' ? 'focusin' : 'focusout';
|
|
self.executeHandlers(evt, id);
|
|
};
|
|
}
|
|
callbackList = self.events[id][name];
|
|
if (!callbackList) {
|
|
self.events[id][name] = callbackList = [{
|
|
func: callback,
|
|
scope: scope
|
|
}];
|
|
callbackList.fakeName = fakeName;
|
|
callbackList.capture = capture;
|
|
callbackList.nativeHandler = nativeHandler;
|
|
if (name === 'ready') {
|
|
bindOnReady(target, nativeHandler, self);
|
|
} else {
|
|
addEvent(target, fakeName || name, nativeHandler, capture);
|
|
}
|
|
} else {
|
|
if (name === 'ready' && self.domLoaded) {
|
|
callback(fix({ type: name }));
|
|
} else {
|
|
callbackList.push({
|
|
func: callback,
|
|
scope: scope
|
|
});
|
|
}
|
|
}
|
|
}
|
|
target = callbackList = 0;
|
|
return callback;
|
|
};
|
|
EventUtils.prototype.unbind = function (target, names, callback) {
|
|
var id, callbackList, i, ci, name, eventMap;
|
|
if (!target || target.nodeType === 3 || target.nodeType === 8) {
|
|
return this;
|
|
}
|
|
id = target[this.expando];
|
|
if (id) {
|
|
eventMap = this.events[id];
|
|
if (names) {
|
|
var namesList = names.split(' ');
|
|
i = namesList.length;
|
|
while (i--) {
|
|
name = namesList[i];
|
|
callbackList = eventMap[name];
|
|
if (callbackList) {
|
|
if (callback) {
|
|
ci = callbackList.length;
|
|
while (ci--) {
|
|
if (callbackList[ci].func === callback) {
|
|
var nativeHandler = callbackList.nativeHandler;
|
|
var fakeName = callbackList.fakeName, capture = callbackList.capture;
|
|
callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
|
|
callbackList.nativeHandler = nativeHandler;
|
|
callbackList.fakeName = fakeName;
|
|
callbackList.capture = capture;
|
|
eventMap[name] = callbackList;
|
|
}
|
|
}
|
|
}
|
|
if (!callback || callbackList.length === 0) {
|
|
delete eventMap[name];
|
|
removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (name in eventMap) {
|
|
callbackList = eventMap[name];
|
|
removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
|
|
}
|
|
eventMap = {};
|
|
}
|
|
for (name in eventMap) {
|
|
return this;
|
|
}
|
|
delete this.events[id];
|
|
try {
|
|
delete target[this.expando];
|
|
} catch (ex) {
|
|
target[this.expando] = null;
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
EventUtils.prototype.fire = function (target, name, args) {
|
|
var id;
|
|
if (!target || target.nodeType === 3 || target.nodeType === 8) {
|
|
return this;
|
|
}
|
|
var event = fix(null, args);
|
|
event.type = name;
|
|
event.target = target;
|
|
do {
|
|
id = target[this.expando];
|
|
if (id) {
|
|
this.executeHandlers(event, id);
|
|
}
|
|
target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
|
|
} while (target && !event.isPropagationStopped());
|
|
return this;
|
|
};
|
|
EventUtils.prototype.clean = function (target) {
|
|
var i, children;
|
|
if (!target || target.nodeType === 3 || target.nodeType === 8) {
|
|
return this;
|
|
}
|
|
if (target[this.expando]) {
|
|
this.unbind(target);
|
|
}
|
|
if (!target.getElementsByTagName) {
|
|
target = target.document;
|
|
}
|
|
if (target && target.getElementsByTagName) {
|
|
this.unbind(target);
|
|
children = target.getElementsByTagName('*');
|
|
i = children.length;
|
|
while (i--) {
|
|
target = children[i];
|
|
if (target[this.expando]) {
|
|
this.unbind(target);
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
EventUtils.prototype.destroy = function () {
|
|
this.events = {};
|
|
};
|
|
EventUtils.prototype.cancel = function (e) {
|
|
if (e) {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
}
|
|
return false;
|
|
};
|
|
EventUtils.prototype.executeHandlers = function (evt, id) {
|
|
var callbackList, i, l, callback;
|
|
var container = this.events[id];
|
|
callbackList = container && container[evt.type];
|
|
if (callbackList) {
|
|
for (i = 0, l = callbackList.length; i < l; i++) {
|
|
callback = callbackList[i];
|
|
if (callback && callback.func.call(callback.scope, evt) === false) {
|
|
evt.preventDefault();
|
|
}
|
|
if (evt.isImmediatePropagationStopped()) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
EventUtils.Event = new EventUtils();
|
|
return EventUtils;
|
|
}();
|
|
|
|
var i, support, Expr, getText, isXML, tokenize, compile, select, outermostContext, sortInput, hasDuplicate, setDocument, document, docElem, documentIsHTML, rbuggyQSA, rbuggyMatches, matches, contains$3, expando = 'sizzle' + -new Date(), preferredDoc = domGlobals.window.document, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), sortOrder = function (a, b) {
|
|
if (a === b) {
|
|
hasDuplicate = true;
|
|
}
|
|
return 0;
|
|
}, strundefined = typeof undefined, MAX_NEGATIVE = 1 << 31, hasOwn = {}.hasOwnProperty, arr = [], pop = arr.pop, push_native = arr.push, push = arr.push, slice = arr.slice, indexOf$2 = arr.indexOf || function (elem) {
|
|
var i = 0, len = this.length;
|
|
for (; i < len; i++) {
|
|
if (this[i] === elem) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}, booleans = 'checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped', whitespace = '[\\x20\\t\\r\\n\\f]', identifier = '(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+', attributes = '\\[' + whitespace + '*(' + identifier + ')(?:' + whitespace + '*([*^$|!~]?=)' + whitespace + '*(?:\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)"|(' + identifier + '))|)' + whitespace + '*\\]', pseudos = ':(' + identifier + ')(?:\\((' + '(\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)")|' + '((?:\\\\.|[^\\\\()[\\]]|' + attributes + ')*)|' + '.*' + ')\\)|)', rtrim = new RegExp('^' + whitespace + '+|((?:^|[^\\\\])(?:\\\\.)*)' + whitespace + '+$', 'g'), rcomma = new RegExp('^' + whitespace + '*,' + whitespace + '*'), rcombinators = new RegExp('^' + whitespace + '*([>+~]|' + whitespace + ')' + whitespace + '*'), rattributeQuotes = new RegExp('=' + whitespace + '*([^\\]\'"]*?)' + whitespace + '*\\]', 'g'), rpseudo = new RegExp(pseudos), ridentifier = new RegExp('^' + identifier + '$'), matchExpr = {
|
|
ID: new RegExp('^#(' + identifier + ')'),
|
|
CLASS: new RegExp('^\\.(' + identifier + ')'),
|
|
TAG: new RegExp('^(' + identifier + '|[*])'),
|
|
ATTR: new RegExp('^' + attributes),
|
|
PSEUDO: new RegExp('^' + pseudos),
|
|
CHILD: new RegExp('^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' + whitespace + '*(even|odd|(([+-]|)(\\d*)n|)' + whitespace + '*(?:([+-]|)' + whitespace + '*(\\d+)|))' + whitespace + '*\\)|)', 'i'),
|
|
bool: new RegExp('^(?:' + booleans + ')$', 'i'),
|
|
needsContext: new RegExp('^' + whitespace + '*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(' + whitespace + '*((?:-\\d)?\\d*)' + whitespace + '*\\)|)(?=[^-]|$)', 'i')
|
|
}, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rnative = /^[^{]+\{\s*\[native \w/, rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rsibling = /[+~]/, rescape = /'|\\/g, runescape = new RegExp('\\\\([\\da-f]{1,6}' + whitespace + '?|(' + whitespace + ')|.)', 'ig'), funescape = function (_, escaped, escapedWhitespace) {
|
|
var high = '0x' + escaped - 65536;
|
|
return high !== high || escapedWhitespace ? escaped : high < 0 ? String.fromCharCode(high + 65536) : String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320);
|
|
};
|
|
try {
|
|
push.apply(arr = slice.call(preferredDoc.childNodes), preferredDoc.childNodes);
|
|
arr[preferredDoc.childNodes.length].nodeType;
|
|
} catch (e) {
|
|
push = {
|
|
apply: arr.length ? function (target, els) {
|
|
push_native.apply(target, slice.call(els));
|
|
} : function (target, els) {
|
|
var j = target.length, i = 0;
|
|
while (target[j++] = els[i++]) {
|
|
}
|
|
target.length = j - 1;
|
|
}
|
|
};
|
|
}
|
|
var Sizzle = function (selector, context, results, seed) {
|
|
var match, elem, m, nodeType, i, groups, old, nid, newContext, newSelector;
|
|
if ((context ? context.ownerDocument || context : preferredDoc) !== document) {
|
|
setDocument(context);
|
|
}
|
|
context = context || document;
|
|
results = results || [];
|
|
if (!selector || typeof selector !== 'string') {
|
|
return results;
|
|
}
|
|
if ((nodeType = context.nodeType) !== 1 && nodeType !== 9) {
|
|
return [];
|
|
}
|
|
if (documentIsHTML && !seed) {
|
|
if (match = rquickExpr.exec(selector)) {
|
|
if (m = match[1]) {
|
|
if (nodeType === 9) {
|
|
elem = context.getElementById(m);
|
|
if (elem && elem.parentNode) {
|
|
if (elem.id === m) {
|
|
results.push(elem);
|
|
return results;
|
|
}
|
|
} else {
|
|
return results;
|
|
}
|
|
} else {
|
|
if (context.ownerDocument && (elem = context.ownerDocument.getElementById(m)) && contains$3(context, elem) && elem.id === m) {
|
|
results.push(elem);
|
|
return results;
|
|
}
|
|
}
|
|
} else if (match[2]) {
|
|
push.apply(results, context.getElementsByTagName(selector));
|
|
return results;
|
|
} else if ((m = match[3]) && support.getElementsByClassName) {
|
|
push.apply(results, context.getElementsByClassName(m));
|
|
return results;
|
|
}
|
|
}
|
|
if (support.qsa && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
|
|
nid = old = expando;
|
|
newContext = context;
|
|
newSelector = nodeType === 9 && selector;
|
|
if (nodeType === 1 && context.nodeName.toLowerCase() !== 'object') {
|
|
groups = tokenize(selector);
|
|
if (old = context.getAttribute('id')) {
|
|
nid = old.replace(rescape, '\\$&');
|
|
} else {
|
|
context.setAttribute('id', nid);
|
|
}
|
|
nid = '[id=\'' + nid + '\'] ';
|
|
i = groups.length;
|
|
while (i--) {
|
|
groups[i] = nid + toSelector(groups[i]);
|
|
}
|
|
newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
|
|
newSelector = groups.join(',');
|
|
}
|
|
if (newSelector) {
|
|
try {
|
|
push.apply(results, newContext.querySelectorAll(newSelector));
|
|
return results;
|
|
} catch (qsaError) {
|
|
} finally {
|
|
if (!old) {
|
|
context.removeAttribute('id');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return select(selector.replace(rtrim, '$1'), context, results, seed);
|
|
};
|
|
function createCache() {
|
|
var keys = [];
|
|
function cache(key, value) {
|
|
if (keys.push(key + ' ') > Expr.cacheLength) {
|
|
delete cache[keys.shift()];
|
|
}
|
|
return cache[key + ' '] = value;
|
|
}
|
|
return cache;
|
|
}
|
|
function markFunction(fn) {
|
|
fn[expando] = true;
|
|
return fn;
|
|
}
|
|
function siblingCheck(a, b) {
|
|
var cur = b && a, diff = cur && a.nodeType === 1 && b.nodeType === 1 && (~b.sourceIndex || MAX_NEGATIVE) - (~a.sourceIndex || MAX_NEGATIVE);
|
|
if (diff) {
|
|
return diff;
|
|
}
|
|
if (cur) {
|
|
while (cur = cur.nextSibling) {
|
|
if (cur === b) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
return a ? 1 : -1;
|
|
}
|
|
function createInputPseudo(type) {
|
|
return function (elem) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === 'input' && elem.type === type;
|
|
};
|
|
}
|
|
function createButtonPseudo(type) {
|
|
return function (elem) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return (name === 'input' || name === 'button') && elem.type === type;
|
|
};
|
|
}
|
|
function createPositionalPseudo(fn) {
|
|
return markFunction(function (argument) {
|
|
argument = +argument;
|
|
return markFunction(function (seed, matches) {
|
|
var j, matchIndexes = fn([], seed.length, argument), i = matchIndexes.length;
|
|
while (i--) {
|
|
if (seed[j = matchIndexes[i]]) {
|
|
seed[j] = !(matches[j] = seed[j]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function testContext(context) {
|
|
return context && typeof context.getElementsByTagName !== strundefined && context;
|
|
}
|
|
support = Sizzle.support = {};
|
|
isXML = Sizzle.isXML = function (elem) {
|
|
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
|
|
return documentElement ? documentElement.nodeName !== 'HTML' : false;
|
|
};
|
|
setDocument = Sizzle.setDocument = function (node) {
|
|
var hasCompare, doc = node ? node.ownerDocument || node : preferredDoc, parent = doc.defaultView;
|
|
function getTop(win) {
|
|
try {
|
|
return win.top;
|
|
} catch (ex) {
|
|
}
|
|
return null;
|
|
}
|
|
if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
|
|
return document;
|
|
}
|
|
document = doc;
|
|
docElem = doc.documentElement;
|
|
documentIsHTML = !isXML(doc);
|
|
if (parent && parent !== getTop(parent)) {
|
|
if (parent.addEventListener) {
|
|
parent.addEventListener('unload', function () {
|
|
setDocument();
|
|
}, false);
|
|
} else if (parent.attachEvent) {
|
|
parent.attachEvent('onunload', function () {
|
|
setDocument();
|
|
});
|
|
}
|
|
}
|
|
support.attributes = true;
|
|
support.getElementsByTagName = true;
|
|
support.getElementsByClassName = rnative.test(doc.getElementsByClassName);
|
|
support.getById = true;
|
|
Expr.find.ID = function (id, context) {
|
|
if (typeof context.getElementById !== strundefined && documentIsHTML) {
|
|
var m = context.getElementById(id);
|
|
return m && m.parentNode ? [m] : [];
|
|
}
|
|
};
|
|
Expr.filter.ID = function (id) {
|
|
var attrId = id.replace(runescape, funescape);
|
|
return function (elem) {
|
|
return elem.getAttribute('id') === attrId;
|
|
};
|
|
};
|
|
Expr.find.TAG = support.getElementsByTagName ? function (tag, context) {
|
|
if (typeof context.getElementsByTagName !== strundefined) {
|
|
return context.getElementsByTagName(tag);
|
|
}
|
|
} : function (tag, context) {
|
|
var elem, tmp = [], i = 0, results = context.getElementsByTagName(tag);
|
|
if (tag === '*') {
|
|
while (elem = results[i++]) {
|
|
if (elem.nodeType === 1) {
|
|
tmp.push(elem);
|
|
}
|
|
}
|
|
return tmp;
|
|
}
|
|
return results;
|
|
};
|
|
Expr.find.CLASS = support.getElementsByClassName && function (className, context) {
|
|
if (documentIsHTML) {
|
|
return context.getElementsByClassName(className);
|
|
}
|
|
};
|
|
rbuggyMatches = [];
|
|
rbuggyQSA = [];
|
|
support.disconnectedMatch = true;
|
|
rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join('|'));
|
|
rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join('|'));
|
|
hasCompare = rnative.test(docElem.compareDocumentPosition);
|
|
contains$3 = hasCompare || rnative.test(docElem.contains) ? function (a, b) {
|
|
var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode;
|
|
return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ? adown.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
|
|
} : function (a, b) {
|
|
if (b) {
|
|
while (b = b.parentNode) {
|
|
if (b === a) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
sortOrder = hasCompare ? function (a, b) {
|
|
if (a === b) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
|
|
if (compare) {
|
|
return compare;
|
|
}
|
|
compare = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) : 1;
|
|
if (compare & 1 || !support.sortDetached && b.compareDocumentPosition(a) === compare) {
|
|
if (a === doc || a.ownerDocument === preferredDoc && contains$3(preferredDoc, a)) {
|
|
return -1;
|
|
}
|
|
if (b === doc || b.ownerDocument === preferredDoc && contains$3(preferredDoc, b)) {
|
|
return 1;
|
|
}
|
|
return sortInput ? indexOf$2.call(sortInput, a) - indexOf$2.call(sortInput, b) : 0;
|
|
}
|
|
return compare & 4 ? -1 : 1;
|
|
} : function (a, b) {
|
|
if (a === b) {
|
|
hasDuplicate = true;
|
|
return 0;
|
|
}
|
|
var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [a], bp = [b];
|
|
if (!aup || !bup) {
|
|
return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : sortInput ? indexOf$2.call(sortInput, a) - indexOf$2.call(sortInput, b) : 0;
|
|
} else if (aup === bup) {
|
|
return siblingCheck(a, b);
|
|
}
|
|
cur = a;
|
|
while (cur = cur.parentNode) {
|
|
ap.unshift(cur);
|
|
}
|
|
cur = b;
|
|
while (cur = cur.parentNode) {
|
|
bp.unshift(cur);
|
|
}
|
|
while (ap[i] === bp[i]) {
|
|
i++;
|
|
}
|
|
return i ? siblingCheck(ap[i], bp[i]) : ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0;
|
|
};
|
|
return doc;
|
|
};
|
|
Sizzle.matches = function (expr, elements) {
|
|
return Sizzle(expr, null, null, elements);
|
|
};
|
|
Sizzle.matchesSelector = function (elem, expr) {
|
|
if ((elem.ownerDocument || elem) !== document) {
|
|
setDocument(elem);
|
|
}
|
|
expr = expr.replace(rattributeQuotes, '=\'$1\']');
|
|
if (support.matchesSelector && documentIsHTML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && (!rbuggyQSA || !rbuggyQSA.test(expr))) {
|
|
try {
|
|
var ret = matches.call(elem, expr);
|
|
if (ret || support.disconnectedMatch || elem.document && elem.document.nodeType !== 11) {
|
|
return ret;
|
|
}
|
|
} catch (e) {
|
|
}
|
|
}
|
|
return Sizzle(expr, document, null, [elem]).length > 0;
|
|
};
|
|
Sizzle.contains = function (context, elem) {
|
|
if ((context.ownerDocument || context) !== document) {
|
|
setDocument(context);
|
|
}
|
|
return contains$3(context, elem);
|
|
};
|
|
Sizzle.attr = function (elem, name) {
|
|
if ((elem.ownerDocument || elem) !== document) {
|
|
setDocument(elem);
|
|
}
|
|
var fn = Expr.attrHandle[name.toLowerCase()], val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined;
|
|
return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute(name) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null;
|
|
};
|
|
Sizzle.error = function (msg) {
|
|
throw new Error('Syntax error, unrecognized expression: ' + msg);
|
|
};
|
|
Sizzle.uniqueSort = function (results) {
|
|
var elem, duplicates = [], j = 0, i = 0;
|
|
hasDuplicate = !support.detectDuplicates;
|
|
sortInput = !support.sortStable && results.slice(0);
|
|
results.sort(sortOrder);
|
|
if (hasDuplicate) {
|
|
while (elem = results[i++]) {
|
|
if (elem === results[i]) {
|
|
j = duplicates.push(i);
|
|
}
|
|
}
|
|
while (j--) {
|
|
results.splice(duplicates[j], 1);
|
|
}
|
|
}
|
|
sortInput = null;
|
|
return results;
|
|
};
|
|
getText = Sizzle.getText = function (elem) {
|
|
var node, ret = '', i = 0, nodeType = elem.nodeType;
|
|
if (!nodeType) {
|
|
while (node = elem[i++]) {
|
|
ret += getText(node);
|
|
}
|
|
} else if (nodeType === 1 || nodeType === 9 || nodeType === 11) {
|
|
if (typeof elem.textContent === 'string') {
|
|
return elem.textContent;
|
|
} else {
|
|
for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
|
|
ret += getText(elem);
|
|
}
|
|
}
|
|
} else if (nodeType === 3 || nodeType === 4) {
|
|
return elem.nodeValue;
|
|
}
|
|
return ret;
|
|
};
|
|
Expr = Sizzle.selectors = {
|
|
cacheLength: 50,
|
|
createPseudo: markFunction,
|
|
match: matchExpr,
|
|
attrHandle: {},
|
|
find: {},
|
|
relative: {
|
|
'>': {
|
|
dir: 'parentNode',
|
|
first: true
|
|
},
|
|
' ': { dir: 'parentNode' },
|
|
'+': {
|
|
dir: 'previousSibling',
|
|
first: true
|
|
},
|
|
'~': { dir: 'previousSibling' }
|
|
},
|
|
preFilter: {
|
|
ATTR: function (match) {
|
|
match[1] = match[1].replace(runescape, funescape);
|
|
match[3] = (match[3] || match[4] || match[5] || '').replace(runescape, funescape);
|
|
if (match[2] === '~=') {
|
|
match[3] = ' ' + match[3] + ' ';
|
|
}
|
|
return match.slice(0, 4);
|
|
},
|
|
CHILD: function (match) {
|
|
match[1] = match[1].toLowerCase();
|
|
if (match[1].slice(0, 3) === 'nth') {
|
|
if (!match[3]) {
|
|
Sizzle.error(match[0]);
|
|
}
|
|
match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === 'even' || match[3] === 'odd'));
|
|
match[5] = +(match[7] + match[8] || match[3] === 'odd');
|
|
} else if (match[3]) {
|
|
Sizzle.error(match[0]);
|
|
}
|
|
return match;
|
|
},
|
|
PSEUDO: function (match) {
|
|
var excess, unquoted = !match[6] && match[2];
|
|
if (matchExpr.CHILD.test(match[0])) {
|
|
return null;
|
|
}
|
|
if (match[3]) {
|
|
match[2] = match[4] || match[5] || '';
|
|
} else if (unquoted && rpseudo.test(unquoted) && (excess = tokenize(unquoted, true)) && (excess = unquoted.indexOf(')', unquoted.length - excess) - unquoted.length)) {
|
|
match[0] = match[0].slice(0, excess);
|
|
match[2] = unquoted.slice(0, excess);
|
|
}
|
|
return match.slice(0, 3);
|
|
}
|
|
},
|
|
filter: {
|
|
TAG: function (nodeNameSelector) {
|
|
var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
|
|
return nodeNameSelector === '*' ? function () {
|
|
return true;
|
|
} : function (elem) {
|
|
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
|
|
};
|
|
},
|
|
CLASS: function (className) {
|
|
var pattern = classCache[className + ' '];
|
|
return pattern || (pattern = new RegExp('(^|' + whitespace + ')' + className + '(' + whitespace + '|$)')) && classCache(className, function (elem) {
|
|
return pattern.test(typeof elem.className === 'string' && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute('class') || '');
|
|
});
|
|
},
|
|
ATTR: function (name, operator, check) {
|
|
return function (elem) {
|
|
var result = Sizzle.attr(elem, name);
|
|
if (result == null) {
|
|
return operator === '!=';
|
|
}
|
|
if (!operator) {
|
|
return true;
|
|
}
|
|
result += '';
|
|
return operator === '=' ? result === check : operator === '!=' ? result !== check : operator === '^=' ? check && result.indexOf(check) === 0 : operator === '*=' ? check && result.indexOf(check) > -1 : operator === '$=' ? check && result.slice(-check.length) === check : operator === '~=' ? (' ' + result + ' ').indexOf(check) > -1 : operator === '|=' ? result === check || result.slice(0, check.length + 1) === check + '-' : false;
|
|
};
|
|
},
|
|
CHILD: function (type, what, argument, first, last) {
|
|
var simple = type.slice(0, 3) !== 'nth', forward = type.slice(-4) !== 'last', ofType = what === 'of-type';
|
|
return first === 1 && last === 0 ? function (elem) {
|
|
return !!elem.parentNode;
|
|
} : function (elem, context, xml) {
|
|
var cache, outerCache, node, diff, nodeIndex, start, dir = simple !== forward ? 'nextSibling' : 'previousSibling', parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType;
|
|
if (parent) {
|
|
if (simple) {
|
|
while (dir) {
|
|
node = elem;
|
|
while (node = node[dir]) {
|
|
if (ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) {
|
|
return false;
|
|
}
|
|
}
|
|
start = dir = type === 'only' && !start && 'nextSibling';
|
|
}
|
|
return true;
|
|
}
|
|
start = [forward ? parent.firstChild : parent.lastChild];
|
|
if (forward && useCache) {
|
|
outerCache = parent[expando] || (parent[expando] = {});
|
|
cache = outerCache[type] || [];
|
|
nodeIndex = cache[0] === dirruns && cache[1];
|
|
diff = cache[0] === dirruns && cache[2];
|
|
node = nodeIndex && parent.childNodes[nodeIndex];
|
|
while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) {
|
|
if (node.nodeType === 1 && ++diff && node === elem) {
|
|
outerCache[type] = [
|
|
dirruns,
|
|
nodeIndex,
|
|
diff
|
|
];
|
|
break;
|
|
}
|
|
}
|
|
} else if (useCache && (cache = (elem[expando] || (elem[expando] = {}))[type]) && cache[0] === dirruns) {
|
|
diff = cache[1];
|
|
} else {
|
|
while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) {
|
|
if ((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff) {
|
|
if (useCache) {
|
|
(node[expando] || (node[expando] = {}))[type] = [
|
|
dirruns,
|
|
diff
|
|
];
|
|
}
|
|
if (node === elem) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
diff -= last;
|
|
return diff === first || diff % first === 0 && diff / first >= 0;
|
|
}
|
|
};
|
|
},
|
|
PSEUDO: function (pseudo, argument) {
|
|
var args, fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || Sizzle.error('unsupported pseudo: ' + pseudo);
|
|
if (fn[expando]) {
|
|
return fn(argument);
|
|
}
|
|
if (fn.length > 1) {
|
|
args = [
|
|
pseudo,
|
|
pseudo,
|
|
'',
|
|
argument
|
|
];
|
|
return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function (seed, matches) {
|
|
var idx, matched = fn(seed, argument), i = matched.length;
|
|
while (i--) {
|
|
idx = indexOf$2.call(seed, matched[i]);
|
|
seed[idx] = !(matches[idx] = matched[i]);
|
|
}
|
|
}) : function (elem) {
|
|
return fn(elem, 0, args);
|
|
};
|
|
}
|
|
return fn;
|
|
}
|
|
},
|
|
pseudos: {
|
|
not: markFunction(function (selector) {
|
|
var input = [], results = [], matcher = compile(selector.replace(rtrim, '$1'));
|
|
return matcher[expando] ? markFunction(function (seed, matches, context, xml) {
|
|
var elem, unmatched = matcher(seed, null, xml, []), i = seed.length;
|
|
while (i--) {
|
|
if (elem = unmatched[i]) {
|
|
seed[i] = !(matches[i] = elem);
|
|
}
|
|
}
|
|
}) : function (elem, context, xml) {
|
|
input[0] = elem;
|
|
matcher(input, null, xml, results);
|
|
return !results.pop();
|
|
};
|
|
}),
|
|
has: markFunction(function (selector) {
|
|
return function (elem) {
|
|
return Sizzle(selector, elem).length > 0;
|
|
};
|
|
}),
|
|
contains: markFunction(function (text) {
|
|
text = text.replace(runescape, funescape);
|
|
return function (elem) {
|
|
return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
|
|
};
|
|
}),
|
|
lang: markFunction(function (lang) {
|
|
if (!ridentifier.test(lang || '')) {
|
|
Sizzle.error('unsupported lang: ' + lang);
|
|
}
|
|
lang = lang.replace(runescape, funescape).toLowerCase();
|
|
return function (elem) {
|
|
var elemLang;
|
|
do {
|
|
if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute('xml:lang') || elem.getAttribute('lang')) {
|
|
elemLang = elemLang.toLowerCase();
|
|
return elemLang === lang || elemLang.indexOf(lang + '-') === 0;
|
|
}
|
|
} while ((elem = elem.parentNode) && elem.nodeType === 1);
|
|
return false;
|
|
};
|
|
}),
|
|
target: function (elem) {
|
|
var hash = domGlobals.window.location && domGlobals.window.location.hash;
|
|
return hash && hash.slice(1) === elem.id;
|
|
},
|
|
root: function (elem) {
|
|
return elem === docElem;
|
|
},
|
|
focus: function (elem) {
|
|
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
|
|
},
|
|
enabled: function (elem) {
|
|
return elem.disabled === false;
|
|
},
|
|
disabled: function (elem) {
|
|
return elem.disabled === true;
|
|
},
|
|
checked: function (elem) {
|
|
var nodeName = elem.nodeName.toLowerCase();
|
|
return nodeName === 'input' && !!elem.checked || nodeName === 'option' && !!elem.selected;
|
|
},
|
|
selected: function (elem) {
|
|
if (elem.parentNode) {
|
|
elem.parentNode.selectedIndex;
|
|
}
|
|
return elem.selected === true;
|
|
},
|
|
empty: function (elem) {
|
|
for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
|
|
if (elem.nodeType < 6) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
parent: function (elem) {
|
|
return !Expr.pseudos.empty(elem);
|
|
},
|
|
header: function (elem) {
|
|
return rheader.test(elem.nodeName);
|
|
},
|
|
input: function (elem) {
|
|
return rinputs.test(elem.nodeName);
|
|
},
|
|
button: function (elem) {
|
|
var name = elem.nodeName.toLowerCase();
|
|
return name === 'input' && elem.type === 'button' || name === 'button';
|
|
},
|
|
text: function (elem) {
|
|
var attr;
|
|
return elem.nodeName.toLowerCase() === 'input' && elem.type === 'text' && ((attr = elem.getAttribute('type')) == null || attr.toLowerCase() === 'text');
|
|
},
|
|
first: createPositionalPseudo(function () {
|
|
return [0];
|
|
}),
|
|
last: createPositionalPseudo(function (matchIndexes, length) {
|
|
return [length - 1];
|
|
}),
|
|
eq: createPositionalPseudo(function (matchIndexes, length, argument) {
|
|
return [argument < 0 ? argument + length : argument];
|
|
}),
|
|
even: createPositionalPseudo(function (matchIndexes, length) {
|
|
var i = 0;
|
|
for (; i < length; i += 2) {
|
|
matchIndexes.push(i);
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
odd: createPositionalPseudo(function (matchIndexes, length) {
|
|
var i = 1;
|
|
for (; i < length; i += 2) {
|
|
matchIndexes.push(i);
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
lt: createPositionalPseudo(function (matchIndexes, length, argument) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for (; --i >= 0;) {
|
|
matchIndexes.push(i);
|
|
}
|
|
return matchIndexes;
|
|
}),
|
|
gt: createPositionalPseudo(function (matchIndexes, length, argument) {
|
|
var i = argument < 0 ? argument + length : argument;
|
|
for (; ++i < length;) {
|
|
matchIndexes.push(i);
|
|
}
|
|
return matchIndexes;
|
|
})
|
|
}
|
|
};
|
|
Expr.pseudos.nth = Expr.pseudos.eq;
|
|
for (i in {
|
|
radio: true,
|
|
checkbox: true,
|
|
file: true,
|
|
password: true,
|
|
image: true
|
|
}) {
|
|
Expr.pseudos[i] = createInputPseudo(i);
|
|
}
|
|
for (i in {
|
|
submit: true,
|
|
reset: true
|
|
}) {
|
|
Expr.pseudos[i] = createButtonPseudo(i);
|
|
}
|
|
function setFilters() {
|
|
}
|
|
setFilters.prototype = Expr.filters = Expr.pseudos;
|
|
Expr.setFilters = new setFilters();
|
|
tokenize = Sizzle.tokenize = function (selector, parseOnly) {
|
|
var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + ' '];
|
|
if (cached) {
|
|
return parseOnly ? 0 : cached.slice(0);
|
|
}
|
|
soFar = selector;
|
|
groups = [];
|
|
preFilters = Expr.preFilter;
|
|
while (soFar) {
|
|
if (!matched || (match = rcomma.exec(soFar))) {
|
|
if (match) {
|
|
soFar = soFar.slice(match[0].length) || soFar;
|
|
}
|
|
groups.push(tokens = []);
|
|
}
|
|
matched = false;
|
|
if (match = rcombinators.exec(soFar)) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
type: match[0].replace(rtrim, ' ')
|
|
});
|
|
soFar = soFar.slice(matched.length);
|
|
}
|
|
for (type in Expr.filter) {
|
|
if (!Expr.filter.hasOwnProperty(type))
|
|
continue;
|
|
if ((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
|
|
matched = match.shift();
|
|
tokens.push({
|
|
value: matched,
|
|
type: type,
|
|
matches: match
|
|
});
|
|
soFar = soFar.slice(matched.length);
|
|
}
|
|
}
|
|
if (!matched) {
|
|
break;
|
|
}
|
|
}
|
|
return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) : tokenCache(selector, groups).slice(0);
|
|
};
|
|
function toSelector(tokens) {
|
|
var i = 0, len = tokens.length, selector = '';
|
|
for (; i < len; i++) {
|
|
selector += tokens[i].value;
|
|
}
|
|
return selector;
|
|
}
|
|
function addCombinator(matcher, combinator, base) {
|
|
var dir = combinator.dir, checkNonElements = base && dir === 'parentNode', doneName = done++;
|
|
return combinator.first ? function (elem, context, xml) {
|
|
while (elem = elem[dir]) {
|
|
if (elem.nodeType === 1 || checkNonElements) {
|
|
return matcher(elem, context, xml);
|
|
}
|
|
}
|
|
} : function (elem, context, xml) {
|
|
var oldCache, outerCache, newCache = [
|
|
dirruns,
|
|
doneName
|
|
];
|
|
if (xml) {
|
|
while (elem = elem[dir]) {
|
|
if (elem.nodeType === 1 || checkNonElements) {
|
|
if (matcher(elem, context, xml)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
while (elem = elem[dir]) {
|
|
if (elem.nodeType === 1 || checkNonElements) {
|
|
outerCache = elem[expando] || (elem[expando] = {});
|
|
if ((oldCache = outerCache[dir]) && oldCache[0] === dirruns && oldCache[1] === doneName) {
|
|
return newCache[2] = oldCache[2];
|
|
} else {
|
|
outerCache[dir] = newCache;
|
|
if (newCache[2] = matcher(elem, context, xml)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
function elementMatcher(matchers) {
|
|
return matchers.length > 1 ? function (elem, context, xml) {
|
|
var i = matchers.length;
|
|
while (i--) {
|
|
if (!matchers[i](elem, context, xml)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} : matchers[0];
|
|
}
|
|
function multipleContexts(selector, contexts, results) {
|
|
var i = 0, len = contexts.length;
|
|
for (; i < len; i++) {
|
|
Sizzle(selector, contexts[i], results);
|
|
}
|
|
return results;
|
|
}
|
|
function condense(unmatched, map, filter, context, xml) {
|
|
var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null;
|
|
for (; i < len; i++) {
|
|
if (elem = unmatched[i]) {
|
|
if (!filter || filter(elem, context, xml)) {
|
|
newUnmatched.push(elem);
|
|
if (mapped) {
|
|
map.push(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return newUnmatched;
|
|
}
|
|
function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector) {
|
|
if (postFilter && !postFilter[expando]) {
|
|
postFilter = setMatcher(postFilter);
|
|
}
|
|
if (postFinder && !postFinder[expando]) {
|
|
postFinder = setMatcher(postFinder, postSelector);
|
|
}
|
|
return markFunction(function (seed, results, context, xml) {
|
|
var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, elems = seed || multipleContexts(selector || '*', context.nodeType ? [context] : context, []), matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems, matcherOut = matcher ? postFinder || (seed ? preFilter : preexisting || postFilter) ? [] : results : matcherIn;
|
|
if (matcher) {
|
|
matcher(matcherIn, matcherOut, context, xml);
|
|
}
|
|
if (postFilter) {
|
|
temp = condense(matcherOut, postMap);
|
|
postFilter(temp, [], context, xml);
|
|
i = temp.length;
|
|
while (i--) {
|
|
if (elem = temp[i]) {
|
|
matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
|
|
}
|
|
}
|
|
}
|
|
if (seed) {
|
|
if (postFinder || preFilter) {
|
|
if (postFinder) {
|
|
temp = [];
|
|
i = matcherOut.length;
|
|
while (i--) {
|
|
if (elem = matcherOut[i]) {
|
|
temp.push(matcherIn[i] = elem);
|
|
}
|
|
}
|
|
postFinder(null, matcherOut = [], temp, xml);
|
|
}
|
|
i = matcherOut.length;
|
|
while (i--) {
|
|
if ((elem = matcherOut[i]) && (temp = postFinder ? indexOf$2.call(seed, elem) : preMap[i]) > -1) {
|
|
seed[temp] = !(results[temp] = elem);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
|
|
if (postFinder) {
|
|
postFinder(null, results, matcherOut, xml);
|
|
} else {
|
|
push.apply(results, matcherOut);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function matcherFromTokens(tokens) {
|
|
var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[tokens[0].type], implicitRelative = leadingRelative || Expr.relative[' '], i = leadingRelative ? 1 : 0, matchContext = addCombinator(function (elem) {
|
|
return elem === checkContext;
|
|
}, implicitRelative, true), matchAnyContext = addCombinator(function (elem) {
|
|
return indexOf$2.call(checkContext, elem) > -1;
|
|
}, implicitRelative, true), matchers = [function (elem, context, xml) {
|
|
return !leadingRelative && (xml || context !== outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
|
|
}];
|
|
for (; i < len; i++) {
|
|
if (matcher = Expr.relative[tokens[i].type]) {
|
|
matchers = [addCombinator(elementMatcher(matchers), matcher)];
|
|
} else {
|
|
matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
|
|
if (matcher[expando]) {
|
|
j = ++i;
|
|
for (; j < len; j++) {
|
|
if (Expr.relative[tokens[j].type]) {
|
|
break;
|
|
}
|
|
}
|
|
return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && toSelector(tokens.slice(0, i - 1).concat({ value: tokens[i - 2].type === ' ' ? '*' : '' })).replace(rtrim, '$1'), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens(tokens = tokens.slice(j)), j < len && toSelector(tokens));
|
|
}
|
|
matchers.push(matcher);
|
|
}
|
|
}
|
|
return elementMatcher(matchers);
|
|
}
|
|
function matcherFromGroupMatchers(elementMatchers, setMatchers) {
|
|
var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function (seed, context, xml, results, outermost) {
|
|
var elem, j, matcher, matchedCount = 0, i = '0', unmatched = seed && [], setMatched = [], contextBackup = outermostContext, elems = seed || byElement && Expr.find.TAG('*', outermost), dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || 0.1, len = elems.length;
|
|
if (outermost) {
|
|
outermostContext = context !== document && context;
|
|
}
|
|
for (; i !== len && (elem = elems[i]) != null; i++) {
|
|
if (byElement && elem) {
|
|
j = 0;
|
|
while (matcher = elementMatchers[j++]) {
|
|
if (matcher(elem, context, xml)) {
|
|
results.push(elem);
|
|
break;
|
|
}
|
|
}
|
|
if (outermost) {
|
|
dirruns = dirrunsUnique;
|
|
}
|
|
}
|
|
if (bySet) {
|
|
if (elem = !matcher && elem) {
|
|
matchedCount--;
|
|
}
|
|
if (seed) {
|
|
unmatched.push(elem);
|
|
}
|
|
}
|
|
}
|
|
matchedCount += i;
|
|
if (bySet && i !== matchedCount) {
|
|
j = 0;
|
|
while (matcher = setMatchers[j++]) {
|
|
matcher(unmatched, setMatched, context, xml);
|
|
}
|
|
if (seed) {
|
|
if (matchedCount > 0) {
|
|
while (i--) {
|
|
if (!(unmatched[i] || setMatched[i])) {
|
|
setMatched[i] = pop.call(results);
|
|
}
|
|
}
|
|
}
|
|
setMatched = condense(setMatched);
|
|
}
|
|
push.apply(results, setMatched);
|
|
if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) {
|
|
Sizzle.uniqueSort(results);
|
|
}
|
|
}
|
|
if (outermost) {
|
|
dirruns = dirrunsUnique;
|
|
outermostContext = contextBackup;
|
|
}
|
|
return unmatched;
|
|
};
|
|
return bySet ? markFunction(superMatcher) : superMatcher;
|
|
}
|
|
compile = Sizzle.compile = function (selector, match) {
|
|
var i, setMatchers = [], elementMatchers = [], cached = compilerCache[selector + ' '];
|
|
if (!cached) {
|
|
if (!match) {
|
|
match = tokenize(selector);
|
|
}
|
|
i = match.length;
|
|
while (i--) {
|
|
cached = matcherFromTokens(match[i]);
|
|
if (cached[expando]) {
|
|
setMatchers.push(cached);
|
|
} else {
|
|
elementMatchers.push(cached);
|
|
}
|
|
}
|
|
cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
|
|
cached.selector = selector;
|
|
}
|
|
return cached;
|
|
};
|
|
select = Sizzle.select = function (selector, context, results, seed) {
|
|
var i, tokens, token, type, find, compiled = typeof selector === 'function' && selector, match = !seed && tokenize(selector = compiled.selector || selector);
|
|
results = results || [];
|
|
if (match.length === 1) {
|
|
tokens = match[0] = match[0].slice(0);
|
|
if (tokens.length > 2 && (token = tokens[0]).type === 'ID' && support.getById && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
|
|
context = (Expr.find.ID(token.matches[0].replace(runescape, funescape), context) || [])[0];
|
|
if (!context) {
|
|
return results;
|
|
} else if (compiled) {
|
|
context = context.parentNode;
|
|
}
|
|
selector = selector.slice(tokens.shift().value.length);
|
|
}
|
|
i = matchExpr.needsContext.test(selector) ? 0 : tokens.length;
|
|
while (i--) {
|
|
token = tokens[i];
|
|
if (Expr.relative[type = token.type]) {
|
|
break;
|
|
}
|
|
if (find = Expr.find[type]) {
|
|
if (seed = find(token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context)) {
|
|
tokens.splice(i, 1);
|
|
selector = seed.length && toSelector(tokens);
|
|
if (!selector) {
|
|
push.apply(results, seed);
|
|
return results;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(compiled || compile(selector, match))(seed, context, !documentIsHTML, results, rsibling.test(selector) && testContext(context.parentNode) || context);
|
|
return results;
|
|
};
|
|
support.sortStable = expando.split('').sort(sortOrder).join('') === expando;
|
|
support.detectDuplicates = !!hasDuplicate;
|
|
setDocument();
|
|
support.sortDetached = true;
|
|
|
|
var doc = domGlobals.document, push$1 = Array.prototype.push, slice$1 = Array.prototype.slice;
|
|
var rquickExpr$1 = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
|
|
var Event = EventUtils.Event;
|
|
var skipUniques = Tools.makeMap('children,contents,next,prev');
|
|
var isDefined = function (obj) {
|
|
return typeof obj !== 'undefined';
|
|
};
|
|
var isString$1 = function (obj) {
|
|
return typeof obj === 'string';
|
|
};
|
|
var isWindow = function (obj) {
|
|
return obj && obj === obj.window;
|
|
};
|
|
var createFragment = function (html, fragDoc) {
|
|
var frag, node, container;
|
|
fragDoc = fragDoc || doc;
|
|
container = fragDoc.createElement('div');
|
|
frag = fragDoc.createDocumentFragment();
|
|
container.innerHTML = html;
|
|
while (node = container.firstChild) {
|
|
frag.appendChild(node);
|
|
}
|
|
return frag;
|
|
};
|
|
var domManipulate = function (targetNodes, sourceItem, callback, reverse) {
|
|
var i;
|
|
if (isString$1(sourceItem)) {
|
|
sourceItem = createFragment(sourceItem, getElementDocument(targetNodes[0]));
|
|
} else if (sourceItem.length && !sourceItem.nodeType) {
|
|
sourceItem = DomQuery.makeArray(sourceItem);
|
|
if (reverse) {
|
|
for (i = sourceItem.length - 1; i >= 0; i--) {
|
|
domManipulate(targetNodes, sourceItem[i], callback, reverse);
|
|
}
|
|
} else {
|
|
for (i = 0; i < sourceItem.length; i++) {
|
|
domManipulate(targetNodes, sourceItem[i], callback, reverse);
|
|
}
|
|
}
|
|
return targetNodes;
|
|
}
|
|
if (sourceItem.nodeType) {
|
|
i = targetNodes.length;
|
|
while (i--) {
|
|
callback.call(targetNodes[i], sourceItem);
|
|
}
|
|
}
|
|
return targetNodes;
|
|
};
|
|
var hasClass = function (node, className) {
|
|
return node && className && (' ' + node.className + ' ').indexOf(' ' + className + ' ') !== -1;
|
|
};
|
|
var wrap = function (elements, wrapper, all) {
|
|
var lastParent, newWrapper;
|
|
wrapper = DomQuery(wrapper)[0];
|
|
elements.each(function () {
|
|
var self = this;
|
|
if (!all || lastParent !== self.parentNode) {
|
|
lastParent = self.parentNode;
|
|
newWrapper = wrapper.cloneNode(false);
|
|
self.parentNode.insertBefore(newWrapper, self);
|
|
newWrapper.appendChild(self);
|
|
} else {
|
|
newWrapper.appendChild(self);
|
|
}
|
|
});
|
|
return elements;
|
|
};
|
|
var numericCssMap = Tools.makeMap('fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom', ' ');
|
|
var booleanMap = Tools.makeMap('checked compact declare defer disabled ismap multiple nohref noshade nowrap readonly selected', ' ');
|
|
var propFix = {
|
|
for: 'htmlFor',
|
|
class: 'className',
|
|
readonly: 'readOnly'
|
|
};
|
|
var cssFix = { float: 'cssFloat' };
|
|
var attrHooks = {}, cssHooks = {};
|
|
var DomQueryConstructor = function (selector, context) {
|
|
return new DomQuery.fn.init(selector, context);
|
|
};
|
|
var inArray$1 = function (item, array) {
|
|
var i;
|
|
if (array.indexOf) {
|
|
return array.indexOf(item);
|
|
}
|
|
i = array.length;
|
|
while (i--) {
|
|
if (array[i] === item) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
var whiteSpaceRegExp$1 = /^\s*|\s*$/g;
|
|
var trim$2 = function (str) {
|
|
return str === null || str === undefined ? '' : ('' + str).replace(whiteSpaceRegExp$1, '');
|
|
};
|
|
var each$4 = function (obj, callback) {
|
|
var length, key, i, value;
|
|
if (obj) {
|
|
length = obj.length;
|
|
if (length === undefined) {
|
|
for (key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
value = obj[key];
|
|
if (callback.call(value, key, value) === false) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < length; i++) {
|
|
value = obj[i];
|
|
if (callback.call(value, i, value) === false) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
};
|
|
var grep = function (array, callback) {
|
|
var out = [];
|
|
each$4(array, function (i, item) {
|
|
if (callback(item, i)) {
|
|
out.push(item);
|
|
}
|
|
});
|
|
return out;
|
|
};
|
|
var getElementDocument = function (element) {
|
|
if (!element) {
|
|
return doc;
|
|
}
|
|
if (element.nodeType === 9) {
|
|
return element;
|
|
}
|
|
return element.ownerDocument;
|
|
};
|
|
DomQueryConstructor.fn = DomQueryConstructor.prototype = {
|
|
constructor: DomQueryConstructor,
|
|
selector: '',
|
|
context: null,
|
|
length: 0,
|
|
init: function (selector, context) {
|
|
var self = this;
|
|
var match, node;
|
|
if (!selector) {
|
|
return self;
|
|
}
|
|
if (selector.nodeType) {
|
|
self.context = self[0] = selector;
|
|
self.length = 1;
|
|
return self;
|
|
}
|
|
if (context && context.nodeType) {
|
|
self.context = context;
|
|
} else {
|
|
if (context) {
|
|
return DomQuery(selector).attr(context);
|
|
}
|
|
self.context = context = domGlobals.document;
|
|
}
|
|
if (isString$1(selector)) {
|
|
self.selector = selector;
|
|
if (selector.charAt(0) === '<' && selector.charAt(selector.length - 1) === '>' && selector.length >= 3) {
|
|
match = [
|
|
null,
|
|
selector,
|
|
null
|
|
];
|
|
} else {
|
|
match = rquickExpr$1.exec(selector);
|
|
}
|
|
if (match) {
|
|
if (match[1]) {
|
|
node = createFragment(selector, getElementDocument(context)).firstChild;
|
|
while (node) {
|
|
push$1.call(self, node);
|
|
node = node.nextSibling;
|
|
}
|
|
} else {
|
|
node = getElementDocument(context).getElementById(match[2]);
|
|
if (!node) {
|
|
return self;
|
|
}
|
|
if (node.id !== match[2]) {
|
|
return self.find(selector);
|
|
}
|
|
self.length = 1;
|
|
self[0] = node;
|
|
}
|
|
} else {
|
|
return DomQuery(context).find(selector);
|
|
}
|
|
} else {
|
|
this.add(selector, false);
|
|
}
|
|
return self;
|
|
},
|
|
toArray: function () {
|
|
return Tools.toArray(this);
|
|
},
|
|
add: function (items, sort) {
|
|
var self = this;
|
|
var nodes, i;
|
|
if (isString$1(items)) {
|
|
return self.add(DomQuery(items));
|
|
}
|
|
if (sort !== false) {
|
|
nodes = DomQuery.unique(self.toArray().concat(DomQuery.makeArray(items)));
|
|
self.length = nodes.length;
|
|
for (i = 0; i < nodes.length; i++) {
|
|
self[i] = nodes[i];
|
|
}
|
|
} else {
|
|
push$1.apply(self, DomQuery.makeArray(items));
|
|
}
|
|
return self;
|
|
},
|
|
attr: function (name, value) {
|
|
var self = this;
|
|
var hook;
|
|
if (typeof name === 'object') {
|
|
each$4(name, function (name, value) {
|
|
self.attr(name, value);
|
|
});
|
|
} else if (isDefined(value)) {
|
|
this.each(function () {
|
|
var hook;
|
|
if (this.nodeType === 1) {
|
|
hook = attrHooks[name];
|
|
if (hook && hook.set) {
|
|
hook.set(this, value);
|
|
return;
|
|
}
|
|
if (value === null) {
|
|
this.removeAttribute(name, 2);
|
|
} else {
|
|
this.setAttribute(name, value, 2);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
if (self[0] && self[0].nodeType === 1) {
|
|
hook = attrHooks[name];
|
|
if (hook && hook.get) {
|
|
return hook.get(self[0], name);
|
|
}
|
|
if (booleanMap[name]) {
|
|
return self.prop(name) ? name : undefined;
|
|
}
|
|
value = self[0].getAttribute(name, 2);
|
|
if (value === null) {
|
|
value = undefined;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
return self;
|
|
},
|
|
removeAttr: function (name) {
|
|
return this.attr(name, null);
|
|
},
|
|
prop: function (name, value) {
|
|
var self = this;
|
|
name = propFix[name] || name;
|
|
if (typeof name === 'object') {
|
|
each$4(name, function (name, value) {
|
|
self.prop(name, value);
|
|
});
|
|
} else if (isDefined(value)) {
|
|
this.each(function () {
|
|
if (this.nodeType === 1) {
|
|
this[name] = value;
|
|
}
|
|
});
|
|
} else {
|
|
if (self[0] && self[0].nodeType && name in self[0]) {
|
|
return self[0][name];
|
|
}
|
|
return value;
|
|
}
|
|
return self;
|
|
},
|
|
css: function (name, value) {
|
|
var self = this;
|
|
var elm, hook;
|
|
var camel = function (name) {
|
|
return name.replace(/-(\D)/g, function (a, b) {
|
|
return b.toUpperCase();
|
|
});
|
|
};
|
|
var dashed = function (name) {
|
|
return name.replace(/[A-Z]/g, function (a) {
|
|
return '-' + a;
|
|
});
|
|
};
|
|
if (typeof name === 'object') {
|
|
each$4(name, function (name, value) {
|
|
self.css(name, value);
|
|
});
|
|
} else {
|
|
if (isDefined(value)) {
|
|
name = camel(name);
|
|
if (typeof value === 'number' && !numericCssMap[name]) {
|
|
value = value.toString() + 'px';
|
|
}
|
|
self.each(function () {
|
|
var style = this.style;
|
|
hook = cssHooks[name];
|
|
if (hook && hook.set) {
|
|
hook.set(this, value);
|
|
return;
|
|
}
|
|
try {
|
|
this.style[cssFix[name] || name] = value;
|
|
} catch (ex) {
|
|
}
|
|
if (value === null || value === '') {
|
|
if (style.removeProperty) {
|
|
style.removeProperty(dashed(name));
|
|
} else {
|
|
style.removeAttribute(name);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
elm = self[0];
|
|
hook = cssHooks[name];
|
|
if (hook && hook.get) {
|
|
return hook.get(elm);
|
|
}
|
|
if (elm.ownerDocument.defaultView) {
|
|
try {
|
|
return elm.ownerDocument.defaultView.getComputedStyle(elm, null).getPropertyValue(dashed(name));
|
|
} catch (ex) {
|
|
return undefined;
|
|
}
|
|
} else if (elm.currentStyle) {
|
|
return elm.currentStyle[camel(name)];
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
}
|
|
return self;
|
|
},
|
|
remove: function () {
|
|
var self = this;
|
|
var node, i = this.length;
|
|
while (i--) {
|
|
node = self[i];
|
|
Event.clean(node);
|
|
if (node.parentNode) {
|
|
node.parentNode.removeChild(node);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
empty: function () {
|
|
var self = this;
|
|
var node, i = this.length;
|
|
while (i--) {
|
|
node = self[i];
|
|
while (node.firstChild) {
|
|
node.removeChild(node.firstChild);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
html: function (value) {
|
|
var self = this;
|
|
var i;
|
|
if (isDefined(value)) {
|
|
i = self.length;
|
|
try {
|
|
while (i--) {
|
|
self[i].innerHTML = value;
|
|
}
|
|
} catch (ex) {
|
|
DomQuery(self[i]).empty().append(value);
|
|
}
|
|
return self;
|
|
}
|
|
return self[0] ? self[0].innerHTML : '';
|
|
},
|
|
text: function (value) {
|
|
var self = this;
|
|
var i;
|
|
if (isDefined(value)) {
|
|
i = self.length;
|
|
while (i--) {
|
|
if ('innerText' in self[i]) {
|
|
self[i].innerText = value;
|
|
} else {
|
|
self[0].textContent = value;
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
return self[0] ? self[0].innerText || self[0].textContent : '';
|
|
},
|
|
append: function () {
|
|
return domManipulate(this, arguments, function (node) {
|
|
if (this.nodeType === 1 || this.host && this.host.nodeType === 1) {
|
|
this.appendChild(node);
|
|
}
|
|
});
|
|
},
|
|
prepend: function () {
|
|
return domManipulate(this, arguments, function (node) {
|
|
if (this.nodeType === 1 || this.host && this.host.nodeType === 1) {
|
|
this.insertBefore(node, this.firstChild);
|
|
}
|
|
}, true);
|
|
},
|
|
before: function () {
|
|
var self = this;
|
|
if (self[0] && self[0].parentNode) {
|
|
return domManipulate(self, arguments, function (node) {
|
|
this.parentNode.insertBefore(node, this);
|
|
});
|
|
}
|
|
return self;
|
|
},
|
|
after: function () {
|
|
var self = this;
|
|
if (self[0] && self[0].parentNode) {
|
|
return domManipulate(self, arguments, function (node) {
|
|
this.parentNode.insertBefore(node, this.nextSibling);
|
|
}, true);
|
|
}
|
|
return self;
|
|
},
|
|
appendTo: function (val) {
|
|
DomQuery(val).append(this);
|
|
return this;
|
|
},
|
|
prependTo: function (val) {
|
|
DomQuery(val).prepend(this);
|
|
return this;
|
|
},
|
|
replaceWith: function (content) {
|
|
return this.before(content).remove();
|
|
},
|
|
wrap: function (content) {
|
|
return wrap(this, content);
|
|
},
|
|
wrapAll: function (content) {
|
|
return wrap(this, content, true);
|
|
},
|
|
wrapInner: function (content) {
|
|
this.each(function () {
|
|
DomQuery(this).contents().wrapAll(content);
|
|
});
|
|
return this;
|
|
},
|
|
unwrap: function () {
|
|
return this.parent().each(function () {
|
|
DomQuery(this).replaceWith(this.childNodes);
|
|
});
|
|
},
|
|
clone: function () {
|
|
var result = [];
|
|
this.each(function () {
|
|
result.push(this.cloneNode(true));
|
|
});
|
|
return DomQuery(result);
|
|
},
|
|
addClass: function (className) {
|
|
return this.toggleClass(className, true);
|
|
},
|
|
removeClass: function (className) {
|
|
return this.toggleClass(className, false);
|
|
},
|
|
toggleClass: function (className, state) {
|
|
var self = this;
|
|
if (typeof className !== 'string') {
|
|
return self;
|
|
}
|
|
if (className.indexOf(' ') !== -1) {
|
|
each$4(className.split(' '), function () {
|
|
self.toggleClass(this, state);
|
|
});
|
|
} else {
|
|
self.each(function (index, node) {
|
|
var existingClassName, classState;
|
|
classState = hasClass(node, className);
|
|
if (classState !== state) {
|
|
existingClassName = node.className;
|
|
if (classState) {
|
|
node.className = trim$2((' ' + existingClassName + ' ').replace(' ' + className + ' ', ' '));
|
|
} else {
|
|
node.className += existingClassName ? ' ' + className : className;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return self;
|
|
},
|
|
hasClass: function (className) {
|
|
return hasClass(this[0], className);
|
|
},
|
|
each: function (callback) {
|
|
return each$4(this, callback);
|
|
},
|
|
on: function (name, callback) {
|
|
return this.each(function () {
|
|
Event.bind(this, name, callback);
|
|
});
|
|
},
|
|
off: function (name, callback) {
|
|
return this.each(function () {
|
|
Event.unbind(this, name, callback);
|
|
});
|
|
},
|
|
trigger: function (name) {
|
|
return this.each(function () {
|
|
if (typeof name === 'object') {
|
|
Event.fire(this, name.type, name);
|
|
} else {
|
|
Event.fire(this, name);
|
|
}
|
|
});
|
|
},
|
|
show: function () {
|
|
return this.css('display', '');
|
|
},
|
|
hide: function () {
|
|
return this.css('display', 'none');
|
|
},
|
|
slice: function () {
|
|
return new DomQuery(slice$1.apply(this, arguments));
|
|
},
|
|
eq: function (index) {
|
|
return index === -1 ? this.slice(index) : this.slice(index, +index + 1);
|
|
},
|
|
first: function () {
|
|
return this.eq(0);
|
|
},
|
|
last: function () {
|
|
return this.eq(-1);
|
|
},
|
|
find: function (selector) {
|
|
var i, l;
|
|
var ret = [];
|
|
for (i = 0, l = this.length; i < l; i++) {
|
|
DomQuery.find(selector, this[i], ret);
|
|
}
|
|
return DomQuery(ret);
|
|
},
|
|
filter: function (selector) {
|
|
if (typeof selector === 'function') {
|
|
return DomQuery(grep(this.toArray(), function (item, i) {
|
|
return selector(i, item);
|
|
}));
|
|
}
|
|
return DomQuery(DomQuery.filter(selector, this.toArray()));
|
|
},
|
|
closest: function (selector) {
|
|
var result = [];
|
|
if (selector instanceof DomQuery) {
|
|
selector = selector[0];
|
|
}
|
|
this.each(function (i, node) {
|
|
while (node) {
|
|
if (typeof selector === 'string' && DomQuery(node).is(selector)) {
|
|
result.push(node);
|
|
break;
|
|
} else if (node === selector) {
|
|
result.push(node);
|
|
break;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
});
|
|
return DomQuery(result);
|
|
},
|
|
offset: function (offset) {
|
|
var elm, doc, docElm;
|
|
var x = 0, y = 0, pos;
|
|
if (!offset) {
|
|
elm = this[0];
|
|
if (elm) {
|
|
doc = elm.ownerDocument;
|
|
docElm = doc.documentElement;
|
|
if (elm.getBoundingClientRect) {
|
|
pos = elm.getBoundingClientRect();
|
|
x = pos.left + (docElm.scrollLeft || doc.body.scrollLeft) - docElm.clientLeft;
|
|
y = pos.top + (docElm.scrollTop || doc.body.scrollTop) - docElm.clientTop;
|
|
}
|
|
}
|
|
return {
|
|
left: x,
|
|
top: y
|
|
};
|
|
}
|
|
return this.css(offset);
|
|
},
|
|
push: push$1,
|
|
sort: Array.prototype.sort,
|
|
splice: Array.prototype.splice
|
|
};
|
|
Tools.extend(DomQueryConstructor, {
|
|
extend: Tools.extend,
|
|
makeArray: function (object) {
|
|
if (isWindow(object) || object.nodeType) {
|
|
return [object];
|
|
}
|
|
return Tools.toArray(object);
|
|
},
|
|
inArray: inArray$1,
|
|
isArray: Tools.isArray,
|
|
each: each$4,
|
|
trim: trim$2,
|
|
grep: grep,
|
|
find: Sizzle,
|
|
expr: Sizzle.selectors,
|
|
unique: Sizzle.uniqueSort,
|
|
text: Sizzle.getText,
|
|
contains: Sizzle.contains,
|
|
filter: function (expr, elems, not) {
|
|
var i = elems.length;
|
|
if (not) {
|
|
expr = ':not(' + expr + ')';
|
|
}
|
|
while (i--) {
|
|
if (elems[i].nodeType !== 1) {
|
|
elems.splice(i, 1);
|
|
}
|
|
}
|
|
if (elems.length === 1) {
|
|
elems = DomQuery.find.matchesSelector(elems[0], expr) ? [elems[0]] : [];
|
|
} else {
|
|
elems = DomQuery.find.matches(expr, elems);
|
|
}
|
|
return elems;
|
|
}
|
|
});
|
|
var dir = function (el, prop, until) {
|
|
var matched = [];
|
|
var cur = el[prop];
|
|
if (typeof until !== 'string' && until instanceof DomQuery) {
|
|
until = until[0];
|
|
}
|
|
while (cur && cur.nodeType !== 9) {
|
|
if (until !== undefined) {
|
|
if (cur === until) {
|
|
break;
|
|
}
|
|
if (typeof until === 'string' && DomQuery(cur).is(until)) {
|
|
break;
|
|
}
|
|
}
|
|
if (cur.nodeType === 1) {
|
|
matched.push(cur);
|
|
}
|
|
cur = cur[prop];
|
|
}
|
|
return matched;
|
|
};
|
|
var sibling = function (node, siblingName, nodeType, until) {
|
|
var result = [];
|
|
if (until instanceof DomQuery) {
|
|
until = until[0];
|
|
}
|
|
for (; node; node = node[siblingName]) {
|
|
if (nodeType && node.nodeType !== nodeType) {
|
|
continue;
|
|
}
|
|
if (until !== undefined) {
|
|
if (node === until) {
|
|
break;
|
|
}
|
|
if (typeof until === 'string' && DomQuery(node).is(until)) {
|
|
break;
|
|
}
|
|
}
|
|
result.push(node);
|
|
}
|
|
return result;
|
|
};
|
|
var firstSibling = function (node, siblingName, nodeType) {
|
|
for (node = node[siblingName]; node; node = node[siblingName]) {
|
|
if (node.nodeType === nodeType) {
|
|
return node;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
each$4({
|
|
parent: function (node) {
|
|
var parent = node.parentNode;
|
|
return parent && parent.nodeType !== 11 ? parent : null;
|
|
},
|
|
parents: function (node) {
|
|
return dir(node, 'parentNode');
|
|
},
|
|
next: function (node) {
|
|
return firstSibling(node, 'nextSibling', 1);
|
|
},
|
|
prev: function (node) {
|
|
return firstSibling(node, 'previousSibling', 1);
|
|
},
|
|
children: function (node) {
|
|
return sibling(node.firstChild, 'nextSibling', 1);
|
|
},
|
|
contents: function (node) {
|
|
return Tools.toArray((node.nodeName === 'iframe' ? node.contentDocument || node.contentWindow.document : node).childNodes);
|
|
}
|
|
}, function (name, fn) {
|
|
DomQueryConstructor.fn[name] = function (selector) {
|
|
var self = this;
|
|
var result = [];
|
|
self.each(function () {
|
|
var nodes = fn.call(result, this, selector, result);
|
|
if (nodes) {
|
|
if (DomQuery.isArray(nodes)) {
|
|
result.push.apply(result, nodes);
|
|
} else {
|
|
result.push(nodes);
|
|
}
|
|
}
|
|
});
|
|
if (this.length > 1) {
|
|
if (!skipUniques[name]) {
|
|
result = DomQuery.unique(result);
|
|
}
|
|
if (name.indexOf('parents') === 0) {
|
|
result = result.reverse();
|
|
}
|
|
}
|
|
var wrappedResult = DomQuery(result);
|
|
if (selector) {
|
|
return wrappedResult.filter(selector);
|
|
}
|
|
return wrappedResult;
|
|
};
|
|
});
|
|
each$4({
|
|
parentsUntil: function (node, until) {
|
|
return dir(node, 'parentNode', until);
|
|
},
|
|
nextUntil: function (node, until) {
|
|
return sibling(node, 'nextSibling', 1, until).slice(1);
|
|
},
|
|
prevUntil: function (node, until) {
|
|
return sibling(node, 'previousSibling', 1, until).slice(1);
|
|
}
|
|
}, function (name, fn) {
|
|
DomQueryConstructor.fn[name] = function (selector, filter) {
|
|
var self = this;
|
|
var result = [];
|
|
self.each(function () {
|
|
var nodes = fn.call(result, this, selector, result);
|
|
if (nodes) {
|
|
if (DomQuery.isArray(nodes)) {
|
|
result.push.apply(result, nodes);
|
|
} else {
|
|
result.push(nodes);
|
|
}
|
|
}
|
|
});
|
|
if (this.length > 1) {
|
|
result = DomQuery.unique(result);
|
|
if (name.indexOf('parents') === 0 || name === 'prevUntil') {
|
|
result = result.reverse();
|
|
}
|
|
}
|
|
var wrappedResult = DomQuery(result);
|
|
if (filter) {
|
|
return wrappedResult.filter(filter);
|
|
}
|
|
return wrappedResult;
|
|
};
|
|
});
|
|
DomQueryConstructor.fn.is = function (selector) {
|
|
return !!selector && this.filter(selector).length > 0;
|
|
};
|
|
DomQueryConstructor.fn.init.prototype = DomQueryConstructor.fn;
|
|
DomQueryConstructor.overrideDefaults = function (callback) {
|
|
var defaults;
|
|
var sub = function (selector, context) {
|
|
defaults = defaults || callback();
|
|
if (arguments.length === 0) {
|
|
selector = defaults.element;
|
|
}
|
|
if (!context) {
|
|
context = defaults.context;
|
|
}
|
|
return new sub.fn.init(selector, context);
|
|
};
|
|
DomQuery.extend(sub, this);
|
|
return sub;
|
|
};
|
|
DomQueryConstructor.attrHooks = attrHooks;
|
|
DomQueryConstructor.cssHooks = cssHooks;
|
|
var DomQuery = DomQueryConstructor;
|
|
|
|
var TreeWalker = function () {
|
|
function TreeWalker(startNode, rootNode) {
|
|
this.node = startNode;
|
|
this.rootNode = rootNode;
|
|
this.current = this.current.bind(this);
|
|
this.next = this.next.bind(this);
|
|
this.prev = this.prev.bind(this);
|
|
this.prev2 = this.prev2.bind(this);
|
|
}
|
|
TreeWalker.prototype.current = function () {
|
|
return this.node;
|
|
};
|
|
TreeWalker.prototype.next = function (shallow) {
|
|
this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow);
|
|
return this.node;
|
|
};
|
|
TreeWalker.prototype.prev = function (shallow) {
|
|
this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow);
|
|
return this.node;
|
|
};
|
|
TreeWalker.prototype.prev2 = function (shallow) {
|
|
this.node = this.findPreviousNode(this.node, 'lastChild', 'previousSibling', shallow);
|
|
return this.node;
|
|
};
|
|
TreeWalker.prototype.findSibling = function (node, startName, siblingName, shallow) {
|
|
var sibling, parent;
|
|
if (node) {
|
|
if (!shallow && node[startName]) {
|
|
return node[startName];
|
|
}
|
|
if (node !== this.rootNode) {
|
|
sibling = node[siblingName];
|
|
if (sibling) {
|
|
return sibling;
|
|
}
|
|
for (parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) {
|
|
sibling = parent[siblingName];
|
|
if (sibling) {
|
|
return sibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
TreeWalker.prototype.findPreviousNode = function (node, startName, siblingName, shallow) {
|
|
var sibling, parent, child;
|
|
if (node) {
|
|
sibling = node[siblingName];
|
|
if (this.rootNode && sibling === this.rootNode) {
|
|
return;
|
|
}
|
|
if (sibling) {
|
|
if (!shallow) {
|
|
for (child = sibling[startName]; child; child = child[startName]) {
|
|
if (!child[startName]) {
|
|
return child;
|
|
}
|
|
}
|
|
}
|
|
return sibling;
|
|
}
|
|
parent = node.parentNode;
|
|
if (parent && parent !== this.rootNode) {
|
|
return parent;
|
|
}
|
|
}
|
|
};
|
|
return TreeWalker;
|
|
}();
|
|
|
|
var before = function (marker, element) {
|
|
var parent$1 = parent(marker);
|
|
parent$1.each(function (v) {
|
|
v.dom().insertBefore(element.dom(), marker.dom());
|
|
});
|
|
};
|
|
var after = function (marker, element) {
|
|
var sibling = nextSibling(marker);
|
|
sibling.fold(function () {
|
|
var parent$1 = parent(marker);
|
|
parent$1.each(function (v) {
|
|
append(v, element);
|
|
});
|
|
}, function (v) {
|
|
before(v, element);
|
|
});
|
|
};
|
|
var prepend = function (parent, element) {
|
|
var firstChild$1 = firstChild(parent);
|
|
firstChild$1.fold(function () {
|
|
append(parent, element);
|
|
}, function (v) {
|
|
parent.dom().insertBefore(element.dom(), v.dom());
|
|
});
|
|
};
|
|
var append = function (parent, element) {
|
|
parent.dom().appendChild(element.dom());
|
|
};
|
|
var wrap$1 = function (element, wrapper) {
|
|
before(element, wrapper);
|
|
append(wrapper, element);
|
|
};
|
|
|
|
var before$1 = function (marker, elements) {
|
|
each(elements, function (x) {
|
|
before(marker, x);
|
|
});
|
|
};
|
|
var append$1 = function (parent, elements) {
|
|
each(elements, function (x) {
|
|
append(parent, x);
|
|
});
|
|
};
|
|
|
|
var empty = function (element) {
|
|
element.dom().textContent = '';
|
|
each(children(element), function (rogue) {
|
|
remove$1(rogue);
|
|
});
|
|
};
|
|
var remove$1 = function (element) {
|
|
var dom = element.dom();
|
|
if (dom.parentNode !== null) {
|
|
dom.parentNode.removeChild(dom);
|
|
}
|
|
};
|
|
var unwrap = function (wrapper) {
|
|
var children$1 = children(wrapper);
|
|
if (children$1.length > 0) {
|
|
before$1(wrapper, children$1);
|
|
}
|
|
remove$1(wrapper);
|
|
};
|
|
|
|
var r = function (left, top) {
|
|
var translate = function (x, y) {
|
|
return r(left + x, top + y);
|
|
};
|
|
return {
|
|
left: constant(left),
|
|
top: constant(top),
|
|
translate: translate
|
|
};
|
|
};
|
|
var Position$1 = r;
|
|
|
|
var boxPosition = function (dom) {
|
|
var box = dom.getBoundingClientRect();
|
|
return Position$1(box.left, box.top);
|
|
};
|
|
var firstDefinedOrZero = function (a, b) {
|
|
return a !== undefined ? a : b !== undefined ? b : 0;
|
|
};
|
|
var absolute = function (element) {
|
|
var doc = element.dom().ownerDocument;
|
|
var body = doc.body;
|
|
var win = doc.defaultView;
|
|
var html = doc.documentElement;
|
|
if (body === element.dom()) {
|
|
return Position$1(body.offsetLeft, body.offsetTop);
|
|
}
|
|
var scrollTop = firstDefinedOrZero(win.pageYOffset, html.scrollTop);
|
|
var scrollLeft = firstDefinedOrZero(win.pageXOffset, html.scrollLeft);
|
|
var clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
|
|
var clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
|
|
return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
|
|
};
|
|
var viewport = function (element) {
|
|
var dom = element.dom();
|
|
var doc = dom.ownerDocument;
|
|
var body = doc.body;
|
|
if (body === dom) {
|
|
return Position$1(body.offsetLeft, body.offsetTop);
|
|
}
|
|
if (!inBody(element)) {
|
|
return Position$1(0, 0);
|
|
}
|
|
return boxPosition(dom);
|
|
};
|
|
|
|
var isSafari = detect$3().browser.isSafari();
|
|
var get$3 = function (_DOC) {
|
|
var doc = _DOC !== undefined ? _DOC.dom() : domGlobals.document;
|
|
var x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
|
|
var y = doc.body.scrollTop || doc.documentElement.scrollTop;
|
|
return Position$1(x, y);
|
|
};
|
|
var to = function (x, y, _DOC) {
|
|
var doc = _DOC !== undefined ? _DOC.dom() : domGlobals.document;
|
|
var win = doc.defaultView;
|
|
win.scrollTo(x, y);
|
|
};
|
|
var intoView = function (element, alignToTop) {
|
|
if (isSafari && isFunction(element.dom().scrollIntoViewIfNeeded)) {
|
|
element.dom().scrollIntoViewIfNeeded(false);
|
|
} else {
|
|
element.dom().scrollIntoView(alignToTop);
|
|
}
|
|
};
|
|
|
|
var bounds = function (x, y, width, height) {
|
|
return {
|
|
x: constant(x),
|
|
y: constant(y),
|
|
width: constant(width),
|
|
height: constant(height),
|
|
right: constant(x + width),
|
|
bottom: constant(y + height)
|
|
};
|
|
};
|
|
var getBounds = function (_win) {
|
|
var win = _win === undefined ? domGlobals.window : _win;
|
|
var doc = win.document;
|
|
var scroll = get$3(Element.fromDom(doc));
|
|
var visualViewport = win['visualViewport'];
|
|
if (visualViewport !== undefined) {
|
|
return bounds(Math.max(visualViewport.pageLeft, scroll.left()), Math.max(visualViewport.pageTop, scroll.top()), visualViewport.width, visualViewport.height);
|
|
} else {
|
|
var html = doc.documentElement;
|
|
var width = html.clientWidth;
|
|
var height = html.clientHeight;
|
|
return bounds(scroll.left(), scroll.top(), width, height);
|
|
}
|
|
};
|
|
|
|
var each$5 = Tools.each;
|
|
var grep$1 = Tools.grep;
|
|
var isIE = Env.ie;
|
|
var simpleSelectorRe = /^([a-z0-9],?)+$/i;
|
|
var whiteSpaceRegExp$2 = /^[ \t\r\n]*$/;
|
|
var setupAttrHooks = function (styles, settings, getContext) {
|
|
var keepValues = settings.keep_values;
|
|
var keepUrlHook = {
|
|
set: function ($elm, value, name) {
|
|
if (settings.url_converter) {
|
|
value = settings.url_converter.call(settings.url_converter_scope || getContext(), value, name, $elm[0]);
|
|
}
|
|
$elm.attr('data-mce-' + name, value).attr(name, value);
|
|
},
|
|
get: function ($elm, name) {
|
|
return $elm.attr('data-mce-' + name) || $elm.attr(name);
|
|
}
|
|
};
|
|
var attrHooks = {
|
|
style: {
|
|
set: function ($elm, value) {
|
|
if (value !== null && typeof value === 'object') {
|
|
$elm.css(value);
|
|
return;
|
|
}
|
|
if (keepValues) {
|
|
$elm.attr('data-mce-style', value);
|
|
}
|
|
$elm.attr('style', value);
|
|
},
|
|
get: function ($elm) {
|
|
var value = $elm.attr('data-mce-style') || $elm.attr('style');
|
|
value = styles.serialize(styles.parse(value), $elm[0].nodeName);
|
|
return value;
|
|
}
|
|
}
|
|
};
|
|
if (keepValues) {
|
|
attrHooks.href = attrHooks.src = keepUrlHook;
|
|
}
|
|
return attrHooks;
|
|
};
|
|
var updateInternalStyleAttr = function (styles, $elm) {
|
|
var rawValue = $elm.attr('style');
|
|
var value = styles.serialize(styles.parse(rawValue), $elm[0].nodeName);
|
|
if (!value) {
|
|
value = null;
|
|
}
|
|
$elm.attr('data-mce-style', value);
|
|
};
|
|
var findNodeIndex = function (node, normalized) {
|
|
var idx = 0, lastNodeType, nodeType;
|
|
if (node) {
|
|
for (lastNodeType = node.nodeType, node = node.previousSibling; node; node = node.previousSibling) {
|
|
nodeType = node.nodeType;
|
|
if (normalized && nodeType === 3) {
|
|
if (nodeType === lastNodeType || !node.nodeValue.length) {
|
|
continue;
|
|
}
|
|
}
|
|
idx++;
|
|
lastNodeType = nodeType;
|
|
}
|
|
}
|
|
return idx;
|
|
};
|
|
function DOMUtils(doc, settings) {
|
|
var _this = this;
|
|
if (settings === void 0) {
|
|
settings = {};
|
|
}
|
|
var attrHooks;
|
|
var addedStyles = {};
|
|
var win = domGlobals.window;
|
|
var files = {};
|
|
var counter = 0;
|
|
var stdMode = true;
|
|
var boxModel = true;
|
|
var styleSheetLoader = StyleSheetLoader(doc, {
|
|
contentCssCors: settings.contentCssCors,
|
|
referrerPolicy: settings.referrerPolicy
|
|
});
|
|
var boundEvents = [];
|
|
var schema = settings.schema ? settings.schema : Schema({});
|
|
var styles = Styles({
|
|
url_converter: settings.url_converter,
|
|
url_converter_scope: settings.url_converter_scope
|
|
}, settings.schema);
|
|
var events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
|
|
var blockElementsMap = schema.getBlockElements();
|
|
var $ = DomQuery.overrideDefaults(function () {
|
|
return {
|
|
context: doc,
|
|
element: self.getRoot()
|
|
};
|
|
});
|
|
var isBlock = function (node) {
|
|
if (typeof node === 'string') {
|
|
return !!blockElementsMap[node];
|
|
} else if (node) {
|
|
var type = node.nodeType;
|
|
if (type) {
|
|
return !!(type === 1 && blockElementsMap[node.nodeName]);
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var get = function (elm) {
|
|
if (elm && doc && typeof elm === 'string') {
|
|
var node = doc.getElementById(elm);
|
|
if (node && node.id !== elm) {
|
|
return doc.getElementsByName(elm)[1];
|
|
} else {
|
|
return node;
|
|
}
|
|
}
|
|
return elm;
|
|
};
|
|
var $$ = function (elm) {
|
|
if (typeof elm === 'string') {
|
|
elm = get(elm);
|
|
}
|
|
return $(elm);
|
|
};
|
|
var getAttrib = function (elm, name, defaultVal) {
|
|
var hook, value;
|
|
var $elm = $$(elm);
|
|
if ($elm.length) {
|
|
hook = attrHooks[name];
|
|
if (hook && hook.get) {
|
|
value = hook.get($elm, name);
|
|
} else {
|
|
value = $elm.attr(name);
|
|
}
|
|
}
|
|
if (typeof value === 'undefined') {
|
|
value = defaultVal || '';
|
|
}
|
|
return value;
|
|
};
|
|
var getAttribs = function (elm) {
|
|
var node = get(elm);
|
|
if (!node) {
|
|
return [];
|
|
}
|
|
return node.attributes;
|
|
};
|
|
var setAttrib = function (elm, name, value) {
|
|
var originalValue, hook;
|
|
if (value === '') {
|
|
value = null;
|
|
}
|
|
var $elm = $$(elm);
|
|
originalValue = $elm.attr(name);
|
|
if (!$elm.length) {
|
|
return;
|
|
}
|
|
hook = attrHooks[name];
|
|
if (hook && hook.set) {
|
|
hook.set($elm, value, name);
|
|
} else {
|
|
$elm.attr(name, value);
|
|
}
|
|
if (originalValue !== value && settings.onSetAttrib) {
|
|
settings.onSetAttrib({
|
|
attrElm: $elm,
|
|
attrName: name,
|
|
attrValue: value
|
|
});
|
|
}
|
|
};
|
|
var clone = function (node, deep) {
|
|
if (!isIE || node.nodeType !== 1 || deep) {
|
|
return node.cloneNode(deep);
|
|
}
|
|
if (!deep) {
|
|
var clone_1 = doc.createElement(node.nodeName);
|
|
each$5(getAttribs(node), function (attr) {
|
|
setAttrib(clone_1, attr.nodeName, getAttrib(node, attr.nodeName));
|
|
});
|
|
return clone_1;
|
|
}
|
|
return null;
|
|
};
|
|
var getRoot = function () {
|
|
return settings.root_element || doc.body;
|
|
};
|
|
var getViewPort = function (argWin) {
|
|
var vp = getBounds(argWin);
|
|
return {
|
|
x: vp.x(),
|
|
y: vp.y(),
|
|
w: vp.width(),
|
|
h: vp.height()
|
|
};
|
|
};
|
|
var getPos = function (elm, rootElm) {
|
|
return Position.getPos(doc.body, get(elm), rootElm);
|
|
};
|
|
var setStyle = function (elm, name, value) {
|
|
var $elm = isString(name) ? $$(elm).css(name, value) : $$(elm).css(name);
|
|
if (settings.update_styles) {
|
|
updateInternalStyleAttr(styles, $elm);
|
|
}
|
|
};
|
|
var setStyles = function (elm, stylesArg) {
|
|
var $elm = $$(elm).css(stylesArg);
|
|
if (settings.update_styles) {
|
|
updateInternalStyleAttr(styles, $elm);
|
|
}
|
|
};
|
|
var getStyle = function (elm, name, computed) {
|
|
var $elm = $$(elm);
|
|
if (computed) {
|
|
return $elm.css(name);
|
|
}
|
|
name = name.replace(/-(\D)/g, function (a, b) {
|
|
return b.toUpperCase();
|
|
});
|
|
if (name === 'float') {
|
|
name = Env.browser.isIE() ? 'styleFloat' : 'cssFloat';
|
|
}
|
|
return $elm[0] && $elm[0].style ? $elm[0].style[name] : undefined;
|
|
};
|
|
var getSize = function (elm) {
|
|
var w, h;
|
|
elm = get(elm);
|
|
w = getStyle(elm, 'width');
|
|
h = getStyle(elm, 'height');
|
|
if (w.indexOf('px') === -1) {
|
|
w = 0;
|
|
}
|
|
if (h.indexOf('px') === -1) {
|
|
h = 0;
|
|
}
|
|
return {
|
|
w: parseInt(w, 10) || elm.offsetWidth || elm.clientWidth,
|
|
h: parseInt(h, 10) || elm.offsetHeight || elm.clientHeight
|
|
};
|
|
};
|
|
var getRect = function (elm) {
|
|
var pos, size;
|
|
elm = get(elm);
|
|
pos = getPos(elm);
|
|
size = getSize(elm);
|
|
return {
|
|
x: pos.x,
|
|
y: pos.y,
|
|
w: size.w,
|
|
h: size.h
|
|
};
|
|
};
|
|
var is = function (elm, selector) {
|
|
var i;
|
|
if (!elm) {
|
|
return false;
|
|
}
|
|
if (!Array.isArray(elm)) {
|
|
if (selector === '*') {
|
|
return elm.nodeType === 1;
|
|
}
|
|
if (simpleSelectorRe.test(selector)) {
|
|
var selectors = selector.toLowerCase().split(/,/);
|
|
var elmName = elm.nodeName.toLowerCase();
|
|
for (i = selectors.length - 1; i >= 0; i--) {
|
|
if (selectors[i] === elmName) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if (elm.nodeType && elm.nodeType !== 1) {
|
|
return false;
|
|
}
|
|
}
|
|
var elms = !Array.isArray(elm) ? [elm] : elm;
|
|
return Sizzle(selector, elms[0].ownerDocument || elms[0], null, elms).length > 0;
|
|
};
|
|
var getParents = function (elm, selector, root, collect) {
|
|
var result = [];
|
|
var selectorVal;
|
|
var node = get(elm);
|
|
collect = collect === undefined;
|
|
root = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
|
|
if (Tools.is(selector, 'string')) {
|
|
selectorVal = selector;
|
|
if (selector === '*') {
|
|
selector = function (node) {
|
|
return node.nodeType === 1;
|
|
};
|
|
} else {
|
|
selector = function (node) {
|
|
return is(node, selectorVal);
|
|
};
|
|
}
|
|
}
|
|
while (node) {
|
|
if (node === root || !node.nodeType || node.nodeType === 9) {
|
|
break;
|
|
}
|
|
if (!selector || typeof selector === 'function' && selector(node)) {
|
|
if (collect) {
|
|
result.push(node);
|
|
} else {
|
|
return [node];
|
|
}
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return collect ? result : null;
|
|
};
|
|
var getParent = function (node, selector, root) {
|
|
var parents = getParents(node, selector, root, false);
|
|
return parents && parents.length > 0 ? parents[0] : null;
|
|
};
|
|
var _findSib = function (node, selector, name) {
|
|
var func = selector;
|
|
if (node) {
|
|
if (typeof selector === 'string') {
|
|
func = function (node) {
|
|
return is(node, selector);
|
|
};
|
|
}
|
|
for (node = node[name]; node; node = node[name]) {
|
|
if (typeof func === 'function' && func(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var getNext = function (node, selector) {
|
|
return _findSib(node, selector, 'nextSibling');
|
|
};
|
|
var getPrev = function (node, selector) {
|
|
return _findSib(node, selector, 'previousSibling');
|
|
};
|
|
var select = function (selector, scope) {
|
|
return Sizzle(selector, get(scope) || settings.root_element || doc, []);
|
|
};
|
|
var run = function (elm, func, scope) {
|
|
var result;
|
|
var node = typeof elm === 'string' ? get(elm) : elm;
|
|
if (!node) {
|
|
return false;
|
|
}
|
|
if (Tools.isArray(node) && (node.length || node.length === 0)) {
|
|
result = [];
|
|
each$5(node, function (elm, i) {
|
|
if (elm) {
|
|
if (typeof elm === 'string') {
|
|
elm = get(elm);
|
|
}
|
|
result.push(func.call(scope, elm, i));
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
var context = scope ? scope : _this;
|
|
return func.call(context, node);
|
|
};
|
|
var setAttribs = function (elm, attrs) {
|
|
$$(elm).each(function (i, node) {
|
|
each$5(attrs, function (value, name) {
|
|
setAttrib(node, name, value);
|
|
});
|
|
});
|
|
};
|
|
var setHTML = function (elm, html) {
|
|
var $elm = $$(elm);
|
|
if (isIE) {
|
|
$elm.each(function (i, target) {
|
|
if (target.canHaveHTML === false) {
|
|
return;
|
|
}
|
|
while (target.firstChild) {
|
|
target.removeChild(target.firstChild);
|
|
}
|
|
try {
|
|
target.innerHTML = '<br>' + html;
|
|
target.removeChild(target.firstChild);
|
|
} catch (ex) {
|
|
DomQuery('<div></div>').html('<br>' + html).contents().slice(1).appendTo(target);
|
|
}
|
|
return html;
|
|
});
|
|
} else {
|
|
$elm.html(html);
|
|
}
|
|
};
|
|
var add = function (parentElm, name, attrs, html, create) {
|
|
return run(parentElm, function (parentElm) {
|
|
var newElm = typeof name === 'string' ? doc.createElement(name) : name;
|
|
setAttribs(newElm, attrs);
|
|
if (html) {
|
|
if (typeof html !== 'string' && html.nodeType) {
|
|
newElm.appendChild(html);
|
|
} else if (typeof html === 'string') {
|
|
setHTML(newElm, html);
|
|
}
|
|
}
|
|
return !create ? parentElm.appendChild(newElm) : newElm;
|
|
});
|
|
};
|
|
var create = function (name, attrs, html) {
|
|
return add(doc.createElement(name), name, attrs, html, true);
|
|
};
|
|
var decode = Entities.decode;
|
|
var encode = Entities.encodeAllRaw;
|
|
var createHTML = function (name, attrs, html) {
|
|
var outHtml = '', key;
|
|
outHtml += '<' + name;
|
|
for (key in attrs) {
|
|
if (attrs.hasOwnProperty(key) && attrs[key] !== null && typeof attrs[key] !== 'undefined') {
|
|
outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
|
|
}
|
|
}
|
|
if (typeof html !== 'undefined') {
|
|
return outHtml + '>' + html + '</' + name + '>';
|
|
}
|
|
return outHtml + ' />';
|
|
};
|
|
var createFragment = function (html) {
|
|
var node;
|
|
var container = doc.createElement('div');
|
|
var frag = doc.createDocumentFragment();
|
|
if (html) {
|
|
container.innerHTML = html;
|
|
}
|
|
while (node = container.firstChild) {
|
|
frag.appendChild(node);
|
|
}
|
|
return frag;
|
|
};
|
|
var remove = function (node, keepChildren) {
|
|
var $node = $$(node);
|
|
if (keepChildren) {
|
|
$node.each(function () {
|
|
var child;
|
|
while (child = this.firstChild) {
|
|
if (child.nodeType === 3 && child.data.length === 0) {
|
|
this.removeChild(child);
|
|
} else {
|
|
this.parentNode.insertBefore(child, this);
|
|
}
|
|
}
|
|
}).remove();
|
|
} else {
|
|
$node.remove();
|
|
}
|
|
return $node.length > 1 ? $node.toArray() : $node[0];
|
|
};
|
|
var removeAllAttribs = function (e) {
|
|
return run(e, function (e) {
|
|
var i;
|
|
var attrs = e.attributes;
|
|
for (i = attrs.length - 1; i >= 0; i--) {
|
|
e.removeAttributeNode(attrs.item(i));
|
|
}
|
|
});
|
|
};
|
|
var parseStyle = function (cssText) {
|
|
return styles.parse(cssText);
|
|
};
|
|
var serializeStyle = function (stylesArg, name) {
|
|
return styles.serialize(stylesArg, name);
|
|
};
|
|
var addStyle = function (cssText) {
|
|
var head, styleElm;
|
|
if (self !== DOMUtils.DOM && doc === domGlobals.document) {
|
|
if (addedStyles[cssText]) {
|
|
return;
|
|
}
|
|
addedStyles[cssText] = true;
|
|
}
|
|
styleElm = doc.getElementById('mceDefaultStyles');
|
|
if (!styleElm) {
|
|
styleElm = doc.createElement('style');
|
|
styleElm.id = 'mceDefaultStyles';
|
|
styleElm.type = 'text/css';
|
|
head = doc.getElementsByTagName('head')[0];
|
|
if (head.firstChild) {
|
|
head.insertBefore(styleElm, head.firstChild);
|
|
} else {
|
|
head.appendChild(styleElm);
|
|
}
|
|
}
|
|
if (styleElm.styleSheet) {
|
|
styleElm.styleSheet.cssText += cssText;
|
|
} else {
|
|
styleElm.appendChild(doc.createTextNode(cssText));
|
|
}
|
|
};
|
|
var loadCSS = function (url) {
|
|
var head;
|
|
if (self !== DOMUtils.DOM && doc === domGlobals.document) {
|
|
DOMUtils.DOM.loadCSS(url);
|
|
return;
|
|
}
|
|
if (!url) {
|
|
url = '';
|
|
}
|
|
head = doc.getElementsByTagName('head')[0];
|
|
each$5(url.split(','), function (url) {
|
|
var link;
|
|
url = Tools._addCacheSuffix(url);
|
|
if (files[url]) {
|
|
return;
|
|
}
|
|
files[url] = true;
|
|
link = create('link', __assign(__assign({
|
|
rel: 'stylesheet',
|
|
type: 'text/css',
|
|
href: url
|
|
}, settings.contentCssCors ? { crossOrigin: 'anonymous' } : {}), settings.referrerPolicy ? { referrerPolicy: settings.referrerPolicy } : {}));
|
|
head.appendChild(link);
|
|
});
|
|
};
|
|
var toggleClass = function (elm, cls, state) {
|
|
$$(elm).toggleClass(cls, state).each(function () {
|
|
if (this.className === '') {
|
|
DomQuery(this).attr('class', null);
|
|
}
|
|
});
|
|
};
|
|
var addClass = function (elm, cls) {
|
|
$$(elm).addClass(cls);
|
|
};
|
|
var removeClass = function (elm, cls) {
|
|
toggleClass(elm, cls, false);
|
|
};
|
|
var hasClass = function (elm, cls) {
|
|
return $$(elm).hasClass(cls);
|
|
};
|
|
var show = function (elm) {
|
|
$$(elm).show();
|
|
};
|
|
var hide = function (elm) {
|
|
$$(elm).hide();
|
|
};
|
|
var isHidden = function (elm) {
|
|
return $$(elm).css('display') === 'none';
|
|
};
|
|
var uniqueId = function (prefix) {
|
|
return (!prefix ? 'mce_' : prefix) + counter++;
|
|
};
|
|
var getOuterHTML = function (elm) {
|
|
var node = typeof elm === 'string' ? get(elm) : elm;
|
|
return NodeType.isElement(node) ? node.outerHTML : DomQuery('<div></div>').append(DomQuery(node).clone()).html();
|
|
};
|
|
var setOuterHTML = function (elm, html) {
|
|
$$(elm).each(function () {
|
|
try {
|
|
if ('outerHTML' in this) {
|
|
this.outerHTML = html;
|
|
return;
|
|
}
|
|
} catch (ex) {
|
|
}
|
|
remove(DomQuery(this).html(html), true);
|
|
});
|
|
};
|
|
var insertAfter = function (node, reference) {
|
|
var referenceNode = get(reference);
|
|
return run(node, function (node) {
|
|
var parent, nextSibling;
|
|
parent = referenceNode.parentNode;
|
|
nextSibling = referenceNode.nextSibling;
|
|
if (nextSibling) {
|
|
parent.insertBefore(node, nextSibling);
|
|
} else {
|
|
parent.appendChild(node);
|
|
}
|
|
return node;
|
|
});
|
|
};
|
|
var replace = function (newElm, oldElm, keepChildren) {
|
|
return run(oldElm, function (oldElm) {
|
|
if (Tools.is(oldElm, 'array')) {
|
|
newElm = newElm.cloneNode(true);
|
|
}
|
|
if (keepChildren) {
|
|
each$5(grep$1(oldElm.childNodes), function (node) {
|
|
newElm.appendChild(node);
|
|
});
|
|
}
|
|
return oldElm.parentNode.replaceChild(newElm, oldElm);
|
|
});
|
|
};
|
|
var rename = function (elm, name) {
|
|
var newElm;
|
|
if (elm.nodeName !== name.toUpperCase()) {
|
|
newElm = create(name);
|
|
each$5(getAttribs(elm), function (attrNode) {
|
|
setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
|
|
});
|
|
replace(newElm, elm, true);
|
|
}
|
|
return newElm || elm;
|
|
};
|
|
var findCommonAncestor = function (a, b) {
|
|
var ps = a, pe;
|
|
while (ps) {
|
|
pe = b;
|
|
while (pe && ps !== pe) {
|
|
pe = pe.parentNode;
|
|
}
|
|
if (ps === pe) {
|
|
break;
|
|
}
|
|
ps = ps.parentNode;
|
|
}
|
|
if (!ps && a.ownerDocument) {
|
|
return a.ownerDocument.documentElement;
|
|
}
|
|
return ps;
|
|
};
|
|
var toHex = function (rgbVal) {
|
|
return styles.toHex(Tools.trim(rgbVal));
|
|
};
|
|
var isEmpty = function (node, elements) {
|
|
var i, attributes, type, name, brCount = 0;
|
|
node = node.firstChild;
|
|
if (node) {
|
|
var walker = new TreeWalker(node, node.parentNode);
|
|
var whitespace = schema ? schema.getWhiteSpaceElements() : {};
|
|
elements = elements || (schema ? schema.getNonEmptyElements() : null);
|
|
do {
|
|
type = node.nodeType;
|
|
if (NodeType.isElement(node)) {
|
|
var bogusVal = node.getAttribute('data-mce-bogus');
|
|
if (bogusVal) {
|
|
node = walker.next(bogusVal === 'all');
|
|
continue;
|
|
}
|
|
name = node.nodeName.toLowerCase();
|
|
if (elements && elements[name]) {
|
|
if (name === 'br') {
|
|
brCount++;
|
|
node = walker.next();
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
attributes = getAttribs(node);
|
|
i = attributes.length;
|
|
while (i--) {
|
|
name = attributes[i].nodeName;
|
|
if (name === 'name' || name === 'data-mce-bookmark') {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (type === 8) {
|
|
return false;
|
|
}
|
|
if (type === 3 && !whiteSpaceRegExp$2.test(node.nodeValue)) {
|
|
return false;
|
|
}
|
|
if (type === 3 && node.parentNode && whitespace[node.parentNode.nodeName] && whiteSpaceRegExp$2.test(node.nodeValue)) {
|
|
return false;
|
|
}
|
|
node = walker.next();
|
|
} while (node);
|
|
}
|
|
return brCount <= 1;
|
|
};
|
|
var createRng = function () {
|
|
return doc.createRange();
|
|
};
|
|
var split = function (parentElm, splitElm, replacementElm) {
|
|
var r = createRng(), bef, aft, pa;
|
|
if (parentElm && splitElm) {
|
|
r.setStart(parentElm.parentNode, findNodeIndex(parentElm));
|
|
r.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
|
|
bef = r.extractContents();
|
|
r = createRng();
|
|
r.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
|
|
r.setEnd(parentElm.parentNode, findNodeIndex(parentElm) + 1);
|
|
aft = r.extractContents();
|
|
pa = parentElm.parentNode;
|
|
pa.insertBefore(TrimNode.trimNode(self, bef), parentElm);
|
|
if (replacementElm) {
|
|
pa.insertBefore(replacementElm, parentElm);
|
|
} else {
|
|
pa.insertBefore(splitElm, parentElm);
|
|
}
|
|
pa.insertBefore(TrimNode.trimNode(self, aft), parentElm);
|
|
remove(parentElm);
|
|
return replacementElm || splitElm;
|
|
}
|
|
};
|
|
var bind = function (target, name, func, scope) {
|
|
if (Tools.isArray(target)) {
|
|
var i = target.length;
|
|
var rv = [];
|
|
while (i--) {
|
|
rv[i] = bind(target[i], name, func, scope);
|
|
}
|
|
return rv;
|
|
}
|
|
if (settings.collect && (target === doc || target === win)) {
|
|
boundEvents.push([
|
|
target,
|
|
name,
|
|
func,
|
|
scope
|
|
]);
|
|
}
|
|
return events.bind(target, name, func, scope || self);
|
|
};
|
|
var unbind = function (target, name, func) {
|
|
var i;
|
|
if (Tools.isArray(target)) {
|
|
i = target.length;
|
|
var rv = [];
|
|
while (i--) {
|
|
rv[i] = unbind(target[i], name, func);
|
|
}
|
|
return rv;
|
|
}
|
|
if (boundEvents && (target === doc || target === win)) {
|
|
i = boundEvents.length;
|
|
while (i--) {
|
|
var item = boundEvents[i];
|
|
if (target === item[0] && (!name || name === item[1]) && (!func || func === item[2])) {
|
|
events.unbind(item[0], item[1], item[2]);
|
|
}
|
|
}
|
|
}
|
|
return events.unbind(target, name, func);
|
|
};
|
|
var fire = function (target, name, evt) {
|
|
return events.fire(target, name, evt);
|
|
};
|
|
var getContentEditable = function (node) {
|
|
if (node && NodeType.isElement(node)) {
|
|
var contentEditable = node.getAttribute('data-mce-contenteditable');
|
|
if (contentEditable && contentEditable !== 'inherit') {
|
|
return contentEditable;
|
|
}
|
|
return node.contentEditable !== 'inherit' ? node.contentEditable : null;
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
var getContentEditableParent = function (node) {
|
|
var root = getRoot();
|
|
var state = null;
|
|
for (; node && node !== root; node = node.parentNode) {
|
|
state = getContentEditable(node);
|
|
if (state !== null) {
|
|
break;
|
|
}
|
|
}
|
|
return state;
|
|
};
|
|
var destroy = function () {
|
|
if (boundEvents) {
|
|
var i = boundEvents.length;
|
|
while (i--) {
|
|
var item = boundEvents[i];
|
|
events.unbind(item[0], item[1], item[2]);
|
|
}
|
|
}
|
|
if (Sizzle.setDocument) {
|
|
Sizzle.setDocument();
|
|
}
|
|
};
|
|
var isChildOf = function (node, parent) {
|
|
while (node) {
|
|
if (parent === node) {
|
|
return true;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return false;
|
|
};
|
|
var dumpRng = function (r) {
|
|
return 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
|
|
};
|
|
var self = {
|
|
doc: doc,
|
|
settings: settings,
|
|
win: win,
|
|
files: files,
|
|
stdMode: stdMode,
|
|
boxModel: boxModel,
|
|
styleSheetLoader: styleSheetLoader,
|
|
boundEvents: boundEvents,
|
|
styles: styles,
|
|
schema: schema,
|
|
events: events,
|
|
isBlock: isBlock,
|
|
$: $,
|
|
$$: $$,
|
|
root: null,
|
|
clone: clone,
|
|
getRoot: getRoot,
|
|
getViewPort: getViewPort,
|
|
getRect: getRect,
|
|
getSize: getSize,
|
|
getParent: getParent,
|
|
getParents: getParents,
|
|
get: get,
|
|
getNext: getNext,
|
|
getPrev: getPrev,
|
|
select: select,
|
|
is: is,
|
|
add: add,
|
|
create: create,
|
|
createHTML: createHTML,
|
|
createFragment: createFragment,
|
|
remove: remove,
|
|
setStyle: setStyle,
|
|
getStyle: getStyle,
|
|
setStyles: setStyles,
|
|
removeAllAttribs: removeAllAttribs,
|
|
setAttrib: setAttrib,
|
|
setAttribs: setAttribs,
|
|
getAttrib: getAttrib,
|
|
getPos: getPos,
|
|
parseStyle: parseStyle,
|
|
serializeStyle: serializeStyle,
|
|
addStyle: addStyle,
|
|
loadCSS: loadCSS,
|
|
addClass: addClass,
|
|
removeClass: removeClass,
|
|
hasClass: hasClass,
|
|
toggleClass: toggleClass,
|
|
show: show,
|
|
hide: hide,
|
|
isHidden: isHidden,
|
|
uniqueId: uniqueId,
|
|
setHTML: setHTML,
|
|
getOuterHTML: getOuterHTML,
|
|
setOuterHTML: setOuterHTML,
|
|
decode: decode,
|
|
encode: encode,
|
|
insertAfter: insertAfter,
|
|
replace: replace,
|
|
rename: rename,
|
|
findCommonAncestor: findCommonAncestor,
|
|
toHex: toHex,
|
|
run: run,
|
|
getAttribs: getAttribs,
|
|
isEmpty: isEmpty,
|
|
createRng: createRng,
|
|
nodeIndex: findNodeIndex,
|
|
split: split,
|
|
bind: bind,
|
|
unbind: unbind,
|
|
fire: fire,
|
|
getContentEditable: getContentEditable,
|
|
getContentEditableParent: getContentEditableParent,
|
|
destroy: destroy,
|
|
isChildOf: isChildOf,
|
|
dumpRng: dumpRng
|
|
};
|
|
attrHooks = setupAttrHooks(styles, settings, function () {
|
|
return self;
|
|
});
|
|
return self;
|
|
}
|
|
(function (DOMUtils) {
|
|
DOMUtils.DOM = DOMUtils(domGlobals.document);
|
|
DOMUtils.nodeIndex = findNodeIndex;
|
|
}(DOMUtils || (DOMUtils = {})));
|
|
var DOMUtils$1 = DOMUtils;
|
|
|
|
var DOM = DOMUtils$1.DOM;
|
|
var each$6 = Tools.each, grep$2 = Tools.grep;
|
|
var QUEUED = 0;
|
|
var LOADING = 1;
|
|
var LOADED = 2;
|
|
var FAILED = 3;
|
|
var ScriptLoader = function () {
|
|
function ScriptLoader(settings) {
|
|
if (settings === void 0) {
|
|
settings = {};
|
|
}
|
|
this.states = {};
|
|
this.queue = [];
|
|
this.scriptLoadedCallbacks = {};
|
|
this.queueLoadedCallbacks = [];
|
|
this.loading = 0;
|
|
this.settings = settings;
|
|
}
|
|
ScriptLoader.prototype._setReferrerPolicy = function (referrerPolicy) {
|
|
this.settings.referrerPolicy = referrerPolicy;
|
|
};
|
|
ScriptLoader.prototype.loadScript = function (url, success, failure) {
|
|
var dom = DOM;
|
|
var elm, id;
|
|
var done = function () {
|
|
dom.remove(id);
|
|
if (elm) {
|
|
elm.onreadystatechange = elm.onload = elm = null;
|
|
}
|
|
success();
|
|
};
|
|
var error = function () {
|
|
if (isFunction(failure)) {
|
|
failure();
|
|
} else {
|
|
if (typeof domGlobals.console !== 'undefined' && domGlobals.console.log) {
|
|
domGlobals.console.log('Failed to load script: ' + url);
|
|
}
|
|
}
|
|
};
|
|
id = dom.uniqueId();
|
|
elm = domGlobals.document.createElement('script');
|
|
elm.id = id;
|
|
elm.type = 'text/javascript';
|
|
elm.src = Tools._addCacheSuffix(url);
|
|
if (this.settings.referrerPolicy) {
|
|
dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
|
|
}
|
|
elm.onload = done;
|
|
elm.onerror = error;
|
|
(domGlobals.document.getElementsByTagName('head')[0] || domGlobals.document.body).appendChild(elm);
|
|
};
|
|
ScriptLoader.prototype.isDone = function (url) {
|
|
return this.states[url] === LOADED;
|
|
};
|
|
ScriptLoader.prototype.markDone = function (url) {
|
|
this.states[url] = LOADED;
|
|
};
|
|
ScriptLoader.prototype.add = function (url, success, scope, failure) {
|
|
var state = this.states[url];
|
|
if (state === undefined) {
|
|
this.queue.push(url);
|
|
this.states[url] = QUEUED;
|
|
}
|
|
if (success) {
|
|
if (!this.scriptLoadedCallbacks[url]) {
|
|
this.scriptLoadedCallbacks[url] = [];
|
|
}
|
|
this.scriptLoadedCallbacks[url].push({
|
|
success: success,
|
|
failure: failure,
|
|
scope: scope || this
|
|
});
|
|
}
|
|
};
|
|
ScriptLoader.prototype.load = function (url, success, scope, failure) {
|
|
return this.add(url, success, scope, failure);
|
|
};
|
|
ScriptLoader.prototype.remove = function (url) {
|
|
delete this.states[url];
|
|
delete this.scriptLoadedCallbacks[url];
|
|
};
|
|
ScriptLoader.prototype.loadQueue = function (success, scope, failure) {
|
|
this.loadScripts(this.queue, success, scope, failure);
|
|
};
|
|
ScriptLoader.prototype.loadScripts = function (scripts, success, scope, failure) {
|
|
var self = this;
|
|
var loadScripts;
|
|
var failures = [];
|
|
var execCallbacks = function (name, url) {
|
|
each$6(self.scriptLoadedCallbacks[url], function (callback) {
|
|
if (isFunction(callback[name])) {
|
|
callback[name].call(callback.scope);
|
|
}
|
|
});
|
|
self.scriptLoadedCallbacks[url] = undefined;
|
|
};
|
|
self.queueLoadedCallbacks.push({
|
|
success: success,
|
|
failure: failure,
|
|
scope: scope || this
|
|
});
|
|
loadScripts = function () {
|
|
var loadingScripts = grep$2(scripts);
|
|
scripts.length = 0;
|
|
each$6(loadingScripts, function (url) {
|
|
if (self.states[url] === LOADED) {
|
|
execCallbacks('success', url);
|
|
return;
|
|
}
|
|
if (self.states[url] === FAILED) {
|
|
execCallbacks('failure', url);
|
|
return;
|
|
}
|
|
if (self.states[url] !== LOADING) {
|
|
self.states[url] = LOADING;
|
|
self.loading++;
|
|
self.loadScript(url, function () {
|
|
self.states[url] = LOADED;
|
|
self.loading--;
|
|
execCallbacks('success', url);
|
|
loadScripts();
|
|
}, function () {
|
|
self.states[url] = FAILED;
|
|
self.loading--;
|
|
failures.push(url);
|
|
execCallbacks('failure', url);
|
|
loadScripts();
|
|
});
|
|
}
|
|
});
|
|
if (!self.loading) {
|
|
var notifyCallbacks = self.queueLoadedCallbacks.slice(0);
|
|
self.queueLoadedCallbacks.length = 0;
|
|
each$6(notifyCallbacks, function (callback) {
|
|
if (failures.length === 0) {
|
|
if (isFunction(callback.success)) {
|
|
callback.success.call(callback.scope);
|
|
}
|
|
} else {
|
|
if (isFunction(callback.failure)) {
|
|
callback.failure.call(callback.scope, failures);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
loadScripts();
|
|
};
|
|
ScriptLoader.ScriptLoader = new ScriptLoader();
|
|
return ScriptLoader;
|
|
}();
|
|
|
|
var isRaw = function (str) {
|
|
return isObject(str) && has(str, 'raw');
|
|
};
|
|
var isTokenised = function (str) {
|
|
return isArray(str) && str.length > 1;
|
|
};
|
|
var data = {};
|
|
var currentCode = Cell('en');
|
|
var getData = function () {
|
|
return map$1(data, function (value) {
|
|
return __assign({}, value);
|
|
});
|
|
};
|
|
var setCode = function (newCode) {
|
|
if (newCode) {
|
|
currentCode.set(newCode);
|
|
}
|
|
};
|
|
var getCode = function () {
|
|
return currentCode.get();
|
|
};
|
|
var add = function (code, items) {
|
|
var langData = data[code];
|
|
if (!langData) {
|
|
data[code] = langData = {};
|
|
}
|
|
for (var name in items) {
|
|
langData[name.toLowerCase()] = items[name];
|
|
}
|
|
};
|
|
var translate = function (text) {
|
|
var langData = data[currentCode.get()] || {};
|
|
var toString = function (obj) {
|
|
if (isFunction(obj)) {
|
|
return Object.prototype.toString.call(obj);
|
|
}
|
|
return !isEmpty(obj) ? '' + obj : '';
|
|
};
|
|
var isEmpty = function (text) {
|
|
return text === '' || text === null || text === undefined;
|
|
};
|
|
var getLangData = function (text) {
|
|
var textstr = toString(text);
|
|
var lowercaseTextstr = textstr.toLowerCase();
|
|
return has(langData, lowercaseTextstr) ? toString(langData[lowercaseTextstr]) : textstr;
|
|
};
|
|
var removeContext = function (str) {
|
|
return str.replace(/{context:\w+}$/, '');
|
|
};
|
|
var translated = function (text) {
|
|
return text;
|
|
};
|
|
if (isEmpty(text)) {
|
|
return translated('');
|
|
}
|
|
if (isRaw(text)) {
|
|
return translated(toString(text.raw));
|
|
}
|
|
if (isTokenised(text)) {
|
|
var values_1 = text.slice(1);
|
|
var substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, function ($1, $2) {
|
|
return has(values_1, $2) ? toString(values_1[$2]) : $1;
|
|
});
|
|
return translated(removeContext(substitued));
|
|
}
|
|
return translated(removeContext(getLangData(text)));
|
|
};
|
|
var isRtl = function () {
|
|
return get(data, currentCode.get()).bind(function (items) {
|
|
return get(items, '_dir');
|
|
}).exists(function (dir) {
|
|
return dir === 'rtl';
|
|
});
|
|
};
|
|
var hasCode = function (code) {
|
|
return has(data, code);
|
|
};
|
|
var I18n = {
|
|
getData: getData,
|
|
setCode: setCode,
|
|
getCode: getCode,
|
|
add: add,
|
|
translate: translate,
|
|
isRtl: isRtl,
|
|
hasCode: hasCode
|
|
};
|
|
|
|
var each$7 = Tools.each;
|
|
function AddOnManager() {
|
|
var _this = this;
|
|
var items = [];
|
|
var urls = {};
|
|
var lookup = {};
|
|
var _listeners = [];
|
|
var get = function (name) {
|
|
if (lookup[name]) {
|
|
return lookup[name].instance;
|
|
}
|
|
return undefined;
|
|
};
|
|
var dependencies = function (name) {
|
|
var result;
|
|
if (lookup[name]) {
|
|
result = lookup[name].dependencies;
|
|
}
|
|
return result || [];
|
|
};
|
|
var requireLangPack = function (name, languages) {
|
|
var language = I18n.getCode();
|
|
if (language && AddOnManager.languageLoad !== false) {
|
|
if (languages) {
|
|
languages = ',' + languages + ',';
|
|
if (languages.indexOf(',' + language.substr(0, 2) + ',') !== -1) {
|
|
language = language.substr(0, 2);
|
|
} else if (languages.indexOf(',' + language + ',') === -1) {
|
|
return;
|
|
}
|
|
}
|
|
ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
|
|
}
|
|
};
|
|
var add = function (id, addOn, dependencies) {
|
|
items.push(addOn);
|
|
lookup[id] = {
|
|
instance: addOn,
|
|
dependencies: dependencies
|
|
};
|
|
var result = partition(_listeners, function (listener) {
|
|
return listener.name === id;
|
|
});
|
|
_listeners = result.fail;
|
|
each$7(result.pass, function (listener) {
|
|
listener.callback();
|
|
});
|
|
return addOn;
|
|
};
|
|
var remove = function (name) {
|
|
delete urls[name];
|
|
delete lookup[name];
|
|
};
|
|
var createUrl = function (baseUrl, dep) {
|
|
if (typeof dep === 'object') {
|
|
return dep;
|
|
}
|
|
return typeof baseUrl === 'string' ? {
|
|
prefix: '',
|
|
resource: dep,
|
|
suffix: ''
|
|
} : {
|
|
prefix: baseUrl.prefix,
|
|
resource: dep,
|
|
suffix: baseUrl.suffix
|
|
};
|
|
};
|
|
var addComponents = function (pluginName, scripts) {
|
|
var pluginUrl = _this.urls[pluginName];
|
|
each$7(scripts, function (script) {
|
|
ScriptLoader.ScriptLoader.add(pluginUrl + '/' + script);
|
|
});
|
|
};
|
|
var loadDependencies = function (name, addOnUrl, success, scope) {
|
|
var deps = dependencies(name);
|
|
each$7(deps, function (dep) {
|
|
var newUrl = createUrl(addOnUrl, dep);
|
|
load(newUrl.resource, newUrl, undefined, undefined);
|
|
});
|
|
if (success) {
|
|
if (scope) {
|
|
success.call(scope);
|
|
} else {
|
|
success.call(ScriptLoader);
|
|
}
|
|
}
|
|
};
|
|
var load = function (name, addOnUrl, success, scope, failure) {
|
|
if (urls[name]) {
|
|
return;
|
|
}
|
|
var urlString = typeof addOnUrl === 'string' ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
|
|
if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
|
|
urlString = AddOnManager.baseURL + '/' + urlString;
|
|
}
|
|
urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
|
|
if (lookup[name]) {
|
|
loadDependencies(name, addOnUrl, success, scope);
|
|
} else {
|
|
ScriptLoader.ScriptLoader.add(urlString, function () {
|
|
return loadDependencies(name, addOnUrl, success, scope);
|
|
}, scope, failure);
|
|
}
|
|
};
|
|
var waitFor = function (name, callback) {
|
|
if (lookup.hasOwnProperty(name)) {
|
|
callback();
|
|
} else {
|
|
_listeners.push({
|
|
name: name,
|
|
callback: callback
|
|
});
|
|
}
|
|
};
|
|
return {
|
|
items: items,
|
|
urls: urls,
|
|
lookup: lookup,
|
|
_listeners: _listeners,
|
|
get: get,
|
|
dependencies: dependencies,
|
|
requireLangPack: requireLangPack,
|
|
add: add,
|
|
remove: remove,
|
|
createUrl: createUrl,
|
|
addComponents: addComponents,
|
|
load: load,
|
|
waitFor: waitFor
|
|
};
|
|
}
|
|
(function (AddOnManager) {
|
|
AddOnManager.PluginManager = AddOnManager();
|
|
AddOnManager.ThemeManager = AddOnManager();
|
|
}(AddOnManager || (AddOnManager = {})));
|
|
var AddOnManager$1 = AddOnManager;
|
|
|
|
var first = function (fn, rate) {
|
|
var timer = null;
|
|
var cancel = function () {
|
|
if (timer !== null) {
|
|
domGlobals.clearTimeout(timer);
|
|
timer = null;
|
|
}
|
|
};
|
|
var throttle = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (timer === null) {
|
|
timer = domGlobals.setTimeout(function () {
|
|
fn.apply(null, args);
|
|
timer = null;
|
|
}, rate);
|
|
}
|
|
};
|
|
return {
|
|
cancel: cancel,
|
|
throttle: throttle
|
|
};
|
|
};
|
|
var last$2 = function (fn, rate) {
|
|
var timer = null;
|
|
var cancel = function () {
|
|
if (timer !== null) {
|
|
domGlobals.clearTimeout(timer);
|
|
timer = null;
|
|
}
|
|
};
|
|
var throttle = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (timer !== null) {
|
|
domGlobals.clearTimeout(timer);
|
|
}
|
|
timer = domGlobals.setTimeout(function () {
|
|
fn.apply(null, args);
|
|
timer = null;
|
|
}, rate);
|
|
};
|
|
return {
|
|
cancel: cancel,
|
|
throttle: throttle
|
|
};
|
|
};
|
|
|
|
var read = function (element, attr) {
|
|
var value = get$1(element, attr);
|
|
return value === undefined || value === '' ? [] : value.split(' ');
|
|
};
|
|
var add$1 = function (element, attr, id) {
|
|
var old = read(element, attr);
|
|
var nu = old.concat([id]);
|
|
set(element, attr, nu.join(' '));
|
|
return true;
|
|
};
|
|
var remove$2 = function (element, attr, id) {
|
|
var nu = filter(read(element, attr), function (v) {
|
|
return v !== id;
|
|
});
|
|
if (nu.length > 0) {
|
|
set(element, attr, nu.join(' '));
|
|
} else {
|
|
remove(element, attr);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
var supports = function (element) {
|
|
return element.dom().classList !== undefined;
|
|
};
|
|
var get$4 = function (element) {
|
|
return read(element, 'class');
|
|
};
|
|
var add$2 = function (element, clazz) {
|
|
return add$1(element, 'class', clazz);
|
|
};
|
|
var remove$3 = function (element, clazz) {
|
|
return remove$2(element, 'class', clazz);
|
|
};
|
|
|
|
var add$3 = function (element, clazz) {
|
|
if (supports(element)) {
|
|
element.dom().classList.add(clazz);
|
|
} else {
|
|
add$2(element, clazz);
|
|
}
|
|
};
|
|
var cleanClass = function (element) {
|
|
var classList = supports(element) ? element.dom().classList : get$4(element);
|
|
if (classList.length === 0) {
|
|
remove(element, 'class');
|
|
}
|
|
};
|
|
var remove$4 = function (element, clazz) {
|
|
if (supports(element)) {
|
|
var classList = element.dom().classList;
|
|
classList.remove(clazz);
|
|
} else {
|
|
remove$3(element, clazz);
|
|
}
|
|
cleanClass(element);
|
|
};
|
|
var has$2 = function (element, clazz) {
|
|
return supports(element) && element.dom().classList.contains(clazz);
|
|
};
|
|
|
|
var descendants = function (scope, predicate) {
|
|
var result = [];
|
|
each(children(scope), function (x) {
|
|
if (predicate(x)) {
|
|
result = result.concat([x]);
|
|
}
|
|
result = result.concat(descendants(x, predicate));
|
|
});
|
|
return result;
|
|
};
|
|
|
|
var descendants$1 = function (scope, selector) {
|
|
return all(selector, scope);
|
|
};
|
|
|
|
function ClosestOrAncestor (is, ancestor, scope, a, isRoot) {
|
|
return is(scope, a) ? Option.some(scope) : isFunction(isRoot) && isRoot(scope) ? Option.none() : ancestor(scope, a, isRoot);
|
|
}
|
|
|
|
var ancestor = function (scope, predicate, isRoot) {
|
|
var element = scope.dom();
|
|
var stop = isFunction(isRoot) ? isRoot : constant(false);
|
|
while (element.parentNode) {
|
|
element = element.parentNode;
|
|
var el = Element.fromDom(element);
|
|
if (predicate(el)) {
|
|
return Option.some(el);
|
|
} else if (stop(el)) {
|
|
break;
|
|
}
|
|
}
|
|
return Option.none();
|
|
};
|
|
var closest = function (scope, predicate, isRoot) {
|
|
var is = function (s, test) {
|
|
return test(s);
|
|
};
|
|
return ClosestOrAncestor(is, ancestor, scope, predicate, isRoot);
|
|
};
|
|
|
|
var ancestor$1 = function (scope, selector, isRoot) {
|
|
return ancestor(scope, function (e) {
|
|
return is(e, selector);
|
|
}, isRoot);
|
|
};
|
|
var descendant = function (scope, selector) {
|
|
return one(selector, scope);
|
|
};
|
|
var closest$1 = function (scope, selector, isRoot) {
|
|
return ClosestOrAncestor(is, ancestor$1, scope, selector, isRoot);
|
|
};
|
|
|
|
var annotation = constant('mce-annotation');
|
|
var dataAnnotation = constant('data-mce-annotation');
|
|
var dataAnnotationId = constant('data-mce-annotation-uid');
|
|
|
|
var identify = function (editor, annotationName) {
|
|
var rng = editor.selection.getRng();
|
|
var start = Element.fromDom(rng.startContainer);
|
|
var root = Element.fromDom(editor.getBody());
|
|
var selector = annotationName.fold(function () {
|
|
return '.' + annotation();
|
|
}, function (an) {
|
|
return '[' + dataAnnotation() + '="' + an + '"]';
|
|
});
|
|
var newStart = child(start, rng.startOffset).getOr(start);
|
|
var closest = closest$1(newStart, selector, function (n) {
|
|
return eq(n, root);
|
|
});
|
|
var getAttr = function (c, property) {
|
|
if (has$1(c, property)) {
|
|
return Option.some(get$1(c, property));
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
};
|
|
return closest.bind(function (c) {
|
|
return getAttr(c, '' + dataAnnotationId()).bind(function (uid) {
|
|
return getAttr(c, '' + dataAnnotation()).map(function (name) {
|
|
var elements = findMarkers(editor, uid);
|
|
return {
|
|
uid: uid,
|
|
name: name,
|
|
elements: elements
|
|
};
|
|
});
|
|
});
|
|
});
|
|
};
|
|
var isAnnotation = function (elem) {
|
|
return isElement$1(elem) && has$2(elem, annotation());
|
|
};
|
|
var findMarkers = function (editor, uid) {
|
|
var body = Element.fromDom(editor.getBody());
|
|
return descendants$1(body, '[' + dataAnnotationId() + '="' + uid + '"]');
|
|
};
|
|
var findAll = function (editor, name) {
|
|
var body = Element.fromDom(editor.getBody());
|
|
var markers = descendants$1(body, '[' + dataAnnotation() + '="' + name + '"]');
|
|
var directory = {};
|
|
each(markers, function (m) {
|
|
var uid = get$1(m, dataAnnotationId());
|
|
var nodesAlready = directory.hasOwnProperty(uid) ? directory[uid] : [];
|
|
directory[uid] = nodesAlready.concat([m]);
|
|
});
|
|
return directory;
|
|
};
|
|
|
|
var setup = function (editor, registry) {
|
|
var changeCallbacks = Cell({});
|
|
var initData = function () {
|
|
return {
|
|
listeners: [],
|
|
previous: Cell(Option.none())
|
|
};
|
|
};
|
|
var withCallbacks = function (name, f) {
|
|
updateCallbacks(name, function (data) {
|
|
f(data);
|
|
return data;
|
|
});
|
|
};
|
|
var updateCallbacks = function (name, f) {
|
|
var callbackMap = changeCallbacks.get();
|
|
var data = callbackMap.hasOwnProperty(name) ? callbackMap[name] : initData();
|
|
var outputData = f(data);
|
|
callbackMap[name] = outputData;
|
|
changeCallbacks.set(callbackMap);
|
|
};
|
|
var fireCallbacks = function (name, uid, elements) {
|
|
withCallbacks(name, function (data) {
|
|
each(data.listeners, function (f) {
|
|
return f(true, name, {
|
|
uid: uid,
|
|
nodes: map(elements, function (elem) {
|
|
return elem.dom();
|
|
})
|
|
});
|
|
});
|
|
});
|
|
};
|
|
var fireNoAnnotation = function (name) {
|
|
withCallbacks(name, function (data) {
|
|
each(data.listeners, function (f) {
|
|
return f(false, name);
|
|
});
|
|
});
|
|
};
|
|
var onNodeChange = last$2(function () {
|
|
var callbackMap = changeCallbacks.get();
|
|
var annotations = sort(keys(callbackMap));
|
|
each(annotations, function (name) {
|
|
updateCallbacks(name, function (data) {
|
|
var prev = data.previous.get();
|
|
identify(editor, Option.some(name)).fold(function () {
|
|
if (prev.isSome()) {
|
|
fireNoAnnotation(name);
|
|
data.previous.set(Option.none());
|
|
}
|
|
}, function (_a) {
|
|
var uid = _a.uid, name = _a.name, elements = _a.elements;
|
|
if (!prev.is(uid)) {
|
|
fireCallbacks(name, uid, elements);
|
|
data.previous.set(Option.some(uid));
|
|
}
|
|
});
|
|
return {
|
|
previous: data.previous,
|
|
listeners: data.listeners
|
|
};
|
|
});
|
|
});
|
|
}, 30);
|
|
editor.on('remove', function () {
|
|
onNodeChange.cancel();
|
|
});
|
|
editor.on('NodeChange', function () {
|
|
onNodeChange.throttle();
|
|
});
|
|
var addListener = function (name, f) {
|
|
updateCallbacks(name, function (data) {
|
|
return {
|
|
previous: data.previous,
|
|
listeners: data.listeners.concat([f])
|
|
};
|
|
});
|
|
};
|
|
return { addListener: addListener };
|
|
};
|
|
|
|
var setup$1 = function (editor, registry) {
|
|
var identifyParserNode = function (span) {
|
|
return Option.from(span.attr(dataAnnotation())).bind(registry.lookup);
|
|
};
|
|
editor.on('init', function () {
|
|
editor.serializer.addNodeFilter('span', function (spans) {
|
|
each(spans, function (span) {
|
|
identifyParserNode(span).each(function (settings) {
|
|
if (settings.persistent === false) {
|
|
span.unwrap();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
var create$1 = function () {
|
|
var annotations = {};
|
|
var register = function (name, settings) {
|
|
annotations[name] = {
|
|
name: name,
|
|
settings: settings
|
|
};
|
|
};
|
|
var lookup = function (name) {
|
|
return annotations.hasOwnProperty(name) ? Option.from(annotations[name]).map(function (a) {
|
|
return a.settings;
|
|
}) : Option.none();
|
|
};
|
|
return {
|
|
register: register,
|
|
lookup: lookup
|
|
};
|
|
};
|
|
|
|
var unique = 0;
|
|
var generate = function (prefix) {
|
|
var date = new Date();
|
|
var time = date.getTime();
|
|
var random = Math.floor(Math.random() * 1000000000);
|
|
unique++;
|
|
return prefix + '_' + random + unique + String(time);
|
|
};
|
|
|
|
var add$4 = function (element, classes) {
|
|
each(classes, function (x) {
|
|
add$3(element, x);
|
|
});
|
|
};
|
|
|
|
var clone = function (original, isDeep) {
|
|
return Element.fromDom(original.dom().cloneNode(isDeep));
|
|
};
|
|
var shallow = function (original) {
|
|
return clone(original, false);
|
|
};
|
|
var deep = function (original) {
|
|
return clone(original, true);
|
|
};
|
|
|
|
var fromHtml$1 = function (html, scope) {
|
|
var doc = scope || domGlobals.document;
|
|
var div = doc.createElement('div');
|
|
div.innerHTML = html;
|
|
return children(Element.fromDom(div));
|
|
};
|
|
|
|
var get$5 = function (element) {
|
|
return element.dom().innerHTML;
|
|
};
|
|
var set$1 = function (element, content) {
|
|
var owner$1 = owner(element);
|
|
var docDom = owner$1.dom();
|
|
var fragment = Element.fromDom(docDom.createDocumentFragment());
|
|
var contentElements = fromHtml$1(content, docDom);
|
|
append$1(fragment, contentElements);
|
|
empty(element);
|
|
append(element, fragment);
|
|
};
|
|
|
|
var ZWSP = '\uFEFF';
|
|
var isZwsp = function (chr) {
|
|
return chr === ZWSP;
|
|
};
|
|
var trim$3 = function (text) {
|
|
return text.replace(new RegExp(ZWSP, 'g'), '');
|
|
};
|
|
var Zwsp = {
|
|
isZwsp: isZwsp,
|
|
ZWSP: ZWSP,
|
|
trim: trim$3
|
|
};
|
|
|
|
var isElement$2 = NodeType.isElement;
|
|
var isText$2 = NodeType.isText;
|
|
var isCaretContainerBlock = function (node) {
|
|
if (isText$2(node)) {
|
|
node = node.parentNode;
|
|
}
|
|
return isElement$2(node) && node.hasAttribute('data-mce-caret');
|
|
};
|
|
var isCaretContainerInline = function (node) {
|
|
return isText$2(node) && Zwsp.isZwsp(node.data);
|
|
};
|
|
var isCaretContainer = function (node) {
|
|
return isCaretContainerBlock(node) || isCaretContainerInline(node);
|
|
};
|
|
var hasContent = function (node) {
|
|
return node.firstChild !== node.lastChild || !NodeType.isBr(node.firstChild);
|
|
};
|
|
var insertInline = function (node, before) {
|
|
var doc, sibling, textNode, parentNode;
|
|
doc = node.ownerDocument;
|
|
textNode = doc.createTextNode(Zwsp.ZWSP);
|
|
parentNode = node.parentNode;
|
|
if (!before) {
|
|
sibling = node.nextSibling;
|
|
if (isText$2(sibling)) {
|
|
if (isCaretContainer(sibling)) {
|
|
return sibling;
|
|
}
|
|
if (startsWithCaretContainer(sibling)) {
|
|
sibling.splitText(1);
|
|
return sibling;
|
|
}
|
|
}
|
|
if (node.nextSibling) {
|
|
parentNode.insertBefore(textNode, node.nextSibling);
|
|
} else {
|
|
parentNode.appendChild(textNode);
|
|
}
|
|
} else {
|
|
sibling = node.previousSibling;
|
|
if (isText$2(sibling)) {
|
|
if (isCaretContainer(sibling)) {
|
|
return sibling;
|
|
}
|
|
if (endsWithCaretContainer(sibling)) {
|
|
return sibling.splitText(sibling.data.length - 1);
|
|
}
|
|
}
|
|
parentNode.insertBefore(textNode, node);
|
|
}
|
|
return textNode;
|
|
};
|
|
var isBeforeInline = function (pos) {
|
|
var container = pos.container();
|
|
if (!pos || !NodeType.isText(container)) {
|
|
return false;
|
|
}
|
|
return container.data.charAt(pos.offset()) === Zwsp.ZWSP || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
|
|
};
|
|
var isAfterInline = function (pos) {
|
|
var container = pos.container();
|
|
if (!pos || !NodeType.isText(container)) {
|
|
return false;
|
|
}
|
|
return container.data.charAt(pos.offset() - 1) === Zwsp.ZWSP || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
|
|
};
|
|
var createBogusBr = function () {
|
|
var br = domGlobals.document.createElement('br');
|
|
br.setAttribute('data-mce-bogus', '1');
|
|
return br;
|
|
};
|
|
var insertBlock = function (blockName, node, before) {
|
|
var doc, blockNode, parentNode;
|
|
doc = node.ownerDocument;
|
|
blockNode = doc.createElement(blockName);
|
|
blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
|
|
blockNode.setAttribute('data-mce-bogus', 'all');
|
|
blockNode.appendChild(createBogusBr());
|
|
parentNode = node.parentNode;
|
|
if (!before) {
|
|
if (node.nextSibling) {
|
|
parentNode.insertBefore(blockNode, node.nextSibling);
|
|
} else {
|
|
parentNode.appendChild(blockNode);
|
|
}
|
|
} else {
|
|
parentNode.insertBefore(blockNode, node);
|
|
}
|
|
return blockNode;
|
|
};
|
|
var startsWithCaretContainer = function (node) {
|
|
return isText$2(node) && node.data[0] === Zwsp.ZWSP;
|
|
};
|
|
var endsWithCaretContainer = function (node) {
|
|
return isText$2(node) && node.data[node.data.length - 1] === Zwsp.ZWSP;
|
|
};
|
|
var trimBogusBr = function (elm) {
|
|
var brs = elm.getElementsByTagName('br');
|
|
var lastBr = brs[brs.length - 1];
|
|
if (NodeType.isBogus(lastBr)) {
|
|
lastBr.parentNode.removeChild(lastBr);
|
|
}
|
|
};
|
|
var showCaretContainerBlock = function (caretContainer) {
|
|
if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
|
|
trimBogusBr(caretContainer);
|
|
caretContainer.removeAttribute('data-mce-caret');
|
|
caretContainer.removeAttribute('data-mce-bogus');
|
|
caretContainer.removeAttribute('style');
|
|
caretContainer.removeAttribute('_moz_abspos');
|
|
return caretContainer;
|
|
}
|
|
return null;
|
|
};
|
|
var isRangeInCaretContainerBlock = function (range) {
|
|
return isCaretContainerBlock(range.startContainer);
|
|
};
|
|
|
|
var isContentEditableTrue$1 = NodeType.isContentEditableTrue;
|
|
var isContentEditableFalse$1 = NodeType.isContentEditableFalse;
|
|
var isBr$2 = NodeType.isBr;
|
|
var isText$3 = NodeType.isText;
|
|
var isInvalidTextElement = NodeType.matchNodeNames([
|
|
'script',
|
|
'style',
|
|
'textarea'
|
|
]);
|
|
var isAtomicInline = NodeType.matchNodeNames([
|
|
'img',
|
|
'input',
|
|
'textarea',
|
|
'hr',
|
|
'iframe',
|
|
'video',
|
|
'audio',
|
|
'object'
|
|
]);
|
|
var isTable$2 = NodeType.matchNodeNames(['table']);
|
|
var isCaretContainer$1 = isCaretContainer;
|
|
var isCaretCandidate = function (node) {
|
|
if (isCaretContainer$1(node)) {
|
|
return false;
|
|
}
|
|
if (isText$3(node)) {
|
|
if (isInvalidTextElement(node.parentNode)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return isAtomicInline(node) || isBr$2(node) || isTable$2(node) || isNonUiContentEditableFalse(node);
|
|
};
|
|
var isUnselectable = function (node) {
|
|
return NodeType.isElement(node) && node.getAttribute('unselectable') === 'true';
|
|
};
|
|
var isNonUiContentEditableFalse = function (node) {
|
|
return isUnselectable(node) === false && isContentEditableFalse$1(node);
|
|
};
|
|
var isInEditable = function (node, root) {
|
|
for (node = node.parentNode; node && node !== root; node = node.parentNode) {
|
|
if (isNonUiContentEditableFalse(node)) {
|
|
return false;
|
|
}
|
|
if (isContentEditableTrue$1(node)) {
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
var isAtomicContentEditableFalse = function (node) {
|
|
if (!isNonUiContentEditableFalse(node)) {
|
|
return false;
|
|
}
|
|
return foldl(from$1(node.getElementsByTagName('*')), function (result, elm) {
|
|
return result || isContentEditableTrue$1(elm);
|
|
}, false) !== true;
|
|
};
|
|
var isAtomic = function (node) {
|
|
return isAtomicInline(node) || isAtomicContentEditableFalse(node);
|
|
};
|
|
var isEditableCaretCandidate = function (node, root) {
|
|
return isCaretCandidate(node) && isInEditable(node, root);
|
|
};
|
|
|
|
var round = Math.round;
|
|
var clone$1 = function (rect) {
|
|
if (!rect) {
|
|
return {
|
|
left: 0,
|
|
top: 0,
|
|
bottom: 0,
|
|
right: 0,
|
|
width: 0,
|
|
height: 0
|
|
};
|
|
}
|
|
return {
|
|
left: round(rect.left),
|
|
top: round(rect.top),
|
|
bottom: round(rect.bottom),
|
|
right: round(rect.right),
|
|
width: round(rect.width),
|
|
height: round(rect.height)
|
|
};
|
|
};
|
|
var collapse = function (rect, toStart) {
|
|
rect = clone$1(rect);
|
|
if (toStart) {
|
|
rect.right = rect.left;
|
|
} else {
|
|
rect.left = rect.left + rect.width;
|
|
rect.right = rect.left;
|
|
}
|
|
rect.width = 0;
|
|
return rect;
|
|
};
|
|
var isEqual = function (rect1, rect2) {
|
|
return rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
|
|
};
|
|
var isValidOverflow = function (overflowY, rect1, rect2) {
|
|
return overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
|
|
};
|
|
var isAbove = function (rect1, rect2) {
|
|
if (rect1.bottom - rect1.height / 2 < rect2.top) {
|
|
return true;
|
|
}
|
|
if (rect1.top > rect2.bottom) {
|
|
return false;
|
|
}
|
|
return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
|
|
};
|
|
var isBelow = function (rect1, rect2) {
|
|
if (rect1.top > rect2.bottom) {
|
|
return true;
|
|
}
|
|
if (rect1.bottom < rect2.top) {
|
|
return false;
|
|
}
|
|
return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
|
|
};
|
|
var containsXY = function (rect, clientX, clientY) {
|
|
return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
|
};
|
|
|
|
var getSelectedNode = function (range) {
|
|
var startContainer = range.startContainer, startOffset = range.startOffset;
|
|
if (startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
|
|
return startContainer.childNodes[startOffset];
|
|
}
|
|
return null;
|
|
};
|
|
var getNode = function (container, offset) {
|
|
if (container.nodeType === 1 && container.hasChildNodes()) {
|
|
if (offset >= container.childNodes.length) {
|
|
offset = container.childNodes.length - 1;
|
|
}
|
|
container = container.childNodes[offset];
|
|
}
|
|
return container;
|
|
};
|
|
|
|
var extendingChars = new RegExp('[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a' + '\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0' + '\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c' + '\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3' + '\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc' + '\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57' + '\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56' + '\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44' + '\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9' + '\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97' + '\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074' + '\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5' + '\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18' + '\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1ABE\u1b00-\u1b03\u1b34' + '\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9' + '\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9' + '\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20DD-\u20E0\u20e1\u20E2-\u20E4\u20e5-\u20f0\u2cef-\u2cf1' + '\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\uA670-\uA672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1' + '\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc' + '\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1' + '\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]');
|
|
var isExtendingChar = function (ch) {
|
|
return typeof ch === 'string' && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
|
|
};
|
|
|
|
var lift2 = function (oa, ob, f) {
|
|
return oa.isSome() && ob.isSome() ? Option.some(f(oa.getOrDie(), ob.getOrDie())) : Option.none();
|
|
};
|
|
var lift3 = function (oa, ob, oc, f) {
|
|
return oa.isSome() && ob.isSome() && oc.isSome() ? Option.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Option.none();
|
|
};
|
|
var someIf = function (b, a) {
|
|
return b ? Option.some(a) : Option.none();
|
|
};
|
|
|
|
var slice$2 = [].slice;
|
|
var or = function () {
|
|
var x = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
x[_i] = arguments[_i];
|
|
}
|
|
var args = slice$2.call(arguments);
|
|
return function (x) {
|
|
for (var i = 0; i < args.length; i++) {
|
|
if (args[i](x)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
};
|
|
var and = function () {
|
|
var x = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
x[_i] = arguments[_i];
|
|
}
|
|
var args = slice$2.call(arguments);
|
|
return function (x) {
|
|
for (var i = 0; i < args.length; i++) {
|
|
if (!args[i](x)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
};
|
|
var Predicate = {
|
|
and: and,
|
|
or: or
|
|
};
|
|
|
|
var isElement$3 = NodeType.isElement;
|
|
var isCaretCandidate$1 = isCaretCandidate;
|
|
var isBlock$1 = NodeType.matchStyleValues('display', 'block table');
|
|
var isFloated = NodeType.matchStyleValues('float', 'left right');
|
|
var isValidElementCaretCandidate = Predicate.and(isElement$3, isCaretCandidate$1, not(isFloated));
|
|
var isNotPre = not(NodeType.matchStyleValues('white-space', 'pre pre-line pre-wrap'));
|
|
var isText$4 = NodeType.isText;
|
|
var isBr$3 = NodeType.isBr;
|
|
var nodeIndex = DOMUtils$1.nodeIndex;
|
|
var resolveIndex = getNode;
|
|
var createRange = function (doc) {
|
|
return 'createRange' in doc ? doc.createRange() : DOMUtils$1.DOM.createRng();
|
|
};
|
|
var isWhiteSpace = function (chr) {
|
|
return chr && /[\r\n\t ]/.test(chr);
|
|
};
|
|
var isRange = function (rng) {
|
|
return !!rng.setStart && !!rng.setEnd;
|
|
};
|
|
var isHiddenWhiteSpaceRange = function (range) {
|
|
var container = range.startContainer;
|
|
var offset = range.startOffset;
|
|
var text;
|
|
if (isWhiteSpace(range.toString()) && isNotPre(container.parentNode) && NodeType.isText(container)) {
|
|
text = container.data;
|
|
if (isWhiteSpace(text[offset - 1]) || isWhiteSpace(text[offset + 1])) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var getBrClientRect = function (brNode) {
|
|
var doc = brNode.ownerDocument;
|
|
var rng = createRange(doc);
|
|
var nbsp = doc.createTextNode('\xA0');
|
|
var parentNode = brNode.parentNode;
|
|
var clientRect;
|
|
parentNode.insertBefore(nbsp, brNode);
|
|
rng.setStart(nbsp, 0);
|
|
rng.setEnd(nbsp, 1);
|
|
clientRect = clone$1(rng.getBoundingClientRect());
|
|
parentNode.removeChild(nbsp);
|
|
return clientRect;
|
|
};
|
|
var getBoundingClientRectWebKitText = function (rng) {
|
|
var sc = rng.startContainer;
|
|
var ec = rng.endContainer;
|
|
var so = rng.startOffset;
|
|
var eo = rng.endOffset;
|
|
if (sc === ec && NodeType.isText(ec) && so === 0 && eo === 1) {
|
|
var newRng = rng.cloneRange();
|
|
newRng.setEndAfter(ec);
|
|
return getBoundingClientRect(newRng);
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
var isZeroRect = function (r) {
|
|
return r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
|
|
};
|
|
var getBoundingClientRect = function (item) {
|
|
var clientRect, clientRects;
|
|
clientRects = item.getClientRects();
|
|
if (clientRects.length > 0) {
|
|
clientRect = clone$1(clientRects[0]);
|
|
} else {
|
|
clientRect = clone$1(item.getBoundingClientRect());
|
|
}
|
|
if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
|
|
return getBrClientRect(item);
|
|
}
|
|
if (isZeroRect(clientRect) && isRange(item)) {
|
|
return getBoundingClientRectWebKitText(item);
|
|
}
|
|
return clientRect;
|
|
};
|
|
var collapseAndInflateWidth = function (clientRect, toStart) {
|
|
var newClientRect = collapse(clientRect, toStart);
|
|
newClientRect.width = 1;
|
|
newClientRect.right = newClientRect.left + 1;
|
|
return newClientRect;
|
|
};
|
|
var getCaretPositionClientRects = function (caretPosition) {
|
|
var clientRects = [];
|
|
var beforeNode, node;
|
|
var addUniqueAndValidRect = function (clientRect) {
|
|
if (clientRect.height === 0) {
|
|
return;
|
|
}
|
|
if (clientRects.length > 0) {
|
|
if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
|
|
return;
|
|
}
|
|
}
|
|
clientRects.push(clientRect);
|
|
};
|
|
var addCharacterOffset = function (container, offset) {
|
|
var range = createRange(container.ownerDocument);
|
|
if (offset < container.data.length) {
|
|
if (isExtendingChar(container.data[offset])) {
|
|
return clientRects;
|
|
}
|
|
if (isExtendingChar(container.data[offset - 1])) {
|
|
range.setStart(container, offset);
|
|
range.setEnd(container, offset + 1);
|
|
if (!isHiddenWhiteSpaceRange(range)) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), false));
|
|
return clientRects;
|
|
}
|
|
}
|
|
}
|
|
if (offset > 0) {
|
|
range.setStart(container, offset - 1);
|
|
range.setEnd(container, offset);
|
|
if (!isHiddenWhiteSpaceRange(range)) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), false));
|
|
}
|
|
}
|
|
if (offset < container.data.length) {
|
|
range.setStart(container, offset);
|
|
range.setEnd(container, offset + 1);
|
|
if (!isHiddenWhiteSpaceRange(range)) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(range), true));
|
|
}
|
|
}
|
|
};
|
|
if (isText$4(caretPosition.container())) {
|
|
addCharacterOffset(caretPosition.container(), caretPosition.offset());
|
|
return clientRects;
|
|
}
|
|
if (isElement$3(caretPosition.container())) {
|
|
if (caretPosition.isAtEnd()) {
|
|
node = resolveIndex(caretPosition.container(), caretPosition.offset());
|
|
if (isText$4(node)) {
|
|
addCharacterOffset(node, node.data.length);
|
|
}
|
|
if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), false));
|
|
}
|
|
} else {
|
|
node = resolveIndex(caretPosition.container(), caretPosition.offset());
|
|
if (isText$4(node)) {
|
|
addCharacterOffset(node, 0);
|
|
}
|
|
if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), false));
|
|
return clientRects;
|
|
}
|
|
beforeNode = resolveIndex(caretPosition.container(), caretPosition.offset() - 1);
|
|
if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
|
|
if (isBlock$1(beforeNode) || isBlock$1(node) || !isValidElementCaretCandidate(node)) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(beforeNode), false));
|
|
}
|
|
}
|
|
if (isValidElementCaretCandidate(node)) {
|
|
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect(node), true));
|
|
}
|
|
}
|
|
}
|
|
return clientRects;
|
|
};
|
|
function CaretPosition(container, offset, clientRects) {
|
|
var isAtStart = function () {
|
|
if (isText$4(container)) {
|
|
return offset === 0;
|
|
}
|
|
return offset === 0;
|
|
};
|
|
var isAtEnd = function () {
|
|
if (isText$4(container)) {
|
|
return offset >= container.data.length;
|
|
}
|
|
return offset >= container.childNodes.length;
|
|
};
|
|
var toRange = function () {
|
|
var range;
|
|
range = createRange(container.ownerDocument);
|
|
range.setStart(container, offset);
|
|
range.setEnd(container, offset);
|
|
return range;
|
|
};
|
|
var getClientRects = function () {
|
|
if (!clientRects) {
|
|
clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
|
|
}
|
|
return clientRects;
|
|
};
|
|
var isVisible = function () {
|
|
return getClientRects().length > 0;
|
|
};
|
|
var isEqual = function (caretPosition) {
|
|
return caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
|
|
};
|
|
var getNode = function (before) {
|
|
return resolveIndex(container, before ? offset - 1 : offset);
|
|
};
|
|
return {
|
|
container: constant(container),
|
|
offset: constant(offset),
|
|
toRange: toRange,
|
|
getClientRects: getClientRects,
|
|
isVisible: isVisible,
|
|
isAtStart: isAtStart,
|
|
isAtEnd: isAtEnd,
|
|
isEqual: isEqual,
|
|
getNode: getNode
|
|
};
|
|
}
|
|
(function (CaretPosition) {
|
|
CaretPosition.fromRangeStart = function (range) {
|
|
return CaretPosition(range.startContainer, range.startOffset);
|
|
};
|
|
CaretPosition.fromRangeEnd = function (range) {
|
|
return CaretPosition(range.endContainer, range.endOffset);
|
|
};
|
|
CaretPosition.after = function (node) {
|
|
return CaretPosition(node.parentNode, nodeIndex(node) + 1);
|
|
};
|
|
CaretPosition.before = function (node) {
|
|
return CaretPosition(node.parentNode, nodeIndex(node));
|
|
};
|
|
CaretPosition.isAbove = function (pos1, pos2) {
|
|
return lift2(head(pos2.getClientRects()), last(pos1.getClientRects()), isAbove).getOr(false);
|
|
};
|
|
CaretPosition.isBelow = function (pos1, pos2) {
|
|
return lift2(last(pos2.getClientRects()), head(pos1.getClientRects()), isBelow).getOr(false);
|
|
};
|
|
CaretPosition.isAtStart = function (pos) {
|
|
return pos ? pos.isAtStart() : false;
|
|
};
|
|
CaretPosition.isAtEnd = function (pos) {
|
|
return pos ? pos.isAtEnd() : false;
|
|
};
|
|
CaretPosition.isTextPosition = function (pos) {
|
|
return pos ? NodeType.isText(pos.container()) : false;
|
|
};
|
|
CaretPosition.isElementPosition = function (pos) {
|
|
return CaretPosition.isTextPosition(pos) === false;
|
|
};
|
|
}(CaretPosition || (CaretPosition = {})));
|
|
var CaretPosition$1 = CaretPosition;
|
|
|
|
var isText$5 = NodeType.isText;
|
|
var isBogus$1 = NodeType.isBogus;
|
|
var nodeIndex$1 = DOMUtils$1.nodeIndex;
|
|
var normalizedParent = function (node) {
|
|
var parentNode = node.parentNode;
|
|
if (isBogus$1(parentNode)) {
|
|
return normalizedParent(parentNode);
|
|
}
|
|
return parentNode;
|
|
};
|
|
var getChildNodes = function (node) {
|
|
if (!node) {
|
|
return [];
|
|
}
|
|
return ArrUtils.reduce(node.childNodes, function (result, node) {
|
|
if (isBogus$1(node) && node.nodeName !== 'BR') {
|
|
result = result.concat(getChildNodes(node));
|
|
} else {
|
|
result.push(node);
|
|
}
|
|
return result;
|
|
}, []);
|
|
};
|
|
var normalizedTextOffset = function (node, offset) {
|
|
while (node = node.previousSibling) {
|
|
if (!isText$5(node)) {
|
|
break;
|
|
}
|
|
offset += node.data.length;
|
|
}
|
|
return offset;
|
|
};
|
|
var equal = function (a) {
|
|
return function (b) {
|
|
return a === b;
|
|
};
|
|
};
|
|
var normalizedNodeIndex = function (node) {
|
|
var nodes, index, numTextFragments;
|
|
nodes = getChildNodes(normalizedParent(node));
|
|
index = ArrUtils.findIndex(nodes, equal(node), node);
|
|
nodes = nodes.slice(0, index + 1);
|
|
numTextFragments = ArrUtils.reduce(nodes, function (result, node, i) {
|
|
if (isText$5(node) && isText$5(nodes[i - 1])) {
|
|
result++;
|
|
}
|
|
return result;
|
|
}, 0);
|
|
nodes = ArrUtils.filter(nodes, NodeType.matchNodeNames([node.nodeName]));
|
|
index = ArrUtils.findIndex(nodes, equal(node), node);
|
|
return index - numTextFragments;
|
|
};
|
|
var createPathItem = function (node) {
|
|
var name;
|
|
if (isText$5(node)) {
|
|
name = 'text()';
|
|
} else {
|
|
name = node.nodeName.toLowerCase();
|
|
}
|
|
return name + '[' + normalizedNodeIndex(node) + ']';
|
|
};
|
|
var parentsUntil = function (root, node, predicate) {
|
|
var parents = [];
|
|
for (node = node.parentNode; node !== root; node = node.parentNode) {
|
|
if (predicate && predicate(node)) {
|
|
break;
|
|
}
|
|
parents.push(node);
|
|
}
|
|
return parents;
|
|
};
|
|
var create$2 = function (root, caretPosition) {
|
|
var container, offset, path = [], outputOffset, childNodes, parents;
|
|
container = caretPosition.container();
|
|
offset = caretPosition.offset();
|
|
if (isText$5(container)) {
|
|
outputOffset = normalizedTextOffset(container, offset);
|
|
} else {
|
|
childNodes = container.childNodes;
|
|
if (offset >= childNodes.length) {
|
|
outputOffset = 'after';
|
|
offset = childNodes.length - 1;
|
|
} else {
|
|
outputOffset = 'before';
|
|
}
|
|
container = childNodes[offset];
|
|
}
|
|
path.push(createPathItem(container));
|
|
parents = parentsUntil(root, container);
|
|
parents = ArrUtils.filter(parents, not(NodeType.isBogus));
|
|
path = path.concat(ArrUtils.map(parents, function (node) {
|
|
return createPathItem(node);
|
|
}));
|
|
return path.reverse().join('/') + ',' + outputOffset;
|
|
};
|
|
var resolvePathItem = function (node, name, index) {
|
|
var nodes = getChildNodes(node);
|
|
nodes = ArrUtils.filter(nodes, function (node, index) {
|
|
return !isText$5(node) || !isText$5(nodes[index - 1]);
|
|
});
|
|
nodes = ArrUtils.filter(nodes, NodeType.matchNodeNames([name]));
|
|
return nodes[index];
|
|
};
|
|
var findTextPosition = function (container, offset) {
|
|
var node = container, targetOffset = 0, dataLen;
|
|
while (isText$5(node)) {
|
|
dataLen = node.data.length;
|
|
if (offset >= targetOffset && offset <= targetOffset + dataLen) {
|
|
container = node;
|
|
offset = offset - targetOffset;
|
|
break;
|
|
}
|
|
if (!isText$5(node.nextSibling)) {
|
|
container = node;
|
|
offset = dataLen;
|
|
break;
|
|
}
|
|
targetOffset += dataLen;
|
|
node = node.nextSibling;
|
|
}
|
|
if (isText$5(container) && offset > container.data.length) {
|
|
offset = container.data.length;
|
|
}
|
|
return CaretPosition$1(container, offset);
|
|
};
|
|
var resolve$1 = function (root, path) {
|
|
var parts, container, offset;
|
|
if (!path) {
|
|
return null;
|
|
}
|
|
parts = path.split(',');
|
|
path = parts[0].split('/');
|
|
offset = parts.length > 1 ? parts[1] : 'before';
|
|
container = ArrUtils.reduce(path, function (result, value) {
|
|
value = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
|
|
if (!value) {
|
|
return null;
|
|
}
|
|
if (value[1] === 'text()') {
|
|
value[1] = '#text';
|
|
}
|
|
return resolvePathItem(result, value[1], parseInt(value[2], 10));
|
|
}, root);
|
|
if (!container) {
|
|
return null;
|
|
}
|
|
if (!isText$5(container)) {
|
|
if (offset === 'after') {
|
|
offset = nodeIndex$1(container) + 1;
|
|
} else {
|
|
offset = nodeIndex$1(container);
|
|
}
|
|
return CaretPosition$1(container.parentNode, offset);
|
|
}
|
|
return findTextPosition(container, parseInt(offset, 10));
|
|
};
|
|
|
|
var trimEmptyTextNode = function (dom, node) {
|
|
if (NodeType.isText(node) && node.data.length === 0) {
|
|
dom.remove(node);
|
|
}
|
|
};
|
|
var insertNode = function (dom, rng, node) {
|
|
rng.insertNode(node);
|
|
trimEmptyTextNode(dom, node.previousSibling);
|
|
trimEmptyTextNode(dom, node.nextSibling);
|
|
};
|
|
var insertFragment = function (dom, rng, frag) {
|
|
var firstChild = Option.from(frag.firstChild);
|
|
var lastChild = Option.from(frag.lastChild);
|
|
rng.insertNode(frag);
|
|
firstChild.each(function (child) {
|
|
return trimEmptyTextNode(dom, child.previousSibling);
|
|
});
|
|
lastChild.each(function (child) {
|
|
return trimEmptyTextNode(dom, child.nextSibling);
|
|
});
|
|
};
|
|
var rangeInsertNode = function (dom, rng, node) {
|
|
if (NodeType.isDocumentFragment(node)) {
|
|
insertFragment(dom, rng, node);
|
|
} else {
|
|
insertNode(dom, rng, node);
|
|
}
|
|
};
|
|
|
|
var isContentEditableFalse$2 = NodeType.isContentEditableFalse;
|
|
var getNormalizedTextOffset = function (trim, container, offset) {
|
|
var node, trimmedOffset;
|
|
trimmedOffset = trim(container.data.slice(0, offset)).length;
|
|
for (node = container.previousSibling; node && NodeType.isText(node); node = node.previousSibling) {
|
|
trimmedOffset += trim(node.data).length;
|
|
}
|
|
return trimmedOffset;
|
|
};
|
|
var getPoint = function (dom, trim, normalized, rng, start) {
|
|
var container = rng[start ? 'startContainer' : 'endContainer'];
|
|
var offset = rng[start ? 'startOffset' : 'endOffset'];
|
|
var point = [];
|
|
var childNodes, after = 0;
|
|
var root = dom.getRoot();
|
|
if (NodeType.isText(container)) {
|
|
point.push(normalized ? getNormalizedTextOffset(trim, container, offset) : offset);
|
|
} else {
|
|
childNodes = container.childNodes;
|
|
if (offset >= childNodes.length && childNodes.length) {
|
|
after = 1;
|
|
offset = Math.max(0, childNodes.length - 1);
|
|
}
|
|
point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
|
|
}
|
|
for (; container && container !== root; container = container.parentNode) {
|
|
point.push(dom.nodeIndex(container, normalized));
|
|
}
|
|
return point;
|
|
};
|
|
var getLocation = function (trim, selection, normalized, rng) {
|
|
var dom = selection.dom, bookmark = {};
|
|
bookmark.start = getPoint(dom, trim, normalized, rng, true);
|
|
if (!selection.isCollapsed()) {
|
|
bookmark.end = getPoint(dom, trim, normalized, rng, false);
|
|
}
|
|
return bookmark;
|
|
};
|
|
var findIndex$2 = function (dom, name, element) {
|
|
var count = 0;
|
|
Tools.each(dom.select(name), function (node) {
|
|
if (node.getAttribute('data-mce-bogus') === 'all') {
|
|
return;
|
|
}
|
|
if (node === element) {
|
|
return false;
|
|
}
|
|
count++;
|
|
});
|
|
return count;
|
|
};
|
|
var moveEndPoint = function (rng, start) {
|
|
var container, offset, childNodes;
|
|
var prefix = start ? 'start' : 'end';
|
|
container = rng[prefix + 'Container'];
|
|
offset = rng[prefix + 'Offset'];
|
|
if (NodeType.isElement(container) && container.nodeName === 'TR') {
|
|
childNodes = container.childNodes;
|
|
container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
|
|
if (container) {
|
|
offset = start ? 0 : container.childNodes.length;
|
|
rng['set' + (start ? 'Start' : 'End')](container, offset);
|
|
}
|
|
}
|
|
};
|
|
var normalizeTableCellSelection = function (rng) {
|
|
moveEndPoint(rng, true);
|
|
moveEndPoint(rng, false);
|
|
return rng;
|
|
};
|
|
var findSibling = function (node, offset) {
|
|
var sibling;
|
|
if (NodeType.isElement(node)) {
|
|
node = getNode(node, offset);
|
|
if (isContentEditableFalse$2(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
if (isCaretContainer(node)) {
|
|
if (NodeType.isText(node) && isCaretContainerBlock(node)) {
|
|
node = node.parentNode;
|
|
}
|
|
sibling = node.previousSibling;
|
|
if (isContentEditableFalse$2(sibling)) {
|
|
return sibling;
|
|
}
|
|
sibling = node.nextSibling;
|
|
if (isContentEditableFalse$2(sibling)) {
|
|
return sibling;
|
|
}
|
|
}
|
|
};
|
|
var findAdjacentContentEditableFalseElm = function (rng) {
|
|
return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
|
|
};
|
|
var getOffsetBookmark = function (trim, normalized, selection) {
|
|
var element = selection.getNode();
|
|
var name = element ? element.nodeName : null;
|
|
var rng = selection.getRng();
|
|
if (isContentEditableFalse$2(element) || name === 'IMG') {
|
|
return {
|
|
name: name,
|
|
index: findIndex$2(selection.dom, name, element)
|
|
};
|
|
}
|
|
var sibling = findAdjacentContentEditableFalseElm(rng);
|
|
if (sibling) {
|
|
name = sibling.tagName;
|
|
return {
|
|
name: name,
|
|
index: findIndex$2(selection.dom, name, sibling)
|
|
};
|
|
}
|
|
return getLocation(trim, selection, normalized, rng);
|
|
};
|
|
var getCaretBookmark = function (selection) {
|
|
var rng = selection.getRng();
|
|
return {
|
|
start: create$2(selection.dom.getRoot(), CaretPosition$1.fromRangeStart(rng)),
|
|
end: create$2(selection.dom.getRoot(), CaretPosition$1.fromRangeEnd(rng))
|
|
};
|
|
};
|
|
var getRangeBookmark = function (selection) {
|
|
return { rng: selection.getRng() };
|
|
};
|
|
var createBookmarkSpan = function (dom, id, filled) {
|
|
var args = {
|
|
'data-mce-type': 'bookmark',
|
|
'id': id,
|
|
'style': 'overflow:hidden;line-height:0px'
|
|
};
|
|
return filled ? dom.create('span', args, '') : dom.create('span', args);
|
|
};
|
|
var getPersistentBookmark = function (selection, filled) {
|
|
var dom = selection.dom;
|
|
var rng = selection.getRng();
|
|
var id = dom.uniqueId();
|
|
var collapsed = selection.isCollapsed();
|
|
var element = selection.getNode();
|
|
var name = element.nodeName;
|
|
if (name === 'IMG') {
|
|
return {
|
|
name: name,
|
|
index: findIndex$2(dom, name, element)
|
|
};
|
|
}
|
|
var rng2 = normalizeTableCellSelection(rng.cloneRange());
|
|
if (!collapsed) {
|
|
rng2.collapse(false);
|
|
var endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
|
|
rangeInsertNode(dom, rng2, endBookmarkNode);
|
|
}
|
|
rng = normalizeTableCellSelection(rng);
|
|
rng.collapse(true);
|
|
var startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
|
|
rangeInsertNode(dom, rng, startBookmarkNode);
|
|
selection.moveToBookmark({
|
|
id: id,
|
|
keep: 1
|
|
});
|
|
return { id: id };
|
|
};
|
|
var getBookmark = function (selection, type, normalized) {
|
|
if (type === 2) {
|
|
return getOffsetBookmark(Zwsp.trim, normalized, selection);
|
|
} else if (type === 3) {
|
|
return getCaretBookmark(selection);
|
|
} else if (type) {
|
|
return getRangeBookmark(selection);
|
|
} else {
|
|
return getPersistentBookmark(selection, false);
|
|
}
|
|
};
|
|
var GetBookmark = {
|
|
getBookmark: getBookmark,
|
|
getUndoBookmark: curry(getOffsetBookmark, identity, true),
|
|
getPersistentBookmark: getPersistentBookmark
|
|
};
|
|
|
|
var CARET_ID = '_mce_caret';
|
|
var isCaretNode = function (node) {
|
|
return NodeType.isElement(node) && node.id === CARET_ID;
|
|
};
|
|
var getParentCaretContainer = function (body, node) {
|
|
while (node && node !== body) {
|
|
if (node.id === CARET_ID) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
var isElement$4 = NodeType.isElement;
|
|
var isText$6 = NodeType.isText;
|
|
var removeNode = function (node) {
|
|
var parentNode = node.parentNode;
|
|
if (parentNode) {
|
|
parentNode.removeChild(node);
|
|
}
|
|
};
|
|
var getNodeValue = function (node) {
|
|
try {
|
|
return node.nodeValue;
|
|
} catch (ex) {
|
|
return '';
|
|
}
|
|
};
|
|
var setNodeValue = function (node, text) {
|
|
if (text.length === 0) {
|
|
removeNode(node);
|
|
} else {
|
|
node.nodeValue = text;
|
|
}
|
|
};
|
|
var trimCount = function (text) {
|
|
var trimmedText = Zwsp.trim(text);
|
|
return {
|
|
count: text.length - trimmedText.length,
|
|
text: trimmedText
|
|
};
|
|
};
|
|
var removeUnchanged = function (caretContainer, pos) {
|
|
remove$5(caretContainer);
|
|
return pos;
|
|
};
|
|
var removeTextAndReposition = function (caretContainer, pos) {
|
|
var before = trimCount(caretContainer.data.substr(0, pos.offset()));
|
|
var after = trimCount(caretContainer.data.substr(pos.offset()));
|
|
var text = before.text + after.text;
|
|
if (text.length > 0) {
|
|
setNodeValue(caretContainer, text);
|
|
return CaretPosition$1(caretContainer, pos.offset() - before.count);
|
|
} else {
|
|
return pos;
|
|
}
|
|
};
|
|
var removeElementAndReposition = function (caretContainer, pos) {
|
|
var parentNode = pos.container();
|
|
var newPosition = indexOf(from$1(parentNode.childNodes), caretContainer).map(function (index) {
|
|
return index < pos.offset() ? CaretPosition$1(parentNode, pos.offset() - 1) : pos;
|
|
}).getOr(pos);
|
|
remove$5(caretContainer);
|
|
return newPosition;
|
|
};
|
|
var removeTextCaretContainer = function (caretContainer, pos) {
|
|
return isText$6(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
|
|
};
|
|
var removeElementCaretContainer = function (caretContainer, pos) {
|
|
return pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
|
|
};
|
|
var removeAndReposition = function (container, pos) {
|
|
return CaretPosition$1.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
|
|
};
|
|
var remove$5 = function (caretContainerNode) {
|
|
if (isElement$4(caretContainerNode) && isCaretContainer(caretContainerNode)) {
|
|
if (hasContent(caretContainerNode)) {
|
|
caretContainerNode.removeAttribute('data-mce-caret');
|
|
} else {
|
|
removeNode(caretContainerNode);
|
|
}
|
|
}
|
|
if (isText$6(caretContainerNode)) {
|
|
var text = Zwsp.trim(getNodeValue(caretContainerNode));
|
|
setNodeValue(caretContainerNode, text);
|
|
}
|
|
};
|
|
var CaretContainerRemove = {
|
|
removeAndReposition: removeAndReposition,
|
|
remove: remove$5
|
|
};
|
|
|
|
var browser$3 = detect$3().browser;
|
|
var isContentEditableFalse$3 = NodeType.isContentEditableFalse;
|
|
var isTableCell$1 = function (node) {
|
|
return NodeType.isElement(node) && /^(TD|TH)$/i.test(node.tagName);
|
|
};
|
|
var getAbsoluteClientRect = function (root, element, before) {
|
|
var clientRect = collapse(element.getBoundingClientRect(), before);
|
|
var docElm, scrollX, scrollY, margin, rootRect;
|
|
if (root.tagName === 'BODY') {
|
|
docElm = root.ownerDocument.documentElement;
|
|
scrollX = root.scrollLeft || docElm.scrollLeft;
|
|
scrollY = root.scrollTop || docElm.scrollTop;
|
|
} else {
|
|
rootRect = root.getBoundingClientRect();
|
|
scrollX = root.scrollLeft - rootRect.left;
|
|
scrollY = root.scrollTop - rootRect.top;
|
|
}
|
|
clientRect.left += scrollX;
|
|
clientRect.right += scrollX;
|
|
clientRect.top += scrollY;
|
|
clientRect.bottom += scrollY;
|
|
clientRect.width = 1;
|
|
margin = element.offsetWidth - element.clientWidth;
|
|
if (margin > 0) {
|
|
if (before) {
|
|
margin *= -1;
|
|
}
|
|
clientRect.left += margin;
|
|
clientRect.right += margin;
|
|
}
|
|
return clientRect;
|
|
};
|
|
var trimInlineCaretContainers = function (root) {
|
|
var contentEditableFalseNodes, node, sibling, i, data;
|
|
contentEditableFalseNodes = DomQuery('*[contentEditable=false]', root);
|
|
for (i = 0; i < contentEditableFalseNodes.length; i++) {
|
|
node = contentEditableFalseNodes[i];
|
|
sibling = node.previousSibling;
|
|
if (endsWithCaretContainer(sibling)) {
|
|
data = sibling.data;
|
|
if (data.length === 1) {
|
|
sibling.parentNode.removeChild(sibling);
|
|
} else {
|
|
sibling.deleteData(data.length - 1, 1);
|
|
}
|
|
}
|
|
sibling = node.nextSibling;
|
|
if (startsWithCaretContainer(sibling)) {
|
|
data = sibling.data;
|
|
if (data.length === 1) {
|
|
sibling.parentNode.removeChild(sibling);
|
|
} else {
|
|
sibling.deleteData(0, 1);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var FakeCaret = function (root, isBlock, hasFocus) {
|
|
var lastVisualCaret = Cell(Option.none());
|
|
var cursorInterval, caretContainerNode;
|
|
var show = function (before, element) {
|
|
var clientRect, rng;
|
|
hide();
|
|
if (isTableCell$1(element)) {
|
|
return null;
|
|
}
|
|
if (isBlock(element)) {
|
|
caretContainerNode = insertBlock('p', element, before);
|
|
clientRect = getAbsoluteClientRect(root, element, before);
|
|
DomQuery(caretContainerNode).css('top', clientRect.top);
|
|
var caret = DomQuery('<div class="mce-visual-caret" data-mce-bogus="all"></div>').css(clientRect).appendTo(root)[0];
|
|
lastVisualCaret.set(Option.some({
|
|
caret: caret,
|
|
element: element,
|
|
before: before
|
|
}));
|
|
lastVisualCaret.get().each(function (caretState) {
|
|
if (before) {
|
|
DomQuery(caretState.caret).addClass('mce-visual-caret-before');
|
|
}
|
|
});
|
|
startBlink();
|
|
rng = element.ownerDocument.createRange();
|
|
rng.setStart(caretContainerNode, 0);
|
|
rng.setEnd(caretContainerNode, 0);
|
|
} else {
|
|
caretContainerNode = insertInline(element, before);
|
|
rng = element.ownerDocument.createRange();
|
|
if (isContentEditableFalse$3(caretContainerNode.nextSibling)) {
|
|
rng.setStart(caretContainerNode, 0);
|
|
rng.setEnd(caretContainerNode, 0);
|
|
} else {
|
|
rng.setStart(caretContainerNode, 1);
|
|
rng.setEnd(caretContainerNode, 1);
|
|
}
|
|
return rng;
|
|
}
|
|
return rng;
|
|
};
|
|
var hide = function () {
|
|
trimInlineCaretContainers(root);
|
|
if (caretContainerNode) {
|
|
CaretContainerRemove.remove(caretContainerNode);
|
|
caretContainerNode = null;
|
|
}
|
|
lastVisualCaret.get().each(function (caretState) {
|
|
DomQuery(caretState.caret).remove();
|
|
lastVisualCaret.set(Option.none());
|
|
});
|
|
Delay.clearInterval(cursorInterval);
|
|
};
|
|
var startBlink = function () {
|
|
cursorInterval = Delay.setInterval(function () {
|
|
if (hasFocus()) {
|
|
DomQuery('div.mce-visual-caret', root).toggleClass('mce-visual-caret-hidden');
|
|
} else {
|
|
DomQuery('div.mce-visual-caret', root).addClass('mce-visual-caret-hidden');
|
|
}
|
|
}, 500);
|
|
};
|
|
var reposition = function () {
|
|
lastVisualCaret.get().each(function (caretState) {
|
|
var clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
|
|
DomQuery(caretState.caret).css(__assign({}, clientRect));
|
|
});
|
|
};
|
|
var destroy = function () {
|
|
return Delay.clearInterval(cursorInterval);
|
|
};
|
|
var getCss = function () {
|
|
return '.mce-visual-caret {' + 'position: absolute;' + 'background-color: black;' + 'background-color: currentcolor;' + '}' + '.mce-visual-caret-hidden {' + 'display: none;' + '}' + '*[data-mce-caret] {' + 'position: absolute;' + 'left: -1000px;' + 'right: auto;' + 'top: 0;' + 'margin: 0;' + 'padding: 0;' + '}';
|
|
};
|
|
return {
|
|
show: show,
|
|
hide: hide,
|
|
getCss: getCss,
|
|
reposition: reposition,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
var isFakeCaretTableBrowser = function () {
|
|
return browser$3.isIE() || browser$3.isEdge() || browser$3.isFirefox();
|
|
};
|
|
var isFakeCaretTarget = function (node) {
|
|
return isContentEditableFalse$3(node) || NodeType.isTable(node) && isFakeCaretTableBrowser();
|
|
};
|
|
|
|
var isContentEditableFalse$4 = NodeType.isContentEditableFalse;
|
|
var isBlockLike = NodeType.matchStyleValues('display', 'block table table-cell table-caption list-item');
|
|
var isCaretContainer$2 = isCaretContainer;
|
|
var isCaretContainerBlock$1 = isCaretContainerBlock;
|
|
var isElement$5 = NodeType.isElement;
|
|
var isCaretCandidate$2 = isCaretCandidate;
|
|
var isForwards = function (direction) {
|
|
return direction > 0;
|
|
};
|
|
var isBackwards = function (direction) {
|
|
return direction < 0;
|
|
};
|
|
var skipCaretContainers = function (walk, shallow) {
|
|
var node;
|
|
while (node = walk(shallow)) {
|
|
if (!isCaretContainerBlock$1(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var findNode = function (node, direction, predicateFn, rootNode, shallow) {
|
|
var walker = new TreeWalker(node, rootNode);
|
|
if (isBackwards(direction)) {
|
|
if (isContentEditableFalse$4(node) || isCaretContainerBlock$1(node)) {
|
|
node = skipCaretContainers(walker.prev, true);
|
|
if (predicateFn(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
while (node = skipCaretContainers(walker.prev, shallow)) {
|
|
if (predicateFn(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
if (isForwards(direction)) {
|
|
if (isContentEditableFalse$4(node) || isCaretContainerBlock$1(node)) {
|
|
node = skipCaretContainers(walker.next, true);
|
|
if (predicateFn(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
while (node = skipCaretContainers(walker.next, shallow)) {
|
|
if (predicateFn(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var getParentBlock = function (node, rootNode) {
|
|
while (node && node !== rootNode) {
|
|
if (isBlockLike(node)) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var isInSameBlock = function (caretPosition1, caretPosition2, rootNode) {
|
|
return getParentBlock(caretPosition1.container(), rootNode) === getParentBlock(caretPosition2.container(), rootNode);
|
|
};
|
|
var getChildNodeAtRelativeOffset = function (relativeOffset, caretPosition) {
|
|
var container, offset;
|
|
if (!caretPosition) {
|
|
return null;
|
|
}
|
|
container = caretPosition.container();
|
|
offset = caretPosition.offset();
|
|
if (!isElement$5(container)) {
|
|
return null;
|
|
}
|
|
return container.childNodes[offset + relativeOffset];
|
|
};
|
|
var beforeAfter = function (before, node) {
|
|
var range = node.ownerDocument.createRange();
|
|
if (before) {
|
|
range.setStartBefore(node);
|
|
range.setEndBefore(node);
|
|
} else {
|
|
range.setStartAfter(node);
|
|
range.setEndAfter(node);
|
|
}
|
|
return range;
|
|
};
|
|
var isNodesInSameBlock = function (root, node1, node2) {
|
|
return getParentBlock(node1, root) === getParentBlock(node2, root);
|
|
};
|
|
var lean = function (left, root, node) {
|
|
var sibling, siblingName;
|
|
if (left) {
|
|
siblingName = 'previousSibling';
|
|
} else {
|
|
siblingName = 'nextSibling';
|
|
}
|
|
while (node && node !== root) {
|
|
sibling = node[siblingName];
|
|
if (isCaretContainer$2(sibling)) {
|
|
sibling = sibling[siblingName];
|
|
}
|
|
if (isContentEditableFalse$4(sibling)) {
|
|
if (isNodesInSameBlock(root, sibling, node)) {
|
|
return sibling;
|
|
}
|
|
break;
|
|
}
|
|
if (isCaretCandidate$2(sibling)) {
|
|
break;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var before$2 = curry(beforeAfter, true);
|
|
var after$1 = curry(beforeAfter, false);
|
|
var normalizeRange = function (direction, root, range) {
|
|
var node, container, offset, location;
|
|
var leanLeft = curry(lean, true, root);
|
|
var leanRight = curry(lean, false, root);
|
|
container = range.startContainer;
|
|
offset = range.startOffset;
|
|
if (isCaretContainerBlock(container)) {
|
|
if (!isElement$5(container)) {
|
|
container = container.parentNode;
|
|
}
|
|
location = container.getAttribute('data-mce-caret');
|
|
if (location === 'before') {
|
|
node = container.nextSibling;
|
|
if (isFakeCaretTarget(node)) {
|
|
return before$2(node);
|
|
}
|
|
}
|
|
if (location === 'after') {
|
|
node = container.previousSibling;
|
|
if (isFakeCaretTarget(node)) {
|
|
return after$1(node);
|
|
}
|
|
}
|
|
}
|
|
if (!range.collapsed) {
|
|
return range;
|
|
}
|
|
if (NodeType.isText(container)) {
|
|
if (isCaretContainer$2(container)) {
|
|
if (direction === 1) {
|
|
node = leanRight(container);
|
|
if (node) {
|
|
return before$2(node);
|
|
}
|
|
node = leanLeft(container);
|
|
if (node) {
|
|
return after$1(node);
|
|
}
|
|
}
|
|
if (direction === -1) {
|
|
node = leanLeft(container);
|
|
if (node) {
|
|
return after$1(node);
|
|
}
|
|
node = leanRight(container);
|
|
if (node) {
|
|
return before$2(node);
|
|
}
|
|
}
|
|
return range;
|
|
}
|
|
if (endsWithCaretContainer(container) && offset >= container.data.length - 1) {
|
|
if (direction === 1) {
|
|
node = leanRight(container);
|
|
if (node) {
|
|
return before$2(node);
|
|
}
|
|
}
|
|
return range;
|
|
}
|
|
if (startsWithCaretContainer(container) && offset <= 1) {
|
|
if (direction === -1) {
|
|
node = leanLeft(container);
|
|
if (node) {
|
|
return after$1(node);
|
|
}
|
|
}
|
|
return range;
|
|
}
|
|
if (offset === container.data.length) {
|
|
node = leanRight(container);
|
|
if (node) {
|
|
return before$2(node);
|
|
}
|
|
return range;
|
|
}
|
|
if (offset === 0) {
|
|
node = leanLeft(container);
|
|
if (node) {
|
|
return after$1(node);
|
|
}
|
|
return range;
|
|
}
|
|
}
|
|
return range;
|
|
};
|
|
var getRelativeCefElm = function (forward, caretPosition) {
|
|
return Option.from(getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition)).filter(isContentEditableFalse$4);
|
|
};
|
|
var getNormalizedRangeEndPoint = function (direction, root, range) {
|
|
var normalizedRange = normalizeRange(direction, root, range);
|
|
if (direction === -1) {
|
|
return CaretPosition.fromRangeStart(normalizedRange);
|
|
}
|
|
return CaretPosition.fromRangeEnd(normalizedRange);
|
|
};
|
|
var getElementFromPosition = function (pos) {
|
|
return Option.from(pos.getNode()).map(Element.fromDom);
|
|
};
|
|
var getElementFromPrevPosition = function (pos) {
|
|
return Option.from(pos.getNode(true)).map(Element.fromDom);
|
|
};
|
|
var getVisualCaretPosition = function (walkFn, caretPosition) {
|
|
while (caretPosition = walkFn(caretPosition)) {
|
|
if (caretPosition.isVisible()) {
|
|
return caretPosition;
|
|
}
|
|
}
|
|
return caretPosition;
|
|
};
|
|
var isMoveInsideSameBlock = function (from, to) {
|
|
var inSameBlock = isInSameBlock(from, to);
|
|
if (!inSameBlock && NodeType.isBr(from.getNode())) {
|
|
return true;
|
|
}
|
|
return inSameBlock;
|
|
};
|
|
|
|
var HDirection;
|
|
(function (HDirection) {
|
|
HDirection[HDirection['Backwards'] = -1] = 'Backwards';
|
|
HDirection[HDirection['Forwards'] = 1] = 'Forwards';
|
|
}(HDirection || (HDirection = {})));
|
|
var isContentEditableFalse$5 = NodeType.isContentEditableFalse;
|
|
var isText$7 = NodeType.isText;
|
|
var isElement$6 = NodeType.isElement;
|
|
var isBr$4 = NodeType.isBr;
|
|
var isCaretCandidate$3 = isCaretCandidate;
|
|
var isAtomic$1 = isAtomic;
|
|
var isEditableCaretCandidate$1 = isEditableCaretCandidate;
|
|
var getParents = function (node, root) {
|
|
var parents = [];
|
|
while (node && node !== root) {
|
|
parents.push(node);
|
|
node = node.parentNode;
|
|
}
|
|
return parents;
|
|
};
|
|
var nodeAtIndex = function (container, offset) {
|
|
if (container.hasChildNodes() && offset < container.childNodes.length) {
|
|
return container.childNodes[offset];
|
|
}
|
|
return null;
|
|
};
|
|
var getCaretCandidatePosition = function (direction, node) {
|
|
if (isForwards(direction)) {
|
|
if (isCaretCandidate$3(node.previousSibling) && !isText$7(node.previousSibling)) {
|
|
return CaretPosition$1.before(node);
|
|
}
|
|
if (isText$7(node)) {
|
|
return CaretPosition$1(node, 0);
|
|
}
|
|
}
|
|
if (isBackwards(direction)) {
|
|
if (isCaretCandidate$3(node.nextSibling) && !isText$7(node.nextSibling)) {
|
|
return CaretPosition$1.after(node);
|
|
}
|
|
if (isText$7(node)) {
|
|
return CaretPosition$1(node, node.data.length);
|
|
}
|
|
}
|
|
if (isBackwards(direction)) {
|
|
if (isBr$4(node)) {
|
|
return CaretPosition$1.before(node);
|
|
}
|
|
return CaretPosition$1.after(node);
|
|
}
|
|
return CaretPosition$1.before(node);
|
|
};
|
|
var moveForwardFromBr = function (root, nextNode) {
|
|
var nextSibling = nextNode.nextSibling;
|
|
if (nextSibling && isCaretCandidate$3(nextSibling)) {
|
|
if (isText$7(nextSibling)) {
|
|
return CaretPosition$1(nextSibling, 0);
|
|
} else {
|
|
return CaretPosition$1.before(nextSibling);
|
|
}
|
|
} else {
|
|
return findCaretPosition(HDirection.Forwards, CaretPosition$1.after(nextNode), root);
|
|
}
|
|
};
|
|
var findCaretPosition = function (direction, startPos, root) {
|
|
var node, nextNode, innerNode;
|
|
var rootContentEditableFalseElm, caretPosition;
|
|
if (!isElement$6(root) || !startPos) {
|
|
return null;
|
|
}
|
|
if (startPos.isEqual(CaretPosition$1.after(root)) && root.lastChild) {
|
|
caretPosition = CaretPosition$1.after(root.lastChild);
|
|
if (isBackwards(direction) && isCaretCandidate$3(root.lastChild) && isElement$6(root.lastChild)) {
|
|
return isBr$4(root.lastChild) ? CaretPosition$1.before(root.lastChild) : caretPosition;
|
|
}
|
|
} else {
|
|
caretPosition = startPos;
|
|
}
|
|
var container = caretPosition.container();
|
|
var offset = caretPosition.offset();
|
|
if (isText$7(container)) {
|
|
if (isBackwards(direction) && offset > 0) {
|
|
return CaretPosition$1(container, --offset);
|
|
}
|
|
if (isForwards(direction) && offset < container.length) {
|
|
return CaretPosition$1(container, ++offset);
|
|
}
|
|
node = container;
|
|
} else {
|
|
if (isBackwards(direction) && offset > 0) {
|
|
nextNode = nodeAtIndex(container, offset - 1);
|
|
if (isCaretCandidate$3(nextNode)) {
|
|
if (!isAtomic$1(nextNode)) {
|
|
innerNode = findNode(nextNode, direction, isEditableCaretCandidate$1, nextNode);
|
|
if (innerNode) {
|
|
if (isText$7(innerNode)) {
|
|
return CaretPosition$1(innerNode, innerNode.data.length);
|
|
}
|
|
return CaretPosition$1.after(innerNode);
|
|
}
|
|
}
|
|
if (isText$7(nextNode)) {
|
|
return CaretPosition$1(nextNode, nextNode.data.length);
|
|
}
|
|
return CaretPosition$1.before(nextNode);
|
|
}
|
|
}
|
|
if (isForwards(direction) && offset < container.childNodes.length) {
|
|
nextNode = nodeAtIndex(container, offset);
|
|
if (isCaretCandidate$3(nextNode)) {
|
|
if (isBr$4(nextNode)) {
|
|
return moveForwardFromBr(root, nextNode);
|
|
}
|
|
if (!isAtomic$1(nextNode)) {
|
|
innerNode = findNode(nextNode, direction, isEditableCaretCandidate$1, nextNode);
|
|
if (innerNode) {
|
|
if (isText$7(innerNode)) {
|
|
return CaretPosition$1(innerNode, 0);
|
|
}
|
|
return CaretPosition$1.before(innerNode);
|
|
}
|
|
}
|
|
if (isText$7(nextNode)) {
|
|
return CaretPosition$1(nextNode, 0);
|
|
}
|
|
return CaretPosition$1.after(nextNode);
|
|
}
|
|
}
|
|
node = nextNode ? nextNode : caretPosition.getNode();
|
|
}
|
|
if (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart()) {
|
|
node = findNode(node, direction, constant(true), root, true);
|
|
if (isEditableCaretCandidate$1(node, root)) {
|
|
return getCaretCandidatePosition(direction, node);
|
|
}
|
|
}
|
|
nextNode = findNode(node, direction, isEditableCaretCandidate$1, root);
|
|
rootContentEditableFalseElm = ArrUtils.last(filter(getParents(container, root), isContentEditableFalse$5));
|
|
if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
|
|
if (isForwards(direction)) {
|
|
caretPosition = CaretPosition$1.after(rootContentEditableFalseElm);
|
|
} else {
|
|
caretPosition = CaretPosition$1.before(rootContentEditableFalseElm);
|
|
}
|
|
return caretPosition;
|
|
}
|
|
if (nextNode) {
|
|
return getCaretCandidatePosition(direction, nextNode);
|
|
}
|
|
return null;
|
|
};
|
|
var CaretWalker = function (root) {
|
|
return {
|
|
next: function (caretPosition) {
|
|
return findCaretPosition(HDirection.Forwards, caretPosition, root);
|
|
},
|
|
prev: function (caretPosition) {
|
|
return findCaretPosition(HDirection.Backwards, caretPosition, root);
|
|
}
|
|
};
|
|
};
|
|
|
|
var walkToPositionIn = function (forward, root, start) {
|
|
var position = forward ? CaretPosition$1.before(start) : CaretPosition$1.after(start);
|
|
return fromPosition(forward, root, position);
|
|
};
|
|
var afterElement = function (node) {
|
|
return NodeType.isBr(node) ? CaretPosition$1.before(node) : CaretPosition$1.after(node);
|
|
};
|
|
var isBeforeOrStart = function (position) {
|
|
if (CaretPosition$1.isTextPosition(position)) {
|
|
return position.offset() === 0;
|
|
} else {
|
|
return isCaretCandidate(position.getNode());
|
|
}
|
|
};
|
|
var isAfterOrEnd = function (position) {
|
|
if (CaretPosition$1.isTextPosition(position)) {
|
|
var container = position.container();
|
|
return position.offset() === container.data.length;
|
|
} else {
|
|
return isCaretCandidate(position.getNode(true));
|
|
}
|
|
};
|
|
var isBeforeAfterSameElement = function (from, to) {
|
|
return !CaretPosition$1.isTextPosition(from) && !CaretPosition$1.isTextPosition(to) && from.getNode() === to.getNode(true);
|
|
};
|
|
var isAtBr = function (position) {
|
|
return !CaretPosition$1.isTextPosition(position) && NodeType.isBr(position.getNode());
|
|
};
|
|
var shouldSkipPosition = function (forward, from, to) {
|
|
if (forward) {
|
|
return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
|
|
} else {
|
|
return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
|
|
}
|
|
};
|
|
var fromPosition = function (forward, root, pos) {
|
|
var walker = CaretWalker(root);
|
|
return Option.from(forward ? walker.next(pos) : walker.prev(pos));
|
|
};
|
|
var navigate = function (forward, root, from) {
|
|
return fromPosition(forward, root, from).bind(function (to) {
|
|
if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
|
|
return fromPosition(forward, root, to);
|
|
} else {
|
|
return Option.some(to);
|
|
}
|
|
});
|
|
};
|
|
var navigateIgnore = function (forward, root, from, ignoreFilter) {
|
|
return navigate(forward, root, from).bind(function (pos) {
|
|
return ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Option.some(pos);
|
|
});
|
|
};
|
|
var positionIn = function (forward, element) {
|
|
var startNode = forward ? element.firstChild : element.lastChild;
|
|
if (NodeType.isText(startNode)) {
|
|
return Option.some(CaretPosition$1(startNode, forward ? 0 : startNode.data.length));
|
|
} else if (startNode) {
|
|
if (isCaretCandidate(startNode)) {
|
|
return Option.some(forward ? CaretPosition$1.before(startNode) : afterElement(startNode));
|
|
} else {
|
|
return walkToPositionIn(forward, element, startNode);
|
|
}
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
};
|
|
var nextPosition = curry(fromPosition, true);
|
|
var prevPosition = curry(fromPosition, false);
|
|
var CaretFinder = {
|
|
fromPosition: fromPosition,
|
|
nextPosition: nextPosition,
|
|
prevPosition: prevPosition,
|
|
navigate: navigate,
|
|
navigateIgnore: navigateIgnore,
|
|
positionIn: positionIn,
|
|
firstPositionIn: curry(positionIn, true),
|
|
lastPositionIn: curry(positionIn, false)
|
|
};
|
|
|
|
var isStringPathBookmark = function (bookmark) {
|
|
return typeof bookmark.start === 'string';
|
|
};
|
|
var isRangeBookmark = function (bookmark) {
|
|
return bookmark.hasOwnProperty('rng');
|
|
};
|
|
var isIdBookmark = function (bookmark) {
|
|
return bookmark.hasOwnProperty('id');
|
|
};
|
|
var isIndexBookmark = function (bookmark) {
|
|
return bookmark.hasOwnProperty('name');
|
|
};
|
|
var isPathBookmark = function (bookmark) {
|
|
return Tools.isArray(bookmark.start);
|
|
};
|
|
|
|
var addBogus = function (dom, node) {
|
|
if (NodeType.isElement(node) && dom.isBlock(node) && !node.innerHTML && !Env.ie) {
|
|
node.innerHTML = '<br data-mce-bogus="1" />';
|
|
}
|
|
return node;
|
|
};
|
|
var resolveCaretPositionBookmark = function (dom, bookmark) {
|
|
var rng, pos;
|
|
rng = dom.createRng();
|
|
pos = resolve$1(dom.getRoot(), bookmark.start);
|
|
rng.setStart(pos.container(), pos.offset());
|
|
pos = resolve$1(dom.getRoot(), bookmark.end);
|
|
rng.setEnd(pos.container(), pos.offset());
|
|
return rng;
|
|
};
|
|
var insertZwsp = function (node, rng) {
|
|
var textNode = node.ownerDocument.createTextNode(Zwsp.ZWSP);
|
|
node.appendChild(textNode);
|
|
rng.setStart(textNode, 0);
|
|
rng.setEnd(textNode, 0);
|
|
};
|
|
var isEmpty = function (node) {
|
|
return node.hasChildNodes() === false;
|
|
};
|
|
var tryFindRangePosition = function (node, rng) {
|
|
return CaretFinder.lastPositionIn(node).fold(function () {
|
|
return false;
|
|
}, function (pos) {
|
|
rng.setStart(pos.container(), pos.offset());
|
|
rng.setEnd(pos.container(), pos.offset());
|
|
return true;
|
|
});
|
|
};
|
|
var padEmptyCaretContainer = function (root, node, rng) {
|
|
if (isEmpty(node) && getParentCaretContainer(root, node)) {
|
|
insertZwsp(node, rng);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var setEndPoint = function (dom, start, bookmark, rng) {
|
|
var point = bookmark[start ? 'start' : 'end'];
|
|
var i, node, offset, children;
|
|
var root = dom.getRoot();
|
|
if (point) {
|
|
offset = point[0];
|
|
for (node = root, i = point.length - 1; i >= 1; i--) {
|
|
children = node.childNodes;
|
|
if (padEmptyCaretContainer(root, node, rng)) {
|
|
return true;
|
|
}
|
|
if (point[i] > children.length - 1) {
|
|
if (padEmptyCaretContainer(root, node, rng)) {
|
|
return true;
|
|
}
|
|
return tryFindRangePosition(node, rng);
|
|
}
|
|
node = children[point[i]];
|
|
}
|
|
if (node.nodeType === 3) {
|
|
offset = Math.min(point[0], node.nodeValue.length);
|
|
}
|
|
if (node.nodeType === 1) {
|
|
offset = Math.min(point[0], node.childNodes.length);
|
|
}
|
|
if (start) {
|
|
rng.setStart(node, offset);
|
|
} else {
|
|
rng.setEnd(node, offset);
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
var isValidTextNode = function (node) {
|
|
return NodeType.isText(node) && node.data.length > 0;
|
|
};
|
|
var restoreEndPoint = function (dom, suffix, bookmark) {
|
|
var marker = dom.get(bookmark.id + '_' + suffix), node, idx, next, prev;
|
|
var keep = bookmark.keep;
|
|
var container, offset;
|
|
if (marker) {
|
|
node = marker.parentNode;
|
|
if (suffix === 'start') {
|
|
if (!keep) {
|
|
idx = dom.nodeIndex(marker);
|
|
} else {
|
|
if (marker.hasChildNodes()) {
|
|
node = marker.firstChild;
|
|
idx = 1;
|
|
} else if (isValidTextNode(marker.nextSibling)) {
|
|
node = marker.nextSibling;
|
|
idx = 0;
|
|
} else if (isValidTextNode(marker.previousSibling)) {
|
|
node = marker.previousSibling;
|
|
idx = marker.previousSibling.data.length;
|
|
} else {
|
|
node = marker.parentNode;
|
|
idx = dom.nodeIndex(marker) + 1;
|
|
}
|
|
}
|
|
container = node;
|
|
offset = idx;
|
|
} else {
|
|
if (!keep) {
|
|
idx = dom.nodeIndex(marker);
|
|
} else {
|
|
if (marker.hasChildNodes()) {
|
|
node = marker.firstChild;
|
|
idx = 1;
|
|
} else if (isValidTextNode(marker.previousSibling)) {
|
|
node = marker.previousSibling;
|
|
idx = marker.previousSibling.data.length;
|
|
} else {
|
|
node = marker.parentNode;
|
|
idx = dom.nodeIndex(marker);
|
|
}
|
|
}
|
|
container = node;
|
|
offset = idx;
|
|
}
|
|
if (!keep) {
|
|
prev = marker.previousSibling;
|
|
next = marker.nextSibling;
|
|
Tools.each(Tools.grep(marker.childNodes), function (node) {
|
|
if (NodeType.isText(node)) {
|
|
node.nodeValue = node.nodeValue.replace(/\uFEFF/g, '');
|
|
}
|
|
});
|
|
while (marker = dom.get(bookmark.id + '_' + suffix)) {
|
|
dom.remove(marker, true);
|
|
}
|
|
if (prev && next && prev.nodeType === next.nodeType && NodeType.isText(prev) && !Env.opera) {
|
|
idx = prev.nodeValue.length;
|
|
prev.appendData(next.nodeValue);
|
|
dom.remove(next);
|
|
if (suffix === 'start') {
|
|
container = prev;
|
|
offset = idx;
|
|
} else {
|
|
container = prev;
|
|
offset = idx;
|
|
}
|
|
}
|
|
}
|
|
return Option.some(CaretPosition$1(container, offset));
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
};
|
|
var resolvePaths = function (dom, bookmark) {
|
|
var rng = dom.createRng();
|
|
if (setEndPoint(dom, true, bookmark, rng) && setEndPoint(dom, false, bookmark, rng)) {
|
|
return Option.some(rng);
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
};
|
|
var resolveId = function (dom, bookmark) {
|
|
var startPos = restoreEndPoint(dom, 'start', bookmark);
|
|
var endPos = restoreEndPoint(dom, 'end', bookmark);
|
|
return lift2(startPos, endPos.or(startPos), function (spos, epos) {
|
|
var rng = dom.createRng();
|
|
rng.setStart(addBogus(dom, spos.container()), spos.offset());
|
|
rng.setEnd(addBogus(dom, epos.container()), epos.offset());
|
|
return rng;
|
|
});
|
|
};
|
|
var resolveIndex$1 = function (dom, bookmark) {
|
|
return Option.from(dom.select(bookmark.name)[bookmark.index]).map(function (elm) {
|
|
var rng = dom.createRng();
|
|
rng.selectNode(elm);
|
|
return rng;
|
|
});
|
|
};
|
|
var resolve$2 = function (selection, bookmark) {
|
|
var dom = selection.dom;
|
|
if (bookmark) {
|
|
if (isPathBookmark(bookmark)) {
|
|
return resolvePaths(dom, bookmark);
|
|
} else if (isStringPathBookmark(bookmark)) {
|
|
return Option.some(resolveCaretPositionBookmark(dom, bookmark));
|
|
} else if (isIdBookmark(bookmark)) {
|
|
return resolveId(dom, bookmark);
|
|
} else if (isIndexBookmark(bookmark)) {
|
|
return resolveIndex$1(dom, bookmark);
|
|
} else if (isRangeBookmark(bookmark)) {
|
|
return Option.some(bookmark.rng);
|
|
}
|
|
}
|
|
return Option.none();
|
|
};
|
|
var ResolveBookmark = { resolve: resolve$2 };
|
|
|
|
var getBookmark$1 = function (selection, type, normalized) {
|
|
return GetBookmark.getBookmark(selection, type, normalized);
|
|
};
|
|
var moveToBookmark = function (selection, bookmark) {
|
|
ResolveBookmark.resolve(selection, bookmark).each(function (rng) {
|
|
selection.setRng(rng);
|
|
});
|
|
};
|
|
var isBookmarkNode$1 = function (node) {
|
|
return NodeType.isElement(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
|
|
};
|
|
var Bookmarks = {
|
|
getBookmark: getBookmark$1,
|
|
moveToBookmark: moveToBookmark,
|
|
isBookmarkNode: isBookmarkNode$1
|
|
};
|
|
|
|
var isInlineBlock = function (node) {
|
|
return node && /^(IMG)$/.test(node.nodeName);
|
|
};
|
|
var moveStart = function (dom, selection, rng) {
|
|
var offset = rng.startOffset;
|
|
var container = rng.startContainer, walker, node, nodes;
|
|
if (rng.startContainer === rng.endContainer) {
|
|
if (isInlineBlock(rng.startContainer.childNodes[rng.startOffset])) {
|
|
return;
|
|
}
|
|
}
|
|
if (container.nodeType === 1) {
|
|
nodes = container.childNodes;
|
|
if (offset < nodes.length) {
|
|
container = nodes[offset];
|
|
walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
|
|
} else {
|
|
container = nodes[nodes.length - 1];
|
|
walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
|
|
walker.next(true);
|
|
}
|
|
for (node = walker.current(); node; node = walker.next()) {
|
|
if (node.nodeType === 3 && !isWhiteSpaceNode(node)) {
|
|
rng.setStart(node, 0);
|
|
selection.setRng(rng);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var getNonWhiteSpaceSibling = function (node, next, inc) {
|
|
if (node) {
|
|
next = next ? 'nextSibling' : 'previousSibling';
|
|
for (node = inc ? node : node[next]; node; node = node[next]) {
|
|
if (node.nodeType === 1 || !isWhiteSpaceNode(node)) {
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var isTextBlock$1 = function (editor, name) {
|
|
if (name.nodeType) {
|
|
name = name.nodeName;
|
|
}
|
|
return !!editor.schema.getTextBlockElements()[name.toLowerCase()];
|
|
};
|
|
var isValid = function (ed, parent, child) {
|
|
return ed.schema.isValidChild(parent, child);
|
|
};
|
|
var isWhiteSpaceNode = function (node) {
|
|
return node && node.nodeType === 3 && /^([\t \r\n]+|)$/.test(node.nodeValue);
|
|
};
|
|
var replaceVars = function (value, vars) {
|
|
if (typeof value !== 'string') {
|
|
value = value(vars);
|
|
} else if (vars) {
|
|
value = value.replace(/%(\w+)/g, function (str, name) {
|
|
return vars[name] || str;
|
|
});
|
|
}
|
|
return value;
|
|
};
|
|
var isEq = function (str1, str2) {
|
|
str1 = str1 || '';
|
|
str2 = str2 || '';
|
|
str1 = '' + (str1.nodeName || str1);
|
|
str2 = '' + (str2.nodeName || str2);
|
|
return str1.toLowerCase() === str2.toLowerCase();
|
|
};
|
|
var normalizeStyleValue = function (dom, value, name) {
|
|
if (name === 'color' || name === 'backgroundColor') {
|
|
value = dom.toHex(value);
|
|
}
|
|
if (name === 'fontWeight' && value === 700) {
|
|
value = 'bold';
|
|
}
|
|
if (name === 'fontFamily') {
|
|
value = value.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
|
|
}
|
|
return '' + value;
|
|
};
|
|
var getStyle = function (dom, node, name) {
|
|
return normalizeStyleValue(dom, dom.getStyle(node, name), name);
|
|
};
|
|
var getTextDecoration = function (dom, node) {
|
|
var decoration;
|
|
dom.getParent(node, function (n) {
|
|
decoration = dom.getStyle(n, 'text-decoration');
|
|
return decoration && decoration !== 'none';
|
|
});
|
|
return decoration;
|
|
};
|
|
var getParents$1 = function (dom, node, selector) {
|
|
return dom.getParents(node, selector, dom.getRoot());
|
|
};
|
|
var FormatUtils = {
|
|
isInlineBlock: isInlineBlock,
|
|
moveStart: moveStart,
|
|
getNonWhiteSpaceSibling: getNonWhiteSpaceSibling,
|
|
isTextBlock: isTextBlock$1,
|
|
isValid: isValid,
|
|
isWhiteSpaceNode: isWhiteSpaceNode,
|
|
replaceVars: replaceVars,
|
|
isEq: isEq,
|
|
normalizeStyleValue: normalizeStyleValue,
|
|
getStyle: getStyle,
|
|
getTextDecoration: getTextDecoration,
|
|
getParents: getParents$1
|
|
};
|
|
|
|
var isBookmarkNode$2 = Bookmarks.isBookmarkNode;
|
|
var getParents$2 = FormatUtils.getParents, isWhiteSpaceNode$1 = FormatUtils.isWhiteSpaceNode, isTextBlock$2 = FormatUtils.isTextBlock;
|
|
var findLeaf = function (node, offset) {
|
|
if (typeof offset === 'undefined') {
|
|
offset = node.nodeType === 3 ? node.length : node.childNodes.length;
|
|
}
|
|
while (node && node.hasChildNodes()) {
|
|
node = node.childNodes[offset];
|
|
if (node) {
|
|
offset = node.nodeType === 3 ? node.length : node.childNodes.length;
|
|
}
|
|
}
|
|
return {
|
|
node: node,
|
|
offset: offset
|
|
};
|
|
};
|
|
var excludeTrailingWhitespace = function (endContainer, endOffset) {
|
|
var leaf = findLeaf(endContainer, endOffset);
|
|
if (leaf.node) {
|
|
while (leaf.node && leaf.offset === 0 && leaf.node.previousSibling) {
|
|
leaf = findLeaf(leaf.node.previousSibling);
|
|
}
|
|
if (leaf.node && leaf.offset > 0 && leaf.node.nodeType === 3 && leaf.node.nodeValue.charAt(leaf.offset - 1) === ' ') {
|
|
if (leaf.offset > 1) {
|
|
endContainer = leaf.node;
|
|
endContainer.splitText(leaf.offset - 1);
|
|
}
|
|
}
|
|
}
|
|
return endContainer;
|
|
};
|
|
var isBogusBr = function (node) {
|
|
return node.nodeName === 'BR' && node.getAttribute('data-mce-bogus') && !node.nextSibling;
|
|
};
|
|
var findParentContentEditable = function (dom, node) {
|
|
var parent = node;
|
|
while (parent) {
|
|
if (parent.nodeType === 1 && dom.getContentEditable(parent)) {
|
|
return dom.getContentEditable(parent) === 'false' ? parent : node;
|
|
}
|
|
parent = parent.parentNode;
|
|
}
|
|
return node;
|
|
};
|
|
var findSpace = function (start, remove, node, offset) {
|
|
var pos, pos2;
|
|
var str = node.nodeValue;
|
|
if (typeof offset === 'undefined') {
|
|
offset = start ? str.length : 0;
|
|
}
|
|
if (start) {
|
|
pos = str.lastIndexOf(' ', offset);
|
|
pos2 = str.lastIndexOf('\xA0', offset);
|
|
pos = pos > pos2 ? pos : pos2;
|
|
if (pos !== -1 && !remove && (pos < offset || !start) && pos <= str.length) {
|
|
pos++;
|
|
}
|
|
} else {
|
|
pos = str.indexOf(' ', offset);
|
|
pos2 = str.indexOf('\xA0', offset);
|
|
pos = pos !== -1 && (pos2 === -1 || pos < pos2) ? pos : pos2;
|
|
}
|
|
return pos;
|
|
};
|
|
var findWordEndPoint = function (dom, body, container, offset, start, remove) {
|
|
var node, pos, lastTextNode;
|
|
if (container.nodeType === 3) {
|
|
pos = findSpace(start, remove, container, offset);
|
|
if (pos !== -1) {
|
|
return {
|
|
container: container,
|
|
offset: pos
|
|
};
|
|
}
|
|
lastTextNode = container;
|
|
}
|
|
var walker = new TreeWalker(container, dom.getParent(container, dom.isBlock) || body);
|
|
while (node = walker[start ? 'prev' : 'next']()) {
|
|
if (node.nodeType === 3 && !isBookmarkNode$2(node.parentNode)) {
|
|
lastTextNode = node;
|
|
pos = findSpace(start, remove, node);
|
|
if (pos !== -1) {
|
|
return {
|
|
container: node,
|
|
offset: pos
|
|
};
|
|
}
|
|
} else if (dom.isBlock(node) || FormatUtils.isEq(node, 'BR')) {
|
|
break;
|
|
}
|
|
}
|
|
if (lastTextNode) {
|
|
if (start) {
|
|
offset = 0;
|
|
} else {
|
|
offset = lastTextNode.length;
|
|
}
|
|
return {
|
|
container: lastTextNode,
|
|
offset: offset
|
|
};
|
|
}
|
|
};
|
|
var findSelectorEndPoint = function (dom, format, rng, container, siblingName) {
|
|
var parents, i, y, curFormat;
|
|
if (container.nodeType === 3 && container.nodeValue.length === 0 && container[siblingName]) {
|
|
container = container[siblingName];
|
|
}
|
|
parents = getParents$2(dom, container);
|
|
for (i = 0; i < parents.length; i++) {
|
|
for (y = 0; y < format.length; y++) {
|
|
curFormat = format[y];
|
|
if ('collapsed' in curFormat && curFormat.collapsed !== rng.collapsed) {
|
|
continue;
|
|
}
|
|
if (dom.is(parents[i], curFormat.selector)) {
|
|
return parents[i];
|
|
}
|
|
}
|
|
}
|
|
return container;
|
|
};
|
|
var findBlockEndPoint = function (editor, format, container, siblingName) {
|
|
var node;
|
|
var dom = editor.dom;
|
|
var root = dom.getRoot();
|
|
if (!format[0].wrapper) {
|
|
node = dom.getParent(container, format[0].block, root);
|
|
}
|
|
if (!node) {
|
|
var scopeRoot = dom.getParent(container, 'LI,TD,TH');
|
|
node = dom.getParent(container.nodeType === 3 ? container.parentNode : container, function (node) {
|
|
return node !== root && isTextBlock$2(editor, node);
|
|
}, scopeRoot);
|
|
}
|
|
if (node && format[0].wrapper) {
|
|
node = getParents$2(dom, node, 'ul,ol').reverse()[0] || node;
|
|
}
|
|
if (!node) {
|
|
node = container;
|
|
while (node[siblingName] && !dom.isBlock(node[siblingName])) {
|
|
node = node[siblingName];
|
|
if (FormatUtils.isEq(node, 'br')) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return node || container;
|
|
};
|
|
var findParentContainer = function (dom, format, startContainer, startOffset, endContainer, endOffset, start) {
|
|
var container, parent, sibling, siblingName, root;
|
|
container = parent = start ? startContainer : endContainer;
|
|
siblingName = start ? 'previousSibling' : 'nextSibling';
|
|
root = dom.getRoot();
|
|
if (container.nodeType === 3 && !isWhiteSpaceNode$1(container)) {
|
|
if (start ? startOffset > 0 : endOffset < container.nodeValue.length) {
|
|
return container;
|
|
}
|
|
}
|
|
while (true) {
|
|
if (!format[0].block_expand && dom.isBlock(parent)) {
|
|
return parent;
|
|
}
|
|
for (sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
|
|
if (!isBookmarkNode$2(sibling) && !isWhiteSpaceNode$1(sibling) && !isBogusBr(sibling)) {
|
|
return parent;
|
|
}
|
|
}
|
|
if (parent === root || parent.parentNode === root) {
|
|
container = parent;
|
|
break;
|
|
}
|
|
parent = parent.parentNode;
|
|
}
|
|
return container;
|
|
};
|
|
var expandRng = function (editor, rng, format, remove) {
|
|
var endPoint, startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
|
|
var dom = editor.dom;
|
|
if (startContainer.nodeType === 1 && startContainer.hasChildNodes()) {
|
|
startContainer = getNode(startContainer, startOffset);
|
|
if (startContainer.nodeType === 3) {
|
|
startOffset = 0;
|
|
}
|
|
}
|
|
if (endContainer.nodeType === 1 && endContainer.hasChildNodes()) {
|
|
endContainer = getNode(endContainer, rng.collapsed ? endOffset : endOffset - 1);
|
|
if (endContainer.nodeType === 3) {
|
|
endOffset = endContainer.nodeValue.length;
|
|
}
|
|
}
|
|
startContainer = findParentContentEditable(dom, startContainer);
|
|
endContainer = findParentContentEditable(dom, endContainer);
|
|
if (isBookmarkNode$2(startContainer.parentNode) || isBookmarkNode$2(startContainer)) {
|
|
startContainer = isBookmarkNode$2(startContainer) ? startContainer : startContainer.parentNode;
|
|
if (rng.collapsed) {
|
|
startContainer = startContainer.previousSibling || startContainer;
|
|
} else {
|
|
startContainer = startContainer.nextSibling || startContainer;
|
|
}
|
|
if (startContainer.nodeType === 3) {
|
|
startOffset = rng.collapsed ? startContainer.length : 0;
|
|
}
|
|
}
|
|
if (isBookmarkNode$2(endContainer.parentNode) || isBookmarkNode$2(endContainer)) {
|
|
endContainer = isBookmarkNode$2(endContainer) ? endContainer : endContainer.parentNode;
|
|
if (rng.collapsed) {
|
|
endContainer = endContainer.nextSibling || endContainer;
|
|
} else {
|
|
endContainer = endContainer.previousSibling || endContainer;
|
|
}
|
|
if (endContainer.nodeType === 3) {
|
|
endOffset = rng.collapsed ? 0 : endContainer.length;
|
|
}
|
|
}
|
|
if (rng.collapsed) {
|
|
endPoint = findWordEndPoint(dom, editor.getBody(), startContainer, startOffset, true, remove);
|
|
if (endPoint) {
|
|
startContainer = endPoint.container;
|
|
startOffset = endPoint.offset;
|
|
}
|
|
endPoint = findWordEndPoint(dom, editor.getBody(), endContainer, endOffset, false, remove);
|
|
if (endPoint) {
|
|
endContainer = endPoint.container;
|
|
endOffset = endPoint.offset;
|
|
}
|
|
}
|
|
if (format[0].inline) {
|
|
endContainer = remove ? endContainer : excludeTrailingWhitespace(endContainer, endOffset);
|
|
}
|
|
if (format[0].inline || format[0].block_expand) {
|
|
if (!format[0].inline || (startContainer.nodeType !== 3 || startOffset === 0)) {
|
|
startContainer = findParentContainer(dom, format, startContainer, startOffset, endContainer, endOffset, true);
|
|
}
|
|
if (!format[0].inline || (endContainer.nodeType !== 3 || endOffset === endContainer.nodeValue.length)) {
|
|
endContainer = findParentContainer(dom, format, startContainer, startOffset, endContainer, endOffset, false);
|
|
}
|
|
}
|
|
if (format[0].selector && format[0].expand !== false && !format[0].inline) {
|
|
startContainer = findSelectorEndPoint(dom, format, rng, startContainer, 'previousSibling');
|
|
endContainer = findSelectorEndPoint(dom, format, rng, endContainer, 'nextSibling');
|
|
}
|
|
if (format[0].block || format[0].selector) {
|
|
startContainer = findBlockEndPoint(editor, format, startContainer, 'previousSibling');
|
|
endContainer = findBlockEndPoint(editor, format, endContainer, 'nextSibling');
|
|
if (format[0].block) {
|
|
if (!dom.isBlock(startContainer)) {
|
|
startContainer = findParentContainer(dom, format, startContainer, startOffset, endContainer, endOffset, true);
|
|
}
|
|
if (!dom.isBlock(endContainer)) {
|
|
endContainer = findParentContainer(dom, format, startContainer, startOffset, endContainer, endOffset, false);
|
|
}
|
|
}
|
|
}
|
|
if (startContainer.nodeType === 1) {
|
|
startOffset = dom.nodeIndex(startContainer);
|
|
startContainer = startContainer.parentNode;
|
|
}
|
|
if (endContainer.nodeType === 1) {
|
|
endOffset = dom.nodeIndex(endContainer) + 1;
|
|
endContainer = endContainer.parentNode;
|
|
}
|
|
return {
|
|
startContainer: startContainer,
|
|
startOffset: startOffset,
|
|
endContainer: endContainer,
|
|
endOffset: endOffset
|
|
};
|
|
};
|
|
var ExpandRange = { expandRng: expandRng };
|
|
|
|
var each$8 = Tools.each;
|
|
var getEndChild = function (container, index) {
|
|
var childNodes = container.childNodes;
|
|
index--;
|
|
if (index > childNodes.length - 1) {
|
|
index = childNodes.length - 1;
|
|
} else if (index < 0) {
|
|
index = 0;
|
|
}
|
|
return childNodes[index] || container;
|
|
};
|
|
var walk$1 = function (dom, rng, callback) {
|
|
var startContainer = rng.startContainer;
|
|
var startOffset = rng.startOffset;
|
|
var endContainer = rng.endContainer;
|
|
var endOffset = rng.endOffset;
|
|
var ancestor;
|
|
var startPoint;
|
|
var endPoint;
|
|
var node;
|
|
var parent;
|
|
var siblings;
|
|
var nodes;
|
|
nodes = dom.select('td[data-mce-selected],th[data-mce-selected]');
|
|
if (nodes.length > 0) {
|
|
each$8(nodes, function (node) {
|
|
callback([node]);
|
|
});
|
|
return;
|
|
}
|
|
var exclude = function (nodes) {
|
|
var node;
|
|
node = nodes[0];
|
|
if (node.nodeType === 3 && node === startContainer && startOffset >= node.nodeValue.length) {
|
|
nodes.splice(0, 1);
|
|
}
|
|
node = nodes[nodes.length - 1];
|
|
if (endOffset === 0 && nodes.length > 0 && node === endContainer && node.nodeType === 3) {
|
|
nodes.splice(nodes.length - 1, 1);
|
|
}
|
|
return nodes;
|
|
};
|
|
var collectSiblings = function (node, name, endNode) {
|
|
var siblings = [];
|
|
for (; node && node !== endNode; node = node[name]) {
|
|
siblings.push(node);
|
|
}
|
|
return siblings;
|
|
};
|
|
var findEndPoint = function (node, root) {
|
|
do {
|
|
if (node.parentNode === root) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
} while (node);
|
|
};
|
|
var walkBoundary = function (startNode, endNode, next) {
|
|
var siblingName = next ? 'nextSibling' : 'previousSibling';
|
|
for (node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
|
|
parent = node.parentNode;
|
|
siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
|
|
if (siblings.length) {
|
|
if (!next) {
|
|
siblings.reverse();
|
|
}
|
|
callback(exclude(siblings));
|
|
}
|
|
}
|
|
};
|
|
if (startContainer.nodeType === 1 && startContainer.hasChildNodes()) {
|
|
startContainer = startContainer.childNodes[startOffset];
|
|
}
|
|
if (endContainer.nodeType === 1 && endContainer.hasChildNodes()) {
|
|
endContainer = getEndChild(endContainer, endOffset);
|
|
}
|
|
if (startContainer === endContainer) {
|
|
return callback(exclude([startContainer]));
|
|
}
|
|
ancestor = dom.findCommonAncestor(startContainer, endContainer);
|
|
for (node = startContainer; node; node = node.parentNode) {
|
|
if (node === endContainer) {
|
|
return walkBoundary(startContainer, ancestor, true);
|
|
}
|
|
if (node === ancestor) {
|
|
break;
|
|
}
|
|
}
|
|
for (node = endContainer; node; node = node.parentNode) {
|
|
if (node === startContainer) {
|
|
return walkBoundary(endContainer, ancestor);
|
|
}
|
|
if (node === ancestor) {
|
|
break;
|
|
}
|
|
}
|
|
startPoint = findEndPoint(startContainer, ancestor) || startContainer;
|
|
endPoint = findEndPoint(endContainer, ancestor) || endContainer;
|
|
walkBoundary(startContainer, startPoint, true);
|
|
siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
|
|
if (siblings.length) {
|
|
callback(exclude(siblings));
|
|
}
|
|
walkBoundary(endContainer, endPoint);
|
|
};
|
|
var RangeWalk = { walk: walk$1 };
|
|
|
|
var zeroWidth = function () {
|
|
return '\uFEFF';
|
|
};
|
|
|
|
function NodeValue (is, name) {
|
|
var get = function (element) {
|
|
if (!is(element)) {
|
|
throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
|
|
}
|
|
return getOption(element).getOr('');
|
|
};
|
|
var getOption = function (element) {
|
|
return is(element) ? Option.from(element.dom().nodeValue) : Option.none();
|
|
};
|
|
var set = function (element, value) {
|
|
if (!is(element)) {
|
|
throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
|
|
}
|
|
element.dom().nodeValue = value;
|
|
};
|
|
return {
|
|
get: get,
|
|
getOption: getOption,
|
|
set: set
|
|
};
|
|
}
|
|
|
|
var api = NodeValue(isText$1, 'text');
|
|
var get$6 = function (element) {
|
|
return api.get(element);
|
|
};
|
|
|
|
var isZeroWidth = function (elem) {
|
|
return isText$1(elem) && get$6(elem) === zeroWidth();
|
|
};
|
|
var context = function (editor, elem, wrapName, nodeName) {
|
|
return parent(elem).fold(function () {
|
|
return 'skipping';
|
|
}, function (parent) {
|
|
if (nodeName === 'br' || isZeroWidth(elem)) {
|
|
return 'valid';
|
|
} else if (isAnnotation(elem)) {
|
|
return 'existing';
|
|
} else if (isCaretNode(elem)) {
|
|
return 'caret';
|
|
} else if (!FormatUtils.isValid(editor, wrapName, nodeName) || !FormatUtils.isValid(editor, name(parent), wrapName)) {
|
|
return 'invalid-child';
|
|
} else {
|
|
return 'valid';
|
|
}
|
|
});
|
|
};
|
|
|
|
var shouldApplyToTrailingSpaces = function (rng) {
|
|
return rng.startContainer.nodeType === 3 && rng.startContainer.nodeValue.length >= rng.startOffset && rng.startContainer.nodeValue[rng.startOffset] === '\xA0';
|
|
};
|
|
var applyWordGrab = function (editor, rng) {
|
|
var r = ExpandRange.expandRng(editor, rng, [{ inline: true }], shouldApplyToTrailingSpaces(rng));
|
|
rng.setStart(r.startContainer, r.startOffset);
|
|
rng.setEnd(r.endContainer, r.endOffset);
|
|
editor.selection.setRng(rng);
|
|
};
|
|
var makeAnnotation = function (eDoc, _a, annotationName, decorate) {
|
|
var _b = _a.uid, uid = _b === void 0 ? generate('mce-annotation') : _b, data = __rest(_a, ['uid']);
|
|
var master = Element.fromTag('span', eDoc);
|
|
add$3(master, annotation());
|
|
set(master, '' + dataAnnotationId(), uid);
|
|
set(master, '' + dataAnnotation(), annotationName);
|
|
var _c = decorate(uid, data), _d = _c.attributes, attributes = _d === void 0 ? {} : _d, _e = _c.classes, classes = _e === void 0 ? [] : _e;
|
|
setAll(master, attributes);
|
|
add$4(master, classes);
|
|
return master;
|
|
};
|
|
var annotate = function (editor, rng, annotationName, decorate, data) {
|
|
var newWrappers = [];
|
|
var master = makeAnnotation(editor.getDoc(), data, annotationName, decorate);
|
|
var wrapper = Cell(Option.none());
|
|
var finishWrapper = function () {
|
|
wrapper.set(Option.none());
|
|
};
|
|
var getOrOpenWrapper = function () {
|
|
return wrapper.get().getOrThunk(function () {
|
|
var nu = shallow(master);
|
|
newWrappers.push(nu);
|
|
wrapper.set(Option.some(nu));
|
|
return nu;
|
|
});
|
|
};
|
|
var processElements = function (elems) {
|
|
each(elems, processElement);
|
|
};
|
|
var processElement = function (elem) {
|
|
var ctx = context(editor, elem, 'span', name(elem));
|
|
switch (ctx) {
|
|
case 'invalid-child': {
|
|
finishWrapper();
|
|
var children$1 = children(elem);
|
|
processElements(children$1);
|
|
finishWrapper();
|
|
break;
|
|
}
|
|
case 'valid': {
|
|
var w = getOrOpenWrapper();
|
|
wrap$1(elem, w);
|
|
break;
|
|
}
|
|
case 'skipping':
|
|
case 'existing':
|
|
case 'caret':
|
|
}
|
|
};
|
|
var processNodes = function (nodes) {
|
|
var elems = map(nodes, Element.fromDom);
|
|
processElements(elems);
|
|
};
|
|
RangeWalk.walk(editor.dom, rng, function (nodes) {
|
|
finishWrapper();
|
|
processNodes(nodes);
|
|
});
|
|
return newWrappers;
|
|
};
|
|
var annotateWithBookmark = function (editor, name, settings, data) {
|
|
editor.undoManager.transact(function () {
|
|
var initialRng = editor.selection.getRng();
|
|
if (initialRng.collapsed) {
|
|
applyWordGrab(editor, initialRng);
|
|
}
|
|
if (editor.selection.getRng().collapsed) {
|
|
var wrapper = makeAnnotation(editor.getDoc(), data, name, settings.decorate);
|
|
set$1(wrapper, '\xA0');
|
|
editor.selection.getRng().insertNode(wrapper.dom());
|
|
editor.selection.select(wrapper.dom());
|
|
} else {
|
|
var bookmark = GetBookmark.getPersistentBookmark(editor.selection, false);
|
|
var rng = editor.selection.getRng();
|
|
annotate(editor, rng, name, settings.decorate, data);
|
|
editor.selection.moveToBookmark(bookmark);
|
|
}
|
|
});
|
|
};
|
|
|
|
var Annotator = function (editor) {
|
|
var registry = create$1();
|
|
setup$1(editor, registry);
|
|
var changes = setup(editor);
|
|
return {
|
|
register: function (name, settings) {
|
|
registry.register(name, settings);
|
|
},
|
|
annotate: function (name, data) {
|
|
registry.lookup(name).each(function (settings) {
|
|
annotateWithBookmark(editor, name, settings, data);
|
|
});
|
|
},
|
|
annotationChanged: function (name, callback) {
|
|
changes.addListener(name, callback);
|
|
},
|
|
remove: function (name) {
|
|
identify(editor, Option.some(name)).each(function (_a) {
|
|
var elements = _a.elements;
|
|
each(elements, unwrap);
|
|
});
|
|
},
|
|
getAll: function (name) {
|
|
var directory = findAll(editor, name);
|
|
return map$1(directory, function (elems) {
|
|
return map(elems, function (elem) {
|
|
return elem.dom();
|
|
});
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
var whiteSpaceRegExp$3 = /^[ \t\r\n]*$/;
|
|
var typeLookup = {
|
|
'#text': 3,
|
|
'#comment': 8,
|
|
'#cdata': 4,
|
|
'#pi': 7,
|
|
'#doctype': 10,
|
|
'#document-fragment': 11
|
|
};
|
|
var walk$2 = function (node, root, prev) {
|
|
var startName = prev ? 'lastChild' : 'firstChild';
|
|
var siblingName = prev ? 'prev' : 'next';
|
|
if (node[startName]) {
|
|
return node[startName];
|
|
}
|
|
if (node !== root) {
|
|
var sibling = node[siblingName];
|
|
if (sibling) {
|
|
return sibling;
|
|
}
|
|
for (var parent = node.parent; parent && parent !== root; parent = parent.parent) {
|
|
sibling = parent[siblingName];
|
|
if (sibling) {
|
|
return sibling;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var Node$1 = function () {
|
|
function Node(name, type) {
|
|
this.name = name;
|
|
this.type = type;
|
|
if (type === 1) {
|
|
this.attributes = [];
|
|
this.attributes.map = {};
|
|
}
|
|
}
|
|
Node.create = function (name, attrs) {
|
|
var node = new Node(name, typeLookup[name] || 1);
|
|
if (attrs) {
|
|
for (var attrName in attrs) {
|
|
node.attr(attrName, attrs[attrName]);
|
|
}
|
|
}
|
|
return node;
|
|
};
|
|
Node.prototype.replace = function (node) {
|
|
var self = this;
|
|
if (node.parent) {
|
|
node.remove();
|
|
}
|
|
self.insert(node, self);
|
|
self.remove();
|
|
return self;
|
|
};
|
|
Node.prototype.attr = function (name, value) {
|
|
var self = this;
|
|
var attrs;
|
|
if (typeof name !== 'string') {
|
|
for (var key in name) {
|
|
self.attr(key, name[key]);
|
|
}
|
|
return self;
|
|
}
|
|
if (attrs = self.attributes) {
|
|
if (value !== undefined) {
|
|
if (value === null) {
|
|
if (name in attrs.map) {
|
|
delete attrs.map[name];
|
|
var i = attrs.length;
|
|
while (i--) {
|
|
if (attrs[i].name === name) {
|
|
attrs.splice(i, 1);
|
|
return self;
|
|
}
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
if (name in attrs.map) {
|
|
var i = attrs.length;
|
|
while (i--) {
|
|
if (attrs[i].name === name) {
|
|
attrs[i].value = value;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
attrs.push({
|
|
name: name,
|
|
value: value
|
|
});
|
|
}
|
|
attrs.map[name] = value;
|
|
return self;
|
|
}
|
|
return attrs.map[name];
|
|
}
|
|
};
|
|
Node.prototype.clone = function () {
|
|
var self = this;
|
|
var clone = new Node(self.name, self.type);
|
|
var selfAttrs;
|
|
if (selfAttrs = self.attributes) {
|
|
var cloneAttrs = [];
|
|
cloneAttrs.map = {};
|
|
for (var i = 0, l = selfAttrs.length; i < l; i++) {
|
|
var selfAttr = selfAttrs[i];
|
|
if (selfAttr.name !== 'id') {
|
|
cloneAttrs[cloneAttrs.length] = {
|
|
name: selfAttr.name,
|
|
value: selfAttr.value
|
|
};
|
|
cloneAttrs.map[selfAttr.name] = selfAttr.value;
|
|
}
|
|
}
|
|
clone.attributes = cloneAttrs;
|
|
}
|
|
clone.value = self.value;
|
|
clone.shortEnded = self.shortEnded;
|
|
return clone;
|
|
};
|
|
Node.prototype.wrap = function (wrapper) {
|
|
var self = this;
|
|
self.parent.insert(wrapper, self);
|
|
wrapper.append(self);
|
|
return self;
|
|
};
|
|
Node.prototype.unwrap = function () {
|
|
var self = this;
|
|
for (var node = self.firstChild; node;) {
|
|
var next = node.next;
|
|
self.insert(node, self, true);
|
|
node = next;
|
|
}
|
|
self.remove();
|
|
};
|
|
Node.prototype.remove = function () {
|
|
var self = this, parent = self.parent, next = self.next, prev = self.prev;
|
|
if (parent) {
|
|
if (parent.firstChild === self) {
|
|
parent.firstChild = next;
|
|
if (next) {
|
|
next.prev = null;
|
|
}
|
|
} else {
|
|
prev.next = next;
|
|
}
|
|
if (parent.lastChild === self) {
|
|
parent.lastChild = prev;
|
|
if (prev) {
|
|
prev.next = null;
|
|
}
|
|
} else {
|
|
next.prev = prev;
|
|
}
|
|
self.parent = self.next = self.prev = null;
|
|
}
|
|
return self;
|
|
};
|
|
Node.prototype.append = function (node) {
|
|
var self = this;
|
|
if (node.parent) {
|
|
node.remove();
|
|
}
|
|
var last = self.lastChild;
|
|
if (last) {
|
|
last.next = node;
|
|
node.prev = last;
|
|
self.lastChild = node;
|
|
} else {
|
|
self.lastChild = self.firstChild = node;
|
|
}
|
|
node.parent = self;
|
|
return node;
|
|
};
|
|
Node.prototype.insert = function (node, refNode, before) {
|
|
if (node.parent) {
|
|
node.remove();
|
|
}
|
|
var parent = refNode.parent || this;
|
|
if (before) {
|
|
if (refNode === parent.firstChild) {
|
|
parent.firstChild = node;
|
|
} else {
|
|
refNode.prev.next = node;
|
|
}
|
|
node.prev = refNode.prev;
|
|
node.next = refNode;
|
|
refNode.prev = node;
|
|
} else {
|
|
if (refNode === parent.lastChild) {
|
|
parent.lastChild = node;
|
|
} else {
|
|
refNode.next.prev = node;
|
|
}
|
|
node.next = refNode.next;
|
|
node.prev = refNode;
|
|
refNode.next = node;
|
|
}
|
|
node.parent = parent;
|
|
return node;
|
|
};
|
|
Node.prototype.getAll = function (name) {
|
|
var self = this;
|
|
var collection = [];
|
|
for (var node = self.firstChild; node; node = walk$2(node, self)) {
|
|
if (node.name === name) {
|
|
collection.push(node);
|
|
}
|
|
}
|
|
return collection;
|
|
};
|
|
Node.prototype.empty = function () {
|
|
var self = this;
|
|
if (self.firstChild) {
|
|
var nodes = [];
|
|
for (var node = self.firstChild; node; node = walk$2(node, self)) {
|
|
nodes.push(node);
|
|
}
|
|
var i = nodes.length;
|
|
while (i--) {
|
|
var node = nodes[i];
|
|
node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
|
|
}
|
|
}
|
|
self.firstChild = self.lastChild = null;
|
|
return self;
|
|
};
|
|
Node.prototype.isEmpty = function (elements, whitespace, predicate) {
|
|
if (whitespace === void 0) {
|
|
whitespace = {};
|
|
}
|
|
var self = this;
|
|
var node = self.firstChild;
|
|
if (node) {
|
|
do {
|
|
if (node.type === 1) {
|
|
if (node.attr('data-mce-bogus')) {
|
|
continue;
|
|
}
|
|
if (elements[node.name]) {
|
|
return false;
|
|
}
|
|
var i = node.attributes.length;
|
|
while (i--) {
|
|
var name = node.attributes[i].name;
|
|
if (name === 'name' || name.indexOf('data-mce-bookmark') === 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (node.type === 8) {
|
|
return false;
|
|
}
|
|
if (node.type === 3 && !whiteSpaceRegExp$3.test(node.value)) {
|
|
return false;
|
|
}
|
|
if (node.type === 3 && node.parent && whitespace[node.parent.name] && whiteSpaceRegExp$3.test(node.value)) {
|
|
return false;
|
|
}
|
|
if (predicate && predicate(node)) {
|
|
return false;
|
|
}
|
|
} while (node = walk$2(node, self));
|
|
}
|
|
return true;
|
|
};
|
|
Node.prototype.walk = function (prev) {
|
|
return walk$2(this, null, prev);
|
|
};
|
|
return Node;
|
|
}();
|
|
|
|
var isValidPrefixAttrName = function (name) {
|
|
return name.indexOf('data-') === 0 || name.indexOf('aria-') === 0;
|
|
};
|
|
var trimComments = function (text) {
|
|
return text.replace(/<!--|-->/g, '');
|
|
};
|
|
var isInvalidUri = function (settings, uri) {
|
|
if (settings.allow_html_data_urls) {
|
|
return false;
|
|
} else if (/^data:image\//i.test(uri)) {
|
|
return settings.allow_svg_data_urls === false && /^data:image\/svg\+xml/i.test(uri);
|
|
} else {
|
|
return /^data:/i.test(uri);
|
|
}
|
|
};
|
|
var findEndTagIndex = function (schema, html, startIndex) {
|
|
var count = 1, index, matches, tokenRegExp, shortEndedElements;
|
|
shortEndedElements = schema.getShortEndedElements();
|
|
tokenRegExp = /<([!?\/])?([A-Za-z0-9\-_\:\.]+)((?:\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\/|\s+)>/g;
|
|
tokenRegExp.lastIndex = index = startIndex;
|
|
while (matches = tokenRegExp.exec(html)) {
|
|
index = tokenRegExp.lastIndex;
|
|
if (matches[1] === '/') {
|
|
count--;
|
|
} else if (!matches[1]) {
|
|
if (matches[2] in shortEndedElements) {
|
|
continue;
|
|
}
|
|
count++;
|
|
}
|
|
if (count === 0) {
|
|
break;
|
|
}
|
|
}
|
|
return index;
|
|
};
|
|
var checkBogusAttribute = function (regExp, attrString) {
|
|
var matches = regExp.exec(attrString);
|
|
if (matches) {
|
|
var name = matches[1];
|
|
var value = matches[2];
|
|
return typeof name === 'string' && name.toLowerCase() === 'data-mce-bogus' ? value : null;
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
function SaxParser(settings, schema) {
|
|
if (schema === void 0) {
|
|
schema = Schema();
|
|
}
|
|
var noop = function () {
|
|
};
|
|
settings = settings || {};
|
|
if (settings.fix_self_closing !== false) {
|
|
settings.fix_self_closing = true;
|
|
}
|
|
var comment = settings.comment ? settings.comment : noop;
|
|
var cdata = settings.cdata ? settings.cdata : noop;
|
|
var text = settings.text ? settings.text : noop;
|
|
var start = settings.start ? settings.start : noop;
|
|
var end = settings.end ? settings.end : noop;
|
|
var pi = settings.pi ? settings.pi : noop;
|
|
var doctype = settings.doctype ? settings.doctype : noop;
|
|
var parse = function (html) {
|
|
var matches, index = 0, value, endRegExp;
|
|
var stack = [];
|
|
var attrList, i, textData, name;
|
|
var isInternalElement, removeInternalElements, shortEndedElements, fillAttrsMap, isShortEnded;
|
|
var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
|
|
var attributesRequired, attributesDefault, attributesForced, processHtml;
|
|
var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
|
|
var decode = Entities.decode;
|
|
var fixSelfClosing;
|
|
var filteredUrlAttrs = Tools.makeMap('src,href,data,background,formaction,poster,xlink:href');
|
|
var scriptUriRegExp = /((java|vb)script|mhtml):/i;
|
|
var processEndTag = function (name) {
|
|
var pos, i;
|
|
pos = stack.length;
|
|
while (pos--) {
|
|
if (stack[pos].name === name) {
|
|
break;
|
|
}
|
|
}
|
|
if (pos >= 0) {
|
|
for (i = stack.length - 1; i >= pos; i--) {
|
|
name = stack[i];
|
|
if (name.valid) {
|
|
end(name.name);
|
|
}
|
|
}
|
|
stack.length = pos;
|
|
}
|
|
};
|
|
var parseAttribute = function (match, name, value, val2, val3) {
|
|
var attrRule, i;
|
|
var trimRegExp = /[\s\u0000-\u001F]+/g;
|
|
name = name.toLowerCase();
|
|
value = name in fillAttrsMap ? name : decode(value || val2 || val3 || '');
|
|
if (validate && !isInternalElement && isValidPrefixAttrName(name) === false) {
|
|
attrRule = validAttributesMap[name];
|
|
if (!attrRule && validAttributePatterns) {
|
|
i = validAttributePatterns.length;
|
|
while (i--) {
|
|
attrRule = validAttributePatterns[i];
|
|
if (attrRule.pattern.test(name)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i === -1) {
|
|
attrRule = null;
|
|
}
|
|
}
|
|
if (!attrRule) {
|
|
return;
|
|
}
|
|
if (attrRule.validValues && !(value in attrRule.validValues)) {
|
|
return;
|
|
}
|
|
}
|
|
if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
|
|
var uri = value.replace(trimRegExp, '');
|
|
try {
|
|
uri = decodeURIComponent(uri);
|
|
} catch (ex) {
|
|
uri = unescape(uri);
|
|
}
|
|
if (scriptUriRegExp.test(uri)) {
|
|
return;
|
|
}
|
|
if (isInvalidUri(settings, uri)) {
|
|
return;
|
|
}
|
|
}
|
|
if (isInternalElement && (name in filteredUrlAttrs || name.indexOf('on') === 0)) {
|
|
return;
|
|
}
|
|
attrList.map[name] = value;
|
|
attrList.push({
|
|
name: name,
|
|
value: value
|
|
});
|
|
};
|
|
tokenRegExp = new RegExp('<(?:' + '(?:!--([\\w\\W]*?)--!?>)|' + '(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|' + '(?:!DOCTYPE([\\w\\W]*?)>)|' + '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + '(?:\\/([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)>)|' + '(?:([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + ')', 'g');
|
|
attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;
|
|
shortEndedElements = schema.getShortEndedElements();
|
|
selfClosing = settings.self_closing_elements || schema.getSelfClosingElements();
|
|
fillAttrsMap = schema.getBoolAttrs();
|
|
validate = settings.validate;
|
|
removeInternalElements = settings.remove_internals;
|
|
fixSelfClosing = settings.fix_self_closing;
|
|
specialElements = schema.getSpecialElements();
|
|
processHtml = html + '>';
|
|
while (matches = tokenRegExp.exec(processHtml)) {
|
|
if (index < matches.index) {
|
|
text(decode(html.substr(index, matches.index - index)));
|
|
}
|
|
if (value = matches[6]) {
|
|
value = value.toLowerCase();
|
|
if (value.charAt(0) === ':') {
|
|
value = value.substr(1);
|
|
}
|
|
processEndTag(value);
|
|
} else if (value = matches[7]) {
|
|
if (matches.index + matches[0].length > html.length) {
|
|
text(decode(html.substr(matches.index)));
|
|
index = matches.index + matches[0].length;
|
|
continue;
|
|
}
|
|
value = value.toLowerCase();
|
|
if (value.charAt(0) === ':') {
|
|
value = value.substr(1);
|
|
}
|
|
isShortEnded = value in shortEndedElements;
|
|
if (fixSelfClosing && selfClosing[value] && stack.length > 0 && stack[stack.length - 1].name === value) {
|
|
processEndTag(value);
|
|
}
|
|
var bogusValue = checkBogusAttribute(attrRegExp, matches[8]);
|
|
if (bogusValue !== null) {
|
|
if (bogusValue === 'all') {
|
|
index = findEndTagIndex(schema, html, tokenRegExp.lastIndex);
|
|
tokenRegExp.lastIndex = index;
|
|
continue;
|
|
}
|
|
isValidElement = false;
|
|
}
|
|
if (!validate || (elementRule = schema.getElementRule(value))) {
|
|
isValidElement = true;
|
|
if (validate) {
|
|
validAttributesMap = elementRule.attributes;
|
|
validAttributePatterns = elementRule.attributePatterns;
|
|
}
|
|
if (attribsValue = matches[8]) {
|
|
isInternalElement = attribsValue.indexOf('data-mce-type') !== -1;
|
|
if (isInternalElement && removeInternalElements) {
|
|
isValidElement = false;
|
|
}
|
|
attrList = [];
|
|
attrList.map = {};
|
|
attribsValue.replace(attrRegExp, parseAttribute);
|
|
} else {
|
|
attrList = [];
|
|
attrList.map = {};
|
|
}
|
|
if (validate && !isInternalElement) {
|
|
attributesRequired = elementRule.attributesRequired;
|
|
attributesDefault = elementRule.attributesDefault;
|
|
attributesForced = elementRule.attributesForced;
|
|
anyAttributesRequired = elementRule.removeEmptyAttrs;
|
|
if (anyAttributesRequired && !attrList.length) {
|
|
isValidElement = false;
|
|
}
|
|
if (attributesForced) {
|
|
i = attributesForced.length;
|
|
while (i--) {
|
|
attr = attributesForced[i];
|
|
name = attr.name;
|
|
attrValue = attr.value;
|
|
if (attrValue === '{$uid}') {
|
|
attrValue = 'mce_' + idCount++;
|
|
}
|
|
attrList.map[name] = attrValue;
|
|
attrList.push({
|
|
name: name,
|
|
value: attrValue
|
|
});
|
|
}
|
|
}
|
|
if (attributesDefault) {
|
|
i = attributesDefault.length;
|
|
while (i--) {
|
|
attr = attributesDefault[i];
|
|
name = attr.name;
|
|
if (!(name in attrList.map)) {
|
|
attrValue = attr.value;
|
|
if (attrValue === '{$uid}') {
|
|
attrValue = 'mce_' + idCount++;
|
|
}
|
|
attrList.map[name] = attrValue;
|
|
attrList.push({
|
|
name: name,
|
|
value: attrValue
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (attributesRequired) {
|
|
i = attributesRequired.length;
|
|
while (i--) {
|
|
if (attributesRequired[i] in attrList.map) {
|
|
break;
|
|
}
|
|
}
|
|
if (i === -1) {
|
|
isValidElement = false;
|
|
}
|
|
}
|
|
if (attr = attrList.map['data-mce-bogus']) {
|
|
if (attr === 'all') {
|
|
index = findEndTagIndex(schema, html, tokenRegExp.lastIndex);
|
|
tokenRegExp.lastIndex = index;
|
|
continue;
|
|
}
|
|
isValidElement = false;
|
|
}
|
|
}
|
|
if (isValidElement) {
|
|
start(value, attrList, isShortEnded);
|
|
}
|
|
} else {
|
|
isValidElement = false;
|
|
}
|
|
if (endRegExp = specialElements[value]) {
|
|
endRegExp.lastIndex = index = matches.index + matches[0].length;
|
|
if (matches = endRegExp.exec(html)) {
|
|
if (isValidElement) {
|
|
textData = html.substr(index, matches.index - index);
|
|
}
|
|
index = matches.index + matches[0].length;
|
|
} else {
|
|
textData = html.substr(index);
|
|
index = html.length;
|
|
}
|
|
if (isValidElement) {
|
|
if (textData.length > 0) {
|
|
text(textData, true);
|
|
}
|
|
end(value);
|
|
}
|
|
tokenRegExp.lastIndex = index;
|
|
continue;
|
|
}
|
|
if (!isShortEnded) {
|
|
if (!attribsValue || attribsValue.indexOf('/') !== attribsValue.length - 1) {
|
|
stack.push({
|
|
name: value,
|
|
valid: isValidElement
|
|
});
|
|
} else if (isValidElement) {
|
|
end(value);
|
|
}
|
|
}
|
|
} else if (value = matches[1]) {
|
|
if (value.charAt(0) === '>') {
|
|
value = ' ' + value;
|
|
}
|
|
if (!settings.allow_conditional_comments && value.substr(0, 3).toLowerCase() === '[if') {
|
|
value = ' ' + value;
|
|
}
|
|
comment(value);
|
|
} else if (value = matches[2]) {
|
|
cdata(trimComments(value));
|
|
} else if (value = matches[3]) {
|
|
doctype(value);
|
|
} else if (value = matches[4]) {
|
|
pi(value, matches[5]);
|
|
}
|
|
index = matches.index + matches[0].length;
|
|
}
|
|
if (index < html.length) {
|
|
text(decode(html.substr(index)));
|
|
}
|
|
for (i = stack.length - 1; i >= 0; i--) {
|
|
value = stack[i];
|
|
if (value.valid) {
|
|
end(value.name);
|
|
}
|
|
}
|
|
};
|
|
return { parse: parse };
|
|
}
|
|
(function (SaxParser) {
|
|
SaxParser.findEndTag = findEndTagIndex;
|
|
}(SaxParser || (SaxParser = {})));
|
|
var SaxParser$1 = SaxParser;
|
|
|
|
var trimHtml = function (tempAttrs, html) {
|
|
var trimContentRegExp = new RegExp(['\\s?(' + tempAttrs.join('|') + ')="[^"]+"'].join('|'), 'gi');
|
|
return html.replace(trimContentRegExp, '');
|
|
};
|
|
var trimInternal = function (serializer, html) {
|
|
var content = html;
|
|
var bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
|
|
var endTagIndex, index, matchLength, matches, shortEndedElements;
|
|
var schema = serializer.schema;
|
|
content = trimHtml(serializer.getTempAttrs(), content);
|
|
shortEndedElements = schema.getShortEndedElements();
|
|
while (matches = bogusAllRegExp.exec(content)) {
|
|
index = bogusAllRegExp.lastIndex;
|
|
matchLength = matches[0].length;
|
|
if (shortEndedElements[matches[1]]) {
|
|
endTagIndex = index;
|
|
} else {
|
|
endTagIndex = SaxParser$1.findEndTag(schema, content, index);
|
|
}
|
|
content = content.substring(0, index - matchLength) + content.substring(endTagIndex);
|
|
bogusAllRegExp.lastIndex = index - matchLength;
|
|
}
|
|
return Zwsp.trim(content);
|
|
};
|
|
var trimExternal = trimInternal;
|
|
var TrimHtml = {
|
|
trimExternal: trimExternal,
|
|
trimInternal: trimInternal
|
|
};
|
|
|
|
var getBodySetting = function (editor, name, defaultValue) {
|
|
var value = editor.getParam(name, defaultValue);
|
|
if (value.indexOf('=') !== -1) {
|
|
var bodyObj = editor.getParam(name, '', 'hash');
|
|
return bodyObj.hasOwnProperty(editor.id) ? bodyObj[editor.id] : defaultValue;
|
|
} else {
|
|
return value;
|
|
}
|
|
};
|
|
var getIframeAttrs = function (editor) {
|
|
return editor.getParam('iframe_attrs', {});
|
|
};
|
|
var getDocType = function (editor) {
|
|
return editor.getParam('doctype', '<!DOCTYPE html>');
|
|
};
|
|
var getDocumentBaseUrl = function (editor) {
|
|
return editor.getParam('document_base_url', '');
|
|
};
|
|
var getBodyId = function (editor) {
|
|
return getBodySetting(editor, 'body_id', 'tinymce');
|
|
};
|
|
var getBodyClass = function (editor) {
|
|
return getBodySetting(editor, 'body_class', '');
|
|
};
|
|
var getContentSecurityPolicy = function (editor) {
|
|
return editor.getParam('content_security_policy', '');
|
|
};
|
|
var shouldPutBrInPre = function (editor) {
|
|
return editor.getParam('br_in_pre', true);
|
|
};
|
|
var getForcedRootBlock = function (editor) {
|
|
if (editor.getParam('force_p_newlines', false)) {
|
|
return 'p';
|
|
}
|
|
var block = editor.getParam('forced_root_block', 'p');
|
|
if (block === false) {
|
|
return '';
|
|
} else if (block === true) {
|
|
return 'p';
|
|
} else {
|
|
return block;
|
|
}
|
|
};
|
|
var getForcedRootBlockAttrs = function (editor) {
|
|
return editor.getParam('forced_root_block_attrs', {});
|
|
};
|
|
var getBrNewLineSelector = function (editor) {
|
|
return editor.getParam('br_newline_selector', '.mce-toc h2,figcaption,caption');
|
|
};
|
|
var getNoNewLineSelector = function (editor) {
|
|
return editor.getParam('no_newline_selector', '');
|
|
};
|
|
var shouldKeepStyles = function (editor) {
|
|
return editor.getParam('keep_styles', true);
|
|
};
|
|
var shouldEndContainerOnEmptyBlock = function (editor) {
|
|
return editor.getParam('end_container_on_empty_block', false);
|
|
};
|
|
var getFontStyleValues = function (editor) {
|
|
return Tools.explode(editor.getParam('font_size_style_values', 'xx-small,x-small,small,medium,large,x-large,xx-large'));
|
|
};
|
|
var getFontSizeClasses = function (editor) {
|
|
return Tools.explode(editor.getParam('font_size_classes', ''));
|
|
};
|
|
var getImagesDataImgFilter = function (editor) {
|
|
return editor.getParam('images_dataimg_filter', constant(true), 'function');
|
|
};
|
|
var isAutomaticUploadsEnabled = function (editor) {
|
|
return editor.getParam('automatic_uploads', true, 'boolean');
|
|
};
|
|
var shouldReuseFileName = function (editor) {
|
|
return editor.getParam('images_reuse_filename', false, 'boolean');
|
|
};
|
|
var shouldReplaceBlobUris = function (editor) {
|
|
return editor.getParam('images_replace_blob_uris', true, 'boolean');
|
|
};
|
|
var getIconPackName = function (editor) {
|
|
return editor.getParam('icons', '', 'string');
|
|
};
|
|
var getIconsUrl = function (editor) {
|
|
return editor.getParam('icons_url', '', 'string');
|
|
};
|
|
var getImageUploadUrl = function (editor) {
|
|
return editor.getParam('images_upload_url', '', 'string');
|
|
};
|
|
var getImageUploadBasePath = function (editor) {
|
|
return editor.getParam('images_upload_base_path', '', 'string');
|
|
};
|
|
var getImagesUploadCredentials = function (editor) {
|
|
return editor.getParam('images_upload_credentials', false, 'boolean');
|
|
};
|
|
var getImagesUploadHandler = function (editor) {
|
|
return editor.getParam('images_upload_handler', null, 'function');
|
|
};
|
|
var shouldUseContentCssCors = function (editor) {
|
|
return editor.getParam('content_css_cors', false, 'boolean');
|
|
};
|
|
var getReferrerPolicy = function (editor) {
|
|
return editor.getParam('referrer_policy', '', 'string');
|
|
};
|
|
var getLanguageCode = function (editor) {
|
|
return editor.getParam('language', 'en', 'string');
|
|
};
|
|
var getLanguageUrl = function (editor) {
|
|
return editor.getParam('language_url', '', 'string');
|
|
};
|
|
var shouldIndentUseMargin = function (editor) {
|
|
return editor.getParam('indent_use_margin', false);
|
|
};
|
|
var getIndentation = function (editor) {
|
|
return editor.getParam('indentation', '40px', 'string');
|
|
};
|
|
var getContentCss = function (editor) {
|
|
var contentCss = editor.settings.content_css;
|
|
if (isString(contentCss)) {
|
|
return map(contentCss.split(','), trim);
|
|
} else if (isArray(contentCss)) {
|
|
return contentCss;
|
|
} else if (contentCss === false || editor.inline) {
|
|
return [];
|
|
} else {
|
|
return ['default'];
|
|
}
|
|
};
|
|
var getDirectionality = function (editor) {
|
|
return editor.getParam('directionality', I18n.isRtl() ? 'rtl' : undefined);
|
|
};
|
|
var getInlineBoundarySelector = function (editor) {
|
|
return editor.getParam('inline_boundaries_selector', 'a[href],code,.mce-annotation', 'string');
|
|
};
|
|
var Settings = {
|
|
getIframeAttrs: getIframeAttrs,
|
|
getDocType: getDocType,
|
|
getDocumentBaseUrl: getDocumentBaseUrl,
|
|
getBodyId: getBodyId,
|
|
getBodyClass: getBodyClass,
|
|
getContentSecurityPolicy: getContentSecurityPolicy,
|
|
shouldPutBrInPre: shouldPutBrInPre,
|
|
getForcedRootBlock: getForcedRootBlock,
|
|
getForcedRootBlockAttrs: getForcedRootBlockAttrs,
|
|
getBrNewLineSelector: getBrNewLineSelector,
|
|
getNoNewLineSelector: getNoNewLineSelector,
|
|
shouldKeepStyles: shouldKeepStyles,
|
|
shouldEndContainerOnEmptyBlock: shouldEndContainerOnEmptyBlock,
|
|
getFontStyleValues: getFontStyleValues,
|
|
getFontSizeClasses: getFontSizeClasses,
|
|
getIconPackName: getIconPackName,
|
|
getIconsUrl: getIconsUrl,
|
|
getImagesDataImgFilter: getImagesDataImgFilter,
|
|
isAutomaticUploadsEnabled: isAutomaticUploadsEnabled,
|
|
shouldReuseFileName: shouldReuseFileName,
|
|
shouldReplaceBlobUris: shouldReplaceBlobUris,
|
|
getImageUploadUrl: getImageUploadUrl,
|
|
getImageUploadBasePath: getImageUploadBasePath,
|
|
getImagesUploadCredentials: getImagesUploadCredentials,
|
|
getImagesUploadHandler: getImagesUploadHandler,
|
|
shouldUseContentCssCors: shouldUseContentCssCors,
|
|
getReferrerPolicy: getReferrerPolicy,
|
|
getLanguageCode: getLanguageCode,
|
|
getLanguageUrl: getLanguageUrl,
|
|
shouldIndentUseMargin: shouldIndentUseMargin,
|
|
getIndentation: getIndentation,
|
|
getContentCss: getContentCss,
|
|
getDirectionality: getDirectionality,
|
|
getInlineBoundarySelector: getInlineBoundarySelector
|
|
};
|
|
|
|
var defaultFormat = 'html';
|
|
var trimEmptyContents = function (editor, html) {
|
|
var blockName = Settings.getForcedRootBlock(editor);
|
|
var emptyRegExp = new RegExp('^(<' + blockName + '[^>]*>( | |\\s|\xA0|<br \\/>|)<\\/' + blockName + '>[\r\n]*|<br \\/>[\r\n]*)$');
|
|
return html.replace(emptyRegExp, '');
|
|
};
|
|
var getContentFromBody = function (editor, args, body) {
|
|
var content;
|
|
args.format = args.format ? args.format : defaultFormat;
|
|
args.get = true;
|
|
args.getInner = true;
|
|
if (!args.no_events) {
|
|
editor.fire('BeforeGetContent', args);
|
|
}
|
|
if (args.format === 'raw') {
|
|
content = Tools.trim(TrimHtml.trimExternal(editor.serializer, body.innerHTML));
|
|
} else if (args.format === 'text') {
|
|
content = Zwsp.trim(body.innerText || body.textContent);
|
|
} else if (args.format === 'tree') {
|
|
return editor.serializer.serialize(body, args);
|
|
} else {
|
|
content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
|
|
}
|
|
if (args.format !== 'text' && !isWsPreserveElement(Element.fromDom(body))) {
|
|
args.content = Tools.trim(content);
|
|
} else {
|
|
args.content = content;
|
|
}
|
|
if (!args.no_events) {
|
|
editor.fire('GetContent', args);
|
|
}
|
|
return args.content;
|
|
};
|
|
var getContent = function (editor, args) {
|
|
if (args === void 0) {
|
|
args = {};
|
|
}
|
|
return Option.from(editor.getBody()).fold(constant(args.format === 'tree' ? new Node$1('body', 11) : ''), function (body) {
|
|
return getContentFromBody(editor, args, body);
|
|
});
|
|
};
|
|
|
|
var makeMap$3 = Tools.makeMap;
|
|
var Writer = function (settings) {
|
|
var html = [];
|
|
var indent, indentBefore, indentAfter, encode, htmlOutput;
|
|
settings = settings || {};
|
|
indent = settings.indent;
|
|
indentBefore = makeMap$3(settings.indent_before || '');
|
|
indentAfter = makeMap$3(settings.indent_after || '');
|
|
encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
|
|
htmlOutput = settings.element_format === 'html';
|
|
return {
|
|
start: function (name, attrs, empty) {
|
|
var i, l, attr, value;
|
|
if (indent && indentBefore[name] && html.length > 0) {
|
|
value = html[html.length - 1];
|
|
if (value.length > 0 && value !== '\n') {
|
|
html.push('\n');
|
|
}
|
|
}
|
|
html.push('<', name);
|
|
if (attrs) {
|
|
for (i = 0, l = attrs.length; i < l; i++) {
|
|
attr = attrs[i];
|
|
html.push(' ', attr.name, '="', encode(attr.value, true), '"');
|
|
}
|
|
}
|
|
if (!empty || htmlOutput) {
|
|
html[html.length] = '>';
|
|
} else {
|
|
html[html.length] = ' />';
|
|
}
|
|
if (empty && indent && indentAfter[name] && html.length > 0) {
|
|
value = html[html.length - 1];
|
|
if (value.length > 0 && value !== '\n') {
|
|
html.push('\n');
|
|
}
|
|
}
|
|
},
|
|
end: function (name) {
|
|
var value;
|
|
html.push('</', name, '>');
|
|
if (indent && indentAfter[name] && html.length > 0) {
|
|
value = html[html.length - 1];
|
|
if (value.length > 0 && value !== '\n') {
|
|
html.push('\n');
|
|
}
|
|
}
|
|
},
|
|
text: function (text, raw) {
|
|
if (text.length > 0) {
|
|
html[html.length] = raw ? text : encode(text);
|
|
}
|
|
},
|
|
cdata: function (text) {
|
|
html.push('<![CDATA[', text, ']]>');
|
|
},
|
|
comment: function (text) {
|
|
html.push('<!--', text, '-->');
|
|
},
|
|
pi: function (name, text) {
|
|
if (text) {
|
|
html.push('<?', name, ' ', encode(text), '?>');
|
|
} else {
|
|
html.push('<?', name, '?>');
|
|
}
|
|
if (indent) {
|
|
html.push('\n');
|
|
}
|
|
},
|
|
doctype: function (text) {
|
|
html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
|
|
},
|
|
reset: function () {
|
|
html.length = 0;
|
|
},
|
|
getContent: function () {
|
|
return html.join('').replace(/\n$/, '');
|
|
}
|
|
};
|
|
};
|
|
|
|
var Serializer = function (settings, schema) {
|
|
if (schema === void 0) {
|
|
schema = Schema();
|
|
}
|
|
var writer = Writer(settings);
|
|
settings = settings || {};
|
|
settings.validate = 'validate' in settings ? settings.validate : true;
|
|
var serialize = function (node) {
|
|
var handlers, validate;
|
|
validate = settings.validate;
|
|
handlers = {
|
|
3: function (node) {
|
|
writer.text(node.value, node.raw);
|
|
},
|
|
8: function (node) {
|
|
writer.comment(node.value);
|
|
},
|
|
7: function (node) {
|
|
writer.pi(node.name, node.value);
|
|
},
|
|
10: function (node) {
|
|
writer.doctype(node.value);
|
|
},
|
|
4: function (node) {
|
|
writer.cdata(node.value);
|
|
},
|
|
11: function (node) {
|
|
if (node = node.firstChild) {
|
|
do {
|
|
walk(node);
|
|
} while (node = node.next);
|
|
}
|
|
}
|
|
};
|
|
writer.reset();
|
|
var walk = function (node) {
|
|
var handler = handlers[node.type];
|
|
var name, isEmpty, attrs, attrName, attrValue, sortedAttrs, i, l, elementRule;
|
|
if (!handler) {
|
|
name = node.name;
|
|
isEmpty = node.shortEnded;
|
|
attrs = node.attributes;
|
|
if (validate && attrs && attrs.length > 1) {
|
|
sortedAttrs = [];
|
|
sortedAttrs.map = {};
|
|
elementRule = schema.getElementRule(node.name);
|
|
if (elementRule) {
|
|
for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
|
|
attrName = elementRule.attributesOrder[i];
|
|
if (attrName in attrs.map) {
|
|
attrValue = attrs.map[attrName];
|
|
sortedAttrs.map[attrName] = attrValue;
|
|
sortedAttrs.push({
|
|
name: attrName,
|
|
value: attrValue
|
|
});
|
|
}
|
|
}
|
|
for (i = 0, l = attrs.length; i < l; i++) {
|
|
attrName = attrs[i].name;
|
|
if (!(attrName in sortedAttrs.map)) {
|
|
attrValue = attrs.map[attrName];
|
|
sortedAttrs.map[attrName] = attrValue;
|
|
sortedAttrs.push({
|
|
name: attrName,
|
|
value: attrValue
|
|
});
|
|
}
|
|
}
|
|
attrs = sortedAttrs;
|
|
}
|
|
}
|
|
writer.start(node.name, attrs, isEmpty);
|
|
if (!isEmpty) {
|
|
if (node = node.firstChild) {
|
|
do {
|
|
walk(node);
|
|
} while (node = node.next);
|
|
}
|
|
writer.end(name);
|
|
}
|
|
} else {
|
|
handler(node);
|
|
}
|
|
};
|
|
if (node.type === 1 && !settings.inner) {
|
|
walk(node);
|
|
} else {
|
|
handlers[11](node);
|
|
}
|
|
return writer.getContent();
|
|
};
|
|
return { serialize: serialize };
|
|
};
|
|
|
|
var traverse = function (node, fn) {
|
|
fn(node);
|
|
if (node.firstChild) {
|
|
traverse(node.firstChild, fn);
|
|
}
|
|
if (node.next) {
|
|
traverse(node.next, fn);
|
|
}
|
|
};
|
|
var findMatchingNodes = function (nodeFilters, attributeFilters, node) {
|
|
var nodeMatches = {};
|
|
var attrMatches = {};
|
|
var matches = [];
|
|
if (node.firstChild) {
|
|
traverse(node.firstChild, function (node) {
|
|
each(nodeFilters, function (filter) {
|
|
if (filter.name === node.name) {
|
|
if (nodeMatches[filter.name]) {
|
|
nodeMatches[filter.name].nodes.push(node);
|
|
} else {
|
|
nodeMatches[filter.name] = {
|
|
filter: filter,
|
|
nodes: [node]
|
|
};
|
|
}
|
|
}
|
|
});
|
|
each(attributeFilters, function (filter) {
|
|
if (typeof node.attr(filter.name) === 'string') {
|
|
if (attrMatches[filter.name]) {
|
|
attrMatches[filter.name].nodes.push(node);
|
|
} else {
|
|
attrMatches[filter.name] = {
|
|
filter: filter,
|
|
nodes: [node]
|
|
};
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
for (var name in nodeMatches) {
|
|
if (nodeMatches.hasOwnProperty(name)) {
|
|
matches.push(nodeMatches[name]);
|
|
}
|
|
}
|
|
for (var name in attrMatches) {
|
|
if (attrMatches.hasOwnProperty(name)) {
|
|
matches.push(attrMatches[name]);
|
|
}
|
|
}
|
|
return matches;
|
|
};
|
|
var filter$2 = function (nodeFilters, attributeFilters, node) {
|
|
var matches = findMatchingNodes(nodeFilters, attributeFilters, node);
|
|
each(matches, function (match) {
|
|
each(match.filter.callbacks, function (callback) {
|
|
callback(match.nodes, match.filter.name, {});
|
|
});
|
|
});
|
|
};
|
|
|
|
var hasFocus = function (element) {
|
|
var doc = owner(element).dom();
|
|
return element.dom() === doc.activeElement;
|
|
};
|
|
var active = function (_doc) {
|
|
var doc = _doc !== undefined ? _doc.dom() : domGlobals.document;
|
|
return Option.from(doc.activeElement).map(Element.fromDom);
|
|
};
|
|
var search = function (element) {
|
|
return active(owner(element)).filter(function (e) {
|
|
return element.dom().contains(e.dom());
|
|
});
|
|
};
|
|
|
|
var generate$1 = function (cases) {
|
|
if (!isArray(cases)) {
|
|
throw new Error('cases must be an array');
|
|
}
|
|
if (cases.length === 0) {
|
|
throw new Error('there must be at least one case');
|
|
}
|
|
var constructors = [];
|
|
var adt = {};
|
|
each(cases, function (acase, count) {
|
|
var keys$1 = keys(acase);
|
|
if (keys$1.length !== 1) {
|
|
throw new Error('one and only one name per case');
|
|
}
|
|
var key = keys$1[0];
|
|
var value = acase[key];
|
|
if (adt[key] !== undefined) {
|
|
throw new Error('duplicate key detected:' + key);
|
|
} else if (key === 'cata') {
|
|
throw new Error('cannot have a case named cata (sorry)');
|
|
} else if (!isArray(value)) {
|
|
throw new Error('case arguments must be an array');
|
|
}
|
|
constructors.push(key);
|
|
adt[key] = function () {
|
|
var argLength = arguments.length;
|
|
if (argLength !== value.length) {
|
|
throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
|
|
}
|
|
var args = new Array(argLength);
|
|
for (var i = 0; i < args.length; i++) {
|
|
args[i] = arguments[i];
|
|
}
|
|
var match = function (branches) {
|
|
var branchKeys = keys(branches);
|
|
if (constructors.length !== branchKeys.length) {
|
|
throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
|
|
}
|
|
var allReqd = forall(constructors, function (reqKey) {
|
|
return contains(branchKeys, reqKey);
|
|
});
|
|
if (!allReqd) {
|
|
throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
|
|
}
|
|
return branches[key].apply(null, args);
|
|
};
|
|
return {
|
|
fold: function () {
|
|
if (arguments.length !== cases.length) {
|
|
throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + arguments.length);
|
|
}
|
|
var target = arguments[count];
|
|
return target.apply(null, args);
|
|
},
|
|
match: match,
|
|
log: function (label) {
|
|
domGlobals.console.log(label, {
|
|
constructors: constructors,
|
|
constructor: key,
|
|
params: args
|
|
});
|
|
}
|
|
};
|
|
};
|
|
});
|
|
return adt;
|
|
};
|
|
var Adt = { generate: generate$1 };
|
|
|
|
var create$3 = Immutable('start', 'soffset', 'finish', 'foffset');
|
|
var SimRange = { create: create$3 };
|
|
|
|
var adt = Adt.generate([
|
|
{ before: ['element'] },
|
|
{
|
|
on: [
|
|
'element',
|
|
'offset'
|
|
]
|
|
},
|
|
{ after: ['element'] }
|
|
]);
|
|
var cata = function (subject, onBefore, onOn, onAfter) {
|
|
return subject.fold(onBefore, onOn, onAfter);
|
|
};
|
|
var getStart = function (situ) {
|
|
return situ.fold(identity, identity, identity);
|
|
};
|
|
var before$3 = adt.before;
|
|
var on = adt.on;
|
|
var after$2 = adt.after;
|
|
var Situ = {
|
|
before: before$3,
|
|
on: on,
|
|
after: after$2,
|
|
cata: cata,
|
|
getStart: getStart
|
|
};
|
|
|
|
var adt$1 = Adt.generate([
|
|
{ domRange: ['rng'] },
|
|
{
|
|
relative: [
|
|
'startSitu',
|
|
'finishSitu'
|
|
]
|
|
},
|
|
{
|
|
exact: [
|
|
'start',
|
|
'soffset',
|
|
'finish',
|
|
'foffset'
|
|
]
|
|
}
|
|
]);
|
|
var exactFromRange = function (simRange) {
|
|
return adt$1.exact(simRange.start(), simRange.soffset(), simRange.finish(), simRange.foffset());
|
|
};
|
|
var getStart$1 = function (selection) {
|
|
return selection.match({
|
|
domRange: function (rng) {
|
|
return Element.fromDom(rng.startContainer);
|
|
},
|
|
relative: function (startSitu, finishSitu) {
|
|
return Situ.getStart(startSitu);
|
|
},
|
|
exact: function (start, soffset, finish, foffset) {
|
|
return start;
|
|
}
|
|
});
|
|
};
|
|
var domRange = adt$1.domRange;
|
|
var relative = adt$1.relative;
|
|
var exact = adt$1.exact;
|
|
var getWin = function (selection) {
|
|
var start = getStart$1(selection);
|
|
return defaultView(start);
|
|
};
|
|
var range = SimRange.create;
|
|
var Selection = {
|
|
domRange: domRange,
|
|
relative: relative,
|
|
exact: exact,
|
|
exactFromRange: exactFromRange,
|
|
getWin: getWin,
|
|
range: range
|
|
};
|
|
|
|
var browser$4 = detect$3().browser;
|
|
var clamp = function (offset, element) {
|
|
var max = isText$1(element) ? get$6(element).length : children(element).length + 1;
|
|
if (offset > max) {
|
|
return max;
|
|
} else if (offset < 0) {
|
|
return 0;
|
|
}
|
|
return offset;
|
|
};
|
|
var normalizeRng = function (rng) {
|
|
return Selection.range(rng.start(), clamp(rng.soffset(), rng.start()), rng.finish(), clamp(rng.foffset(), rng.finish()));
|
|
};
|
|
var isOrContains = function (root, elm) {
|
|
return !NodeType.isRestrictedNode(elm.dom()) && (contains$2(root, elm) || eq(root, elm));
|
|
};
|
|
var isRngInRoot = function (root) {
|
|
return function (rng) {
|
|
return isOrContains(root, rng.start()) && isOrContains(root, rng.finish());
|
|
};
|
|
};
|
|
var shouldStore = function (editor) {
|
|
return editor.inline === true || browser$4.isIE();
|
|
};
|
|
var nativeRangeToSelectionRange = function (r) {
|
|
return Selection.range(Element.fromDom(r.startContainer), r.startOffset, Element.fromDom(r.endContainer), r.endOffset);
|
|
};
|
|
var readRange = function (win) {
|
|
var selection = win.getSelection();
|
|
var rng = !selection || selection.rangeCount === 0 ? Option.none() : Option.from(selection.getRangeAt(0));
|
|
return rng.map(nativeRangeToSelectionRange);
|
|
};
|
|
var getBookmark$2 = function (root) {
|
|
var win = defaultView(root);
|
|
return readRange(win.dom()).filter(isRngInRoot(root));
|
|
};
|
|
var validate = function (root, bookmark) {
|
|
return Option.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
|
|
};
|
|
var bookmarkToNativeRng = function (bookmark) {
|
|
var rng = domGlobals.document.createRange();
|
|
try {
|
|
rng.setStart(bookmark.start().dom(), bookmark.soffset());
|
|
rng.setEnd(bookmark.finish().dom(), bookmark.foffset());
|
|
return Option.some(rng);
|
|
} catch (_) {
|
|
return Option.none();
|
|
}
|
|
};
|
|
var store = function (editor) {
|
|
var newBookmark = shouldStore(editor) ? getBookmark$2(Element.fromDom(editor.getBody())) : Option.none();
|
|
editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
|
|
};
|
|
var storeNative = function (editor, rng) {
|
|
var root = Element.fromDom(editor.getBody());
|
|
var range = shouldStore(editor) ? Option.from(rng) : Option.none();
|
|
var newBookmark = range.map(nativeRangeToSelectionRange).filter(isRngInRoot(root));
|
|
editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
|
|
};
|
|
var getRng = function (editor) {
|
|
var bookmark = editor.bookmark ? editor.bookmark : Option.none();
|
|
return bookmark.bind(function (x) {
|
|
return validate(Element.fromDom(editor.getBody()), x);
|
|
}).bind(bookmarkToNativeRng);
|
|
};
|
|
var restore = function (editor) {
|
|
getRng(editor).each(function (rng) {
|
|
editor.selection.setRng(rng);
|
|
});
|
|
};
|
|
var SelectionBookmark = {
|
|
store: store,
|
|
storeNative: storeNative,
|
|
readRange: readRange,
|
|
restore: restore,
|
|
getRng: getRng,
|
|
getBookmark: getBookmark$2,
|
|
validate: validate
|
|
};
|
|
|
|
var isEditorUIElement = function (elm) {
|
|
var className = elm.className.toString();
|
|
return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
|
|
};
|
|
var FocusManager = { isEditorUIElement: isEditorUIElement };
|
|
|
|
var isManualNodeChange = function (e) {
|
|
return e.type === 'nodechange' && e.selectionChange;
|
|
};
|
|
var registerPageMouseUp = function (editor, throttledStore) {
|
|
var mouseUpPage = function () {
|
|
throttledStore.throttle();
|
|
};
|
|
DOMUtils$1.DOM.bind(domGlobals.document, 'mouseup', mouseUpPage);
|
|
editor.on('remove', function () {
|
|
DOMUtils$1.DOM.unbind(domGlobals.document, 'mouseup', mouseUpPage);
|
|
});
|
|
};
|
|
var registerFocusOut = function (editor) {
|
|
editor.on('focusout', function () {
|
|
SelectionBookmark.store(editor);
|
|
});
|
|
};
|
|
var registerMouseUp = function (editor, throttledStore) {
|
|
editor.on('mouseup touchend', function (e) {
|
|
throttledStore.throttle();
|
|
});
|
|
};
|
|
var registerEditorEvents = function (editor, throttledStore) {
|
|
var browser = detect$3().browser;
|
|
if (browser.isIE()) {
|
|
registerFocusOut(editor);
|
|
} else {
|
|
registerMouseUp(editor, throttledStore);
|
|
}
|
|
editor.on('keyup NodeChange', function (e) {
|
|
if (!isManualNodeChange(e)) {
|
|
SelectionBookmark.store(editor);
|
|
}
|
|
});
|
|
};
|
|
var register = function (editor) {
|
|
var throttledStore = first(function () {
|
|
SelectionBookmark.store(editor);
|
|
}, 0);
|
|
editor.on('init', function () {
|
|
if (editor.inline) {
|
|
registerPageMouseUp(editor, throttledStore);
|
|
}
|
|
registerEditorEvents(editor, throttledStore);
|
|
});
|
|
editor.on('remove', function () {
|
|
throttledStore.cancel();
|
|
});
|
|
};
|
|
var SelectionRestore = { register: register };
|
|
|
|
var documentFocusInHandler;
|
|
var DOM$1 = DOMUtils$1.DOM;
|
|
var isEditorUIElement$1 = function (elm) {
|
|
return FocusManager.isEditorUIElement(elm);
|
|
};
|
|
var isEditorContentAreaElement = function (elm) {
|
|
var classList = elm.classList;
|
|
if (classList !== undefined) {
|
|
return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var isUIElement = function (editor, elm) {
|
|
var customSelector = editor ? editor.settings.custom_ui_selector : '';
|
|
var parent = DOM$1.getParent(elm, function (elm) {
|
|
return isEditorUIElement$1(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
|
|
});
|
|
return parent !== null;
|
|
};
|
|
var getActiveElement = function () {
|
|
try {
|
|
return domGlobals.document.activeElement;
|
|
} catch (ex) {
|
|
return domGlobals.document.body;
|
|
}
|
|
};
|
|
var registerEvents = function (editorManager, e) {
|
|
var editor = e.editor;
|
|
SelectionRestore.register(editor);
|
|
editor.on('focusin', function () {
|
|
var self = this;
|
|
var focusedEditor = editorManager.focusedEditor;
|
|
if (focusedEditor !== self) {
|
|
if (focusedEditor) {
|
|
focusedEditor.fire('blur', { focusedEditor: self });
|
|
}
|
|
editorManager.setActive(self);
|
|
editorManager.focusedEditor = self;
|
|
self.fire('focus', { blurredEditor: focusedEditor });
|
|
self.focus(true);
|
|
}
|
|
});
|
|
editor.on('focusout', function () {
|
|
var self = this;
|
|
Delay.setEditorTimeout(self, function () {
|
|
var focusedEditor = editorManager.focusedEditor;
|
|
if (!isUIElement(self, getActiveElement()) && focusedEditor === self) {
|
|
self.fire('blur', { focusedEditor: null });
|
|
editorManager.focusedEditor = null;
|
|
}
|
|
});
|
|
});
|
|
if (!documentFocusInHandler) {
|
|
documentFocusInHandler = function (e) {
|
|
var activeEditor = editorManager.activeEditor;
|
|
var target;
|
|
target = e.target;
|
|
if (activeEditor && target.ownerDocument === domGlobals.document) {
|
|
if (target !== domGlobals.document.body && !isUIElement(activeEditor, target) && editorManager.focusedEditor === activeEditor) {
|
|
activeEditor.fire('blur', { focusedEditor: null });
|
|
editorManager.focusedEditor = null;
|
|
}
|
|
}
|
|
};
|
|
DOM$1.bind(domGlobals.document, 'focusin', documentFocusInHandler);
|
|
}
|
|
};
|
|
var unregisterDocumentEvents = function (editorManager, e) {
|
|
if (editorManager.focusedEditor === e.editor) {
|
|
editorManager.focusedEditor = null;
|
|
}
|
|
if (!editorManager.activeEditor) {
|
|
DOM$1.unbind(domGlobals.document, 'focusin', documentFocusInHandler);
|
|
documentFocusInHandler = null;
|
|
}
|
|
};
|
|
var setup$2 = function (editorManager) {
|
|
editorManager.on('AddEditor', curry(registerEvents, editorManager));
|
|
editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
|
|
};
|
|
var FocusController = {
|
|
setup: setup$2,
|
|
isEditorUIElement: isEditorUIElement$1,
|
|
isEditorContentAreaElement: isEditorContentAreaElement,
|
|
isUIElement: isUIElement
|
|
};
|
|
|
|
var getContentEditableHost = function (editor, node) {
|
|
return editor.dom.getParent(node, function (node) {
|
|
return editor.dom.getContentEditable(node) === 'true';
|
|
});
|
|
};
|
|
var getCollapsedNode = function (rng) {
|
|
return rng.collapsed ? Option.from(getNode(rng.startContainer, rng.startOffset)).map(Element.fromDom) : Option.none();
|
|
};
|
|
var getFocusInElement = function (root, rng) {
|
|
return getCollapsedNode(rng).bind(function (node) {
|
|
if (isTableSection(node)) {
|
|
return Option.some(node);
|
|
} else if (contains$2(root, node) === false) {
|
|
return Option.some(root);
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
});
|
|
};
|
|
var normalizeSelection = function (editor, rng) {
|
|
getFocusInElement(Element.fromDom(editor.getBody()), rng).bind(function (elm) {
|
|
return CaretFinder.firstPositionIn(elm.dom());
|
|
}).fold(function () {
|
|
editor.selection.normalize();
|
|
return;
|
|
}, function (caretPos) {
|
|
return editor.selection.setRng(caretPos.toRange());
|
|
});
|
|
};
|
|
var focusBody = function (body) {
|
|
if (body.setActive) {
|
|
try {
|
|
body.setActive();
|
|
} catch (ex) {
|
|
body.focus();
|
|
}
|
|
} else {
|
|
body.focus();
|
|
}
|
|
};
|
|
var hasElementFocus = function (elm) {
|
|
return hasFocus(elm) || search(elm).isSome();
|
|
};
|
|
var hasIframeFocus = function (editor) {
|
|
return editor.iframeElement && hasFocus(Element.fromDom(editor.iframeElement));
|
|
};
|
|
var hasInlineFocus = function (editor) {
|
|
var rawBody = editor.getBody();
|
|
return rawBody && hasElementFocus(Element.fromDom(rawBody));
|
|
};
|
|
var hasUiFocus = function (editor) {
|
|
return active().filter(function (elem) {
|
|
return !FocusController.isEditorContentAreaElement(elem.dom()) && FocusController.isUIElement(editor, elem.dom());
|
|
}).isSome();
|
|
};
|
|
var hasFocus$1 = function (editor) {
|
|
return editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
|
|
};
|
|
var hasEditorOrUiFocus = function (editor) {
|
|
return hasFocus$1(editor) || hasUiFocus(editor);
|
|
};
|
|
var focusEditor = function (editor) {
|
|
var selection = editor.selection;
|
|
var body = editor.getBody();
|
|
var rng = selection.getRng();
|
|
editor.quirks.refreshContentEditable();
|
|
if (editor.bookmark !== undefined && hasFocus$1(editor) === false) {
|
|
SelectionBookmark.getRng(editor).each(function (bookmarkRng) {
|
|
editor.selection.setRng(bookmarkRng);
|
|
rng = bookmarkRng;
|
|
});
|
|
}
|
|
var contentEditableHost = getContentEditableHost(editor, selection.getNode());
|
|
if (editor.$.contains(body, contentEditableHost)) {
|
|
focusBody(contentEditableHost);
|
|
normalizeSelection(editor, rng);
|
|
activateEditor(editor);
|
|
return;
|
|
}
|
|
if (!editor.inline) {
|
|
if (!Env.opera) {
|
|
focusBody(body);
|
|
}
|
|
editor.getWin().focus();
|
|
}
|
|
if (Env.gecko || editor.inline) {
|
|
focusBody(body);
|
|
normalizeSelection(editor, rng);
|
|
}
|
|
activateEditor(editor);
|
|
};
|
|
var activateEditor = function (editor) {
|
|
return editor.editorManager.setActive(editor);
|
|
};
|
|
var focus = function (editor, skipFocus) {
|
|
if (editor.removed) {
|
|
return;
|
|
}
|
|
skipFocus ? activateEditor(editor) : focusEditor(editor);
|
|
};
|
|
var EditorFocus = {
|
|
focus: focus,
|
|
hasFocus: hasFocus$1,
|
|
hasEditorOrUiFocus: hasEditorOrUiFocus
|
|
};
|
|
|
|
var defaultFormat$1 = 'html';
|
|
var isTreeNode = function (content) {
|
|
return content instanceof Node$1;
|
|
};
|
|
var moveSelection = function (editor) {
|
|
if (EditorFocus.hasFocus(editor)) {
|
|
CaretFinder.firstPositionIn(editor.getBody()).each(function (pos) {
|
|
var node = pos.getNode();
|
|
var caretPos = NodeType.isTable(node) ? CaretFinder.firstPositionIn(node).getOr(pos) : pos;
|
|
editor.selection.setRng(caretPos.toRange());
|
|
});
|
|
}
|
|
};
|
|
var setEditorHtml = function (editor, html) {
|
|
editor.dom.setHTML(editor.getBody(), html);
|
|
moveSelection(editor);
|
|
};
|
|
var setContentString = function (editor, body, content, args) {
|
|
var forcedRootBlockName, padd;
|
|
if (content.length === 0 || /^\s+$/.test(content)) {
|
|
padd = '<br data-mce-bogus="1">';
|
|
if (body.nodeName === 'TABLE') {
|
|
content = '<tr><td>' + padd + '</td></tr>';
|
|
} else if (/^(UL|OL)$/.test(body.nodeName)) {
|
|
content = '<li>' + padd + '</li>';
|
|
}
|
|
forcedRootBlockName = Settings.getForcedRootBlock(editor);
|
|
if (forcedRootBlockName && editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
|
|
content = padd;
|
|
content = editor.dom.createHTML(forcedRootBlockName, editor.settings.forced_root_block_attrs, content);
|
|
} else if (!content) {
|
|
content = '<br data-mce-bogus="1">';
|
|
}
|
|
setEditorHtml(editor, content);
|
|
editor.fire('SetContent', args);
|
|
} else {
|
|
if (args.format !== 'raw') {
|
|
content = Serializer({ validate: editor.validate }, editor.schema).serialize(editor.parser.parse(content, {
|
|
isRootContent: true,
|
|
insert: true
|
|
}));
|
|
}
|
|
args.content = isWsPreserveElement(Element.fromDom(body)) ? content : Tools.trim(content);
|
|
setEditorHtml(editor, args.content);
|
|
if (!args.no_events) {
|
|
editor.fire('SetContent', args);
|
|
}
|
|
}
|
|
return args.content;
|
|
};
|
|
var setContentTree = function (editor, body, content, args) {
|
|
filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
|
|
var html = Serializer({ validate: editor.validate }, editor.schema).serialize(content);
|
|
args.content = isWsPreserveElement(Element.fromDom(body)) ? html : Tools.trim(html);
|
|
setEditorHtml(editor, args.content);
|
|
if (!args.no_events) {
|
|
editor.fire('SetContent', args);
|
|
}
|
|
return content;
|
|
};
|
|
var setContent = function (editor, content, args) {
|
|
if (args === void 0) {
|
|
args = {};
|
|
}
|
|
args.format = args.format ? args.format : defaultFormat$1;
|
|
args.set = true;
|
|
args.content = isTreeNode(content) ? '' : content;
|
|
if (!isTreeNode(content) && !args.no_events) {
|
|
editor.fire('BeforeSetContent', args);
|
|
content = args.content;
|
|
}
|
|
return Option.from(editor.getBody()).fold(constant(content), function (body) {
|
|
return isTreeNode(content) ? setContentTree(editor, body, content, args) : setContentString(editor, body, content, args);
|
|
});
|
|
};
|
|
|
|
var firePreProcess = function (editor, args) {
|
|
return editor.fire('PreProcess', args);
|
|
};
|
|
var firePostProcess = function (editor, args) {
|
|
return editor.fire('PostProcess', args);
|
|
};
|
|
var fireRemove = function (editor) {
|
|
return editor.fire('remove');
|
|
};
|
|
var fireDetach = function (editor) {
|
|
return editor.fire('detach');
|
|
};
|
|
var fireSwitchMode = function (editor, mode) {
|
|
return editor.fire('SwitchMode', { mode: mode });
|
|
};
|
|
var fireObjectResizeStart = function (editor, target, width, height) {
|
|
editor.fire('ObjectResizeStart', {
|
|
target: target,
|
|
width: width,
|
|
height: height
|
|
});
|
|
};
|
|
var fireObjectResized = function (editor, target, width, height) {
|
|
editor.fire('ObjectResized', {
|
|
target: target,
|
|
width: width,
|
|
height: height
|
|
});
|
|
};
|
|
var Events = {
|
|
firePreProcess: firePreProcess,
|
|
firePostProcess: firePostProcess,
|
|
fireRemove: fireRemove,
|
|
fireDetach: fireDetach,
|
|
fireSwitchMode: fireSwitchMode,
|
|
fireObjectResizeStart: fireObjectResizeStart,
|
|
fireObjectResized: fireObjectResized
|
|
};
|
|
|
|
var DOM$2 = DOMUtils$1.DOM;
|
|
var restoreOriginalStyles = function (editor) {
|
|
DOM$2.setStyle(editor.id, 'display', editor.orgDisplay);
|
|
};
|
|
var safeDestroy = function (x) {
|
|
return Option.from(x).each(function (x) {
|
|
return x.destroy();
|
|
});
|
|
};
|
|
var clearDomReferences = function (editor) {
|
|
editor.contentAreaContainer = editor.formElement = editor.container = editor.editorContainer = null;
|
|
editor.bodyElement = editor.contentDocument = editor.contentWindow = null;
|
|
editor.iframeElement = editor.targetElm = null;
|
|
if (editor.selection) {
|
|
editor.selection = editor.selection.win = editor.selection.dom = editor.selection.dom.doc = null;
|
|
}
|
|
};
|
|
var restoreForm = function (editor) {
|
|
var form = editor.formElement;
|
|
if (form) {
|
|
if (form._mceOldSubmit) {
|
|
form.submit = form._mceOldSubmit;
|
|
form._mceOldSubmit = null;
|
|
}
|
|
DOM$2.unbind(form, 'submit reset', editor.formEventDelegate);
|
|
}
|
|
};
|
|
var remove$6 = function (editor) {
|
|
if (!editor.removed) {
|
|
var _selectionOverrides = editor._selectionOverrides, editorUpload = editor.editorUpload;
|
|
var body = editor.getBody();
|
|
var element = editor.getElement();
|
|
if (body) {
|
|
editor.save({ is_removing: true });
|
|
}
|
|
editor.removed = true;
|
|
editor.unbindAllNativeEvents();
|
|
if (editor.hasHiddenInput && element) {
|
|
DOM$2.remove(element.nextSibling);
|
|
}
|
|
Events.fireRemove(editor);
|
|
editor.editorManager.remove(editor);
|
|
if (!editor.inline && body) {
|
|
restoreOriginalStyles(editor);
|
|
}
|
|
Events.fireDetach(editor);
|
|
DOM$2.remove(editor.getContainer());
|
|
safeDestroy(_selectionOverrides);
|
|
safeDestroy(editorUpload);
|
|
editor.destroy();
|
|
}
|
|
};
|
|
var destroy = function (editor, automatic) {
|
|
var selection = editor.selection, dom = editor.dom;
|
|
if (editor.destroyed) {
|
|
return;
|
|
}
|
|
if (!automatic && !editor.removed) {
|
|
editor.remove();
|
|
return;
|
|
}
|
|
if (!automatic) {
|
|
editor.editorManager.off('beforeunload', editor._beforeUnload);
|
|
if (editor.theme && editor.theme.destroy) {
|
|
editor.theme.destroy();
|
|
}
|
|
safeDestroy(selection);
|
|
safeDestroy(dom);
|
|
}
|
|
restoreForm(editor);
|
|
clearDomReferences(editor);
|
|
editor.destroyed = true;
|
|
};
|
|
|
|
var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
|
|
var shallow$1 = function (old, nu) {
|
|
return nu;
|
|
};
|
|
var deep$1 = function (old, nu) {
|
|
var bothObjects = isObject(old) && isObject(nu);
|
|
return bothObjects ? deepMerge(old, nu) : nu;
|
|
};
|
|
var baseMerge = function (merger) {
|
|
return function () {
|
|
var objects = new Array(arguments.length);
|
|
for (var i = 0; i < objects.length; i++) {
|
|
objects[i] = arguments[i];
|
|
}
|
|
if (objects.length === 0) {
|
|
throw new Error('Can\'t merge zero objects');
|
|
}
|
|
var ret = {};
|
|
for (var j = 0; j < objects.length; j++) {
|
|
var curObject = objects[j];
|
|
for (var key in curObject) {
|
|
if (hasOwnProperty$2.call(curObject, key)) {
|
|
ret[key] = merger(ret[key], curObject[key]);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
};
|
|
};
|
|
var deepMerge = baseMerge(deep$1);
|
|
var merge = baseMerge(shallow$1);
|
|
|
|
var sectionResult = Immutable('sections', 'settings');
|
|
var deviceDetection = detect$3().deviceType;
|
|
var isTouch = deviceDetection.isTouch();
|
|
var isPhone = deviceDetection.isPhone();
|
|
var isTablet = deviceDetection.isTablet();
|
|
var legacyMobilePlugins = [
|
|
'lists',
|
|
'autolink',
|
|
'autosave'
|
|
];
|
|
var defaultTouchSettings = {
|
|
table_grid: false,
|
|
object_resizing: false,
|
|
resize: false
|
|
};
|
|
var normalizePlugins = function (plugins) {
|
|
var pluginNames = isArray(plugins) ? plugins.join(' ') : plugins;
|
|
var trimmedPlugins = map(isString(pluginNames) ? pluginNames.split(' ') : [], trim);
|
|
return filter(trimmedPlugins, function (item) {
|
|
return item.length > 0;
|
|
});
|
|
};
|
|
var filterLegacyMobilePlugins = function (plugins) {
|
|
return filter(plugins, curry(contains, legacyMobilePlugins));
|
|
};
|
|
var extractSections = function (keys, settings) {
|
|
var result = bifilter(settings, function (value, key) {
|
|
return contains(keys, key);
|
|
});
|
|
return sectionResult(result.t, result.f);
|
|
};
|
|
var getSection = function (sectionResult, name, defaults) {
|
|
if (defaults === void 0) {
|
|
defaults = {};
|
|
}
|
|
var sections = sectionResult.sections();
|
|
var sectionSettings = sections.hasOwnProperty(name) ? sections[name] : {};
|
|
return Tools.extend({}, defaults, sectionSettings);
|
|
};
|
|
var hasSection = function (sectionResult, name) {
|
|
return sectionResult.sections().hasOwnProperty(name);
|
|
};
|
|
var isSectionTheme = function (sectionResult, name, theme) {
|
|
var section = sectionResult.sections();
|
|
return hasSection(sectionResult, name) && section[name].theme === theme;
|
|
};
|
|
var getSectionConfig = function (sectionResult, name) {
|
|
return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
|
|
};
|
|
var getDefaultSettings = function (id, documentBaseUrl, isTouch, editor) {
|
|
var baseDefaults = {
|
|
id: id,
|
|
theme: 'silver',
|
|
toolbar_drawer: 'floating',
|
|
plugins: '',
|
|
document_base_url: documentBaseUrl,
|
|
add_form_submit_trigger: true,
|
|
submit_patch: true,
|
|
add_unload_trigger: true,
|
|
convert_urls: true,
|
|
relative_urls: true,
|
|
remove_script_host: true,
|
|
object_resizing: true,
|
|
doctype: '<!DOCTYPE html>',
|
|
visual: true,
|
|
font_size_legacy_values: 'xx-small,small,medium,large,x-large,xx-large,300%',
|
|
forced_root_block: 'p',
|
|
hidden_input: true,
|
|
inline_styles: true,
|
|
convert_fonts_to_spans: true,
|
|
indent: true,
|
|
indent_before: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
|
|
indent_after: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
|
|
entity_encoding: 'named',
|
|
url_converter: editor.convertURL,
|
|
url_converter_scope: editor
|
|
};
|
|
return __assign(__assign({}, baseDefaults), isTouch ? defaultTouchSettings : {});
|
|
};
|
|
var getDefaultMobileSettings = function (isPhone) {
|
|
var defaultMobileSettings = {
|
|
resize: false,
|
|
toolbar_drawer: 'scrolling',
|
|
toolbar_sticky: false
|
|
};
|
|
var defaultPhoneSettings = { menubar: false };
|
|
return __assign(__assign(__assign({}, defaultTouchSettings), defaultMobileSettings), isPhone ? defaultPhoneSettings : {});
|
|
};
|
|
var getExternalPlugins = function (overrideSettings, settings) {
|
|
var userDefinedExternalPlugins = settings.external_plugins ? settings.external_plugins : {};
|
|
if (overrideSettings && overrideSettings.external_plugins) {
|
|
return Tools.extend({}, overrideSettings.external_plugins, userDefinedExternalPlugins);
|
|
} else {
|
|
return userDefinedExternalPlugins;
|
|
}
|
|
};
|
|
var combinePlugins = function (forcedPlugins, plugins) {
|
|
return [].concat(normalizePlugins(forcedPlugins)).concat(normalizePlugins(plugins));
|
|
};
|
|
var processPlugins = function (isMobileDevice, sectionResult, defaultOverrideSettings, settings) {
|
|
var forcedPlugins = normalizePlugins(defaultOverrideSettings.forced_plugins);
|
|
var desktopPlugins = normalizePlugins(settings.plugins);
|
|
var mobileConfig = getSectionConfig(sectionResult, 'mobile');
|
|
var mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
|
|
var platformPlugins = isMobileDevice && isSectionTheme(sectionResult, 'mobile', 'mobile') ? filterLegacyMobilePlugins(mobilePlugins) : isMobileDevice && hasSection(sectionResult, 'mobile') ? mobilePlugins : desktopPlugins;
|
|
var combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
|
|
return Tools.extend(settings, { plugins: combinedPlugins.join(' ') });
|
|
};
|
|
var isOnMobile = function (isMobileDevice, sectionResult) {
|
|
return isMobileDevice && hasSection(sectionResult, 'mobile');
|
|
};
|
|
var combineSettings = function (isMobileDevice, isPhone, defaultSettings, defaultOverrideSettings, settings) {
|
|
var defaultDeviceSettings = isMobileDevice ? { mobile: getDefaultMobileSettings(isPhone) } : {};
|
|
var sectionResult = extractSections(['mobile'], deepMerge(defaultDeviceSettings, settings));
|
|
var extendedSettings = Tools.extend(defaultSettings, defaultOverrideSettings, sectionResult.settings(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, {
|
|
validate: true,
|
|
external_plugins: getExternalPlugins(defaultOverrideSettings, sectionResult.settings())
|
|
});
|
|
return processPlugins(isMobileDevice, sectionResult, defaultOverrideSettings, extendedSettings);
|
|
};
|
|
var getEditorSettings = function (editor, id, documentBaseUrl, defaultOverrideSettings, settings) {
|
|
var defaultSettings = getDefaultSettings(id, documentBaseUrl, isTouch, editor);
|
|
return combineSettings(isPhone || isTablet, isPhone, defaultSettings, defaultOverrideSettings, settings);
|
|
};
|
|
var getFiltered = function (predicate, editor, name) {
|
|
return Option.from(editor.settings[name]).filter(predicate);
|
|
};
|
|
var getParamObject = function (value) {
|
|
var output = {};
|
|
if (typeof value === 'string') {
|
|
each(value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(','), function (val) {
|
|
var arr = val.split('=');
|
|
if (arr.length > 1) {
|
|
output[Tools.trim(arr[0])] = Tools.trim(arr[1]);
|
|
} else {
|
|
output[Tools.trim(arr[0])] = Tools.trim(arr[0]);
|
|
}
|
|
});
|
|
} else {
|
|
output = value;
|
|
}
|
|
return output;
|
|
};
|
|
var isArrayOf = function (p) {
|
|
return function (a) {
|
|
return isArray(a) && forall(a, p);
|
|
};
|
|
};
|
|
var getParam = function (editor, name, defaultVal, type) {
|
|
var value = name in editor.settings ? editor.settings[name] : defaultVal;
|
|
if (type === 'hash') {
|
|
return getParamObject(value);
|
|
} else if (type === 'string') {
|
|
return getFiltered(isString, editor, name).getOr(defaultVal);
|
|
} else if (type === 'number') {
|
|
return getFiltered(isNumber, editor, name).getOr(defaultVal);
|
|
} else if (type === 'boolean') {
|
|
return getFiltered(isBoolean, editor, name).getOr(defaultVal);
|
|
} else if (type === 'object') {
|
|
return getFiltered(isObject, editor, name).getOr(defaultVal);
|
|
} else if (type === 'array') {
|
|
return getFiltered(isArray, editor, name).getOr(defaultVal);
|
|
} else if (type === 'string[]') {
|
|
return getFiltered(isArrayOf(isString), editor, name).getOr(defaultVal);
|
|
} else if (type === 'function') {
|
|
return getFiltered(isFunction, editor, name).getOr(defaultVal);
|
|
} else {
|
|
return value;
|
|
}
|
|
};
|
|
|
|
var getProp = function (propName, elm) {
|
|
var rawElm = elm.dom();
|
|
return rawElm[propName];
|
|
};
|
|
var getComputedSizeProp = function (propName, elm) {
|
|
return parseInt(get$2(elm, propName), 10);
|
|
};
|
|
var getClientWidth = curry(getProp, 'clientWidth');
|
|
var getClientHeight = curry(getProp, 'clientHeight');
|
|
var getMarginTop = curry(getComputedSizeProp, 'margin-top');
|
|
var getMarginLeft = curry(getComputedSizeProp, 'margin-left');
|
|
var getBoundingClientRect$1 = function (elm) {
|
|
return elm.dom().getBoundingClientRect();
|
|
};
|
|
var isInsideElementContentArea = function (bodyElm, clientX, clientY) {
|
|
var clientWidth = getClientWidth(bodyElm);
|
|
var clientHeight = getClientHeight(bodyElm);
|
|
return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
|
|
};
|
|
var transpose = function (inline, elm, clientX, clientY) {
|
|
var clientRect = getBoundingClientRect$1(elm);
|
|
var deltaX = inline ? clientRect.left + elm.dom().clientLeft + getMarginLeft(elm) : 0;
|
|
var deltaY = inline ? clientRect.top + elm.dom().clientTop + getMarginTop(elm) : 0;
|
|
var x = clientX - deltaX;
|
|
var y = clientY - deltaY;
|
|
return {
|
|
x: x,
|
|
y: y
|
|
};
|
|
};
|
|
var isXYInContentArea = function (editor, clientX, clientY) {
|
|
var bodyElm = Element.fromDom(editor.getBody());
|
|
var targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
|
|
var transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
|
|
return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
|
|
};
|
|
var fromDomSafe = function (node) {
|
|
return Option.from(node).map(Element.fromDom);
|
|
};
|
|
var isEditorAttachedToDom = function (editor) {
|
|
var rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
|
|
return fromDomSafe(rawContainer).map(function (container) {
|
|
return contains$2(owner(container), container);
|
|
}).getOr(false);
|
|
};
|
|
var EditorView = {
|
|
isXYInContentArea: isXYInContentArea,
|
|
isEditorAttachedToDom: isEditorAttachedToDom
|
|
};
|
|
|
|
function NotificationManagerImpl() {
|
|
var unimplemented = function () {
|
|
throw new Error('Theme did not provide a NotificationManager implementation.');
|
|
};
|
|
return {
|
|
open: unimplemented,
|
|
close: unimplemented,
|
|
reposition: unimplemented,
|
|
getArgs: unimplemented
|
|
};
|
|
}
|
|
|
|
function NotificationManager(editor) {
|
|
var notifications = [];
|
|
var getImplementation = function () {
|
|
var theme = editor.theme;
|
|
return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
|
|
};
|
|
var getTopNotification = function () {
|
|
return Option.from(notifications[0]);
|
|
};
|
|
var isEqual = function (a, b) {
|
|
return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
|
|
};
|
|
var reposition = function () {
|
|
if (notifications.length > 0) {
|
|
getImplementation().reposition(notifications);
|
|
}
|
|
};
|
|
var addNotification = function (notification) {
|
|
notifications.push(notification);
|
|
};
|
|
var closeNotification = function (notification) {
|
|
findIndex(notifications, function (otherNotification) {
|
|
return otherNotification === notification;
|
|
}).each(function (index) {
|
|
notifications.splice(index, 1);
|
|
});
|
|
};
|
|
var open = function (spec) {
|
|
if (editor.removed || !EditorView.isEditorAttachedToDom(editor)) {
|
|
return;
|
|
}
|
|
return find(notifications, function (notification) {
|
|
return isEqual(getImplementation().getArgs(notification), spec);
|
|
}).getOrThunk(function () {
|
|
editor.editorManager.setActive(editor);
|
|
var notification = getImplementation().open(spec, function () {
|
|
closeNotification(notification);
|
|
reposition();
|
|
});
|
|
addNotification(notification);
|
|
reposition();
|
|
return notification;
|
|
});
|
|
};
|
|
var close = function () {
|
|
getTopNotification().each(function (notification) {
|
|
getImplementation().close(notification);
|
|
closeNotification(notification);
|
|
reposition();
|
|
});
|
|
};
|
|
var getNotifications = function () {
|
|
return notifications;
|
|
};
|
|
var registerEvents = function (editor) {
|
|
editor.on('SkinLoaded', function () {
|
|
var serviceMessage = editor.settings.service_message;
|
|
if (serviceMessage) {
|
|
open({
|
|
text: serviceMessage,
|
|
type: 'warning',
|
|
timeout: 0
|
|
});
|
|
}
|
|
});
|
|
editor.on('ResizeEditor ResizeWindow NodeChange', function () {
|
|
Delay.requestAnimationFrame(reposition);
|
|
});
|
|
editor.on('remove', function () {
|
|
each(notifications.slice(), function (notification) {
|
|
getImplementation().close(notification);
|
|
});
|
|
});
|
|
};
|
|
registerEvents(editor);
|
|
return {
|
|
open: open,
|
|
close: close,
|
|
getNotifications: getNotifications
|
|
};
|
|
}
|
|
|
|
function WindowManagerImpl () {
|
|
var unimplemented = function () {
|
|
throw new Error('Theme did not provide a WindowManager implementation.');
|
|
};
|
|
return {
|
|
open: unimplemented,
|
|
openUrl: unimplemented,
|
|
alert: unimplemented,
|
|
confirm: unimplemented,
|
|
close: unimplemented,
|
|
getParams: unimplemented,
|
|
setParams: unimplemented
|
|
};
|
|
}
|
|
|
|
var WindowManager = function (editor) {
|
|
var dialogs = [];
|
|
var getImplementation = function () {
|
|
var theme = editor.theme;
|
|
return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
|
|
};
|
|
var funcBind = function (scope, f) {
|
|
return function () {
|
|
return f ? f.apply(scope, arguments) : undefined;
|
|
};
|
|
};
|
|
var fireOpenEvent = function (dialog) {
|
|
editor.fire('OpenWindow', { dialog: dialog });
|
|
};
|
|
var fireCloseEvent = function (dialog) {
|
|
editor.fire('CloseWindow', { dialog: dialog });
|
|
};
|
|
var addDialog = function (dialog) {
|
|
dialogs.push(dialog);
|
|
fireOpenEvent(dialog);
|
|
};
|
|
var closeDialog = function (dialog) {
|
|
fireCloseEvent(dialog);
|
|
dialogs = filter(dialogs, function (otherDialog) {
|
|
return otherDialog !== dialog;
|
|
});
|
|
if (dialogs.length === 0) {
|
|
editor.focus();
|
|
}
|
|
};
|
|
var getTopDialog = function () {
|
|
return Option.from(dialogs[dialogs.length - 1]);
|
|
};
|
|
var storeSelectionAndOpenDialog = function (openDialog) {
|
|
editor.editorManager.setActive(editor);
|
|
SelectionBookmark.store(editor);
|
|
var dialog = openDialog();
|
|
addDialog(dialog);
|
|
return dialog;
|
|
};
|
|
var open = function (args, params) {
|
|
return storeSelectionAndOpenDialog(function () {
|
|
return getImplementation().open(args, params, closeDialog);
|
|
});
|
|
};
|
|
var openUrl = function (args) {
|
|
return storeSelectionAndOpenDialog(function () {
|
|
return getImplementation().openUrl(args, closeDialog);
|
|
});
|
|
};
|
|
var alert = function (message, callback, scope) {
|
|
getImplementation().alert(message, funcBind(scope ? scope : this, callback));
|
|
};
|
|
var confirm = function (message, callback, scope) {
|
|
getImplementation().confirm(message, funcBind(scope ? scope : this, callback));
|
|
};
|
|
var close = function () {
|
|
getTopDialog().each(function (dialog) {
|
|
getImplementation().close(dialog);
|
|
closeDialog(dialog);
|
|
});
|
|
};
|
|
editor.on('remove', function () {
|
|
each(dialogs, function (dialog) {
|
|
getImplementation().close(dialog);
|
|
});
|
|
});
|
|
return {
|
|
open: open,
|
|
openUrl: openUrl,
|
|
alert: alert,
|
|
confirm: confirm,
|
|
close: close
|
|
};
|
|
};
|
|
|
|
var displayNotification = function (editor, message) {
|
|
editor.notificationManager.open({
|
|
type: 'error',
|
|
text: message
|
|
});
|
|
};
|
|
var displayError = function (editor, message) {
|
|
if (editor._skinLoaded) {
|
|
displayNotification(editor, message);
|
|
} else {
|
|
editor.on('SkinLoaded', function () {
|
|
displayNotification(editor, message);
|
|
});
|
|
}
|
|
};
|
|
var uploadError = function (editor, message) {
|
|
displayError(editor, I18n.translate([
|
|
'Failed to upload image: {0}',
|
|
message
|
|
]));
|
|
};
|
|
var logError = function (msg) {
|
|
domGlobals.console.error(msg);
|
|
};
|
|
var createLoadError = function (type, url, name) {
|
|
return name ? 'Failed to load ' + type + ': ' + name + ' from url ' + url : 'Failed to load ' + type + ' url: ' + url;
|
|
};
|
|
var pluginLoadError = function (url, name) {
|
|
logError(createLoadError('plugin', url, name));
|
|
};
|
|
var iconsLoadError = function (url, name) {
|
|
logError(createLoadError('icons', url, name));
|
|
};
|
|
var languageLoadError = function (url, name) {
|
|
logError(createLoadError('language', url, name));
|
|
};
|
|
var pluginInitError = function (editor, name, err) {
|
|
var message = I18n.translate([
|
|
'Failed to initialize plugin: {0}',
|
|
name
|
|
]);
|
|
initError(message, err);
|
|
displayError(editor, message);
|
|
};
|
|
var initError = function (message) {
|
|
var x = [];
|
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
x[_i - 1] = arguments[_i];
|
|
}
|
|
var console = domGlobals.window.console;
|
|
if (console) {
|
|
if (console.error) {
|
|
console.error.apply(console, arguments);
|
|
} else {
|
|
console.log.apply(console, arguments);
|
|
}
|
|
}
|
|
};
|
|
var ErrorReporter = {
|
|
pluginLoadError: pluginLoadError,
|
|
iconsLoadError: iconsLoadError,
|
|
languageLoadError: languageLoadError,
|
|
pluginInitError: pluginInitError,
|
|
uploadError: uploadError,
|
|
displayError: displayError,
|
|
initError: initError
|
|
};
|
|
|
|
var getAll = function () {
|
|
return {
|
|
'accessibility-check': '<svg width="24" height="24"><path d="M12 2a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2c0-1.1.9-2 2-2zm8 7h-5v12c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5c0-.6-.4-1-1-1a1 1 0 0 0-1 1v5c0 .6-.4 1-1 1a1 1 0 0 1-1-1V9H4a1 1 0 1 1 0-2h16c.6 0 1 .4 1 1s-.4 1-1 1z" fill-rule="nonzero"/></svg>',
|
|
'action-next': '<svg width="24" height="24"><path fill-rule="nonzero" d="M5.7 7.3a1 1 0 0 0-1.4 1.4l7.7 7.7 7.7-7.7a1 1 0 1 0-1.4-1.4L12 13.6 5.7 7.3z"/></svg>',
|
|
'action-prev': '<svg width="24" height="24"><path fill-rule="nonzero" d="M18.3 15.7a1 1 0 0 0 1.4-1.4L12 6.6l-7.7 7.7a1 1 0 0 0 1.4 1.4L12 9.4l6.3 6.3z"/></svg>',
|
|
'align-center': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm3 4h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2zm-3-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"/></svg>',
|
|
'align-justify': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"/></svg>',
|
|
'align-left': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm0 4h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"/></svg>',
|
|
'align-none': '<svg width="24" height="24"><path d="M14.2 5L13 7H5a1 1 0 1 1 0-2h9.2zm4 0h.8a1 1 0 0 1 0 2h-2l1.2-2zm-6.4 4l-1.2 2H5a1 1 0 0 1 0-2h6.8zm4 0H19a1 1 0 0 1 0 2h-4.4l1.2-2zm-6.4 4l-1.2 2H5a1 1 0 0 1 0-2h4.4zm4 0H19a1 1 0 0 1 0 2h-6.8l1.2-2zM7 17l-1.2 2H5a1 1 0 0 1 0-2h2zm4 0h8a1 1 0 0 1 0 2H9.8l1.2-2zm5.2-13.5l1.3.7-9.7 16.3-1.3-.7 9.7-16.3z" fill-rule="evenodd"/></svg>',
|
|
'align-right': '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm6 4h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm-6-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2z" fill-rule="evenodd"/></svg>',
|
|
'arrow-left': '<svg width="24" height="24"><path d="M5.6 13l12 6a1 1 0 0 0 1.4-1V6a1 1 0 0 0-1.4-.9l-12 6a1 1 0 0 0 0 1.8z" fill-rule="evenodd"/></svg>',
|
|
'arrow-right': '<svg width="24" height="24"><path d="M18.5 13l-12 6A1 1 0 0 1 5 18V6a1 1 0 0 1 1.4-.9l12 6a1 1 0 0 1 0 1.8z" fill-rule="evenodd"/></svg>',
|
|
'bold': '<svg width="24" height="24"><path d="M7.8 19c-.3 0-.5 0-.6-.2l-.2-.5V5.7c0-.2 0-.4.2-.5l.6-.2h5c1.5 0 2.7.3 3.5 1 .7.6 1.1 1.4 1.1 2.5a3 3 0 0 1-.6 1.9c-.4.6-1 1-1.6 1.2.4.1.9.3 1.3.6s.8.7 1 1.2c.4.4.5 1 .5 1.6 0 1.3-.4 2.3-1.3 3-.8.7-2.1 1-3.8 1H7.8zm5-8.3c.6 0 1.2-.1 1.6-.5.4-.3.6-.7.6-1.3 0-1.1-.8-1.7-2.3-1.7H9.3v3.5h3.4zm.5 6c.7 0 1.3-.1 1.7-.4.4-.4.6-.9.6-1.5s-.2-1-.7-1.4c-.4-.3-1-.4-2-.4H9.4v3.8h4z" fill-rule="evenodd"/></svg>',
|
|
'bookmark': '<svg width="24" height="24"><path d="M6 4v17l6-4 6 4V4c0-.6-.4-1-1-1H7a1 1 0 0 0-1 1z" fill-rule="nonzero"/></svg>',
|
|
'border-width': '<svg width="24" height="24"><path d="M5 14.8h14a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm-.5 3.7h15c.3 0 .5.2.5.5s-.2.5-.5.5h-15a.5.5 0 1 1 0-1zm.5-8.3h14c.6 0 1 .4 1 1v1c0 .5-.4 1-1 1H5a1 1 0 0 1-1-1v-1c0-.6.4-1 1-1zm0-5.7h14c.6 0 1 .4 1 1v2c0 .6-.4 1-1 1H5a1 1 0 0 1-1-1v-2c0-.6.4-1 1-1z" fill-rule="evenodd"/></svg>',
|
|
'brightness': '<svg width="24" height="24"><path d="M12 17c.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7v-1c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3zm0-10a1 1 0 0 1-.7-.3A1 1 0 0 1 11 6V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3zm7 4c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-1a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1zM7 12c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H5a1 1 0 0 1-.7-.3A1 1 0 0 1 4 12c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1c.3 0 .5.1.7.3.2.2.3.4.3.7zm10 3.5l.7.8c.2.1.3.4.3.6 0 .3-.1.6-.3.8a1 1 0 0 1-.8.3 1 1 0 0 1-.6-.3l-.8-.7a1 1 0 0 1-.3-.8c0-.2.1-.5.3-.7a1 1 0 0 1 1.4 0zm-10-7l-.7-.8a1 1 0 0 1-.3-.6c0-.3.1-.6.3-.8.2-.2.5-.3.8-.3.2 0 .5.1.7.3l.7.7c.2.2.3.5.3.8 0 .2-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.8-.3zm10 0a1 1 0 0 1-.8.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.6.3-.8l.8-.7c.1-.2.4-.3.6-.3.3 0 .6.1.8.3.2.2.3.5.3.8 0 .2-.1.5-.3.7l-.7.7zm-10 7c.2-.2.5-.3.8-.3.2 0 .5.1.7.3a1 1 0 0 1 0 1.4l-.8.8a1 1 0 0 1-.6.3 1 1 0 0 1-.8-.3 1 1 0 0 1-.3-.8c0-.2.1-.5.3-.6l.7-.8zM12 8a4 4 0 0 1 3.7 2.4 4 4 0 0 1 0 3.2A4 4 0 0 1 12 16a4 4 0 0 1-3.7-2.4 4 4 0 0 1 0-3.2A4 4 0 0 1 12 8zm0 6.5c.7 0 1.3-.2 1.8-.7.5-.5.7-1.1.7-1.8s-.2-1.3-.7-1.8c-.5-.5-1.1-.7-1.8-.7s-1.3.2-1.8.7c-.5.5-.7 1.1-.7 1.8s.2 1.3.7 1.8c.5.5 1.1.7 1.8.7z" fill-rule="evenodd"/></svg>',
|
|
'browse': '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-4v-2h4V8H5v10h4v2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14zm-8 9.4l-2.3 2.3a1 1 0 1 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 0 1-1.4 1.4L13 13.4V20a1 1 0 0 1-2 0v-6.6z" fill-rule="nonzero"/></svg>',
|
|
'cancel': '<svg width="24" height="24"><path d="M12 4.6a7.4 7.4 0 1 1 0 14.8 7.4 7.4 0 0 1 0-14.8zM12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zm0 8L14.8 8l1 1.1-2.7 2.8 2.7 2.7-1.1 1.1-2.7-2.7-2.7 2.7-1-1.1 2.6-2.7-2.7-2.7 1-1.1 2.8 2.7z" fill-rule="nonzero"/></svg>',
|
|
'change-case': '<svg width="24" height="24"><path d="M18.4 18.2v-.6c-.5.8-1.3 1.2-2.4 1.2-2.2 0-3.3-1.6-3.3-4.8 0-3.1 1-4.7 3.3-4.7 1.1 0 1.8.3 2.4 1.1v-.6c0-.5.4-.8.8-.8s.8.3.8.8v8.4c0 .5-.4.8-.8.8a.8.8 0 0 1-.8-.8zm-2-7.4c-1.3 0-1.8.9-1.8 3.2 0 2.4.5 3.3 1.7 3.3 1.3 0 1.8-.9 1.8-3.2 0-2.4-.5-3.3-1.7-3.3zM10 15.7H5.5l-.8 2.6a1 1 0 0 1-1 .7h-.2a.7.7 0 0 1-.7-1l4-12a1 1 0 1 1 2 0l4 12a.7.7 0 0 1-.8 1h-.2a1 1 0 0 1-1-.7l-.8-2.6zm-.3-1.5l-2-6.5-1.9 6.5h3.9z" fill-rule="evenodd"/></svg>',
|
|
'character-count': '<svg width="24" height="24"><path d="M4 11.5h16v1H4v-1zm4.8-6.8V10H7.7V5.8h-1v-1h2zM11 8.3V9h2v1h-3V7.7l2-1v-.9h-2v-1h3v2.4l-2 1zm6.3-3.4V10h-3.1V9h2.1V8h-2.1V6.8h2.1v-1h-2.1v-1h3.1zM5.8 16.4c0-.5.2-.8.5-1 .2-.2.6-.3 1.2-.3l.8.1c.2 0 .4.2.5.3l.4.4v2.8l.2.3H8.2v-.1-.2l-.6.3H7c-.4 0-.7 0-1-.2a1 1 0 0 1-.3-.9c0-.3 0-.6.3-.8.3-.2.7-.4 1.2-.4l.6-.2h.3v-.2l-.1-.2a.8.8 0 0 0-.5-.1 1 1 0 0 0-.4 0l-.3.4h-1zm2.3.8h-.2l-.2.1-.4.1a1 1 0 0 0-.4.2l-.2.2.1.3.5.1h.4l.4-.4v-.6zm2-3.4h1.2v1.7l.5-.3h.5c.5 0 .9.1 1.2.5.3.4.5.8.5 1.4 0 .6-.2 1.1-.5 1.5-.3.4-.7.6-1.3.6l-.6-.1-.4-.4v.4h-1.1v-5.4zm1.1 3.3c0 .3 0 .6.2.8a.7.7 0 0 0 1.2 0l.2-.8c0-.4 0-.6-.2-.8a.7.7 0 0 0-.6-.3l-.6.3-.2.8zm6.1-.5c0-.2 0-.3-.2-.4a.8.8 0 0 0-.5-.2c-.3 0-.5.1-.6.3l-.2.9c0 .3 0 .6.2.8.1.2.3.3.6.3.2 0 .4 0 .5-.2l.2-.4h1.1c0 .5-.3.8-.6 1.1a2 2 0 0 1-1.3.4c-.5 0-1-.2-1.3-.6a2 2 0 0 1-.5-1.4c0-.6.1-1.1.5-1.5.3-.4.8-.5 1.4-.5.5 0 1 0 1.2.3.4.3.5.7.5 1.2h-1v-.1z" fill-rule="evenodd"/></svg>',
|
|
'checklist-rtl': '<svg width="24" height="24"><path d="M5 17h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm14.2 11c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 8c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8z" fill-rule="evenodd"/></svg>',
|
|
'checklist': '<svg width="24" height="24"><path d="M11 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0-6h8a1 1 0 0 1 0 2h-8a1 1 0 0 1 0-2zM7.2 16c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 8c-.2.3-.7.4-1 0L3.8 6.9a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8z" fill-rule="evenodd"/></svg>',
|
|
'checkmark': '<svg width="24" height="24"><path d="M18.2 5.4a1 1 0 0 1 1.6 1.2l-8 12a1 1 0 0 1-1.5.1l-5-5a1 1 0 1 1 1.4-1.4l4.1 4.1 7.4-11z" fill-rule="nonzero"/></svg>',
|
|
'chevron-down': '<svg width="10" height="10"><path d="M8.7 2.2c.3-.3.8-.3 1 0 .4.4.4.9 0 1.2L5.7 7.8c-.3.3-.9.3-1.2 0L.2 3.4a.8.8 0 0 1 0-1.2c.3-.3.8-.3 1.1 0L5 6l3.7-3.8z" fill-rule="nonzero"/></svg>',
|
|
'chevron-left': '<svg width="10" height="10"><path d="M7.8 1.3L4 5l3.8 3.7c.3.3.3.8 0 1-.4.4-.9.4-1.2 0L2.2 5.7a.8.8 0 0 1 0-1.2L6.6.2C7 0 7.4 0 7.8.2c.3.3.3.8 0 1.1z" fill-rule="nonzero"/></svg>',
|
|
'chevron-right': '<svg width="10" height="10"><path d="M2.2 1.3a.8.8 0 0 1 0-1c.4-.4.9-.4 1.2 0l4.4 4.1c.3.4.3.9 0 1.2L3.4 9.8c-.3.3-.8.3-1.2 0a.8.8 0 0 1 0-1.1L6 5 2.2 1.3z" fill-rule="nonzero"/></svg>',
|
|
'chevron-up': '<svg width="10" height="10"><path d="M8.7 7.8L5 4 1.3 7.8c-.3.3-.8.3-1 0a.8.8 0 0 1 0-1.2l4.1-4.4c.3-.3.9-.3 1.2 0l4.2 4.4c.3.3.3.9 0 1.2-.3.3-.8.3-1.1 0z" fill-rule="nonzero"/></svg>',
|
|
'close': '<svg width="24" height="24"><path d="M17.3 8.2L13.4 12l3.9 3.8a1 1 0 0 1-1.5 1.5L12 13.4l-3.8 3.9a1 1 0 0 1-1.5-1.5l3.9-3.8-3.9-3.8a1 1 0 0 1 1.5-1.5l3.8 3.9 3.8-3.9a1 1 0 0 1 1.5 1.5z" fill-rule="evenodd"/></svg>',
|
|
'code-sample': '<svg width="24" height="26"><path d="M7.1 11a2.8 2.8 0 0 1-.8 2 2.8 2.8 0 0 1 .8 2v1.7c0 .3.1.6.4.8.2.3.5.4.8.4.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.7 0-1.4-.3-2-.8-.5-.6-.8-1.3-.8-2V15c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4v-.8c0-.2.2-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V9.3c0-.7.3-1.4.8-2 .6-.5 1.3-.8 2-.8.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8V11zm9.8 0V9.3c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4V7c0-.2.1-.4.4-.4.7 0 1.4.3 2 .8.5.6.8 1.3.8 2V11c0 .3.1.6.4.8.2.3.5.4.8.4.2 0 .4.2.4.4v.8c0 .2-.2.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8v1.7c0 .7-.3 1.4-.8 2-.6.5-1.3.8-2 .8a.4.4 0 0 1-.4-.4v-.8c0-.2.1-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V15a2.8 2.8 0 0 1 .8-2 2.8 2.8 0 0 1-.8-2zm-3.3-.4c0 .4-.1.8-.5 1.1-.3.3-.7.5-1.1.5-.4 0-.8-.2-1.1-.5-.4-.3-.5-.7-.5-1.1 0-.5.1-.9.5-1.2.3-.3.7-.4 1.1-.4.4 0 .8.1 1.1.4.4.3.5.7.5 1.2zM12 13c.4 0 .8.1 1.1.5.4.3.5.7.5 1.1 0 1-.1 1.6-.5 2a3 3 0 0 1-1.1 1c-.4.3-.8.4-1.1.4a.5.5 0 0 1-.5-.5V17a3 3 0 0 0 1-.2l.6-.6c-.6 0-1-.2-1.3-.5-.2-.3-.3-.7-.3-1 0-.5.1-1 .5-1.2.3-.4.7-.5 1.1-.5z" fill-rule="evenodd"/></svg>',
|
|
'color-levels': '<svg width="24" height="24"><path d="M17.5 11.4A9 9 0 0 1 18 14c0 .5 0 1-.2 1.4 0 .4-.3.9-.5 1.3a6.2 6.2 0 0 1-3.7 3 5.7 5.7 0 0 1-3.2 0A5.9 5.9 0 0 1 7.6 18a6.2 6.2 0 0 1-1.4-2.6 6.7 6.7 0 0 1 0-2.8c0-.4.1-.9.3-1.3a13.6 13.6 0 0 1 2.3-4A20 20 0 0 1 12 4a26.4 26.4 0 0 1 3.2 3.4 18.2 18.2 0 0 1 2.3 4zm-2 4.5c.4-.7.5-1.4.5-2a7.3 7.3 0 0 0-1-3.2c.2.6.2 1.2.2 1.9a4.5 4.5 0 0 1-1.3 3 5.3 5.3 0 0 1-2.3 1.5 4.9 4.9 0 0 1-2 .1 4.3 4.3 0 0 0 2.4.8 4 4 0 0 0 2-.6 4 4 0 0 0 1.5-1.5z" fill-rule="evenodd"/></svg>',
|
|
'color-picker': '<svg width="24" height="24"><path d="M12 3a9 9 0 0 0 0 18 1.5 1.5 0 0 0 1.1-2.5c-.2-.3-.4-.6-.4-1 0-.8.7-1.5 1.5-1.5H16a5 5 0 0 0 5-5c0-4.4-4-8-9-8zm-5.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm3-4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm3 4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z" fill-rule="nonzero"/></svg>',
|
|
'color-swatch-remove-color': '<svg width="24" height="24"><path stroke="#000" stroke-width="2" d="M21 3L3 21" fill-rule="evenodd"/></svg>',
|
|
'color-swatch': '<svg width="24" height="24"><rect x="3" y="3" width="18" height="18" rx="1" fill-rule="evenodd"/></svg>',
|
|
'comment-add': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M9 19l3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23z"/><path d="M13 10h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H9a1 1 0 0 1 0-2h2V8a1 1 0 0 1 2 0v2z"/></g></svg>',
|
|
'comment': '<svg width="24" height="24"><path fill-rule="nonzero" d="M9 19l3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23z"/></svg>',
|
|
'contrast': '<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4zm-6 8a6 6 0 0 0 6 6V6a6 6 0 0 0-6 6z" fill-rule="evenodd"/></svg>',
|
|
'copy': '<svg width="24" height="24"><path d="M16 3H6a2 2 0 0 0-2 2v11h2V5h10V3zm1 4a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7zm0 12V9h-7v10h7z" fill-rule="nonzero"/></svg>',
|
|
'crop': '<svg width="24" height="24"><path d="M17 8v7h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v2c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-2H7V9H5a1 1 0 1 1 0-2h2V5c0-.6.4-1 1-1s1 .4 1 1v2h7l3-3 1 1-3 3zM9 9v5l5-5H9zm1 6h5v-5l-5 5z" fill-rule="evenodd"/></svg>',
|
|
'cut': '<svg width="24" height="24"><path d="M18 15c.6.7 1 1.4 1 2.3 0 .8-.2 1.5-.7 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l6 6 6-6 .5 1a3.3 3.3 0 0 1 0 2c0 .4-.3.7-.5 1l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8zm-8.5 2.2l.1-.4v-.3-.4a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2 1.6 1.6 0 0 0-.8 0 2.6 2.6 0 0 0-.8.3 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3 2.8 2.8 0 0 0 1-1zm2.5-2.8c.4 0 .7-.1 1-.4.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4zm5.4 4l.2-.5v-.4-.3a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3 1.5 1.5 0 0 0-.8 0 1 1 0 0 0-.4.2 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4l.3.4.3.4a2.8 2.8 0 0 0 .8.5l.4.1h.7l.5-.2z" fill-rule="evenodd"/></svg>',
|
|
'document-properties': '<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3zM17 19H7V5h6v4h4v10z" fill-rule="nonzero"/></svg>',
|
|
'drag': '<svg width="24" height="24"><path d="M13 5h2v2h-2V5zm0 4h2v2h-2V9zM9 9h2v2H9V9zm4 4h2v2h-2v-2zm-4 0h2v2H9v-2zm0 4h2v2H9v-2zm4 0h2v2h-2v-2zM9 5h2v2H9V5z" fill-rule="evenodd"/></svg>',
|
|
'duplicate': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M16 3v2H6v11H4V5c0-1.1.9-2 2-2h10zm3 8h-2V9h-7v10h9a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7a2 2 0 0 1 2 2v2z"/><path d="M17 14h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1h-1a1 1 0 0 1 0-2h1v-1a1 1 0 0 1 2 0v1z"/></g></svg>',
|
|
'edit-block': '<svg width="24" height="24"><path fill-rule="nonzero" d="M19.8 8.8l-9.4 9.4c-.2.2-.5.4-.9.4l-5.4 1.2 1.2-5.4.5-.8 9.4-9.4c.7-.7 1.8-.7 2.5 0l2.1 2.1c.7.7.7 1.8 0 2.5zm-2-.2l1-.9v-.3l-2.2-2.2a.3.3 0 0 0-.3 0l-1 1L18 8.5zm-1 1l-2.5-2.4-6 6 2.5 2.5 6-6zm-7 7.1l-2.6-2.4-.3.3-.1.2-.7 3 3.1-.6h.1l.4-.5z"/></svg>',
|
|
'edit-image': '<svg width="24" height="24"><path d="M18 16h2V7a2 2 0 0 0-2-2H7v2h11v9zM6 17h15a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1H6a2 2 0 0 1-2-2V7H3a1 1 0 1 1 0-2h1V4a1 1 0 1 1 2 0v13zm3-5.3l1.3 2 3-4.7 3.7 6H7l2-3.3z" fill-rule="nonzero"/></svg>',
|
|
'embed-page': '<svg width="24" height="24"><path d="M19 6V5H5v14h2A13 13 0 0 1 19 6zm0 1.4c-.8.8-1.6 2.4-2.2 4.6H19V7.4zm0 5.6h-2.4c-.4 1.8-.6 3.8-.6 6h3v-6zm-4 6c0-2.2.2-4.2.6-6H13c-.7 1.8-1.1 3.8-1.1 6h3zm-4 0c0-2.2.4-4.2 1-6H9.6A12 12 0 0 0 8 19h3zM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1zm11.8 9c.4-1.9 1-3.4 1.8-4.5a9.2 9.2 0 0 0-4 4.5h2.2zm-3.4 0a12 12 0 0 1 2.8-4 12 12 0 0 0-5 4h2.2z" fill-rule="nonzero"/></svg>',
|
|
'embed': '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1zm1 2v14h14V5H5zm4.8 2.6l5.6 4a.5.5 0 0 1 0 .8l-5.6 4A.5.5 0 0 1 9 16V8a.5.5 0 0 1 .8-.4z" fill-rule="nonzero"/></svg>',
|
|
'emoji': '<svg width="24" height="24"><path d="M9 11c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1zm6 0c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1zm-3 5.5c2.1 0 4-1.5 4.4-3.5H7.6c.5 2 2.3 3.5 4.4 3.5zM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16zm0 14.5a6.5 6.5 0 1 1 0-13 6.5 6.5 0 0 1 0 13z" fill-rule="nonzero"/></svg>',
|
|
'fill': '<svg width="24" height="26"><path d="M16.6 12l-9-9-1.4 1.4 2.4 2.4-5.2 5.1c-.5.6-.5 1.6 0 2.2L9 19.6a1.5 1.5 0 0 0 2.2 0l5.5-5.5c.5-.6.5-1.6 0-2.2zM5.2 13L10 8.2l4.8 4.8H5.2zM19 14.5s-2 2.2-2 3.5c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.3-2-3.5-2-3.5z" fill-rule="nonzero"/></svg>',
|
|
'flip-horizontally': '<svg width="24" height="24"><path d="M14 19h2v-2h-2v2zm4-8h2V9h-2v2zM4 7v10c0 1.1.9 2 2 2h3v-2H6V7h3V5H6a2 2 0 0 0-2 2zm14-2v2h2a2 2 0 0 0-2-2zm-7 16h2V3h-2v18zm7-6h2v-2h-2v2zm-4-8h2V5h-2v2zm4 12a2 2 0 0 0 2-2h-2v2z" fill-rule="nonzero"/></svg>',
|
|
'flip-vertically': '<svg width="24" height="24"><path d="M5 14v2h2v-2H5zm8 4v2h2v-2h-2zm4-14H7a2 2 0 0 0-2 2v3h2V6h10v3h2V6a2 2 0 0 0-2-2zm2 14h-2v2a2 2 0 0 0 2-2zM3 11v2h18v-2H3zm6 7v2h2v-2H9zm8-4v2h2v-2h-2zM5 18c0 1.1.9 2 2 2v-2H5z" fill-rule="nonzero"/></svg>',
|
|
'format-painter': '<svg width="24" height="24"><path d="M18 5V4c0-.5-.4-1-1-1H5a1 1 0 0 0-1 1v4c0 .6.5 1 1 1h12c.6 0 1-.4 1-1V7h1v4H9v9c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-7h8V5h-3z" fill-rule="nonzero"/></svg>',
|
|
'fullscreen': '<svg width="24" height="24"><path d="M15.3 10l-1.2-1.3 2.9-3h-2.3a.9.9 0 1 1 0-1.7H19c.5 0 .9.4.9.9v4.4a.9.9 0 1 1-1.8 0V7l-2.9 3zm0 4l3 3v-2.3a.9.9 0 1 1 1.7 0V19c0 .5-.4.9-.9.9h-4.4a.9.9 0 1 1 0-1.8H17l-3-2.9 1.3-1.2zM10 15.4l-2.9 3h2.3a.9.9 0 1 1 0 1.7H5a.9.9 0 0 1-.9-.9v-4.4a.9.9 0 1 1 1.8 0V17l2.9-3 1.2 1.3zM8.7 10L5.7 7v2.3a.9.9 0 0 1-1.7 0V5c0-.5.4-.9.9-.9h4.4a.9.9 0 0 1 0 1.8H7l3 2.9-1.3 1.2z" fill-rule="nonzero"/></svg>',
|
|
'gallery': '<svg width="24" height="24"><path fill-rule="nonzero" d="M5 15.7l2.3-2.2c.3-.3.7-.3 1 0L11 16l5.1-5c.3-.4.8-.4 1 0l2 1.9V8H5v7.7zM5 18V19h3l1.8-1.9-2-2L5 17.9zm14-3l-2.5-2.4-6.4 6.5H19v-4zM4 6h16c.6 0 1 .4 1 1v13c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V7c0-.6.4-1 1-1zm6 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM4.5 4h15a.5.5 0 1 1 0 1h-15a.5.5 0 0 1 0-1zm2-2h11a.5.5 0 1 1 0 1h-11a.5.5 0 0 1 0-1z"/></svg>',
|
|
'gamma': '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1zm1 2v14h14V5H5zm6.5 11.8V14L9.2 8.7a5.1 5.1 0 0 0-.4-.8l-.1-.2H8 8v-1l.3-.1.3-.1h.7a1 1 0 0 1 .6.5l.1.3a8.5 8.5 0 0 1 .3.6l1.9 4.6 2-5.2a1 1 0 0 1 1-.6.5.5 0 0 1 .5.6L13 14v2.8a.7.7 0 0 1-1.4 0z" fill-rule="nonzero"/></svg>',
|
|
'help': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M12 5.5a6.5 6.5 0 0 0-6 9 6.3 6.3 0 0 0 1.4 2l1 1a6.3 6.3 0 0 0 3.6 1 6.5 6.5 0 0 0 6-9 6.3 6.3 0 0 0-1.4-2l-1-1a6.3 6.3 0 0 0-3.6-1zM12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4z"/><path d="M9.6 9.7a.7.7 0 0 1-.7-.8c0-1.1 1.5-1.8 3.2-1.8 1.8 0 3.2.8 3.2 2.4 0 1.4-.4 2.1-1.5 2.8-.2 0-.3.1-.3.2a2 2 0 0 0-.8.8.8.8 0 0 1-1.4-.6c.3-.7.8-1 1.3-1.5l.4-.2c.7-.4.8-.6.8-1.5 0-.5-.6-.9-1.7-.9-.5 0-1 .1-1.4.3-.2 0-.3.1-.3.2v-.2c0 .4-.4.8-.8.8z" fill-rule="nonzero"/><circle cx="12" cy="16" r="1"/></g></svg>',
|
|
'highlight-bg-color': '<svg width="24" height="24"><g fill-rule="evenodd"><path id="tox-icon-highlight-bg-color__color" d="M3 18h18v3H3z"/><path fill-rule="nonzero" d="M7.7 16.7H3l3.3-3.3-.7-.8L10.2 8l4 4.1-4 4.2c-.2.2-.6.2-.8 0l-.6-.7-1.1 1.1zm5-7.5L11 7.4l3-2.9a2 2 0 0 1 2.6 0L18 6c.7.7.7 2 0 2.7l-2.9 2.9-1.8-1.8-.5-.6"/></g></svg>',
|
|
'home': '<svg width="24" height="24"><path fill-rule="nonzero" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>',
|
|
'horizontal-rule': '<svg width="24" height="24"><path d="M4 11h16v2H4z" fill-rule="evenodd"/></svg>',
|
|
'image-options': '<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" fill-rule="nonzero"/></svg>',
|
|
'image': '<svg width="24" height="24"><path d="M5 15.7l3.3-3.2c.3-.3.7-.3 1 0L12 15l4.1-4c.3-.4.8-.4 1 0l2 1.9V5H5v10.7zM5 18V19h3l2.8-2.9-2-2L5 17.9zm14-3l-2.5-2.4-6.4 6.5H19v-4zM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1zm6 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill-rule="nonzero"/></svg>',
|
|
'indent': '<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2zm-2.6-3.8L6.2 12l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6z" fill-rule="evenodd"/></svg>',
|
|
'info': '<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4zm-1 3v2h2V7h-2zm3 10v-1h-1v-5h-3v1h1v4h-1v1h4z" fill-rule="evenodd"/></svg>',
|
|
'insert-character': '<svg width="24" height="24"><path d="M15 18h4l1-2v4h-6v-3.3l1.4-1a6 6 0 0 0 1.8-2.9 6.3 6.3 0 0 0-.1-4.1 5.8 5.8 0 0 0-3-3.2c-.6-.3-1.3-.5-2.1-.5a5.1 5.1 0 0 0-3.9 1.8 6.3 6.3 0 0 0-1.3 6 6.2 6.2 0 0 0 1.8 3l1.4.9V20H4v-4l1 2h4v-.5l-2-1L5.4 15A6.5 6.5 0 0 1 4 11c0-1 .2-1.9.6-2.7A7 7 0 0 1 6.3 6C7.1 5.4 8 5 9 4.5c1-.3 2-.5 3.1-.5a8.8 8.8 0 0 1 5.7 2 7 7 0 0 1 1.7 2.3 6 6 0 0 1 .2 4.8c-.2.7-.6 1.3-1 1.9a7.6 7.6 0 0 1-3.6 2.5v.5z" fill-rule="evenodd"/></svg>',
|
|
'insert-time': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M12 19a7 7 0 1 0 0-14 7 7 0 0 0 0 14zm0 2a9 9 0 1 1 0-18 9 9 0 0 1 0 18z"/><path d="M16 12h-3V7c0-.6-.4-1-1-1a1 1 0 0 0-1 1v7h5c.6 0 1-.4 1-1s-.4-1-1-1z"/></g></svg>',
|
|
'invert': '<svg width="24" height="24"><path d="M18 19.3L16.5 18a5.8 5.8 0 0 1-3.1 1.9 6.1 6.1 0 0 1-5.5-1.6A5.8 5.8 0 0 1 6 14v-.3l.1-1.2A13.9 13.9 0 0 1 7.7 9l-3-3 .7-.8 2.8 2.9 9 8.9 1.5 1.6-.7.6zm0-5.5v.3l-.1 1.1-.4 1-1.2-1.2a4.3 4.3 0 0 0 .2-1v-.2c0-.4 0-.8-.2-1.3l-.5-1.4a14.8 14.8 0 0 0-3-4.2L12 6a26.1 26.1 0 0 0-2.2 2.5l-1-1a20.9 20.9 0 0 1 2.9-3.3L12 4l1 .8a22.2 22.2 0 0 1 4 5.4c.6 1.2 1 2.4 1 3.6z" fill-rule="evenodd"/></svg>',
|
|
'italic': '<svg width="24" height="24"><path d="M16.7 4.7l-.1.9h-.3c-.6 0-1 0-1.4.3-.3.3-.4.6-.5 1.1l-2.1 9.8v.6c0 .5.4.8 1.4.8h.2l-.2.8H8l.2-.8h.2c1.1 0 1.8-.5 2-1.5l2-9.8.1-.5c0-.6-.4-.8-1.4-.8h-.3l.2-.9h5.8z" fill-rule="evenodd"/></svg>',
|
|
'line': '<svg width="24" height="24"><path d="M15 9l-8 8H4v-3l8-8 3 3zm1-1l-3-3 1-1h1c-.2 0 0 0 0 0l2 2s0 .2 0 0v1l-1 1zM4 18h16v2H4v-2z" fill-rule="evenodd"/></svg>',
|
|
'link': '<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2.1 2a2 2 0 1 0 2.7 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2zm11.6-.6a1 1 0 0 1-1.4-1.4l2-2a2 2 0 1 0-2.6-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2z" fill-rule="nonzero"/></svg>',
|
|
'list-bull-circle': '<svg width="48" height="48"><g fill-rule="evenodd"><path d="M11 16a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM11 26a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6zM11 36a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6z" fill-rule="nonzero"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
|
|
'list-bull-default': '<svg width="48" height="48"><g fill-rule="evenodd"><circle cx="11" cy="14" r="3"/><circle cx="11" cy="24" r="3"/><circle cx="11" cy="34" r="3"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
|
|
'list-bull-square': '<svg width="48" height="48"><g fill-rule="evenodd"><path d="M8 11h6v6H8zM8 21h6v6H8zM8 31h6v6H8z"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
|
|
'list-num-default-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 17v-4.8l-1.6 1v-1.1l1.6-1h1.2V17zM33.3 17.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm1.7 5.7c0-1.2 1-2 2.2-2 1.3 0 2.1.8 2.1 1.8 0 .7-.3 1.2-1.3 2.2l-1.2 1v.2h2.6v1h-4.3v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H35zm-1.7 4.3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm3.2 7.3v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H35c0-1.1 1-1.8 2.2-1.8 1.2 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.7.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .6 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7zm-3.3 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7z"/></g></svg>',
|
|
'list-num-default': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10 17v-4.8l-1.5 1v-1.1l1.6-1h1.2V17h-1.2zm3.6.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7zm-5 5.7c0-1.2.8-2 2.1-2s2.1.8 2.1 1.8c0 .7-.3 1.2-1.4 2.2l-1.1 1v.2h2.6v1H8.6v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H8.5zm6.3 4.3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zM10 34.4v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H8.6c0-1.1 1-1.8 2.2-1.8 1.3 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.8.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .7 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7zm4.7 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7z"/></g></svg>',
|
|
'list-num-lower-alpha-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M36.5 16c-.9 0-1.5-.5-1.5-1.3s.6-1.3 1.8-1.4h1v-.4c0-.4-.2-.6-.7-.6-.4 0-.7.1-.8.4h-1.1c0-.8.8-1.4 2-1.4S39 12 39 13V16h-1.2v-.6c-.3.4-.8.7-1.4.7zm.4-.8c.6 0 1-.4 1-.9V14h-1c-.5.1-.7.3-.7.6 0 .4.3.6.7.6zM33.1 16.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7zM37.7 26c-.7 0-1.2-.2-1.5-.7v.7H35v-6.3h1.2v2.5c.3-.5.8-.9 1.5-.9 1.1 0 1.8 1 1.8 2.4 0 1.5-.7 2.4-1.8 2.4zm-.5-3.6c-.6 0-1 .5-1 1.3s.4 1.4 1 1.4c.7 0 1-.6 1-1.4 0-.8-.3-1.3-1-1.3zM33.2 26.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7zm6 7h-1c-.1-.5-.4-.8-1-.8s-1 .5-1 1.4c0 1 .4 1.4 1 1.4.5 0 .9-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7zm-6.1 3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
|
|
'list-num-lower-alpha': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.3 15.2c.5 0 1-.4 1-.9V14h-1c-.5.1-.8.3-.8.6 0 .4.3.6.8.6zm-.4.9c-1 0-1.5-.6-1.5-1.4 0-.8.6-1.3 1.7-1.4h1.1v-.4c0-.4-.2-.6-.7-.6-.5 0-.8.1-.9.4h-1c0-.8.8-1.4 2-1.4 1.1 0 1.8.6 1.8 1.6V16h-1.1v-.6h-.1c-.2.4-.7.7-1.3.7zm4.6 0c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm-3.2 10c-.6 0-1.2-.3-1.4-.8v.7H8.5v-6.3H10v2.5c.3-.5.8-.9 1.4-.9 1.2 0 1.9 1 1.9 2.4 0 1.5-.7 2.4-1.9 2.4zm-.4-3.7c-.7 0-1 .5-1 1.3s.3 1.4 1 1.4c.6 0 1-.6 1-1.4 0-.8-.4-1.3-1-1.3zm4 3.7c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm-2.2 7h-1.2c0-.5-.4-.8-.9-.8-.6 0-1 .5-1 1.4 0 1 .4 1.4 1 1.4.5 0 .8-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7zm1.8 3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
|
|
'list-num-lower-greek-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 16c-1.2 0-2-.8-2-2.3 0-1.5.8-2.4 2-2.4.6 0 1 .4 1.3 1v-.9H40v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1-.7h-.2c-.2.4-.7.8-1.3.8zm.3-1c.6 0 1-.5 1-1.3s-.4-1.3-1-1.3-1 .5-1 1.3.4 1.4 1 1.4zM33.3 16.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zM36 21.9c0-1.5.8-2.3 2.1-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.9 1.3.9.3 1.3.8 1.3 1.7 0 1.2-.7 1.9-1.8 1.9-.6 0-1.1-.3-1.4-.8v2.2H36V22zm1.8 1.2v-1h.3c.5 0 .9-.2.9-.7 0-.5-.3-.8-.9-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1 1.3s1-.4 1-1-.4-1-1.2-1h-.3zM33.3 26.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zM37.1 34.6L34.8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.2.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1zM33.3 36.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
|
|
'list-num-lower-greek': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.5 15c.7 0 1-.5 1-1.3s-.3-1.3-1-1.3c-.5 0-.9.5-.9 1.3s.4 1.4 1 1.4zm-.3 1c-1.1 0-1.8-.8-1.8-2.3 0-1.5.7-2.4 1.8-2.4.7 0 1.1.4 1.3 1h.1v-.9h1.2v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1.1-.7h-.1c-.2.4-.7.8-1.4.8zm5 .1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7zm-4.9 7v-1h.3c.6 0 1-.2 1-.7 0-.5-.4-.8-1-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1.1 1.3.6 0 1-.4 1-1s-.5-1-1.3-1h-.3zM8.6 22c0-1.5.7-2.3 2-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.8 1.3.8.3 1.3.8 1.3 1.7 0 1.2-.8 1.9-1.9 1.9-.6 0-1.1-.3-1.3-.8v2.2H8.5V22zm6.2 4.2c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7zm-4.5 8.5L8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.1.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1zm4.5.5c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
|
|
'list-num-lower-roman-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M32.9 16v-1.2h-1.3V16H33zm0 10v-1.2h-1.3V26H33zm0 10v-1.2h-1.3V36H33z"/><path fill-rule="nonzero" d="M36 21h-1.5v5H36zM36 31h-1.5v5H36zM39 21h-1.5v5H39zM39 31h-1.5v5H39zM42 31h-1.5v5H42zM36 11h-1.5v5H36zM36 19h-1.5v1H36zM36 29h-1.5v1H36zM39 19h-1.5v1H39zM39 29h-1.5v1H39zM42 29h-1.5v1H42zM36 9h-1.5v1H36z"/></g></svg>',
|
|
'list-num-lower-roman': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 16v-1.2h1.3V16H15zm0 10v-1.2h1.3V26H15zm0 10v-1.2h1.3V36H15z"/><path fill-rule="nonzero" d="M12 21h1.5v5H12zM12 31h1.5v5H12zM9 21h1.5v5H9zM9 31h1.5v5H9zM6 31h1.5v5H6zM12 11h1.5v5H12zM12 19h1.5v1H12zM12 29h1.5v1H12zM9 19h1.5v1H9zM9 29h1.5v1H9zM6 29h1.5v1H6zM12 9h1.5v1H12z"/></g></svg>',
|
|
'list-num-upper-alpha-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M39.3 17l-.5-1.4h-2l-.5 1.4H35l2-6h1.6l2 6h-1.3zm-1.6-4.7l-.7 2.3h1.6l-.8-2.3zM33.4 17c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7zm4.7 9.9h-2.7v-6H38c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7zm-1.4-5v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1zm0 4h1.1c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9h-1.1V26zM33 27.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm4.9 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2zm-4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
|
|
'list-num-upper-alpha': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M12.6 17l-.5-1.4h-2L9.5 17H8.3l2-6H12l2 6h-1.3zM11 12.3l-.7 2.3h1.6l-.8-2.3zm4.7 4.8c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7zM11.4 27H8.7v-6h2.6c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7zM10 22v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1zm0 4H11c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9H10V26zm5.4 1.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm-4.1 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2zm4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
|
|
'list-num-upper-roman-rtl': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M31.6 17v-1.2H33V17h-1.3zm0 10v-1.2H33V27h-1.3zm0 10v-1.2H33V37h-1.3z"/><path fill-rule="nonzero" d="M34.5 20H36v7h-1.5zM34.5 30H36v7h-1.5zM37.5 20H39v7h-1.5zM37.5 30H39v7h-1.5zM40.5 30H42v7h-1.5zM34.5 10H36v7h-1.5z"/></g></svg>',
|
|
'list-num-upper-roman': '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 17v-1.2h1.3V17H15zm0 10v-1.2h1.3V27H15zm0 10v-1.2h1.3V37H15z"/><path fill-rule="nonzero" d="M12 20h1.5v7H12zM12 30h1.5v7H12zM9 20h1.5v7H9zM9 30h1.5v7H9zM6 30h1.5v7H6zM12 10h1.5v7H12z"/></g></svg>',
|
|
'lock': '<svg width="24" height="24"><path d="M16.3 11c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H8V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h.3zM10 8v3h4V8a1 1 0 0 0-.3-.7A1 1 0 0 0 13 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7z" fill-rule="evenodd"/></svg>',
|
|
'ltr': '<svg width="24" height="24"><path d="M11 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 7.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L11 5zM4.4 16.2L6.2 15l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6z" fill-rule="evenodd"/></svg>',
|
|
'more-drawer': '<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2z" fill-rule="nonzero"/></svg>',
|
|
'new-document': '<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3zM17 19H7V5h6v4h4v10z" fill-rule="nonzero"/></svg>',
|
|
'new-tab': '<svg width="24" height="24"><path d="M15 13l2-2v8H5V7h8l-2 2H7v8h8v-4zm4-8v5.5l-2-2-5.6 5.5H10v-1.4L15.5 7l-2-2H19z" fill-rule="evenodd"/></svg>',
|
|
'non-breaking': '<svg width="24" height="24"><path d="M11 11H8a1 1 0 1 1 0-2h3V6c0-.6.4-1 1-1s1 .4 1 1v3h3c.6 0 1 .4 1 1s-.4 1-1 1h-3v3c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-3zm10 4v5H3v-5c0-.6.4-1 1-1s1 .4 1 1v3h14v-3c0-.6.4-1 1-1s1 .4 1 1z" fill-rule="evenodd"/></svg>',
|
|
'notice': '<svg width="24" height="24"><path d="M17.8 9.8L15.4 4 20 8.5v7L15.5 20h-7L4 15.5v-7L8.5 4h7l2.3 5.8zm0 0l2.2 5.7-2.3-5.8zM13 17v-2h-2v2h2zm0-4V7h-2v6h2z" fill-rule="evenodd"/></svg>',
|
|
'ordered-list-rtl': '<svg width="24" height="24"><path d="M6 17h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2zm13-1v3.5a.5.5 0 1 1-1 0V5h-.5a.5.5 0 1 1 0-1H19zm-1 8.8l.2.2h1.3a.5.5 0 1 1 0 1h-1.6a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2h-1.3a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3zm2 4.2v2c0 .6-.4 1-1 1h-1.5a.5.5 0 0 1 0-1h1.2a.3.3 0 1 0 0-.6h-1.3a.4.4 0 1 1 0-.8h1.3a.3.3 0 0 0 0-.6h-1.2a.5.5 0 1 1 0-1H19c.6 0 1 .4 1 1z" fill-rule="evenodd"/></svg>',
|
|
'ordered-list': '<svg width="24" height="24"><path d="M10 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 1 1 0-2zM6 4v3.5c0 .3-.2.5-.5.5a.5.5 0 0 1-.5-.5V5h-.5a.5.5 0 0 1 0-1H6zm-1 8.8l.2.2h1.3c.3 0 .5.2.5.5s-.2.5-.5.5H4.9a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2H4.5a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3zM7 17v2c0 .6-.4 1-1 1H4.5a.5.5 0 0 1 0-1h1.2c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.4a.4.4 0 1 1 0-.8h1.3c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.5a.5.5 0 1 1 0-1H6c.6 0 1 .4 1 1z" fill-rule="evenodd"/></svg>',
|
|
'orientation': '<svg width="24" height="24"><path d="M7.3 6.4L1 13l6.4 6.5 6.5-6.5-6.5-6.5zM3.7 13l3.6-3.7L11 13l-3.7 3.7-3.6-3.7zM12 6l2.8 2.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0L9.2 5.7a.8.8 0 0 1 0-1.2L13.6.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L12 4h1a9 9 0 1 1-4.3 16.9l1.5-1.5A7 7 0 1 0 13 6h-1z" fill-rule="nonzero"/></svg>',
|
|
'outdent': '<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2zm1.6-3.8a1 1 0 0 1-1.2 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 0 1 1.2 1.6L6.8 12l1.8 1.2z" fill-rule="evenodd"/></svg>',
|
|
'page-break': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M5 11c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1h-1a1 1 0 0 1 0-2zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2zM7 3v5h10V3c0-.6.4-1 1-1s1 .4 1 1v7H5V3c0-.6.4-1 1-1s1 .4 1 1zM6 22a1 1 0 0 1-1-1v-7h14v7c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5H7v5c0 .6-.4 1-1 1z"/></g></svg>',
|
|
'paste-text': '<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9zM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1zm1.5-9.5v9h9v-9h-9zM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1zm0 9h6v2h-.5l-.5-1h-1v4h.8v1h-3.6v-1h.8v-4h-1l-.5 1H12v-2z" fill-rule="nonzero"/></svg>',
|
|
'paste': '<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9zM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1zm1.5-9.5v9h9v-9h-9zM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1z" fill-rule="nonzero"/></svg>',
|
|
'permanent-pen': '<svg width="24" height="24"><path d="M10.5 17.5L8 20H3v-3l3.5-3.5a2 2 0 0 1 0-3L14 3l1 1-7.3 7.3a1 1 0 0 0 0 1.4l3.6 3.6c.4.4 1 .4 1.4 0L20 9l1 1-7.6 7.6a2 2 0 0 1-2.8 0l-.1-.1z" fill-rule="nonzero"/></svg>',
|
|
'plus': '<svg width="24" height="24"><g fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke="#000" stroke-width="2"><path d="M12 5v14M5 12h14"/></g></svg>',
|
|
'preferences': '<svg width="24" height="24"><path d="M20.1 13.5l-1.9.2a5.8 5.8 0 0 1-.6 1.5l1.2 1.5c.4.4.3 1 0 1.4l-.7.7a1 1 0 0 1-1.4 0l-1.5-1.2a6.2 6.2 0 0 1-1.5.6l-.2 1.9c0 .5-.5.9-1 .9h-1a1 1 0 0 1-1-.9l-.2-1.9a5.8 5.8 0 0 1-1.5-.6l-1.5 1.2a1 1 0 0 1-1.4 0l-.7-.7a1 1 0 0 1 0-1.4l1.2-1.5a6.2 6.2 0 0 1-.6-1.5l-1.9-.2a1 1 0 0 1-.9-1v-1c0-.5.4-1 .9-1l1.9-.2a5.8 5.8 0 0 1 .6-1.5L5.2 7.3a1 1 0 0 1 0-1.4l.7-.7a1 1 0 0 1 1.4 0l1.5 1.2a6.2 6.2 0 0 1 1.5-.6l.2-1.9c0-.5.5-.9 1-.9h1c.5 0 1 .4 1 .9l.2 1.9a5.8 5.8 0 0 1 1.5.6l1.5-1.2a1 1 0 0 1 1.4 0l.7.7c.3.4.4 1 0 1.4l-1.2 1.5a6.2 6.2 0 0 1 .6 1.5l1.9.2c.5 0 .9.5.9 1v1c0 .5-.4 1-.9 1zM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" fill-rule="evenodd"/></svg>',
|
|
'preview': '<svg width="24" height="24"><path d="M3.5 12.5c.5.8 1.1 1.6 1.8 2.3 2 2 4.2 3.2 6.7 3.2s4.7-1.2 6.7-3.2a16.2 16.2 0 0 0 2.1-2.8 15.7 15.7 0 0 0-2.1-2.8c-2-2-4.2-3.2-6.7-3.2a9.3 9.3 0 0 0-6.7 3.2A16.2 16.2 0 0 0 3.2 12c0 .2.2.3.3.5zm-2.4-1l.7-1.2L4 7.8C6.2 5.4 8.9 4 12 4c3 0 5.8 1.4 8.1 3.8a18.2 18.2 0 0 1 2.8 3.7v1l-.7 1.2-2.1 2.5c-2.3 2.4-5 3.8-8.1 3.8-3 0-5.8-1.4-8.1-3.8a18.2 18.2 0 0 1-2.8-3.7 1 1 0 0 1 0-1zm12-3.3a2 2 0 1 0 2.7 2.6 4 4 0 1 1-2.6-2.6z" fill-rule="nonzero"/></svg>',
|
|
'print': '<svg width="24" height="24"><path d="M18 8H6a3 3 0 0 0-3 3v6h2v3h14v-3h2v-6a3 3 0 0 0-3-3zm-1 10H7v-4h10v4zm.5-5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm.5-8H6v2h12V5z" fill-rule="nonzero"/></svg>',
|
|
'quote': '<svg width="24" height="24"><path d="M7.5 17h.9c.4 0 .7-.2.9-.6L11 13V8c0-.6-.4-1-1-1H6a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3zm8 0h.9c.4 0 .7-.2.9-.6L19 13V8c0-.6-.4-1-1-1h-4a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3z" fill-rule="nonzero"/></svg>',
|
|
'redo': '<svg width="24" height="24"><path d="M17.6 10H12c-2.8 0-4.4 1.4-4.9 3.5-.4 2 .3 4 1.4 4.6a1 1 0 1 1-1 1.8c-2-1.2-2.9-4.1-2.3-6.8.6-3 3-5.1 6.8-5.1h5.6l-3.3-3.3a1 1 0 1 1 1.4-1.4l5 5a1 1 0 0 1 0 1.4l-5 5a1 1 0 0 1-1.4-1.4l3.3-3.3z" fill-rule="nonzero"/></svg>',
|
|
'reload': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M5 22.1l-1.2-4.7v-.2a1 1 0 0 1 1-1l5 .4a1 1 0 1 1-.2 2l-2.2-.2a7.8 7.8 0 0 0 8.4.2 7.5 7.5 0 0 0 3.5-6.4 1 1 0 1 1 2 0 9.5 9.5 0 0 1-4.5 8 9.9 9.9 0 0 1-10.2 0l.4 1.4a1 1 0 1 1-2 .5zM13.6 7.4c0-.5.5-1 1-.9l2.8.2a8 8 0 0 0-9.5-1 7.5 7.5 0 0 0-3.6 7 1 1 0 0 1-2 0 9.5 9.5 0 0 1 4.5-8.6 10 10 0 0 1 10.9.3l-.3-1a1 1 0 0 1 2-.5l1.1 4.8a1 1 0 0 1-1 1.2l-5-.4a1 1 0 0 1-.9-1z"/></g></svg>',
|
|
'remove-formatting': '<svg width="24" height="24"><path d="M13.2 6a1 1 0 0 1 0 .2l-2.6 10a1 1 0 0 1-1 .8h-.2a.8.8 0 0 1-.8-1l2.6-10H8a1 1 0 1 1 0-2h9a1 1 0 0 1 0 2h-3.8zM5 18h7a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm13 1.5L16.5 18 15 19.5a.7.7 0 0 1-1-1l1.5-1.5-1.5-1.5a.7.7 0 0 1 1-1l1.5 1.5 1.5-1.5a.7.7 0 0 1 1 1L17.5 17l1.5 1.5a.7.7 0 0 1-1 1z" fill-rule="evenodd"/></svg>',
|
|
'remove': '<svg width="24" height="24"><path d="M16 7h3a1 1 0 0 1 0 2h-1v9a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V9H5a1 1 0 1 1 0-2h3V6a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v1zm-2 0V6c0-.6-.4-1-1-1h-2a1 1 0 0 0-1 1v1h4zm2 2H8v9c0 .6.4 1 1 1h6c.6 0 1-.4 1-1V9zm-7 3a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4zm4 0a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4z" fill-rule="nonzero"/></svg>',
|
|
'resize-handle': '<svg width="10" height="10"><g fill-rule="nonzero"><path d="M8.1 1.1A.5.5 0 1 1 9 2l-7 7A.5.5 0 1 1 1 8l7-7zM8.1 5.1A.5.5 0 1 1 9 6l-3 3A.5.5 0 1 1 5 8l3-3z"/></g></svg>',
|
|
'resize': '<svg width="24" height="24"><path d="M4 5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h6c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H7.4L18 16.6V13c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v6c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-6a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3.6L6 7.4V11c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3A1 1 0 0 1 4 11V5z" fill-rule="evenodd"/></svg>',
|
|
'restore-draft': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M17 13c0 .6-.4 1-1 1h-4V8c0-.6.4-1 1-1s1 .4 1 1v4h2c.6 0 1 .4 1 1z"/><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10z" fill-rule="nonzero"/></g></svg>',
|
|
'rotate-left': '<svg width="24" height="24"><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10z" fill-rule="nonzero"/></svg>',
|
|
'rotate-right': '<svg width="24" height="24"><path d="M20 8V5a1 1 0 0 1 2 0v6c0 .6-.4 1-1 1h-6a1 1 0 0 1 0-2h4.3L16 7A7.2 7.2 0 0 0 7.7 6a7 7 0 0 0 3 13.1c1.9.1 3.7-.5 5-1.7a1 1 0 0 1 1.4 1.5A9.2 9.2 0 0 1 2.2 14c-.9-3.9 1-8 4.5-9.9 3.5-1.9 8-1.3 10.8 1.5L20 8z" fill-rule="nonzero"/></svg>',
|
|
'rtl': '<svg width="24" height="24"><path d="M8 5h8v2h-2v12h-2V7h-2v12H8v-7c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 4.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L8 5zm12 11.2a1 1 0 1 1-1 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 1 1 1 1.6L18.4 15l1.8 1.2z" fill-rule="evenodd"/></svg>',
|
|
'save': '<svg width="24" height="24"><path d="M5 16h14a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2c0-1.1.9-2 2-2zm0 2v2h14v-2H5zm10 0h2v2h-2v-2zm-4-6.4L8.7 9.3a1 1 0 1 0-1.4 1.4l4 4c.4.4 1 .4 1.4 0l4-4a1 1 0 1 0-1.4-1.4L13 11.6V4a1 1 0 0 0-2 0v7.6z" fill-rule="nonzero"/></svg>',
|
|
'search': '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12z" fill-rule="nonzero"/></svg>',
|
|
'select-all': '<svg width="24" height="24"><path d="M3 5h2V3a2 2 0 0 0-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2a2 2 0 0 0-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8a2 2 0 0 0 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z" fill-rule="nonzero"/></svg>',
|
|
'selected': '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2zm3.6 10.9L7 12.3a.7.7 0 0 0-1 1L9.6 17 18 8.6a.7.7 0 0 0 0-1 .7.7 0 0 0-1 0l-7.4 7.3z"/></svg>',
|
|
'settings': '<svg width="24" height="24"><path d="M11 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V8H5a1 1 0 1 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.5V6zM8 8h2V6H8v2zm9 2.8v.2h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v.3c0 .2 0 .3-.2.5l-.6.2h-2.4c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V13H5a1 1 0 0 1 0-2h8v-.3c0-.2 0-.3.2-.5l.6-.2h2.4c.3 0 .4 0 .6.2l.2.6zM14 13h2v-2h-2v2zm-3 2.8v.2h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V18H5a1 1 0 0 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.6zM8 18h2v-2H8v2z" fill-rule="evenodd"/></svg>',
|
|
'sharpen': '<svg width="24" height="24"><path d="M16 6l4 4-8 9-8-9 4-4h8zm-4 10.2l5.5-6.2-.1-.1H12v-.3h5.1l-.2-.2H12V9h4.6l-.2-.2H12v-.3h4.1l-.2-.2H12V8h3.6l-.2-.2H8.7L6.5 10l.1.1H12v.3H6.9l.2.2H12v.3H7.3l.2.2H12v.3H7.7l.3.2h4v.3H8.2l.2.2H12v.3H8.6l.3.2H12v.3H9l.3.2H12v.3H9.5l.2.2H12v.3h-2l.2.2H12v.3h-1.6l.2.2H12v.3h-1.1l.2.2h.9v.3h-.7l.2.2h.5v.3h-.3l.3.2z" fill-rule="evenodd"/></svg>',
|
|
'sourcecode': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M9.8 15.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0l-4.4-4.1a.8.8 0 0 1 0-1.2l4.4-4.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L6 12l3.8 3.7zM14.2 15.7c-.3.3-.3.8 0 1 .4.4.9.4 1.2 0l4.4-4.1c.3-.3.3-.9 0-1.2l-4.4-4.2a.8.8 0 0 0-1.2 0c-.3.3-.3.8 0 1.1L18 12l-3.8 3.7z"/></g></svg>',
|
|
'spell-check': '<svg width="24" height="24"><path d="M6 8v3H5V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h2c.3 0 .5.1.7.3.2.2.3.4.3.7v6H8V8H6zm0-3v2h2V5H6zm13 0h-3v5h3v1h-3a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3v1zm-5 1.5l-.1.7c-.1.2-.3.3-.6.3.3 0 .5.1.6.3l.1.7V10c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-3V4h3c.3 0 .5.1.7.3.2.2.3.4.3.7v1.5zM13 10V8h-2v2h2zm0-3V5h-2v2h2zm3 5l1 1-6.5 7L7 15.5l1.3-1 2.2 2.2L16 12z" fill-rule="evenodd"/></svg>',
|
|
'strike-through': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M15.6 8.5c-.5-.7-1-1.1-1.3-1.3-.6-.4-1.3-.6-2-.6-2.7 0-2.8 1.7-2.8 2.1 0 1.6 1.8 2 3.2 2.3 4.4.9 4.6 2.8 4.6 3.9 0 1.4-.7 4.1-5 4.1A6.2 6.2 0 0 1 7 16.4l1.5-1.1c.4.6 1.6 2 3.7 2 1.6 0 2.5-.4 3-1.2.4-.8.3-2-.8-2.6-.7-.4-1.6-.7-2.9-1-1-.2-3.9-.8-3.9-3.6C7.6 6 10.3 5 12.4 5c2.9 0 4.2 1.6 4.7 2.4l-1.5 1.1z"/><path d="M5 11h14a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2z" fill-rule="nonzero"/></g></svg>',
|
|
'subscript': '<svg width="24" height="24"><path d="M10.4 10l4.6 4.6-1.4 1.4L9 11.4 4.4 16 3 14.6 7.6 10 3 5.4 4.4 4 9 8.6 13.6 4 15 5.4 10.4 10zM21 19h-5v-1l1-.8 1.7-1.6c.3-.4.5-.8.5-1.2 0-.3 0-.6-.2-.7-.2-.2-.5-.3-.9-.3a2 2 0 0 0-.8.2l-.7.3-.4-1.1 1-.6 1.2-.2c.8 0 1.4.3 1.8.7.4.4.6.9.6 1.5s-.2 1.1-.5 1.6a8 8 0 0 1-1.3 1.3l-.6.6h2.6V19z" fill-rule="nonzero"/></svg>',
|
|
'superscript': '<svg width="24" height="24"><path d="M15 9.4L10.4 14l4.6 4.6-1.4 1.4L9 15.4 4.4 20 3 18.6 7.6 14 3 9.4 4.4 8 9 12.6 13.6 8 15 9.4zm5.9 1.6h-5v-1l1-.8 1.7-1.6c.3-.5.5-.9.5-1.3 0-.3 0-.5-.2-.7-.2-.2-.5-.3-.9-.3l-.8.2-.7.4-.4-1.2c.2-.2.5-.4 1-.5.3-.2.8-.2 1.2-.2.8 0 1.4.2 1.8.6.4.4.6 1 .6 1.6 0 .5-.2 1-.5 1.5l-1.3 1.4-.6.5h2.6V11z" fill-rule="nonzero"/></svg>',
|
|
'table-cell-properties': '<svg width="24" height="24"><path d="M4 5h16v14H4V5zm10 10h-4v3h4v-3zm0-8h-4v3h4V7zM9 7H5v3h4V7zm-4 4v3h4v-3H5zm10 0v3h4v-3h-4zm0-1h4V7h-4v3zM5 15v3h4v-3H5zm10 3h4v-3h-4v3z" fill-rule="evenodd"/></svg>',
|
|
'table-cell-select-all': '<svg width="24" height="24"><path d="M12.5 5.5v6h6v-6h-6zm-1 0h-6v6h6v-6zm1 13h6v-6h-6v6zm-1 0v-6h-6v6h6zm-7-14h15v15h-15v-15z" fill-rule="nonzero"/></svg>',
|
|
'table-cell-select-inner': '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M5.5 5.5v13h13v-13h-13zm-1-1h15v15h-15v-15z" opacity=".2"/><path d="M11.5 11.5v-7h1v7h7v1h-7v7h-1v-7h-7v-1h7z"/></g></svg>',
|
|
'table-delete-column': '<svg width="24" height="24"><path d="M9 11.2l1 1v.2l-1 1v-2.2zm5 1l1-1v2.2l-1-1v-.2zM20 5v14H4V5h16zm-1 2h-4v.8l-.2-.2-.8.8V7h-4v1.4l-.8-.8-.2.2V7H5v11h4v-1.8l.5.5.5-.4V18h4v-1.8l.8.8.2-.3V18h4V7zm-3.9 3.4l-1.8 1.9 1.8 1.9c.4.3.4.9 0 1.2-.3.3-.8.3-1.2 0L12 13.5l-1.8 1.9a.8.8 0 0 1-1.2 0 .9.9 0 0 1 0-1.2l1.8-1.9-1.9-2a.9.9 0 0 1 1.2-1.2l2 2 1.8-1.8c.3-.4.9-.4 1.2 0a.8.8 0 0 1 0 1.1z" fill-rule="evenodd"/></svg>',
|
|
'table-delete-row': '<svg width="24" height="24"><path d="M16.7 8.8l1.1 1.2-2.4 2.5L18 15l-1.2 1.2-2.5-2.5-2.4 2.5-1.3-1.2 2.5-2.5-2.5-2.5 1.2-1.3 2.6 2.6 2.4-2.5zM4 5h16v14H4V5zm15 5V7H5v3h4.8l1 1H5v3h5.8l-1 1H5v3h14v-3h-.4l-1-1H19v-3h-1.3l1-1h.3z" fill-rule="evenodd"/></svg>',
|
|
'table-delete-table': '<svg width="24" height="26"><path d="M4 6h16v14H4V6zm1 2v11h14V8H5zm11.7 8.7l-1.5 1.5L12 15l-3.3 3.2-1.4-1.5 3.2-3.2-3.3-3.2 1.5-1.5L12 12l3.2-3.2 1.5 1.5-3.2 3.2 3.2 3.2z" fill-rule="evenodd"/></svg>',
|
|
'table-insert-column-after': '<svg width="24" height="24"><path d="M14.3 9c.4 0 .7.3.7.6v2.2h2.1c.4 0 .7.3.7.7 0 .4-.3.7-.7.7H15v2.2c0 .3-.3.6-.7.6a.7.7 0 0 1-.6-.6v-2.2h-2.2a.7.7 0 0 1 0-1.4h2.2V9.6c0-.3.3-.6.6-.6zM4 5h16v14H4V5zm5 13v-3H5v3h4zm0-4v-3H5v3h4zm0-4V7H5v3h4zm10 8V7h-9v11h9z" fill-rule="evenodd"/></svg>',
|
|
'table-insert-column-before': '<svg width="24" height="24"><path d="M9.7 16a.7.7 0 0 1-.7-.6v-2.2H6.9a.7.7 0 0 1 0-1.4H9V9.6c0-.3.3-.6.7-.6.3 0 .6.3.6.6v2.2h2.2c.4 0 .8.3.8.7 0 .4-.4.7-.8.7h-2.2v2.2c0 .3-.3.6-.6.6zM4 5h16v14H4V5zm10 13V7H5v11h9zm5 0v-3h-4v3h4zm0-4v-3h-4v3h4zm0-4V7h-4v3h4z" fill-rule="evenodd"/></svg>',
|
|
'table-insert-row-above': '<svg width="24" height="24"><path d="M14.8 10.5c0 .3-.2.5-.5.5h-1.8v1.8c0 .3-.2.5-.5.5a.5.5 0 0 1-.5-.6V11H9.7a.5.5 0 0 1 0-1h1.8V8.3c0-.3.2-.6.5-.6s.5.3.5.6V10h1.8c.3 0 .5.2.5.5zM4 5h16v14H4V5zm5 13v-3H5v3h4zm5 0v-3h-4v3h4zm5 0v-3h-4v3h4zm0-4V7H5v7h14z" fill-rule="evenodd"/></svg>',
|
|
'table-insert-row-after': '<svg width="24" height="24"><path d="M9.2 14.5c0-.3.2-.5.5-.5h1.8v-1.8c0-.3.2-.5.5-.5s.5.2.5.6V14h1.8c.3 0 .5.2.5.5s-.2.5-.5.5h-1.8v1.7c0 .3-.2.6-.5.6a.5.5 0 0 1-.5-.6V15H9.7a.5.5 0 0 1-.5-.5zM4 5h16v14H4V5zm6 2v3h4V7h-4zM5 7v3h4V7H5zm14 11v-7H5v7h14zm0-8V7h-4v3h4z" fill-rule="evenodd"/></svg>',
|
|
'table-left-header': '<svg width="24" height="24"><path d="M4 5h16v13H4V5zm10 12v-3h-4v3h4zm0-4v-3h-4v3h4zm0-4V6h-4v3h4zm5 8v-3h-4v3h4zm0-4v-3h-4v3h4zm0-4V6h-4v3h4z" fill-rule="evenodd"/></svg>',
|
|
'table-merge-cells': '<svg width="24" height="24"><path d="M4 5h16v14H4V5zm6 13h9v-7h-9v7zm4-11h-4v3h4V7zM9 7H5v3h4V7zm-4 4v3h4v-3H5zm10-1h4V7h-4v3zM5 15v3h4v-3H5z" fill-rule="evenodd"/></svg>',
|
|
'table-row-properties': '<svg width="24" height="24"><path d="M4 5h16v14H4V5zm10 10h-4v3h4v-3zm0-8h-4v3h4V7zM9 7H5v3h4V7zm6 3h4V7h-4v3zM5 15v3h4v-3H5zm10 3h4v-3h-4v3z" fill-rule="evenodd"/></svg>',
|
|
'table-split-cells': '<svg width="24" height="24"><path d="M4 5h16v14H4V5zm6 2v3h4V7h-4zM9 18v-3H5v3h4zm0-4v-3H5v3h4zm0-4V7H5v3h4zm10 8v-7h-9v7h9zm0-8V7h-4v3h4zm-3.5 4.5l1.5 1.6c.3.2.3.7 0 1-.2.2-.7.2-1 0l-1.5-1.6-1.6 1.5c-.2.3-.7.3-1 0a.7.7 0 0 1 0-1l1.6-1.5-1.5-1.6a.7.7 0 0 1 1-1l1.5 1.6 1.6-1.5c.2-.3.7-.3 1 0 .2.2.2.7 0 1l-1.6 1.5z" fill-rule="evenodd"/></svg>',
|
|
'table-top-header': '<svg width="24" height="24"><path d="M4 5h16v13H4V5zm5 12v-3H5v3h4zm0-4v-3H5v3h4zm5 4v-3h-4v3h4zm0-4v-3h-4v3h4zm5 4v-3h-4v3h4zm0-4v-3h-4v3h4z" fill-rule="evenodd"/></svg>',
|
|
'table': '<svg width="24" height="24"><path d="M4 5h16v14H4V5zm6 9h4v-3h-4v3zm4 1h-4v3h4v-3zm0-8h-4v3h4V7zM9 7H5v3h4V7zm-4 4v3h4v-3H5zm10 0v3h4v-3h-4zm0-1h4V7h-4v3zM5 15v3h4v-3H5zm10 3h4v-3h-4v3z" fill-rule="evenodd"/></svg>',
|
|
'template': '<svg width="24" height="24"><path d="M19 19v-1H5v1h14zM9 16v-4a5 5 0 1 1 6 0v4h4a2 2 0 0 1 2 2v3H3v-3c0-1.1.9-2 2-2h4zm4 0v-5l.8-.6a3 3 0 1 0-3.6 0l.8.6v5h2z" fill-rule="nonzero"/></svg>',
|
|
'temporary-placeholder': '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M9 7.6V6h2.5V4.5a.5.5 0 1 1 1 0V6H15v1.6a8 8 0 1 1-6 0zm-2.6 5.3a.5.5 0 0 0 .3.6c.3 0 .6 0 .6-.3l.1-.2a5 5 0 0 1 3.3-2.8c.3-.1.4-.4.4-.6-.1-.3-.4-.5-.6-.4a6 6 0 0 0-4.1 3.7z"/><circle cx="14" cy="4" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="10" cy="4" r="1"/></g></svg>',
|
|
'text-color': '<svg width="24" height="24"><g fill-rule="evenodd"><path id="tox-icon-text-color__color" d="M3 18h18v3H3z"/><path d="M8.7 16h-.8a.5.5 0 0 1-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 0 1-.5.6h-.8a.5.5 0 0 1-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4zm2.6-7.6l-.6 2a.5.5 0 0 0 .5.6h1.6a.5.5 0 0 0 .5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4z"/></g></svg>',
|
|
'toc': '<svg width="24" height="24"><path d="M5 5c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2zm0-4c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2z" fill-rule="evenodd"/></svg>',
|
|
'translate': '<svg width="24" height="24"><path d="M12.7 14.3l-.3.7-.4.7-2.2-2.2-3.1 3c-.3.4-.8.4-1 0a.7.7 0 0 1 0-1l3.1-3A12.4 12.4 0 0 1 6.7 9H8a10.1 10.1 0 0 0 1.7 2.4c.5-.5 1-1.1 1.4-1.8l.9-2H4.7a.7.7 0 1 1 0-1.5h4.4v-.7c0-.4.3-.8.7-.8.4 0 .7.4.7.8v.7H15c.4 0 .8.3.8.7 0 .4-.4.8-.8.8h-1.4a12.3 12.3 0 0 1-1 2.4 13.5 13.5 0 0 1-1.7 2.3l1.9 1.8zm4.3-3l2.7 7.3a.5.5 0 0 1-.4.7 1 1 0 0 1-1-.7l-.6-1.5h-3.4l-.6 1.5a1 1 0 0 1-1 .7.5.5 0 0 1-.4-.7l2.7-7.4a1 1 0 1 1 2 0zm-2.2 4.4h2.4L16 12.5l-1.2 3.2z" fill-rule="evenodd"/></svg>',
|
|
'underline': '<svg width="24" height="24"><path d="M16 5c.6 0 1 .4 1 1v5.5a4 4 0 0 1-.4 1.8l-1 1.4a5.3 5.3 0 0 1-5.5 1 5 5 0 0 1-1.6-1c-.5-.4-.8-.9-1.1-1.4a4 4 0 0 1-.4-1.8V6c0-.6.4-1 1-1s1 .4 1 1v5.5c0 .3 0 .6.2 1l.6.7a3.3 3.3 0 0 0 2.2.8 3.4 3.4 0 0 0 2.2-.8c.3-.2.4-.5.6-.8l.2-.9V6c0-.6.4-1 1-1zM8 17h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2z" fill-rule="evenodd"/></svg>',
|
|
'undo': '<svg width="24" height="24"><path d="M6.4 8H12c3.7 0 6.2 2 6.8 5.1.6 2.7-.4 5.6-2.3 6.8a1 1 0 0 1-1-1.8c1.1-.6 1.8-2.7 1.4-4.6-.5-2.1-2.1-3.5-4.9-3.5H6.4l3.3 3.3a1 1 0 1 1-1.4 1.4l-5-5a1 1 0 0 1 0-1.4l5-5a1 1 0 0 1 1.4 1.4L6.4 8z" fill-rule="nonzero"/></svg>',
|
|
'unlink': '<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2zm11.6-.6a1 1 0 0 1-1.4-1.4l2.1-2a2 2 0 1 0-2.7-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2zM7.6 6.3a.8.8 0 0 1-1 1.1L3.3 4.2a.7.7 0 1 1 1-1l3.2 3.1zM5.1 8.6a.8.8 0 0 1 0 1.5H3a.8.8 0 0 1 0-1.5H5zm5-3.5a.8.8 0 0 1-1.5 0V3a.8.8 0 0 1 1.5 0V5zm6 11.8a.8.8 0 0 1 1-1l3.2 3.2a.8.8 0 0 1-1 1L16 17zm-2.2 2a.8.8 0 0 1 1.5 0V21a.8.8 0 0 1-1.5 0V19zm5-3.5a.7.7 0 1 1 0-1.5H21a.8.8 0 0 1 0 1.5H19z" fill-rule="nonzero"/></svg>',
|
|
'unlock': '<svg width="24" height="24"><path d="M16 5c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h-2V8a1 1 0 0 0-.3-.7A1 1 0 0 0 16 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7v3h.3c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H4.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H11V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2z" fill-rule="evenodd"/></svg>',
|
|
'unordered-list': '<svg width="24" height="24"><path d="M11 5h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2zM4.5 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1z" fill-rule="evenodd"/></svg>',
|
|
'unselected': '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2zm0 1a1 1 0 0 0-1 1v12c0 .6.4 1 1 1h12c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H6z"/></svg>',
|
|
'upload': '<svg width="24" height="24"><path d="M18 19v-2a1 1 0 0 1 2 0v3c0 .6-.4 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 2 0v2h12zM11 6.4L8.7 8.7a1 1 0 0 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 1 1-1.4 1.4L13 6.4V16a1 1 0 0 1-2 0V6.4z" fill-rule="nonzero"/></svg>',
|
|
'user': '<svg width="24" height="24"><path d="M12 24a12 12 0 1 1 0-24 12 12 0 0 1 0 24zm-8.7-5.3a11 11 0 0 0 17.4 0C19.4 16.3 14.6 15 12 15c-2.6 0-7.4 1.3-8.7 3.7zM12 13c2.2 0 4-2 4-4.5S14.2 4 12 4 8 6 8 8.5 9.8 13 12 13z" fill-rule="nonzero"/></svg>',
|
|
'visualblocks': '<svg width="24" height="24"><path d="M9 19v2H7v-2h2zm-4 0v2a2 2 0 0 1-2-2h2zm8 0v2h-2v-2h2zm8 0a2 2 0 0 1-2 2v-2h2zm-4 0v2h-2v-2h2zM15 7a1 1 0 0 1 0 2v7a1 1 0 0 1-2 0V9h-1v7a1 1 0 0 1-2 0v-4a2.5 2.5 0 0 1-.2-5H15zM5 15v2H3v-2h2zm16 0v2h-2v-2h2zM5 11v2H3v-2h2zm16 0v2h-2v-2h2zM5 7v2H3V7h2zm16 0v2h-2V7h2zM5 3v2H3c0-1.1.9-2 2-2zm8 0v2h-2V3h2zm6 0a2 2 0 0 1 2 2h-2V3zM9 3v2H7V3h2zm8 0v2h-2V3h2z" fill-rule="evenodd"/></svg>',
|
|
'visualchars': '<svg width="24" height="24"><path d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5z" fill-rule="evenodd"/></svg>',
|
|
'warning': '<svg width="24" height="24"><path d="M19.8 18.3c.2.5.3.9 0 1.2-.1.3-.5.5-1 .5H5.2c-.5 0-.9-.2-1-.5-.3-.3-.2-.7 0-1.2L11 4.7l.5-.5.5-.2c.2 0 .3 0 .5.2.2 0 .3.3.5.5l6.8 13.6zM12 18c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7c0 .3.1.5.3.7.2.2.4.3.7.3zm.7-3l.3-4a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7l.3 4h1.4z" fill-rule="evenodd"/></svg>',
|
|
'zoom-in': '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm-1-9a1 1 0 0 1 2 0v6a1 1 0 0 1-2 0V8zm-2 4a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8z" fill-rule="nonzero"/></svg>',
|
|
'zoom-out': '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm-3-5a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8z" fill-rule="nonzero"/></svg>'
|
|
};
|
|
};
|
|
|
|
var CreateIconManager = function () {
|
|
var lookup = {};
|
|
var add = function (id, iconPack) {
|
|
lookup[id] = iconPack;
|
|
};
|
|
var get = function (id) {
|
|
if (lookup[id]) {
|
|
return lookup[id];
|
|
}
|
|
return { icons: {} };
|
|
};
|
|
var has$1 = function (id) {
|
|
return has(lookup, id);
|
|
};
|
|
return {
|
|
add: add,
|
|
get: get,
|
|
has: has$1
|
|
};
|
|
};
|
|
var IconManager = CreateIconManager();
|
|
|
|
var PluginManager = AddOnManager$1.PluginManager;
|
|
|
|
var ThemeManager = AddOnManager$1.ThemeManager;
|
|
|
|
function Uploader(uploadStatus, settings) {
|
|
var pendingPromises = {};
|
|
var pathJoin = function (path1, path2) {
|
|
if (path1) {
|
|
return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
|
|
}
|
|
return path2;
|
|
};
|
|
var defaultHandler = function (blobInfo, success, failure, progress) {
|
|
var xhr, formData;
|
|
xhr = new domGlobals.XMLHttpRequest();
|
|
xhr.open('POST', settings.url);
|
|
xhr.withCredentials = settings.credentials;
|
|
xhr.upload.onprogress = function (e) {
|
|
progress(e.loaded / e.total * 100);
|
|
};
|
|
xhr.onerror = function () {
|
|
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
|
};
|
|
xhr.onload = function () {
|
|
var json;
|
|
if (xhr.status < 200 || xhr.status >= 300) {
|
|
failure('HTTP Error: ' + xhr.status);
|
|
return;
|
|
}
|
|
json = JSON.parse(xhr.responseText);
|
|
if (!json || typeof json.location !== 'string') {
|
|
failure('Invalid JSON: ' + xhr.responseText);
|
|
return;
|
|
}
|
|
success(pathJoin(settings.basePath, json.location));
|
|
};
|
|
formData = new domGlobals.FormData();
|
|
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
|
xhr.send(formData);
|
|
};
|
|
var noUpload = function () {
|
|
return new promiseObj(function (resolve) {
|
|
resolve([]);
|
|
});
|
|
};
|
|
var handlerSuccess = function (blobInfo, url) {
|
|
return {
|
|
url: url,
|
|
blobInfo: blobInfo,
|
|
status: true
|
|
};
|
|
};
|
|
var handlerFailure = function (blobInfo, error) {
|
|
return {
|
|
url: '',
|
|
blobInfo: blobInfo,
|
|
status: false,
|
|
error: error
|
|
};
|
|
};
|
|
var resolvePending = function (blobUri, result) {
|
|
Tools.each(pendingPromises[blobUri], function (resolve) {
|
|
resolve(result);
|
|
});
|
|
delete pendingPromises[blobUri];
|
|
};
|
|
var uploadBlobInfo = function (blobInfo, handler, openNotification) {
|
|
uploadStatus.markPending(blobInfo.blobUri());
|
|
return new promiseObj(function (resolve) {
|
|
var notification, progress;
|
|
var noop = function () {
|
|
};
|
|
try {
|
|
var closeNotification_1 = function () {
|
|
if (notification) {
|
|
notification.close();
|
|
progress = noop;
|
|
}
|
|
};
|
|
var success = function (url) {
|
|
closeNotification_1();
|
|
uploadStatus.markUploaded(blobInfo.blobUri(), url);
|
|
resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
|
|
resolve(handlerSuccess(blobInfo, url));
|
|
};
|
|
var failure = function (error) {
|
|
closeNotification_1();
|
|
uploadStatus.removeFailed(blobInfo.blobUri());
|
|
resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
|
|
resolve(handlerFailure(blobInfo, error));
|
|
};
|
|
progress = function (percent) {
|
|
if (percent < 0 || percent > 100) {
|
|
return;
|
|
}
|
|
if (!notification) {
|
|
notification = openNotification();
|
|
}
|
|
notification.progressBar.value(percent);
|
|
};
|
|
handler(blobInfo, success, failure, progress);
|
|
} catch (ex) {
|
|
resolve(handlerFailure(blobInfo, ex.message));
|
|
}
|
|
});
|
|
};
|
|
var isDefaultHandler = function (handler) {
|
|
return handler === defaultHandler;
|
|
};
|
|
var pendingUploadBlobInfo = function (blobInfo) {
|
|
var blobUri = blobInfo.blobUri();
|
|
return new promiseObj(function (resolve) {
|
|
pendingPromises[blobUri] = pendingPromises[blobUri] || [];
|
|
pendingPromises[blobUri].push(resolve);
|
|
});
|
|
};
|
|
var uploadBlobs = function (blobInfos, openNotification) {
|
|
blobInfos = Tools.grep(blobInfos, function (blobInfo) {
|
|
return !uploadStatus.isUploaded(blobInfo.blobUri());
|
|
});
|
|
return promiseObj.all(Tools.map(blobInfos, function (blobInfo) {
|
|
return uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, settings.handler, openNotification);
|
|
}));
|
|
};
|
|
var upload = function (blobInfos, openNotification) {
|
|
return !settings.url && isDefaultHandler(settings.handler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
|
|
};
|
|
if (isFunction(settings.handler) === false) {
|
|
settings.handler = defaultHandler;
|
|
}
|
|
return { upload: upload };
|
|
}
|
|
|
|
var blobUriToBlob = function (url) {
|
|
return new promiseObj(function (resolve, reject) {
|
|
var rejectWithError = function () {
|
|
reject('Cannot convert ' + url + ' to Blob. Resource might not exist or is inaccessible.');
|
|
};
|
|
try {
|
|
var xhr = new domGlobals.XMLHttpRequest();
|
|
xhr.open('GET', url, true);
|
|
xhr.responseType = 'blob';
|
|
xhr.onload = function () {
|
|
if (this.status === 200) {
|
|
resolve(this.response);
|
|
} else {
|
|
rejectWithError();
|
|
}
|
|
};
|
|
xhr.onerror = rejectWithError;
|
|
xhr.send();
|
|
} catch (ex) {
|
|
rejectWithError();
|
|
}
|
|
});
|
|
};
|
|
var parseDataUri = function (uri) {
|
|
var type, matches;
|
|
var uriParts = decodeURIComponent(uri).split(',');
|
|
matches = /data:([^;]+)/.exec(uriParts[0]);
|
|
if (matches) {
|
|
type = matches[1];
|
|
}
|
|
return {
|
|
type: type,
|
|
data: uriParts[1]
|
|
};
|
|
};
|
|
var dataUriToBlob = function (uri) {
|
|
return new promiseObj(function (resolve) {
|
|
var str, arr, i;
|
|
var uriParts = parseDataUri(uri);
|
|
try {
|
|
str = domGlobals.atob(uriParts.data);
|
|
} catch (e) {
|
|
resolve(new domGlobals.Blob([]));
|
|
return;
|
|
}
|
|
arr = new Uint8Array(str.length);
|
|
for (i = 0; i < arr.length; i++) {
|
|
arr[i] = str.charCodeAt(i);
|
|
}
|
|
resolve(new domGlobals.Blob([arr], { type: uriParts.type }));
|
|
});
|
|
};
|
|
var uriToBlob = function (url) {
|
|
if (url.indexOf('blob:') === 0) {
|
|
return blobUriToBlob(url);
|
|
}
|
|
if (url.indexOf('data:') === 0) {
|
|
return dataUriToBlob(url);
|
|
}
|
|
return null;
|
|
};
|
|
var blobToDataUri = function (blob) {
|
|
return new promiseObj(function (resolve) {
|
|
var reader = new domGlobals.FileReader();
|
|
reader.onloadend = function () {
|
|
resolve(reader.result);
|
|
};
|
|
reader.readAsDataURL(blob);
|
|
});
|
|
};
|
|
var Conversions = {
|
|
uriToBlob: uriToBlob,
|
|
blobToDataUri: blobToDataUri,
|
|
parseDataUri: parseDataUri
|
|
};
|
|
|
|
var count = 0;
|
|
var uniqueId = function (prefix) {
|
|
return (prefix || 'blobid') + count++;
|
|
};
|
|
var imageToBlobInfo = function (blobCache, img, resolve, reject) {
|
|
var base64, blobInfo;
|
|
if (img.src.indexOf('blob:') === 0) {
|
|
blobInfo = blobCache.getByUri(img.src);
|
|
if (blobInfo) {
|
|
resolve({
|
|
image: img,
|
|
blobInfo: blobInfo
|
|
});
|
|
} else {
|
|
Conversions.uriToBlob(img.src).then(function (blob) {
|
|
Conversions.blobToDataUri(blob).then(function (dataUri) {
|
|
base64 = Conversions.parseDataUri(dataUri).data;
|
|
blobInfo = blobCache.create(uniqueId(), blob, base64);
|
|
blobCache.add(blobInfo);
|
|
resolve({
|
|
image: img,
|
|
blobInfo: blobInfo
|
|
});
|
|
});
|
|
}, function (err) {
|
|
reject(err);
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
base64 = Conversions.parseDataUri(img.src).data;
|
|
blobInfo = blobCache.findFirst(function (cachedBlobInfo) {
|
|
return cachedBlobInfo.base64() === base64;
|
|
});
|
|
if (blobInfo) {
|
|
resolve({
|
|
image: img,
|
|
blobInfo: blobInfo
|
|
});
|
|
} else {
|
|
Conversions.uriToBlob(img.src).then(function (blob) {
|
|
blobInfo = blobCache.create(uniqueId(), blob, base64);
|
|
blobCache.add(blobInfo);
|
|
resolve({
|
|
image: img,
|
|
blobInfo: blobInfo
|
|
});
|
|
}, function (err) {
|
|
reject(err);
|
|
});
|
|
}
|
|
};
|
|
var getAllImages = function (elm) {
|
|
return elm ? from$1(elm.getElementsByTagName('img')) : [];
|
|
};
|
|
function ImageScanner(uploadStatus, blobCache) {
|
|
var cachedPromises = {};
|
|
var findAll = function (elm, predicate) {
|
|
var images;
|
|
if (!predicate) {
|
|
predicate = constant(true);
|
|
}
|
|
images = filter(getAllImages(elm), function (img) {
|
|
var src = img.src;
|
|
if (!Env.fileApi) {
|
|
return false;
|
|
}
|
|
if (img.hasAttribute('data-mce-bogus')) {
|
|
return false;
|
|
}
|
|
if (img.hasAttribute('data-mce-placeholder')) {
|
|
return false;
|
|
}
|
|
if (!src || src === Env.transparentSrc) {
|
|
return false;
|
|
}
|
|
if (src.indexOf('blob:') === 0) {
|
|
return !uploadStatus.isUploaded(src) && predicate(img);
|
|
}
|
|
if (src.indexOf('data:') === 0) {
|
|
return predicate(img);
|
|
}
|
|
return false;
|
|
});
|
|
var promises = map(images, function (img) {
|
|
if (cachedPromises[img.src]) {
|
|
return new promiseObj(function (resolve) {
|
|
cachedPromises[img.src].then(function (imageInfo) {
|
|
if (typeof imageInfo === 'string') {
|
|
return imageInfo;
|
|
}
|
|
resolve({
|
|
image: img,
|
|
blobInfo: imageInfo.blobInfo
|
|
});
|
|
});
|
|
});
|
|
}
|
|
var newPromise = new promiseObj(function (resolve, reject) {
|
|
imageToBlobInfo(blobCache, img, resolve, reject);
|
|
}).then(function (result) {
|
|
delete cachedPromises[result.image.src];
|
|
return result;
|
|
}).catch(function (error) {
|
|
delete cachedPromises[img.src];
|
|
return error;
|
|
});
|
|
cachedPromises[img.src] = newPromise;
|
|
return newPromise;
|
|
});
|
|
return promiseObj.all(promises);
|
|
};
|
|
return { findAll: findAll };
|
|
}
|
|
|
|
var count$1 = 0;
|
|
var seed = function () {
|
|
var rnd = function () {
|
|
return Math.round(Math.random() * 4294967295).toString(36);
|
|
};
|
|
var now = new Date().getTime();
|
|
return 's' + now.toString(36) + rnd() + rnd() + rnd();
|
|
};
|
|
var uuid = function (prefix) {
|
|
return prefix + count$1++ + seed();
|
|
};
|
|
var Uuid = { uuid: uuid };
|
|
|
|
var BlobCache = function () {
|
|
var cache = [];
|
|
var mimeToExt = function (mime) {
|
|
var mimes = {
|
|
'image/jpeg': 'jpg',
|
|
'image/jpg': 'jpg',
|
|
'image/gif': 'gif',
|
|
'image/png': 'png'
|
|
};
|
|
return mimes[mime.toLowerCase()] || 'dat';
|
|
};
|
|
var create = function (o, blob, base64, filename) {
|
|
if (isString(o)) {
|
|
var id = o;
|
|
return toBlobInfo({
|
|
id: id,
|
|
name: filename,
|
|
blob: blob,
|
|
base64: base64
|
|
});
|
|
} else if (isObject(o)) {
|
|
return toBlobInfo(o);
|
|
} else {
|
|
throw new Error('Unknown input type');
|
|
}
|
|
};
|
|
var toBlobInfo = function (o) {
|
|
var id, name;
|
|
if (!o.blob || !o.base64) {
|
|
throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
|
|
}
|
|
id = o.id || Uuid.uuid('blobid');
|
|
name = o.name || id;
|
|
return {
|
|
id: constant(id),
|
|
name: constant(name),
|
|
filename: constant(name + '.' + mimeToExt(o.blob.type)),
|
|
blob: constant(o.blob),
|
|
base64: constant(o.base64),
|
|
blobUri: constant(o.blobUri || domGlobals.URL.createObjectURL(o.blob)),
|
|
uri: constant(o.uri)
|
|
};
|
|
};
|
|
var add = function (blobInfo) {
|
|
if (!get(blobInfo.id())) {
|
|
cache.push(blobInfo);
|
|
}
|
|
};
|
|
var get = function (id) {
|
|
return findFirst(function (cachedBlobInfo) {
|
|
return cachedBlobInfo.id() === id;
|
|
});
|
|
};
|
|
var findFirst = function (predicate) {
|
|
return filter(cache, predicate)[0];
|
|
};
|
|
var getByUri = function (blobUri) {
|
|
return findFirst(function (blobInfo) {
|
|
return blobInfo.blobUri() === blobUri;
|
|
});
|
|
};
|
|
var removeByUri = function (blobUri) {
|
|
cache = filter(cache, function (blobInfo) {
|
|
if (blobInfo.blobUri() === blobUri) {
|
|
domGlobals.URL.revokeObjectURL(blobInfo.blobUri());
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
};
|
|
var destroy = function () {
|
|
each(cache, function (cachedBlobInfo) {
|
|
domGlobals.URL.revokeObjectURL(cachedBlobInfo.blobUri());
|
|
});
|
|
cache = [];
|
|
};
|
|
return {
|
|
create: create,
|
|
add: add,
|
|
get: get,
|
|
getByUri: getByUri,
|
|
findFirst: findFirst,
|
|
removeByUri: removeByUri,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
|
|
function UploadStatus () {
|
|
var PENDING = 1, UPLOADED = 2;
|
|
var blobUriStatuses = {};
|
|
var createStatus = function (status, resultUri) {
|
|
return {
|
|
status: status,
|
|
resultUri: resultUri
|
|
};
|
|
};
|
|
var hasBlobUri = function (blobUri) {
|
|
return blobUri in blobUriStatuses;
|
|
};
|
|
var getResultUri = function (blobUri) {
|
|
var result = blobUriStatuses[blobUri];
|
|
return result ? result.resultUri : null;
|
|
};
|
|
var isPending = function (blobUri) {
|
|
return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
|
|
};
|
|
var isUploaded = function (blobUri) {
|
|
return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
|
|
};
|
|
var markPending = function (blobUri) {
|
|
blobUriStatuses[blobUri] = createStatus(PENDING, null);
|
|
};
|
|
var markUploaded = function (blobUri, resultUri) {
|
|
blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
|
|
};
|
|
var removeFailed = function (blobUri) {
|
|
delete blobUriStatuses[blobUri];
|
|
};
|
|
var destroy = function () {
|
|
blobUriStatuses = {};
|
|
};
|
|
return {
|
|
hasBlobUri: hasBlobUri,
|
|
getResultUri: getResultUri,
|
|
isPending: isPending,
|
|
isUploaded: isUploaded,
|
|
markPending: markPending,
|
|
markUploaded: markUploaded,
|
|
removeFailed: removeFailed,
|
|
destroy: destroy
|
|
};
|
|
}
|
|
|
|
var EditorUpload = function (editor) {
|
|
var blobCache = BlobCache();
|
|
var uploader, imageScanner;
|
|
var uploadStatus = UploadStatus();
|
|
var urlFilters = [];
|
|
var aliveGuard = function (callback) {
|
|
return function (result) {
|
|
if (editor.selection) {
|
|
return callback(result);
|
|
}
|
|
return [];
|
|
};
|
|
};
|
|
var cacheInvalidator = function () {
|
|
return '?' + new Date().getTime();
|
|
};
|
|
var replaceString = function (content, search, replace) {
|
|
var index = 0;
|
|
do {
|
|
index = content.indexOf(search, index);
|
|
if (index !== -1) {
|
|
content = content.substring(0, index) + replace + content.substr(index + search.length);
|
|
index += replace.length - search.length + 1;
|
|
}
|
|
} while (index !== -1);
|
|
return content;
|
|
};
|
|
var replaceImageUrl = function (content, targetUrl, replacementUrl) {
|
|
content = replaceString(content, 'src="' + targetUrl + '"', 'src="' + replacementUrl + '"');
|
|
content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
|
|
return content;
|
|
};
|
|
var replaceUrlInUndoStack = function (targetUrl, replacementUrl) {
|
|
each(editor.undoManager.data, function (level) {
|
|
if (level.type === 'fragmented') {
|
|
level.fragments = map(level.fragments, function (fragment) {
|
|
return replaceImageUrl(fragment, targetUrl, replacementUrl);
|
|
});
|
|
} else {
|
|
level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
|
|
}
|
|
});
|
|
};
|
|
var openNotification = function () {
|
|
return editor.notificationManager.open({
|
|
text: editor.translate('Image uploading...'),
|
|
type: 'info',
|
|
timeout: -1,
|
|
progressBar: true
|
|
});
|
|
};
|
|
var replaceImageUri = function (image, resultUri) {
|
|
blobCache.removeByUri(image.src);
|
|
replaceUrlInUndoStack(image.src, resultUri);
|
|
editor.$(image).attr({
|
|
'src': Settings.shouldReuseFileName(editor) ? resultUri + cacheInvalidator() : resultUri,
|
|
'data-mce-src': editor.convertURL(resultUri, 'src')
|
|
});
|
|
};
|
|
var uploadImages = function (callback) {
|
|
if (!uploader) {
|
|
uploader = Uploader(uploadStatus, {
|
|
url: Settings.getImageUploadUrl(editor),
|
|
basePath: Settings.getImageUploadBasePath(editor),
|
|
credentials: Settings.getImagesUploadCredentials(editor),
|
|
handler: Settings.getImagesUploadHandler(editor)
|
|
});
|
|
}
|
|
return scanForImages().then(aliveGuard(function (imageInfos) {
|
|
var blobInfos;
|
|
blobInfos = map(imageInfos, function (imageInfo) {
|
|
return imageInfo.blobInfo;
|
|
});
|
|
return uploader.upload(blobInfos, openNotification).then(aliveGuard(function (result) {
|
|
var filteredResult = map(result, function (uploadInfo, index) {
|
|
var image = imageInfos[index].image;
|
|
if (uploadInfo.status && Settings.shouldReplaceBlobUris(editor)) {
|
|
replaceImageUri(image, uploadInfo.url);
|
|
} else if (uploadInfo.error) {
|
|
ErrorReporter.uploadError(editor, uploadInfo.error);
|
|
}
|
|
return {
|
|
element: image,
|
|
status: uploadInfo.status
|
|
};
|
|
});
|
|
if (callback) {
|
|
callback(filteredResult);
|
|
}
|
|
return filteredResult;
|
|
}));
|
|
}));
|
|
};
|
|
var uploadImagesAuto = function (callback) {
|
|
if (Settings.isAutomaticUploadsEnabled(editor)) {
|
|
return uploadImages(callback);
|
|
}
|
|
};
|
|
var isValidDataUriImage = function (imgElm) {
|
|
if (forall(urlFilters, function (filter) {
|
|
return filter(imgElm);
|
|
}) === false) {
|
|
return false;
|
|
}
|
|
if (imgElm.getAttribute('src').indexOf('data:') === 0) {
|
|
var dataImgFilter = Settings.getImagesDataImgFilter(editor);
|
|
return dataImgFilter(imgElm);
|
|
}
|
|
return true;
|
|
};
|
|
var addFilter = function (filter) {
|
|
urlFilters.push(filter);
|
|
};
|
|
var scanForImages = function () {
|
|
if (!imageScanner) {
|
|
imageScanner = ImageScanner(uploadStatus, blobCache);
|
|
}
|
|
return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(function (result) {
|
|
result = filter(result, function (resultItem) {
|
|
if (typeof resultItem === 'string') {
|
|
ErrorReporter.displayError(editor, resultItem);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
each(result, function (resultItem) {
|
|
replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
|
|
resultItem.image.src = resultItem.blobInfo.blobUri();
|
|
resultItem.image.removeAttribute('data-mce-src');
|
|
});
|
|
return result;
|
|
}));
|
|
};
|
|
var destroy = function () {
|
|
blobCache.destroy();
|
|
uploadStatus.destroy();
|
|
imageScanner = uploader = null;
|
|
};
|
|
var replaceBlobUris = function (content) {
|
|
return content.replace(/src="(blob:[^"]+)"/g, function (match, blobUri) {
|
|
var resultUri = uploadStatus.getResultUri(blobUri);
|
|
if (resultUri) {
|
|
return 'src="' + resultUri + '"';
|
|
}
|
|
var blobInfo = blobCache.getByUri(blobUri);
|
|
if (!blobInfo) {
|
|
blobInfo = foldl(editor.editorManager.get(), function (result, editor) {
|
|
return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
|
|
}, null);
|
|
}
|
|
if (blobInfo) {
|
|
var blob = blobInfo.blob();
|
|
return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
|
|
}
|
|
return match;
|
|
});
|
|
};
|
|
editor.on('SetContent', function () {
|
|
if (Settings.isAutomaticUploadsEnabled(editor)) {
|
|
uploadImagesAuto();
|
|
} else {
|
|
scanForImages();
|
|
}
|
|
});
|
|
editor.on('RawSaveContent', function (e) {
|
|
e.content = replaceBlobUris(e.content);
|
|
});
|
|
editor.on('GetContent', function (e) {
|
|
if (e.source_view || e.format === 'raw') {
|
|
return;
|
|
}
|
|
e.content = replaceBlobUris(e.content);
|
|
});
|
|
editor.on('PostRender', function () {
|
|
editor.parser.addNodeFilter('img', function (images) {
|
|
each(images, function (img) {
|
|
var src = img.attr('src');
|
|
if (blobCache.getByUri(src)) {
|
|
return;
|
|
}
|
|
var resultUri = uploadStatus.getResultUri(src);
|
|
if (resultUri) {
|
|
img.attr('src', resultUri);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
return {
|
|
blobCache: blobCache,
|
|
addFilter: addFilter,
|
|
uploadImages: uploadImages,
|
|
uploadImagesAuto: uploadImagesAuto,
|
|
scanForImages: scanForImages,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
|
|
var dropLast = function (xs) {
|
|
return xs.slice(0, -1);
|
|
};
|
|
var parentsUntil$1 = function (start, root, predicate) {
|
|
if (contains$2(root, start)) {
|
|
return dropLast(parents(start, function (elm) {
|
|
return predicate(elm) || eq(elm, root);
|
|
}));
|
|
} else {
|
|
return [];
|
|
}
|
|
};
|
|
var parents$1 = function (start, root) {
|
|
return parentsUntil$1(start, root, constant(false));
|
|
};
|
|
var parentsAndSelf = function (start, root) {
|
|
return [start].concat(parents$1(start, root));
|
|
};
|
|
var Parents = {
|
|
parentsUntil: parentsUntil$1,
|
|
parents: parents$1,
|
|
parentsAndSelf: parentsAndSelf
|
|
};
|
|
|
|
var isBlockElement = function (blockElements, node) {
|
|
return blockElements.hasOwnProperty(node.nodeName);
|
|
};
|
|
var isValidTarget = function (blockElements, node) {
|
|
if (NodeType.isText(node)) {
|
|
return true;
|
|
} else if (NodeType.isElement(node)) {
|
|
return !isBlockElement(blockElements, node) && !Bookmarks.isBookmarkNode(node);
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var hasBlockParent = function (blockElements, root, node) {
|
|
return exists(Parents.parents(Element.fromDom(node), Element.fromDom(root)), function (elm) {
|
|
return isBlockElement(blockElements, elm.dom());
|
|
});
|
|
};
|
|
var shouldRemoveTextNode = function (blockElements, node) {
|
|
if (NodeType.isText(node)) {
|
|
if (node.nodeValue.length === 0) {
|
|
return true;
|
|
} else if (/^\s+$/.test(node.nodeValue) && (!node.nextSibling || isBlockElement(blockElements, node.nextSibling))) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var addRootBlocks = function (editor) {
|
|
var dom = editor.dom, selection = editor.selection;
|
|
var schema = editor.schema, blockElements = schema.getBlockElements();
|
|
var node = selection.getStart();
|
|
var rootNode = editor.getBody();
|
|
var rng;
|
|
var startContainer, startOffset, endContainer, endOffset, rootBlockNode;
|
|
var tempNode, wrapped, restoreSelection;
|
|
var rootNodeName;
|
|
var forcedRootBlock = Settings.getForcedRootBlock(editor);
|
|
if (!node || !NodeType.isElement(node) || !forcedRootBlock) {
|
|
return;
|
|
}
|
|
rootNodeName = rootNode.nodeName.toLowerCase();
|
|
if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, node)) {
|
|
return;
|
|
}
|
|
rng = selection.getRng();
|
|
startContainer = rng.startContainer;
|
|
startOffset = rng.startOffset;
|
|
endContainer = rng.endContainer;
|
|
endOffset = rng.endOffset;
|
|
restoreSelection = EditorFocus.hasFocus(editor);
|
|
node = rootNode.firstChild;
|
|
while (node) {
|
|
if (isValidTarget(blockElements, node)) {
|
|
if (shouldRemoveTextNode(blockElements, node)) {
|
|
tempNode = node;
|
|
node = node.nextSibling;
|
|
dom.remove(tempNode);
|
|
continue;
|
|
}
|
|
if (!rootBlockNode) {
|
|
rootBlockNode = dom.create(forcedRootBlock, Settings.getForcedRootBlockAttrs(editor));
|
|
node.parentNode.insertBefore(rootBlockNode, node);
|
|
wrapped = true;
|
|
}
|
|
tempNode = node;
|
|
node = node.nextSibling;
|
|
rootBlockNode.appendChild(tempNode);
|
|
} else {
|
|
rootBlockNode = null;
|
|
node = node.nextSibling;
|
|
}
|
|
}
|
|
if (wrapped && restoreSelection) {
|
|
rng.setStart(startContainer, startOffset);
|
|
rng.setEnd(endContainer, endOffset);
|
|
selection.setRng(rng);
|
|
editor.nodeChanged();
|
|
}
|
|
};
|
|
var setup$3 = function (editor) {
|
|
if (Settings.getForcedRootBlock(editor)) {
|
|
editor.on('NodeChange', curry(addRootBlocks, editor));
|
|
}
|
|
};
|
|
var ForceBlocks = { setup: setup$3 };
|
|
|
|
var isEq$1 = function (rng1, rng2) {
|
|
return rng1 && rng2 && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
|
|
};
|
|
var RangeCompare = { isEq: isEq$1 };
|
|
|
|
var getStartNode = function (rng) {
|
|
var sc = rng.startContainer, so = rng.startOffset;
|
|
if (NodeType.isText(sc)) {
|
|
return so === 0 ? Option.some(Element.fromDom(sc)) : Option.none();
|
|
} else {
|
|
return Option.from(sc.childNodes[so]).map(Element.fromDom);
|
|
}
|
|
};
|
|
var getEndNode = function (rng) {
|
|
var ec = rng.endContainer, eo = rng.endOffset;
|
|
if (NodeType.isText(ec)) {
|
|
return eo === ec.data.length ? Option.some(Element.fromDom(ec)) : Option.none();
|
|
} else {
|
|
return Option.from(ec.childNodes[eo - 1]).map(Element.fromDom);
|
|
}
|
|
};
|
|
var getFirstChildren = function (node) {
|
|
return firstChild(node).fold(constant([node]), function (child) {
|
|
return [node].concat(getFirstChildren(child));
|
|
});
|
|
};
|
|
var getLastChildren = function (node) {
|
|
return lastChild(node).fold(constant([node]), function (child) {
|
|
if (name(child) === 'br') {
|
|
return prevSibling(child).map(function (sibling) {
|
|
return [node].concat(getLastChildren(sibling));
|
|
}).getOr([]);
|
|
} else {
|
|
return [node].concat(getLastChildren(child));
|
|
}
|
|
});
|
|
};
|
|
var hasAllContentsSelected = function (elm, rng) {
|
|
return lift2(getStartNode(rng), getEndNode(rng), function (startNode, endNode) {
|
|
var start = find(getFirstChildren(elm), curry(eq, startNode));
|
|
var end = find(getLastChildren(elm), curry(eq, endNode));
|
|
return start.isSome() && end.isSome();
|
|
}).getOr(false);
|
|
};
|
|
var moveEndPoint$1 = function (dom, rng, node, start) {
|
|
var root = node, walker = new TreeWalker(node, root);
|
|
var nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
|
do {
|
|
if (node.nodeType === 3 && Tools.trim(node.nodeValue).length !== 0) {
|
|
if (start) {
|
|
rng.setStart(node, 0);
|
|
} else {
|
|
rng.setEnd(node, node.nodeValue.length);
|
|
}
|
|
return;
|
|
}
|
|
if (nonEmptyElementsMap[node.nodeName] && !/^(TD|TH)$/.test(node.nodeName)) {
|
|
if (start) {
|
|
rng.setStartBefore(node);
|
|
} else {
|
|
if (node.nodeName === 'BR') {
|
|
rng.setEndBefore(node);
|
|
} else {
|
|
rng.setEndAfter(node);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
} while (node = start ? walker.next() : walker.prev());
|
|
if (root.nodeName === 'BODY') {
|
|
if (start) {
|
|
rng.setStart(root, 0);
|
|
} else {
|
|
rng.setEnd(root, root.childNodes.length);
|
|
}
|
|
}
|
|
};
|
|
var hasAnyRanges = function (editor) {
|
|
var sel = editor.selection.getSel();
|
|
return sel && sel.rangeCount > 0;
|
|
};
|
|
|
|
var NodeChange = function () {
|
|
function NodeChange(editor) {
|
|
this.lastPath = [];
|
|
this.editor = editor;
|
|
var lastRng;
|
|
var self = this;
|
|
if (!('onselectionchange' in editor.getDoc())) {
|
|
editor.on('NodeChange click mouseup keyup focus', function (e) {
|
|
var nativeRng, fakeRng;
|
|
nativeRng = editor.selection.getRng();
|
|
fakeRng = {
|
|
startContainer: nativeRng.startContainer,
|
|
startOffset: nativeRng.startOffset,
|
|
endContainer: nativeRng.endContainer,
|
|
endOffset: nativeRng.endOffset
|
|
};
|
|
if (e.type === 'nodechange' || !RangeCompare.isEq(fakeRng, lastRng)) {
|
|
editor.fire('SelectionChange');
|
|
}
|
|
lastRng = fakeRng;
|
|
});
|
|
}
|
|
editor.on('contextmenu', function () {
|
|
editor.fire('SelectionChange');
|
|
});
|
|
editor.on('SelectionChange', function () {
|
|
var startElm = editor.selection.getStart(true);
|
|
if (!startElm || !Env.range && editor.selection.isCollapsed()) {
|
|
return;
|
|
}
|
|
if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
|
|
editor.nodeChanged({ selectionChange: true });
|
|
}
|
|
});
|
|
editor.on('mouseup', function (e) {
|
|
if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
|
|
if (editor.selection.getNode().nodeName === 'IMG') {
|
|
Delay.setEditorTimeout(editor, function () {
|
|
editor.nodeChanged();
|
|
});
|
|
} else {
|
|
editor.nodeChanged();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
NodeChange.prototype.nodeChanged = function (args) {
|
|
var selection = this.editor.selection;
|
|
var node, parents, root;
|
|
if (this.editor.initialized && selection && !this.editor.settings.disable_nodechange && !this.editor.readonly) {
|
|
root = this.editor.getBody();
|
|
node = selection.getStart(true) || root;
|
|
if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
|
|
node = root;
|
|
}
|
|
parents = [];
|
|
this.editor.dom.getParent(node, function (node) {
|
|
if (node === root) {
|
|
return true;
|
|
}
|
|
parents.push(node);
|
|
});
|
|
args = args || {};
|
|
args.element = node;
|
|
args.parents = parents;
|
|
this.editor.fire('NodeChange', args);
|
|
}
|
|
};
|
|
NodeChange.prototype.isSameElementPath = function (startElm) {
|
|
var i, currentPath;
|
|
currentPath = this.editor.$(startElm).parentsUntil(this.editor.getBody()).add(startElm);
|
|
if (currentPath.length === this.lastPath.length) {
|
|
for (i = currentPath.length; i >= 0; i--) {
|
|
if (currentPath[i] !== this.lastPath[i]) {
|
|
break;
|
|
}
|
|
}
|
|
if (i === -1) {
|
|
this.lastPath = currentPath;
|
|
return true;
|
|
}
|
|
}
|
|
this.lastPath = currentPath;
|
|
return false;
|
|
};
|
|
return NodeChange;
|
|
}();
|
|
|
|
var VK = {
|
|
BACKSPACE: 8,
|
|
DELETE: 46,
|
|
DOWN: 40,
|
|
ENTER: 13,
|
|
LEFT: 37,
|
|
RIGHT: 39,
|
|
SPACEBAR: 32,
|
|
TAB: 9,
|
|
UP: 38,
|
|
END: 35,
|
|
HOME: 36,
|
|
modifierPressed: function (e) {
|
|
return e.shiftKey || e.ctrlKey || e.altKey || this.metaKeyPressed(e);
|
|
},
|
|
metaKeyPressed: function (e) {
|
|
return Env.mac ? e.metaKey : e.ctrlKey && !e.altKey;
|
|
}
|
|
};
|
|
|
|
var is$2 = function (expected) {
|
|
return function (actual) {
|
|
return expected === actual;
|
|
};
|
|
};
|
|
var isNbsp = is$2('\xA0');
|
|
var isWhiteSpace$1 = function (chr) {
|
|
return /^[\r\n\t ]$/.test(chr);
|
|
};
|
|
var isContent = function (chr) {
|
|
return !isWhiteSpace$1(chr) && !isNbsp(chr);
|
|
};
|
|
|
|
var isChar = function (forward, predicate, pos) {
|
|
return Option.from(pos.container()).filter(NodeType.isText).exists(function (text) {
|
|
var delta = forward ? 0 : -1;
|
|
return predicate(text.data.charAt(pos.offset() + delta));
|
|
});
|
|
};
|
|
var isBeforeSpace = curry(isChar, true, isWhiteSpace$1);
|
|
var isAfterSpace = curry(isChar, false, isWhiteSpace$1);
|
|
var isEmptyText = function (pos) {
|
|
var container = pos.container();
|
|
return NodeType.isText(container) && container.data.length === 0;
|
|
};
|
|
var matchesElementPosition = function (before, predicate) {
|
|
return function (pos) {
|
|
return Option.from(getChildNodeAtRelativeOffset(before ? 0 : -1, pos)).filter(predicate).isSome();
|
|
};
|
|
};
|
|
var isImageBlock = function (node) {
|
|
return node.nodeName === 'IMG' && get$2(Element.fromDom(node), 'display') === 'block';
|
|
};
|
|
var isCefNode = function (node) {
|
|
return NodeType.isContentEditableFalse(node) && !NodeType.isBogusAll(node);
|
|
};
|
|
var isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
|
|
var isAfterImageBlock = matchesElementPosition(false, isImageBlock);
|
|
var isBeforeTable = matchesElementPosition(true, NodeType.isTable);
|
|
var isAfterTable = matchesElementPosition(false, NodeType.isTable);
|
|
var isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
|
|
var isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
|
|
|
|
var getNodeClientRects = function (node) {
|
|
var toArrayWithNode = function (clientRects) {
|
|
return map(clientRects, function (clientRect) {
|
|
clientRect = clone$1(clientRect);
|
|
clientRect.node = node;
|
|
return clientRect;
|
|
});
|
|
};
|
|
if (NodeType.isElement(node)) {
|
|
return toArrayWithNode(node.getClientRects());
|
|
}
|
|
if (NodeType.isText(node)) {
|
|
var rng = node.ownerDocument.createRange();
|
|
rng.setStart(node, 0);
|
|
rng.setEnd(node, node.data.length);
|
|
return toArrayWithNode(rng.getClientRects());
|
|
}
|
|
};
|
|
var getClientRects = function (node) {
|
|
return foldl(node, function (result, node) {
|
|
return result.concat(getNodeClientRects(node));
|
|
}, []);
|
|
};
|
|
|
|
var VDirection;
|
|
(function (VDirection) {
|
|
VDirection[VDirection['Up'] = -1] = 'Up';
|
|
VDirection[VDirection['Down'] = 1] = 'Down';
|
|
}(VDirection || (VDirection = {})));
|
|
var findUntil = function (direction, root, predicateFn, node) {
|
|
while (node = findNode(node, direction, isEditableCaretCandidate, root)) {
|
|
if (predicateFn(node)) {
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
var walkUntil = function (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) {
|
|
var line = 0, node;
|
|
var result = [];
|
|
var targetClientRect;
|
|
var add = function (node) {
|
|
var i, clientRect, clientRects;
|
|
clientRects = getClientRects([node]);
|
|
if (direction === -1) {
|
|
clientRects = clientRects.reverse();
|
|
}
|
|
for (i = 0; i < clientRects.length; i++) {
|
|
clientRect = clientRects[i];
|
|
if (isBeflowFn(clientRect, targetClientRect)) {
|
|
continue;
|
|
}
|
|
if (result.length > 0 && isAboveFn(clientRect, ArrUtils.last(result))) {
|
|
line++;
|
|
}
|
|
clientRect.line = line;
|
|
if (predicateFn(clientRect)) {
|
|
return true;
|
|
}
|
|
result.push(clientRect);
|
|
}
|
|
};
|
|
targetClientRect = ArrUtils.last(caretPosition.getClientRects());
|
|
if (!targetClientRect) {
|
|
return result;
|
|
}
|
|
node = caretPosition.getNode();
|
|
add(node);
|
|
findUntil(direction, root, add, node);
|
|
return result;
|
|
};
|
|
var aboveLineNumber = function (lineNumber, clientRect) {
|
|
return clientRect.line > lineNumber;
|
|
};
|
|
var isLineNumber = function (lineNumber, clientRect) {
|
|
return clientRect.line === lineNumber;
|
|
};
|
|
var upUntil = curry(walkUntil, VDirection.Up, isAbove, isBelow);
|
|
var downUntil = curry(walkUntil, VDirection.Down, isBelow, isAbove);
|
|
var positionsUntil = function (direction, root, predicateFn, node) {
|
|
var caretWalker = CaretWalker(root);
|
|
var walkFn, isBelowFn, isAboveFn, caretPosition;
|
|
var result = [];
|
|
var line = 0, clientRect, targetClientRect;
|
|
var getClientRect = function (caretPosition) {
|
|
if (direction === 1) {
|
|
return ArrUtils.last(caretPosition.getClientRects());
|
|
}
|
|
return ArrUtils.last(caretPosition.getClientRects());
|
|
};
|
|
if (direction === 1) {
|
|
walkFn = caretWalker.next;
|
|
isBelowFn = isBelow;
|
|
isAboveFn = isAbove;
|
|
caretPosition = CaretPosition$1.after(node);
|
|
} else {
|
|
walkFn = caretWalker.prev;
|
|
isBelowFn = isAbove;
|
|
isAboveFn = isBelow;
|
|
caretPosition = CaretPosition$1.before(node);
|
|
}
|
|
targetClientRect = getClientRect(caretPosition);
|
|
do {
|
|
if (!caretPosition.isVisible()) {
|
|
continue;
|
|
}
|
|
clientRect = getClientRect(caretPosition);
|
|
if (isAboveFn(clientRect, targetClientRect)) {
|
|
continue;
|
|
}
|
|
if (result.length > 0 && isBelowFn(clientRect, ArrUtils.last(result))) {
|
|
line++;
|
|
}
|
|
clientRect = clone$1(clientRect);
|
|
clientRect.position = caretPosition;
|
|
clientRect.line = line;
|
|
if (predicateFn(clientRect)) {
|
|
return result;
|
|
}
|
|
result.push(clientRect);
|
|
} while (caretPosition = walkFn(caretPosition));
|
|
return result;
|
|
};
|
|
var isAboveLine = function (lineNumber) {
|
|
return function (clientRect) {
|
|
return aboveLineNumber(lineNumber, clientRect);
|
|
};
|
|
};
|
|
var isLine = function (lineNumber) {
|
|
return function (clientRect) {
|
|
return isLineNumber(lineNumber, clientRect);
|
|
};
|
|
};
|
|
|
|
var isContentEditableFalse$6 = NodeType.isContentEditableFalse;
|
|
var findNode$1 = findNode;
|
|
var distanceToRectLeft = function (clientRect, clientX) {
|
|
return Math.abs(clientRect.left - clientX);
|
|
};
|
|
var distanceToRectRight = function (clientRect, clientX) {
|
|
return Math.abs(clientRect.right - clientX);
|
|
};
|
|
var isInside = function (clientX, clientRect) {
|
|
return clientX >= clientRect.left && clientX <= clientRect.right;
|
|
};
|
|
var findClosestClientRect = function (clientRects, clientX) {
|
|
return ArrUtils.reduce(clientRects, function (oldClientRect, clientRect) {
|
|
var oldDistance, newDistance;
|
|
oldDistance = Math.min(distanceToRectLeft(oldClientRect, clientX), distanceToRectRight(oldClientRect, clientX));
|
|
newDistance = Math.min(distanceToRectLeft(clientRect, clientX), distanceToRectRight(clientRect, clientX));
|
|
if (isInside(clientX, clientRect)) {
|
|
return clientRect;
|
|
}
|
|
if (isInside(clientX, oldClientRect)) {
|
|
return oldClientRect;
|
|
}
|
|
if (newDistance === oldDistance && isContentEditableFalse$6(clientRect.node)) {
|
|
return clientRect;
|
|
}
|
|
if (newDistance < oldDistance) {
|
|
return clientRect;
|
|
}
|
|
return oldClientRect;
|
|
});
|
|
};
|
|
var walkUntil$1 = function (direction, root, predicateFn, node) {
|
|
while (node = findNode$1(node, direction, isEditableCaretCandidate, root)) {
|
|
if (predicateFn(node)) {
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
var findLineNodeRects = function (root, targetNodeRect) {
|
|
var clientRects = [];
|
|
var collect = function (checkPosFn, node) {
|
|
var lineRects;
|
|
lineRects = filter(getClientRects([node]), function (clientRect) {
|
|
return !checkPosFn(clientRect, targetNodeRect);
|
|
});
|
|
clientRects = clientRects.concat(lineRects);
|
|
return lineRects.length === 0;
|
|
};
|
|
clientRects.push(targetNodeRect);
|
|
walkUntil$1(VDirection.Up, root, curry(collect, isAbove), targetNodeRect.node);
|
|
walkUntil$1(VDirection.Down, root, curry(collect, isBelow), targetNodeRect.node);
|
|
return clientRects;
|
|
};
|
|
var getFakeCaretTargets = function (root) {
|
|
return filter(from$1(root.getElementsByTagName('*')), isFakeCaretTarget);
|
|
};
|
|
var caretInfo = function (clientRect, clientX) {
|
|
return {
|
|
node: clientRect.node,
|
|
before: distanceToRectLeft(clientRect, clientX) < distanceToRectRight(clientRect, clientX)
|
|
};
|
|
};
|
|
var closestCaret = function (root, clientX, clientY) {
|
|
var closestNodeRect;
|
|
var contentEditableFalseNodeRects = getClientRects(getFakeCaretTargets(root));
|
|
var targetNodeRects = filter(contentEditableFalseNodeRects, function (rect) {
|
|
return clientY >= rect.top && clientY <= rect.bottom;
|
|
});
|
|
closestNodeRect = findClosestClientRect(targetNodeRects, clientX);
|
|
if (closestNodeRect) {
|
|
closestNodeRect = findClosestClientRect(findLineNodeRects(root, closestNodeRect), clientX);
|
|
if (closestNodeRect && isFakeCaretTarget(closestNodeRect.node)) {
|
|
return caretInfo(closestNodeRect, clientX);
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
var isXYWithinRange = function (clientX, clientY, range) {
|
|
if (range.collapsed) {
|
|
return false;
|
|
}
|
|
if (Env.browser.isIE() && range.startOffset === range.endOffset - 1 && range.startContainer === range.endContainer) {
|
|
var elm = range.startContainer.childNodes[range.startOffset];
|
|
if (NodeType.isElement(elm)) {
|
|
return exists(elm.getClientRects(), function (rect) {
|
|
return containsXY(rect, clientX, clientY);
|
|
});
|
|
}
|
|
}
|
|
return exists(range.getClientRects(), function (rect) {
|
|
return containsXY(rect, clientX, clientY);
|
|
});
|
|
};
|
|
var RangePoint = { isXYWithinRange: isXYWithinRange };
|
|
|
|
var getAbsolutePosition = function (elm) {
|
|
var doc, docElem, win, clientRect;
|
|
clientRect = elm.getBoundingClientRect();
|
|
doc = elm.ownerDocument;
|
|
docElem = doc.documentElement;
|
|
win = doc.defaultView;
|
|
return {
|
|
top: clientRect.top + win.pageYOffset - docElem.clientTop,
|
|
left: clientRect.left + win.pageXOffset - docElem.clientLeft
|
|
};
|
|
};
|
|
var getBodyPosition = function (editor) {
|
|
return editor.inline ? getAbsolutePosition(editor.getBody()) : {
|
|
left: 0,
|
|
top: 0
|
|
};
|
|
};
|
|
var getScrollPosition = function (editor) {
|
|
var body = editor.getBody();
|
|
return editor.inline ? {
|
|
left: body.scrollLeft,
|
|
top: body.scrollTop
|
|
} : {
|
|
left: 0,
|
|
top: 0
|
|
};
|
|
};
|
|
var getBodyScroll = function (editor) {
|
|
var body = editor.getBody(), docElm = editor.getDoc().documentElement;
|
|
var inlineScroll = {
|
|
left: body.scrollLeft,
|
|
top: body.scrollTop
|
|
};
|
|
var iframeScroll = {
|
|
left: body.scrollLeft || docElm.scrollLeft,
|
|
top: body.scrollTop || docElm.scrollTop
|
|
};
|
|
return editor.inline ? inlineScroll : iframeScroll;
|
|
};
|
|
var getMousePosition = function (editor, event) {
|
|
if (event.target.ownerDocument !== editor.getDoc()) {
|
|
var iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
|
|
var scrollPosition = getBodyScroll(editor);
|
|
return {
|
|
left: event.pageX - iframePosition.left + scrollPosition.left,
|
|
top: event.pageY - iframePosition.top + scrollPosition.top
|
|
};
|
|
}
|
|
return {
|
|
left: event.pageX,
|
|
top: event.pageY
|
|
};
|
|
};
|
|
var calculatePosition = function (bodyPosition, scrollPosition, mousePosition) {
|
|
return {
|
|
pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
|
|
pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
|
|
};
|
|
};
|
|
var calc = function (editor, event) {
|
|
return calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
|
|
};
|
|
var MousePosition = { calc: calc };
|
|
|
|
var isContentEditableFalse$7 = NodeType.isContentEditableFalse, isContentEditableTrue$2 = NodeType.isContentEditableTrue;
|
|
var isDraggable = function (rootElm, elm) {
|
|
return isContentEditableFalse$7(elm) && elm !== rootElm;
|
|
};
|
|
var isValidDropTarget = function (editor, targetElement, dragElement) {
|
|
if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
|
|
return false;
|
|
}
|
|
return !isContentEditableFalse$7(targetElement);
|
|
};
|
|
var cloneElement = function (elm) {
|
|
var cloneElm = elm.cloneNode(true);
|
|
cloneElm.removeAttribute('data-mce-selected');
|
|
return cloneElm;
|
|
};
|
|
var createGhost = function (editor, elm, width, height) {
|
|
var clonedElm = elm.cloneNode(true);
|
|
editor.dom.setStyles(clonedElm, {
|
|
width: width,
|
|
height: height
|
|
});
|
|
editor.dom.setAttrib(clonedElm, 'data-mce-selected', null);
|
|
var ghostElm = editor.dom.create('div', {
|
|
'class': 'mce-drag-container',
|
|
'data-mce-bogus': 'all',
|
|
'unselectable': 'on',
|
|
'contenteditable': 'false'
|
|
});
|
|
editor.dom.setStyles(ghostElm, {
|
|
position: 'absolute',
|
|
opacity: 0.5,
|
|
overflow: 'hidden',
|
|
border: 0,
|
|
padding: 0,
|
|
margin: 0,
|
|
width: width,
|
|
height: height
|
|
});
|
|
editor.dom.setStyles(clonedElm, {
|
|
margin: 0,
|
|
boxSizing: 'border-box'
|
|
});
|
|
ghostElm.appendChild(clonedElm);
|
|
return ghostElm;
|
|
};
|
|
var appendGhostToBody = function (ghostElm, bodyElm) {
|
|
if (ghostElm.parentNode !== bodyElm) {
|
|
bodyElm.appendChild(ghostElm);
|
|
}
|
|
};
|
|
var moveGhost = function (ghostElm, position, width, height, maxX, maxY) {
|
|
var overflowX = 0, overflowY = 0;
|
|
ghostElm.style.left = position.pageX + 'px';
|
|
ghostElm.style.top = position.pageY + 'px';
|
|
if (position.pageX + width > maxX) {
|
|
overflowX = position.pageX + width - maxX;
|
|
}
|
|
if (position.pageY + height > maxY) {
|
|
overflowY = position.pageY + height - maxY;
|
|
}
|
|
ghostElm.style.width = width - overflowX + 'px';
|
|
ghostElm.style.height = height - overflowY + 'px';
|
|
};
|
|
var removeElement = function (elm) {
|
|
if (elm && elm.parentNode) {
|
|
elm.parentNode.removeChild(elm);
|
|
}
|
|
};
|
|
var isLeftMouseButtonPressed = function (e) {
|
|
return e.button === 0;
|
|
};
|
|
var hasDraggableElement = function (state) {
|
|
return state.element;
|
|
};
|
|
var applyRelPos = function (state, position) {
|
|
return {
|
|
pageX: position.pageX - state.relX,
|
|
pageY: position.pageY + 5
|
|
};
|
|
};
|
|
var start = function (state, editor) {
|
|
return function (e) {
|
|
if (isLeftMouseButtonPressed(e)) {
|
|
var ceElm = find(editor.dom.getParents(e.target), Predicate.or(isContentEditableFalse$7, isContentEditableTrue$2)).getOr(null);
|
|
if (isDraggable(editor.getBody(), ceElm)) {
|
|
var elmPos = editor.dom.getPos(ceElm);
|
|
var bodyElm = editor.getBody();
|
|
var docElm = editor.getDoc().documentElement;
|
|
state.element = ceElm;
|
|
state.screenX = e.screenX;
|
|
state.screenY = e.screenY;
|
|
state.maxX = (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2;
|
|
state.maxY = (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2;
|
|
state.relX = e.pageX - elmPos.x;
|
|
state.relY = e.pageY - elmPos.y;
|
|
state.width = ceElm.offsetWidth;
|
|
state.height = ceElm.offsetHeight;
|
|
state.ghost = createGhost(editor, ceElm, state.width, state.height);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
var move = function (state, editor) {
|
|
var throttledPlaceCaretAt = Delay.throttle(function (clientX, clientY) {
|
|
editor._selectionOverrides.hideFakeCaret();
|
|
editor.selection.placeCaretAt(clientX, clientY);
|
|
}, 0);
|
|
return function (e) {
|
|
var movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
|
|
if (hasDraggableElement(state) && !state.dragging && movement > 10) {
|
|
var args = editor.fire('dragstart', { target: state.element });
|
|
if (args.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
state.dragging = true;
|
|
editor.focus();
|
|
}
|
|
if (state.dragging) {
|
|
var targetPos = applyRelPos(state, MousePosition.calc(editor, e));
|
|
appendGhostToBody(state.ghost, editor.getBody());
|
|
moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY);
|
|
throttledPlaceCaretAt(e.clientX, e.clientY);
|
|
}
|
|
};
|
|
};
|
|
var getRawTarget = function (selection) {
|
|
var rng = selection.getSel().getRangeAt(0);
|
|
var startContainer = rng.startContainer;
|
|
return startContainer.nodeType === 3 ? startContainer.parentNode : startContainer;
|
|
};
|
|
var drop = function (state, editor) {
|
|
return function (e) {
|
|
if (state.dragging) {
|
|
if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
|
|
var targetClone_1 = cloneElement(state.element);
|
|
var args = editor.fire('drop', {
|
|
targetClone: targetClone_1,
|
|
clientX: e.clientX,
|
|
clientY: e.clientY
|
|
});
|
|
if (!args.isDefaultPrevented()) {
|
|
targetClone_1 = args.targetClone;
|
|
editor.undoManager.transact(function () {
|
|
removeElement(state.element);
|
|
editor.insertContent(editor.dom.getOuterHTML(targetClone_1));
|
|
editor._selectionOverrides.hideFakeCaret();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
removeDragState(state);
|
|
};
|
|
};
|
|
var stop = function (state, editor) {
|
|
return function () {
|
|
if (state.dragging) {
|
|
editor.fire('dragend');
|
|
}
|
|
removeDragState(state);
|
|
};
|
|
};
|
|
var removeDragState = function (state) {
|
|
state.dragging = false;
|
|
state.element = null;
|
|
removeElement(state.ghost);
|
|
};
|
|
var bindFakeDragEvents = function (editor) {
|
|
var state = {};
|
|
var pageDom, dragStartHandler, dragHandler, dropHandler, dragEndHandler, rootDocument;
|
|
pageDom = DOMUtils$1.DOM;
|
|
rootDocument = domGlobals.document;
|
|
dragStartHandler = start(state, editor);
|
|
dragHandler = move(state, editor);
|
|
dropHandler = drop(state, editor);
|
|
dragEndHandler = stop(state, editor);
|
|
editor.on('mousedown', dragStartHandler);
|
|
editor.on('mousemove', dragHandler);
|
|
editor.on('mouseup', dropHandler);
|
|
pageDom.bind(rootDocument, 'mousemove', dragHandler);
|
|
pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
|
|
editor.on('remove', function () {
|
|
pageDom.unbind(rootDocument, 'mousemove', dragHandler);
|
|
pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
|
|
});
|
|
};
|
|
var blockIeDrop = function (editor) {
|
|
editor.on('drop', function (e) {
|
|
var realTarget = typeof e.clientX !== 'undefined' ? editor.getDoc().elementFromPoint(e.clientX, e.clientY) : null;
|
|
if (isContentEditableFalse$7(realTarget) || isContentEditableFalse$7(editor.dom.getContentEditableParent(realTarget))) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
};
|
|
var init = function (editor) {
|
|
bindFakeDragEvents(editor);
|
|
blockIeDrop(editor);
|
|
};
|
|
var DragDropOverrides = { init: init };
|
|
|
|
var isContentEditableTrue$3 = NodeType.isContentEditableTrue;
|
|
var isContentEditableFalse$8 = NodeType.isContentEditableFalse;
|
|
var showCaret = function (direction, editor, node, before, scrollIntoView) {
|
|
return editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView);
|
|
};
|
|
var getNodeRange = function (node) {
|
|
var rng = node.ownerDocument.createRange();
|
|
rng.selectNode(node);
|
|
return rng;
|
|
};
|
|
var selectNode = function (editor, node) {
|
|
var e = editor.fire('BeforeObjectSelected', { target: node });
|
|
if (e.isDefaultPrevented()) {
|
|
return null;
|
|
}
|
|
return getNodeRange(node);
|
|
};
|
|
var renderCaretAtRange = function (editor, range, scrollIntoView) {
|
|
var normalizedRange = normalizeRange(1, editor.getBody(), range);
|
|
var caretPosition = CaretPosition$1.fromRangeStart(normalizedRange);
|
|
var caretPositionNode = caretPosition.getNode();
|
|
if (isContentEditableFalse$8(caretPositionNode)) {
|
|
return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
|
|
}
|
|
var caretPositionBeforeNode = caretPosition.getNode(true);
|
|
if (isContentEditableFalse$8(caretPositionBeforeNode)) {
|
|
return showCaret(1, editor, caretPositionBeforeNode, false, false);
|
|
}
|
|
var ceRoot = editor.dom.getParent(caretPosition.getNode(), function (node) {
|
|
return isContentEditableFalse$8(node) || isContentEditableTrue$3(node);
|
|
});
|
|
if (isContentEditableFalse$8(ceRoot)) {
|
|
return showCaret(1, editor, ceRoot, false, scrollIntoView);
|
|
}
|
|
return null;
|
|
};
|
|
var renderRangeCaret = function (editor, range, scrollIntoView) {
|
|
if (!range || !range.collapsed) {
|
|
return range;
|
|
}
|
|
var caretRange = renderCaretAtRange(editor, range, scrollIntoView);
|
|
if (caretRange) {
|
|
return caretRange;
|
|
}
|
|
return range;
|
|
};
|
|
|
|
var setup$4 = function (editor) {
|
|
var renderFocusCaret = first(function () {
|
|
if (!editor.removed && editor.getBody().contains(domGlobals.document.activeElement)) {
|
|
var rng = editor.selection.getRng();
|
|
if (rng.collapsed) {
|
|
var caretRange = renderRangeCaret(editor, editor.selection.getRng(), false);
|
|
editor.selection.setRng(caretRange);
|
|
}
|
|
}
|
|
}, 0);
|
|
editor.on('focus', function () {
|
|
renderFocusCaret.throttle();
|
|
});
|
|
editor.on('blur', function () {
|
|
renderFocusCaret.cancel();
|
|
});
|
|
};
|
|
var CefFocus = { setup: setup$4 };
|
|
|
|
var isContentEditableTrue$4 = NodeType.isContentEditableTrue;
|
|
var isContentEditableFalse$9 = NodeType.isContentEditableFalse;
|
|
var getContentEditableRoot = function (editor, node) {
|
|
var root = editor.getBody();
|
|
while (node && node !== root) {
|
|
if (isContentEditableTrue$4(node) || isContentEditableFalse$9(node)) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var SelectionOverrides = function (editor) {
|
|
var isBlock = function (node) {
|
|
return editor.dom.isBlock(node);
|
|
};
|
|
var rootNode = editor.getBody();
|
|
var fakeCaret = FakeCaret(editor.getBody(), isBlock, function () {
|
|
return EditorFocus.hasFocus(editor);
|
|
});
|
|
var realSelectionId = 'sel-' + editor.dom.uniqueId();
|
|
var selectedContentEditableNode;
|
|
var isFakeSelectionElement = function (elm) {
|
|
return editor.dom.hasClass(elm, 'mce-offscreen-selection');
|
|
};
|
|
var getRealSelectionElement = function () {
|
|
var container = editor.dom.get(realSelectionId);
|
|
return container ? container.getElementsByTagName('*')[0] : container;
|
|
};
|
|
var setRange = function (range) {
|
|
if (range) {
|
|
editor.selection.setRng(range);
|
|
}
|
|
};
|
|
var getRange = function () {
|
|
return editor.selection.getRng();
|
|
};
|
|
var showCaret = function (direction, node, before, scrollIntoView) {
|
|
if (scrollIntoView === void 0) {
|
|
scrollIntoView = true;
|
|
}
|
|
var e;
|
|
e = editor.fire('ShowCaret', {
|
|
target: node,
|
|
direction: direction,
|
|
before: before
|
|
});
|
|
if (e.isDefaultPrevented()) {
|
|
return null;
|
|
}
|
|
if (scrollIntoView) {
|
|
editor.selection.scrollIntoView(node, direction === -1);
|
|
}
|
|
return fakeCaret.show(before, node);
|
|
};
|
|
var showBlockCaretContainer = function (blockCaretContainer) {
|
|
if (blockCaretContainer.hasAttribute('data-mce-caret')) {
|
|
showCaretContainerBlock(blockCaretContainer);
|
|
setRange(getRange());
|
|
editor.selection.scrollIntoView(blockCaretContainer[0]);
|
|
}
|
|
};
|
|
var registerEvents = function () {
|
|
editor.on('mouseup', function (e) {
|
|
var range = getRange();
|
|
if (range.collapsed && EditorView.isXYInContentArea(editor, e.clientX, e.clientY)) {
|
|
setRange(renderCaretAtRange(editor, range, false));
|
|
}
|
|
});
|
|
editor.on('click', function (e) {
|
|
var contentEditableRoot;
|
|
contentEditableRoot = getContentEditableRoot(editor, e.target);
|
|
if (contentEditableRoot) {
|
|
if (isContentEditableFalse$9(contentEditableRoot)) {
|
|
e.preventDefault();
|
|
editor.focus();
|
|
}
|
|
if (isContentEditableTrue$4(contentEditableRoot)) {
|
|
if (editor.dom.isChildOf(contentEditableRoot, editor.selection.getNode())) {
|
|
removeContentEditableSelection();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
editor.on('blur NewBlock', function () {
|
|
removeContentEditableSelection();
|
|
});
|
|
editor.on('ResizeWindow FullscreenStateChanged', function () {
|
|
return fakeCaret.reposition();
|
|
});
|
|
var handleTouchSelect = function (editor) {
|
|
var moved = false;
|
|
editor.on('touchstart', function () {
|
|
moved = false;
|
|
});
|
|
editor.on('touchmove', function () {
|
|
moved = true;
|
|
});
|
|
editor.on('touchend', function (e) {
|
|
if (!moved) {
|
|
var contentEditableRoot = getContentEditableRoot(editor, e.target);
|
|
if (isContentEditableFalse$9(contentEditableRoot)) {
|
|
e.preventDefault();
|
|
setContentEditableSelection(selectNode(editor, contentEditableRoot));
|
|
}
|
|
}
|
|
}, true);
|
|
};
|
|
var hasNormalCaretPosition = function (elm) {
|
|
var caretWalker = CaretWalker(elm);
|
|
if (!elm.firstChild) {
|
|
return false;
|
|
}
|
|
var startPos = CaretPosition$1.before(elm.firstChild);
|
|
var newPos = caretWalker.next(startPos);
|
|
return newPos && !isBeforeContentEditableFalse(newPos) && !isAfterContentEditableFalse(newPos);
|
|
};
|
|
var isInSameBlock = function (node1, node2) {
|
|
var block1 = editor.dom.getParent(node1, editor.dom.isBlock);
|
|
var block2 = editor.dom.getParent(node2, editor.dom.isBlock);
|
|
return block1 === block2;
|
|
};
|
|
var hasBetterMouseTarget = function (targetNode, caretNode) {
|
|
var targetBlock = editor.dom.getParent(targetNode, editor.dom.isBlock);
|
|
var caretBlock = editor.dom.getParent(caretNode, editor.dom.isBlock);
|
|
if (targetBlock && editor.dom.isChildOf(targetBlock, caretBlock) && isContentEditableFalse$9(getContentEditableRoot(editor, targetBlock)) === false) {
|
|
return true;
|
|
}
|
|
return targetBlock && !isInSameBlock(targetBlock, caretBlock) && hasNormalCaretPosition(targetBlock);
|
|
};
|
|
handleTouchSelect(editor);
|
|
editor.on('mousedown', function (e) {
|
|
var contentEditableRoot;
|
|
var targetElm = e.target;
|
|
if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !editor.dom.isChildOf(targetElm, rootNode)) {
|
|
return;
|
|
}
|
|
if (EditorView.isXYInContentArea(editor, e.clientX, e.clientY) === false) {
|
|
return;
|
|
}
|
|
contentEditableRoot = getContentEditableRoot(editor, targetElm);
|
|
if (contentEditableRoot) {
|
|
if (isContentEditableFalse$9(contentEditableRoot)) {
|
|
e.preventDefault();
|
|
setContentEditableSelection(selectNode(editor, contentEditableRoot));
|
|
} else {
|
|
removeContentEditableSelection();
|
|
if (!(isContentEditableTrue$4(contentEditableRoot) && e.shiftKey) && !RangePoint.isXYWithinRange(e.clientX, e.clientY, editor.selection.getRng())) {
|
|
hideFakeCaret();
|
|
editor.selection.placeCaretAt(e.clientX, e.clientY);
|
|
}
|
|
}
|
|
} else if (isFakeCaretTarget(targetElm) === false) {
|
|
removeContentEditableSelection();
|
|
hideFakeCaret();
|
|
var caretInfo = closestCaret(rootNode, e.clientX, e.clientY);
|
|
if (caretInfo) {
|
|
if (!hasBetterMouseTarget(e.target, caretInfo.node)) {
|
|
e.preventDefault();
|
|
var range = showCaret(1, caretInfo.node, caretInfo.before, false);
|
|
editor.getBody().focus();
|
|
setRange(range);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
editor.on('keypress', function (e) {
|
|
if (VK.modifierPressed(e)) {
|
|
return;
|
|
}
|
|
switch (e.keyCode) {
|
|
default:
|
|
if (isContentEditableFalse$9(editor.selection.getNode())) {
|
|
e.preventDefault();
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
editor.on('GetSelectionRange', function (e) {
|
|
var rng = e.range;
|
|
if (selectedContentEditableNode) {
|
|
if (!selectedContentEditableNode.parentNode) {
|
|
selectedContentEditableNode = null;
|
|
return;
|
|
}
|
|
rng = rng.cloneRange();
|
|
rng.selectNode(selectedContentEditableNode);
|
|
e.range = rng;
|
|
}
|
|
});
|
|
editor.on('SetSelectionRange', function (e) {
|
|
e.range = normalizeShortEndedElementSelection(e.range);
|
|
var rng = setContentEditableSelection(e.range, e.forward);
|
|
if (rng) {
|
|
e.range = rng;
|
|
}
|
|
});
|
|
var isPasteBin = function (node) {
|
|
return node.id === 'mcepastebin';
|
|
};
|
|
editor.on('AfterSetSelectionRange', function (e) {
|
|
var rng = e.range;
|
|
if (!isRangeInCaretContainer(rng) && !isPasteBin(rng.startContainer.parentNode)) {
|
|
hideFakeCaret();
|
|
}
|
|
if (!isFakeSelectionElement(rng.startContainer.parentNode)) {
|
|
removeContentEditableSelection();
|
|
}
|
|
});
|
|
editor.on('copy', function (e) {
|
|
var clipboardData = e.clipboardData;
|
|
if (!e.isDefaultPrevented() && e.clipboardData && !Env.ie) {
|
|
var realSelectionElement = getRealSelectionElement();
|
|
if (realSelectionElement) {
|
|
e.preventDefault();
|
|
clipboardData.clearData();
|
|
clipboardData.setData('text/html', realSelectionElement.outerHTML);
|
|
clipboardData.setData('text/plain', realSelectionElement.outerText);
|
|
}
|
|
}
|
|
});
|
|
DragDropOverrides.init(editor);
|
|
CefFocus.setup(editor);
|
|
};
|
|
var isWithinCaretContainer = function (node) {
|
|
return isCaretContainer(node) || startsWithCaretContainer(node) || endsWithCaretContainer(node);
|
|
};
|
|
var isRangeInCaretContainer = function (rng) {
|
|
return isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
|
|
};
|
|
var normalizeShortEndedElementSelection = function (rng) {
|
|
var shortEndedElements = editor.schema.getShortEndedElements();
|
|
var newRng = editor.dom.createRng();
|
|
var startContainer = rng.startContainer;
|
|
var startOffset = rng.startOffset;
|
|
var endContainer = rng.endContainer;
|
|
var endOffset = rng.endOffset;
|
|
if (has(shortEndedElements, startContainer.nodeName.toLowerCase())) {
|
|
if (startOffset === 0) {
|
|
newRng.setStartBefore(startContainer);
|
|
} else {
|
|
newRng.setStartAfter(startContainer);
|
|
}
|
|
} else {
|
|
newRng.setStart(startContainer, startOffset);
|
|
}
|
|
if (has(shortEndedElements, endContainer.nodeName.toLowerCase())) {
|
|
if (endOffset === 0) {
|
|
newRng.setEndBefore(endContainer);
|
|
} else {
|
|
newRng.setEndAfter(endContainer);
|
|
}
|
|
} else {
|
|
newRng.setEnd(endContainer, endOffset);
|
|
}
|
|
return newRng;
|
|
};
|
|
var setContentEditableSelection = function (range, forward) {
|
|
var node;
|
|
var $ = editor.$;
|
|
var dom = editor.dom;
|
|
var $realSelectionContainer, sel, startContainer, startOffset, endOffset, e, caretPosition, targetClone, origTargetClone;
|
|
if (!range) {
|
|
return null;
|
|
}
|
|
if (range.collapsed) {
|
|
if (!isRangeInCaretContainer(range)) {
|
|
if (forward === false) {
|
|
caretPosition = getNormalizedRangeEndPoint(-1, rootNode, range);
|
|
if (isFakeCaretTarget(caretPosition.getNode(true))) {
|
|
return showCaret(-1, caretPosition.getNode(true), false, false);
|
|
}
|
|
if (isFakeCaretTarget(caretPosition.getNode())) {
|
|
return showCaret(-1, caretPosition.getNode(), !caretPosition.isAtEnd(), false);
|
|
}
|
|
} else {
|
|
caretPosition = getNormalizedRangeEndPoint(1, rootNode, range);
|
|
if (isFakeCaretTarget(caretPosition.getNode())) {
|
|
return showCaret(1, caretPosition.getNode(), !caretPosition.isAtEnd(), false);
|
|
}
|
|
if (isFakeCaretTarget(caretPosition.getNode(true))) {
|
|
return showCaret(1, caretPosition.getNode(true), false, false);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
startContainer = range.startContainer;
|
|
startOffset = range.startOffset;
|
|
endOffset = range.endOffset;
|
|
if (startContainer.nodeType === 3 && startOffset === 0 && isContentEditableFalse$9(startContainer.parentNode)) {
|
|
startContainer = startContainer.parentNode;
|
|
startOffset = dom.nodeIndex(startContainer);
|
|
startContainer = startContainer.parentNode;
|
|
}
|
|
if (startContainer.nodeType !== 1) {
|
|
return null;
|
|
}
|
|
if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
|
|
node = startContainer.childNodes[startOffset];
|
|
}
|
|
if (!isContentEditableFalse$9(node)) {
|
|
return null;
|
|
}
|
|
targetClone = origTargetClone = node.cloneNode(true);
|
|
e = editor.fire('ObjectSelected', {
|
|
target: node,
|
|
targetClone: targetClone
|
|
});
|
|
if (e.isDefaultPrevented()) {
|
|
return null;
|
|
}
|
|
$realSelectionContainer = descendant(Element.fromDom(editor.getBody()), '#' + realSelectionId).fold(function () {
|
|
return $([]);
|
|
}, function (elm) {
|
|
return $([elm.dom()]);
|
|
});
|
|
targetClone = e.targetClone;
|
|
if ($realSelectionContainer.length === 0) {
|
|
$realSelectionContainer = $('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>').attr('id', realSelectionId);
|
|
$realSelectionContainer.appendTo(editor.getBody());
|
|
}
|
|
range = editor.dom.createRng();
|
|
if (targetClone === origTargetClone && Env.ie) {
|
|
$realSelectionContainer.empty().append('<p style="font-size: 0" data-mce-bogus="all">\xA0</p>').append(targetClone);
|
|
range.setStartAfter($realSelectionContainer[0].firstChild.firstChild);
|
|
range.setEndAfter(targetClone);
|
|
} else {
|
|
$realSelectionContainer.empty().append('\xA0').append(targetClone).append('\xA0');
|
|
range.setStart($realSelectionContainer[0].firstChild, 1);
|
|
range.setEnd($realSelectionContainer[0].lastChild, 0);
|
|
}
|
|
$realSelectionContainer.css({ top: dom.getPos(node, editor.getBody()).y });
|
|
$realSelectionContainer[0].focus();
|
|
sel = editor.selection.getSel();
|
|
sel.removeAllRanges();
|
|
sel.addRange(range);
|
|
var nodeElm = Element.fromDom(node);
|
|
each(descendants$1(Element.fromDom(editor.getBody()), '*[data-mce-selected]'), function (elm) {
|
|
if (!eq(nodeElm, elm)) {
|
|
remove(elm, 'data-mce-selected');
|
|
}
|
|
});
|
|
if (!editor.dom.getAttrib(node, 'data-mce-selected')) {
|
|
node.setAttribute('data-mce-selected', '1');
|
|
}
|
|
selectedContentEditableNode = node;
|
|
hideFakeCaret();
|
|
return range;
|
|
};
|
|
var removeContentEditableSelection = function () {
|
|
if (selectedContentEditableNode) {
|
|
selectedContentEditableNode.removeAttribute('data-mce-selected');
|
|
descendant(Element.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$1);
|
|
selectedContentEditableNode = null;
|
|
}
|
|
descendant(Element.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$1);
|
|
selectedContentEditableNode = null;
|
|
};
|
|
var destroy = function () {
|
|
fakeCaret.destroy();
|
|
selectedContentEditableNode = null;
|
|
};
|
|
var hideFakeCaret = function () {
|
|
fakeCaret.hide();
|
|
};
|
|
if (Env.ceFalse) {
|
|
registerEvents();
|
|
}
|
|
return {
|
|
showCaret: showCaret,
|
|
showBlockCaretContainer: showBlockCaretContainer,
|
|
hideFakeCaret: hideFakeCaret,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
|
|
var KEEP = 0, INSERT = 1, DELETE = 2;
|
|
var diff = function (left, right) {
|
|
var size = left.length + right.length + 2;
|
|
var vDown = new Array(size);
|
|
var vUp = new Array(size);
|
|
var snake = function (start, end, diag) {
|
|
return {
|
|
start: start,
|
|
end: end,
|
|
diag: diag
|
|
};
|
|
};
|
|
var buildScript = function (start1, end1, start2, end2, script) {
|
|
var middle = getMiddleSnake(start1, end1, start2, end2);
|
|
if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
|
|
var i = start1;
|
|
var j = start2;
|
|
while (i < end1 || j < end2) {
|
|
if (i < end1 && j < end2 && left[i] === right[j]) {
|
|
script.push([
|
|
KEEP,
|
|
left[i]
|
|
]);
|
|
++i;
|
|
++j;
|
|
} else {
|
|
if (end1 - start1 > end2 - start2) {
|
|
script.push([
|
|
DELETE,
|
|
left[i]
|
|
]);
|
|
++i;
|
|
} else {
|
|
script.push([
|
|
INSERT,
|
|
right[j]
|
|
]);
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
|
|
for (var i2 = middle.start; i2 < middle.end; ++i2) {
|
|
script.push([
|
|
KEEP,
|
|
left[i2]
|
|
]);
|
|
}
|
|
buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
|
|
}
|
|
};
|
|
var buildSnake = function (start, diag, end1, end2) {
|
|
var end = start;
|
|
while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
|
|
++end;
|
|
}
|
|
return snake(start, end, diag);
|
|
};
|
|
var getMiddleSnake = function (start1, end1, start2, end2) {
|
|
var m = end1 - start1;
|
|
var n = end2 - start2;
|
|
if (m === 0 || n === 0) {
|
|
return null;
|
|
}
|
|
var delta = m - n;
|
|
var sum = n + m;
|
|
var offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
|
|
vDown[1 + offset] = start1;
|
|
vUp[1 + offset] = end1 + 1;
|
|
var d, k, i, x, y;
|
|
for (d = 0; d <= offset; ++d) {
|
|
for (k = -d; k <= d; k += 2) {
|
|
i = k + offset;
|
|
if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
|
|
vDown[i] = vDown[i + 1];
|
|
} else {
|
|
vDown[i] = vDown[i - 1] + 1;
|
|
}
|
|
x = vDown[i];
|
|
y = x - start1 + start2 - k;
|
|
while (x < end1 && y < end2 && left[x] === right[y]) {
|
|
vDown[i] = ++x;
|
|
++y;
|
|
}
|
|
if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
|
|
if (vUp[i - delta] <= vDown[i]) {
|
|
return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
|
|
}
|
|
}
|
|
}
|
|
for (k = delta - d; k <= delta + d; k += 2) {
|
|
i = k + offset - delta;
|
|
if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
|
|
vUp[i] = vUp[i + 1] - 1;
|
|
} else {
|
|
vUp[i] = vUp[i - 1];
|
|
}
|
|
x = vUp[i] - 1;
|
|
y = x - start1 + start2 - k;
|
|
while (x >= start1 && y >= start2 && left[x] === right[y]) {
|
|
vUp[i] = x--;
|
|
y--;
|
|
}
|
|
if (delta % 2 === 0 && -d <= k && k <= d) {
|
|
if (vUp[i] <= vDown[i + delta]) {
|
|
return buildSnake(vUp[i], k + start1 - start2, end1, end2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var script = [];
|
|
buildScript(0, left.length, 0, right.length, script);
|
|
return script;
|
|
};
|
|
var Diff = {
|
|
KEEP: KEEP,
|
|
DELETE: DELETE,
|
|
INSERT: INSERT,
|
|
diff: diff
|
|
};
|
|
|
|
var getOuterHtml = function (elm) {
|
|
if (NodeType.isElement(elm)) {
|
|
return elm.outerHTML;
|
|
} else if (NodeType.isText(elm)) {
|
|
return Entities.encodeRaw(elm.data, false);
|
|
} else if (NodeType.isComment(elm)) {
|
|
return '<!--' + elm.data + '-->';
|
|
}
|
|
return '';
|
|
};
|
|
var createFragment$1 = function (html) {
|
|
var frag, node, container;
|
|
container = domGlobals.document.createElement('div');
|
|
frag = domGlobals.document.createDocumentFragment();
|
|
if (html) {
|
|
container.innerHTML = html;
|
|
}
|
|
while (node = container.firstChild) {
|
|
frag.appendChild(node);
|
|
}
|
|
return frag;
|
|
};
|
|
var insertAt = function (elm, html, index) {
|
|
var fragment = createFragment$1(html);
|
|
if (elm.hasChildNodes() && index < elm.childNodes.length) {
|
|
var target = elm.childNodes[index];
|
|
target.parentNode.insertBefore(fragment, target);
|
|
} else {
|
|
elm.appendChild(fragment);
|
|
}
|
|
};
|
|
var removeAt = function (elm, index) {
|
|
if (elm.hasChildNodes() && index < elm.childNodes.length) {
|
|
var target = elm.childNodes[index];
|
|
target.parentNode.removeChild(target);
|
|
}
|
|
};
|
|
var applyDiff = function (diff, elm) {
|
|
var index = 0;
|
|
each(diff, function (action) {
|
|
if (action[0] === Diff.KEEP) {
|
|
index++;
|
|
} else if (action[0] === Diff.INSERT) {
|
|
insertAt(elm, action[1], index);
|
|
index++;
|
|
} else if (action[0] === Diff.DELETE) {
|
|
removeAt(elm, index);
|
|
}
|
|
});
|
|
};
|
|
var read$1 = function (elm) {
|
|
return filter(map(from$1(elm.childNodes), getOuterHtml), function (item) {
|
|
return item.length > 0;
|
|
});
|
|
};
|
|
var write = function (fragments, elm) {
|
|
var currentFragments = map(from$1(elm.childNodes), getOuterHtml);
|
|
applyDiff(Diff.diff(currentFragments, fragments), elm);
|
|
return elm;
|
|
};
|
|
var Fragments = {
|
|
read: read$1,
|
|
write: write
|
|
};
|
|
|
|
var undoLevelDocument = Cell(Option.none());
|
|
var lazyTempDocument = function () {
|
|
return undoLevelDocument.get().getOrThunk(function () {
|
|
var doc = domGlobals.document.implementation.createHTMLDocument('undo');
|
|
undoLevelDocument.set(Option.some(doc));
|
|
return doc;
|
|
});
|
|
};
|
|
var hasIframes = function (html) {
|
|
return html.indexOf('</iframe>') !== -1;
|
|
};
|
|
var createFragmentedLevel = function (fragments) {
|
|
return {
|
|
type: 'fragmented',
|
|
fragments: fragments,
|
|
content: '',
|
|
bookmark: null,
|
|
beforeBookmark: null
|
|
};
|
|
};
|
|
var createCompleteLevel = function (content) {
|
|
return {
|
|
type: 'complete',
|
|
fragments: null,
|
|
content: content,
|
|
bookmark: null,
|
|
beforeBookmark: null
|
|
};
|
|
};
|
|
var createFromEditor = function (editor) {
|
|
var fragments, content, trimmedFragments;
|
|
fragments = Fragments.read(editor.getBody());
|
|
trimmedFragments = bind(fragments, function (html) {
|
|
var trimmed = TrimHtml.trimInternal(editor.serializer, html);
|
|
return trimmed.length > 0 ? [trimmed] : [];
|
|
});
|
|
content = trimmedFragments.join('');
|
|
return hasIframes(content) ? createFragmentedLevel(trimmedFragments) : createCompleteLevel(content);
|
|
};
|
|
var applyToEditor = function (editor, level, before) {
|
|
if (level.type === 'fragmented') {
|
|
Fragments.write(level.fragments, editor.getBody());
|
|
} else {
|
|
editor.setContent(level.content, { format: 'raw' });
|
|
}
|
|
editor.selection.moveToBookmark(before ? level.beforeBookmark : level.bookmark);
|
|
};
|
|
var getLevelContent = function (level) {
|
|
return level.type === 'fragmented' ? level.fragments.join('') : level.content;
|
|
};
|
|
var getCleanLevelContent = function (level) {
|
|
var elm = Element.fromTag('body', lazyTempDocument());
|
|
set$1(elm, getLevelContent(level));
|
|
each(descendants$1(elm, '*[data-mce-bogus]'), unwrap);
|
|
return get$5(elm);
|
|
};
|
|
var hasEqualContent = function (level1, level2) {
|
|
return getLevelContent(level1) === getLevelContent(level2);
|
|
};
|
|
var hasEqualCleanedContent = function (level1, level2) {
|
|
return getCleanLevelContent(level1) === getCleanLevelContent(level2);
|
|
};
|
|
var isEq$2 = function (level1, level2) {
|
|
if (!level1 || !level2) {
|
|
return false;
|
|
} else if (hasEqualContent(level1, level2)) {
|
|
return true;
|
|
} else {
|
|
return hasEqualCleanedContent(level1, level2);
|
|
}
|
|
};
|
|
var Levels = {
|
|
createFragmentedLevel: createFragmentedLevel,
|
|
createCompleteLevel: createCompleteLevel,
|
|
createFromEditor: createFromEditor,
|
|
applyToEditor: applyToEditor,
|
|
isEq: isEq$2
|
|
};
|
|
|
|
var isUnlocked = function (locks) {
|
|
return locks.get() === 0;
|
|
};
|
|
|
|
var setTyping = function (undoManager, typing, locks) {
|
|
if (isUnlocked(locks)) {
|
|
undoManager.typing = typing;
|
|
}
|
|
};
|
|
var endTyping = function (undoManager, locks) {
|
|
if (undoManager.typing) {
|
|
setTyping(undoManager, false, locks);
|
|
undoManager.add();
|
|
}
|
|
};
|
|
var endTypingLevelIgnoreLocks = function (undoManager) {
|
|
if (undoManager.typing) {
|
|
undoManager.typing = false;
|
|
undoManager.add();
|
|
}
|
|
};
|
|
|
|
var beforeChange = function (editor, locks, beforeBookmark) {
|
|
if (isUnlocked(locks)) {
|
|
beforeBookmark.set(Option.some(GetBookmark.getUndoBookmark(editor.selection)));
|
|
}
|
|
};
|
|
var addUndoLevel = function (editor, undoManager, index, locks, beforeBookmark, level, event) {
|
|
var settings = editor.settings;
|
|
var currentLevel = Levels.createFromEditor(editor);
|
|
level = level || {};
|
|
level = Tools.extend(level, currentLevel);
|
|
if (isUnlocked(locks) === false || editor.removed) {
|
|
return null;
|
|
}
|
|
var lastLevel = undoManager.data[index.get()];
|
|
if (editor.fire('BeforeAddUndo', {
|
|
level: level,
|
|
lastLevel: lastLevel,
|
|
originalEvent: event
|
|
}).isDefaultPrevented()) {
|
|
return null;
|
|
}
|
|
if (lastLevel && Levels.isEq(lastLevel, level)) {
|
|
return null;
|
|
}
|
|
if (undoManager.data[index.get()]) {
|
|
beforeBookmark.get().each(function (bm) {
|
|
undoManager.data[index.get()].beforeBookmark = bm;
|
|
});
|
|
}
|
|
if (settings.custom_undo_redo_levels) {
|
|
if (undoManager.data.length > settings.custom_undo_redo_levels) {
|
|
for (var i = 0; i < undoManager.data.length - 1; i++) {
|
|
undoManager.data[i] = undoManager.data[i + 1];
|
|
}
|
|
undoManager.data.length--;
|
|
index.set(undoManager.data.length);
|
|
}
|
|
}
|
|
level.bookmark = GetBookmark.getUndoBookmark(editor.selection);
|
|
if (index.get() < undoManager.data.length - 1) {
|
|
undoManager.data.length = index.get() + 1;
|
|
}
|
|
undoManager.data.push(level);
|
|
index.set(undoManager.data.length - 1);
|
|
var args = {
|
|
level: level,
|
|
lastLevel: lastLevel,
|
|
originalEvent: event
|
|
};
|
|
editor.fire('AddUndo', args);
|
|
if (index.get() > 0) {
|
|
editor.setDirty(true);
|
|
editor.fire('change', args);
|
|
}
|
|
return level;
|
|
};
|
|
var clear = function (editor, undoManager, index) {
|
|
undoManager.data = [];
|
|
index.set(0);
|
|
undoManager.typing = false;
|
|
editor.fire('ClearUndos');
|
|
};
|
|
var extra = function (editor, undoManager, index, callback1, callback2) {
|
|
if (undoManager.transact(callback1)) {
|
|
var bookmark = undoManager.data[index.get()].bookmark;
|
|
var lastLevel = undoManager.data[index.get() - 1];
|
|
Levels.applyToEditor(editor, lastLevel, true);
|
|
if (undoManager.transact(callback2)) {
|
|
undoManager.data[index.get() - 1].beforeBookmark = bookmark;
|
|
}
|
|
}
|
|
};
|
|
var redo = function (editor, index, data) {
|
|
var level;
|
|
if (index.get() < data.length - 1) {
|
|
index.set(index.get() + 1);
|
|
level = data[index.get()];
|
|
Levels.applyToEditor(editor, level, false);
|
|
editor.setDirty(true);
|
|
editor.fire('Redo', { level: level });
|
|
}
|
|
return level;
|
|
};
|
|
var undo = function (editor, undoManager, locks, index) {
|
|
var level;
|
|
if (undoManager.typing) {
|
|
undoManager.add();
|
|
undoManager.typing = false;
|
|
setTyping(undoManager, false, locks);
|
|
}
|
|
if (index.get() > 0) {
|
|
index.set(index.get() - 1);
|
|
level = undoManager.data[index.get()];
|
|
Levels.applyToEditor(editor, level, true);
|
|
editor.setDirty(true);
|
|
editor.fire('Undo', { level: level });
|
|
}
|
|
return level;
|
|
};
|
|
var reset = function (undoManager) {
|
|
undoManager.clear();
|
|
undoManager.add();
|
|
};
|
|
var hasUndo = function (editor, undoManager, index) {
|
|
return index.get() > 0 || undoManager.typing && undoManager.data[0] && !Levels.isEq(Levels.createFromEditor(editor), undoManager.data[0]);
|
|
};
|
|
var hasRedo = function (undoManager, index) {
|
|
return index.get() < undoManager.data.length - 1 && !undoManager.typing;
|
|
};
|
|
var transact = function (undoManager, locks, callback) {
|
|
endTyping(undoManager, locks);
|
|
undoManager.beforeChange();
|
|
undoManager.ignore(callback);
|
|
return undoManager.add();
|
|
};
|
|
var ignore = function (locks, callback) {
|
|
try {
|
|
locks.set(locks.get() + 1);
|
|
callback();
|
|
} finally {
|
|
locks.set(locks.get() - 1);
|
|
}
|
|
};
|
|
|
|
var registerEvents$1 = function (editor, undoManager, locks) {
|
|
var isFirstTypedCharacter = Cell(false);
|
|
var addNonTypingUndoLevel = function (e) {
|
|
setTyping(undoManager, false, locks);
|
|
undoManager.add({}, e);
|
|
};
|
|
editor.on('init', function () {
|
|
undoManager.add();
|
|
});
|
|
editor.on('BeforeExecCommand', function (e) {
|
|
var cmd = e.command;
|
|
if (cmd !== 'Undo' && cmd !== 'Redo' && cmd !== 'mceRepaint') {
|
|
endTyping(undoManager, locks);
|
|
undoManager.beforeChange();
|
|
}
|
|
});
|
|
editor.on('ExecCommand', function (e) {
|
|
var cmd = e.command;
|
|
if (cmd !== 'Undo' && cmd !== 'Redo' && cmd !== 'mceRepaint') {
|
|
addNonTypingUndoLevel(e);
|
|
}
|
|
});
|
|
editor.on('ObjectResizeStart cut', function () {
|
|
undoManager.beforeChange();
|
|
});
|
|
editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
|
|
editor.on('dragend', addNonTypingUndoLevel);
|
|
editor.on('keyup', function (e) {
|
|
var keyCode = e.keyCode;
|
|
if (e.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey) {
|
|
addNonTypingUndoLevel();
|
|
editor.nodeChanged();
|
|
}
|
|
if (keyCode === 46 || keyCode === 8) {
|
|
editor.nodeChanged();
|
|
}
|
|
if (isFirstTypedCharacter.get() && undoManager.typing && Levels.isEq(Levels.createFromEditor(editor), undoManager.data[0]) === false) {
|
|
if (editor.isDirty() === false) {
|
|
editor.setDirty(true);
|
|
editor.fire('change', {
|
|
level: undoManager.data[0],
|
|
lastLevel: null
|
|
});
|
|
}
|
|
editor.fire('TypingUndo');
|
|
isFirstTypedCharacter.set(false);
|
|
editor.nodeChanged();
|
|
}
|
|
});
|
|
editor.on('keydown', function (e) {
|
|
var keyCode = e.keyCode;
|
|
if (e.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
|
|
if (undoManager.typing) {
|
|
addNonTypingUndoLevel(e);
|
|
}
|
|
return;
|
|
}
|
|
var modKey = e.ctrlKey && !e.altKey || e.metaKey;
|
|
if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
|
|
undoManager.beforeChange();
|
|
setTyping(undoManager, true, locks);
|
|
undoManager.add({}, e);
|
|
isFirstTypedCharacter.set(true);
|
|
}
|
|
});
|
|
editor.on('mousedown', function (e) {
|
|
if (undoManager.typing) {
|
|
addNonTypingUndoLevel(e);
|
|
}
|
|
});
|
|
var isInsertReplacementText = function (event) {
|
|
return event.inputType === 'insertReplacementText';
|
|
};
|
|
var isInsertTextDataNull = function (event) {
|
|
return event.inputType === 'insertText' && event.data === null;
|
|
};
|
|
editor.on('input', function (e) {
|
|
if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e))) {
|
|
addNonTypingUndoLevel(e);
|
|
}
|
|
});
|
|
editor.on('AddUndo Undo Redo ClearUndos', function (e) {
|
|
if (!e.isDefaultPrevented()) {
|
|
editor.nodeChanged();
|
|
}
|
|
});
|
|
};
|
|
var addKeyboardShortcuts = function (editor) {
|
|
editor.addShortcut('meta+z', '', 'Undo');
|
|
editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
|
|
};
|
|
|
|
var UndoManager = function (editor) {
|
|
var beforeBookmark = Cell(Option.none());
|
|
var locks = Cell(0);
|
|
var index = Cell(0);
|
|
var undoManager = {
|
|
data: [],
|
|
typing: false,
|
|
beforeChange: function () {
|
|
beforeChange(editor, locks, beforeBookmark);
|
|
},
|
|
add: function (level, event) {
|
|
return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
|
|
},
|
|
undo: function () {
|
|
return undo(editor, undoManager, locks, index);
|
|
},
|
|
redo: function () {
|
|
return redo(editor, index, undoManager.data);
|
|
},
|
|
clear: function () {
|
|
clear(editor, undoManager, index);
|
|
},
|
|
reset: function () {
|
|
reset(undoManager);
|
|
},
|
|
hasUndo: function () {
|
|
return hasUndo(editor, undoManager, index);
|
|
},
|
|
hasRedo: function () {
|
|
return hasRedo(undoManager, index);
|
|
},
|
|
transact: function (callback) {
|
|
return transact(undoManager, locks, callback);
|
|
},
|
|
ignore: function (callback) {
|
|
ignore(locks, callback);
|
|
},
|
|
extra: function (callback1, callback2) {
|
|
extra(editor, undoManager, index, callback1, callback2);
|
|
}
|
|
};
|
|
registerEvents$1(editor, undoManager, locks);
|
|
addKeyboardShortcuts(editor);
|
|
return undoManager;
|
|
};
|
|
|
|
var getLastChildren$1 = function (elm) {
|
|
var children = [];
|
|
var rawNode = elm.dom();
|
|
while (rawNode) {
|
|
children.push(Element.fromDom(rawNode));
|
|
rawNode = rawNode.lastChild;
|
|
}
|
|
return children;
|
|
};
|
|
var removeTrailingBr = function (elm) {
|
|
var allBrs = descendants$1(elm, 'br');
|
|
var brs = filter(getLastChildren$1(elm).slice(-1), isBr$1);
|
|
if (allBrs.length === brs.length) {
|
|
each(brs, remove$1);
|
|
}
|
|
};
|
|
var fillWithPaddingBr = function (elm) {
|
|
empty(elm);
|
|
append(elm, Element.fromHtml('<br data-mce-bogus="1">'));
|
|
};
|
|
var isPaddingContents = function (elm) {
|
|
return isText$1(elm) ? get$6(elm) === '\xA0' : isBr$1(elm);
|
|
};
|
|
var isPaddedElement = function (elm) {
|
|
return filter(children(elm), isPaddingContents).length === 1;
|
|
};
|
|
var trimBlockTrailingBr = function (elm) {
|
|
lastChild(elm).each(function (lastChild) {
|
|
prevSibling(lastChild).each(function (lastChildPrevSibling) {
|
|
if (isBlock(elm) && isBr$1(lastChild) && isBlock(lastChildPrevSibling)) {
|
|
remove$1(lastChild);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
var PaddingBr = {
|
|
removeTrailingBr: removeTrailingBr,
|
|
fillWithPaddingBr: fillWithPaddingBr,
|
|
isPaddedElement: isPaddedElement,
|
|
trimBlockTrailingBr: trimBlockTrailingBr
|
|
};
|
|
|
|
var isEq$3 = FormatUtils.isEq;
|
|
var matchesUnInheritedFormatSelector = function (ed, node, name) {
|
|
var formatList = ed.formatter.get(name);
|
|
if (formatList) {
|
|
for (var i = 0; i < formatList.length; i++) {
|
|
if (formatList[i].inherit === false && ed.dom.is(node, formatList[i].selector)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var matchParents = function (editor, node, name, vars) {
|
|
var root = editor.dom.getRoot();
|
|
if (node === root) {
|
|
return false;
|
|
}
|
|
node = editor.dom.getParent(node, function (node) {
|
|
if (matchesUnInheritedFormatSelector(editor, node, name)) {
|
|
return true;
|
|
}
|
|
return node.parentNode === root || !!matchNode(editor, node, name, vars, true);
|
|
});
|
|
return matchNode(editor, node, name, vars);
|
|
};
|
|
var matchName = function (dom, node, format) {
|
|
if (isEq$3(node, format.inline)) {
|
|
return true;
|
|
}
|
|
if (isEq$3(node, format.block)) {
|
|
return true;
|
|
}
|
|
if (format.selector) {
|
|
return node.nodeType === 1 && dom.is(node, format.selector);
|
|
}
|
|
};
|
|
var matchItems = function (dom, node, format, itemName, similar, vars) {
|
|
var key, value;
|
|
var items = format[itemName];
|
|
var i;
|
|
if (format.onmatch) {
|
|
return format.onmatch(node, format, itemName);
|
|
}
|
|
if (items) {
|
|
if (typeof items.length === 'undefined') {
|
|
for (key in items) {
|
|
if (items.hasOwnProperty(key)) {
|
|
if (itemName === 'attributes') {
|
|
value = dom.getAttrib(node, key);
|
|
} else {
|
|
value = FormatUtils.getStyle(dom, node, key);
|
|
}
|
|
if (similar && !value && !format.exact) {
|
|
return;
|
|
}
|
|
if ((!similar || format.exact) && !isEq$3(value, FormatUtils.normalizeStyleValue(dom, FormatUtils.replaceVars(items[key], vars), key))) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < items.length; i++) {
|
|
if (itemName === 'attributes' ? dom.getAttrib(node, items[i]) : FormatUtils.getStyle(dom, node, items[i])) {
|
|
return format;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return format;
|
|
};
|
|
var matchNode = function (ed, node, name, vars, similar) {
|
|
var formatList = ed.formatter.get(name);
|
|
var format, i, x, classes;
|
|
var dom = ed.dom;
|
|
if (formatList && node) {
|
|
for (i = 0; i < formatList.length; i++) {
|
|
format = formatList[i];
|
|
if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
|
|
if (classes = format.classes) {
|
|
for (x = 0; x < classes.length; x++) {
|
|
if (!ed.dom.hasClass(node, classes[x])) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
return format;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var match = function (editor, name, vars, node) {
|
|
var startNode;
|
|
if (node) {
|
|
return matchParents(editor, node, name, vars);
|
|
}
|
|
node = editor.selection.getNode();
|
|
if (matchParents(editor, node, name, vars)) {
|
|
return true;
|
|
}
|
|
startNode = editor.selection.getStart();
|
|
if (startNode !== node) {
|
|
if (matchParents(editor, startNode, name, vars)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var matchAll = function (editor, names, vars) {
|
|
var startElement;
|
|
var matchedFormatNames = [];
|
|
var checkedMap = {};
|
|
startElement = editor.selection.getStart();
|
|
editor.dom.getParent(startElement, function (node) {
|
|
var i, name;
|
|
for (i = 0; i < names.length; i++) {
|
|
name = names[i];
|
|
if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
|
|
checkedMap[name] = true;
|
|
matchedFormatNames.push(name);
|
|
}
|
|
}
|
|
}, editor.dom.getRoot());
|
|
return matchedFormatNames;
|
|
};
|
|
var canApply = function (editor, name) {
|
|
var formatList = editor.formatter.get(name);
|
|
var startNode, parents, i, x, selector;
|
|
var dom = editor.dom;
|
|
if (formatList) {
|
|
startNode = editor.selection.getStart();
|
|
parents = FormatUtils.getParents(dom, startNode);
|
|
for (x = formatList.length - 1; x >= 0; x--) {
|
|
selector = formatList[x].selector;
|
|
if (!selector || formatList[x].defaultBlock) {
|
|
return true;
|
|
}
|
|
for (i = parents.length - 1; i >= 0; i--) {
|
|
if (dom.is(parents[i], selector)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var MatchFormat = {
|
|
matchNode: matchNode,
|
|
matchName: matchName,
|
|
match: match,
|
|
matchAll: matchAll,
|
|
canApply: canApply,
|
|
matchesUnInheritedFormatSelector: matchesUnInheritedFormatSelector
|
|
};
|
|
|
|
var splitText = function (node, offset) {
|
|
return node.splitText(offset);
|
|
};
|
|
var split$1 = function (rng) {
|
|
var startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
|
|
if (startContainer === endContainer && NodeType.isText(startContainer)) {
|
|
if (startOffset > 0 && startOffset < startContainer.nodeValue.length) {
|
|
endContainer = splitText(startContainer, startOffset);
|
|
startContainer = endContainer.previousSibling;
|
|
if (endOffset > startOffset) {
|
|
endOffset = endOffset - startOffset;
|
|
startContainer = endContainer = splitText(endContainer, endOffset).previousSibling;
|
|
endOffset = endContainer.nodeValue.length;
|
|
startOffset = 0;
|
|
} else {
|
|
endOffset = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (NodeType.isText(startContainer) && startOffset > 0 && startOffset < startContainer.nodeValue.length) {
|
|
startContainer = splitText(startContainer, startOffset);
|
|
startOffset = 0;
|
|
}
|
|
if (NodeType.isText(endContainer) && endOffset > 0 && endOffset < endContainer.nodeValue.length) {
|
|
endContainer = splitText(endContainer, endOffset).previousSibling;
|
|
endOffset = endContainer.nodeValue.length;
|
|
}
|
|
}
|
|
return {
|
|
startContainer: startContainer,
|
|
startOffset: startOffset,
|
|
endContainer: endContainer,
|
|
endOffset: endOffset
|
|
};
|
|
};
|
|
|
|
var isCollapsibleWhitespace = function (c) {
|
|
return ' \f\n\r\t\x0B'.indexOf(c) !== -1;
|
|
};
|
|
var normalizeContent = function (content, isStartOfContent, isEndOfContent) {
|
|
var result = foldl(content, function (acc, c) {
|
|
if (isCollapsibleWhitespace(c) || c === '\xA0') {
|
|
if (acc.previousCharIsSpace || acc.str === '' && isStartOfContent || acc.str.length === content.length - 1 && isEndOfContent) {
|
|
return {
|
|
previousCharIsSpace: false,
|
|
str: acc.str + '\xA0'
|
|
};
|
|
} else {
|
|
return {
|
|
previousCharIsSpace: true,
|
|
str: acc.str + ' '
|
|
};
|
|
}
|
|
} else {
|
|
return {
|
|
previousCharIsSpace: false,
|
|
str: acc.str + c
|
|
};
|
|
}
|
|
}, {
|
|
previousCharIsSpace: false,
|
|
str: ''
|
|
});
|
|
return result.str;
|
|
};
|
|
var normalize = function (node, offset, count) {
|
|
if (count === 0) {
|
|
return;
|
|
}
|
|
var whitespace = node.data.slice(offset, offset + count);
|
|
var isEndOfContent = offset + count >= node.data.length;
|
|
var isStartOfContent = offset === 0;
|
|
node.replaceData(offset, count, normalizeContent(whitespace, isStartOfContent, isEndOfContent));
|
|
};
|
|
var normalizeWhitespaceAfter = function (node, offset) {
|
|
var content = node.data.slice(offset);
|
|
var whitespaceCount = content.length - lTrim(content).length;
|
|
return normalize(node, offset, whitespaceCount);
|
|
};
|
|
var normalizeWhitespaceBefore = function (node, offset) {
|
|
var content = node.data.slice(0, offset);
|
|
var whitespaceCount = content.length - rTrim(content).length;
|
|
return normalize(node, offset - whitespaceCount, whitespaceCount);
|
|
};
|
|
var mergeTextNodes = function (prevNode, nextNode, normalizeWhitespace) {
|
|
var whitespaceOffset = rTrim(prevNode.data).length;
|
|
prevNode.appendData(nextNode.data);
|
|
remove$1(Element.fromDom(nextNode));
|
|
if (normalizeWhitespace) {
|
|
normalizeWhitespaceAfter(prevNode, whitespaceOffset);
|
|
}
|
|
return prevNode;
|
|
};
|
|
|
|
var ancestor$2 = function (scope, selector, isRoot) {
|
|
return ancestor$1(scope, selector, isRoot).isSome();
|
|
};
|
|
|
|
var hasWhitespacePreserveParent = function (rootNode, node) {
|
|
var rootElement = Element.fromDom(rootNode);
|
|
var startNode = Element.fromDom(node);
|
|
return ancestor$2(startNode, 'pre,code', curry(eq, rootElement));
|
|
};
|
|
var isWhitespace = function (rootNode, node) {
|
|
return NodeType.isText(node) && /^[ \t\r\n]*$/.test(node.data) && hasWhitespacePreserveParent(rootNode, node) === false;
|
|
};
|
|
var isNamedAnchor = function (node) {
|
|
return NodeType.isElement(node) && node.nodeName === 'A' && node.hasAttribute('name');
|
|
};
|
|
var isContent$1 = function (rootNode, node) {
|
|
return isCaretCandidate(node) && isWhitespace(rootNode, node) === false || isNamedAnchor(node) || isBookmark(node);
|
|
};
|
|
var isBookmark = NodeType.hasAttribute('data-mce-bookmark');
|
|
var isBogus$2 = NodeType.hasAttribute('data-mce-bogus');
|
|
var isBogusAll$1 = NodeType.hasAttributeValue('data-mce-bogus', 'all');
|
|
var isEmptyNode = function (targetNode) {
|
|
var node, brCount = 0;
|
|
if (isContent$1(targetNode, targetNode)) {
|
|
return false;
|
|
} else {
|
|
node = targetNode.firstChild;
|
|
if (!node) {
|
|
return true;
|
|
}
|
|
var walker = new TreeWalker(node, targetNode);
|
|
do {
|
|
if (isBogusAll$1(node)) {
|
|
node = walker.next(true);
|
|
continue;
|
|
}
|
|
if (isBogus$2(node)) {
|
|
node = walker.next();
|
|
continue;
|
|
}
|
|
if (NodeType.isBr(node)) {
|
|
brCount++;
|
|
node = walker.next();
|
|
continue;
|
|
}
|
|
if (isContent$1(targetNode, node)) {
|
|
return false;
|
|
}
|
|
node = walker.next();
|
|
} while (node);
|
|
return brCount <= 1;
|
|
}
|
|
};
|
|
var isEmpty$1 = function (elm) {
|
|
return isEmptyNode(elm.dom());
|
|
};
|
|
var Empty = { isEmpty: isEmpty$1 };
|
|
|
|
var needsReposition = function (pos, elm) {
|
|
var container = pos.container();
|
|
var offset = pos.offset();
|
|
return CaretPosition$1.isTextPosition(pos) === false && container === elm.parentNode && offset > CaretPosition$1.before(elm).offset();
|
|
};
|
|
var reposition = function (elm, pos) {
|
|
return needsReposition(pos, elm) ? CaretPosition$1(pos.container(), pos.offset() - 1) : pos;
|
|
};
|
|
var beforeOrStartOf = function (node) {
|
|
return NodeType.isText(node) ? CaretPosition$1(node, 0) : CaretPosition$1.before(node);
|
|
};
|
|
var afterOrEndOf = function (node) {
|
|
return NodeType.isText(node) ? CaretPosition$1(node, node.data.length) : CaretPosition$1.after(node);
|
|
};
|
|
var getPreviousSiblingCaretPosition = function (elm) {
|
|
if (isCaretCandidate(elm.previousSibling)) {
|
|
return Option.some(afterOrEndOf(elm.previousSibling));
|
|
} else {
|
|
return elm.previousSibling ? CaretFinder.lastPositionIn(elm.previousSibling) : Option.none();
|
|
}
|
|
};
|
|
var getNextSiblingCaretPosition = function (elm) {
|
|
if (isCaretCandidate(elm.nextSibling)) {
|
|
return Option.some(beforeOrStartOf(elm.nextSibling));
|
|
} else {
|
|
return elm.nextSibling ? CaretFinder.firstPositionIn(elm.nextSibling) : Option.none();
|
|
}
|
|
};
|
|
var findCaretPositionBackwardsFromElm = function (rootElement, elm) {
|
|
var startPosition = CaretPosition$1.before(elm.previousSibling ? elm.previousSibling : elm.parentNode);
|
|
return CaretFinder.prevPosition(rootElement, startPosition).fold(function () {
|
|
return CaretFinder.nextPosition(rootElement, CaretPosition$1.after(elm));
|
|
}, Option.some);
|
|
};
|
|
var findCaretPositionForwardsFromElm = function (rootElement, elm) {
|
|
return CaretFinder.nextPosition(rootElement, CaretPosition$1.after(elm)).fold(function () {
|
|
return CaretFinder.prevPosition(rootElement, CaretPosition$1.before(elm));
|
|
}, Option.some);
|
|
};
|
|
var findCaretPositionBackwards = function (rootElement, elm) {
|
|
return getPreviousSiblingCaretPosition(elm).orThunk(function () {
|
|
return getNextSiblingCaretPosition(elm);
|
|
}).orThunk(function () {
|
|
return findCaretPositionBackwardsFromElm(rootElement, elm);
|
|
});
|
|
};
|
|
var findCaretPositionForward = function (rootElement, elm) {
|
|
return getNextSiblingCaretPosition(elm).orThunk(function () {
|
|
return getPreviousSiblingCaretPosition(elm);
|
|
}).orThunk(function () {
|
|
return findCaretPositionForwardsFromElm(rootElement, elm);
|
|
});
|
|
};
|
|
var findCaretPosition$1 = function (forward, rootElement, elm) {
|
|
return forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
|
|
};
|
|
var findCaretPosOutsideElmAfterDelete = function (forward, rootElement, elm) {
|
|
return findCaretPosition$1(forward, rootElement, elm).map(curry(reposition, elm));
|
|
};
|
|
var setSelection = function (editor, forward, pos) {
|
|
pos.fold(function () {
|
|
editor.focus();
|
|
}, function (pos) {
|
|
editor.selection.setRng(pos.toRange(), forward);
|
|
});
|
|
};
|
|
var eqRawNode = function (rawNode) {
|
|
return function (elm) {
|
|
return elm.dom() === rawNode;
|
|
};
|
|
};
|
|
var isBlock$2 = function (editor, elm) {
|
|
return elm && editor.schema.getBlockElements().hasOwnProperty(name(elm));
|
|
};
|
|
var paddEmptyBlock = function (elm) {
|
|
if (Empty.isEmpty(elm)) {
|
|
var br = Element.fromHtml('<br data-mce-bogus="1">');
|
|
empty(elm);
|
|
append(elm, br);
|
|
return Option.some(CaretPosition$1.before(br.dom()));
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
};
|
|
var deleteNormalized = function (elm, afterDeletePosOpt, normalizeWhitespace) {
|
|
var prevTextOpt = prevSibling(elm).filter(isText$1);
|
|
var nextTextOpt = nextSibling(elm).filter(isText$1);
|
|
remove$1(elm);
|
|
return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, function (prev, next, pos) {
|
|
var prevNode = prev.dom(), nextNode = next.dom();
|
|
var offset = prevNode.data.length;
|
|
mergeTextNodes(prevNode, nextNode, normalizeWhitespace);
|
|
return pos.container() === nextNode ? CaretPosition$1(prevNode, offset) : pos;
|
|
}).orThunk(function () {
|
|
if (normalizeWhitespace) {
|
|
prevTextOpt.each(function (elm) {
|
|
return normalizeWhitespaceBefore(elm.dom(), elm.dom().length);
|
|
});
|
|
nextTextOpt.each(function (elm) {
|
|
return normalizeWhitespaceAfter(elm.dom(), 0);
|
|
});
|
|
}
|
|
return afterDeletePosOpt;
|
|
});
|
|
};
|
|
var isInlineElement = function (editor, element) {
|
|
return has(editor.schema.getTextInlineElements(), name(element));
|
|
};
|
|
var deleteElement = function (editor, forward, elm, moveCaret) {
|
|
if (moveCaret === void 0) {
|
|
moveCaret = true;
|
|
}
|
|
var afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom());
|
|
var parentBlock = ancestor(elm, curry(isBlock$2, editor), eqRawNode(editor.getBody()));
|
|
var normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, isInlineElement(editor, elm));
|
|
if (editor.dom.isEmpty(editor.getBody())) {
|
|
editor.setContent('');
|
|
editor.selection.setCursorLocation();
|
|
} else {
|
|
parentBlock.bind(paddEmptyBlock).fold(function () {
|
|
if (moveCaret) {
|
|
setSelection(editor, forward, normalizedAfterDeletePos);
|
|
}
|
|
}, function (paddPos) {
|
|
if (moveCaret) {
|
|
setSelection(editor, forward, Option.some(paddPos));
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var DeleteElement = { deleteElement: deleteElement };
|
|
|
|
var ZWSP$1 = Zwsp.ZWSP, CARET_ID$1 = '_mce_caret';
|
|
var importNode = function (ownerDocument, node) {
|
|
return ownerDocument.importNode(node, true);
|
|
};
|
|
var getEmptyCaretContainers = function (node) {
|
|
var nodes = [];
|
|
while (node) {
|
|
if (node.nodeType === 3 && node.nodeValue !== ZWSP$1 || node.childNodes.length > 1) {
|
|
return [];
|
|
}
|
|
if (node.nodeType === 1) {
|
|
nodes.push(node);
|
|
}
|
|
node = node.firstChild;
|
|
}
|
|
return nodes;
|
|
};
|
|
var isCaretContainerEmpty = function (node) {
|
|
return getEmptyCaretContainers(node).length > 0;
|
|
};
|
|
var findFirstTextNode = function (node) {
|
|
if (node) {
|
|
var walker = new TreeWalker(node, node);
|
|
for (node = walker.current(); node; node = walker.next()) {
|
|
if (node.nodeType === 3) {
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var createCaretContainer = function (fill) {
|
|
var caretContainer = Element.fromTag('span');
|
|
setAll(caretContainer, {
|
|
'id': CARET_ID$1,
|
|
'data-mce-bogus': '1',
|
|
'data-mce-type': 'format-caret'
|
|
});
|
|
if (fill) {
|
|
append(caretContainer, Element.fromText(ZWSP$1));
|
|
}
|
|
return caretContainer;
|
|
};
|
|
var trimZwspFromCaretContainer = function (caretContainerNode) {
|
|
var textNode = findFirstTextNode(caretContainerNode);
|
|
if (textNode && textNode.nodeValue.charAt(0) === ZWSP$1) {
|
|
textNode.deleteData(0, 1);
|
|
}
|
|
return textNode;
|
|
};
|
|
var removeCaretContainerNode = function (editor, node, moveCaret) {
|
|
if (moveCaret === void 0) {
|
|
moveCaret = true;
|
|
}
|
|
var dom = editor.dom, selection = editor.selection;
|
|
if (isCaretContainerEmpty(node)) {
|
|
DeleteElement.deleteElement(editor, false, Element.fromDom(node), moveCaret);
|
|
} else {
|
|
var rng = selection.getRng();
|
|
var block = dom.getParent(node, dom.isBlock);
|
|
var textNode = trimZwspFromCaretContainer(node);
|
|
if (rng.startContainer === textNode && rng.startOffset > 0) {
|
|
rng.setStart(textNode, rng.startOffset - 1);
|
|
}
|
|
if (rng.endContainer === textNode && rng.endOffset > 0) {
|
|
rng.setEnd(textNode, rng.endOffset - 1);
|
|
}
|
|
dom.remove(node, true);
|
|
if (block && dom.isEmpty(block)) {
|
|
PaddingBr.fillWithPaddingBr(Element.fromDom(block));
|
|
}
|
|
selection.setRng(rng);
|
|
}
|
|
};
|
|
var removeCaretContainer = function (editor, node, moveCaret) {
|
|
if (moveCaret === void 0) {
|
|
moveCaret = true;
|
|
}
|
|
var dom = editor.dom, selection = editor.selection;
|
|
if (!node) {
|
|
node = getParentCaretContainer(editor.getBody(), selection.getStart());
|
|
if (!node) {
|
|
while (node = dom.get(CARET_ID$1)) {
|
|
removeCaretContainerNode(editor, node, false);
|
|
}
|
|
}
|
|
} else {
|
|
removeCaretContainerNode(editor, node, moveCaret);
|
|
}
|
|
};
|
|
var insertCaretContainerNode = function (editor, caretContainer, formatNode) {
|
|
var dom = editor.dom, block = dom.getParent(formatNode, curry(FormatUtils.isTextBlock, editor));
|
|
if (block && dom.isEmpty(block)) {
|
|
formatNode.parentNode.replaceChild(caretContainer, formatNode);
|
|
} else {
|
|
PaddingBr.removeTrailingBr(Element.fromDom(formatNode));
|
|
if (dom.isEmpty(formatNode)) {
|
|
formatNode.parentNode.replaceChild(caretContainer, formatNode);
|
|
} else {
|
|
dom.insertAfter(caretContainer, formatNode);
|
|
}
|
|
}
|
|
};
|
|
var appendNode = function (parentNode, node) {
|
|
parentNode.appendChild(node);
|
|
return node;
|
|
};
|
|
var insertFormatNodesIntoCaretContainer = function (formatNodes, caretContainer) {
|
|
var innerMostFormatNode = foldr(formatNodes, function (parentNode, formatNode) {
|
|
return appendNode(parentNode, formatNode.cloneNode(false));
|
|
}, caretContainer);
|
|
return appendNode(innerMostFormatNode, innerMostFormatNode.ownerDocument.createTextNode(ZWSP$1));
|
|
};
|
|
var applyCaretFormat = function (editor, name, vars) {
|
|
var rng, caretContainer, textNode, offset, bookmark, container, text;
|
|
var selection = editor.selection;
|
|
rng = selection.getRng();
|
|
offset = rng.startOffset;
|
|
container = rng.startContainer;
|
|
text = container.nodeValue;
|
|
caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
|
|
if (caretContainer) {
|
|
textNode = findFirstTextNode(caretContainer);
|
|
}
|
|
var wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
|
|
if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
|
|
bookmark = selection.getBookmark();
|
|
rng.collapse(true);
|
|
rng = ExpandRange.expandRng(editor, rng, editor.formatter.get(name));
|
|
rng = split$1(rng);
|
|
editor.formatter.apply(name, vars, rng);
|
|
selection.moveToBookmark(bookmark);
|
|
} else {
|
|
if (!caretContainer || textNode.nodeValue !== ZWSP$1) {
|
|
caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom());
|
|
textNode = caretContainer.firstChild;
|
|
rng.insertNode(caretContainer);
|
|
offset = 1;
|
|
editor.formatter.apply(name, vars, caretContainer);
|
|
} else {
|
|
editor.formatter.apply(name, vars, caretContainer);
|
|
}
|
|
selection.setCursorLocation(textNode, offset);
|
|
}
|
|
};
|
|
var removeCaretFormat = function (editor, name, vars, similar) {
|
|
var dom = editor.dom, selection = editor.selection;
|
|
var container, offset, bookmark;
|
|
var hasContentAfter, node, formatNode;
|
|
var parents = [], rng = selection.getRng();
|
|
var caretContainer;
|
|
container = rng.startContainer;
|
|
offset = rng.startOffset;
|
|
node = container;
|
|
if (container.nodeType === 3) {
|
|
if (offset !== container.nodeValue.length) {
|
|
hasContentAfter = true;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
while (node) {
|
|
if (MatchFormat.matchNode(editor, node, name, vars, similar)) {
|
|
formatNode = node;
|
|
break;
|
|
}
|
|
if (node.nextSibling) {
|
|
hasContentAfter = true;
|
|
}
|
|
parents.push(node);
|
|
node = node.parentNode;
|
|
}
|
|
if (!formatNode) {
|
|
return;
|
|
}
|
|
if (hasContentAfter) {
|
|
bookmark = selection.getBookmark();
|
|
rng.collapse(true);
|
|
var expandedRng = ExpandRange.expandRng(editor, rng, editor.formatter.get(name), true);
|
|
expandedRng = split$1(expandedRng);
|
|
editor.formatter.remove(name, vars, expandedRng);
|
|
selection.moveToBookmark(bookmark);
|
|
} else {
|
|
caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
|
|
var newCaretContainer = createCaretContainer(false).dom();
|
|
var caretNode = insertFormatNodesIntoCaretContainer(parents, newCaretContainer);
|
|
if (caretContainer) {
|
|
insertCaretContainerNode(editor, newCaretContainer, caretContainer);
|
|
} else {
|
|
insertCaretContainerNode(editor, newCaretContainer, formatNode);
|
|
}
|
|
removeCaretContainerNode(editor, caretContainer, false);
|
|
selection.setCursorLocation(caretNode, 1);
|
|
if (dom.isEmpty(formatNode)) {
|
|
dom.remove(formatNode);
|
|
}
|
|
}
|
|
};
|
|
var disableCaretContainer = function (editor, keyCode) {
|
|
var selection = editor.selection, body = editor.getBody();
|
|
removeCaretContainer(editor, null, false);
|
|
if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP$1) {
|
|
removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
|
|
}
|
|
if (keyCode === 37 || keyCode === 39) {
|
|
removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
|
|
}
|
|
};
|
|
var setup$5 = function (editor) {
|
|
editor.on('mouseup keydown', function (e) {
|
|
disableCaretContainer(editor, e.keyCode);
|
|
});
|
|
};
|
|
var replaceWithCaretFormat = function (targetNode, formatNodes) {
|
|
var caretContainer = createCaretContainer(false);
|
|
var innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom());
|
|
before(Element.fromDom(targetNode), caretContainer);
|
|
remove$1(Element.fromDom(targetNode));
|
|
return CaretPosition$1(innerMost, 0);
|
|
};
|
|
var isFormatElement = function (editor, element) {
|
|
var inlineElements = editor.schema.getTextInlineElements();
|
|
return inlineElements.hasOwnProperty(name(element)) && !isCaretNode(element.dom()) && !NodeType.isBogus(element.dom());
|
|
};
|
|
var isEmptyCaretFormatElement = function (element) {
|
|
return isCaretNode(element.dom()) && isCaretContainerEmpty(element.dom());
|
|
};
|
|
|
|
var postProcessHooks = {}, filter$3 = ArrUtils.filter, each$9 = ArrUtils.each;
|
|
var addPostProcessHook = function (name, hook) {
|
|
var hooks = postProcessHooks[name];
|
|
if (!hooks) {
|
|
postProcessHooks[name] = hooks = [];
|
|
}
|
|
postProcessHooks[name].push(hook);
|
|
};
|
|
var postProcess = function (name, editor) {
|
|
each$9(postProcessHooks[name], function (hook) {
|
|
hook(editor);
|
|
});
|
|
};
|
|
addPostProcessHook('pre', function (editor) {
|
|
var rng = editor.selection.getRng();
|
|
var isPre, blocks;
|
|
var hasPreSibling = function (pre) {
|
|
return isPre(pre.previousSibling) && ArrUtils.indexOf(blocks, pre.previousSibling) !== -1;
|
|
};
|
|
var joinPre = function (pre1, pre2) {
|
|
DomQuery(pre2).remove();
|
|
DomQuery(pre1).append('<br><br>').append(pre2.childNodes);
|
|
};
|
|
isPre = NodeType.matchNodeNames(['pre']);
|
|
if (!rng.collapsed) {
|
|
blocks = editor.selection.getSelectedBlocks();
|
|
each$9(filter$3(filter$3(blocks, isPre), hasPreSibling), function (pre) {
|
|
joinPre(pre.previousSibling, pre);
|
|
});
|
|
}
|
|
});
|
|
var Hooks = { postProcess: postProcess };
|
|
|
|
var each$a = Tools.each;
|
|
var ElementUtils = function (dom) {
|
|
this.compare = function (node1, node2) {
|
|
if (node1.nodeName !== node2.nodeName) {
|
|
return false;
|
|
}
|
|
var getAttribs = function (node) {
|
|
var attribs = {};
|
|
each$a(dom.getAttribs(node), function (attr) {
|
|
var name = attr.nodeName.toLowerCase();
|
|
if (name.indexOf('_') !== 0 && name !== 'style' && name.indexOf('data-') !== 0) {
|
|
attribs[name] = dom.getAttrib(node, name);
|
|
}
|
|
});
|
|
return attribs;
|
|
};
|
|
var compareObjects = function (obj1, obj2) {
|
|
var value, name;
|
|
for (name in obj1) {
|
|
if (obj1.hasOwnProperty(name)) {
|
|
value = obj2[name];
|
|
if (typeof value === 'undefined') {
|
|
return false;
|
|
}
|
|
if (obj1[name] !== value) {
|
|
return false;
|
|
}
|
|
delete obj2[name];
|
|
}
|
|
}
|
|
for (name in obj2) {
|
|
if (obj2.hasOwnProperty(name)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
|
|
return false;
|
|
}
|
|
if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
|
|
return false;
|
|
}
|
|
return !Bookmarks.isBookmarkNode(node1) && !Bookmarks.isBookmarkNode(node2);
|
|
};
|
|
};
|
|
|
|
var MCE_ATTR_RE = /^(src|href|style)$/;
|
|
var each$b = Tools.each;
|
|
var isEq$4 = FormatUtils.isEq;
|
|
var isTableCell$2 = function (node) {
|
|
return /^(TH|TD)$/.test(node.nodeName);
|
|
};
|
|
var isChildOfInlineParent = function (dom, node, parent) {
|
|
return dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
|
|
};
|
|
var getContainer = function (ed, rng, start) {
|
|
var container, offset, lastIdx;
|
|
container = rng[start ? 'startContainer' : 'endContainer'];
|
|
offset = rng[start ? 'startOffset' : 'endOffset'];
|
|
if (NodeType.isElement(container)) {
|
|
lastIdx = container.childNodes.length - 1;
|
|
if (!start && offset) {
|
|
offset--;
|
|
}
|
|
container = container.childNodes[offset > lastIdx ? lastIdx : offset];
|
|
}
|
|
if (NodeType.isText(container) && start && offset >= container.nodeValue.length) {
|
|
container = new TreeWalker(container, ed.getBody()).next() || container;
|
|
}
|
|
if (NodeType.isText(container) && !start && offset === 0) {
|
|
container = new TreeWalker(container, ed.getBody()).prev() || container;
|
|
}
|
|
return container;
|
|
};
|
|
var wrap$2 = function (dom, node, name, attrs) {
|
|
var wrapper = dom.create(name, attrs);
|
|
node.parentNode.insertBefore(wrapper, node);
|
|
wrapper.appendChild(node);
|
|
return wrapper;
|
|
};
|
|
var wrapWithSiblings = function (dom, node, next, name, attrs) {
|
|
var start = Element.fromDom(node);
|
|
var wrapper = Element.fromDom(dom.create(name, attrs));
|
|
var siblings = next ? nextSiblings(start) : prevSiblings(start);
|
|
append$1(wrapper, siblings);
|
|
if (next) {
|
|
before(start, wrapper);
|
|
prepend(wrapper, start);
|
|
} else {
|
|
after(start, wrapper);
|
|
append(wrapper, start);
|
|
}
|
|
return wrapper.dom();
|
|
};
|
|
var matchName$1 = function (dom, node, format) {
|
|
if (isEq$4(node, format.inline)) {
|
|
return true;
|
|
}
|
|
if (isEq$4(node, format.block)) {
|
|
return true;
|
|
}
|
|
if (format.selector) {
|
|
return NodeType.isElement(node) && dom.is(node, format.selector);
|
|
}
|
|
};
|
|
var isColorFormatAndAnchor = function (node, format) {
|
|
return format.links && node.tagName === 'A';
|
|
};
|
|
var find$3 = function (dom, node, next, inc) {
|
|
node = FormatUtils.getNonWhiteSpaceSibling(node, next, inc);
|
|
return !node || (node.nodeName === 'BR' || dom.isBlock(node));
|
|
};
|
|
var removeNode$1 = function (ed, node, format) {
|
|
var parentNode = node.parentNode;
|
|
var rootBlockElm;
|
|
var dom = ed.dom, forcedRootBlock = Settings.getForcedRootBlock(ed);
|
|
if (format.block) {
|
|
if (!forcedRootBlock) {
|
|
if (dom.isBlock(node) && !dom.isBlock(parentNode)) {
|
|
if (!find$3(dom, node, false) && !find$3(dom, node.firstChild, true, 1)) {
|
|
node.insertBefore(dom.create('br'), node.firstChild);
|
|
}
|
|
if (!find$3(dom, node, true) && !find$3(dom, node.lastChild, false, 1)) {
|
|
node.appendChild(dom.create('br'));
|
|
}
|
|
}
|
|
} else {
|
|
if (parentNode === dom.getRoot()) {
|
|
if (!format.list_block || !isEq$4(node, format.list_block)) {
|
|
each$b(Tools.grep(node.childNodes), function (node) {
|
|
if (FormatUtils.isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
|
|
if (!rootBlockElm) {
|
|
rootBlockElm = wrap$2(dom, node, forcedRootBlock);
|
|
dom.setAttribs(rootBlockElm, ed.settings.forced_root_block_attrs);
|
|
} else {
|
|
rootBlockElm.appendChild(node);
|
|
}
|
|
} else {
|
|
rootBlockElm = 0;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (format.selector && format.inline && !isEq$4(format.inline, node)) {
|
|
return;
|
|
}
|
|
dom.remove(node, 1);
|
|
};
|
|
var removeFormat = function (ed, format, vars, node, compareNode) {
|
|
var i, attrs, stylesModified;
|
|
var dom = ed.dom;
|
|
if (!matchName$1(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
|
|
return false;
|
|
}
|
|
if (format.remove !== 'all') {
|
|
each$b(format.styles, function (value, name) {
|
|
value = FormatUtils.normalizeStyleValue(dom, FormatUtils.replaceVars(value, vars), name);
|
|
if (typeof name === 'number') {
|
|
name = value;
|
|
compareNode = 0;
|
|
}
|
|
if (format.remove_similar || (!compareNode || isEq$4(FormatUtils.getStyle(dom, compareNode, name), value))) {
|
|
dom.setStyle(node, name, '');
|
|
}
|
|
stylesModified = 1;
|
|
});
|
|
if (stylesModified && dom.getAttrib(node, 'style') === '') {
|
|
node.removeAttribute('style');
|
|
node.removeAttribute('data-mce-style');
|
|
}
|
|
each$b(format.attributes, function (value, name) {
|
|
var valueOut;
|
|
value = FormatUtils.replaceVars(value, vars);
|
|
if (typeof name === 'number') {
|
|
name = value;
|
|
compareNode = 0;
|
|
}
|
|
if (format.remove_similar || (!compareNode || isEq$4(dom.getAttrib(compareNode, name), value))) {
|
|
if (name === 'class') {
|
|
value = dom.getAttrib(node, name);
|
|
if (value) {
|
|
valueOut = '';
|
|
each$b(value.split(/\s+/), function (cls) {
|
|
if (/mce\-\w+/.test(cls)) {
|
|
valueOut += (valueOut ? ' ' : '') + cls;
|
|
}
|
|
});
|
|
if (valueOut) {
|
|
dom.setAttrib(node, name, valueOut);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (name === 'class') {
|
|
node.removeAttribute('className');
|
|
}
|
|
if (MCE_ATTR_RE.test(name)) {
|
|
node.removeAttribute('data-mce-' + name);
|
|
}
|
|
node.removeAttribute(name);
|
|
}
|
|
});
|
|
each$b(format.classes, function (value) {
|
|
value = FormatUtils.replaceVars(value, vars);
|
|
if (!compareNode || dom.hasClass(compareNode, value)) {
|
|
dom.removeClass(node, value);
|
|
}
|
|
});
|
|
attrs = dom.getAttribs(node);
|
|
for (i = 0; i < attrs.length; i++) {
|
|
var attrName = attrs[i].nodeName;
|
|
if (attrName.indexOf('_') !== 0 && attrName.indexOf('data-') !== 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (format.remove !== 'none') {
|
|
removeNode$1(ed, node, format);
|
|
return true;
|
|
}
|
|
};
|
|
var findFormatRoot = function (editor, container, name, vars, similar) {
|
|
var formatRoot;
|
|
each$b(FormatUtils.getParents(editor.dom, container.parentNode).reverse(), function (parent) {
|
|
var format;
|
|
if (!formatRoot && parent.id !== '_start' && parent.id !== '_end') {
|
|
format = MatchFormat.matchNode(editor, parent, name, vars, similar);
|
|
if (format && format.split !== false) {
|
|
formatRoot = parent;
|
|
}
|
|
}
|
|
});
|
|
return formatRoot;
|
|
};
|
|
var wrapAndSplit = function (editor, formatList, formatRoot, container, target, split, format, vars) {
|
|
var parent, clone, lastClone, firstClone, i, formatRootParent;
|
|
var dom = editor.dom;
|
|
if (formatRoot) {
|
|
formatRootParent = formatRoot.parentNode;
|
|
for (parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
|
|
clone = dom.clone(parent, false);
|
|
for (i = 0; i < formatList.length; i++) {
|
|
if (removeFormat(editor, formatList[i], vars, clone, clone)) {
|
|
clone = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (clone) {
|
|
if (lastClone) {
|
|
clone.appendChild(lastClone);
|
|
}
|
|
if (!firstClone) {
|
|
firstClone = clone;
|
|
}
|
|
lastClone = clone;
|
|
}
|
|
}
|
|
if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
|
|
container = dom.split(formatRoot, container);
|
|
}
|
|
if (lastClone) {
|
|
target.parentNode.insertBefore(lastClone, target);
|
|
firstClone.appendChild(target);
|
|
}
|
|
}
|
|
return container;
|
|
};
|
|
var remove$7 = function (ed, name, vars, node, similar) {
|
|
var formatList = ed.formatter.get(name), format = formatList[0];
|
|
var bookmark, rng, contentEditable = true;
|
|
var dom = ed.dom;
|
|
var selection = ed.selection;
|
|
var splitToFormatRoot = function (container) {
|
|
var formatRoot = findFormatRoot(ed, container, name, vars, similar);
|
|
return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
|
|
};
|
|
var isRemoveBookmarkNode = function (node) {
|
|
return Bookmarks.isBookmarkNode(node) && NodeType.isElement(node) && (node.id === '_start' || node.id === '_end');
|
|
};
|
|
var process = function (node) {
|
|
var children, i, l, lastContentEditable, hasContentEditableState;
|
|
if (NodeType.isElement(node) && dom.getContentEditable(node)) {
|
|
lastContentEditable = contentEditable;
|
|
contentEditable = dom.getContentEditable(node) === 'true';
|
|
hasContentEditableState = true;
|
|
}
|
|
children = Tools.grep(node.childNodes);
|
|
if (contentEditable && !hasContentEditableState) {
|
|
for (i = 0, l = formatList.length; i < l; i++) {
|
|
if (removeFormat(ed, formatList[i], vars, node, node)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (format.deep) {
|
|
if (children.length) {
|
|
for (i = 0, l = children.length; i < l; i++) {
|
|
process(children[i]);
|
|
}
|
|
if (hasContentEditableState) {
|
|
contentEditable = lastContentEditable;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var unwrap = function (start) {
|
|
var node = dom.get(start ? '_start' : '_end');
|
|
var out = node[start ? 'firstChild' : 'lastChild'];
|
|
if (isRemoveBookmarkNode(out)) {
|
|
out = out[start ? 'firstChild' : 'lastChild'];
|
|
}
|
|
if (NodeType.isText(out) && out.data.length === 0) {
|
|
out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
|
|
}
|
|
dom.remove(node, true);
|
|
return out;
|
|
};
|
|
var removeRngStyle = function (rng) {
|
|
var startContainer, endContainer;
|
|
var commonAncestorContainer = rng.commonAncestorContainer;
|
|
rng = ExpandRange.expandRng(ed, rng, formatList, true);
|
|
if (format.split) {
|
|
rng = split$1(rng);
|
|
startContainer = getContainer(ed, rng, true);
|
|
endContainer = getContainer(ed, rng);
|
|
if (startContainer !== endContainer) {
|
|
if (/^(TR|TH|TD)$/.test(startContainer.nodeName) && startContainer.firstChild) {
|
|
if (startContainer.nodeName === 'TR') {
|
|
startContainer = startContainer.firstChild.firstChild || startContainer;
|
|
} else {
|
|
startContainer = startContainer.firstChild || startContainer;
|
|
}
|
|
}
|
|
if (commonAncestorContainer && /^T(HEAD|BODY|FOOT|R)$/.test(commonAncestorContainer.nodeName) && isTableCell$2(endContainer) && endContainer.firstChild) {
|
|
endContainer = endContainer.firstChild || endContainer;
|
|
}
|
|
if (isChildOfInlineParent(dom, startContainer, endContainer)) {
|
|
var marker = Option.from(startContainer.firstChild).getOr(startContainer);
|
|
splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
|
|
'id': '_start',
|
|
'data-mce-type': 'bookmark'
|
|
}));
|
|
unwrap(true);
|
|
return;
|
|
}
|
|
if (isChildOfInlineParent(dom, endContainer, startContainer)) {
|
|
var marker = Option.from(endContainer.lastChild).getOr(endContainer);
|
|
splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
|
|
'id': '_end',
|
|
'data-mce-type': 'bookmark'
|
|
}));
|
|
unwrap(false);
|
|
return;
|
|
}
|
|
startContainer = wrap$2(dom, startContainer, 'span', {
|
|
'id': '_start',
|
|
'data-mce-type': 'bookmark'
|
|
});
|
|
endContainer = wrap$2(dom, endContainer, 'span', {
|
|
'id': '_end',
|
|
'data-mce-type': 'bookmark'
|
|
});
|
|
splitToFormatRoot(startContainer);
|
|
splitToFormatRoot(endContainer);
|
|
startContainer = unwrap(true);
|
|
endContainer = unwrap();
|
|
} else {
|
|
startContainer = endContainer = splitToFormatRoot(startContainer);
|
|
}
|
|
rng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
|
|
rng.startOffset = dom.nodeIndex(startContainer);
|
|
rng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
|
|
rng.endOffset = dom.nodeIndex(endContainer) + 1;
|
|
}
|
|
RangeWalk.walk(dom, rng, function (nodes) {
|
|
each$b(nodes, function (node) {
|
|
process(node);
|
|
if (NodeType.isElement(node) && ed.dom.getStyle(node, 'text-decoration') === 'underline' && node.parentNode && FormatUtils.getTextDecoration(dom, node.parentNode) === 'underline') {
|
|
removeFormat(ed, {
|
|
deep: false,
|
|
exact: true,
|
|
inline: 'span',
|
|
styles: { textDecoration: 'underline' }
|
|
}, null, node);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
if (node) {
|
|
if (node.nodeType) {
|
|
rng = dom.createRng();
|
|
rng.setStartBefore(node);
|
|
rng.setEndAfter(node);
|
|
removeRngStyle(rng);
|
|
} else {
|
|
removeRngStyle(node);
|
|
}
|
|
return;
|
|
}
|
|
if (dom.getContentEditable(selection.getNode()) === 'false') {
|
|
node = selection.getNode();
|
|
for (var i = 0, l = formatList.length; i < l; i++) {
|
|
if (formatList[i].ceFalseOverride) {
|
|
if (removeFormat(ed, formatList[i], vars, node, node)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (!selection.isCollapsed() || !format.inline || dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
|
|
bookmark = GetBookmark.getPersistentBookmark(ed.selection, true);
|
|
removeRngStyle(selection.getRng());
|
|
selection.moveToBookmark(bookmark);
|
|
if (format.inline && MatchFormat.match(ed, name, vars, selection.getStart())) {
|
|
FormatUtils.moveStart(dom, selection, selection.getRng());
|
|
}
|
|
ed.nodeChanged();
|
|
} else {
|
|
removeCaretFormat(ed, name, vars, similar);
|
|
}
|
|
};
|
|
var RemoveFormat = {
|
|
removeFormat: removeFormat,
|
|
remove: remove$7
|
|
};
|
|
|
|
var each$c = Tools.each;
|
|
var isElementNode = function (node) {
|
|
return node && node.nodeType === 1 && !Bookmarks.isBookmarkNode(node) && !isCaretNode(node) && !NodeType.isBogus(node);
|
|
};
|
|
var findElementSibling = function (node, siblingName) {
|
|
var sibling;
|
|
for (sibling = node; sibling; sibling = sibling[siblingName]) {
|
|
if (sibling.nodeType === 3 && sibling.nodeValue.length !== 0) {
|
|
return node;
|
|
}
|
|
if (sibling.nodeType === 1 && !Bookmarks.isBookmarkNode(sibling)) {
|
|
return sibling;
|
|
}
|
|
}
|
|
return node;
|
|
};
|
|
var mergeSiblingsNodes = function (dom, prev, next) {
|
|
var sibling, tmpSibling;
|
|
var elementUtils = new ElementUtils(dom);
|
|
if (prev && next) {
|
|
prev = findElementSibling(prev, 'previousSibling');
|
|
next = findElementSibling(next, 'nextSibling');
|
|
if (elementUtils.compare(prev, next)) {
|
|
for (sibling = prev.nextSibling; sibling && sibling !== next;) {
|
|
tmpSibling = sibling;
|
|
sibling = sibling.nextSibling;
|
|
prev.appendChild(tmpSibling);
|
|
}
|
|
dom.remove(next);
|
|
Tools.each(Tools.grep(next.childNodes), function (node) {
|
|
prev.appendChild(node);
|
|
});
|
|
return prev;
|
|
}
|
|
}
|
|
return next;
|
|
};
|
|
var processChildElements = function (node, filter, process) {
|
|
each$c(node.childNodes, function (node) {
|
|
if (isElementNode(node)) {
|
|
if (filter(node)) {
|
|
process(node);
|
|
}
|
|
if (node.hasChildNodes()) {
|
|
processChildElements(node, filter, process);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
var hasStyle = function (dom, name) {
|
|
return curry(function (name, node) {
|
|
return !!(node && FormatUtils.getStyle(dom, node, name));
|
|
}, name);
|
|
};
|
|
var applyStyle = function (dom, name, value) {
|
|
return curry(function (name, value, node) {
|
|
dom.setStyle(node, name, value);
|
|
if (node.getAttribute('style') === '') {
|
|
node.removeAttribute('style');
|
|
}
|
|
unwrapEmptySpan(dom, node);
|
|
}, name, value);
|
|
};
|
|
var unwrapEmptySpan = function (dom, node) {
|
|
if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
|
|
dom.remove(node, true);
|
|
}
|
|
};
|
|
var processUnderlineAndColor = function (dom, node) {
|
|
var textDecoration;
|
|
if (node.nodeType === 1 && node.parentNode && node.parentNode.nodeType === 1) {
|
|
textDecoration = FormatUtils.getTextDecoration(dom, node.parentNode);
|
|
if (dom.getStyle(node, 'color') && textDecoration) {
|
|
dom.setStyle(node, 'text-decoration', textDecoration);
|
|
} else if (dom.getStyle(node, 'text-decoration') === textDecoration) {
|
|
dom.setStyle(node, 'text-decoration', null);
|
|
}
|
|
}
|
|
};
|
|
var mergeUnderlineAndColor = function (dom, format, vars, node) {
|
|
if (format.styles.color || format.styles.textDecoration) {
|
|
Tools.walk(node, curry(processUnderlineAndColor, dom), 'childNodes');
|
|
processUnderlineAndColor(dom, node);
|
|
}
|
|
};
|
|
var mergeBackgroundColorAndFontSize = function (dom, format, vars, node) {
|
|
if (format.styles && format.styles.backgroundColor) {
|
|
processChildElements(node, hasStyle(dom, 'fontSize'), applyStyle(dom, 'backgroundColor', FormatUtils.replaceVars(format.styles.backgroundColor, vars)));
|
|
}
|
|
};
|
|
var mergeSubSup = function (dom, format, vars, node) {
|
|
if (format.inline === 'sub' || format.inline === 'sup') {
|
|
processChildElements(node, hasStyle(dom, 'fontSize'), applyStyle(dom, 'fontSize', ''));
|
|
dom.remove(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), true);
|
|
}
|
|
};
|
|
var mergeSiblings = function (dom, format, vars, node) {
|
|
if (node && format.merge_siblings !== false) {
|
|
node = mergeSiblingsNodes(dom, FormatUtils.getNonWhiteSpaceSibling(node), node);
|
|
node = mergeSiblingsNodes(dom, node, FormatUtils.getNonWhiteSpaceSibling(node, true));
|
|
}
|
|
};
|
|
var clearChildStyles = function (dom, format, node) {
|
|
if (format.clear_child_styles) {
|
|
var selector = format.links ? '*:not(a)' : '*';
|
|
each$c(dom.select(selector, node), function (node) {
|
|
if (isElementNode(node)) {
|
|
each$c(format.styles, function (value, name) {
|
|
dom.setStyle(node, name, '');
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var mergeWithChildren = function (editor, formatList, vars, node) {
|
|
each$c(formatList, function (format) {
|
|
each$c(editor.dom.select(format.inline, node), function (child) {
|
|
if (!isElementNode(child)) {
|
|
return;
|
|
}
|
|
RemoveFormat.removeFormat(editor, format, vars, child, format.exact ? child : null);
|
|
});
|
|
clearChildStyles(editor.dom, format, node);
|
|
});
|
|
};
|
|
var mergeWithParents = function (editor, format, name, vars, node) {
|
|
if (MatchFormat.matchNode(editor, node.parentNode, name, vars)) {
|
|
if (RemoveFormat.removeFormat(editor, format, vars, node)) {
|
|
return;
|
|
}
|
|
}
|
|
if (format.merge_with_parents) {
|
|
editor.dom.getParent(node.parentNode, function (parent) {
|
|
if (MatchFormat.matchNode(editor, parent, name, vars)) {
|
|
RemoveFormat.removeFormat(editor, format, vars, node);
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var MergeFormats = {
|
|
mergeWithChildren: mergeWithChildren,
|
|
mergeUnderlineAndColor: mergeUnderlineAndColor,
|
|
mergeBackgroundColorAndFontSize: mergeBackgroundColorAndFontSize,
|
|
mergeSubSup: mergeSubSup,
|
|
mergeSiblings: mergeSiblings,
|
|
mergeWithParents: mergeWithParents
|
|
};
|
|
|
|
var createRange$1 = function (sc, so, ec, eo) {
|
|
var rng = domGlobals.document.createRange();
|
|
rng.setStart(sc, so);
|
|
rng.setEnd(ec, eo);
|
|
return rng;
|
|
};
|
|
var normalizeBlockSelectionRange = function (rng) {
|
|
var startPos = CaretPosition$1.fromRangeStart(rng);
|
|
var endPos = CaretPosition$1.fromRangeEnd(rng);
|
|
var rootNode = rng.commonAncestorContainer;
|
|
return CaretFinder.fromPosition(false, rootNode, endPos).map(function (newEndPos) {
|
|
if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
|
|
return createRange$1(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
|
|
} else {
|
|
return rng;
|
|
}
|
|
}).getOr(rng);
|
|
};
|
|
var normalize$1 = function (rng) {
|
|
return rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
|
|
};
|
|
var RangeNormalizer = { normalize: normalize$1 };
|
|
|
|
var each$d = Tools.each;
|
|
var isElementNode$1 = function (node) {
|
|
return node && node.nodeType === 1 && !Bookmarks.isBookmarkNode(node) && !isCaretNode(node) && !NodeType.isBogus(node);
|
|
};
|
|
var applyFormat = function (ed, name, vars, node) {
|
|
var formatList = ed.formatter.get(name);
|
|
var format = formatList[0];
|
|
var bookmark, rng;
|
|
var isCollapsed = !node && ed.selection.isCollapsed();
|
|
var dom = ed.dom, selection = ed.selection;
|
|
var setElementFormat = function (elm, fmt) {
|
|
fmt = fmt || format;
|
|
if (elm) {
|
|
if (fmt.onformat) {
|
|
fmt.onformat(elm, fmt, vars, node);
|
|
}
|
|
each$d(fmt.styles, function (value, name) {
|
|
dom.setStyle(elm, name, FormatUtils.replaceVars(value, vars));
|
|
});
|
|
if (fmt.styles) {
|
|
var styleVal = dom.getAttrib(elm, 'style');
|
|
if (styleVal) {
|
|
elm.setAttribute('data-mce-style', styleVal);
|
|
}
|
|
}
|
|
each$d(fmt.attributes, function (value, name) {
|
|
dom.setAttrib(elm, name, FormatUtils.replaceVars(value, vars));
|
|
});
|
|
each$d(fmt.classes, function (value) {
|
|
value = FormatUtils.replaceVars(value, vars);
|
|
if (!dom.hasClass(elm, value)) {
|
|
dom.addClass(elm, value);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var applyNodeStyle = function (formatList, node) {
|
|
var found = false;
|
|
if (!format.selector) {
|
|
return false;
|
|
}
|
|
each$d(formatList, function (format) {
|
|
if ('collapsed' in format && format.collapsed !== isCollapsed) {
|
|
return;
|
|
}
|
|
if (dom.is(node, format.selector) && !isCaretNode(node)) {
|
|
setElementFormat(node, format);
|
|
found = true;
|
|
return false;
|
|
}
|
|
});
|
|
return found;
|
|
};
|
|
var applyRngStyle = function (dom, rng, bookmark, nodeSpecific) {
|
|
var newWrappers = [];
|
|
var wrapName, wrapElm, contentEditable = true;
|
|
wrapName = format.inline || format.block;
|
|
wrapElm = dom.create(wrapName);
|
|
setElementFormat(wrapElm);
|
|
RangeWalk.walk(dom, rng, function (nodes) {
|
|
var currentWrapElm;
|
|
var process = function (node) {
|
|
var nodeName, parentName, hasContentEditableState, lastContentEditable;
|
|
lastContentEditable = contentEditable;
|
|
nodeName = node.nodeName.toLowerCase();
|
|
parentName = node.parentNode.nodeName.toLowerCase();
|
|
if (node.nodeType === 1 && dom.getContentEditable(node)) {
|
|
lastContentEditable = contentEditable;
|
|
contentEditable = dom.getContentEditable(node) === 'true';
|
|
hasContentEditableState = true;
|
|
}
|
|
if (FormatUtils.isEq(nodeName, 'br')) {
|
|
currentWrapElm = 0;
|
|
if (format.block) {
|
|
dom.remove(node);
|
|
}
|
|
return;
|
|
}
|
|
if (format.wrapper && MatchFormat.matchNode(ed, node, name, vars)) {
|
|
currentWrapElm = 0;
|
|
return;
|
|
}
|
|
if (contentEditable && !hasContentEditableState && format.block && !format.wrapper && FormatUtils.isTextBlock(ed, nodeName) && FormatUtils.isValid(ed, parentName, wrapName)) {
|
|
node = dom.rename(node, wrapName);
|
|
setElementFormat(node);
|
|
newWrappers.push(node);
|
|
currentWrapElm = 0;
|
|
return;
|
|
}
|
|
if (format.selector) {
|
|
var found = applyNodeStyle(formatList, node);
|
|
if (!format.inline || found) {
|
|
currentWrapElm = 0;
|
|
return;
|
|
}
|
|
}
|
|
if (contentEditable && !hasContentEditableState && FormatUtils.isValid(ed, wrapName, nodeName) && FormatUtils.isValid(ed, parentName, wrapName) && !(!nodeSpecific && node.nodeType === 3 && node.nodeValue.length === 1 && node.nodeValue.charCodeAt(0) === 65279) && !isCaretNode(node) && (!format.inline || !dom.isBlock(node))) {
|
|
if (!currentWrapElm) {
|
|
currentWrapElm = dom.clone(wrapElm, false);
|
|
node.parentNode.insertBefore(currentWrapElm, node);
|
|
newWrappers.push(currentWrapElm);
|
|
}
|
|
currentWrapElm.appendChild(node);
|
|
} else {
|
|
currentWrapElm = 0;
|
|
each$d(Tools.grep(node.childNodes), process);
|
|
if (hasContentEditableState) {
|
|
contentEditable = lastContentEditable;
|
|
}
|
|
currentWrapElm = 0;
|
|
}
|
|
};
|
|
each$d(nodes, process);
|
|
});
|
|
if (format.links === true) {
|
|
each$d(newWrappers, function (node) {
|
|
var process = function (node) {
|
|
if (node.nodeName === 'A') {
|
|
setElementFormat(node, format);
|
|
}
|
|
each$d(Tools.grep(node.childNodes), process);
|
|
};
|
|
process(node);
|
|
});
|
|
}
|
|
each$d(newWrappers, function (node) {
|
|
var childCount;
|
|
var getChildCount = function (node) {
|
|
var count = 0;
|
|
each$d(node.childNodes, function (node) {
|
|
if (!FormatUtils.isWhiteSpaceNode(node) && !Bookmarks.isBookmarkNode(node)) {
|
|
count++;
|
|
}
|
|
});
|
|
return count;
|
|
};
|
|
var getChildElementNode = function (root) {
|
|
var child = false;
|
|
each$d(root.childNodes, function (node) {
|
|
if (isElementNode$1(node)) {
|
|
child = node;
|
|
return false;
|
|
}
|
|
});
|
|
return child;
|
|
};
|
|
var mergeStyles = function (node) {
|
|
var child, clone;
|
|
child = getChildElementNode(node);
|
|
if (child && !Bookmarks.isBookmarkNode(child) && MatchFormat.matchName(dom, child, format)) {
|
|
clone = dom.clone(child, false);
|
|
setElementFormat(clone);
|
|
dom.replace(clone, node, true);
|
|
dom.remove(child, 1);
|
|
}
|
|
return clone || node;
|
|
};
|
|
childCount = getChildCount(node);
|
|
if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
|
|
dom.remove(node, 1);
|
|
return;
|
|
}
|
|
if (format.inline || format.wrapper) {
|
|
if (!format.exact && childCount === 1) {
|
|
node = mergeStyles(node);
|
|
}
|
|
MergeFormats.mergeWithChildren(ed, formatList, vars, node);
|
|
MergeFormats.mergeWithParents(ed, format, name, vars, node);
|
|
MergeFormats.mergeBackgroundColorAndFontSize(dom, format, vars, node);
|
|
MergeFormats.mergeSubSup(dom, format, vars, node);
|
|
MergeFormats.mergeSiblings(dom, format, vars, node);
|
|
}
|
|
});
|
|
};
|
|
if (dom.getContentEditable(selection.getNode()) === 'false') {
|
|
node = selection.getNode();
|
|
for (var i = 0, l = formatList.length; i < l; i++) {
|
|
if (formatList[i].ceFalseOverride && dom.is(node, formatList[i].selector)) {
|
|
setElementFormat(node, formatList[i]);
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (format) {
|
|
if (node) {
|
|
if (node.nodeType) {
|
|
if (!applyNodeStyle(formatList, node)) {
|
|
rng = dom.createRng();
|
|
rng.setStartBefore(node);
|
|
rng.setEndAfter(node);
|
|
applyRngStyle(dom, ExpandRange.expandRng(ed, rng, formatList), null, true);
|
|
}
|
|
} else {
|
|
applyRngStyle(dom, node, null, true);
|
|
}
|
|
} else {
|
|
if (!isCollapsed || !format.inline || dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
|
|
var curSelNode = ed.selection.getNode();
|
|
if (!ed.settings.forced_root_block && formatList[0].defaultBlock && !dom.getParent(curSelNode, dom.isBlock)) {
|
|
applyFormat(ed, formatList[0].defaultBlock);
|
|
}
|
|
ed.selection.setRng(RangeNormalizer.normalize(ed.selection.getRng()));
|
|
bookmark = GetBookmark.getPersistentBookmark(ed.selection, true);
|
|
applyRngStyle(dom, ExpandRange.expandRng(ed, selection.getRng(), formatList));
|
|
if (format.styles) {
|
|
MergeFormats.mergeUnderlineAndColor(dom, format, vars, curSelNode);
|
|
}
|
|
selection.moveToBookmark(bookmark);
|
|
FormatUtils.moveStart(dom, selection, selection.getRng());
|
|
ed.nodeChanged();
|
|
} else {
|
|
applyCaretFormat(ed, name, vars);
|
|
}
|
|
}
|
|
Hooks.postProcess(name, ed);
|
|
}
|
|
};
|
|
var ApplyFormat = { applyFormat: applyFormat };
|
|
|
|
var setup$6 = function (registeredFormatListeners, editor) {
|
|
var currentFormats = Cell({});
|
|
registeredFormatListeners.set({});
|
|
editor.on('NodeChange', function (e) {
|
|
updateAndFireChangeCallbacks(editor, e.element, currentFormats, registeredFormatListeners.get());
|
|
});
|
|
};
|
|
var updateAndFireChangeCallbacks = function (editor, elm, currentFormats, formatChangeData) {
|
|
var formatsList = keys(currentFormats.get());
|
|
var newFormats = {};
|
|
var matchedFormats = {};
|
|
var parents = filter(FormatUtils.getParents(editor.dom, elm), function (node) {
|
|
return node.nodeType === 1 && !node.getAttribute('data-mce-bogus');
|
|
});
|
|
each$1(formatChangeData, function (data, format) {
|
|
Tools.each(parents, function (node) {
|
|
if (editor.formatter.matchNode(node, format, {}, data.similar)) {
|
|
if (formatsList.indexOf(format) === -1) {
|
|
each(data.callbacks, function (callback) {
|
|
callback(true, {
|
|
node: node,
|
|
format: format,
|
|
parents: parents
|
|
});
|
|
});
|
|
newFormats[format] = data.callbacks;
|
|
}
|
|
matchedFormats[format] = data.callbacks;
|
|
return false;
|
|
}
|
|
if (MatchFormat.matchesUnInheritedFormatSelector(editor, node, format)) {
|
|
return false;
|
|
}
|
|
});
|
|
});
|
|
var remainingFormats = filterRemainingFormats(currentFormats.get(), matchedFormats, elm, parents);
|
|
currentFormats.set(__assign(__assign({}, newFormats), remainingFormats));
|
|
};
|
|
var filterRemainingFormats = function (currentFormats, matchedFormats, elm, parents) {
|
|
return bifilter(currentFormats, function (callbacks, format) {
|
|
if (!has(matchedFormats, format)) {
|
|
each(callbacks, function (callback) {
|
|
callback(false, {
|
|
node: elm,
|
|
format: format,
|
|
parents: parents
|
|
});
|
|
});
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}).t;
|
|
};
|
|
var addListeners = function (registeredFormatListeners, formats, callback, similar) {
|
|
var formatChangeItems = registeredFormatListeners.get();
|
|
each(formats.split(','), function (format) {
|
|
if (!formatChangeItems[format]) {
|
|
formatChangeItems[format] = {
|
|
similar: similar,
|
|
callbacks: []
|
|
};
|
|
}
|
|
formatChangeItems[format].callbacks.push(callback);
|
|
});
|
|
registeredFormatListeners.set(formatChangeItems);
|
|
};
|
|
var removeListeners = function (registeredFormatListeners, formats, callback) {
|
|
var formatChangeItems = registeredFormatListeners.get();
|
|
each(formats.split(','), function (format) {
|
|
formatChangeItems[format].callbacks = filter(formatChangeItems[format].callbacks, function (c) {
|
|
return c !== callback;
|
|
});
|
|
if (formatChangeItems[format].callbacks.length === 0) {
|
|
delete formatChangeItems[format];
|
|
}
|
|
});
|
|
registeredFormatListeners.set(formatChangeItems);
|
|
};
|
|
var formatChanged = function (editor, registeredFormatListeners, formats, callback, similar) {
|
|
if (registeredFormatListeners.get() === null) {
|
|
setup$6(registeredFormatListeners, editor);
|
|
}
|
|
addListeners(registeredFormatListeners, formats, callback, similar);
|
|
return {
|
|
unbind: function () {
|
|
return removeListeners(registeredFormatListeners, formats, callback);
|
|
}
|
|
};
|
|
};
|
|
|
|
var get$7 = function (dom) {
|
|
var formats = {
|
|
valigntop: [{
|
|
selector: 'td,th',
|
|
styles: { verticalAlign: 'top' }
|
|
}],
|
|
valignmiddle: [{
|
|
selector: 'td,th',
|
|
styles: { verticalAlign: 'middle' }
|
|
}],
|
|
valignbottom: [{
|
|
selector: 'td,th',
|
|
styles: { verticalAlign: 'bottom' }
|
|
}],
|
|
alignleft: [
|
|
{
|
|
selector: 'figure.image',
|
|
collapsed: false,
|
|
classes: 'align-left',
|
|
ceFalseOverride: true,
|
|
preview: 'font-family font-size'
|
|
},
|
|
{
|
|
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
|
|
styles: { textAlign: 'left' },
|
|
inherit: false,
|
|
preview: false,
|
|
defaultBlock: 'div'
|
|
},
|
|
{
|
|
selector: 'img,table',
|
|
collapsed: false,
|
|
styles: { float: 'left' },
|
|
preview: 'font-family font-size'
|
|
}
|
|
],
|
|
aligncenter: [
|
|
{
|
|
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
|
|
styles: { textAlign: 'center' },
|
|
inherit: false,
|
|
preview: 'font-family font-size',
|
|
defaultBlock: 'div'
|
|
},
|
|
{
|
|
selector: 'figure.image',
|
|
collapsed: false,
|
|
classes: 'align-center',
|
|
ceFalseOverride: true,
|
|
preview: 'font-family font-size'
|
|
},
|
|
{
|
|
selector: 'img',
|
|
collapsed: false,
|
|
styles: {
|
|
display: 'block',
|
|
marginLeft: 'auto',
|
|
marginRight: 'auto'
|
|
},
|
|
preview: false
|
|
},
|
|
{
|
|
selector: 'table',
|
|
collapsed: false,
|
|
styles: {
|
|
marginLeft: 'auto',
|
|
marginRight: 'auto'
|
|
},
|
|
preview: 'font-family font-size'
|
|
}
|
|
],
|
|
alignright: [
|
|
{
|
|
selector: 'figure.image',
|
|
collapsed: false,
|
|
classes: 'align-right',
|
|
ceFalseOverride: true,
|
|
preview: 'font-family font-size'
|
|
},
|
|
{
|
|
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
|
|
styles: { textAlign: 'right' },
|
|
inherit: false,
|
|
preview: 'font-family font-size',
|
|
defaultBlock: 'div'
|
|
},
|
|
{
|
|
selector: 'img,table',
|
|
collapsed: false,
|
|
styles: { float: 'right' },
|
|
preview: 'font-family font-size'
|
|
}
|
|
],
|
|
alignjustify: [{
|
|
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li',
|
|
styles: { textAlign: 'justify' },
|
|
inherit: false,
|
|
defaultBlock: 'div',
|
|
preview: 'font-family font-size'
|
|
}],
|
|
bold: [
|
|
{
|
|
inline: 'strong',
|
|
remove: 'all'
|
|
},
|
|
{
|
|
inline: 'span',
|
|
styles: { fontWeight: 'bold' }
|
|
},
|
|
{
|
|
inline: 'b',
|
|
remove: 'all'
|
|
}
|
|
],
|
|
italic: [
|
|
{
|
|
inline: 'em',
|
|
remove: 'all'
|
|
},
|
|
{
|
|
inline: 'span',
|
|
styles: { fontStyle: 'italic' }
|
|
},
|
|
{
|
|
inline: 'i',
|
|
remove: 'all'
|
|
}
|
|
],
|
|
underline: [
|
|
{
|
|
inline: 'span',
|
|
styles: { textDecoration: 'underline' },
|
|
exact: true
|
|
},
|
|
{
|
|
inline: 'u',
|
|
remove: 'all'
|
|
}
|
|
],
|
|
strikethrough: [
|
|
{
|
|
inline: 'span',
|
|
styles: { textDecoration: 'line-through' },
|
|
exact: true
|
|
},
|
|
{
|
|
inline: 'strike',
|
|
remove: 'all'
|
|
}
|
|
],
|
|
forecolor: {
|
|
inline: 'span',
|
|
styles: { color: '%value' },
|
|
links: true,
|
|
remove_similar: true,
|
|
clear_child_styles: true
|
|
},
|
|
hilitecolor: {
|
|
inline: 'span',
|
|
styles: { backgroundColor: '%value' },
|
|
links: true,
|
|
remove_similar: true,
|
|
clear_child_styles: true
|
|
},
|
|
fontname: {
|
|
inline: 'span',
|
|
toggle: false,
|
|
styles: { fontFamily: '%value' },
|
|
clear_child_styles: true
|
|
},
|
|
fontsize: {
|
|
inline: 'span',
|
|
toggle: false,
|
|
styles: { fontSize: '%value' },
|
|
clear_child_styles: true
|
|
},
|
|
fontsize_class: {
|
|
inline: 'span',
|
|
attributes: { class: '%value' }
|
|
},
|
|
blockquote: {
|
|
block: 'blockquote',
|
|
wrapper: true,
|
|
remove: 'all'
|
|
},
|
|
subscript: { inline: 'sub' },
|
|
superscript: { inline: 'sup' },
|
|
code: { inline: 'code' },
|
|
link: {
|
|
inline: 'a',
|
|
selector: 'a',
|
|
remove: 'all',
|
|
split: true,
|
|
deep: true,
|
|
onmatch: function () {
|
|
return true;
|
|
},
|
|
onformat: function (elm, fmt, vars) {
|
|
Tools.each(vars, function (value, key) {
|
|
dom.setAttrib(elm, key, value);
|
|
});
|
|
}
|
|
},
|
|
removeformat: [
|
|
{
|
|
selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins',
|
|
remove: 'all',
|
|
split: true,
|
|
expand: false,
|
|
block_expand: true,
|
|
deep: true
|
|
},
|
|
{
|
|
selector: 'span',
|
|
attributes: [
|
|
'style',
|
|
'class'
|
|
],
|
|
remove: 'empty',
|
|
split: true,
|
|
expand: false,
|
|
deep: true
|
|
},
|
|
{
|
|
selector: '*',
|
|
attributes: [
|
|
'style',
|
|
'class'
|
|
],
|
|
split: false,
|
|
expand: false,
|
|
deep: true
|
|
}
|
|
]
|
|
};
|
|
Tools.each('p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp'.split(/\s/), function (name) {
|
|
formats[name] = {
|
|
block: name,
|
|
remove: 'all'
|
|
};
|
|
});
|
|
return formats;
|
|
};
|
|
var DefaultFormats = { get: get$7 };
|
|
|
|
function FormatRegistry(editor) {
|
|
var formats = {};
|
|
var get = function (name) {
|
|
return name ? formats[name] : formats;
|
|
};
|
|
var has$1 = function (name) {
|
|
return has(formats, name);
|
|
};
|
|
var register = function (name, format) {
|
|
if (name) {
|
|
if (typeof name !== 'string') {
|
|
Tools.each(name, function (format, name) {
|
|
register(name, format);
|
|
});
|
|
} else {
|
|
if (!isArray(format)) {
|
|
format = [format];
|
|
}
|
|
Tools.each(format, function (format) {
|
|
if (typeof format.deep === 'undefined') {
|
|
format.deep = !format.selector;
|
|
}
|
|
if (typeof format.split === 'undefined') {
|
|
format.split = !format.selector || format.inline;
|
|
}
|
|
if (typeof format.remove === 'undefined' && format.selector && !format.inline) {
|
|
format.remove = 'none';
|
|
}
|
|
if (format.selector && format.inline) {
|
|
format.mixed = true;
|
|
format.block_expand = true;
|
|
}
|
|
if (typeof format.classes === 'string') {
|
|
format.classes = format.classes.split(/\s+/);
|
|
}
|
|
});
|
|
formats[name] = format;
|
|
}
|
|
}
|
|
};
|
|
var unregister = function (name) {
|
|
if (name && formats[name]) {
|
|
delete formats[name];
|
|
}
|
|
return formats;
|
|
};
|
|
register(DefaultFormats.get(editor.dom));
|
|
register(editor.settings.formats);
|
|
return {
|
|
get: get,
|
|
has: has$1,
|
|
register: register,
|
|
unregister: unregister
|
|
};
|
|
}
|
|
|
|
var each$e = Tools.each;
|
|
var dom = DOMUtils$1.DOM;
|
|
var parsedSelectorToHtml = function (ancestry, editor) {
|
|
var elm, item, fragment;
|
|
var schema = editor && editor.schema || Schema({});
|
|
var decorate = function (elm, item) {
|
|
if (item.classes.length) {
|
|
dom.addClass(elm, item.classes.join(' '));
|
|
}
|
|
dom.setAttribs(elm, item.attrs);
|
|
};
|
|
var createElement = function (sItem) {
|
|
var elm;
|
|
item = typeof sItem === 'string' ? {
|
|
name: sItem,
|
|
classes: [],
|
|
attrs: {}
|
|
} : sItem;
|
|
elm = dom.create(item.name);
|
|
decorate(elm, item);
|
|
return elm;
|
|
};
|
|
var getRequiredParent = function (elm, candidate) {
|
|
var name = typeof elm !== 'string' ? elm.nodeName.toLowerCase() : elm;
|
|
var elmRule = schema.getElementRule(name);
|
|
var parentsRequired = elmRule && elmRule.parentsRequired;
|
|
if (parentsRequired && parentsRequired.length) {
|
|
return candidate && Tools.inArray(parentsRequired, candidate) !== -1 ? candidate : parentsRequired[0];
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var wrapInHtml = function (elm, ancestry, siblings) {
|
|
var parent, parentCandidate, parentRequired;
|
|
var ancestor = ancestry.length > 0 && ancestry[0];
|
|
var ancestorName = ancestor && ancestor.name;
|
|
parentRequired = getRequiredParent(elm, ancestorName);
|
|
if (parentRequired) {
|
|
if (ancestorName === parentRequired) {
|
|
parentCandidate = ancestry[0];
|
|
ancestry = ancestry.slice(1);
|
|
} else {
|
|
parentCandidate = parentRequired;
|
|
}
|
|
} else if (ancestor) {
|
|
parentCandidate = ancestry[0];
|
|
ancestry = ancestry.slice(1);
|
|
} else if (!siblings) {
|
|
return elm;
|
|
}
|
|
if (parentCandidate) {
|
|
parent = createElement(parentCandidate);
|
|
parent.appendChild(elm);
|
|
}
|
|
if (siblings) {
|
|
if (!parent) {
|
|
parent = dom.create('div');
|
|
parent.appendChild(elm);
|
|
}
|
|
Tools.each(siblings, function (sibling) {
|
|
var siblingElm = createElement(sibling);
|
|
parent.insertBefore(siblingElm, elm);
|
|
});
|
|
}
|
|
return wrapInHtml(parent, ancestry, parentCandidate && parentCandidate.siblings);
|
|
};
|
|
if (ancestry && ancestry.length) {
|
|
item = ancestry[0];
|
|
elm = createElement(item);
|
|
fragment = dom.create('div');
|
|
fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), item.siblings));
|
|
return fragment;
|
|
} else {
|
|
return '';
|
|
}
|
|
};
|
|
var selectorToHtml = function (selector, editor) {
|
|
return parsedSelectorToHtml(parseSelector(selector), editor);
|
|
};
|
|
var parseSelectorItem = function (item) {
|
|
var tagName;
|
|
var obj = {
|
|
classes: [],
|
|
attrs: {}
|
|
};
|
|
item = obj.selector = Tools.trim(item);
|
|
if (item !== '*') {
|
|
tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, function ($0, $1, $2, $3, $4) {
|
|
switch ($1) {
|
|
case '#':
|
|
obj.attrs.id = $2;
|
|
break;
|
|
case '.':
|
|
obj.classes.push($2);
|
|
break;
|
|
case ':':
|
|
if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
|
|
obj.attrs[$2] = $2;
|
|
}
|
|
break;
|
|
}
|
|
if ($3 === '[') {
|
|
var m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
|
|
if (m) {
|
|
obj.attrs[m[1]] = m[2];
|
|
}
|
|
}
|
|
return '';
|
|
});
|
|
}
|
|
obj.name = tagName || 'div';
|
|
return obj;
|
|
};
|
|
var parseSelector = function (selector) {
|
|
if (!selector || typeof selector !== 'string') {
|
|
return [];
|
|
}
|
|
selector = selector.split(/\s*,\s*/)[0];
|
|
selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
|
|
return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), function (item) {
|
|
var siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
|
|
var obj = siblings.pop();
|
|
if (siblings.length) {
|
|
obj.siblings = siblings;
|
|
}
|
|
return obj;
|
|
}).reverse();
|
|
};
|
|
var getCssText = function (editor, format) {
|
|
var name, previewFrag, previewElm, items;
|
|
var previewCss = '', parentFontSize, previewStyles;
|
|
previewStyles = editor.settings.preview_styles;
|
|
if (previewStyles === false) {
|
|
return '';
|
|
}
|
|
if (typeof previewStyles !== 'string') {
|
|
previewStyles = 'font-family font-size font-weight font-style text-decoration ' + 'text-transform color background-color border border-radius outline text-shadow';
|
|
}
|
|
var removeVars = function (val) {
|
|
return val.replace(/%(\w+)/g, '');
|
|
};
|
|
if (typeof format === 'string') {
|
|
format = editor.formatter.get(format);
|
|
if (!format) {
|
|
return;
|
|
}
|
|
format = format[0];
|
|
}
|
|
if ('preview' in format) {
|
|
previewStyles = format.preview;
|
|
if (previewStyles === false) {
|
|
return '';
|
|
}
|
|
}
|
|
name = format.block || format.inline || 'span';
|
|
items = parseSelector(format.selector);
|
|
if (items.length) {
|
|
if (!items[0].name) {
|
|
items[0].name = name;
|
|
}
|
|
name = format.selector;
|
|
previewFrag = parsedSelectorToHtml(items, editor);
|
|
} else {
|
|
previewFrag = parsedSelectorToHtml([name], editor);
|
|
}
|
|
previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
|
|
each$e(format.styles, function (value, name) {
|
|
value = removeVars(value);
|
|
if (value) {
|
|
dom.setStyle(previewElm, name, value);
|
|
}
|
|
});
|
|
each$e(format.attributes, function (value, name) {
|
|
value = removeVars(value);
|
|
if (value) {
|
|
dom.setAttrib(previewElm, name, value);
|
|
}
|
|
});
|
|
each$e(format.classes, function (value) {
|
|
value = removeVars(value);
|
|
if (!dom.hasClass(previewElm, value)) {
|
|
dom.addClass(previewElm, value);
|
|
}
|
|
});
|
|
editor.fire('PreviewFormats');
|
|
dom.setStyles(previewFrag, {
|
|
position: 'absolute',
|
|
left: -65535
|
|
});
|
|
editor.getBody().appendChild(previewFrag);
|
|
parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
|
|
parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
|
|
each$e(previewStyles.split(' '), function (name) {
|
|
var value = dom.getStyle(previewElm, name, true);
|
|
if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
|
|
value = dom.getStyle(editor.getBody(), name, true);
|
|
if (dom.toHex(value).toLowerCase() === '#ffffff') {
|
|
return;
|
|
}
|
|
}
|
|
if (name === 'color') {
|
|
if (dom.toHex(value).toLowerCase() === '#000000') {
|
|
return;
|
|
}
|
|
}
|
|
if (name === 'font-size') {
|
|
if (/em|%$/.test(value)) {
|
|
if (parentFontSize === 0) {
|
|
return;
|
|
}
|
|
var numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
|
|
value = numValue * parentFontSize + 'px';
|
|
}
|
|
}
|
|
if (name === 'border' && value) {
|
|
previewCss += 'padding:0 2px;';
|
|
}
|
|
previewCss += name + ':' + value + ';';
|
|
});
|
|
editor.fire('AfterPreviewFormats');
|
|
dom.remove(previewFrag);
|
|
return previewCss;
|
|
};
|
|
var Preview = {
|
|
getCssText: getCssText,
|
|
parseSelector: parseSelector,
|
|
selectorToHtml: selectorToHtml
|
|
};
|
|
|
|
var toggle = function (editor, formats, name, vars, node) {
|
|
var fmt = formats.get(name);
|
|
if (MatchFormat.match(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
|
|
RemoveFormat.remove(editor, name, vars, node);
|
|
} else {
|
|
ApplyFormat.applyFormat(editor, name, vars, node);
|
|
}
|
|
};
|
|
var ToggleFormat = { toggle: toggle };
|
|
|
|
var setup$7 = function (editor) {
|
|
editor.addShortcut('meta+b', '', 'Bold');
|
|
editor.addShortcut('meta+i', '', 'Italic');
|
|
editor.addShortcut('meta+u', '', 'Underline');
|
|
for (var i = 1; i <= 6; i++) {
|
|
editor.addShortcut('access+' + i, '', [
|
|
'FormatBlock',
|
|
false,
|
|
'h' + i
|
|
]);
|
|
}
|
|
editor.addShortcut('access+7', '', [
|
|
'FormatBlock',
|
|
false,
|
|
'p'
|
|
]);
|
|
editor.addShortcut('access+8', '', [
|
|
'FormatBlock',
|
|
false,
|
|
'div'
|
|
]);
|
|
editor.addShortcut('access+9', '', [
|
|
'FormatBlock',
|
|
false,
|
|
'address'
|
|
]);
|
|
};
|
|
var FormatShortcuts = { setup: setup$7 };
|
|
|
|
var Formatter = function (editor) {
|
|
var formats = FormatRegistry(editor);
|
|
var formatChangeState = Cell(null);
|
|
FormatShortcuts.setup(editor);
|
|
setup$5(editor);
|
|
return {
|
|
get: formats.get,
|
|
has: formats.has,
|
|
register: formats.register,
|
|
unregister: formats.unregister,
|
|
apply: curry(ApplyFormat.applyFormat, editor),
|
|
remove: curry(RemoveFormat.remove, editor),
|
|
toggle: curry(ToggleFormat.toggle, editor, formats),
|
|
match: curry(MatchFormat.match, editor),
|
|
matchAll: curry(MatchFormat.matchAll, editor),
|
|
matchNode: curry(MatchFormat.matchNode, editor),
|
|
canApply: curry(MatchFormat.canApply, editor),
|
|
formatChanged: curry(formatChanged, editor, formatChangeState),
|
|
getCssText: curry(Preview.getCssText, editor)
|
|
};
|
|
};
|
|
|
|
var register$1 = function (htmlParser, settings, dom) {
|
|
htmlParser.addAttributeFilter('data-mce-tabindex', function (nodes, name) {
|
|
var i = nodes.length, node;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
node.attr('tabindex', node.attr('data-mce-tabindex'));
|
|
node.attr(name, null);
|
|
}
|
|
});
|
|
htmlParser.addAttributeFilter('src,href,style', function (nodes, name) {
|
|
var i = nodes.length, node, value;
|
|
var internalName = 'data-mce-' + name;
|
|
var urlConverter = settings.url_converter;
|
|
var urlConverterScope = settings.url_converter_scope;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
value = node.attr(internalName);
|
|
if (value !== undefined) {
|
|
node.attr(name, value.length > 0 ? value : null);
|
|
node.attr(internalName, null);
|
|
} else {
|
|
value = node.attr(name);
|
|
if (name === 'style') {
|
|
value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
|
} else if (urlConverter) {
|
|
value = urlConverter.call(urlConverterScope, value, name, node.name);
|
|
}
|
|
node.attr(name, value.length > 0 ? value : null);
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addAttributeFilter('class', function (nodes) {
|
|
var i = nodes.length, node, value;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
value = node.attr('class');
|
|
if (value) {
|
|
value = node.attr('class').replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
|
|
node.attr('class', value.length > 0 ? value : null);
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addAttributeFilter('data-mce-type', function (nodes, name, args) {
|
|
var i = nodes.length, node;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
|
|
var hasChildren = Option.from(node.firstChild).exists(function (firstChild) {
|
|
return !Zwsp.isZwsp(firstChild.value);
|
|
});
|
|
if (hasChildren) {
|
|
node.unwrap();
|
|
} else {
|
|
node.remove();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addNodeFilter('noscript', function (nodes) {
|
|
var i = nodes.length, node;
|
|
while (i--) {
|
|
node = nodes[i].firstChild;
|
|
if (node) {
|
|
node.value = Entities.decode(node.value);
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addNodeFilter('script,style', function (nodes, name) {
|
|
var i = nodes.length, node, value, type;
|
|
var trim = function (value) {
|
|
return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n').replace(/^[\r\n]*|[\r\n]*$/g, '').replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '').replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
|
|
};
|
|
while (i--) {
|
|
node = nodes[i];
|
|
value = node.firstChild ? node.firstChild.value : '';
|
|
if (name === 'script') {
|
|
type = node.attr('type');
|
|
if (type) {
|
|
node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
|
|
}
|
|
if (settings.element_format === 'xhtml' && value.length > 0) {
|
|
node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
|
|
}
|
|
} else {
|
|
if (settings.element_format === 'xhtml' && value.length > 0) {
|
|
node.firstChild.value = '<!--\n' + trim(value) + '\n-->';
|
|
}
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addNodeFilter('#comment', function (nodes) {
|
|
var i = nodes.length, node;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
if (node.value.indexOf('[CDATA[') === 0) {
|
|
node.name = '#cdata';
|
|
node.type = 4;
|
|
node.value = node.value.replace(/^\[CDATA\[|\]\]$/g, '');
|
|
} else if (node.value.indexOf('mce:protected ') === 0) {
|
|
node.name = '#text';
|
|
node.type = 3;
|
|
node.raw = true;
|
|
node.value = unescape(node.value).substr(14);
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addNodeFilter('xml:namespace,input', function (nodes, name) {
|
|
var i = nodes.length, node;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
if (node.type === 7) {
|
|
node.remove();
|
|
} else if (node.type === 1) {
|
|
if (name === 'input' && !node.attr('type')) {
|
|
node.attr('type', 'text');
|
|
}
|
|
}
|
|
}
|
|
});
|
|
htmlParser.addAttributeFilter('data-mce-type', function (nodes) {
|
|
each(nodes, function (node) {
|
|
if (node.attr('data-mce-type') === 'format-caret') {
|
|
if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
|
|
node.remove();
|
|
} else {
|
|
node.unwrap();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style,' + 'data-mce-selected,data-mce-expando,' + 'data-mce-type,data-mce-resize', function (nodes, name) {
|
|
var i = nodes.length;
|
|
while (i--) {
|
|
nodes[i].attr(name, null);
|
|
}
|
|
});
|
|
};
|
|
var trimTrailingBr = function (rootNode) {
|
|
var brNode1, brNode2;
|
|
var isBr = function (node) {
|
|
return node && node.name === 'br';
|
|
};
|
|
brNode1 = rootNode.lastChild;
|
|
if (isBr(brNode1)) {
|
|
brNode2 = brNode1.prev;
|
|
if (isBr(brNode2)) {
|
|
brNode1.remove();
|
|
brNode2.remove();
|
|
}
|
|
}
|
|
};
|
|
var DomSerializerFilters = {
|
|
register: register$1,
|
|
trimTrailingBr: trimTrailingBr
|
|
};
|
|
|
|
var preProcess = function (editor, node, args) {
|
|
var impl, doc, oldDoc;
|
|
var dom = editor.dom;
|
|
node = node.cloneNode(true);
|
|
impl = domGlobals.document.implementation;
|
|
if (impl.createHTMLDocument) {
|
|
doc = impl.createHTMLDocument('');
|
|
Tools.each(node.nodeName === 'BODY' ? node.childNodes : [node], function (node) {
|
|
doc.body.appendChild(doc.importNode(node, true));
|
|
});
|
|
if (node.nodeName !== 'BODY') {
|
|
node = doc.body.firstChild;
|
|
} else {
|
|
node = doc.body;
|
|
}
|
|
oldDoc = dom.doc;
|
|
dom.doc = doc;
|
|
}
|
|
Events.firePreProcess(editor, merge(args, { node: node }));
|
|
if (oldDoc) {
|
|
dom.doc = oldDoc;
|
|
}
|
|
return node;
|
|
};
|
|
var shouldFireEvent = function (editor, args) {
|
|
return editor && editor.hasEventListeners('PreProcess') && !args.no_events;
|
|
};
|
|
var process = function (editor, node, args) {
|
|
return shouldFireEvent(editor, args) ? preProcess(editor, node, args) : node;
|
|
};
|
|
var DomSerializerPreProcess = { process: process };
|
|
|
|
var removeAttrs = function (node, names) {
|
|
each(names, function (name) {
|
|
node.attr(name, null);
|
|
});
|
|
};
|
|
var addFontToSpansFilter = function (domParser, styles, fontSizes) {
|
|
domParser.addNodeFilter('font', function (nodes) {
|
|
each(nodes, function (node) {
|
|
var props = styles.parse(node.attr('style'));
|
|
var color = node.attr('color');
|
|
var face = node.attr('face');
|
|
var size = node.attr('size');
|
|
if (color) {
|
|
props.color = color;
|
|
}
|
|
if (face) {
|
|
props['font-family'] = face;
|
|
}
|
|
if (size) {
|
|
props['font-size'] = fontSizes[parseInt(node.attr('size'), 10) - 1];
|
|
}
|
|
node.name = 'span';
|
|
node.attr('style', styles.serialize(props));
|
|
removeAttrs(node, [
|
|
'color',
|
|
'face',
|
|
'size'
|
|
]);
|
|
});
|
|
});
|
|
};
|
|
var addStrikeToSpanFilter = function (domParser, styles) {
|
|
domParser.addNodeFilter('strike', function (nodes) {
|
|
each(nodes, function (node) {
|
|
var props = styles.parse(node.attr('style'));
|
|
props['text-decoration'] = 'line-through';
|
|
node.name = 'span';
|
|
node.attr('style', styles.serialize(props));
|
|
});
|
|
});
|
|
};
|
|
var addFilters = function (domParser, settings) {
|
|
var styles = Styles();
|
|
if (settings.convert_fonts_to_spans) {
|
|
addFontToSpansFilter(domParser, styles, Tools.explode(settings.font_size_legacy_values));
|
|
}
|
|
addStrikeToSpanFilter(domParser, styles);
|
|
};
|
|
var register$2 = function (domParser, settings) {
|
|
if (settings.inline_styles) {
|
|
addFilters(domParser, settings);
|
|
}
|
|
};
|
|
var LegacyFilter = { register: register$2 };
|
|
|
|
var paddEmptyNode = function (settings, args, blockElements, node) {
|
|
var brPreferred = settings.padd_empty_with_br || args.insert;
|
|
if (brPreferred && blockElements[node.name]) {
|
|
node.empty().append(new Node$1('br', 1)).shortEnded = true;
|
|
} else {
|
|
node.empty().append(new Node$1('#text', 3)).value = '\xA0';
|
|
}
|
|
};
|
|
var isPaddedWithNbsp = function (node) {
|
|
return hasOnlyChild(node, '#text') && node.firstChild.value === '\xA0';
|
|
};
|
|
var hasOnlyChild = function (node, name) {
|
|
return node && node.firstChild && node.firstChild === node.lastChild && node.firstChild.name === name;
|
|
};
|
|
var isPadded = function (schema, node) {
|
|
var rule = schema.getElementRule(node.name);
|
|
return rule && rule.paddEmpty;
|
|
};
|
|
var isEmpty$2 = function (schema, nonEmptyElements, whitespaceElements, node) {
|
|
return node.isEmpty(nonEmptyElements, whitespaceElements, function (node) {
|
|
return isPadded(schema, node);
|
|
});
|
|
};
|
|
var isLineBreakNode = function (node, blockElements) {
|
|
return node && (blockElements[node.name] || node.name === 'br');
|
|
};
|
|
|
|
var register$3 = function (parser, settings) {
|
|
var schema = parser.schema;
|
|
if (settings.remove_trailing_brs) {
|
|
parser.addNodeFilter('br', function (nodes, _, args) {
|
|
var i;
|
|
var l = nodes.length;
|
|
var node;
|
|
var blockElements = Tools.extend({}, schema.getBlockElements());
|
|
var nonEmptyElements = schema.getNonEmptyElements();
|
|
var parent, lastParent, prev, prevName;
|
|
var whiteSpaceElements = schema.getNonEmptyElements();
|
|
var elementRule, textNode;
|
|
blockElements.body = 1;
|
|
for (i = 0; i < l; i++) {
|
|
node = nodes[i];
|
|
parent = node.parent;
|
|
if (blockElements[node.parent.name] && node === parent.lastChild) {
|
|
prev = node.prev;
|
|
while (prev) {
|
|
prevName = prev.name;
|
|
if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
|
|
if (prevName !== 'br') {
|
|
break;
|
|
}
|
|
if (prevName === 'br') {
|
|
node = null;
|
|
break;
|
|
}
|
|
}
|
|
prev = prev.prev;
|
|
}
|
|
if (node) {
|
|
node.remove();
|
|
if (isEmpty$2(schema, nonEmptyElements, whiteSpaceElements, parent)) {
|
|
elementRule = schema.getElementRule(parent.name);
|
|
if (elementRule) {
|
|
if (elementRule.removeEmpty) {
|
|
parent.remove();
|
|
} else if (elementRule.paddEmpty) {
|
|
paddEmptyNode(settings, args, blockElements, parent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
lastParent = node;
|
|
while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
|
|
lastParent = parent;
|
|
if (blockElements[parent.name]) {
|
|
break;
|
|
}
|
|
parent = parent.parent;
|
|
}
|
|
if (lastParent === parent && settings.padd_empty_with_br !== true) {
|
|
textNode = new Node$1('#text', 3);
|
|
textNode.value = '\xA0';
|
|
node.replace(textNode);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
parser.addAttributeFilter('href', function (nodes) {
|
|
var i = nodes.length, node;
|
|
var appendRel = function (rel) {
|
|
var parts = rel.split(' ').filter(function (p) {
|
|
return p.length > 0;
|
|
});
|
|
return parts.concat(['noopener']).sort().join(' ');
|
|
};
|
|
var addNoOpener = function (rel) {
|
|
var newRel = rel ? Tools.trim(rel) : '';
|
|
if (!/\b(noopener)\b/g.test(newRel)) {
|
|
return appendRel(newRel);
|
|
} else {
|
|
return newRel;
|
|
}
|
|
};
|
|
if (!settings.allow_unsafe_link_target) {
|
|
while (i--) {
|
|
node = nodes[i];
|
|
if (node.name === 'a' && node.attr('target') === '_blank') {
|
|
node.attr('rel', addNoOpener(node.attr('rel')));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (!settings.allow_html_in_named_anchor) {
|
|
parser.addAttributeFilter('id,name', function (nodes) {
|
|
var i = nodes.length, sibling, prevSibling, parent, node;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
if (node.name === 'a' && node.firstChild && !node.attr('href')) {
|
|
parent = node.parent;
|
|
sibling = node.lastChild;
|
|
do {
|
|
prevSibling = sibling.prev;
|
|
parent.insert(sibling, node);
|
|
sibling = prevSibling;
|
|
} while (sibling);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (settings.fix_list_elements) {
|
|
parser.addNodeFilter('ul,ol', function (nodes) {
|
|
var i = nodes.length, node, parentNode;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
parentNode = node.parent;
|
|
if (parentNode.name === 'ul' || parentNode.name === 'ol') {
|
|
if (node.prev && node.prev.name === 'li') {
|
|
node.prev.append(node);
|
|
} else {
|
|
var li = new Node$1('li', 1);
|
|
li.attr('style', 'list-style-type: none');
|
|
node.wrap(li);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (settings.validate && schema.getValidClasses()) {
|
|
parser.addAttributeFilter('class', function (nodes) {
|
|
var i = nodes.length, node, classList, ci, className, classValue;
|
|
var validClasses = schema.getValidClasses();
|
|
var validClassesMap, valid;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
classList = node.attr('class').split(' ');
|
|
classValue = '';
|
|
for (ci = 0; ci < classList.length; ci++) {
|
|
className = classList[ci];
|
|
valid = false;
|
|
validClassesMap = validClasses['*'];
|
|
if (validClassesMap && validClassesMap[className]) {
|
|
valid = true;
|
|
}
|
|
validClassesMap = validClasses[node.name];
|
|
if (!valid && validClassesMap && validClassesMap[className]) {
|
|
valid = true;
|
|
}
|
|
if (valid) {
|
|
if (classValue) {
|
|
classValue += ' ';
|
|
}
|
|
classValue += className;
|
|
}
|
|
}
|
|
if (!classValue.length) {
|
|
classValue = null;
|
|
}
|
|
node.attr('class', classValue);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
var makeMap$4 = Tools.makeMap, each$f = Tools.each, explode$2 = Tools.explode, extend$2 = Tools.extend;
|
|
var DomParser = function (settings, schema) {
|
|
if (schema === void 0) {
|
|
schema = Schema();
|
|
}
|
|
var nodeFilters = {};
|
|
var attributeFilters = [];
|
|
var matchedNodes = {};
|
|
var matchedAttributes = {};
|
|
settings = settings || {};
|
|
settings.validate = 'validate' in settings ? settings.validate : true;
|
|
settings.root_name = settings.root_name || 'body';
|
|
var fixInvalidChildren = function (nodes) {
|
|
var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i;
|
|
var nonEmptyElements, whitespaceElements, nonSplitableElements, textBlockElements, specialElements, sibling, nextNode;
|
|
nonSplitableElements = makeMap$4('tr,td,th,tbody,thead,tfoot,table');
|
|
nonEmptyElements = schema.getNonEmptyElements();
|
|
whitespaceElements = schema.getWhiteSpaceElements();
|
|
textBlockElements = schema.getTextBlockElements();
|
|
specialElements = schema.getSpecialElements();
|
|
for (ni = 0; ni < nodes.length; ni++) {
|
|
node = nodes[ni];
|
|
if (!node.parent || node.fixed) {
|
|
continue;
|
|
}
|
|
if (textBlockElements[node.name] && node.parent.name === 'li') {
|
|
sibling = node.next;
|
|
while (sibling) {
|
|
if (textBlockElements[sibling.name]) {
|
|
sibling.name = 'li';
|
|
sibling.fixed = true;
|
|
node.parent.insert(sibling, node.parent);
|
|
} else {
|
|
break;
|
|
}
|
|
sibling = sibling.next;
|
|
}
|
|
node.unwrap(node);
|
|
continue;
|
|
}
|
|
parents = [node];
|
|
for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && !nonSplitableElements[parent.name]; parent = parent.parent) {
|
|
parents.push(parent);
|
|
}
|
|
if (parent && parents.length > 1) {
|
|
parents.reverse();
|
|
newParent = currentNode = filterNode(parents[0].clone());
|
|
for (i = 0; i < parents.length - 1; i++) {
|
|
if (schema.isValidChild(currentNode.name, parents[i].name)) {
|
|
tempNode = filterNode(parents[i].clone());
|
|
currentNode.append(tempNode);
|
|
} else {
|
|
tempNode = currentNode;
|
|
}
|
|
for (childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
|
|
nextNode = childNode.next;
|
|
tempNode.append(childNode);
|
|
childNode = nextNode;
|
|
}
|
|
currentNode = tempNode;
|
|
}
|
|
if (!isEmpty$2(schema, nonEmptyElements, whitespaceElements, newParent)) {
|
|
parent.insert(newParent, parents[0], true);
|
|
parent.insert(node, newParent);
|
|
} else {
|
|
parent.insert(node, parents[0], true);
|
|
}
|
|
parent = parents[0];
|
|
if (isEmpty$2(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
|
|
parent.empty().remove();
|
|
}
|
|
} else if (node.parent) {
|
|
if (node.name === 'li') {
|
|
sibling = node.prev;
|
|
if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
|
|
sibling.append(node);
|
|
continue;
|
|
}
|
|
sibling = node.next;
|
|
if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
|
|
sibling.insert(node, sibling.firstChild, true);
|
|
continue;
|
|
}
|
|
node.wrap(filterNode(new Node$1('ul', 1)));
|
|
continue;
|
|
}
|
|
if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
|
|
node.wrap(filterNode(new Node$1('div', 1)));
|
|
} else {
|
|
if (specialElements[node.name]) {
|
|
node.empty().remove();
|
|
} else {
|
|
node.unwrap();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var filterNode = function (node) {
|
|
var i, name, list;
|
|
name = node.name;
|
|
if (name in nodeFilters) {
|
|
list = matchedNodes[name];
|
|
if (list) {
|
|
list.push(node);
|
|
} else {
|
|
matchedNodes[name] = [node];
|
|
}
|
|
}
|
|
i = attributeFilters.length;
|
|
while (i--) {
|
|
name = attributeFilters[i].name;
|
|
if (name in node.attributes.map) {
|
|
list = matchedAttributes[name];
|
|
if (list) {
|
|
list.push(node);
|
|
} else {
|
|
matchedAttributes[name] = [node];
|
|
}
|
|
}
|
|
}
|
|
return node;
|
|
};
|
|
var addNodeFilter = function (name, callback) {
|
|
each$f(explode$2(name), function (name) {
|
|
var list = nodeFilters[name];
|
|
if (!list) {
|
|
nodeFilters[name] = list = [];
|
|
}
|
|
list.push(callback);
|
|
});
|
|
};
|
|
var getNodeFilters = function () {
|
|
var out = [];
|
|
for (var name in nodeFilters) {
|
|
if (nodeFilters.hasOwnProperty(name)) {
|
|
out.push({
|
|
name: name,
|
|
callbacks: nodeFilters[name]
|
|
});
|
|
}
|
|
}
|
|
return out;
|
|
};
|
|
var addAttributeFilter = function (name, callback) {
|
|
each$f(explode$2(name), function (name) {
|
|
var i;
|
|
for (i = 0; i < attributeFilters.length; i++) {
|
|
if (attributeFilters[i].name === name) {
|
|
attributeFilters[i].callbacks.push(callback);
|
|
return;
|
|
}
|
|
}
|
|
attributeFilters.push({
|
|
name: name,
|
|
callbacks: [callback]
|
|
});
|
|
});
|
|
};
|
|
var getAttributeFilters = function () {
|
|
return [].concat(attributeFilters);
|
|
};
|
|
var parse = function (html, args) {
|
|
var parser, nodes, i, l, fi, fl, list, name;
|
|
var blockElements;
|
|
var invalidChildren = [];
|
|
var isInWhiteSpacePreservedElement;
|
|
var node;
|
|
var getRootBlockName = function (name) {
|
|
if (name === false) {
|
|
return '';
|
|
} else if (name === true) {
|
|
return 'p';
|
|
} else {
|
|
return name;
|
|
}
|
|
};
|
|
args = args || {};
|
|
matchedNodes = {};
|
|
matchedAttributes = {};
|
|
blockElements = extend$2(makeMap$4('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
|
|
var nonEmptyElements = schema.getNonEmptyElements();
|
|
var children = schema.children;
|
|
var validate = settings.validate;
|
|
var forcedRootBlockName = 'forced_root_block' in args ? args.forced_root_block : settings.forced_root_block;
|
|
var rootBlockName = getRootBlockName(forcedRootBlockName);
|
|
var whiteSpaceElements = schema.getWhiteSpaceElements();
|
|
var startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
|
var endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
|
var allWhiteSpaceRegExp = /[ \t\r\n]+/g;
|
|
var isAllWhiteSpaceRegExp = /^[ \t\r\n]+$/;
|
|
isInWhiteSpacePreservedElement = whiteSpaceElements.hasOwnProperty(args.context) || whiteSpaceElements.hasOwnProperty(settings.root_name);
|
|
var addRootBlocks = function () {
|
|
var node = rootNode.firstChild, next, rootBlockNode;
|
|
var trim = function (rootBlockNode) {
|
|
if (rootBlockNode) {
|
|
node = rootBlockNode.firstChild;
|
|
if (node && node.type === 3) {
|
|
node.value = node.value.replace(startWhiteSpaceRegExp, '');
|
|
}
|
|
node = rootBlockNode.lastChild;
|
|
if (node && node.type === 3) {
|
|
node.value = node.value.replace(endWhiteSpaceRegExp, '');
|
|
}
|
|
}
|
|
};
|
|
if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
|
|
return;
|
|
}
|
|
while (node) {
|
|
next = node.next;
|
|
if (node.type === 3 || node.type === 1 && node.name !== 'p' && !blockElements[node.name] && !node.attr('data-mce-type')) {
|
|
if (!rootBlockNode) {
|
|
rootBlockNode = createNode(rootBlockName, 1);
|
|
rootBlockNode.attr(settings.forced_root_block_attrs);
|
|
rootNode.insert(rootBlockNode, node);
|
|
rootBlockNode.append(node);
|
|
} else {
|
|
rootBlockNode.append(node);
|
|
}
|
|
} else {
|
|
trim(rootBlockNode);
|
|
rootBlockNode = null;
|
|
}
|
|
node = next;
|
|
}
|
|
trim(rootBlockNode);
|
|
};
|
|
var createNode = function (name, type) {
|
|
var node = new Node$1(name, type);
|
|
var list;
|
|
if (name in nodeFilters) {
|
|
list = matchedNodes[name];
|
|
if (list) {
|
|
list.push(node);
|
|
} else {
|
|
matchedNodes[name] = [node];
|
|
}
|
|
}
|
|
return node;
|
|
};
|
|
var removeWhitespaceBefore = function (node) {
|
|
var textNode, textNodeNext, textVal, sibling;
|
|
var blockElements = schema.getBlockElements();
|
|
for (textNode = node.prev; textNode && textNode.type === 3;) {
|
|
textVal = textNode.value.replace(endWhiteSpaceRegExp, '');
|
|
if (textVal.length > 0) {
|
|
textNode.value = textVal;
|
|
return;
|
|
}
|
|
textNodeNext = textNode.next;
|
|
if (textNodeNext) {
|
|
if (textNodeNext.type === 3 && textNodeNext.value.length) {
|
|
textNode = textNode.prev;
|
|
continue;
|
|
}
|
|
if (!blockElements[textNodeNext.name] && textNodeNext.name !== 'script' && textNodeNext.name !== 'style') {
|
|
textNode = textNode.prev;
|
|
continue;
|
|
}
|
|
}
|
|
sibling = textNode.prev;
|
|
textNode.remove();
|
|
textNode = sibling;
|
|
}
|
|
};
|
|
var cloneAndExcludeBlocks = function (input) {
|
|
var name;
|
|
var output = {};
|
|
for (name in input) {
|
|
if (name !== 'li' && name !== 'p') {
|
|
output[name] = input[name];
|
|
}
|
|
}
|
|
return output;
|
|
};
|
|
parser = SaxParser$1({
|
|
validate: validate,
|
|
allow_script_urls: settings.allow_script_urls,
|
|
allow_conditional_comments: settings.allow_conditional_comments,
|
|
self_closing_elements: cloneAndExcludeBlocks(schema.getSelfClosingElements()),
|
|
cdata: function (text) {
|
|
node.append(createNode('#cdata', 4)).value = text;
|
|
},
|
|
text: function (text, raw) {
|
|
var textNode;
|
|
if (!isInWhiteSpacePreservedElement) {
|
|
text = text.replace(allWhiteSpaceRegExp, ' ');
|
|
if (isLineBreakNode(node.lastChild, blockElements)) {
|
|
text = text.replace(startWhiteSpaceRegExp, '');
|
|
}
|
|
}
|
|
if (text.length !== 0) {
|
|
textNode = createNode('#text', 3);
|
|
textNode.raw = !!raw;
|
|
node.append(textNode).value = text;
|
|
}
|
|
},
|
|
comment: function (text) {
|
|
node.append(createNode('#comment', 8)).value = text;
|
|
},
|
|
pi: function (name, text) {
|
|
node.append(createNode(name, 7)).value = text;
|
|
removeWhitespaceBefore(node);
|
|
},
|
|
doctype: function (text) {
|
|
var newNode;
|
|
newNode = node.append(createNode('#doctype', 10));
|
|
newNode.value = text;
|
|
removeWhitespaceBefore(node);
|
|
},
|
|
start: function (name, attrs, empty) {
|
|
var newNode, attrFiltersLen, elementRule, attrName, parent;
|
|
elementRule = validate ? schema.getElementRule(name) : {};
|
|
if (elementRule) {
|
|
newNode = createNode(elementRule.outputName || name, 1);
|
|
newNode.attributes = attrs;
|
|
newNode.shortEnded = empty;
|
|
node.append(newNode);
|
|
parent = children[node.name];
|
|
if (parent && children[newNode.name] && !parent[newNode.name]) {
|
|
invalidChildren.push(newNode);
|
|
}
|
|
attrFiltersLen = attributeFilters.length;
|
|
while (attrFiltersLen--) {
|
|
attrName = attributeFilters[attrFiltersLen].name;
|
|
if (attrName in attrs.map) {
|
|
list = matchedAttributes[attrName];
|
|
if (list) {
|
|
list.push(newNode);
|
|
} else {
|
|
matchedAttributes[attrName] = [newNode];
|
|
}
|
|
}
|
|
}
|
|
if (blockElements[name]) {
|
|
removeWhitespaceBefore(newNode);
|
|
}
|
|
if (!empty) {
|
|
node = newNode;
|
|
}
|
|
if (!isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
|
|
isInWhiteSpacePreservedElement = true;
|
|
}
|
|
}
|
|
},
|
|
end: function (name) {
|
|
var textNode, elementRule, text, sibling, tempNode;
|
|
elementRule = validate ? schema.getElementRule(name) : {};
|
|
if (elementRule) {
|
|
if (blockElements[name]) {
|
|
if (!isInWhiteSpacePreservedElement) {
|
|
textNode = node.firstChild;
|
|
if (textNode && textNode.type === 3) {
|
|
text = textNode.value.replace(startWhiteSpaceRegExp, '');
|
|
if (text.length > 0) {
|
|
textNode.value = text;
|
|
textNode = textNode.next;
|
|
} else {
|
|
sibling = textNode.next;
|
|
textNode.remove();
|
|
textNode = sibling;
|
|
while (textNode && textNode.type === 3) {
|
|
text = textNode.value;
|
|
sibling = textNode.next;
|
|
if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
|
|
textNode.remove();
|
|
textNode = sibling;
|
|
}
|
|
textNode = sibling;
|
|
}
|
|
}
|
|
}
|
|
textNode = node.lastChild;
|
|
if (textNode && textNode.type === 3) {
|
|
text = textNode.value.replace(endWhiteSpaceRegExp, '');
|
|
if (text.length > 0) {
|
|
textNode.value = text;
|
|
textNode = textNode.prev;
|
|
} else {
|
|
sibling = textNode.prev;
|
|
textNode.remove();
|
|
textNode = sibling;
|
|
while (textNode && textNode.type === 3) {
|
|
text = textNode.value;
|
|
sibling = textNode.prev;
|
|
if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
|
|
textNode.remove();
|
|
textNode = sibling;
|
|
}
|
|
textNode = sibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
|
|
isInWhiteSpacePreservedElement = false;
|
|
}
|
|
if (elementRule.removeEmpty && isEmpty$2(schema, nonEmptyElements, whiteSpaceElements, node)) {
|
|
if (!node.attr('name') && !node.attr('id')) {
|
|
tempNode = node.parent;
|
|
if (blockElements[node.name]) {
|
|
node.empty().remove();
|
|
} else {
|
|
node.unwrap();
|
|
}
|
|
node = tempNode;
|
|
return;
|
|
}
|
|
}
|
|
if (elementRule.paddEmpty && (isPaddedWithNbsp(node) || isEmpty$2(schema, nonEmptyElements, whiteSpaceElements, node))) {
|
|
paddEmptyNode(settings, args, blockElements, node);
|
|
}
|
|
node = node.parent;
|
|
}
|
|
}
|
|
}, schema);
|
|
var rootNode = node = new Node$1(args.context || settings.root_name, 11);
|
|
parser.parse(html);
|
|
if (validate && invalidChildren.length) {
|
|
if (!args.context) {
|
|
fixInvalidChildren(invalidChildren);
|
|
} else {
|
|
args.invalid = true;
|
|
}
|
|
}
|
|
if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
|
|
addRootBlocks();
|
|
}
|
|
if (!args.invalid) {
|
|
for (name in matchedNodes) {
|
|
if (!matchedNodes.hasOwnProperty(name)) {
|
|
continue;
|
|
}
|
|
list = nodeFilters[name];
|
|
nodes = matchedNodes[name];
|
|
fi = nodes.length;
|
|
while (fi--) {
|
|
if (!nodes[fi].parent) {
|
|
nodes.splice(fi, 1);
|
|
}
|
|
}
|
|
for (i = 0, l = list.length; i < l; i++) {
|
|
list[i](nodes, name, args);
|
|
}
|
|
}
|
|
for (i = 0, l = attributeFilters.length; i < l; i++) {
|
|
list = attributeFilters[i];
|
|
if (list.name in matchedAttributes) {
|
|
nodes = matchedAttributes[list.name];
|
|
fi = nodes.length;
|
|
while (fi--) {
|
|
if (!nodes[fi].parent) {
|
|
nodes.splice(fi, 1);
|
|
}
|
|
}
|
|
for (fi = 0, fl = list.callbacks.length; fi < fl; fi++) {
|
|
list.callbacks[fi](nodes, list.name, args);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rootNode;
|
|
};
|
|
var exports = {
|
|
schema: schema,
|
|
addAttributeFilter: addAttributeFilter,
|
|
getAttributeFilters: getAttributeFilters,
|
|
addNodeFilter: addNodeFilter,
|
|
getNodeFilters: getNodeFilters,
|
|
filterNode: filterNode,
|
|
parse: parse
|
|
};
|
|
register$3(exports, settings);
|
|
LegacyFilter.register(exports, settings);
|
|
return exports;
|
|
};
|
|
|
|
var addTempAttr = function (htmlParser, tempAttrs, name) {
|
|
if (Tools.inArray(tempAttrs, name) === -1) {
|
|
htmlParser.addAttributeFilter(name, function (nodes, name) {
|
|
var i = nodes.length;
|
|
while (i--) {
|
|
nodes[i].attr(name, null);
|
|
}
|
|
});
|
|
tempAttrs.push(name);
|
|
}
|
|
};
|
|
var postProcess$1 = function (editor, args, content) {
|
|
if (!args.no_events && editor) {
|
|
var outArgs = Events.firePostProcess(editor, merge(args, { content: content }));
|
|
return outArgs.content;
|
|
} else {
|
|
return content;
|
|
}
|
|
};
|
|
var getHtmlFromNode = function (dom, node, args) {
|
|
var html = Zwsp.trim(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
|
|
return args.selection || isWsPreserveElement(Element.fromDom(node)) ? html : Tools.trim(html);
|
|
};
|
|
var parseHtml = function (htmlParser, html, args) {
|
|
var parserArgs = args.selection ? merge({ forced_root_block: false }, args) : args;
|
|
var rootNode = htmlParser.parse(html, parserArgs);
|
|
DomSerializerFilters.trimTrailingBr(rootNode);
|
|
return rootNode;
|
|
};
|
|
var serializeNode = function (settings, schema, node) {
|
|
var htmlSerializer = Serializer(settings, schema);
|
|
return htmlSerializer.serialize(node);
|
|
};
|
|
var toHtml = function (editor, settings, schema, rootNode, args) {
|
|
var content = serializeNode(settings, schema, rootNode);
|
|
return postProcess$1(editor, args, content);
|
|
};
|
|
var DomSerializer = function (settings, editor) {
|
|
var dom, schema, htmlParser;
|
|
var tempAttrs = ['data-mce-selected'];
|
|
dom = editor && editor.dom ? editor.dom : DOMUtils$1.DOM;
|
|
schema = editor && editor.schema ? editor.schema : Schema(settings);
|
|
settings.entity_encoding = settings.entity_encoding || 'named';
|
|
settings.remove_trailing_brs = 'remove_trailing_brs' in settings ? settings.remove_trailing_brs : true;
|
|
htmlParser = DomParser(settings, schema);
|
|
DomSerializerFilters.register(htmlParser, settings, dom);
|
|
var serialize = function (node, parserArgs) {
|
|
var args = merge({ format: 'html' }, parserArgs ? parserArgs : {});
|
|
var targetNode = DomSerializerPreProcess.process(editor, node, args);
|
|
var html = getHtmlFromNode(dom, targetNode, args);
|
|
var rootNode = parseHtml(htmlParser, html, args);
|
|
return args.format === 'tree' ? rootNode : toHtml(editor, settings, schema, rootNode, args);
|
|
};
|
|
return {
|
|
schema: schema,
|
|
addNodeFilter: htmlParser.addNodeFilter,
|
|
addAttributeFilter: htmlParser.addAttributeFilter,
|
|
serialize: serialize,
|
|
addRules: function (rules) {
|
|
schema.addValidElements(rules);
|
|
},
|
|
setRules: function (rules) {
|
|
schema.setValidElements(rules);
|
|
},
|
|
addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
|
|
getTempAttrs: function () {
|
|
return tempAttrs;
|
|
}
|
|
};
|
|
};
|
|
|
|
var Serializer$1 = function (settings, editor) {
|
|
var domSerializer = DomSerializer(settings, editor);
|
|
return {
|
|
schema: domSerializer.schema,
|
|
addNodeFilter: domSerializer.addNodeFilter,
|
|
addAttributeFilter: domSerializer.addAttributeFilter,
|
|
serialize: domSerializer.serialize,
|
|
addRules: domSerializer.addRules,
|
|
setRules: domSerializer.setRules,
|
|
addTempAttr: domSerializer.addTempAttr,
|
|
getTempAttrs: domSerializer.getTempAttrs
|
|
};
|
|
};
|
|
|
|
function BookmarkManager(selection) {
|
|
return {
|
|
getBookmark: curry(Bookmarks.getBookmark, selection),
|
|
moveToBookmark: curry(Bookmarks.moveToBookmark, selection)
|
|
};
|
|
}
|
|
(function (BookmarkManager) {
|
|
BookmarkManager.isBookmarkNode = Bookmarks.isBookmarkNode;
|
|
}(BookmarkManager || (BookmarkManager = {})));
|
|
var BookmarkManager$1 = BookmarkManager;
|
|
|
|
var isContentEditableFalse$a = NodeType.isContentEditableFalse;
|
|
var isContentEditableTrue$5 = NodeType.isContentEditableTrue;
|
|
var getContentEditableRoot$1 = function (root, node) {
|
|
while (node && node !== root) {
|
|
if (isContentEditableTrue$5(node) || isContentEditableFalse$a(node)) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var ControlSelection = function (selection, editor) {
|
|
var dom = editor.dom, each = Tools.each;
|
|
var selectedElm, selectedElmGhost, resizeHelper, resizeHandles, selectedHandle;
|
|
var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
|
|
var width, height;
|
|
var editableDoc = editor.getDoc(), rootDocument = domGlobals.document;
|
|
var abs = Math.abs, round = Math.round, rootElement = editor.getBody();
|
|
var startScrollWidth, startScrollHeight;
|
|
resizeHandles = {
|
|
nw: [
|
|
0,
|
|
0,
|
|
-1,
|
|
-1
|
|
],
|
|
ne: [
|
|
1,
|
|
0,
|
|
1,
|
|
-1
|
|
],
|
|
se: [
|
|
1,
|
|
1,
|
|
1,
|
|
1
|
|
],
|
|
sw: [
|
|
0,
|
|
1,
|
|
-1,
|
|
1
|
|
]
|
|
};
|
|
var isImage = function (elm) {
|
|
return elm && (elm.nodeName === 'IMG' || editor.dom.is(elm, 'figure.image'));
|
|
};
|
|
var isEventOnImageOutsideRange = function (evt, range) {
|
|
if (evt.type === 'longpress' || evt.type.indexOf('touch') === 0) {
|
|
var touch = evt.touches[0];
|
|
return isImage(evt.target) && !RangePoint.isXYWithinRange(touch.clientX, touch.clientY, range);
|
|
} else {
|
|
return isImage(evt.target) && !RangePoint.isXYWithinRange(evt.clientX, evt.clientY, range);
|
|
}
|
|
};
|
|
var contextMenuSelectImage = function (evt) {
|
|
var target = evt.target;
|
|
if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
|
|
editor.selection.select(target);
|
|
}
|
|
};
|
|
var getResizeTarget = function (elm) {
|
|
return editor.dom.is(elm, 'figure.image') ? elm.querySelector('img') : elm;
|
|
};
|
|
var isResizable = function (elm) {
|
|
var selector = editor.settings.object_resizing;
|
|
if (selector === false || Env.iOS) {
|
|
return false;
|
|
}
|
|
if (typeof selector !== 'string') {
|
|
selector = 'table,img,figure.image,div';
|
|
}
|
|
if (elm.getAttribute('data-mce-resize') === 'false') {
|
|
return false;
|
|
}
|
|
if (elm === editor.getBody()) {
|
|
return false;
|
|
}
|
|
return is(Element.fromDom(elm), selector);
|
|
};
|
|
var resizeGhostElement = function (e) {
|
|
var deltaX, deltaY, proportional;
|
|
var resizeHelperX, resizeHelperY;
|
|
deltaX = e.screenX - startX;
|
|
deltaY = e.screenY - startY;
|
|
width = deltaX * selectedHandle[2] + startW;
|
|
height = deltaY * selectedHandle[3] + startH;
|
|
width = width < 5 ? 5 : width;
|
|
height = height < 5 ? 5 : height;
|
|
if (isImage(selectedElm) && editor.settings.resize_img_proportional !== false) {
|
|
proportional = !VK.modifierPressed(e);
|
|
} else {
|
|
proportional = VK.modifierPressed(e) || isImage(selectedElm) && selectedHandle[2] * selectedHandle[3] !== 0;
|
|
}
|
|
if (proportional) {
|
|
if (abs(deltaX) > abs(deltaY)) {
|
|
height = round(width * ratio);
|
|
width = round(height / ratio);
|
|
} else {
|
|
width = round(height / ratio);
|
|
height = round(width * ratio);
|
|
}
|
|
}
|
|
dom.setStyles(getResizeTarget(selectedElmGhost), {
|
|
width: width,
|
|
height: height
|
|
});
|
|
resizeHelperX = selectedHandle.startPos.x + deltaX;
|
|
resizeHelperY = selectedHandle.startPos.y + deltaY;
|
|
resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
|
|
resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
|
|
dom.setStyles(resizeHelper, {
|
|
left: resizeHelperX,
|
|
top: resizeHelperY,
|
|
display: 'block'
|
|
});
|
|
resizeHelper.innerHTML = width + ' × ' + height;
|
|
if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
|
|
dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
|
|
}
|
|
if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
|
|
dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
|
|
}
|
|
deltaX = rootElement.scrollWidth - startScrollWidth;
|
|
deltaY = rootElement.scrollHeight - startScrollHeight;
|
|
if (deltaX + deltaY !== 0) {
|
|
dom.setStyles(resizeHelper, {
|
|
left: resizeHelperX - deltaX,
|
|
top: resizeHelperY - deltaY
|
|
});
|
|
}
|
|
if (!resizeStarted) {
|
|
Events.fireObjectResizeStart(editor, selectedElm, startW, startH);
|
|
resizeStarted = true;
|
|
}
|
|
};
|
|
var endGhostResize = function () {
|
|
resizeStarted = false;
|
|
var setSizeProp = function (name, value) {
|
|
if (value) {
|
|
if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) {
|
|
dom.setStyle(getResizeTarget(selectedElm), name, value);
|
|
} else {
|
|
dom.setAttrib(getResizeTarget(selectedElm), name, value);
|
|
}
|
|
}
|
|
};
|
|
setSizeProp('width', width);
|
|
setSizeProp('height', height);
|
|
dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
|
|
dom.unbind(editableDoc, 'mouseup', endGhostResize);
|
|
if (rootDocument !== editableDoc) {
|
|
dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
|
|
dom.unbind(rootDocument, 'mouseup', endGhostResize);
|
|
}
|
|
dom.remove(selectedElmGhost);
|
|
dom.remove(resizeHelper);
|
|
showResizeRect(selectedElm);
|
|
Events.fireObjectResized(editor, selectedElm, width, height);
|
|
dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
|
|
editor.nodeChanged();
|
|
};
|
|
var showResizeRect = function (targetElm) {
|
|
var position, targetWidth, targetHeight, e, rect;
|
|
hideResizeRect();
|
|
unbindResizeHandleEvents();
|
|
position = dom.getPos(targetElm, rootElement);
|
|
selectedElmX = position.x;
|
|
selectedElmY = position.y;
|
|
rect = targetElm.getBoundingClientRect();
|
|
targetWidth = rect.width || rect.right - rect.left;
|
|
targetHeight = rect.height || rect.bottom - rect.top;
|
|
if (selectedElm !== targetElm) {
|
|
selectedElm = targetElm;
|
|
width = height = 0;
|
|
}
|
|
e = editor.fire('ObjectSelected', { target: targetElm });
|
|
if (isResizable(targetElm) && !e.isDefaultPrevented()) {
|
|
each(resizeHandles, function (handle, name) {
|
|
var handleElm;
|
|
var startDrag = function (e) {
|
|
startX = e.screenX;
|
|
startY = e.screenY;
|
|
startW = getResizeTarget(selectedElm).clientWidth;
|
|
startH = getResizeTarget(selectedElm).clientHeight;
|
|
ratio = startH / startW;
|
|
selectedHandle = handle;
|
|
handle.startPos = {
|
|
x: targetWidth * handle[0] + selectedElmX,
|
|
y: targetHeight * handle[1] + selectedElmY
|
|
};
|
|
startScrollWidth = rootElement.scrollWidth;
|
|
startScrollHeight = rootElement.scrollHeight;
|
|
selectedElmGhost = selectedElm.cloneNode(true);
|
|
dom.addClass(selectedElmGhost, 'mce-clonedresizable');
|
|
dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
|
|
selectedElmGhost.contentEditable = false;
|
|
selectedElmGhost.unSelectabe = true;
|
|
dom.setStyles(selectedElmGhost, {
|
|
left: selectedElmX,
|
|
top: selectedElmY,
|
|
margin: 0
|
|
});
|
|
selectedElmGhost.removeAttribute('data-mce-selected');
|
|
rootElement.appendChild(selectedElmGhost);
|
|
dom.bind(editableDoc, 'mousemove', resizeGhostElement);
|
|
dom.bind(editableDoc, 'mouseup', endGhostResize);
|
|
if (rootDocument !== editableDoc) {
|
|
dom.bind(rootDocument, 'mousemove', resizeGhostElement);
|
|
dom.bind(rootDocument, 'mouseup', endGhostResize);
|
|
}
|
|
resizeHelper = dom.add(rootElement, 'div', {
|
|
'class': 'mce-resize-helper',
|
|
'data-mce-bogus': 'all'
|
|
}, startW + ' × ' + startH);
|
|
};
|
|
handleElm = dom.get('mceResizeHandle' + name);
|
|
if (handleElm) {
|
|
dom.remove(handleElm);
|
|
}
|
|
handleElm = dom.add(rootElement, 'div', {
|
|
'id': 'mceResizeHandle' + name,
|
|
'data-mce-bogus': 'all',
|
|
'class': 'mce-resizehandle',
|
|
'unselectable': true,
|
|
'style': 'cursor:' + name + '-resize; margin:0; padding:0'
|
|
});
|
|
if (Env.ie === 11) {
|
|
handleElm.contentEditable = false;
|
|
}
|
|
dom.bind(handleElm, 'mousedown', function (e) {
|
|
e.stopImmediatePropagation();
|
|
e.preventDefault();
|
|
startDrag(e);
|
|
});
|
|
handle.elm = handleElm;
|
|
dom.setStyles(handleElm, {
|
|
left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
|
|
top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
|
|
});
|
|
});
|
|
} else {
|
|
hideResizeRect();
|
|
}
|
|
selectedElm.setAttribute('data-mce-selected', '1');
|
|
};
|
|
var hideResizeRect = function () {
|
|
var name, handleElm;
|
|
unbindResizeHandleEvents();
|
|
if (selectedElm) {
|
|
selectedElm.removeAttribute('data-mce-selected');
|
|
}
|
|
for (name in resizeHandles) {
|
|
handleElm = dom.get('mceResizeHandle' + name);
|
|
if (handleElm) {
|
|
dom.unbind(handleElm);
|
|
dom.remove(handleElm);
|
|
}
|
|
}
|
|
};
|
|
var updateResizeRect = function (e) {
|
|
var startElm, controlElm;
|
|
var isChildOrEqual = function (node, parent) {
|
|
if (node) {
|
|
do {
|
|
if (node === parent) {
|
|
return true;
|
|
}
|
|
} while (node = node.parentNode);
|
|
}
|
|
};
|
|
if (resizeStarted || editor.removed) {
|
|
return;
|
|
}
|
|
each(dom.select('img[data-mce-selected],hr[data-mce-selected]'), function (img) {
|
|
img.removeAttribute('data-mce-selected');
|
|
});
|
|
controlElm = e.type === 'mousedown' ? e.target : selection.getNode();
|
|
controlElm = dom.$(controlElm).closest('table,img,figure.image,hr')[0];
|
|
if (isChildOrEqual(controlElm, rootElement)) {
|
|
disableGeckoResize();
|
|
startElm = selection.getStart(true);
|
|
if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
|
|
showResizeRect(controlElm);
|
|
return;
|
|
}
|
|
}
|
|
hideResizeRect();
|
|
};
|
|
var isWithinContentEditableFalse = function (elm) {
|
|
return isContentEditableFalse$a(getContentEditableRoot$1(editor.getBody(), elm));
|
|
};
|
|
var unbindResizeHandleEvents = function () {
|
|
for (var name in resizeHandles) {
|
|
var handle = resizeHandles[name];
|
|
if (handle.elm) {
|
|
dom.unbind(handle.elm);
|
|
delete handle.elm;
|
|
}
|
|
}
|
|
};
|
|
var disableGeckoResize = function () {
|
|
try {
|
|
editor.getDoc().execCommand('enableObjectResizing', false, false);
|
|
} catch (ex) {
|
|
}
|
|
};
|
|
editor.on('init', function () {
|
|
disableGeckoResize();
|
|
if (Env.browser.isIE() || Env.browser.isEdge()) {
|
|
editor.on('mousedown click', function (e) {
|
|
var target = e.target, nodeName = target.nodeName;
|
|
if (!resizeStarted && /^(TABLE|IMG|HR)$/.test(nodeName) && !isWithinContentEditableFalse(target)) {
|
|
if (e.button !== 2) {
|
|
editor.selection.select(target, nodeName === 'TABLE');
|
|
}
|
|
if (e.type === 'mousedown') {
|
|
editor.nodeChanged();
|
|
}
|
|
}
|
|
});
|
|
editor.dom.bind(rootElement, 'mscontrolselect', function (e) {
|
|
var delayedSelect = function (node) {
|
|
Delay.setEditorTimeout(editor, function () {
|
|
editor.selection.select(node);
|
|
});
|
|
};
|
|
if (isWithinContentEditableFalse(e.target)) {
|
|
e.preventDefault();
|
|
delayedSelect(e.target);
|
|
return;
|
|
}
|
|
if (/^(TABLE|IMG|HR)$/.test(e.target.nodeName)) {
|
|
e.preventDefault();
|
|
if (e.target.tagName === 'IMG') {
|
|
delayedSelect(e.target);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
var throttledUpdateResizeRect = Delay.throttle(function (e) {
|
|
if (!editor.composing) {
|
|
updateResizeRect(e);
|
|
}
|
|
});
|
|
editor.on('nodechange ResizeEditor ResizeWindow drop FullscreenStateChanged', throttledUpdateResizeRect);
|
|
editor.on('keyup compositionend', function (e) {
|
|
if (selectedElm && selectedElm.nodeName === 'TABLE') {
|
|
throttledUpdateResizeRect(e);
|
|
}
|
|
});
|
|
editor.on('hide blur', hideResizeRect);
|
|
editor.on('contextmenu longpress', contextMenuSelectImage, true);
|
|
});
|
|
editor.on('remove', unbindResizeHandleEvents);
|
|
var destroy = function () {
|
|
selectedElm = selectedElmGhost = null;
|
|
};
|
|
return {
|
|
isResizable: isResizable,
|
|
showResizeRect: showResizeRect,
|
|
hideResizeRect: hideResizeRect,
|
|
updateResizeRect: updateResizeRect,
|
|
destroy: destroy
|
|
};
|
|
};
|
|
|
|
function Dimension (name, getOffset) {
|
|
var set = function (element, h) {
|
|
if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
|
|
throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
|
|
}
|
|
var dom = element.dom();
|
|
if (isSupported(dom)) {
|
|
dom.style[name] = h + 'px';
|
|
}
|
|
};
|
|
var get = function (element) {
|
|
var r = getOffset(element);
|
|
if (r <= 0 || r === null) {
|
|
var css = get$2(element, name);
|
|
return parseFloat(css) || 0;
|
|
}
|
|
return r;
|
|
};
|
|
var getOuter = get;
|
|
var aggregate = function (element, properties) {
|
|
return foldl(properties, function (acc, property) {
|
|
var val = get$2(element, property);
|
|
var value = val === undefined ? 0 : parseInt(val, 10);
|
|
return isNaN(value) ? acc : acc + value;
|
|
}, 0);
|
|
};
|
|
var max = function (element, value, properties) {
|
|
var cumulativeInclusions = aggregate(element, properties);
|
|
var absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
|
|
return absoluteMax;
|
|
};
|
|
return {
|
|
set: set,
|
|
get: get,
|
|
getOuter: getOuter,
|
|
aggregate: aggregate,
|
|
max: max
|
|
};
|
|
}
|
|
|
|
var api$1 = Dimension('height', function (element) {
|
|
var dom = element.dom();
|
|
return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
|
|
});
|
|
var get$8 = function (element) {
|
|
return api$1.get(element);
|
|
};
|
|
|
|
var walkUp = function (navigation, doc) {
|
|
var frame = navigation.view(doc);
|
|
return frame.fold(constant([]), function (f) {
|
|
var parent = navigation.owner(f);
|
|
var rest = walkUp(navigation, parent);
|
|
return [f].concat(rest);
|
|
});
|
|
};
|
|
var pathTo = function (element, navigation) {
|
|
var d = navigation.owner(element);
|
|
return walkUp(navigation, d);
|
|
};
|
|
|
|
var view = function (doc) {
|
|
var element = doc.dom() === domGlobals.document ? Option.none() : Option.from(doc.dom().defaultView.frameElement);
|
|
return element.map(Element.fromDom);
|
|
};
|
|
var owner$1 = function (element) {
|
|
return owner(element);
|
|
};
|
|
|
|
var Navigation = /*#__PURE__*/Object.freeze({
|
|
view: view,
|
|
owner: owner$1
|
|
});
|
|
|
|
var find$4 = function (element) {
|
|
var doc = Element.fromDom(domGlobals.document);
|
|
var scroll = get$3(doc);
|
|
var frames = pathTo(element, Navigation);
|
|
var offset = viewport(element);
|
|
var r = foldr(frames, function (b, a) {
|
|
var loc = viewport(a);
|
|
return {
|
|
left: b.left + loc.left(),
|
|
top: b.top + loc.top()
|
|
};
|
|
}, {
|
|
left: 0,
|
|
top: 0
|
|
});
|
|
return Position$1(r.left + offset.left() + scroll.left(), r.top + offset.top() + scroll.top());
|
|
};
|
|
|
|
var excludeFromDescend = function (element) {
|
|
return name(element) === 'textarea';
|
|
};
|
|
var descend = function (element, offset) {
|
|
var children$1 = children(element);
|
|
if (children$1.length === 0 || excludeFromDescend(element)) {
|
|
return {
|
|
element: element,
|
|
offset: offset
|
|
};
|
|
} else if (offset < children$1.length && !excludeFromDescend(children$1[offset])) {
|
|
return {
|
|
element: children$1[offset],
|
|
offset: 0
|
|
};
|
|
} else {
|
|
var last = children$1[children$1.length - 1];
|
|
if (excludeFromDescend(last)) {
|
|
return {
|
|
element: element,
|
|
offset: offset
|
|
};
|
|
} else {
|
|
if (name(last) === 'img') {
|
|
return {
|
|
element: last,
|
|
offset: 1
|
|
};
|
|
} else if (isText$1(last)) {
|
|
return {
|
|
element: last,
|
|
offset: get$6(last).length
|
|
};
|
|
} else {
|
|
return {
|
|
element: last,
|
|
offset: children(last).length
|
|
};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var markerInfo = function (element, cleanupFun) {
|
|
var pos = absolute(element);
|
|
var height = get$8(element);
|
|
return {
|
|
element: element,
|
|
bottom: pos.top() + height,
|
|
pos: pos,
|
|
cleanup: cleanupFun
|
|
};
|
|
};
|
|
var createMarker = function (element, offset) {
|
|
var startPoint = descend(element, offset);
|
|
var span = Element.fromHtml('<span data-mce-bogus="all">' + Zwsp.ZWSP + '</span>');
|
|
before(startPoint.element, span);
|
|
return markerInfo(span, function () {
|
|
return remove$1(span);
|
|
});
|
|
};
|
|
var elementMarker = function (element) {
|
|
return markerInfo(Element.fromDom(element), noop);
|
|
};
|
|
var withMarker = function (editor, f, rng, alignToTop) {
|
|
preserveWith(editor, function (_s, _e) {
|
|
return applyWithMarker(editor, f, rng, alignToTop);
|
|
}, rng);
|
|
};
|
|
var applyWithMarker = function (editor, f, rng, alignToTop) {
|
|
var body = Element.fromDom(editor.getBody());
|
|
var doc = Element.fromDom(editor.getDoc());
|
|
reflow(body);
|
|
var scrollTop = get$3(doc).top();
|
|
var marker = createMarker(Element.fromDom(rng.startContainer), rng.startOffset);
|
|
f(doc, scrollTop, marker, alignToTop);
|
|
marker.cleanup();
|
|
};
|
|
var withElement = function (editor, element, f, alignToTop) {
|
|
var doc = Element.fromDom(editor.getDoc());
|
|
var scrollTop = get$3(doc).top();
|
|
f(doc, scrollTop, element, alignToTop);
|
|
};
|
|
var preserveWith = function (editor, f, rng) {
|
|
var startElement = rng.startContainer;
|
|
var startOffset = rng.startOffset;
|
|
var endElement = rng.endContainer;
|
|
var endOffset = rng.endOffset;
|
|
f(Element.fromDom(startElement), Element.fromDom(endElement));
|
|
var newRng = editor.dom.createRng();
|
|
newRng.setStart(startElement, startOffset);
|
|
newRng.setEnd(endElement, endOffset);
|
|
editor.selection.setRng(rng);
|
|
};
|
|
var fireScrollIntoViewEvent = function (editor, elm, alignToTop) {
|
|
var scrollEvent = editor.fire('ScrollIntoView', {
|
|
elm: elm,
|
|
alignToTop: alignToTop
|
|
});
|
|
return scrollEvent.isDefaultPrevented();
|
|
};
|
|
var scrollTo = function (marker, viewHeight, alignToTop, doc) {
|
|
var pos = marker.pos;
|
|
if (alignToTop) {
|
|
to(pos.left(), pos.top(), doc);
|
|
} else {
|
|
var y = pos.top() - viewHeight + (marker.bottom - pos.top());
|
|
to(pos.left(), y, doc);
|
|
}
|
|
};
|
|
var intoWindowIfNeeded = function (doc, scrollTop, viewHeight, marker, alignToTop) {
|
|
if (marker.pos.top() < scrollTop) {
|
|
scrollTo(marker, viewHeight, alignToTop !== false, doc);
|
|
} else if (marker.bottom > viewHeight + scrollTop) {
|
|
scrollTo(marker, viewHeight, alignToTop === true, doc);
|
|
}
|
|
};
|
|
var intoWindow = function (doc, scrollTop, marker, alignToTop) {
|
|
var viewHeight = doc.dom().defaultView.innerHeight;
|
|
intoWindowIfNeeded(doc, scrollTop, viewHeight, marker, alignToTop);
|
|
};
|
|
var intoFrame = function (editor, doc, scrollTop, marker, alignToTop) {
|
|
var frameViewHeight = doc.dom().defaultView.innerHeight;
|
|
intoWindowIfNeeded(doc, scrollTop, frameViewHeight, marker, alignToTop);
|
|
var op = find$4(marker.element);
|
|
var viewportBounds = getBounds(domGlobals.window);
|
|
if (op.top() < viewportBounds.y()) {
|
|
intoView(marker.element, alignToTop !== false);
|
|
} else if (op.top() > viewportBounds.bottom()) {
|
|
intoView(marker.element, alignToTop === true);
|
|
}
|
|
};
|
|
var rangeIntoWindow = function (editor, rng, alignToTop) {
|
|
return withMarker(editor, curry(intoWindow), rng, alignToTop);
|
|
};
|
|
var elementIntoWindow = function (editor, element, alignToTop) {
|
|
return withElement(editor, elementMarker(element), curry(intoWindow), alignToTop);
|
|
};
|
|
var rangeIntoFrame = function (editor, rng, alignToTop) {
|
|
return withMarker(editor, curry(intoFrame, editor), rng, alignToTop);
|
|
};
|
|
var elementIntoFrame = function (editor, element, alignToTop) {
|
|
return withElement(editor, elementMarker(element), curry(intoFrame, editor), alignToTop);
|
|
};
|
|
var elementIntoView = function (editor, element, alignToTop) {
|
|
if (fireScrollIntoViewEvent(editor, element, alignToTop)) {
|
|
return;
|
|
}
|
|
var scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
|
|
scroller(editor, element, alignToTop);
|
|
};
|
|
var rangeIntoView = function (editor, rng, alignToTop) {
|
|
var scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
|
|
scroller(editor, rng, alignToTop);
|
|
};
|
|
var ScrollIntoView = {
|
|
scrollElementIntoView: elementIntoView,
|
|
scrollRangeIntoView: rangeIntoView
|
|
};
|
|
|
|
var hasCeProperty = function (node) {
|
|
return NodeType.isContentEditableTrue(node) || NodeType.isContentEditableFalse(node);
|
|
};
|
|
var findParent = function (node, rootNode, predicate) {
|
|
while (node && node !== rootNode) {
|
|
if (predicate(node)) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var findClosestIeRange = function (clientX, clientY, doc) {
|
|
var element, rng, rects;
|
|
element = doc.elementFromPoint(clientX, clientY);
|
|
rng = doc.body.createTextRange();
|
|
if (!element || element.tagName === 'HTML') {
|
|
element = doc.body;
|
|
}
|
|
rng.moveToElementText(element);
|
|
rects = Tools.toArray(rng.getClientRects());
|
|
rects = rects.sort(function (a, b) {
|
|
a = Math.abs(Math.max(a.top - clientY, a.bottom - clientY));
|
|
b = Math.abs(Math.max(b.top - clientY, b.bottom - clientY));
|
|
return a - b;
|
|
});
|
|
if (rects.length > 0) {
|
|
clientY = (rects[0].bottom + rects[0].top) / 2;
|
|
try {
|
|
rng.moveToPoint(clientX, clientY);
|
|
rng.collapse(true);
|
|
return rng;
|
|
} catch (ex) {
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var moveOutOfContentEditableFalse = function (rng, rootNode) {
|
|
var parentElement = rng && rng.parentElement ? rng.parentElement() : null;
|
|
return NodeType.isContentEditableFalse(findParent(parentElement, rootNode, hasCeProperty)) ? null : rng;
|
|
};
|
|
var fromPoint$1 = function (clientX, clientY, doc) {
|
|
var rng, point;
|
|
var pointDoc = doc;
|
|
if (pointDoc.caretPositionFromPoint) {
|
|
point = pointDoc.caretPositionFromPoint(clientX, clientY);
|
|
if (point) {
|
|
rng = doc.createRange();
|
|
rng.setStart(point.offsetNode, point.offset);
|
|
rng.collapse(true);
|
|
}
|
|
} else if (doc.caretRangeFromPoint) {
|
|
rng = doc.caretRangeFromPoint(clientX, clientY);
|
|
} else if (pointDoc.body.createTextRange) {
|
|
rng = pointDoc.body.createTextRange();
|
|
try {
|
|
rng.moveToPoint(clientX, clientY);
|
|
rng.collapse(true);
|
|
} catch (ex) {
|
|
rng = findClosestIeRange(clientX, clientY, doc);
|
|
}
|
|
return moveOutOfContentEditableFalse(rng, doc.body);
|
|
}
|
|
return rng;
|
|
};
|
|
var CaretRangeFromPoint = { fromPoint: fromPoint$1 };
|
|
|
|
var processRanges = function (editor, ranges) {
|
|
return map(ranges, function (range) {
|
|
var evt = editor.fire('GetSelectionRange', { range: range });
|
|
return evt.range !== range ? evt.range : range;
|
|
});
|
|
};
|
|
var EventProcessRanges = { processRanges: processRanges };
|
|
|
|
var fromElements = function (elements, scope) {
|
|
var doc = scope || domGlobals.document;
|
|
var fragment = doc.createDocumentFragment();
|
|
each(elements, function (element) {
|
|
fragment.appendChild(element.dom());
|
|
});
|
|
return Element.fromDom(fragment);
|
|
};
|
|
|
|
var tableModel = Immutable('element', 'width', 'rows');
|
|
var tableRow = Immutable('element', 'cells');
|
|
var cellPosition = Immutable('x', 'y');
|
|
var getSpan = function (td, key) {
|
|
var value = parseInt(get$1(td, key), 10);
|
|
return isNaN(value) ? 1 : value;
|
|
};
|
|
var fillout = function (table, x, y, tr, td) {
|
|
var rowspan = getSpan(td, 'rowspan');
|
|
var colspan = getSpan(td, 'colspan');
|
|
var rows = table.rows();
|
|
for (var y2 = y; y2 < y + rowspan; y2++) {
|
|
if (!rows[y2]) {
|
|
rows[y2] = tableRow(deep(tr), []);
|
|
}
|
|
for (var x2 = x; x2 < x + colspan; x2++) {
|
|
var cells = rows[y2].cells();
|
|
cells[x2] = y2 === y && x2 === x ? td : shallow(td);
|
|
}
|
|
}
|
|
};
|
|
var cellExists = function (table, x, y) {
|
|
var rows = table.rows();
|
|
var cells = rows[y] ? rows[y].cells() : [];
|
|
return !!cells[x];
|
|
};
|
|
var skipCellsX = function (table, x, y) {
|
|
while (cellExists(table, x, y)) {
|
|
x++;
|
|
}
|
|
return x;
|
|
};
|
|
var getWidth = function (rows) {
|
|
return foldl(rows, function (acc, row) {
|
|
return row.cells().length > acc ? row.cells().length : acc;
|
|
}, 0);
|
|
};
|
|
var findElementPos = function (table, element) {
|
|
var rows = table.rows();
|
|
for (var y = 0; y < rows.length; y++) {
|
|
var cells = rows[y].cells();
|
|
for (var x = 0; x < cells.length; x++) {
|
|
if (eq(cells[x], element)) {
|
|
return Option.some(cellPosition(x, y));
|
|
}
|
|
}
|
|
}
|
|
return Option.none();
|
|
};
|
|
var extractRows = function (table, sx, sy, ex, ey) {
|
|
var newRows = [];
|
|
var rows = table.rows();
|
|
for (var y = sy; y <= ey; y++) {
|
|
var cells = rows[y].cells();
|
|
var slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
|
|
newRows.push(tableRow(rows[y].element(), slice));
|
|
}
|
|
return newRows;
|
|
};
|
|
var subTable = function (table, startPos, endPos) {
|
|
var sx = startPos.x(), sy = startPos.y();
|
|
var ex = endPos.x(), ey = endPos.y();
|
|
var newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
|
|
return tableModel(table.element(), getWidth(newRows), newRows);
|
|
};
|
|
var createDomTable = function (table, rows) {
|
|
var tableElement = shallow(table.element());
|
|
var tableBody = Element.fromTag('tbody');
|
|
append$1(tableBody, rows);
|
|
append(tableElement, tableBody);
|
|
return tableElement;
|
|
};
|
|
var modelRowsToDomRows = function (table) {
|
|
return map(table.rows(), function (row) {
|
|
var cells = map(row.cells(), function (cell) {
|
|
var td = deep(cell);
|
|
remove(td, 'colspan');
|
|
remove(td, 'rowspan');
|
|
return td;
|
|
});
|
|
var tr = shallow(row.element());
|
|
append$1(tr, cells);
|
|
return tr;
|
|
});
|
|
};
|
|
var fromDom$1 = function (tableElm) {
|
|
var table = tableModel(shallow(tableElm), 0, []);
|
|
each(descendants$1(tableElm, 'tr'), function (tr, y) {
|
|
each(descendants$1(tr, 'td,th'), function (td, x) {
|
|
fillout(table, skipCellsX(table, x, y), y, tr, td);
|
|
});
|
|
});
|
|
return tableModel(table.element(), getWidth(table.rows()), table.rows());
|
|
};
|
|
var toDom = function (table) {
|
|
return createDomTable(table, modelRowsToDomRows(table));
|
|
};
|
|
var subsection = function (table, startElement, endElement) {
|
|
return findElementPos(table, startElement).bind(function (startPos) {
|
|
return findElementPos(table, endElement).map(function (endPos) {
|
|
return subTable(table, startPos, endPos);
|
|
});
|
|
});
|
|
};
|
|
var SimpleTableModel = {
|
|
fromDom: fromDom$1,
|
|
toDom: toDom,
|
|
subsection: subsection
|
|
};
|
|
|
|
var getRanges = function (selection) {
|
|
var ranges = [];
|
|
if (selection) {
|
|
for (var i = 0; i < selection.rangeCount; i++) {
|
|
ranges.push(selection.getRangeAt(i));
|
|
}
|
|
}
|
|
return ranges;
|
|
};
|
|
var getSelectedNodes = function (ranges) {
|
|
return bind(ranges, function (range) {
|
|
var node = getSelectedNode(range);
|
|
return node ? [Element.fromDom(node)] : [];
|
|
});
|
|
};
|
|
var hasMultipleRanges = function (selection) {
|
|
return getRanges(selection).length > 1;
|
|
};
|
|
var MultiRange = {
|
|
getRanges: getRanges,
|
|
getSelectedNodes: getSelectedNodes,
|
|
hasMultipleRanges: hasMultipleRanges
|
|
};
|
|
|
|
var getCellsFromRanges = function (ranges) {
|
|
return filter(MultiRange.getSelectedNodes(ranges), isTableCell);
|
|
};
|
|
var getCellsFromElement = function (elm) {
|
|
return descendants$1(elm, 'td[data-mce-selected],th[data-mce-selected]');
|
|
};
|
|
var getCellsFromElementOrRanges = function (ranges, element) {
|
|
var selectedCells = getCellsFromElement(element);
|
|
var rangeCells = getCellsFromRanges(ranges);
|
|
return selectedCells.length > 0 ? selectedCells : rangeCells;
|
|
};
|
|
var getCellsFromEditor = function (editor) {
|
|
return getCellsFromElementOrRanges(MultiRange.getRanges(editor.selection.getSel()), Element.fromDom(editor.getBody()));
|
|
};
|
|
var TableCellSelection = {
|
|
getCellsFromRanges: getCellsFromRanges,
|
|
getCellsFromElement: getCellsFromElement,
|
|
getCellsFromElementOrRanges: getCellsFromElementOrRanges,
|
|
getCellsFromEditor: getCellsFromEditor
|
|
};
|
|
|
|
var findParentListContainer = function (parents) {
|
|
return find(parents, function (elm) {
|
|
return name(elm) === 'ul' || name(elm) === 'ol';
|
|
});
|
|
};
|
|
var getFullySelectedListWrappers = function (parents, rng) {
|
|
return find(parents, function (elm) {
|
|
return name(elm) === 'li' && hasAllContentsSelected(elm, rng);
|
|
}).fold(constant([]), function (li) {
|
|
return findParentListContainer(parents).map(function (listCont) {
|
|
return [
|
|
Element.fromTag('li'),
|
|
Element.fromTag(name(listCont))
|
|
];
|
|
}).getOr([]);
|
|
});
|
|
};
|
|
var wrap$3 = function (innerElm, elms) {
|
|
var wrapped = foldl(elms, function (acc, elm) {
|
|
append(elm, acc);
|
|
return elm;
|
|
}, innerElm);
|
|
return elms.length > 0 ? fromElements([wrapped]) : wrapped;
|
|
};
|
|
var directListWrappers = function (commonAnchorContainer) {
|
|
if (isListItem(commonAnchorContainer)) {
|
|
return parent(commonAnchorContainer).filter(isList).fold(constant([]), function (listElm) {
|
|
return [
|
|
commonAnchorContainer,
|
|
listElm
|
|
];
|
|
});
|
|
} else {
|
|
return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
|
|
}
|
|
};
|
|
var getWrapElements = function (rootNode, rng) {
|
|
var commonAnchorContainer = Element.fromDom(rng.commonAncestorContainer);
|
|
var parents = Parents.parentsAndSelf(commonAnchorContainer, rootNode);
|
|
var wrapElements = filter(parents, function (elm) {
|
|
return isInline(elm) || isHeading(elm);
|
|
});
|
|
var listWrappers = getFullySelectedListWrappers(parents, rng);
|
|
var allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
|
|
return map(allWrappers, shallow);
|
|
};
|
|
var emptyFragment = function () {
|
|
return fromElements([]);
|
|
};
|
|
var getFragmentFromRange = function (rootNode, rng) {
|
|
return wrap$3(Element.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng));
|
|
};
|
|
var getParentTable = function (rootElm, cell) {
|
|
return ancestor$1(cell, 'table', curry(eq, rootElm));
|
|
};
|
|
var getTableFragment = function (rootNode, selectedTableCells) {
|
|
return getParentTable(rootNode, selectedTableCells[0]).bind(function (tableElm) {
|
|
var firstCell = selectedTableCells[0];
|
|
var lastCell = selectedTableCells[selectedTableCells.length - 1];
|
|
var fullTableModel = SimpleTableModel.fromDom(tableElm);
|
|
return SimpleTableModel.subsection(fullTableModel, firstCell, lastCell).map(function (sectionedTableModel) {
|
|
return fromElements([SimpleTableModel.toDom(sectionedTableModel)]);
|
|
});
|
|
}).getOrThunk(emptyFragment);
|
|
};
|
|
var getSelectionFragment = function (rootNode, ranges) {
|
|
return ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0]);
|
|
};
|
|
var read$2 = function (rootNode, ranges) {
|
|
var selectedCells = TableCellSelection.getCellsFromElementOrRanges(ranges, rootNode);
|
|
return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges);
|
|
};
|
|
var FragmentReader = { read: read$2 };
|
|
|
|
var getTextContent = function (editor) {
|
|
return Option.from(editor.selection.getRng()).map(function (rng) {
|
|
var bin = editor.dom.add(editor.getBody(), 'div', {
|
|
'data-mce-bogus': 'all',
|
|
'style': 'overflow: hidden; opacity: 0;'
|
|
}, rng.cloneContents());
|
|
var text = Zwsp.trim(bin.innerText);
|
|
editor.dom.remove(bin);
|
|
return text;
|
|
}).getOr('');
|
|
};
|
|
var getHtmlContent = function (editor, args) {
|
|
var rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
|
|
var sel = editor.selection.getSel();
|
|
var fragment;
|
|
var ranges = EventProcessRanges.processRanges(editor, MultiRange.getRanges(sel));
|
|
fragment = args.contextual ? FragmentReader.read(Element.fromDom(editor.getBody()), ranges).dom() : rng.cloneContents();
|
|
if (fragment) {
|
|
tmpElm.appendChild(fragment);
|
|
}
|
|
return editor.selection.serializer.serialize(tmpElm, args);
|
|
};
|
|
var getContent$1 = function (editor, args) {
|
|
if (args === void 0) {
|
|
args = {};
|
|
}
|
|
args.get = true;
|
|
args.format = args.format || 'html';
|
|
args.selection = true;
|
|
args = editor.fire('BeforeGetContent', args);
|
|
if (args.isDefaultPrevented()) {
|
|
editor.fire('GetContent', args);
|
|
return args.content;
|
|
}
|
|
if (args.format === 'text') {
|
|
return getTextContent(editor);
|
|
} else {
|
|
args.getInner = true;
|
|
var content = getHtmlContent(editor, args);
|
|
if (args.format === 'tree') {
|
|
return content;
|
|
} else {
|
|
args.content = editor.selection.isCollapsed() ? '' : content;
|
|
editor.fire('GetContent', args);
|
|
return args.content;
|
|
}
|
|
}
|
|
};
|
|
var GetSelectionContent = { getContent: getContent$1 };
|
|
|
|
var findParent$1 = function (node, rootNode, predicate) {
|
|
while (node && node !== rootNode) {
|
|
if (predicate(node)) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var hasParent = function (node, rootNode, predicate) {
|
|
return findParent$1(node, rootNode, predicate) !== null;
|
|
};
|
|
var hasParentWithName = function (node, rootNode, name) {
|
|
return hasParent(node, rootNode, function (node) {
|
|
return node.nodeName === name;
|
|
});
|
|
};
|
|
var isTable$3 = function (node) {
|
|
return node && node.nodeName === 'TABLE';
|
|
};
|
|
var isTableCell$3 = function (node) {
|
|
return node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
|
|
};
|
|
var isCeFalseCaretContainer = function (node, rootNode) {
|
|
return isCaretContainer(node) && hasParent(node, rootNode, isCaretNode) === false;
|
|
};
|
|
var hasBrBeforeAfter = function (dom, node, left) {
|
|
var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || dom.getRoot());
|
|
while (node = walker[left ? 'prev' : 'next']()) {
|
|
if (NodeType.isBr(node)) {
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
var isPrevNode = function (node, name) {
|
|
return node.previousSibling && node.previousSibling.nodeName === name;
|
|
};
|
|
var hasContentEditableFalseParent = function (body, node) {
|
|
while (node && node !== body) {
|
|
if (NodeType.isContentEditableFalse(node)) {
|
|
return true;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return false;
|
|
};
|
|
var findTextNodeRelative = function (dom, isAfterNode, collapsed, left, startNode) {
|
|
var lastInlineElement;
|
|
var body = dom.getRoot();
|
|
var node;
|
|
var nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
|
var parentBlockContainer = dom.getParent(startNode.parentNode, dom.isBlock) || body;
|
|
if (left && NodeType.isBr(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
|
|
return Option.some(CaretPosition(startNode.parentNode, dom.nodeIndex(startNode)));
|
|
}
|
|
var walker = new TreeWalker(startNode, parentBlockContainer);
|
|
while (node = walker[left ? 'prev' : 'next']()) {
|
|
if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
|
|
return Option.none();
|
|
}
|
|
if (NodeType.isText(node) && node.nodeValue.length > 0) {
|
|
if (hasParentWithName(node, body, 'A') === false) {
|
|
return Option.some(CaretPosition(node, left ? node.nodeValue.length : 0));
|
|
}
|
|
return Option.none();
|
|
}
|
|
if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
|
return Option.none();
|
|
}
|
|
lastInlineElement = node;
|
|
}
|
|
if (collapsed && lastInlineElement) {
|
|
return Option.some(CaretPosition(lastInlineElement, 0));
|
|
}
|
|
return Option.none();
|
|
};
|
|
var normalizeEndPoint = function (dom, collapsed, start, rng) {
|
|
var container, offset;
|
|
var body = dom.getRoot();
|
|
var node, nonEmptyElementsMap;
|
|
var directionLeft, isAfterNode, normalized = false;
|
|
container = rng[(start ? 'start' : 'end') + 'Container'];
|
|
offset = rng[(start ? 'start' : 'end') + 'Offset'];
|
|
isAfterNode = NodeType.isElement(container) && offset === container.childNodes.length;
|
|
nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
|
directionLeft = start;
|
|
if (isCaretContainer(container)) {
|
|
return Option.none();
|
|
}
|
|
if (NodeType.isElement(container) && offset > container.childNodes.length - 1) {
|
|
directionLeft = false;
|
|
}
|
|
if (NodeType.isDocument(container)) {
|
|
container = body;
|
|
offset = 0;
|
|
}
|
|
if (container === body) {
|
|
if (directionLeft) {
|
|
node = container.childNodes[offset > 0 ? offset - 1 : 0];
|
|
if (node) {
|
|
if (isCaretContainer(node)) {
|
|
return Option.none();
|
|
}
|
|
if (nonEmptyElementsMap[node.nodeName] || isTable$3(node)) {
|
|
return Option.none();
|
|
}
|
|
}
|
|
}
|
|
if (container.hasChildNodes()) {
|
|
offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
|
|
container = container.childNodes[offset];
|
|
offset = NodeType.isText(container) && isAfterNode ? container.data.length : 0;
|
|
if (!collapsed && container === body.lastChild && isTable$3(container)) {
|
|
return Option.none();
|
|
}
|
|
if (hasContentEditableFalseParent(body, container) || isCaretContainer(container)) {
|
|
return Option.none();
|
|
}
|
|
if (container.hasChildNodes() && isTable$3(container) === false) {
|
|
node = container;
|
|
var walker = new TreeWalker(container, body);
|
|
do {
|
|
if (NodeType.isContentEditableFalse(node) || isCaretContainer(node)) {
|
|
normalized = false;
|
|
break;
|
|
}
|
|
if (NodeType.isText(node) && node.nodeValue.length > 0) {
|
|
offset = directionLeft ? 0 : node.nodeValue.length;
|
|
container = node;
|
|
normalized = true;
|
|
break;
|
|
}
|
|
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCell$3(node)) {
|
|
offset = dom.nodeIndex(node);
|
|
container = node.parentNode;
|
|
if (!directionLeft) {
|
|
offset++;
|
|
}
|
|
normalized = true;
|
|
break;
|
|
}
|
|
} while (node = directionLeft ? walker.next() : walker.prev());
|
|
}
|
|
}
|
|
}
|
|
if (collapsed) {
|
|
if (NodeType.isText(container) && offset === 0) {
|
|
findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(function (pos) {
|
|
container = pos.container();
|
|
offset = pos.offset();
|
|
normalized = true;
|
|
});
|
|
}
|
|
if (NodeType.isElement(container)) {
|
|
node = container.childNodes[offset];
|
|
if (!node) {
|
|
node = container.childNodes[offset - 1];
|
|
}
|
|
if (node && NodeType.isBr(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
|
|
findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(function (pos) {
|
|
container = pos.container();
|
|
offset = pos.offset();
|
|
normalized = true;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (directionLeft && !collapsed && NodeType.isText(container) && offset === container.nodeValue.length) {
|
|
findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(function (pos) {
|
|
container = pos.container();
|
|
offset = pos.offset();
|
|
normalized = true;
|
|
});
|
|
}
|
|
return normalized ? Option.some(CaretPosition(container, offset)) : Option.none();
|
|
};
|
|
var normalize$2 = function (dom, rng) {
|
|
var collapsed = rng.collapsed, normRng = rng.cloneRange();
|
|
var startPos = CaretPosition.fromRangeStart(rng);
|
|
normalizeEndPoint(dom, collapsed, true, normRng).each(function (pos) {
|
|
if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
|
|
normRng.setStart(pos.container(), pos.offset());
|
|
}
|
|
});
|
|
if (!collapsed) {
|
|
normalizeEndPoint(dom, collapsed, false, normRng).each(function (pos) {
|
|
normRng.setEnd(pos.container(), pos.offset());
|
|
});
|
|
}
|
|
if (collapsed) {
|
|
normRng.collapse(true);
|
|
}
|
|
return RangeCompare.isEq(rng, normRng) ? Option.none() : Option.some(normRng);
|
|
};
|
|
var NormalizeRange = { normalize: normalize$2 };
|
|
|
|
var prependData = function (target, data) {
|
|
target.insertData(0, data);
|
|
};
|
|
var removeEmpty = function (text) {
|
|
if (text.dom().length === 0) {
|
|
remove$1(text);
|
|
return Option.none();
|
|
}
|
|
return Option.some(text);
|
|
};
|
|
var rngSetContent = function (rng, fragment) {
|
|
var firstChild = Option.from(fragment.firstChild).map(Element.fromDom);
|
|
var lastChild = Option.from(fragment.lastChild).map(Element.fromDom);
|
|
rng.deleteContents();
|
|
rng.insertNode(fragment);
|
|
var prevText = firstChild.bind(prevSibling).filter(isText$1).bind(removeEmpty);
|
|
var nextText = lastChild.bind(nextSibling).filter(isText$1).bind(removeEmpty);
|
|
lift2(prevText, firstChild.filter(isText$1), function (prev, start) {
|
|
prependData(start.dom(), prev.dom().data);
|
|
remove$1(prev);
|
|
});
|
|
lift2(nextText, lastChild.filter(isText$1), function (next, end) {
|
|
var oldLength = end.dom().length;
|
|
end.dom().appendData(next.dom().data);
|
|
rng.setEnd(end.dom(), oldLength);
|
|
remove$1(next);
|
|
});
|
|
rng.collapse(false);
|
|
};
|
|
var setupArgs = function (args, content) {
|
|
args = args || { format: 'html' };
|
|
args.set = true;
|
|
args.selection = true;
|
|
args.content = content;
|
|
return args;
|
|
};
|
|
var setContent$1 = function (editor, content, args) {
|
|
args = setupArgs(args, content);
|
|
if (!args.no_events) {
|
|
args = editor.fire('BeforeSetContent', args);
|
|
if (args.isDefaultPrevented()) {
|
|
editor.fire('SetContent', args);
|
|
return;
|
|
}
|
|
}
|
|
var rng = editor.selection.getRng();
|
|
rngSetContent(rng, rng.createContextualFragment(args.content));
|
|
editor.selection.setRng(rng);
|
|
ScrollIntoView.scrollRangeIntoView(editor, rng);
|
|
if (!args.no_events) {
|
|
editor.fire('SetContent', args);
|
|
}
|
|
};
|
|
var SetSelectionContent = { setContent: setContent$1 };
|
|
|
|
var getEndpointElement = function (root, rng, start, real, resolve) {
|
|
var container = start ? rng.startContainer : rng.endContainer;
|
|
var offset = start ? rng.startOffset : rng.endOffset;
|
|
return Option.from(container).map(Element.fromDom).map(function (elm) {
|
|
return !real || !rng.collapsed ? child(elm, resolve(elm, offset)).getOr(elm) : elm;
|
|
}).bind(function (elm) {
|
|
return isElement$1(elm) ? Option.some(elm) : parent(elm);
|
|
}).map(function (elm) {
|
|
return elm.dom();
|
|
}).getOr(root);
|
|
};
|
|
var getStart$2 = function (root, rng, real) {
|
|
return getEndpointElement(root, rng, true, real, function (elm, offset) {
|
|
return Math.min(childNodesCount(elm), offset);
|
|
});
|
|
};
|
|
var getEnd = function (root, rng, real) {
|
|
return getEndpointElement(root, rng, false, real, function (elm, offset) {
|
|
return offset > 0 ? offset - 1 : offset;
|
|
});
|
|
};
|
|
var skipEmptyTextNodes = function (node, forwards) {
|
|
var orig = node;
|
|
while (node && NodeType.isText(node) && node.length === 0) {
|
|
node = forwards ? node.nextSibling : node.previousSibling;
|
|
}
|
|
return node || orig;
|
|
};
|
|
var getNode$1 = function (root, rng) {
|
|
var elm, startContainer, endContainer, startOffset, endOffset;
|
|
if (!rng) {
|
|
return root;
|
|
}
|
|
startContainer = rng.startContainer;
|
|
endContainer = rng.endContainer;
|
|
startOffset = rng.startOffset;
|
|
endOffset = rng.endOffset;
|
|
elm = rng.commonAncestorContainer;
|
|
if (!rng.collapsed) {
|
|
if (startContainer === endContainer) {
|
|
if (endOffset - startOffset < 2) {
|
|
if (startContainer.hasChildNodes()) {
|
|
elm = startContainer.childNodes[startOffset];
|
|
}
|
|
}
|
|
}
|
|
if (startContainer.nodeType === 3 && endContainer.nodeType === 3) {
|
|
if (startContainer.length === startOffset) {
|
|
startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
|
|
} else {
|
|
startContainer = startContainer.parentNode;
|
|
}
|
|
if (endOffset === 0) {
|
|
endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
|
|
} else {
|
|
endContainer = endContainer.parentNode;
|
|
}
|
|
if (startContainer && startContainer === endContainer) {
|
|
return startContainer;
|
|
}
|
|
}
|
|
}
|
|
if (elm && elm.nodeType === 3) {
|
|
return elm.parentNode;
|
|
}
|
|
return elm;
|
|
};
|
|
var getSelectedBlocks = function (dom, rng, startElm, endElm) {
|
|
var node, root;
|
|
var selectedBlocks = [];
|
|
root = dom.getRoot();
|
|
startElm = dom.getParent(startElm || getStart$2(root, rng, rng.collapsed), dom.isBlock);
|
|
endElm = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock);
|
|
if (startElm && startElm !== root) {
|
|
selectedBlocks.push(startElm);
|
|
}
|
|
if (startElm && endElm && startElm !== endElm) {
|
|
node = startElm;
|
|
var walker = new TreeWalker(startElm, root);
|
|
while ((node = walker.next()) && node !== endElm) {
|
|
if (dom.isBlock(node)) {
|
|
selectedBlocks.push(node);
|
|
}
|
|
}
|
|
}
|
|
if (endElm && startElm !== endElm && endElm !== root) {
|
|
selectedBlocks.push(endElm);
|
|
}
|
|
return selectedBlocks;
|
|
};
|
|
var select$1 = function (dom, node, content) {
|
|
return Option.from(node).map(function (node) {
|
|
var idx = dom.nodeIndex(node);
|
|
var rng = dom.createRng();
|
|
rng.setStart(node.parentNode, idx);
|
|
rng.setEnd(node.parentNode, idx + 1);
|
|
if (content) {
|
|
moveEndPoint$1(dom, rng, node, true);
|
|
moveEndPoint$1(dom, rng, node, false);
|
|
}
|
|
return rng;
|
|
});
|
|
};
|
|
|
|
var deleteFromCallbackMap = function (callbackMap, selector, callback) {
|
|
if (callbackMap && callbackMap.hasOwnProperty(selector)) {
|
|
var newCallbacks = filter(callbackMap[selector], function (cb) {
|
|
return cb !== callback;
|
|
});
|
|
if (newCallbacks.length === 0) {
|
|
delete callbackMap[selector];
|
|
} else {
|
|
callbackMap[selector] = newCallbacks;
|
|
}
|
|
}
|
|
};
|
|
function SelectorChanged (dom, editor) {
|
|
var selectorChangedData;
|
|
var currentSelectors;
|
|
return {
|
|
selectorChangedWithUnbind: function (selector, callback) {
|
|
if (!selectorChangedData) {
|
|
selectorChangedData = {};
|
|
currentSelectors = {};
|
|
editor.on('NodeChange', function (e) {
|
|
var node = e.element, parents = dom.getParents(node, null, dom.getRoot()), matchedSelectors = {};
|
|
Tools.each(selectorChangedData, function (callbacks, selector) {
|
|
Tools.each(parents, function (node) {
|
|
if (dom.is(node, selector)) {
|
|
if (!currentSelectors[selector]) {
|
|
Tools.each(callbacks, function (callback) {
|
|
callback(true, {
|
|
node: node,
|
|
selector: selector,
|
|
parents: parents
|
|
});
|
|
});
|
|
currentSelectors[selector] = callbacks;
|
|
}
|
|
matchedSelectors[selector] = callbacks;
|
|
return false;
|
|
}
|
|
});
|
|
});
|
|
Tools.each(currentSelectors, function (callbacks, selector) {
|
|
if (!matchedSelectors[selector]) {
|
|
delete currentSelectors[selector];
|
|
Tools.each(callbacks, function (callback) {
|
|
callback(false, {
|
|
node: node,
|
|
selector: selector,
|
|
parents: parents
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
if (!selectorChangedData[selector]) {
|
|
selectorChangedData[selector] = [];
|
|
}
|
|
selectorChangedData[selector].push(callback);
|
|
return {
|
|
unbind: function () {
|
|
deleteFromCallbackMap(selectorChangedData, selector, callback);
|
|
deleteFromCallbackMap(currentSelectors, selector, callback);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
var isNativeIeSelection = function (rng) {
|
|
return !!rng.select;
|
|
};
|
|
var isAttachedToDom = function (node) {
|
|
return !!(node && node.ownerDocument) && contains$2(Element.fromDom(node.ownerDocument), Element.fromDom(node));
|
|
};
|
|
var isValidRange = function (rng) {
|
|
if (!rng) {
|
|
return false;
|
|
} else if (isNativeIeSelection(rng)) {
|
|
return true;
|
|
} else {
|
|
return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
|
|
}
|
|
};
|
|
var Selection$1 = function (dom, win, serializer, editor) {
|
|
var bookmarkManager;
|
|
var controlSelection;
|
|
var selectedRange;
|
|
var explicitRange;
|
|
var selectorChangedWithUnbind = SelectorChanged(dom, editor).selectorChangedWithUnbind;
|
|
var setCursorLocation = function (node, offset) {
|
|
var rng = dom.createRng();
|
|
if (!node) {
|
|
moveEndPoint$1(dom, rng, editor.getBody(), true);
|
|
setRng(rng);
|
|
} else {
|
|
rng.setStart(node, offset);
|
|
rng.setEnd(node, offset);
|
|
setRng(rng);
|
|
collapse(false);
|
|
}
|
|
};
|
|
var getContent = function (args) {
|
|
return GetSelectionContent.getContent(editor, args);
|
|
};
|
|
var setContent = function (content, args) {
|
|
return SetSelectionContent.setContent(editor, content, args);
|
|
};
|
|
var getStart = function (real) {
|
|
return getStart$2(editor.getBody(), getRng(), real);
|
|
};
|
|
var getEnd$1 = function (real) {
|
|
return getEnd(editor.getBody(), getRng(), real);
|
|
};
|
|
var getBookmark = function (type, normalized) {
|
|
return bookmarkManager.getBookmark(type, normalized);
|
|
};
|
|
var moveToBookmark = function (bookmark) {
|
|
return bookmarkManager.moveToBookmark(bookmark);
|
|
};
|
|
var select = function (node, content) {
|
|
select$1(dom, node, content).each(setRng);
|
|
return node;
|
|
};
|
|
var isCollapsed = function () {
|
|
var rng = getRng(), sel = getSel();
|
|
if (!rng || rng.item) {
|
|
return false;
|
|
}
|
|
if (rng.compareEndPoints) {
|
|
return rng.compareEndPoints('StartToEnd', rng) === 0;
|
|
}
|
|
return !sel || rng.collapsed;
|
|
};
|
|
var collapse = function (toStart) {
|
|
var rng = getRng();
|
|
rng.collapse(!!toStart);
|
|
setRng(rng);
|
|
};
|
|
var getSel = function () {
|
|
return win.getSelection ? win.getSelection() : win.document.selection;
|
|
};
|
|
var getRng = function () {
|
|
var selection, rng, elm, doc;
|
|
var tryCompareBoundaryPoints = function (how, sourceRange, destinationRange) {
|
|
try {
|
|
return sourceRange.compareBoundaryPoints(how, destinationRange);
|
|
} catch (ex) {
|
|
return -1;
|
|
}
|
|
};
|
|
if (!win) {
|
|
return null;
|
|
}
|
|
doc = win.document;
|
|
if (typeof doc === 'undefined' || doc === null) {
|
|
return null;
|
|
}
|
|
if (editor.bookmark !== undefined && EditorFocus.hasFocus(editor) === false) {
|
|
var bookmark = SelectionBookmark.getRng(editor);
|
|
if (bookmark.isSome()) {
|
|
return bookmark.map(function (r) {
|
|
return EventProcessRanges.processRanges(editor, [r])[0];
|
|
}).getOr(doc.createRange());
|
|
}
|
|
}
|
|
try {
|
|
if ((selection = getSel()) && !NodeType.isRestrictedNode(selection.anchorNode)) {
|
|
if (selection.rangeCount > 0) {
|
|
rng = selection.getRangeAt(0);
|
|
} else {
|
|
rng = selection.createRange ? selection.createRange() : doc.createRange();
|
|
}
|
|
}
|
|
} catch (ex) {
|
|
}
|
|
rng = EventProcessRanges.processRanges(editor, [rng])[0];
|
|
if (!rng) {
|
|
rng = doc.createRange ? doc.createRange() : doc.body.createTextRange();
|
|
}
|
|
if (rng.setStart && rng.startContainer.nodeType === 9 && rng.collapsed) {
|
|
elm = dom.getRoot();
|
|
rng.setStart(elm, 0);
|
|
rng.setEnd(elm, 0);
|
|
}
|
|
if (selectedRange && explicitRange) {
|
|
if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
|
|
rng = explicitRange;
|
|
} else {
|
|
selectedRange = null;
|
|
explicitRange = null;
|
|
}
|
|
}
|
|
return rng;
|
|
};
|
|
var setRng = function (rng, forward) {
|
|
var sel, node, evt;
|
|
if (!isValidRange(rng)) {
|
|
return;
|
|
}
|
|
var ieRange = isNativeIeSelection(rng) ? rng : null;
|
|
if (ieRange) {
|
|
explicitRange = null;
|
|
try {
|
|
ieRange.select();
|
|
} catch (ex) {
|
|
}
|
|
return;
|
|
}
|
|
sel = getSel();
|
|
evt = editor.fire('SetSelectionRange', {
|
|
range: rng,
|
|
forward: forward
|
|
});
|
|
rng = evt.range;
|
|
if (sel) {
|
|
explicitRange = rng;
|
|
try {
|
|
sel.removeAllRanges();
|
|
sel.addRange(rng);
|
|
} catch (ex) {
|
|
}
|
|
if (forward === false && sel.extend) {
|
|
sel.collapse(rng.endContainer, rng.endOffset);
|
|
sel.extend(rng.startContainer, rng.startOffset);
|
|
}
|
|
selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
|
|
}
|
|
if (!rng.collapsed && rng.startContainer === rng.endContainer && sel.setBaseAndExtent && !Env.ie) {
|
|
if (rng.endOffset - rng.startOffset < 2) {
|
|
if (rng.startContainer.hasChildNodes()) {
|
|
node = rng.startContainer.childNodes[rng.startOffset];
|
|
if (node && node.tagName === 'IMG') {
|
|
sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
|
|
if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
|
|
sel.setBaseAndExtent(node, 0, node, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
editor.fire('AfterSetSelectionRange', {
|
|
range: rng,
|
|
forward: forward
|
|
});
|
|
};
|
|
var setNode = function (elm) {
|
|
setContent(dom.getOuterHTML(elm));
|
|
return elm;
|
|
};
|
|
var getNode = function () {
|
|
return getNode$1(editor.getBody(), getRng());
|
|
};
|
|
var getSelectedBlocks$1 = function (startElm, endElm) {
|
|
return getSelectedBlocks(dom, getRng(), startElm, endElm);
|
|
};
|
|
var isForward = function () {
|
|
var sel = getSel();
|
|
var anchorRange, focusRange;
|
|
if (!sel || !sel.anchorNode || !sel.focusNode) {
|
|
return true;
|
|
}
|
|
anchorRange = dom.createRng();
|
|
anchorRange.setStart(sel.anchorNode, sel.anchorOffset);
|
|
anchorRange.collapse(true);
|
|
focusRange = dom.createRng();
|
|
focusRange.setStart(sel.focusNode, sel.focusOffset);
|
|
focusRange.collapse(true);
|
|
return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
|
|
};
|
|
var normalize = function () {
|
|
var rng = getRng();
|
|
var sel = getSel();
|
|
if (!MultiRange.hasMultipleRanges(sel) && hasAnyRanges(editor)) {
|
|
var normRng = NormalizeRange.normalize(dom, rng);
|
|
normRng.each(function (normRng) {
|
|
setRng(normRng, isForward());
|
|
});
|
|
return normRng.getOr(rng);
|
|
}
|
|
return rng;
|
|
};
|
|
var selectorChanged = function (selector, callback) {
|
|
selectorChangedWithUnbind(selector, callback);
|
|
return exports;
|
|
};
|
|
var getScrollContainer = function () {
|
|
var scrollContainer;
|
|
var node = dom.getRoot();
|
|
while (node && node.nodeName !== 'BODY') {
|
|
if (node.scrollHeight > node.clientHeight) {
|
|
scrollContainer = node;
|
|
break;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return scrollContainer;
|
|
};
|
|
var scrollIntoView = function (elm, alignToTop) {
|
|
return ScrollIntoView.scrollElementIntoView(editor, elm, alignToTop);
|
|
};
|
|
var placeCaretAt = function (clientX, clientY) {
|
|
return setRng(CaretRangeFromPoint.fromPoint(clientX, clientY, editor.getDoc()));
|
|
};
|
|
var getBoundingClientRect = function () {
|
|
var rng = getRng();
|
|
return rng.collapsed ? CaretPosition$1.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
|
|
};
|
|
var destroy = function () {
|
|
win = selectedRange = explicitRange = null;
|
|
controlSelection.destroy();
|
|
};
|
|
var exports = {
|
|
bookmarkManager: null,
|
|
controlSelection: null,
|
|
dom: dom,
|
|
win: win,
|
|
serializer: serializer,
|
|
editor: editor,
|
|
collapse: collapse,
|
|
setCursorLocation: setCursorLocation,
|
|
getContent: getContent,
|
|
setContent: setContent,
|
|
getBookmark: getBookmark,
|
|
moveToBookmark: moveToBookmark,
|
|
select: select,
|
|
isCollapsed: isCollapsed,
|
|
isForward: isForward,
|
|
setNode: setNode,
|
|
getNode: getNode,
|
|
getSel: getSel,
|
|
setRng: setRng,
|
|
getRng: getRng,
|
|
getStart: getStart,
|
|
getEnd: getEnd$1,
|
|
getSelectedBlocks: getSelectedBlocks$1,
|
|
normalize: normalize,
|
|
selectorChanged: selectorChanged,
|
|
selectorChangedWithUnbind: selectorChangedWithUnbind,
|
|
getScrollContainer: getScrollContainer,
|
|
scrollIntoView: scrollIntoView,
|
|
placeCaretAt: placeCaretAt,
|
|
getBoundingClientRect: getBoundingClientRect,
|
|
destroy: destroy
|
|
};
|
|
bookmarkManager = BookmarkManager$1(exports);
|
|
controlSelection = ControlSelection(exports, editor);
|
|
exports.bookmarkManager = bookmarkManager;
|
|
exports.controlSelection = controlSelection;
|
|
return exports;
|
|
};
|
|
|
|
var isText$8 = NodeType.isText;
|
|
var startsWithCaretContainer$1 = function (node) {
|
|
return isText$8(node) && node.data[0] === Zwsp.ZWSP;
|
|
};
|
|
var endsWithCaretContainer$1 = function (node) {
|
|
return isText$8(node) && node.data[node.data.length - 1] === Zwsp.ZWSP;
|
|
};
|
|
var createZwsp = function (node) {
|
|
return node.ownerDocument.createTextNode(Zwsp.ZWSP);
|
|
};
|
|
var insertBefore = function (node) {
|
|
if (isText$8(node.previousSibling)) {
|
|
if (endsWithCaretContainer$1(node.previousSibling)) {
|
|
return node.previousSibling;
|
|
} else {
|
|
node.previousSibling.appendData(Zwsp.ZWSP);
|
|
return node.previousSibling;
|
|
}
|
|
} else if (isText$8(node)) {
|
|
if (startsWithCaretContainer$1(node)) {
|
|
return node;
|
|
} else {
|
|
node.insertData(0, Zwsp.ZWSP);
|
|
return node;
|
|
}
|
|
} else {
|
|
var newNode = createZwsp(node);
|
|
node.parentNode.insertBefore(newNode, node);
|
|
return newNode;
|
|
}
|
|
};
|
|
var insertAfter = function (node) {
|
|
if (isText$8(node.nextSibling)) {
|
|
if (startsWithCaretContainer$1(node.nextSibling)) {
|
|
return node.nextSibling;
|
|
} else {
|
|
node.nextSibling.insertData(0, Zwsp.ZWSP);
|
|
return node.nextSibling;
|
|
}
|
|
} else if (isText$8(node)) {
|
|
if (endsWithCaretContainer$1(node)) {
|
|
return node;
|
|
} else {
|
|
node.appendData(Zwsp.ZWSP);
|
|
return node;
|
|
}
|
|
} else {
|
|
var newNode = createZwsp(node);
|
|
if (node.nextSibling) {
|
|
node.parentNode.insertBefore(newNode, node.nextSibling);
|
|
} else {
|
|
node.parentNode.appendChild(newNode);
|
|
}
|
|
return newNode;
|
|
}
|
|
};
|
|
var insertInline$1 = function (before, node) {
|
|
return before ? insertBefore(node) : insertAfter(node);
|
|
};
|
|
var insertInlineBefore = curry(insertInline$1, true);
|
|
var insertInlineAfter = curry(insertInline$1, false);
|
|
|
|
var insertInlinePos = function (pos, before) {
|
|
if (NodeType.isText(pos.container())) {
|
|
return insertInline$1(before, pos.container());
|
|
} else {
|
|
return insertInline$1(before, pos.getNode());
|
|
}
|
|
};
|
|
var isPosCaretContainer = function (pos, caret) {
|
|
var caretNode = caret.get();
|
|
return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
|
|
};
|
|
var renderCaret = function (caret, location) {
|
|
return location.fold(function (element) {
|
|
CaretContainerRemove.remove(caret.get());
|
|
var text = insertInlineBefore(element);
|
|
caret.set(text);
|
|
return Option.some(CaretPosition$1(text, text.length - 1));
|
|
}, function (element) {
|
|
return CaretFinder.firstPositionIn(element).map(function (pos) {
|
|
if (!isPosCaretContainer(pos, caret)) {
|
|
CaretContainerRemove.remove(caret.get());
|
|
var text = insertInlinePos(pos, true);
|
|
caret.set(text);
|
|
return CaretPosition$1(text, 1);
|
|
} else {
|
|
return CaretPosition$1(caret.get(), 1);
|
|
}
|
|
});
|
|
}, function (element) {
|
|
return CaretFinder.lastPositionIn(element).map(function (pos) {
|
|
if (!isPosCaretContainer(pos, caret)) {
|
|
CaretContainerRemove.remove(caret.get());
|
|
var text = insertInlinePos(pos, false);
|
|
caret.set(text);
|
|
return CaretPosition$1(text, text.length - 1);
|
|
} else {
|
|
return CaretPosition$1(caret.get(), caret.get().length - 1);
|
|
}
|
|
});
|
|
}, function (element) {
|
|
CaretContainerRemove.remove(caret.get());
|
|
var text = insertInlineAfter(element);
|
|
caret.set(text);
|
|
return Option.some(CaretPosition$1(text, 1));
|
|
});
|
|
};
|
|
var BoundaryCaret = { renderCaret: renderCaret };
|
|
|
|
var strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
|
|
var hasStrongRtl = function (text) {
|
|
return strongRtl.test(text);
|
|
};
|
|
|
|
var isInlineTarget = function (editor, elm) {
|
|
return is(Element.fromDom(elm), Settings.getInlineBoundarySelector(editor));
|
|
};
|
|
var isRtl$1 = function (element) {
|
|
return DOMUtils$1.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl(element.textContent);
|
|
};
|
|
var findInlineParents = function (isInlineTarget, rootNode, pos) {
|
|
return filter(DOMUtils$1.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
|
|
};
|
|
var findRootInline = function (isInlineTarget, rootNode, pos) {
|
|
var parents = findInlineParents(isInlineTarget, rootNode, pos);
|
|
return Option.from(parents[parents.length - 1]);
|
|
};
|
|
var hasSameParentBlock = function (rootNode, node1, node2) {
|
|
var block1 = getParentBlock(node1, rootNode);
|
|
var block2 = getParentBlock(node2, rootNode);
|
|
return block1 && block1 === block2;
|
|
};
|
|
var isAtZwsp = function (pos) {
|
|
return isBeforeInline(pos) || isAfterInline(pos);
|
|
};
|
|
var normalizePosition = function (forward, pos) {
|
|
if (!pos) {
|
|
return pos;
|
|
}
|
|
var container = pos.container(), offset = pos.offset();
|
|
if (forward) {
|
|
if (isCaretContainerInline(container)) {
|
|
if (NodeType.isText(container.nextSibling)) {
|
|
return CaretPosition$1(container.nextSibling, 0);
|
|
} else {
|
|
return CaretPosition$1.after(container);
|
|
}
|
|
} else {
|
|
return isBeforeInline(pos) ? CaretPosition$1(container, offset + 1) : pos;
|
|
}
|
|
} else {
|
|
if (isCaretContainerInline(container)) {
|
|
if (NodeType.isText(container.previousSibling)) {
|
|
return CaretPosition$1(container.previousSibling, container.previousSibling.data.length);
|
|
} else {
|
|
return CaretPosition$1.before(container);
|
|
}
|
|
} else {
|
|
return isAfterInline(pos) ? CaretPosition$1(container, offset - 1) : pos;
|
|
}
|
|
}
|
|
};
|
|
var normalizeForwards = curry(normalizePosition, true);
|
|
var normalizeBackwards = curry(normalizePosition, false);
|
|
var InlineUtils = {
|
|
isInlineTarget: isInlineTarget,
|
|
findRootInline: findRootInline,
|
|
isRtl: isRtl$1,
|
|
isAtZwsp: isAtZwsp,
|
|
normalizePosition: normalizePosition,
|
|
normalizeForwards: normalizeForwards,
|
|
normalizeBackwards: normalizeBackwards,
|
|
hasSameParentBlock: hasSameParentBlock
|
|
};
|
|
|
|
var evaluateUntil = function (fns, args) {
|
|
for (var i = 0; i < fns.length; i++) {
|
|
var result = fns[i].apply(null, args);
|
|
if (result.isSome()) {
|
|
return result;
|
|
}
|
|
}
|
|
return Option.none();
|
|
};
|
|
var LazyEvaluator = { evaluateUntil: evaluateUntil };
|
|
|
|
var Location = Adt.generate([
|
|
{ before: ['element'] },
|
|
{ start: ['element'] },
|
|
{ end: ['element'] },
|
|
{ after: ['element'] }
|
|
]);
|
|
var rescope = function (rootNode, node) {
|
|
var parentBlock = getParentBlock(node, rootNode);
|
|
return parentBlock ? parentBlock : rootNode;
|
|
};
|
|
var before$4 = function (isInlineTarget, rootNode, pos) {
|
|
var nPos = InlineUtils.normalizeForwards(pos);
|
|
var scope = rescope(rootNode, nPos.container());
|
|
return InlineUtils.findRootInline(isInlineTarget, scope, nPos).fold(function () {
|
|
return CaretFinder.nextPosition(scope, nPos).bind(curry(InlineUtils.findRootInline, isInlineTarget, scope)).map(function (inline) {
|
|
return Location.before(inline);
|
|
});
|
|
}, Option.none);
|
|
};
|
|
var isNotInsideFormatCaretContainer = function (rootNode, elm) {
|
|
return getParentCaretContainer(rootNode, elm) === null;
|
|
};
|
|
var findInsideRootInline = function (isInlineTarget, rootNode, pos) {
|
|
return InlineUtils.findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
|
|
};
|
|
var start$1 = function (isInlineTarget, rootNode, pos) {
|
|
var nPos = InlineUtils.normalizeBackwards(pos);
|
|
return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(function (inline) {
|
|
var prevPos = CaretFinder.prevPosition(inline, nPos);
|
|
return prevPos.isNone() ? Option.some(Location.start(inline)) : Option.none();
|
|
});
|
|
};
|
|
var end = function (isInlineTarget, rootNode, pos) {
|
|
var nPos = InlineUtils.normalizeForwards(pos);
|
|
return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(function (inline) {
|
|
var nextPos = CaretFinder.nextPosition(inline, nPos);
|
|
return nextPos.isNone() ? Option.some(Location.end(inline)) : Option.none();
|
|
});
|
|
};
|
|
var after$3 = function (isInlineTarget, rootNode, pos) {
|
|
var nPos = InlineUtils.normalizeBackwards(pos);
|
|
var scope = rescope(rootNode, nPos.container());
|
|
return InlineUtils.findRootInline(isInlineTarget, scope, nPos).fold(function () {
|
|
return CaretFinder.prevPosition(scope, nPos).bind(curry(InlineUtils.findRootInline, isInlineTarget, scope)).map(function (inline) {
|
|
return Location.after(inline);
|
|
});
|
|
}, Option.none);
|
|
};
|
|
var isValidLocation = function (location) {
|
|
return InlineUtils.isRtl(getElement(location)) === false;
|
|
};
|
|
var readLocation = function (isInlineTarget, rootNode, pos) {
|
|
var location = LazyEvaluator.evaluateUntil([
|
|
before$4,
|
|
start$1,
|
|
end,
|
|
after$3
|
|
], [
|
|
isInlineTarget,
|
|
rootNode,
|
|
pos
|
|
]);
|
|
return location.filter(isValidLocation);
|
|
};
|
|
var getElement = function (location) {
|
|
return location.fold(identity, identity, identity, identity);
|
|
};
|
|
var getName = function (location) {
|
|
return location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
|
|
};
|
|
var outside = function (location) {
|
|
return location.fold(Location.before, Location.before, Location.after, Location.after);
|
|
};
|
|
var inside = function (location) {
|
|
return location.fold(Location.start, Location.start, Location.end, Location.end);
|
|
};
|
|
var isEq$5 = function (location1, location2) {
|
|
return getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
|
|
};
|
|
var betweenInlines = function (forward, isInlineTarget, rootNode, from, to, location) {
|
|
return lift2(InlineUtils.findRootInline(isInlineTarget, rootNode, from), InlineUtils.findRootInline(isInlineTarget, rootNode, to), function (fromInline, toInline) {
|
|
if (fromInline !== toInline && InlineUtils.hasSameParentBlock(rootNode, fromInline, toInline)) {
|
|
return Location.after(forward ? fromInline : toInline);
|
|
} else {
|
|
return location;
|
|
}
|
|
}).getOr(location);
|
|
};
|
|
var skipNoMovement = function (fromLocation, toLocation) {
|
|
return fromLocation.fold(constant(true), function (fromLocation) {
|
|
return !isEq$5(fromLocation, toLocation);
|
|
});
|
|
};
|
|
var findLocationTraverse = function (forward, isInlineTarget, rootNode, fromLocation, pos) {
|
|
var from = InlineUtils.normalizePosition(forward, pos);
|
|
var to = CaretFinder.fromPosition(forward, rootNode, from).map(curry(InlineUtils.normalizePosition, forward));
|
|
var location = to.fold(function () {
|
|
return fromLocation.map(outside);
|
|
}, function (to) {
|
|
return readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation));
|
|
});
|
|
return location.filter(isValidLocation);
|
|
};
|
|
var findLocationSimple = function (forward, location) {
|
|
if (forward) {
|
|
return location.fold(compose(Option.some, Location.start), Option.none, compose(Option.some, Location.after), Option.none);
|
|
} else {
|
|
return location.fold(Option.none, compose(Option.some, Location.before), Option.none, compose(Option.some, Location.end));
|
|
}
|
|
};
|
|
var findLocation = function (forward, isInlineTarget, rootNode, pos) {
|
|
var from = InlineUtils.normalizePosition(forward, pos);
|
|
var fromLocation = readLocation(isInlineTarget, rootNode, from);
|
|
return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(function () {
|
|
return findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos);
|
|
});
|
|
};
|
|
var BoundaryLocation = {
|
|
readLocation: readLocation,
|
|
findLocation: findLocation,
|
|
prevLocation: curry(findLocation, false),
|
|
nextLocation: curry(findLocation, true),
|
|
getElement: getElement,
|
|
outside: outside,
|
|
inside: inside
|
|
};
|
|
|
|
var hasSelectionModifyApi = function (editor) {
|
|
return isFunction(editor.selection.getSel().modify);
|
|
};
|
|
var moveRel = function (forward, selection, pos) {
|
|
var delta = forward ? 1 : -1;
|
|
selection.setRng(CaretPosition$1(pos.container(), pos.offset() + delta).toRange());
|
|
selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
|
|
return true;
|
|
};
|
|
var moveByWord = function (forward, editor) {
|
|
var rng = editor.selection.getRng();
|
|
var pos = forward ? CaretPosition$1.fromRangeEnd(rng) : CaretPosition$1.fromRangeStart(rng);
|
|
if (!hasSelectionModifyApi(editor)) {
|
|
return false;
|
|
} else if (forward && isBeforeInline(pos)) {
|
|
return moveRel(true, editor.selection, pos);
|
|
} else if (!forward && isAfterInline(pos)) {
|
|
return moveRel(false, editor.selection, pos);
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var WordSelection = {
|
|
hasSelectionModifyApi: hasSelectionModifyApi,
|
|
moveByWord: moveByWord
|
|
};
|
|
|
|
var setCaretPosition = function (editor, pos) {
|
|
var rng = editor.dom.createRng();
|
|
rng.setStart(pos.container(), pos.offset());
|
|
rng.setEnd(pos.container(), pos.offset());
|
|
editor.selection.setRng(rng);
|
|
};
|
|
var isFeatureEnabled = function (editor) {
|
|
return editor.settings.inline_boundaries !== false;
|
|
};
|
|
var setSelected = function (state, elm) {
|
|
if (state) {
|
|
elm.setAttribute('data-mce-selected', 'inline-boundary');
|
|
} else {
|
|
elm.removeAttribute('data-mce-selected');
|
|
}
|
|
};
|
|
var renderCaretLocation = function (editor, caret, location) {
|
|
return BoundaryCaret.renderCaret(caret, location).map(function (pos) {
|
|
setCaretPosition(editor, pos);
|
|
return location;
|
|
});
|
|
};
|
|
var findLocation$1 = function (editor, caret, forward) {
|
|
var rootNode = editor.getBody();
|
|
var from = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
var isInlineTarget = curry(InlineUtils.isInlineTarget, editor);
|
|
var location = BoundaryLocation.findLocation(forward, isInlineTarget, rootNode, from);
|
|
return location.bind(function (location) {
|
|
return renderCaretLocation(editor, caret, location);
|
|
});
|
|
};
|
|
var toggleInlines = function (isInlineTarget, dom, elms) {
|
|
var selectedInlines = filter(dom.select('*[data-mce-selected="inline-boundary"]'), isInlineTarget);
|
|
var targetInlines = filter(elms, isInlineTarget);
|
|
each(difference(selectedInlines, targetInlines), curry(setSelected, false));
|
|
each(difference(targetInlines, selectedInlines), curry(setSelected, true));
|
|
};
|
|
var safeRemoveCaretContainer = function (editor, caret) {
|
|
if (editor.selection.isCollapsed() && editor.composing !== true && caret.get()) {
|
|
var pos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
if (CaretPosition$1.isTextPosition(pos) && InlineUtils.isAtZwsp(pos) === false) {
|
|
setCaretPosition(editor, CaretContainerRemove.removeAndReposition(caret.get(), pos));
|
|
caret.set(null);
|
|
}
|
|
}
|
|
};
|
|
var renderInsideInlineCaret = function (isInlineTarget, editor, caret, elms) {
|
|
if (editor.selection.isCollapsed()) {
|
|
var inlines = filter(elms, isInlineTarget);
|
|
each(inlines, function (inline) {
|
|
var pos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
BoundaryLocation.readLocation(isInlineTarget, editor.getBody(), pos).bind(function (location) {
|
|
return renderCaretLocation(editor, caret, location);
|
|
});
|
|
});
|
|
}
|
|
};
|
|
var move$1 = function (editor, caret, forward) {
|
|
return function () {
|
|
return isFeatureEnabled(editor) ? findLocation$1(editor, caret, forward).isSome() : false;
|
|
};
|
|
};
|
|
var moveWord = function (forward, editor, caret) {
|
|
return function () {
|
|
return isFeatureEnabled(editor) ? WordSelection.moveByWord(forward, editor) : false;
|
|
};
|
|
};
|
|
var setupSelectedState = function (editor) {
|
|
var caret = Cell(null);
|
|
var isInlineTarget = curry(InlineUtils.isInlineTarget, editor);
|
|
editor.on('NodeChange', function (e) {
|
|
if (isFeatureEnabled(editor)) {
|
|
toggleInlines(isInlineTarget, editor.dom, e.parents);
|
|
safeRemoveCaretContainer(editor, caret);
|
|
renderInsideInlineCaret(isInlineTarget, editor, caret, e.parents);
|
|
}
|
|
});
|
|
return caret;
|
|
};
|
|
var moveNextWord = curry(moveWord, true);
|
|
var movePrevWord = curry(moveWord, false);
|
|
var BoundarySelection = {
|
|
move: move$1,
|
|
moveNextWord: moveNextWord,
|
|
movePrevWord: movePrevWord,
|
|
setupSelectedState: setupSelectedState,
|
|
setCaretPosition: setCaretPosition
|
|
};
|
|
|
|
var BreakType;
|
|
(function (BreakType) {
|
|
BreakType[BreakType['Br'] = 0] = 'Br';
|
|
BreakType[BreakType['Block'] = 1] = 'Block';
|
|
BreakType[BreakType['Wrap'] = 2] = 'Wrap';
|
|
BreakType[BreakType['Eol'] = 3] = 'Eol';
|
|
}(BreakType || (BreakType = {})));
|
|
var flip = function (direction, positions) {
|
|
return direction === HDirection.Backwards ? positions.reverse() : positions;
|
|
};
|
|
var walk$3 = function (direction, caretWalker, pos) {
|
|
return direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
|
|
};
|
|
var getBreakType = function (scope, direction, currentPos, nextPos) {
|
|
if (NodeType.isBr(nextPos.getNode(direction === HDirection.Forwards))) {
|
|
return BreakType.Br;
|
|
} else if (isInSameBlock(currentPos, nextPos) === false) {
|
|
return BreakType.Block;
|
|
} else {
|
|
return BreakType.Wrap;
|
|
}
|
|
};
|
|
var getPositionsUntil = function (predicate, direction, scope, start) {
|
|
var caretWalker = CaretWalker(scope);
|
|
var currentPos = start, nextPos;
|
|
var positions = [];
|
|
while (currentPos) {
|
|
nextPos = walk$3(direction, caretWalker, currentPos);
|
|
if (!nextPos) {
|
|
break;
|
|
}
|
|
if (NodeType.isBr(nextPos.getNode(false))) {
|
|
if (direction === HDirection.Forwards) {
|
|
return {
|
|
positions: flip(direction, positions).concat([nextPos]),
|
|
breakType: BreakType.Br,
|
|
breakAt: Option.some(nextPos)
|
|
};
|
|
} else {
|
|
return {
|
|
positions: flip(direction, positions),
|
|
breakType: BreakType.Br,
|
|
breakAt: Option.some(nextPos)
|
|
};
|
|
}
|
|
}
|
|
if (!nextPos.isVisible()) {
|
|
currentPos = nextPos;
|
|
continue;
|
|
}
|
|
if (predicate(currentPos, nextPos)) {
|
|
var breakType = getBreakType(scope, direction, currentPos, nextPos);
|
|
return {
|
|
positions: flip(direction, positions),
|
|
breakType: breakType,
|
|
breakAt: Option.some(nextPos)
|
|
};
|
|
}
|
|
positions.push(nextPos);
|
|
currentPos = nextPos;
|
|
}
|
|
return {
|
|
positions: flip(direction, positions),
|
|
breakType: BreakType.Eol,
|
|
breakAt: Option.none()
|
|
};
|
|
};
|
|
var getAdjacentLinePositions = function (direction, getPositionsUntilBreak, scope, start) {
|
|
return getPositionsUntilBreak(scope, start).breakAt.map(function (pos) {
|
|
var positions = getPositionsUntilBreak(scope, pos).positions;
|
|
return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
|
|
}).getOr([]);
|
|
};
|
|
var findClosestHorizontalPositionFromPoint = function (positions, x) {
|
|
return foldl(positions, function (acc, newPos) {
|
|
return acc.fold(function () {
|
|
return Option.some(newPos);
|
|
}, function (lastPos) {
|
|
return lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), function (lastRect, newRect) {
|
|
var lastDist = Math.abs(x - lastRect.left);
|
|
var newDist = Math.abs(x - newRect.left);
|
|
return newDist <= lastDist ? newPos : lastPos;
|
|
}).or(acc);
|
|
});
|
|
}, Option.none());
|
|
};
|
|
var findClosestHorizontalPosition = function (positions, pos) {
|
|
return head(pos.getClientRects()).bind(function (targetRect) {
|
|
return findClosestHorizontalPositionFromPoint(positions, targetRect.left);
|
|
});
|
|
};
|
|
var getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
|
|
var getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
|
|
var isAtFirstLine = function (scope, pos) {
|
|
return getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
|
|
};
|
|
var isAtLastLine = function (scope, pos) {
|
|
return getPositionsUntilNextLine(scope, pos).breakAt.isNone();
|
|
};
|
|
var getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
|
|
var getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
|
|
var getFirstLinePositions = function (scope) {
|
|
return CaretFinder.firstPositionIn(scope).map(function (pos) {
|
|
return [pos].concat(getPositionsUntilNextLine(scope, pos).positions);
|
|
}).getOr([]);
|
|
};
|
|
var getLastLinePositions = function (scope) {
|
|
return CaretFinder.lastPositionIn(scope).map(function (pos) {
|
|
return getPositionsUntilPreviousLine(scope, pos).positions.concat(pos);
|
|
}).getOr([]);
|
|
};
|
|
|
|
var isContentEditableFalse$b = NodeType.isContentEditableFalse;
|
|
var getSelectedNode$1 = getSelectedNode;
|
|
var moveToCeFalseHorizontally = function (direction, editor, getNextPosFn, range) {
|
|
var forwards = direction === HDirection.Forwards;
|
|
var isBeforeContentEditableFalseFn = forwards ? isBeforeContentEditableFalse : isAfterContentEditableFalse;
|
|
if (!range.collapsed) {
|
|
var node = getSelectedNode$1(range);
|
|
if (isContentEditableFalse$b(node)) {
|
|
return showCaret(direction, editor, node, direction === HDirection.Backwards, true);
|
|
}
|
|
}
|
|
var rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
|
|
var caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
|
if (isBeforeContentEditableFalseFn(caretPosition)) {
|
|
return selectNode(editor, caretPosition.getNode(!forwards));
|
|
}
|
|
var nextCaretPosition = InlineUtils.normalizePosition(forwards, getNextPosFn(caretPosition));
|
|
if (!nextCaretPosition) {
|
|
if (rangeIsInContainerBlock) {
|
|
return range;
|
|
}
|
|
return null;
|
|
}
|
|
if (isBeforeContentEditableFalseFn(nextCaretPosition)) {
|
|
return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, true);
|
|
}
|
|
var peekCaretPosition = getNextPosFn(nextCaretPosition);
|
|
if (peekCaretPosition && isBeforeContentEditableFalseFn(peekCaretPosition)) {
|
|
if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
|
|
return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, true);
|
|
}
|
|
}
|
|
if (rangeIsInContainerBlock) {
|
|
return renderRangeCaret(editor, nextCaretPosition.toRange(), true);
|
|
}
|
|
return null;
|
|
};
|
|
var moveToCeFalseVertically = function (direction, editor, walkerFn, range) {
|
|
var caretPosition, linePositions, nextLinePositions;
|
|
var closestNextLineRect, caretClientRect, clientX;
|
|
var dist1, dist2, contentEditableFalseNode;
|
|
contentEditableFalseNode = getSelectedNode$1(range);
|
|
caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
|
linePositions = walkerFn(editor.getBody(), isAboveLine(1), caretPosition);
|
|
nextLinePositions = filter(linePositions, isLine(1));
|
|
caretClientRect = ArrUtils.last(caretPosition.getClientRects());
|
|
if (isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition)) {
|
|
contentEditableFalseNode = caretPosition.getNode();
|
|
}
|
|
if (isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition)) {
|
|
contentEditableFalseNode = caretPosition.getNode(true);
|
|
}
|
|
if (!caretClientRect) {
|
|
return null;
|
|
}
|
|
clientX = caretClientRect.left;
|
|
closestNextLineRect = findClosestClientRect(nextLinePositions, clientX);
|
|
if (closestNextLineRect) {
|
|
if (isContentEditableFalse$b(closestNextLineRect.node)) {
|
|
dist1 = Math.abs(clientX - closestNextLineRect.left);
|
|
dist2 = Math.abs(clientX - closestNextLineRect.right);
|
|
return showCaret(direction, editor, closestNextLineRect.node, dist1 < dist2, true);
|
|
}
|
|
}
|
|
if (contentEditableFalseNode) {
|
|
var caretPositions = positionsUntil(direction, editor.getBody(), isAboveLine(1), contentEditableFalseNode);
|
|
closestNextLineRect = findClosestClientRect(filter(caretPositions, isLine(1)), clientX);
|
|
if (closestNextLineRect) {
|
|
return renderRangeCaret(editor, closestNextLineRect.position.toRange(), true);
|
|
}
|
|
closestNextLineRect = ArrUtils.last(filter(caretPositions, isLine(0)));
|
|
if (closestNextLineRect) {
|
|
return renderRangeCaret(editor, closestNextLineRect.position.toRange(), true);
|
|
}
|
|
}
|
|
};
|
|
var createTextBlock = function (editor) {
|
|
var textBlock = editor.dom.create(Settings.getForcedRootBlock(editor));
|
|
if (!Env.ie || Env.ie >= 11) {
|
|
textBlock.innerHTML = '<br data-mce-bogus="1">';
|
|
}
|
|
return textBlock;
|
|
};
|
|
var exitPreBlock = function (editor, direction, range) {
|
|
var pre, caretPos, newBlock;
|
|
var caretWalker = CaretWalker(editor.getBody());
|
|
var getNextVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.next);
|
|
var getPrevVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.prev);
|
|
if (range.collapsed && editor.settings.forced_root_block) {
|
|
pre = editor.dom.getParent(range.startContainer, 'PRE');
|
|
if (!pre) {
|
|
return;
|
|
}
|
|
if (direction === 1) {
|
|
caretPos = getNextVisualCaretPosition(CaretPosition$1.fromRangeStart(range));
|
|
} else {
|
|
caretPos = getPrevVisualCaretPosition(CaretPosition$1.fromRangeStart(range));
|
|
}
|
|
if (!caretPos) {
|
|
newBlock = createTextBlock(editor);
|
|
if (direction === 1) {
|
|
editor.$(pre).after(newBlock);
|
|
} else {
|
|
editor.$(pre).before(newBlock);
|
|
}
|
|
editor.selection.select(newBlock, true);
|
|
editor.selection.collapse();
|
|
}
|
|
}
|
|
};
|
|
var getHorizontalRange = function (editor, forward) {
|
|
var caretWalker = CaretWalker(editor.getBody());
|
|
var getNextVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.next);
|
|
var getPrevVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.prev);
|
|
var newRange;
|
|
var direction = forward ? HDirection.Forwards : HDirection.Backwards;
|
|
var getNextPosFn = forward ? getNextVisualCaretPosition : getPrevVisualCaretPosition;
|
|
var range = editor.selection.getRng();
|
|
newRange = moveToCeFalseHorizontally(direction, editor, getNextPosFn, range);
|
|
if (newRange) {
|
|
return newRange;
|
|
}
|
|
newRange = exitPreBlock(editor, direction, range);
|
|
if (newRange) {
|
|
return newRange;
|
|
}
|
|
return null;
|
|
};
|
|
var getVerticalRange = function (editor, down) {
|
|
var newRange;
|
|
var direction = down ? 1 : -1;
|
|
var walkerFn = down ? downUntil : upUntil;
|
|
var range = editor.selection.getRng();
|
|
newRange = moveToCeFalseVertically(direction, editor, walkerFn, range);
|
|
if (newRange) {
|
|
return newRange;
|
|
}
|
|
newRange = exitPreBlock(editor, direction, range);
|
|
if (newRange) {
|
|
return newRange;
|
|
}
|
|
return null;
|
|
};
|
|
var moveH = function (editor, forward) {
|
|
return function () {
|
|
var newRng = getHorizontalRange(editor, forward);
|
|
if (newRng) {
|
|
editor.selection.setRng(newRng);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
};
|
|
var moveV = function (editor, down) {
|
|
return function () {
|
|
var newRng = getVerticalRange(editor, down);
|
|
if (newRng) {
|
|
editor.selection.setRng(newRng);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
};
|
|
var isCefPosition = function (forward) {
|
|
return function (pos) {
|
|
return forward ? isAfterContentEditableFalse(pos) : isBeforeContentEditableFalse(pos);
|
|
};
|
|
};
|
|
var moveToLineEndPoint = function (editor, forward) {
|
|
return function () {
|
|
var from = forward ? CaretPosition$1.fromRangeEnd(editor.selection.getRng()) : CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
var result = forward ? getPositionsUntilNextLine(editor.getBody(), from) : getPositionsUntilPreviousLine(editor.getBody(), from);
|
|
var to = forward ? last(result.positions) : head(result.positions);
|
|
return to.filter(isCefPosition(forward)).fold(constant(false), function (pos) {
|
|
editor.selection.setRng(pos.toRange());
|
|
return true;
|
|
});
|
|
};
|
|
};
|
|
|
|
var deflate = function (rect, delta) {
|
|
return {
|
|
left: rect.left - delta,
|
|
top: rect.top - delta,
|
|
right: rect.right + delta * 2,
|
|
bottom: rect.bottom + delta * 2,
|
|
width: rect.width + delta,
|
|
height: rect.height + delta
|
|
};
|
|
};
|
|
var getCorners = function (getYAxisValue, tds) {
|
|
return bind(tds, function (td) {
|
|
var rect = deflate(clone$1(td.getBoundingClientRect()), -1);
|
|
return [
|
|
{
|
|
x: rect.left,
|
|
y: getYAxisValue(rect),
|
|
cell: td
|
|
},
|
|
{
|
|
x: rect.right,
|
|
y: getYAxisValue(rect),
|
|
cell: td
|
|
}
|
|
];
|
|
});
|
|
};
|
|
var findClosestCorner = function (corners, x, y) {
|
|
return foldl(corners, function (acc, newCorner) {
|
|
return acc.fold(function () {
|
|
return Option.some(newCorner);
|
|
}, function (oldCorner) {
|
|
var oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
|
|
var newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
|
|
return Option.some(newDist < oldDist ? newCorner : oldCorner);
|
|
});
|
|
}, Option.none());
|
|
};
|
|
var getClosestCell = function (getYAxisValue, isTargetCorner, table, x, y) {
|
|
var cells = descendants$1(Element.fromDom(table), 'td,th,caption').map(function (e) {
|
|
return e.dom();
|
|
});
|
|
var corners = filter(getCorners(getYAxisValue, cells), function (corner) {
|
|
return isTargetCorner(corner, y);
|
|
});
|
|
return findClosestCorner(corners, x, y).map(function (corner) {
|
|
return corner.cell;
|
|
});
|
|
};
|
|
var getBottomValue = function (rect) {
|
|
return rect.bottom;
|
|
};
|
|
var getTopValue = function (rect) {
|
|
return rect.top;
|
|
};
|
|
var isAbove$1 = function (corner, y) {
|
|
return corner.y < y;
|
|
};
|
|
var isBelow$1 = function (corner, y) {
|
|
return corner.y > y;
|
|
};
|
|
var getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove$1);
|
|
var getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow$1);
|
|
var findClosestPositionInAboveCell = function (table, pos) {
|
|
return head(pos.getClientRects()).bind(function (rect) {
|
|
return getClosestCellAbove(table, rect.left, rect.top);
|
|
}).bind(function (cell) {
|
|
return findClosestHorizontalPosition(getLastLinePositions(cell), pos);
|
|
});
|
|
};
|
|
var findClosestPositionInBelowCell = function (table, pos) {
|
|
return last(pos.getClientRects()).bind(function (rect) {
|
|
return getClosestCellBelow(table, rect.left, rect.top);
|
|
}).bind(function (cell) {
|
|
return findClosestHorizontalPosition(getFirstLinePositions(cell), pos);
|
|
});
|
|
};
|
|
|
|
var moveToRange = function (editor, rng) {
|
|
editor.selection.setRng(rng);
|
|
ScrollIntoView.scrollRangeIntoView(editor, rng);
|
|
};
|
|
var hasNextBreak = function (getPositionsUntil, scope, lineInfo) {
|
|
return lineInfo.breakAt.map(function (breakPos) {
|
|
return getPositionsUntil(scope, breakPos).breakAt.isSome();
|
|
}).getOr(false);
|
|
};
|
|
var startsWithWrapBreak = function (lineInfo) {
|
|
return lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
|
|
};
|
|
var startsWithBrBreak = function (lineInfo) {
|
|
return lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
|
|
};
|
|
var isAtTableCellLine = function (getPositionsUntil, scope, pos) {
|
|
var lineInfo = getPositionsUntil(scope, pos);
|
|
if (startsWithWrapBreak(lineInfo) || !NodeType.isBr(pos.getNode()) && startsWithBrBreak(lineInfo)) {
|
|
return !hasNextBreak(getPositionsUntil, scope, lineInfo);
|
|
} else {
|
|
return lineInfo.breakAt.isNone();
|
|
}
|
|
};
|
|
var isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
|
|
var isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
|
|
var isCaretAtStartOrEndOfTable = function (forward, rng, table) {
|
|
var caretPos = CaretPosition$1.fromRangeStart(rng);
|
|
return CaretFinder.positionIn(!forward, table).map(function (pos) {
|
|
return pos.isEqual(caretPos);
|
|
}).getOr(false);
|
|
};
|
|
var navigateHorizontally = function (editor, forward, table, td) {
|
|
var rng = editor.selection.getRng();
|
|
var direction = forward ? 1 : -1;
|
|
if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
|
|
var newRng = showCaret(direction, editor, table, !forward, true);
|
|
moveToRange(editor, newRng);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
var getClosestAbovePosition = function (root, table, start) {
|
|
return findClosestPositionInAboveCell(table, start).orThunk(function () {
|
|
return head(start.getClientRects()).bind(function (rect) {
|
|
return findClosestHorizontalPositionFromPoint(getPositionsAbove(root, CaretPosition$1.before(table)), rect.left);
|
|
});
|
|
}).getOr(CaretPosition$1.before(table));
|
|
};
|
|
var getClosestBelowPosition = function (root, table, start) {
|
|
return findClosestPositionInBelowCell(table, start).orThunk(function () {
|
|
return head(start.getClientRects()).bind(function (rect) {
|
|
return findClosestHorizontalPositionFromPoint(getPositionsBelow(root, CaretPosition$1.after(table)), rect.left);
|
|
});
|
|
}).getOr(CaretPosition$1.after(table));
|
|
};
|
|
var getTable = function (previous, pos) {
|
|
var node = pos.getNode(previous);
|
|
return NodeType.isElement(node) && node.nodeName === 'TABLE' ? Option.some(node) : Option.none();
|
|
};
|
|
var renderBlock = function (down, editor, table, pos) {
|
|
var forcedRootBlock = Settings.getForcedRootBlock(editor);
|
|
if (forcedRootBlock) {
|
|
editor.undoManager.transact(function () {
|
|
var element = Element.fromTag(forcedRootBlock);
|
|
setAll(element, Settings.getForcedRootBlockAttrs(editor));
|
|
append(element, Element.fromTag('br'));
|
|
if (down) {
|
|
after(Element.fromDom(table), element);
|
|
} else {
|
|
before(Element.fromDom(table), element);
|
|
}
|
|
var rng = editor.dom.createRng();
|
|
rng.setStart(element.dom(), 0);
|
|
rng.setEnd(element.dom(), 0);
|
|
moveToRange(editor, rng);
|
|
});
|
|
} else {
|
|
moveToRange(editor, pos.toRange());
|
|
}
|
|
};
|
|
var moveCaret = function (editor, down, pos) {
|
|
var table = down ? getTable(true, pos) : getTable(false, pos);
|
|
var last = down === false;
|
|
table.fold(function () {
|
|
return moveToRange(editor, pos.toRange());
|
|
}, function (table) {
|
|
return CaretFinder.positionIn(last, editor.getBody()).filter(function (lastPos) {
|
|
return lastPos.isEqual(pos);
|
|
}).fold(function () {
|
|
return moveToRange(editor, pos.toRange());
|
|
}, function (_) {
|
|
return renderBlock(down, editor, table, pos);
|
|
});
|
|
});
|
|
};
|
|
var navigateVertically = function (editor, down, table, td) {
|
|
var rng = editor.selection.getRng();
|
|
var pos = CaretPosition$1.fromRangeStart(rng);
|
|
var root = editor.getBody();
|
|
if (!down && isAtFirstTableCellLine(td, pos)) {
|
|
var newPos = getClosestAbovePosition(root, table, pos);
|
|
moveCaret(editor, down, newPos);
|
|
return true;
|
|
} else if (down && isAtLastTableCellLine(td, pos)) {
|
|
var newPos = getClosestBelowPosition(root, table, pos);
|
|
moveCaret(editor, down, newPos);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var moveH$1 = function (editor, forward) {
|
|
return function () {
|
|
return Option.from(editor.dom.getParent(editor.selection.getNode(), 'td,th')).bind(function (td) {
|
|
return Option.from(editor.dom.getParent(td, 'table')).map(function (table) {
|
|
return navigateHorizontally(editor, forward, table);
|
|
});
|
|
}).getOr(false);
|
|
};
|
|
};
|
|
var moveV$1 = function (editor, forward) {
|
|
return function () {
|
|
return Option.from(editor.dom.getParent(editor.selection.getNode(), 'td,th')).bind(function (td) {
|
|
return Option.from(editor.dom.getParent(td, 'table')).map(function (table) {
|
|
return navigateVertically(editor, forward, table, td);
|
|
});
|
|
}).getOr(false);
|
|
};
|
|
};
|
|
|
|
var isTarget = function (node) {
|
|
return contains(['figcaption'], name(node));
|
|
};
|
|
var rangeBefore = function (target) {
|
|
var rng = domGlobals.document.createRange();
|
|
rng.setStartBefore(target.dom());
|
|
rng.setEndBefore(target.dom());
|
|
return rng;
|
|
};
|
|
var insertElement = function (root, elm, forward) {
|
|
if (forward) {
|
|
append(root, elm);
|
|
} else {
|
|
prepend(root, elm);
|
|
}
|
|
};
|
|
var insertBr = function (root, forward) {
|
|
var br = Element.fromTag('br');
|
|
insertElement(root, br, forward);
|
|
return rangeBefore(br);
|
|
};
|
|
var insertBlock$1 = function (root, forward, blockName, attrs) {
|
|
var block = Element.fromTag(blockName);
|
|
var br = Element.fromTag('br');
|
|
setAll(block, attrs);
|
|
append(block, br);
|
|
insertElement(root, block, forward);
|
|
return rangeBefore(br);
|
|
};
|
|
var insertEmptyLine = function (root, rootBlockName, attrs, forward) {
|
|
if (rootBlockName === '') {
|
|
return insertBr(root, forward);
|
|
} else {
|
|
return insertBlock$1(root, forward, rootBlockName, attrs);
|
|
}
|
|
};
|
|
var getClosestTargetBlock = function (pos, root) {
|
|
var isRoot = curry(eq, root);
|
|
return closest(Element.fromDom(pos.container()), isBlock, isRoot).filter(isTarget);
|
|
};
|
|
var isAtFirstOrLastLine = function (root, forward, pos) {
|
|
return forward ? isAtLastLine(root.dom(), pos) : isAtFirstLine(root.dom(), pos);
|
|
};
|
|
var moveCaretToNewEmptyLine = function (editor, forward) {
|
|
var root = Element.fromDom(editor.getBody());
|
|
var pos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
var rootBlock = Settings.getForcedRootBlock(editor);
|
|
var rootBlockAttrs = Settings.getForcedRootBlockAttrs(editor);
|
|
return getClosestTargetBlock(pos, root).exists(function () {
|
|
if (isAtFirstOrLastLine(root, forward, pos)) {
|
|
var rng = insertEmptyLine(root, rootBlock, rootBlockAttrs, forward);
|
|
editor.selection.setRng(rng);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
});
|
|
};
|
|
var moveV$2 = function (editor, forward) {
|
|
return function () {
|
|
if (editor.selection.isCollapsed()) {
|
|
return moveCaretToNewEmptyLine(editor, forward);
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
};
|
|
|
|
var defaultPatterns = function (patterns) {
|
|
return map(patterns, function (pattern) {
|
|
return merge({
|
|
shiftKey: false,
|
|
altKey: false,
|
|
ctrlKey: false,
|
|
metaKey: false,
|
|
keyCode: 0,
|
|
action: noop
|
|
}, pattern);
|
|
});
|
|
};
|
|
var matchesEvent = function (pattern, evt) {
|
|
return evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
|
|
};
|
|
var match$1 = function (patterns, evt) {
|
|
return bind(defaultPatterns(patterns), function (pattern) {
|
|
return matchesEvent(pattern, evt) ? [pattern] : [];
|
|
});
|
|
};
|
|
var action = function (f) {
|
|
var x = [];
|
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
x[_i - 1] = arguments[_i];
|
|
}
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
return function () {
|
|
return f.apply(null, args);
|
|
};
|
|
};
|
|
var execute = function (patterns, evt) {
|
|
return find(match$1(patterns, evt), function (pattern) {
|
|
return pattern.action();
|
|
});
|
|
};
|
|
var MatchKeys = {
|
|
match: match$1,
|
|
action: action,
|
|
execute: execute
|
|
};
|
|
|
|
var executeKeydownOverride = function (editor, caret, evt) {
|
|
var os = detect$3().os;
|
|
MatchKeys.execute([
|
|
{
|
|
keyCode: VK.RIGHT,
|
|
action: moveH(editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.LEFT,
|
|
action: moveH(editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.UP,
|
|
action: moveV(editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DOWN,
|
|
action: moveV(editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.RIGHT,
|
|
action: moveH$1(editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.LEFT,
|
|
action: moveH$1(editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.UP,
|
|
action: moveV$1(editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DOWN,
|
|
action: moveV$1(editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.RIGHT,
|
|
action: BoundarySelection.move(editor, caret, true)
|
|
},
|
|
{
|
|
keyCode: VK.LEFT,
|
|
action: BoundarySelection.move(editor, caret, false)
|
|
},
|
|
{
|
|
keyCode: VK.RIGHT,
|
|
ctrlKey: !os.isOSX(),
|
|
altKey: os.isOSX(),
|
|
action: BoundarySelection.moveNextWord(editor, caret)
|
|
},
|
|
{
|
|
keyCode: VK.LEFT,
|
|
ctrlKey: !os.isOSX(),
|
|
altKey: os.isOSX(),
|
|
action: BoundarySelection.movePrevWord(editor, caret)
|
|
},
|
|
{
|
|
keyCode: VK.UP,
|
|
action: moveV$2(editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DOWN,
|
|
action: moveV$2(editor, true)
|
|
}
|
|
], evt).each(function (_) {
|
|
evt.preventDefault();
|
|
});
|
|
};
|
|
var setup$8 = function (editor, caret) {
|
|
editor.on('keydown', function (evt) {
|
|
if (evt.isDefaultPrevented() === false) {
|
|
executeKeydownOverride(editor, caret, evt);
|
|
}
|
|
});
|
|
};
|
|
var ArrowKeys = { setup: setup$8 };
|
|
|
|
var isBeforeRoot = function (rootNode) {
|
|
return function (elm) {
|
|
return eq(rootNode, Element.fromDom(elm.dom().parentNode));
|
|
};
|
|
};
|
|
var getParentBlock$1 = function (rootNode, elm) {
|
|
return contains$2(rootNode, elm) ? closest(elm, function (element) {
|
|
return isTextBlock(element) || isListItem(element);
|
|
}, isBeforeRoot(rootNode)) : Option.none();
|
|
};
|
|
var placeCaretInEmptyBody = function (editor) {
|
|
var body = editor.getBody();
|
|
var node = body.firstChild && editor.dom.isBlock(body.firstChild) ? body.firstChild : body;
|
|
editor.selection.setCursorLocation(node, 0);
|
|
};
|
|
var paddEmptyBody = function (editor) {
|
|
if (editor.dom.isEmpty(editor.getBody())) {
|
|
editor.setContent('');
|
|
placeCaretInEmptyBody(editor);
|
|
}
|
|
};
|
|
var willDeleteLastPositionInElement = function (forward, fromPos, elm) {
|
|
return lift2(CaretFinder.firstPositionIn(elm), CaretFinder.lastPositionIn(elm), function (firstPos, lastPos) {
|
|
var normalizedFirstPos = InlineUtils.normalizePosition(true, firstPos);
|
|
var normalizedLastPos = InlineUtils.normalizePosition(false, lastPos);
|
|
var normalizedFromPos = InlineUtils.normalizePosition(false, fromPos);
|
|
if (forward) {
|
|
return CaretFinder.nextPosition(elm, normalizedFromPos).map(function (nextPos) {
|
|
return nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos);
|
|
}).getOr(false);
|
|
} else {
|
|
return CaretFinder.prevPosition(elm, normalizedFromPos).map(function (prevPos) {
|
|
return prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos);
|
|
}).getOr(false);
|
|
}
|
|
}).getOr(true);
|
|
};
|
|
var DeleteUtils = {
|
|
getParentBlock: getParentBlock$1,
|
|
paddEmptyBody: paddEmptyBody,
|
|
willDeleteLastPositionInElement: willDeleteLastPositionInElement
|
|
};
|
|
|
|
var blockPosition = function (block, position) {
|
|
return {
|
|
block: constant(block),
|
|
position: constant(position)
|
|
};
|
|
};
|
|
var blockBoundary = function (from, to) {
|
|
return {
|
|
from: constant(from),
|
|
to: constant(to)
|
|
};
|
|
};
|
|
var getBlockPosition = function (rootNode, pos) {
|
|
var rootElm = Element.fromDom(rootNode);
|
|
var containerElm = Element.fromDom(pos.container());
|
|
return DeleteUtils.getParentBlock(rootElm, containerElm).map(function (block) {
|
|
return blockPosition(block, pos);
|
|
});
|
|
};
|
|
var isDifferentBlocks = function (blockBoundary) {
|
|
return eq(blockBoundary.from().block(), blockBoundary.to().block()) === false;
|
|
};
|
|
var hasSameParent = function (blockBoundary) {
|
|
return parent(blockBoundary.from().block()).bind(function (parent1) {
|
|
return parent(blockBoundary.to().block()).filter(function (parent2) {
|
|
return eq(parent1, parent2);
|
|
});
|
|
}).isSome();
|
|
};
|
|
var isEditable = function (blockBoundary) {
|
|
return NodeType.isContentEditableFalse(blockBoundary.from().block().dom()) === false && NodeType.isContentEditableFalse(blockBoundary.to().block().dom()) === false;
|
|
};
|
|
var skipLastBr = function (rootNode, forward, blockPosition) {
|
|
if (NodeType.isBr(blockPosition.position().getNode()) && Empty.isEmpty(blockPosition.block()) === false) {
|
|
return CaretFinder.positionIn(false, blockPosition.block().dom()).bind(function (lastPositionInBlock) {
|
|
if (lastPositionInBlock.isEqual(blockPosition.position())) {
|
|
return CaretFinder.fromPosition(forward, rootNode, lastPositionInBlock).bind(function (to) {
|
|
return getBlockPosition(rootNode, to);
|
|
});
|
|
} else {
|
|
return Option.some(blockPosition);
|
|
}
|
|
}).getOr(blockPosition);
|
|
} else {
|
|
return blockPosition;
|
|
}
|
|
};
|
|
var readFromRange = function (rootNode, forward, rng) {
|
|
var fromBlockPos = getBlockPosition(rootNode, CaretPosition$1.fromRangeStart(rng));
|
|
var toBlockPos = fromBlockPos.bind(function (blockPos) {
|
|
return CaretFinder.fromPosition(forward, rootNode, blockPos.position()).bind(function (to) {
|
|
return getBlockPosition(rootNode, to).map(function (blockPos) {
|
|
return skipLastBr(rootNode, forward, blockPos);
|
|
});
|
|
});
|
|
});
|
|
return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(function (blockBoundary) {
|
|
return isDifferentBlocks(blockBoundary) && hasSameParent(blockBoundary) && isEditable(blockBoundary);
|
|
});
|
|
};
|
|
var read$3 = function (rootNode, forward, rng) {
|
|
return rng.collapsed ? readFromRange(rootNode, forward, rng) : Option.none();
|
|
};
|
|
var BlockMergeBoundary = { read: read$3 };
|
|
|
|
var getChildrenUntilBlockBoundary = function (block) {
|
|
var children$1 = children(block);
|
|
return findIndex(children$1, isBlock).fold(function () {
|
|
return children$1;
|
|
}, function (index) {
|
|
return children$1.slice(0, index);
|
|
});
|
|
};
|
|
var extractChildren = function (block) {
|
|
var children = getChildrenUntilBlockBoundary(block);
|
|
each(children, remove$1);
|
|
return children;
|
|
};
|
|
var removeEmptyRoot = function (rootNode, block) {
|
|
var parents = Parents.parentsAndSelf(block, rootNode);
|
|
return find(parents.reverse(), Empty.isEmpty).each(remove$1);
|
|
};
|
|
var isEmptyBefore = function (el) {
|
|
return filter(prevSiblings(el), function (el) {
|
|
return !Empty.isEmpty(el);
|
|
}).length === 0;
|
|
};
|
|
var nestedBlockMerge = function (rootNode, fromBlock, toBlock, insertionPoint) {
|
|
if (Empty.isEmpty(toBlock)) {
|
|
PaddingBr.fillWithPaddingBr(toBlock);
|
|
return CaretFinder.firstPositionIn(toBlock.dom());
|
|
}
|
|
if (isEmptyBefore(insertionPoint) && Empty.isEmpty(fromBlock)) {
|
|
before(insertionPoint, Element.fromTag('br'));
|
|
}
|
|
var position = CaretFinder.prevPosition(toBlock.dom(), CaretPosition$1.before(insertionPoint.dom()));
|
|
each(extractChildren(fromBlock), function (child) {
|
|
before(insertionPoint, child);
|
|
});
|
|
removeEmptyRoot(rootNode, fromBlock);
|
|
return position;
|
|
};
|
|
var sidelongBlockMerge = function (rootNode, fromBlock, toBlock) {
|
|
if (Empty.isEmpty(toBlock)) {
|
|
remove$1(toBlock);
|
|
if (Empty.isEmpty(fromBlock)) {
|
|
PaddingBr.fillWithPaddingBr(fromBlock);
|
|
}
|
|
return CaretFinder.firstPositionIn(fromBlock.dom());
|
|
}
|
|
var position = CaretFinder.lastPositionIn(toBlock.dom());
|
|
each(extractChildren(fromBlock), function (child) {
|
|
append(toBlock, child);
|
|
});
|
|
removeEmptyRoot(rootNode, fromBlock);
|
|
return position;
|
|
};
|
|
var findInsertionPoint = function (toBlock, block) {
|
|
var parentsAndSelf = Parents.parentsAndSelf(block, toBlock);
|
|
return Option.from(parentsAndSelf[parentsAndSelf.length - 1]);
|
|
};
|
|
var getInsertionPoint = function (fromBlock, toBlock) {
|
|
return contains$2(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Option.none();
|
|
};
|
|
var trimBr = function (first, block) {
|
|
CaretFinder.positionIn(first, block.dom()).map(function (position) {
|
|
return position.getNode();
|
|
}).map(Element.fromDom).filter(isBr$1).each(remove$1);
|
|
};
|
|
var mergeBlockInto = function (rootNode, fromBlock, toBlock) {
|
|
trimBr(true, fromBlock);
|
|
trimBr(false, toBlock);
|
|
return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock), curry(nestedBlockMerge, rootNode, fromBlock, toBlock));
|
|
};
|
|
var mergeBlocks = function (rootNode, forward, block1, block2) {
|
|
return forward ? mergeBlockInto(rootNode, block2, block1) : mergeBlockInto(rootNode, block1, block2);
|
|
};
|
|
var MergeBlocks = { mergeBlocks: mergeBlocks };
|
|
|
|
var backspaceDelete = function (editor, forward) {
|
|
var rootNode = Element.fromDom(editor.getBody());
|
|
var position = BlockMergeBoundary.read(rootNode.dom(), forward, editor.selection.getRng()).bind(function (blockBoundary) {
|
|
return MergeBlocks.mergeBlocks(rootNode, forward, blockBoundary.from().block(), blockBoundary.to().block());
|
|
});
|
|
position.each(function (pos) {
|
|
editor.selection.setRng(pos.toRange());
|
|
});
|
|
return position.isSome();
|
|
};
|
|
var BlockBoundaryDelete = { backspaceDelete: backspaceDelete };
|
|
|
|
var deleteRangeMergeBlocks = function (rootNode, selection) {
|
|
var rng = selection.getRng();
|
|
return lift2(DeleteUtils.getParentBlock(rootNode, Element.fromDom(rng.startContainer)), DeleteUtils.getParentBlock(rootNode, Element.fromDom(rng.endContainer)), function (block1, block2) {
|
|
if (eq(block1, block2) === false) {
|
|
rng.deleteContents();
|
|
MergeBlocks.mergeBlocks(rootNode, true, block1, block2).each(function (pos) {
|
|
selection.setRng(pos.toRange());
|
|
});
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}).getOr(false);
|
|
};
|
|
var isRawNodeInTable = function (root, rawNode) {
|
|
var node = Element.fromDom(rawNode);
|
|
var isRoot = curry(eq, root);
|
|
return ancestor(node, isTableCell, isRoot).isSome();
|
|
};
|
|
var isSelectionInTable = function (root, rng) {
|
|
return isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
|
|
};
|
|
var isEverythingSelected = function (root, rng) {
|
|
var noPrevious = CaretFinder.prevPosition(root.dom(), CaretPosition$1.fromRangeStart(rng)).isNone();
|
|
var noNext = CaretFinder.nextPosition(root.dom(), CaretPosition$1.fromRangeEnd(rng)).isNone();
|
|
return !isSelectionInTable(root, rng) && noPrevious && noNext;
|
|
};
|
|
var emptyEditor = function (editor) {
|
|
editor.setContent('');
|
|
editor.selection.setCursorLocation();
|
|
return true;
|
|
};
|
|
var deleteRange = function (editor) {
|
|
var rootNode = Element.fromDom(editor.getBody());
|
|
var rng = editor.selection.getRng();
|
|
return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection);
|
|
};
|
|
var backspaceDelete$1 = function (editor, forward) {
|
|
return editor.selection.isCollapsed() ? false : deleteRange(editor);
|
|
};
|
|
var BlockRangeDelete = { backspaceDelete: backspaceDelete$1 };
|
|
|
|
var isBr$5 = function (pos) {
|
|
return getElementFromPosition(pos).exists(isBr$1);
|
|
};
|
|
var findBr = function (forward, root, pos) {
|
|
var parentBlocks = filter(Parents.parentsAndSelf(Element.fromDom(pos.container()), root), isBlock);
|
|
var scope = head(parentBlocks).getOr(root);
|
|
return CaretFinder.fromPosition(forward, scope.dom(), pos).filter(isBr$5);
|
|
};
|
|
var isBeforeBr = function (root, pos) {
|
|
return getElementFromPosition(pos).exists(isBr$1) || findBr(true, root, pos).isSome();
|
|
};
|
|
var isAfterBr = function (root, pos) {
|
|
return getElementFromPrevPosition(pos).exists(isBr$1) || findBr(false, root, pos).isSome();
|
|
};
|
|
var findPreviousBr = curry(findBr, false);
|
|
var findNextBr = curry(findBr, true);
|
|
|
|
var isCompoundElement = function (node) {
|
|
return isTableCell(Element.fromDom(node)) || isListItem(Element.fromDom(node));
|
|
};
|
|
var DeleteAction = Adt.generate([
|
|
{ remove: ['element'] },
|
|
{ moveToElement: ['element'] },
|
|
{ moveToPosition: ['position'] }
|
|
]);
|
|
var isAtContentEditableBlockCaret = function (forward, from) {
|
|
var elm = from.getNode(forward === false);
|
|
var caretLocation = forward ? 'after' : 'before';
|
|
return NodeType.isElement(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
|
|
};
|
|
var isDeleteFromCefDifferentBlocks = function (root, forward, from, to) {
|
|
var inSameBlock = function (elm) {
|
|
return isInline(Element.fromDom(elm)) && !isInSameBlock(from, to, root);
|
|
};
|
|
return getRelativeCefElm(!forward, from).fold(function () {
|
|
return getRelativeCefElm(forward, to).fold(constant(false), inSameBlock);
|
|
}, inSameBlock);
|
|
};
|
|
var deleteEmptyBlockOrMoveToCef = function (root, forward, from, to) {
|
|
var toCefElm = to.getNode(forward === false);
|
|
return DeleteUtils.getParentBlock(Element.fromDom(root), Element.fromDom(from.getNode())).map(function (blockElm) {
|
|
return Empty.isEmpty(blockElm) ? DeleteAction.remove(blockElm.dom()) : DeleteAction.moveToElement(toCefElm);
|
|
}).orThunk(function () {
|
|
return Option.some(DeleteAction.moveToElement(toCefElm));
|
|
});
|
|
};
|
|
var findCefPosition = function (root, forward, from) {
|
|
return CaretFinder.fromPosition(forward, root, from).bind(function (to) {
|
|
if (isCompoundElement(to.getNode())) {
|
|
return Option.none();
|
|
} else if (isDeleteFromCefDifferentBlocks(root, forward, from, to)) {
|
|
return Option.none();
|
|
} else if (forward && NodeType.isContentEditableFalse(to.getNode())) {
|
|
return deleteEmptyBlockOrMoveToCef(root, forward, from, to);
|
|
} else if (forward === false && NodeType.isContentEditableFalse(to.getNode(true))) {
|
|
return deleteEmptyBlockOrMoveToCef(root, forward, from, to);
|
|
} else if (forward && isAfterContentEditableFalse(from)) {
|
|
return Option.some(DeleteAction.moveToPosition(to));
|
|
} else if (forward === false && isBeforeContentEditableFalse(from)) {
|
|
return Option.some(DeleteAction.moveToPosition(to));
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
});
|
|
};
|
|
var getContentEditableBlockAction = function (forward, elm) {
|
|
if (forward && NodeType.isContentEditableFalse(elm.nextSibling)) {
|
|
return Option.some(DeleteAction.moveToElement(elm.nextSibling));
|
|
} else if (forward === false && NodeType.isContentEditableFalse(elm.previousSibling)) {
|
|
return Option.some(DeleteAction.moveToElement(elm.previousSibling));
|
|
} else {
|
|
return Option.none();
|
|
}
|
|
};
|
|
var skipMoveToActionFromInlineCefToContent = function (root, from, deleteAction) {
|
|
return deleteAction.fold(function (elm) {
|
|
return Option.some(DeleteAction.remove(elm));
|
|
}, function (elm) {
|
|
return Option.some(DeleteAction.moveToElement(elm));
|
|
}, function (to) {
|
|
if (isInSameBlock(from, to, root)) {
|
|
return Option.none();
|
|
} else {
|
|
return Option.some(DeleteAction.moveToPosition(to));
|
|
}
|
|
});
|
|
};
|
|
var getContentEditableAction = function (root, forward, from) {
|
|
if (isAtContentEditableBlockCaret(forward, from)) {
|
|
return getContentEditableBlockAction(forward, from.getNode(forward === false)).fold(function () {
|
|
return findCefPosition(root, forward, from);
|
|
}, Option.some);
|
|
} else {
|
|
return findCefPosition(root, forward, from).bind(function (deleteAction) {
|
|
return skipMoveToActionFromInlineCefToContent(root, from, deleteAction);
|
|
});
|
|
}
|
|
};
|
|
var read$4 = function (root, forward, rng) {
|
|
var normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
|
|
var from = CaretPosition$1.fromRangeStart(normalizedRange);
|
|
var rootElement = Element.fromDom(root);
|
|
if (forward === false && isAfterContentEditableFalse(from)) {
|
|
return Option.some(DeleteAction.remove(from.getNode(true)));
|
|
} else if (forward && isBeforeContentEditableFalse(from)) {
|
|
return Option.some(DeleteAction.remove(from.getNode()));
|
|
} else if (forward === false && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from)) {
|
|
return findPreviousBr(rootElement, from).map(function (br) {
|
|
return DeleteAction.remove(br.getNode());
|
|
});
|
|
} else if (forward && isAfterContentEditableFalse(from) && isBeforeBr(rootElement, from)) {
|
|
return findNextBr(rootElement, from).map(function (br) {
|
|
return DeleteAction.remove(br.getNode());
|
|
});
|
|
} else {
|
|
return getContentEditableAction(root, forward, from);
|
|
}
|
|
};
|
|
|
|
var deleteElement$1 = function (editor, forward) {
|
|
return function (element) {
|
|
editor._selectionOverrides.hideFakeCaret();
|
|
DeleteElement.deleteElement(editor, forward, Element.fromDom(element));
|
|
return true;
|
|
};
|
|
};
|
|
var moveToElement = function (editor, forward) {
|
|
return function (element) {
|
|
var pos = forward ? CaretPosition$1.before(element) : CaretPosition$1.after(element);
|
|
editor.selection.setRng(pos.toRange());
|
|
return true;
|
|
};
|
|
};
|
|
var moveToPosition = function (editor) {
|
|
return function (pos) {
|
|
editor.selection.setRng(pos.toRange());
|
|
return true;
|
|
};
|
|
};
|
|
var getAncestorCe = function (editor, node) {
|
|
return Option.from(getContentEditableRoot$2(editor.getBody(), node));
|
|
};
|
|
var backspaceDeleteCaret = function (editor, forward) {
|
|
var selectedNode = editor.selection.getNode();
|
|
return getAncestorCe(editor, selectedNode).filter(NodeType.isContentEditableFalse).fold(function () {
|
|
var result = read$4(editor.getBody(), forward, editor.selection.getRng()).map(function (deleteAction) {
|
|
return deleteAction.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor));
|
|
});
|
|
return result.getOr(false);
|
|
}, function () {
|
|
return true;
|
|
});
|
|
};
|
|
var deleteOffscreenSelection = function (rootElement) {
|
|
each(descendants$1(rootElement, '.mce-offscreen-selection'), remove$1);
|
|
};
|
|
var backspaceDeleteRange = function (editor, forward) {
|
|
var selectedNode = editor.selection.getNode();
|
|
if (NodeType.isContentEditableFalse(selectedNode)) {
|
|
var hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(NodeType.isContentEditableFalse);
|
|
return hasCefAncestor.fold(function () {
|
|
deleteOffscreenSelection(Element.fromDom(editor.getBody()));
|
|
DeleteElement.deleteElement(editor, forward, Element.fromDom(editor.selection.getNode()));
|
|
DeleteUtils.paddEmptyBody(editor);
|
|
return true;
|
|
}, function () {
|
|
return true;
|
|
});
|
|
}
|
|
return false;
|
|
};
|
|
var getContentEditableRoot$2 = function (root, node) {
|
|
while (node && node !== root) {
|
|
if (NodeType.isContentEditableTrue(node) || NodeType.isContentEditableFalse(node)) {
|
|
return node;
|
|
}
|
|
node = node.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
var paddEmptyElement = function (editor) {
|
|
var br;
|
|
var ceRoot = getContentEditableRoot$2(editor.getBody(), editor.selection.getNode());
|
|
if (NodeType.isContentEditableTrue(ceRoot) && editor.dom.isBlock(ceRoot) && editor.dom.isEmpty(ceRoot)) {
|
|
br = editor.dom.create('br', { 'data-mce-bogus': '1' });
|
|
editor.dom.setHTML(ceRoot, '');
|
|
ceRoot.appendChild(br);
|
|
editor.selection.setRng(CaretPosition$1.before(br).toRange());
|
|
}
|
|
return true;
|
|
};
|
|
var backspaceDelete$2 = function (editor, forward) {
|
|
if (editor.selection.isCollapsed()) {
|
|
return backspaceDeleteCaret(editor, forward);
|
|
} else {
|
|
return backspaceDeleteRange(editor, forward);
|
|
}
|
|
};
|
|
var CefDelete = {
|
|
backspaceDelete: backspaceDelete$2,
|
|
paddEmptyElement: paddEmptyElement
|
|
};
|
|
|
|
var trimEmptyTextNode$1 = function (dom, node) {
|
|
if (NodeType.isText(node) && node.data.length === 0) {
|
|
dom.remove(node);
|
|
}
|
|
};
|
|
var deleteContentAndShowCaret = function (editor, range, node, direction, forward, peekCaretPosition) {
|
|
var caretRange = showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true);
|
|
if (range.collapsed) {
|
|
var deleteRange = range.cloneRange();
|
|
if (forward) {
|
|
deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
|
|
} else {
|
|
deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
|
|
}
|
|
deleteRange.deleteContents();
|
|
} else {
|
|
range.deleteContents();
|
|
}
|
|
editor.selection.setRng(caretRange);
|
|
trimEmptyTextNode$1(editor.dom, node);
|
|
return true;
|
|
};
|
|
var deleteCefBoundaryText = function (editor, forward) {
|
|
var range = editor.selection.getRng();
|
|
if (!NodeType.isText(range.commonAncestorContainer)) {
|
|
return false;
|
|
}
|
|
var direction = forward ? HDirection.Forwards : HDirection.Backwards;
|
|
var caretWalker = CaretWalker(editor.getBody());
|
|
var getNextVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.next);
|
|
var getPrevVisualCaretPosition = curry(getVisualCaretPosition, caretWalker.prev);
|
|
var getNextPosFn = forward ? getNextVisualCaretPosition : getPrevVisualCaretPosition;
|
|
var isBeforeContentEditableFalseFn = forward ? isBeforeContentEditableFalse : isAfterContentEditableFalse;
|
|
var caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
|
var nextCaretPosition = InlineUtils.normalizePosition(forward, getNextPosFn(caretPosition));
|
|
if (!nextCaretPosition || !isMoveInsideSameBlock(caretPosition, nextCaretPosition)) {
|
|
return false;
|
|
} else if (isBeforeContentEditableFalseFn(nextCaretPosition)) {
|
|
return deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, nextCaretPosition);
|
|
}
|
|
var peekCaretPosition = getNextPosFn(nextCaretPosition);
|
|
if (peekCaretPosition && isBeforeContentEditableFalseFn(peekCaretPosition)) {
|
|
if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
|
|
return deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition);
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var backspaceDelete$3 = function (editor, forward) {
|
|
return deleteCefBoundaryText(editor, forward);
|
|
};
|
|
var CefBoundaryDelete = { backspaceDelete: backspaceDelete$3 };
|
|
|
|
var isFeatureEnabled$1 = function (editor) {
|
|
return editor.settings.inline_boundaries !== false;
|
|
};
|
|
var rangeFromPositions = function (from, to) {
|
|
var range = domGlobals.document.createRange();
|
|
range.setStart(from.container(), from.offset());
|
|
range.setEnd(to.container(), to.offset());
|
|
return range;
|
|
};
|
|
var hasOnlyTwoOrLessPositionsLeft = function (elm) {
|
|
return lift2(CaretFinder.firstPositionIn(elm), CaretFinder.lastPositionIn(elm), function (firstPos, lastPos) {
|
|
var normalizedFirstPos = InlineUtils.normalizePosition(true, firstPos);
|
|
var normalizedLastPos = InlineUtils.normalizePosition(false, lastPos);
|
|
return CaretFinder.nextPosition(elm, normalizedFirstPos).map(function (pos) {
|
|
return pos.isEqual(normalizedLastPos);
|
|
}).getOr(true);
|
|
}).getOr(true);
|
|
};
|
|
var setCaretLocation = function (editor, caret) {
|
|
return function (location) {
|
|
return BoundaryCaret.renderCaret(caret, location).map(function (pos) {
|
|
BoundarySelection.setCaretPosition(editor, pos);
|
|
return true;
|
|
}).getOr(false);
|
|
};
|
|
};
|
|
var deleteFromTo = function (editor, caret, from, to) {
|
|
var rootNode = editor.getBody();
|
|
var isInlineTarget = curry(InlineUtils.isInlineTarget, editor);
|
|
editor.undoManager.ignore(function () {
|
|
editor.selection.setRng(rangeFromPositions(from, to));
|
|
editor.execCommand('Delete');
|
|
BoundaryLocation.readLocation(isInlineTarget, rootNode, CaretPosition$1.fromRangeStart(editor.selection.getRng())).map(BoundaryLocation.inside).map(setCaretLocation(editor, caret));
|
|
});
|
|
editor.nodeChanged();
|
|
};
|
|
var rescope$1 = function (rootNode, node) {
|
|
var parentBlock = getParentBlock(node, rootNode);
|
|
return parentBlock ? parentBlock : rootNode;
|
|
};
|
|
var backspaceDeleteCollapsed = function (editor, caret, forward, from) {
|
|
var rootNode = rescope$1(editor.getBody(), from.container());
|
|
var isInlineTarget = curry(InlineUtils.isInlineTarget, editor);
|
|
var fromLocation = BoundaryLocation.readLocation(isInlineTarget, rootNode, from);
|
|
return fromLocation.bind(function (location) {
|
|
if (forward) {
|
|
return location.fold(constant(Option.some(BoundaryLocation.inside(location))), Option.none, constant(Option.some(BoundaryLocation.outside(location))), Option.none);
|
|
} else {
|
|
return location.fold(Option.none, constant(Option.some(BoundaryLocation.outside(location))), Option.none, constant(Option.some(BoundaryLocation.inside(location))));
|
|
}
|
|
}).map(setCaretLocation(editor, caret)).getOrThunk(function () {
|
|
var toPosition = CaretFinder.navigate(forward, rootNode, from);
|
|
var toLocation = toPosition.bind(function (pos) {
|
|
return BoundaryLocation.readLocation(isInlineTarget, rootNode, pos);
|
|
});
|
|
if (fromLocation.isSome() && toLocation.isSome()) {
|
|
return InlineUtils.findRootInline(isInlineTarget, rootNode, from).map(function (elm) {
|
|
if (hasOnlyTwoOrLessPositionsLeft(elm)) {
|
|
DeleteElement.deleteElement(editor, forward, Element.fromDom(elm));
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}).getOr(false);
|
|
} else {
|
|
return toLocation.bind(function (_) {
|
|
return toPosition.map(function (to) {
|
|
if (forward) {
|
|
deleteFromTo(editor, caret, from, to);
|
|
} else {
|
|
deleteFromTo(editor, caret, to, from);
|
|
}
|
|
return true;
|
|
});
|
|
}).getOr(false);
|
|
}
|
|
});
|
|
};
|
|
var backspaceDelete$4 = function (editor, caret, forward) {
|
|
if (editor.selection.isCollapsed() && isFeatureEnabled$1(editor)) {
|
|
var from = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return backspaceDeleteCollapsed(editor, caret, forward, from);
|
|
}
|
|
return false;
|
|
};
|
|
var BoundaryDelete = { backspaceDelete: backspaceDelete$4 };
|
|
|
|
var getParentInlines = function (rootElm, startElm) {
|
|
var parents = Parents.parentsAndSelf(startElm, rootElm);
|
|
return findIndex(parents, isBlock).fold(constant(parents), function (index) {
|
|
return parents.slice(0, index);
|
|
});
|
|
};
|
|
var hasOnlyOneChild = function (elm) {
|
|
return children(elm).length === 1;
|
|
};
|
|
var deleteLastPosition = function (forward, editor, target, parentInlines) {
|
|
var isFormatElement$1 = curry(isFormatElement, editor);
|
|
var formatNodes = map(filter(parentInlines, isFormatElement$1), function (elm) {
|
|
return elm.dom();
|
|
});
|
|
if (formatNodes.length === 0) {
|
|
DeleteElement.deleteElement(editor, forward, target);
|
|
} else {
|
|
var pos = replaceWithCaretFormat(target.dom(), formatNodes);
|
|
editor.selection.setRng(pos.toRange());
|
|
}
|
|
};
|
|
var deleteCaret = function (editor, forward) {
|
|
var rootElm = Element.fromDom(editor.getBody());
|
|
var startElm = Element.fromDom(editor.selection.getStart());
|
|
var parentInlines = filter(getParentInlines(rootElm, startElm), hasOnlyOneChild);
|
|
return last(parentInlines).map(function (target) {
|
|
var fromPos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
if (DeleteUtils.willDeleteLastPositionInElement(forward, fromPos, target.dom()) && !isEmptyCaretFormatElement(target)) {
|
|
deleteLastPosition(forward, editor, target, parentInlines);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}).getOr(false);
|
|
};
|
|
var backspaceDelete$5 = function (editor, forward) {
|
|
return editor.selection.isCollapsed() ? deleteCaret(editor, forward) : false;
|
|
};
|
|
var InlineFormatDelete = { backspaceDelete: backspaceDelete$5 };
|
|
|
|
var tableCellRng = function (start, end) {
|
|
return {
|
|
start: constant(start),
|
|
end: constant(end)
|
|
};
|
|
};
|
|
var tableSelection = function (rng, table, cells) {
|
|
return {
|
|
rng: constant(rng),
|
|
table: constant(table),
|
|
cells: constant(cells)
|
|
};
|
|
};
|
|
var deleteAction = Adt.generate([
|
|
{ removeTable: ['element'] },
|
|
{ emptyCells: ['cells'] }
|
|
]);
|
|
var isRootFromElement = function (root) {
|
|
return function (cur) {
|
|
return eq(root, cur);
|
|
};
|
|
};
|
|
var getClosestCell$1 = function (container, isRoot) {
|
|
return closest$1(Element.fromDom(container), 'td,th', isRoot);
|
|
};
|
|
var getClosestTable = function (cell, isRoot) {
|
|
return ancestor$1(cell, 'table', isRoot);
|
|
};
|
|
var isExpandedCellRng = function (cellRng) {
|
|
return eq(cellRng.start(), cellRng.end()) === false;
|
|
};
|
|
var getTableFromCellRng = function (cellRng, isRoot) {
|
|
return getClosestTable(cellRng.start(), isRoot).bind(function (startParentTable) {
|
|
return getClosestTable(cellRng.end(), isRoot).bind(function (endParentTable) {
|
|
return someIf(eq(startParentTable, endParentTable), startParentTable);
|
|
});
|
|
});
|
|
};
|
|
var getTableCells = function (table) {
|
|
return descendants$1(table, 'td,th');
|
|
};
|
|
var getCellRangeFromStartTable = function (cellRng, isRoot) {
|
|
return getClosestTable(cellRng.start(), isRoot).bind(function (table) {
|
|
return last(getTableCells(table)).map(function (endCell) {
|
|
return tableCellRng(cellRng.start(), endCell);
|
|
});
|
|
});
|
|
};
|
|
var partialSelection = function (isRoot, rng) {
|
|
var startCell = getClosestCell$1(rng.startContainer, isRoot);
|
|
var endCell = getClosestCell$1(rng.endContainer, isRoot);
|
|
return rng.collapsed ? Option.none() : lift2(startCell, endCell, tableCellRng).fold(function () {
|
|
return startCell.fold(function () {
|
|
return endCell.bind(function (endCell) {
|
|
return getClosestTable(endCell, isRoot).bind(function (table) {
|
|
return head(getTableCells(table)).map(function (startCell) {
|
|
return tableCellRng(startCell, endCell);
|
|
});
|
|
});
|
|
});
|
|
}, function (startCell) {
|
|
return getClosestTable(startCell, isRoot).bind(function (table) {
|
|
return last(getTableCells(table)).map(function (endCell) {
|
|
return tableCellRng(startCell, endCell);
|
|
});
|
|
});
|
|
});
|
|
}, function (cellRng) {
|
|
return isWithinSameTable(isRoot, cellRng) ? Option.none() : getCellRangeFromStartTable(cellRng, isRoot);
|
|
});
|
|
};
|
|
var isWithinSameTable = function (isRoot, cellRng) {
|
|
return getTableFromCellRng(cellRng, isRoot).isSome();
|
|
};
|
|
var getCellRng = function (rng, isRoot) {
|
|
var startCell = getClosestCell$1(rng.startContainer, isRoot);
|
|
var endCell = getClosestCell$1(rng.endContainer, isRoot);
|
|
return lift2(startCell, endCell, tableCellRng).filter(isExpandedCellRng).filter(function (cellRng) {
|
|
return isWithinSameTable(isRoot, cellRng);
|
|
}).orThunk(function () {
|
|
return partialSelection(isRoot, rng);
|
|
});
|
|
};
|
|
var getTableSelectionFromCellRng = function (cellRng, isRoot) {
|
|
return getTableFromCellRng(cellRng, isRoot).map(function (table) {
|
|
return tableSelection(cellRng, table, getTableCells(table));
|
|
});
|
|
};
|
|
var getTableSelectionFromRng = function (root, rng) {
|
|
var isRoot = isRootFromElement(root);
|
|
return getCellRng(rng, isRoot).bind(function (cellRng) {
|
|
return getTableSelectionFromCellRng(cellRng, isRoot);
|
|
});
|
|
};
|
|
var getCellIndex = function (cells, cell) {
|
|
return findIndex(cells, function (x) {
|
|
return eq(x, cell);
|
|
});
|
|
};
|
|
var getSelectedCells = function (tableSelection) {
|
|
return lift2(getCellIndex(tableSelection.cells(), tableSelection.rng().start()), getCellIndex(tableSelection.cells(), tableSelection.rng().end()), function (startIndex, endIndex) {
|
|
return tableSelection.cells().slice(startIndex, endIndex + 1);
|
|
});
|
|
};
|
|
var getAction = function (tableSelection) {
|
|
return getSelectedCells(tableSelection).map(function (selected) {
|
|
var cells = tableSelection.cells();
|
|
return selected.length === cells.length ? deleteAction.removeTable(tableSelection.table()) : deleteAction.emptyCells(selected);
|
|
});
|
|
};
|
|
var getActionFromRange = function (root, rng) {
|
|
return getTableSelectionFromRng(root, rng).bind(getAction);
|
|
};
|
|
|
|
var emptyCells = function (editor, cells) {
|
|
each(cells, PaddingBr.fillWithPaddingBr);
|
|
editor.selection.setCursorLocation(cells[0].dom(), 0);
|
|
return true;
|
|
};
|
|
var deleteTableElement = function (editor, table) {
|
|
DeleteElement.deleteElement(editor, false, table);
|
|
return true;
|
|
};
|
|
var deleteCellRange = function (editor, rootElm, rng) {
|
|
return getActionFromRange(rootElm, rng).map(function (action) {
|
|
return action.fold(curry(deleteTableElement, editor), curry(emptyCells, editor));
|
|
});
|
|
};
|
|
var deleteCaptionRange = function (editor, caption) {
|
|
return emptyElement(editor, caption);
|
|
};
|
|
var deleteTableRange = function (editor, rootElm, rng, startElm) {
|
|
return getParentCaption(rootElm, startElm).fold(function () {
|
|
return deleteCellRange(editor, rootElm, rng);
|
|
}, function (caption) {
|
|
return deleteCaptionRange(editor, caption);
|
|
}).getOr(false);
|
|
};
|
|
var deleteRange$1 = function (editor, startElm) {
|
|
var rootNode = Element.fromDom(editor.getBody());
|
|
var rng = editor.selection.getRng();
|
|
var selectedCells = TableCellSelection.getCellsFromEditor(editor);
|
|
return selectedCells.length !== 0 ? emptyCells(editor, selectedCells) : deleteTableRange(editor, rootNode, rng, startElm);
|
|
};
|
|
var getParentCell = function (rootElm, elm) {
|
|
return find(Parents.parentsAndSelf(elm, rootElm), isTableCell);
|
|
};
|
|
var getParentCaption = function (rootElm, elm) {
|
|
return find(Parents.parentsAndSelf(elm, rootElm), function (elm) {
|
|
return name(elm) === 'caption';
|
|
});
|
|
};
|
|
var deleteBetweenCells = function (editor, rootElm, forward, fromCell, from) {
|
|
return CaretFinder.navigate(forward, editor.getBody(), from).bind(function (to) {
|
|
return getParentCell(rootElm, Element.fromDom(to.getNode())).map(function (toCell) {
|
|
return eq(toCell, fromCell) === false;
|
|
});
|
|
});
|
|
};
|
|
var emptyElement = function (editor, elm) {
|
|
PaddingBr.fillWithPaddingBr(elm);
|
|
editor.selection.setCursorLocation(elm.dom(), 0);
|
|
return Option.some(true);
|
|
};
|
|
var isDeleteOfLastCharPos = function (fromCaption, forward, from, to) {
|
|
return CaretFinder.firstPositionIn(fromCaption.dom()).bind(function (first) {
|
|
return CaretFinder.lastPositionIn(fromCaption.dom()).map(function (last) {
|
|
return forward ? from.isEqual(first) && to.isEqual(last) : from.isEqual(last) && to.isEqual(first);
|
|
});
|
|
}).getOr(true);
|
|
};
|
|
var emptyCaretCaption = function (editor, elm) {
|
|
return emptyElement(editor, elm);
|
|
};
|
|
var validateCaretCaption = function (rootElm, fromCaption, to) {
|
|
return getParentCaption(rootElm, Element.fromDom(to.getNode())).map(function (toCaption) {
|
|
return eq(toCaption, fromCaption) === false;
|
|
});
|
|
};
|
|
var deleteCaretInsideCaption = function (editor, rootElm, forward, fromCaption, from) {
|
|
return CaretFinder.navigate(forward, editor.getBody(), from).bind(function (to) {
|
|
return isDeleteOfLastCharPos(fromCaption, forward, from, to) ? emptyCaretCaption(editor, fromCaption) : validateCaretCaption(rootElm, fromCaption, to);
|
|
}).or(Option.some(true));
|
|
};
|
|
var deleteCaretCells = function (editor, forward, rootElm, startElm) {
|
|
var from = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return getParentCell(rootElm, startElm).bind(function (fromCell) {
|
|
return Empty.isEmpty(fromCell) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from);
|
|
}).getOr(false);
|
|
};
|
|
var deleteCaretCaption = function (editor, forward, rootElm, fromCaption) {
|
|
var from = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return Empty.isEmpty(fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
|
|
};
|
|
var isNearTable = function (forward, pos) {
|
|
return forward ? isBeforeTable(pos) : isAfterTable(pos);
|
|
};
|
|
var isBeforeOrAfterTable = function (editor, forward) {
|
|
var fromPos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return isNearTable(forward, fromPos) || CaretFinder.fromPosition(forward, editor.getBody(), fromPos).map(function (pos) {
|
|
return isNearTable(forward, pos);
|
|
}).getOr(false);
|
|
};
|
|
var deleteCaret$1 = function (editor, forward, startElm) {
|
|
var rootElm = Element.fromDom(editor.getBody());
|
|
return getParentCaption(rootElm, startElm).fold(function () {
|
|
return deleteCaretCells(editor, forward, rootElm, startElm) || isBeforeOrAfterTable(editor, forward);
|
|
}, function (fromCaption) {
|
|
return deleteCaretCaption(editor, forward, rootElm, fromCaption).getOr(false);
|
|
});
|
|
};
|
|
var backspaceDelete$6 = function (editor, forward) {
|
|
var startElm = Element.fromDom(editor.selection.getStart(true));
|
|
var cells = TableCellSelection.getCellsFromEditor(editor);
|
|
return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$1(editor, forward, startElm) : deleteRange$1(editor, startElm);
|
|
};
|
|
var TableDelete = { backspaceDelete: backspaceDelete$6 };
|
|
|
|
var deleteCaret$2 = function (editor, forward) {
|
|
var fromPos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return CaretFinder.fromPosition(forward, editor.getBody(), fromPos).filter(function (pos) {
|
|
return forward ? isBeforeImageBlock(pos) : isAfterImageBlock(pos);
|
|
}).bind(function (pos) {
|
|
return Option.from(getChildNodeAtRelativeOffset(forward ? 0 : -1, pos));
|
|
}).map(function (elm) {
|
|
editor.selection.select(elm);
|
|
return true;
|
|
}).getOr(false);
|
|
};
|
|
var backspaceDelete$7 = function (editor, forward) {
|
|
return editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : false;
|
|
};
|
|
var PageBreakDelete = { backspaceDelete: backspaceDelete$7 };
|
|
|
|
var isEditable$1 = function (target) {
|
|
return closest(target, function (elm) {
|
|
return NodeType.isContentEditableTrue(elm.dom()) || NodeType.isContentEditableFalse(elm.dom());
|
|
}).exists(function (elm) {
|
|
return NodeType.isContentEditableTrue(elm.dom());
|
|
});
|
|
};
|
|
var parseIndentValue = function (value) {
|
|
var number = parseInt(value, 10);
|
|
return isNaN(number) ? 0 : number;
|
|
};
|
|
var getIndentStyleName = function (useMargin, element) {
|
|
var indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
|
|
var suffix = get$2(element, 'direction') === 'rtl' ? '-right' : '-left';
|
|
return indentStyleName + suffix;
|
|
};
|
|
var indentElement = function (dom, command, useMargin, value, unit, element) {
|
|
var indentStyleName = getIndentStyleName(useMargin, Element.fromDom(element));
|
|
if (command === 'outdent') {
|
|
var styleValue = Math.max(0, parseIndentValue(element.style[indentStyleName]) - value);
|
|
dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
|
|
} else {
|
|
var styleValue = parseIndentValue(element.style[indentStyleName]) + value + unit;
|
|
dom.setStyle(element, indentStyleName, styleValue);
|
|
}
|
|
};
|
|
var validateBlocks = function (editor, blocks) {
|
|
return forall(blocks, function (block) {
|
|
var indentStyleName = getIndentStyleName(Settings.shouldIndentUseMargin(editor), block);
|
|
var intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
|
|
var contentEditable = editor.dom.getContentEditable(block.dom());
|
|
return contentEditable !== 'false' && intentValue > 0;
|
|
});
|
|
};
|
|
var canOutdent = function (editor) {
|
|
var blocks = getBlocksToIndent(editor);
|
|
return editor.readonly !== true && (blocks.length > 1 || validateBlocks(editor, blocks));
|
|
};
|
|
var isListComponent = function (el) {
|
|
return isList(el) || isListItem(el);
|
|
};
|
|
var parentIsListComponent = function (el) {
|
|
return parent(el).map(isListComponent).getOr(false);
|
|
};
|
|
var getBlocksToIndent = function (editor) {
|
|
return filter(map(editor.selection.getSelectedBlocks(), Element.fromDom), function (el) {
|
|
return !isListComponent(el) && !parentIsListComponent(el) && isEditable$1(el);
|
|
});
|
|
};
|
|
var handle = function (editor, command) {
|
|
var dom = editor.dom, selection = editor.selection, formatter = editor.formatter;
|
|
var indentation = Settings.getIndentation(editor);
|
|
var indentUnit = /[a-z%]+$/i.exec(indentation)[0];
|
|
var indentValue = parseInt(indentation, 10);
|
|
var useMargin = Settings.shouldIndentUseMargin(editor);
|
|
var forcedRootBlock = Settings.getForcedRootBlock(editor);
|
|
if (!editor.queryCommandState('InsertUnorderedList') && !editor.queryCommandState('InsertOrderedList')) {
|
|
if (forcedRootBlock === '' && !dom.getParent(selection.getNode(), dom.isBlock)) {
|
|
formatter.apply('div');
|
|
}
|
|
}
|
|
each(getBlocksToIndent(editor), function (block) {
|
|
indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom());
|
|
});
|
|
};
|
|
|
|
var navigateIgnoreEmptyTextNodes = function (forward, root, from) {
|
|
return CaretFinder.navigateIgnore(forward, root, from, isEmptyText);
|
|
};
|
|
var getClosestBlock = function (root, pos) {
|
|
return find(Parents.parentsAndSelf(Element.fromDom(pos.container()), root), isBlock);
|
|
};
|
|
var isAtBeforeAfterBlockBoundary = function (forward, root, pos) {
|
|
return navigateIgnoreEmptyTextNodes(forward, root.dom(), pos).forall(function (newPos) {
|
|
return getClosestBlock(root, pos).fold(function () {
|
|
return isInSameBlock(newPos, pos, root.dom()) === false;
|
|
}, function (fromBlock) {
|
|
return isInSameBlock(newPos, pos, root.dom()) === false && contains$2(fromBlock, Element.fromDom(newPos.container()));
|
|
});
|
|
});
|
|
};
|
|
var isAtBlockBoundary = function (forward, root, pos) {
|
|
return getClosestBlock(root, pos).fold(function () {
|
|
return navigateIgnoreEmptyTextNodes(forward, root.dom(), pos).forall(function (newPos) {
|
|
return isInSameBlock(newPos, pos, root.dom()) === false;
|
|
});
|
|
}, function (parent) {
|
|
return navigateIgnoreEmptyTextNodes(forward, parent.dom(), pos).isNone();
|
|
});
|
|
};
|
|
var isAtStartOfBlock = curry(isAtBlockBoundary, false);
|
|
var isAtEndOfBlock = curry(isAtBlockBoundary, true);
|
|
var isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
|
|
var isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
|
|
|
|
var backspaceDelete$8 = function (editor, _caret, _forward) {
|
|
if (editor.selection.isCollapsed() && canOutdent(editor)) {
|
|
var dom = editor.dom;
|
|
var rng = editor.selection.getRng();
|
|
var pos = CaretPosition$1.fromRangeStart(rng);
|
|
var block = dom.getParent(rng.startContainer, dom.isBlock);
|
|
if (block !== null && isAtStartOfBlock(Element.fromDom(block), pos)) {
|
|
handle(editor, 'outdent');
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var Outdent = { backspaceDelete: backspaceDelete$8 };
|
|
|
|
var executeKeydownOverride$1 = function (editor, caret, evt) {
|
|
MatchKeys.execute([
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(Outdent.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(CefDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(CefDelete.backspaceDelete, editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(CefBoundaryDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(CefBoundaryDelete.backspaceDelete, editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(BoundaryDelete.backspaceDelete, editor, caret, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(BoundaryDelete.backspaceDelete, editor, caret, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(TableDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(TableDelete.backspaceDelete, editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(PageBreakDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(PageBreakDelete.backspaceDelete, editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(BlockRangeDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(BlockRangeDelete.backspaceDelete, editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(BlockBoundaryDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(BlockBoundaryDelete.backspaceDelete, editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(InlineFormatDelete.backspaceDelete, editor, false)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(InlineFormatDelete.backspaceDelete, editor, true)
|
|
}
|
|
], evt).each(function (_) {
|
|
evt.preventDefault();
|
|
});
|
|
};
|
|
var executeKeyupOverride = function (editor, evt) {
|
|
MatchKeys.execute([
|
|
{
|
|
keyCode: VK.BACKSPACE,
|
|
action: MatchKeys.action(CefDelete.paddEmptyElement, editor)
|
|
},
|
|
{
|
|
keyCode: VK.DELETE,
|
|
action: MatchKeys.action(CefDelete.paddEmptyElement, editor)
|
|
}
|
|
], evt);
|
|
};
|
|
var setup$9 = function (editor, caret) {
|
|
editor.on('keydown', function (evt) {
|
|
if (evt.isDefaultPrevented() === false) {
|
|
executeKeydownOverride$1(editor, caret, evt);
|
|
}
|
|
});
|
|
editor.on('keyup', function (evt) {
|
|
if (evt.isDefaultPrevented() === false) {
|
|
executeKeyupOverride(editor, evt);
|
|
}
|
|
});
|
|
};
|
|
var DeleteBackspaceKeys = { setup: setup$9 };
|
|
|
|
var firstNonWhiteSpaceNodeSibling = function (node) {
|
|
while (node) {
|
|
if (node.nodeType === 1 || node.nodeType === 3 && node.data && /[\r\n\s]/.test(node.data)) {
|
|
return node;
|
|
}
|
|
node = node.nextSibling;
|
|
}
|
|
};
|
|
var moveToCaretPosition = function (editor, root) {
|
|
var node, rng, lastNode = root;
|
|
var dom = editor.dom;
|
|
var moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
|
|
if (!root) {
|
|
return;
|
|
}
|
|
if (/^(LI|DT|DD)$/.test(root.nodeName)) {
|
|
var firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
|
|
if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
|
|
root.insertBefore(dom.doc.createTextNode('\xA0'), root.firstChild);
|
|
}
|
|
}
|
|
rng = dom.createRng();
|
|
root.normalize();
|
|
if (root.hasChildNodes()) {
|
|
var walker = new TreeWalker(root, root);
|
|
while (node = walker.current()) {
|
|
if (NodeType.isText(node)) {
|
|
rng.setStart(node, 0);
|
|
rng.setEnd(node, 0);
|
|
break;
|
|
}
|
|
if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
|
|
rng.setStartBefore(node);
|
|
rng.setEndBefore(node);
|
|
break;
|
|
}
|
|
lastNode = node;
|
|
node = walker.next();
|
|
}
|
|
if (!node) {
|
|
rng.setStart(lastNode, 0);
|
|
rng.setEnd(lastNode, 0);
|
|
}
|
|
} else {
|
|
if (NodeType.isBr(root)) {
|
|
if (root.nextSibling && dom.isBlock(root.nextSibling)) {
|
|
rng.setStartBefore(root);
|
|
rng.setEndBefore(root);
|
|
} else {
|
|
rng.setStartAfter(root);
|
|
rng.setEndAfter(root);
|
|
}
|
|
} else {
|
|
rng.setStart(root, 0);
|
|
rng.setEnd(root, 0);
|
|
}
|
|
}
|
|
editor.selection.setRng(rng);
|
|
editor.selection.scrollIntoView(root);
|
|
};
|
|
var getEditableRoot = function (dom, node) {
|
|
var root = dom.getRoot();
|
|
var parent, editableRoot;
|
|
parent = node;
|
|
while (parent !== root && dom.getContentEditable(parent) !== 'false') {
|
|
if (dom.getContentEditable(parent) === 'true') {
|
|
editableRoot = parent;
|
|
}
|
|
parent = parent.parentNode;
|
|
}
|
|
return parent !== root ? editableRoot : root;
|
|
};
|
|
var getParentBlock$2 = function (editor) {
|
|
return Option.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
|
|
};
|
|
var getParentBlockName = function (editor) {
|
|
return getParentBlock$2(editor).fold(constant(''), function (parentBlock) {
|
|
return parentBlock.nodeName.toUpperCase();
|
|
});
|
|
};
|
|
var isListItemParentBlock = function (editor) {
|
|
return getParentBlock$2(editor).filter(function (elm) {
|
|
return isListItem(Element.fromDom(elm));
|
|
}).isSome();
|
|
};
|
|
var NewLineUtils = {
|
|
moveToCaretPosition: moveToCaretPosition,
|
|
getEditableRoot: getEditableRoot,
|
|
getParentBlock: getParentBlock$2,
|
|
getParentBlockName: getParentBlockName,
|
|
isListItemParentBlock: isListItemParentBlock
|
|
};
|
|
|
|
var hasFirstChild = function (elm, name) {
|
|
return elm.firstChild && elm.firstChild.nodeName === name;
|
|
};
|
|
var hasParent$1 = function (elm, parentName) {
|
|
return elm && elm.parentNode && elm.parentNode.nodeName === parentName;
|
|
};
|
|
var isListBlock = function (elm) {
|
|
return elm && /^(OL|UL|LI)$/.test(elm.nodeName);
|
|
};
|
|
var isNestedList = function (elm) {
|
|
return isListBlock(elm) && isListBlock(elm.parentNode);
|
|
};
|
|
var getContainerBlock = function (containerBlock) {
|
|
var containerBlockParent = containerBlock.parentNode;
|
|
if (/^(LI|DT|DD)$/.test(containerBlockParent.nodeName)) {
|
|
return containerBlockParent;
|
|
}
|
|
return containerBlock;
|
|
};
|
|
var isFirstOrLastLi = function (containerBlock, parentBlock, first) {
|
|
var node = containerBlock[first ? 'firstChild' : 'lastChild'];
|
|
while (node) {
|
|
if (NodeType.isElement(node)) {
|
|
break;
|
|
}
|
|
node = node[first ? 'nextSibling' : 'previousSibling'];
|
|
}
|
|
return node === parentBlock;
|
|
};
|
|
var insert = function (editor, createNewBlock, containerBlock, parentBlock, newBlockName) {
|
|
var dom = editor.dom;
|
|
var rng = editor.selection.getRng();
|
|
if (containerBlock === editor.getBody()) {
|
|
return;
|
|
}
|
|
if (isNestedList(containerBlock)) {
|
|
newBlockName = 'LI';
|
|
}
|
|
var newBlock = newBlockName ? createNewBlock(newBlockName) : dom.create('BR');
|
|
if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
|
|
if (hasParent$1(containerBlock, 'LI')) {
|
|
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
|
} else {
|
|
dom.replace(newBlock, containerBlock);
|
|
}
|
|
} else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
|
|
if (hasParent$1(containerBlock, 'LI')) {
|
|
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
|
newBlock.appendChild(dom.doc.createTextNode(' '));
|
|
newBlock.appendChild(containerBlock);
|
|
} else {
|
|
containerBlock.parentNode.insertBefore(newBlock, containerBlock);
|
|
}
|
|
} else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
|
|
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
|
} else {
|
|
containerBlock = getContainerBlock(containerBlock);
|
|
var tmpRng = rng.cloneRange();
|
|
tmpRng.setStartAfter(parentBlock);
|
|
tmpRng.setEndAfter(containerBlock);
|
|
var fragment = tmpRng.extractContents();
|
|
if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
|
|
newBlock = fragment.firstChild;
|
|
dom.insertAfter(fragment, containerBlock);
|
|
} else {
|
|
dom.insertAfter(fragment, containerBlock);
|
|
dom.insertAfter(newBlock, containerBlock);
|
|
}
|
|
}
|
|
dom.remove(parentBlock);
|
|
NewLineUtils.moveToCaretPosition(editor, newBlock);
|
|
};
|
|
var InsertLi = { insert: insert };
|
|
|
|
var trimZwsp = function (fragment) {
|
|
each(descendants(Element.fromDom(fragment), isText$1), function (text) {
|
|
var rawNode = text.dom();
|
|
rawNode.nodeValue = Zwsp.trim(rawNode.nodeValue);
|
|
});
|
|
};
|
|
var isEmptyAnchor = function (dom, elm) {
|
|
return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
|
|
};
|
|
var isTableCell$4 = function (node) {
|
|
return node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
|
|
};
|
|
var emptyBlock = function (elm) {
|
|
elm.innerHTML = '<br data-mce-bogus="1">';
|
|
};
|
|
var containerAndSiblingName = function (container, nodeName) {
|
|
return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
|
|
};
|
|
var canSplitBlock = function (dom, node) {
|
|
return node && dom.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom.getContentEditable(node) !== 'true';
|
|
};
|
|
var trimInlineElementsOnLeftSideOfBlock = function (dom, nonEmptyElementsMap, block) {
|
|
var node = block;
|
|
var firstChilds = [];
|
|
var i;
|
|
if (!node) {
|
|
return;
|
|
}
|
|
while (node = node.firstChild) {
|
|
if (dom.isBlock(node)) {
|
|
return;
|
|
}
|
|
if (NodeType.isElement(node) && !nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
|
firstChilds.push(node);
|
|
}
|
|
}
|
|
i = firstChilds.length;
|
|
while (i--) {
|
|
node = firstChilds[i];
|
|
if (!node.hasChildNodes() || node.firstChild === node.lastChild && node.firstChild.nodeValue === '') {
|
|
dom.remove(node);
|
|
} else {
|
|
if (isEmptyAnchor(dom, node)) {
|
|
dom.remove(node);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var normalizeZwspOffset = function (start, container, offset) {
|
|
if (NodeType.isText(container) === false) {
|
|
return offset;
|
|
} else if (start) {
|
|
return offset === 1 && container.data.charAt(offset - 1) === Zwsp.ZWSP ? 0 : offset;
|
|
} else {
|
|
return offset === container.data.length - 1 && container.data.charAt(offset) === Zwsp.ZWSP ? container.data.length : offset;
|
|
}
|
|
};
|
|
var includeZwspInRange = function (rng) {
|
|
var newRng = rng.cloneRange();
|
|
newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
|
|
newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
|
|
return newRng;
|
|
};
|
|
var trimLeadingLineBreaks = function (node) {
|
|
do {
|
|
if (NodeType.isText(node)) {
|
|
node.nodeValue = node.nodeValue.replace(/^[\r\n]+/, '');
|
|
}
|
|
node = node.firstChild;
|
|
} while (node);
|
|
};
|
|
var getEditableRoot$1 = function (dom, node) {
|
|
var root = dom.getRoot();
|
|
var parent, editableRoot;
|
|
parent = node;
|
|
while (parent !== root && dom.getContentEditable(parent) !== 'false') {
|
|
if (dom.getContentEditable(parent) === 'true') {
|
|
editableRoot = parent;
|
|
}
|
|
parent = parent.parentNode;
|
|
}
|
|
return parent !== root ? editableRoot : root;
|
|
};
|
|
var setForcedBlockAttrs = function (editor, node) {
|
|
var forcedRootBlockName = Settings.getForcedRootBlock(editor);
|
|
if (forcedRootBlockName && forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
|
|
editor.dom.setAttribs(node, Settings.getForcedRootBlockAttrs(editor));
|
|
}
|
|
};
|
|
var wrapSelfAndSiblingsInDefaultBlock = function (editor, newBlockName, rng, container, offset) {
|
|
var newBlock, parentBlock, startNode, node, next, rootBlockName;
|
|
var blockName = newBlockName || 'P';
|
|
var dom = editor.dom, editableRoot = getEditableRoot$1(dom, container);
|
|
parentBlock = dom.getParent(container, dom.isBlock);
|
|
if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
|
|
parentBlock = parentBlock || editableRoot;
|
|
if (parentBlock === editor.getBody() || isTableCell$4(parentBlock)) {
|
|
rootBlockName = parentBlock.nodeName.toLowerCase();
|
|
} else {
|
|
rootBlockName = parentBlock.parentNode.nodeName.toLowerCase();
|
|
}
|
|
if (!parentBlock.hasChildNodes()) {
|
|
newBlock = dom.create(blockName);
|
|
setForcedBlockAttrs(editor, newBlock);
|
|
parentBlock.appendChild(newBlock);
|
|
rng.setStart(newBlock, 0);
|
|
rng.setEnd(newBlock, 0);
|
|
return newBlock;
|
|
}
|
|
node = container;
|
|
while (node.parentNode !== parentBlock) {
|
|
node = node.parentNode;
|
|
}
|
|
while (node && !dom.isBlock(node)) {
|
|
startNode = node;
|
|
node = node.previousSibling;
|
|
}
|
|
if (startNode && editor.schema.isValidChild(rootBlockName, blockName.toLowerCase())) {
|
|
newBlock = dom.create(blockName);
|
|
setForcedBlockAttrs(editor, newBlock);
|
|
startNode.parentNode.insertBefore(newBlock, startNode);
|
|
node = startNode;
|
|
while (node && !dom.isBlock(node)) {
|
|
next = node.nextSibling;
|
|
newBlock.appendChild(node);
|
|
node = next;
|
|
}
|
|
rng.setStart(container, offset);
|
|
rng.setEnd(container, offset);
|
|
}
|
|
}
|
|
return container;
|
|
};
|
|
var addBrToBlockIfNeeded = function (dom, block) {
|
|
var lastChild;
|
|
block.normalize();
|
|
lastChild = block.lastChild;
|
|
if (!lastChild || /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
|
|
dom.add(block, 'br');
|
|
}
|
|
};
|
|
var insert$1 = function (editor, evt) {
|
|
var tmpRng, editableRoot, container, offset, parentBlock, shiftKey;
|
|
var newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
|
|
var dom = editor.dom;
|
|
var schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
|
|
var rng = editor.selection.getRng();
|
|
var createNewBlock = function (name) {
|
|
var node = container, block, clonedNode, caretNode;
|
|
var textInlineElements = schema.getTextInlineElements();
|
|
if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
|
|
block = dom.create(name || newBlockName);
|
|
setForcedBlockAttrs(editor, block);
|
|
} else {
|
|
block = parentBlock.cloneNode(false);
|
|
}
|
|
caretNode = block;
|
|
if (Settings.shouldKeepStyles(editor) === false) {
|
|
dom.setAttrib(block, 'style', null);
|
|
dom.setAttrib(block, 'class', null);
|
|
} else {
|
|
do {
|
|
if (textInlineElements[node.nodeName]) {
|
|
if (isCaretNode(node) || Bookmarks.isBookmarkNode(node)) {
|
|
continue;
|
|
}
|
|
clonedNode = node.cloneNode(false);
|
|
dom.setAttrib(clonedNode, 'id', '');
|
|
if (block.hasChildNodes()) {
|
|
clonedNode.appendChild(block.firstChild);
|
|
block.appendChild(clonedNode);
|
|
} else {
|
|
caretNode = clonedNode;
|
|
block.appendChild(clonedNode);
|
|
}
|
|
}
|
|
} while ((node = node.parentNode) && node !== editableRoot);
|
|
}
|
|
emptyBlock(caretNode);
|
|
return block;
|
|
};
|
|
var isCaretAtStartOrEndOfBlock = function (start) {
|
|
var node, name;
|
|
var normalizedOffset = normalizeZwspOffset(start, container, offset);
|
|
if (NodeType.isText(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.nodeValue.length)) {
|
|
return false;
|
|
}
|
|
if (container.parentNode === parentBlock && isAfterLastNodeInContainer && !start) {
|
|
return true;
|
|
}
|
|
if (start && NodeType.isElement(container) && container === parentBlock.firstChild) {
|
|
return true;
|
|
}
|
|
if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
|
|
return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
|
|
}
|
|
var walker = new TreeWalker(container, parentBlock);
|
|
if (NodeType.isText(container)) {
|
|
if (start && normalizedOffset === 0) {
|
|
walker.prev();
|
|
} else if (!start && normalizedOffset === container.nodeValue.length) {
|
|
walker.next();
|
|
}
|
|
}
|
|
while (node = walker.current()) {
|
|
if (NodeType.isElement(node)) {
|
|
if (!node.getAttribute('data-mce-bogus')) {
|
|
name = node.nodeName.toLowerCase();
|
|
if (nonEmptyElementsMap[name] && name !== 'br') {
|
|
return false;
|
|
}
|
|
}
|
|
} else if (NodeType.isText(node) && !/^[ \t\r\n]*$/.test(node.nodeValue)) {
|
|
return false;
|
|
}
|
|
if (start) {
|
|
walker.prev();
|
|
} else {
|
|
walker.next();
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
var insertNewBlockAfter = function () {
|
|
if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
|
|
newBlock = createNewBlock(newBlockName);
|
|
} else {
|
|
newBlock = createNewBlock();
|
|
}
|
|
if (Settings.shouldEndContainerOnEmptyBlock(editor) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock)) {
|
|
newBlock = dom.split(containerBlock, parentBlock);
|
|
} else {
|
|
dom.insertAfter(newBlock, parentBlock);
|
|
}
|
|
NewLineUtils.moveToCaretPosition(editor, newBlock);
|
|
};
|
|
NormalizeRange.normalize(dom, rng).each(function (normRng) {
|
|
rng.setStart(normRng.startContainer, normRng.startOffset);
|
|
rng.setEnd(normRng.endContainer, normRng.endOffset);
|
|
});
|
|
container = rng.startContainer;
|
|
offset = rng.startOffset;
|
|
newBlockName = Settings.getForcedRootBlock(editor);
|
|
shiftKey = !!(evt && evt.shiftKey);
|
|
var ctrlKey = !!(evt && evt.ctrlKey);
|
|
if (NodeType.isElement(container) && container.hasChildNodes()) {
|
|
isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
|
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
|
if (isAfterLastNodeInContainer && NodeType.isText(container)) {
|
|
offset = container.nodeValue.length;
|
|
} else {
|
|
offset = 0;
|
|
}
|
|
}
|
|
editableRoot = getEditableRoot$1(dom, container);
|
|
if (!editableRoot) {
|
|
return;
|
|
}
|
|
if (newBlockName && !shiftKey || !newBlockName && shiftKey) {
|
|
container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
|
|
}
|
|
parentBlock = dom.getParent(container, dom.isBlock);
|
|
containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
|
parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
|
|
containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
|
|
if (containerBlockName === 'LI' && !ctrlKey) {
|
|
parentBlock = containerBlock;
|
|
containerBlock = containerBlock.parentNode;
|
|
parentBlockName = containerBlockName;
|
|
}
|
|
if (/^(LI|DT|DD)$/.test(parentBlockName)) {
|
|
if (dom.isEmpty(parentBlock)) {
|
|
InsertLi.insert(editor, createNewBlock, containerBlock, parentBlock, newBlockName);
|
|
return;
|
|
}
|
|
}
|
|
if (newBlockName && parentBlock === editor.getBody()) {
|
|
return;
|
|
}
|
|
newBlockName = newBlockName || 'P';
|
|
if (isCaretContainerBlock(parentBlock)) {
|
|
newBlock = showCaretContainerBlock(parentBlock);
|
|
if (dom.isEmpty(parentBlock)) {
|
|
emptyBlock(parentBlock);
|
|
}
|
|
NewLineUtils.moveToCaretPosition(editor, newBlock);
|
|
} else if (isCaretAtStartOrEndOfBlock()) {
|
|
insertNewBlockAfter();
|
|
} else if (isCaretAtStartOrEndOfBlock(true)) {
|
|
newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
|
|
NewLineUtils.moveToCaretPosition(editor, containerAndSiblingName(parentBlock, 'HR') ? newBlock : parentBlock);
|
|
} else {
|
|
tmpRng = includeZwspInRange(rng).cloneRange();
|
|
tmpRng.setEndAfter(parentBlock);
|
|
fragment = tmpRng.extractContents();
|
|
trimZwsp(fragment);
|
|
trimLeadingLineBreaks(fragment);
|
|
newBlock = fragment.firstChild;
|
|
dom.insertAfter(fragment, parentBlock);
|
|
trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
|
|
addBrToBlockIfNeeded(dom, parentBlock);
|
|
if (dom.isEmpty(parentBlock)) {
|
|
emptyBlock(parentBlock);
|
|
}
|
|
newBlock.normalize();
|
|
if (dom.isEmpty(newBlock)) {
|
|
dom.remove(newBlock);
|
|
insertNewBlockAfter();
|
|
} else {
|
|
NewLineUtils.moveToCaretPosition(editor, newBlock);
|
|
}
|
|
}
|
|
dom.setAttrib(newBlock, 'id', '');
|
|
editor.fire('NewBlock', { newBlock: newBlock });
|
|
};
|
|
var InsertBlock = { insert: insert$1 };
|
|
|
|
var hasRightSideContent = function (schema, container, parentBlock) {
|
|
var walker = new TreeWalker(container, parentBlock);
|
|
var node;
|
|
var nonEmptyElementsMap = schema.getNonEmptyElements();
|
|
while (node = walker.next()) {
|
|
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
var scrollToBr = function (dom, selection, brElm) {
|
|
var marker = dom.create('span', {}, ' ');
|
|
brElm.parentNode.insertBefore(marker, brElm);
|
|
selection.scrollIntoView(marker);
|
|
dom.remove(marker);
|
|
};
|
|
var moveSelectionToBr = function (dom, selection, brElm, extraBr) {
|
|
var rng = dom.createRng();
|
|
if (!extraBr) {
|
|
rng.setStartAfter(brElm);
|
|
rng.setEndAfter(brElm);
|
|
} else {
|
|
rng.setStartBefore(brElm);
|
|
rng.setEndBefore(brElm);
|
|
}
|
|
selection.setRng(rng);
|
|
};
|
|
var insertBrAtCaret = function (editor, evt) {
|
|
var selection = editor.selection;
|
|
var dom = editor.dom;
|
|
var rng = selection.getRng();
|
|
var brElm;
|
|
var extraBr;
|
|
NormalizeRange.normalize(dom, rng).each(function (normRng) {
|
|
rng.setStart(normRng.startContainer, normRng.startOffset);
|
|
rng.setEnd(normRng.endContainer, normRng.endOffset);
|
|
});
|
|
var offset = rng.startOffset;
|
|
var container = rng.startContainer;
|
|
if (container.nodeType === 1 && container.hasChildNodes()) {
|
|
var isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
|
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
|
if (isAfterLastNodeInContainer && container.nodeType === 3) {
|
|
offset = container.nodeValue.length;
|
|
} else {
|
|
offset = 0;
|
|
}
|
|
}
|
|
var parentBlock = dom.getParent(container, dom.isBlock);
|
|
var containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
|
var containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
|
|
var isControlKey = !!(evt && evt.ctrlKey);
|
|
if (containerBlockName === 'LI' && !isControlKey) {
|
|
parentBlock = containerBlock;
|
|
}
|
|
if (container && container.nodeType === 3 && offset >= container.nodeValue.length) {
|
|
if (!hasRightSideContent(editor.schema, container, parentBlock)) {
|
|
brElm = dom.create('br');
|
|
rng.insertNode(brElm);
|
|
rng.setStartAfter(brElm);
|
|
rng.setEndAfter(brElm);
|
|
extraBr = true;
|
|
}
|
|
}
|
|
brElm = dom.create('br');
|
|
rangeInsertNode(dom, rng, brElm);
|
|
scrollToBr(dom, selection, brElm);
|
|
moveSelectionToBr(dom, selection, brElm, extraBr);
|
|
editor.undoManager.add();
|
|
};
|
|
var insertBrBefore = function (editor, inline) {
|
|
var br = Element.fromTag('br');
|
|
before(Element.fromDom(inline), br);
|
|
editor.undoManager.add();
|
|
};
|
|
var insertBrAfter = function (editor, inline) {
|
|
if (!hasBrAfter(editor.getBody(), inline)) {
|
|
after(Element.fromDom(inline), Element.fromTag('br'));
|
|
}
|
|
var br = Element.fromTag('br');
|
|
after(Element.fromDom(inline), br);
|
|
scrollToBr(editor.dom, editor.selection, br.dom());
|
|
moveSelectionToBr(editor.dom, editor.selection, br.dom(), false);
|
|
editor.undoManager.add();
|
|
};
|
|
var isBeforeBr$1 = function (pos) {
|
|
return NodeType.isBr(pos.getNode());
|
|
};
|
|
var hasBrAfter = function (rootNode, startNode) {
|
|
if (isBeforeBr$1(CaretPosition$1.after(startNode))) {
|
|
return true;
|
|
} else {
|
|
return CaretFinder.nextPosition(rootNode, CaretPosition$1.after(startNode)).map(function (pos) {
|
|
return NodeType.isBr(pos.getNode());
|
|
}).getOr(false);
|
|
}
|
|
};
|
|
var isAnchorLink = function (elm) {
|
|
return elm && elm.nodeName === 'A' && 'href' in elm;
|
|
};
|
|
var isInsideAnchor = function (location) {
|
|
return location.fold(constant(false), isAnchorLink, isAnchorLink, constant(false));
|
|
};
|
|
var readInlineAnchorLocation = function (editor) {
|
|
var isInlineTarget = curry(InlineUtils.isInlineTarget, editor);
|
|
var position = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return BoundaryLocation.readLocation(isInlineTarget, editor.getBody(), position).filter(isInsideAnchor);
|
|
};
|
|
var insertBrOutsideAnchor = function (editor, location) {
|
|
location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
|
|
};
|
|
var insert$2 = function (editor, evt) {
|
|
var anchorLocation = readInlineAnchorLocation(editor);
|
|
if (anchorLocation.isSome()) {
|
|
anchorLocation.each(curry(insertBrOutsideAnchor, editor));
|
|
} else {
|
|
insertBrAtCaret(editor, evt);
|
|
}
|
|
};
|
|
var InsertBr = { insert: insert$2 };
|
|
|
|
var matchesSelector = function (editor, selector) {
|
|
return NewLineUtils.getParentBlock(editor).filter(function (parentBlock) {
|
|
return selector.length > 0 && is(Element.fromDom(parentBlock), selector);
|
|
}).isSome();
|
|
};
|
|
var shouldInsertBr = function (editor) {
|
|
return matchesSelector(editor, Settings.getBrNewLineSelector(editor));
|
|
};
|
|
var shouldBlockNewLine = function (editor) {
|
|
return matchesSelector(editor, Settings.getNoNewLineSelector(editor));
|
|
};
|
|
var ContextSelectors = {
|
|
shouldInsertBr: shouldInsertBr,
|
|
shouldBlockNewLine: shouldBlockNewLine
|
|
};
|
|
|
|
var newLineAction = Adt.generate([
|
|
{ br: [] },
|
|
{ block: [] },
|
|
{ none: [] }
|
|
]);
|
|
var shouldBlockNewLine$1 = function (editor, shiftKey) {
|
|
return ContextSelectors.shouldBlockNewLine(editor);
|
|
};
|
|
var isBrMode = function (requiredState) {
|
|
return function (editor, shiftKey) {
|
|
var brMode = Settings.getForcedRootBlock(editor) === '';
|
|
return brMode === requiredState;
|
|
};
|
|
};
|
|
var inListBlock = function (requiredState) {
|
|
return function (editor, shiftKey) {
|
|
return NewLineUtils.isListItemParentBlock(editor) === requiredState;
|
|
};
|
|
};
|
|
var inBlock = function (blockName, requiredState) {
|
|
return function (editor, shiftKey) {
|
|
var state = NewLineUtils.getParentBlockName(editor) === blockName.toUpperCase();
|
|
return state === requiredState;
|
|
};
|
|
};
|
|
var inPreBlock = function (requiredState) {
|
|
return inBlock('pre', requiredState);
|
|
};
|
|
var inSummaryBlock = function () {
|
|
return inBlock('summary', true);
|
|
};
|
|
var shouldPutBrInPre$1 = function (requiredState) {
|
|
return function (editor, shiftKey) {
|
|
return Settings.shouldPutBrInPre(editor) === requiredState;
|
|
};
|
|
};
|
|
var inBrContext = function (editor, shiftKey) {
|
|
return ContextSelectors.shouldInsertBr(editor);
|
|
};
|
|
var hasShiftKey = function (editor, shiftKey) {
|
|
return shiftKey;
|
|
};
|
|
var canInsertIntoEditableRoot = function (editor) {
|
|
var forcedRootBlock = Settings.getForcedRootBlock(editor);
|
|
var rootEditable = NewLineUtils.getEditableRoot(editor.dom, editor.selection.getStart());
|
|
return rootEditable && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock ? forcedRootBlock : 'P');
|
|
};
|
|
var match$2 = function (predicates, action) {
|
|
return function (editor, shiftKey) {
|
|
var isMatch = foldl(predicates, function (res, p) {
|
|
return res && p(editor, shiftKey);
|
|
}, true);
|
|
return isMatch ? Option.some(action) : Option.none();
|
|
};
|
|
};
|
|
var getAction$1 = function (editor, evt) {
|
|
return LazyEvaluator.evaluateUntil([
|
|
match$2([shouldBlockNewLine$1], newLineAction.none()),
|
|
match$2([inSummaryBlock()], newLineAction.br()),
|
|
match$2([
|
|
inPreBlock(true),
|
|
shouldPutBrInPre$1(false),
|
|
hasShiftKey
|
|
], newLineAction.br()),
|
|
match$2([
|
|
inPreBlock(true),
|
|
shouldPutBrInPre$1(false)
|
|
], newLineAction.block()),
|
|
match$2([
|
|
inPreBlock(true),
|
|
shouldPutBrInPre$1(true),
|
|
hasShiftKey
|
|
], newLineAction.block()),
|
|
match$2([
|
|
inPreBlock(true),
|
|
shouldPutBrInPre$1(true)
|
|
], newLineAction.br()),
|
|
match$2([
|
|
inListBlock(true),
|
|
hasShiftKey
|
|
], newLineAction.br()),
|
|
match$2([inListBlock(true)], newLineAction.block()),
|
|
match$2([
|
|
isBrMode(true),
|
|
hasShiftKey,
|
|
canInsertIntoEditableRoot
|
|
], newLineAction.block()),
|
|
match$2([isBrMode(true)], newLineAction.br()),
|
|
match$2([inBrContext], newLineAction.br()),
|
|
match$2([
|
|
isBrMode(false),
|
|
hasShiftKey
|
|
], newLineAction.br()),
|
|
match$2([canInsertIntoEditableRoot], newLineAction.block())
|
|
], [
|
|
editor,
|
|
!!(evt && evt.shiftKey)
|
|
]).getOr(newLineAction.none());
|
|
};
|
|
var NewLineAction = { getAction: getAction$1 };
|
|
|
|
var insert$3 = function (editor, evt) {
|
|
NewLineAction.getAction(editor, evt).fold(function () {
|
|
InsertBr.insert(editor, evt);
|
|
}, function () {
|
|
InsertBlock.insert(editor, evt);
|
|
}, noop);
|
|
};
|
|
var InsertNewLine = { insert: insert$3 };
|
|
|
|
var handleEnterKeyEvent = function (editor, event) {
|
|
if (event.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
endTypingLevelIgnoreLocks(editor.undoManager);
|
|
editor.undoManager.transact(function () {
|
|
if (editor.selection.isCollapsed() === false) {
|
|
editor.execCommand('Delete');
|
|
}
|
|
InsertNewLine.insert(editor, event);
|
|
});
|
|
};
|
|
var setup$a = function (editor) {
|
|
editor.on('keydown', function (event) {
|
|
if (event.keyCode === VK.ENTER) {
|
|
handleEnterKeyEvent(editor, event);
|
|
}
|
|
});
|
|
};
|
|
var EnterKey = { setup: setup$a };
|
|
|
|
var insertTextAtPosition = function (text, pos) {
|
|
var container = pos.container();
|
|
var offset = pos.offset();
|
|
if (NodeType.isText(container)) {
|
|
container.insertData(offset, text);
|
|
return Option.some(CaretPosition(container, offset + text.length));
|
|
} else {
|
|
return getElementFromPosition(pos).map(function (elm) {
|
|
var textNode = Element.fromText(text);
|
|
if (pos.isAtEnd()) {
|
|
after(elm, textNode);
|
|
} else {
|
|
before(elm, textNode);
|
|
}
|
|
return CaretPosition(textNode.dom(), text.length);
|
|
});
|
|
}
|
|
};
|
|
var insertNbspAtPosition = curry(insertTextAtPosition, '\xA0');
|
|
var insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
|
|
|
|
var nbsp = '\xA0';
|
|
var isInMiddleOfText = function (pos) {
|
|
return CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
|
|
};
|
|
var getClosestBlock$1 = function (root, pos) {
|
|
var parentBlocks = filter(Parents.parentsAndSelf(Element.fromDom(pos.container()), root), isBlock);
|
|
return head(parentBlocks).getOr(root);
|
|
};
|
|
var hasSpaceBefore = function (root, pos) {
|
|
if (isInMiddleOfText(pos)) {
|
|
return isAfterSpace(pos);
|
|
} else {
|
|
return isAfterSpace(pos) || CaretFinder.prevPosition(getClosestBlock$1(root, pos).dom(), pos).exists(isAfterSpace);
|
|
}
|
|
};
|
|
var hasSpaceAfter = function (root, pos) {
|
|
if (isInMiddleOfText(pos)) {
|
|
return isBeforeSpace(pos);
|
|
} else {
|
|
return isBeforeSpace(pos) || CaretFinder.nextPosition(getClosestBlock$1(root, pos).dom(), pos).exists(isBeforeSpace);
|
|
}
|
|
};
|
|
var isPreValue = function (value) {
|
|
return contains([
|
|
'pre',
|
|
'pre-wrap'
|
|
], value);
|
|
};
|
|
var isInPre = function (pos) {
|
|
return getElementFromPosition(pos).bind(function (elm) {
|
|
return closest(elm, isElement$1);
|
|
}).exists(function (elm) {
|
|
return isPreValue(get$2(elm, 'white-space'));
|
|
});
|
|
};
|
|
var isAtBeginningOfBody = function (root, pos) {
|
|
return CaretFinder.prevPosition(root.dom(), pos).isNone();
|
|
};
|
|
var isAtEndOfBody = function (root, pos) {
|
|
return CaretFinder.nextPosition(root.dom(), pos).isNone();
|
|
};
|
|
var isAtLineBoundary = function (root, pos) {
|
|
return isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos) || isAtEndOfBlock(root, pos) || isAfterBr(root, pos) || isBeforeBr(root, pos);
|
|
};
|
|
var needsToHaveNbsp = function (root, pos) {
|
|
if (isInPre(pos)) {
|
|
return false;
|
|
} else {
|
|
return isAtLineBoundary(root, pos) || hasSpaceBefore(root, pos) || hasSpaceAfter(root, pos);
|
|
}
|
|
};
|
|
var needsToBeNbspLeft = function (root, pos) {
|
|
if (isInPre(pos)) {
|
|
return false;
|
|
} else {
|
|
return isAtStartOfBlock(root, pos) || isBeforeBlock(root, pos) || isAfterBr(root, pos) || hasSpaceBefore(root, pos);
|
|
}
|
|
};
|
|
var leanRight = function (pos) {
|
|
var container = pos.container();
|
|
var offset = pos.offset();
|
|
if (NodeType.isText(container) && offset < container.data.length) {
|
|
return CaretPosition(container, offset + 1);
|
|
} else {
|
|
return pos;
|
|
}
|
|
};
|
|
var needsToBeNbspRight = function (root, pos) {
|
|
var afterPos = leanRight(pos);
|
|
if (isInPre(afterPos)) {
|
|
return false;
|
|
} else {
|
|
return isAtEndOfBlock(root, afterPos) || isAfterBlock(root, afterPos) || isBeforeBr(root, afterPos) || hasSpaceAfter(root, afterPos);
|
|
}
|
|
};
|
|
var needsToBeNbsp = function (root, pos) {
|
|
return needsToBeNbspLeft(root, pos) || needsToBeNbspRight(root, pos);
|
|
};
|
|
var isNbspAt = function (text, offset) {
|
|
return isNbsp(text.charAt(offset));
|
|
};
|
|
var hasNbsp = function (pos) {
|
|
var container = pos.container();
|
|
return NodeType.isText(container) && contains$1(container.data, nbsp);
|
|
};
|
|
var normalizeNbspMiddle = function (text) {
|
|
var chars = text.split('');
|
|
return map(chars, function (chr, i) {
|
|
if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
|
|
return ' ';
|
|
} else {
|
|
return chr;
|
|
}
|
|
}).join('');
|
|
};
|
|
var normalizeNbspAtStart = function (root, node) {
|
|
var text = node.data;
|
|
var firstPos = CaretPosition(node, 0);
|
|
if (isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos)) {
|
|
node.data = ' ' + text.slice(1);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var normalizeNbspInMiddleOfTextNode = function (node) {
|
|
var text = node.data;
|
|
var newText = normalizeNbspMiddle(text);
|
|
if (newText !== text) {
|
|
node.data = newText;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var normalizeNbspAtEnd = function (root, node) {
|
|
var text = node.data;
|
|
var lastPos = CaretPosition(node, text.length - 1);
|
|
if (isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos)) {
|
|
node.data = text.slice(0, -1) + ' ';
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
var normalizeNbsps = function (root, pos) {
|
|
return Option.some(pos).filter(hasNbsp).bind(function (pos) {
|
|
var container = pos.container();
|
|
var normalized = normalizeNbspAtStart(root, container) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container);
|
|
return normalized ? Option.some(pos) : Option.none();
|
|
});
|
|
};
|
|
var normalizeNbspsInEditor = function (editor) {
|
|
var root = Element.fromDom(editor.getBody());
|
|
if (editor.selection.isCollapsed()) {
|
|
normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng())).each(function (pos) {
|
|
editor.selection.setRng(pos.toRange());
|
|
});
|
|
}
|
|
};
|
|
|
|
var locationToCaretPosition = function (root) {
|
|
return function (location) {
|
|
return location.fold(function (element) {
|
|
return CaretFinder.prevPosition(root.dom(), CaretPosition$1.before(element));
|
|
}, function (element) {
|
|
return CaretFinder.firstPositionIn(element);
|
|
}, function (element) {
|
|
return CaretFinder.lastPositionIn(element);
|
|
}, function (element) {
|
|
return CaretFinder.nextPosition(root.dom(), CaretPosition$1.after(element));
|
|
});
|
|
};
|
|
};
|
|
var insertInlineBoundarySpaceOrNbsp = function (root, pos) {
|
|
return function (checkPos) {
|
|
return needsToHaveNbsp(root, checkPos) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
|
|
};
|
|
};
|
|
var setSelection$1 = function (editor) {
|
|
return function (pos) {
|
|
editor.selection.setRng(pos.toRange());
|
|
editor.nodeChanged();
|
|
return true;
|
|
};
|
|
};
|
|
var insertSpaceOrNbspAtSelection = function (editor) {
|
|
var pos = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
var root = Element.fromDom(editor.getBody());
|
|
if (editor.selection.isCollapsed()) {
|
|
var isInlineTarget = curry(InlineUtils.isInlineTarget, editor);
|
|
var caretPosition = CaretPosition$1.fromRangeStart(editor.selection.getRng());
|
|
return BoundaryLocation.readLocation(isInlineTarget, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).bind(insertInlineBoundarySpaceOrNbsp(root, pos)).exists(setSelection$1(editor));
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
var executeKeydownOverride$2 = function (editor, evt) {
|
|
MatchKeys.execute([{
|
|
keyCode: VK.SPACEBAR,
|
|
action: MatchKeys.action(insertSpaceOrNbspAtSelection, editor)
|
|
}], evt).each(function (_) {
|
|
evt.preventDefault();
|
|
});
|
|
};
|
|
var setup$b = function (editor) {
|
|
editor.on('keydown', function (evt) {
|
|
if (evt.isDefaultPrevented() === false) {
|
|
executeKeydownOverride$2(editor, evt);
|
|
}
|
|
});
|
|
};
|
|
var SpaceKey = { setup: setup$b };
|
|
|
|
var findBlockCaretContainer = function (editor) {
|
|
return descendant(Element.fromDom(editor.getBody()), '*[data-mce-caret]').fold(constant(null), function (elm) {
|
|
return elm.dom();
|
|
});
|
|
};
|
|
var removeIeControlRect = function (editor) {
|
|
editor.selection.setRng(editor.selection.getRng());
|
|
};
|
|
var showBlockCaretContainer = function (editor, blockCaretContainer) {
|
|
if (blockCaretContainer.hasAttribute('data-mce-caret')) {
|
|
showCaretContainerBlock(blockCaretContainer);
|
|
removeIeControlRect(editor);
|
|
editor.selection.scrollIntoView(blockCaretContainer);
|
|
}
|
|
};
|
|
var handleBlockContainer = function (editor, e) {
|
|
var blockCaretContainer = findBlockCaretContainer(editor);
|
|
if (!blockCaretContainer) {
|
|
return;
|
|
}
|
|
if (e.type === 'compositionstart') {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
showBlockCaretContainer(editor, blockCaretContainer);
|
|
return;
|
|
}
|
|
if (hasContent(blockCaretContainer)) {
|
|
showBlockCaretContainer(editor, blockCaretContainer);
|
|
editor.undoManager.add();
|
|
}
|
|
};
|
|
var setup$c = function (editor) {
|
|
editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
|
|
};
|
|
var CaretContainerInput = { setup: setup$c };
|
|
|
|
var browser$5 = detect$3().browser;
|
|
var setupIeInput = function (editor) {
|
|
var keypressThrotter = first(function () {
|
|
if (!editor.composing) {
|
|
normalizeNbspsInEditor(editor);
|
|
}
|
|
}, 0);
|
|
if (browser$5.isIE()) {
|
|
editor.on('keypress', function (e) {
|
|
keypressThrotter.throttle();
|
|
});
|
|
editor.on('remove', function (e) {
|
|
keypressThrotter.cancel();
|
|
});
|
|
}
|
|
};
|
|
var setup$d = function (editor) {
|
|
setupIeInput(editor);
|
|
editor.on('input', function (e) {
|
|
if (e.isComposing === false) {
|
|
normalizeNbspsInEditor(editor);
|
|
}
|
|
});
|
|
};
|
|
|
|
var executeKeydownOverride$3 = function (editor, evt) {
|
|
MatchKeys.execute([
|
|
{
|
|
keyCode: VK.END,
|
|
action: moveToLineEndPoint(editor, true)
|
|
},
|
|
{
|
|
keyCode: VK.HOME,
|
|
action: moveToLineEndPoint(editor, false)
|
|
}
|
|
], evt).each(function (_) {
|
|
evt.preventDefault();
|
|
});
|
|
};
|
|
var setup$e = function (editor) {
|
|
editor.on('keydown', function (evt) {
|
|
if (evt.isDefaultPrevented() === false) {
|
|
executeKeydownOverride$3(editor, evt);
|
|
}
|
|
});
|
|
};
|
|
var HomeEndKeys = { setup: setup$e };
|
|
|
|
var setup$f = function (editor) {
|
|
var caret = BoundarySelection.setupSelectedState(editor);
|
|
CaretContainerInput.setup(editor);
|
|
ArrowKeys.setup(editor, caret);
|
|
DeleteBackspaceKeys.setup(editor, caret);
|
|
EnterKey.setup(editor);
|
|
SpaceKey.setup(editor);
|
|
setup$d(editor);
|
|
HomeEndKeys.setup(editor);
|
|
};
|
|
var KeyboardOverrides = { setup: setup$f };
|
|
|
|
var Quirks = function (editor) {
|
|
var each = Tools.each;
|
|
var BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, settings = editor.settings, parser = editor.parser;
|
|
var isGecko = Env.gecko, isIE = Env.ie, isWebKit = Env.webkit;
|
|
var mceInternalUrlPrefix = 'data:text/mce-internal,';
|
|
var mceInternalDataType = isIE ? 'Text' : 'URL';
|
|
var setEditorCommandState = function (cmd, state) {
|
|
try {
|
|
editor.getDoc().execCommand(cmd, false, state);
|
|
} catch (ex) {
|
|
}
|
|
};
|
|
var isDefaultPrevented = function (e) {
|
|
return e.isDefaultPrevented();
|
|
};
|
|
var setMceInternalContent = function (e) {
|
|
var selectionHtml, internalContent;
|
|
if (e.dataTransfer) {
|
|
if (editor.selection.isCollapsed() && e.target.tagName === 'IMG') {
|
|
selection.select(e.target);
|
|
}
|
|
selectionHtml = editor.selection.getContent();
|
|
if (selectionHtml.length > 0) {
|
|
internalContent = mceInternalUrlPrefix + escape(editor.id) + ',' + escape(selectionHtml);
|
|
e.dataTransfer.setData(mceInternalDataType, internalContent);
|
|
}
|
|
}
|
|
};
|
|
var getMceInternalContent = function (e) {
|
|
var internalContent;
|
|
if (e.dataTransfer) {
|
|
internalContent = e.dataTransfer.getData(mceInternalDataType);
|
|
if (internalContent && internalContent.indexOf(mceInternalUrlPrefix) >= 0) {
|
|
internalContent = internalContent.substr(mceInternalUrlPrefix.length).split(',');
|
|
return {
|
|
id: unescape(internalContent[0]),
|
|
html: unescape(internalContent[1])
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var insertClipboardContents = function (content, internal) {
|
|
if (editor.queryCommandSupported('mceInsertClipboardContent')) {
|
|
editor.execCommand('mceInsertClipboardContent', false, {
|
|
content: content,
|
|
internal: internal
|
|
});
|
|
} else {
|
|
editor.execCommand('mceInsertContent', false, content);
|
|
}
|
|
};
|
|
var emptyEditorWhenDeleting = function () {
|
|
var serializeRng = function (rng) {
|
|
var body = dom.create('body');
|
|
var contents = rng.cloneContents();
|
|
body.appendChild(contents);
|
|
return selection.serializer.serialize(body, { format: 'html' });
|
|
};
|
|
var allContentsSelected = function (rng) {
|
|
var selection = serializeRng(rng);
|
|
var allRng = dom.createRng();
|
|
allRng.selectNode(editor.getBody());
|
|
var allSelection = serializeRng(allRng);
|
|
return selection === allSelection;
|
|
};
|
|
editor.on('keydown', function (e) {
|
|
var keyCode = e.keyCode;
|
|
var isCollapsed, body;
|
|
if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE)) {
|
|
isCollapsed = editor.selection.isCollapsed();
|
|
body = editor.getBody();
|
|
if (isCollapsed && !dom.isEmpty(body)) {
|
|
return;
|
|
}
|
|
if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
editor.setContent('');
|
|
if (body.firstChild && dom.isBlock(body.firstChild)) {
|
|
editor.selection.setCursorLocation(body.firstChild, 0);
|
|
} else {
|
|
editor.selection.setCursorLocation(body, 0);
|
|
}
|
|
editor.nodeChanged();
|
|
}
|
|
});
|
|
};
|
|
var selectAll = function () {
|
|
editor.shortcuts.add('meta+a', null, 'SelectAll');
|
|
};
|
|
var inputMethodFocus = function () {
|
|
if (!editor.inline) {
|
|
dom.bind(editor.getDoc(), 'mousedown mouseup', function (e) {
|
|
var rng;
|
|
if (e.target === editor.getDoc().documentElement) {
|
|
rng = selection.getRng();
|
|
editor.getBody().focus();
|
|
if (e.type === 'mousedown') {
|
|
if (isCaretContainer(rng.startContainer)) {
|
|
return;
|
|
}
|
|
selection.placeCaretAt(e.clientX, e.clientY);
|
|
} else {
|
|
selection.setRng(rng);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var removeHrOnBackspace = function () {
|
|
editor.on('keydown', function (e) {
|
|
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
|
if (!editor.getBody().getElementsByTagName('hr').length) {
|
|
return;
|
|
}
|
|
if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
|
|
var node = selection.getNode();
|
|
var previousSibling = node.previousSibling;
|
|
if (node.nodeName === 'HR') {
|
|
dom.remove(node);
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
|
|
dom.remove(previousSibling);
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
};
|
|
var focusBody = function () {
|
|
if (!domGlobals.Range.prototype.getClientRects) {
|
|
editor.on('mousedown', function (e) {
|
|
if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
|
|
var body_1 = editor.getBody();
|
|
body_1.blur();
|
|
Delay.setEditorTimeout(editor, function () {
|
|
body_1.focus();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var selectControlElements = function () {
|
|
editor.on('click', function (e) {
|
|
var target = e.target;
|
|
if (/^(IMG|HR)$/.test(target.nodeName) && dom.getContentEditableParent(target) !== 'false') {
|
|
e.preventDefault();
|
|
editor.selection.select(target);
|
|
editor.nodeChanged();
|
|
}
|
|
if (target.nodeName === 'A' && dom.hasClass(target, 'mce-item-anchor')) {
|
|
e.preventDefault();
|
|
selection.select(target);
|
|
}
|
|
});
|
|
};
|
|
var removeStylesWhenDeletingAcrossBlockElements = function () {
|
|
var getAttributeApplyFunction = function () {
|
|
var template = dom.getAttribs(selection.getStart().cloneNode(false));
|
|
return function () {
|
|
var target = selection.getStart();
|
|
if (target !== editor.getBody()) {
|
|
dom.setAttrib(target, 'style', null);
|
|
each(template, function (attr) {
|
|
target.setAttributeNode(attr.cloneNode(true));
|
|
});
|
|
}
|
|
};
|
|
};
|
|
var isSelectionAcrossElements = function () {
|
|
return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
|
|
};
|
|
editor.on('keypress', function (e) {
|
|
var applyAttributes;
|
|
if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
|
|
applyAttributes = getAttributeApplyFunction();
|
|
editor.getDoc().execCommand('delete', false, null);
|
|
applyAttributes();
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
dom.bind(editor.getDoc(), 'cut', function (e) {
|
|
var applyAttributes;
|
|
if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
|
|
applyAttributes = getAttributeApplyFunction();
|
|
Delay.setEditorTimeout(editor, function () {
|
|
applyAttributes();
|
|
});
|
|
}
|
|
});
|
|
};
|
|
var disableBackspaceIntoATable = function () {
|
|
editor.on('keydown', function (e) {
|
|
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
|
if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
|
|
var previousSibling = selection.getNode().previousSibling;
|
|
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
};
|
|
var removeBlockQuoteOnBackSpace = function () {
|
|
editor.on('keydown', function (e) {
|
|
var rng, container, offset, root, parent;
|
|
if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
|
|
return;
|
|
}
|
|
rng = selection.getRng();
|
|
container = rng.startContainer;
|
|
offset = rng.startOffset;
|
|
root = dom.getRoot();
|
|
parent = container;
|
|
if (!rng.collapsed || offset !== 0) {
|
|
return;
|
|
}
|
|
while (parent && parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
|
|
parent = parent.parentNode;
|
|
}
|
|
if (parent.tagName === 'BLOCKQUOTE') {
|
|
editor.formatter.toggle('blockquote', null, parent);
|
|
rng = dom.createRng();
|
|
rng.setStart(container, 0);
|
|
rng.setEnd(container, 0);
|
|
selection.setRng(rng);
|
|
}
|
|
});
|
|
};
|
|
var setGeckoEditingOptions = function () {
|
|
var setOpts = function () {
|
|
setEditorCommandState('StyleWithCSS', false);
|
|
setEditorCommandState('enableInlineTableEditing', false);
|
|
if (!settings.object_resizing) {
|
|
setEditorCommandState('enableObjectResizing', false);
|
|
}
|
|
};
|
|
if (!settings.readonly) {
|
|
editor.on('BeforeExecCommand mousedown', setOpts);
|
|
}
|
|
};
|
|
var addBrAfterLastLinks = function () {
|
|
var fixLinks = function () {
|
|
each(dom.select('a'), function (node) {
|
|
var parentNode = node.parentNode;
|
|
var root = dom.getRoot();
|
|
if (parentNode.lastChild === node) {
|
|
while (parentNode && !dom.isBlock(parentNode)) {
|
|
if (parentNode.parentNode.lastChild !== parentNode || parentNode === root) {
|
|
return;
|
|
}
|
|
parentNode = parentNode.parentNode;
|
|
}
|
|
dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
|
|
}
|
|
});
|
|
};
|
|
editor.on('SetContent ExecCommand', function (e) {
|
|
if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
|
|
fixLinks();
|
|
}
|
|
});
|
|
};
|
|
var setDefaultBlockType = function () {
|
|
if (settings.forced_root_block) {
|
|
editor.on('init', function () {
|
|
setEditorCommandState('DefaultParagraphSeparator', Settings.getForcedRootBlock(editor));
|
|
});
|
|
}
|
|
};
|
|
var normalizeSelection = function () {
|
|
editor.on('keyup focusin mouseup', function (e) {
|
|
if (!VK.modifierPressed(e)) {
|
|
selection.normalize();
|
|
}
|
|
}, true);
|
|
};
|
|
var showBrokenImageIcon = function () {
|
|
editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
|
|
};
|
|
var restoreFocusOnKeyDown = function () {
|
|
if (!editor.inline) {
|
|
editor.on('keydown', function () {
|
|
if (domGlobals.document.activeElement === domGlobals.document.body) {
|
|
editor.getWin().focus();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var bodyHeight = function () {
|
|
if (!editor.inline) {
|
|
editor.contentStyles.push('body {min-height: 150px}');
|
|
editor.on('click', function (e) {
|
|
var rng;
|
|
if (e.target.nodeName === 'HTML') {
|
|
if (Env.ie > 11) {
|
|
editor.getBody().focus();
|
|
return;
|
|
}
|
|
rng = editor.selection.getRng();
|
|
editor.getBody().focus();
|
|
editor.selection.setRng(rng);
|
|
editor.selection.normalize();
|
|
editor.nodeChanged();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var blockCmdArrowNavigation = function () {
|
|
if (Env.mac) {
|
|
editor.on('keydown', function (e) {
|
|
if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
|
|
e.preventDefault();
|
|
var selection_1 = editor.selection.getSel();
|
|
selection_1.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var disableAutoUrlDetect = function () {
|
|
setEditorCommandState('AutoUrlDetect', false);
|
|
};
|
|
var tapLinksAndImages = function () {
|
|
editor.on('click', function (e) {
|
|
var elm = e.target;
|
|
do {
|
|
if (elm.tagName === 'A') {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
} while (elm = elm.parentNode);
|
|
});
|
|
editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
|
|
};
|
|
var blockFormSubmitInsideEditor = function () {
|
|
editor.on('init', function () {
|
|
editor.dom.bind(editor.getBody(), 'submit', function (e) {
|
|
e.preventDefault();
|
|
});
|
|
});
|
|
};
|
|
var removeAppleInterchangeBrs = function () {
|
|
parser.addNodeFilter('br', function (nodes) {
|
|
var i = nodes.length;
|
|
while (i--) {
|
|
if (nodes[i].attr('class') === 'Apple-interchange-newline') {
|
|
nodes[i].remove();
|
|
}
|
|
}
|
|
});
|
|
};
|
|
var ieInternalDragAndDrop = function () {
|
|
editor.on('dragstart', function (e) {
|
|
setMceInternalContent(e);
|
|
});
|
|
editor.on('drop', function (e) {
|
|
if (!isDefaultPrevented(e)) {
|
|
var internalContent = getMceInternalContent(e);
|
|
if (internalContent && internalContent.id !== editor.id) {
|
|
e.preventDefault();
|
|
var rng = CaretRangeFromPoint.fromPoint(e.x, e.y, editor.getDoc());
|
|
selection.setRng(rng);
|
|
insertClipboardContents(internalContent.html, true);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
var refreshContentEditable = function () {
|
|
};
|
|
var isHidden = function () {
|
|
var sel;
|
|
if (!isGecko || editor.removed) {
|
|
return false;
|
|
}
|
|
sel = editor.selection.getSel();
|
|
return !sel || !sel.rangeCount || sel.rangeCount === 0;
|
|
};
|
|
removeBlockQuoteOnBackSpace();
|
|
emptyEditorWhenDeleting();
|
|
if (!Env.windowsPhone) {
|
|
normalizeSelection();
|
|
}
|
|
if (isWebKit) {
|
|
inputMethodFocus();
|
|
selectControlElements();
|
|
setDefaultBlockType();
|
|
blockFormSubmitInsideEditor();
|
|
disableBackspaceIntoATable();
|
|
removeAppleInterchangeBrs();
|
|
if (Env.iOS) {
|
|
restoreFocusOnKeyDown();
|
|
bodyHeight();
|
|
tapLinksAndImages();
|
|
} else {
|
|
selectAll();
|
|
}
|
|
}
|
|
if (Env.ie >= 11) {
|
|
bodyHeight();
|
|
disableBackspaceIntoATable();
|
|
}
|
|
if (Env.ie) {
|
|
selectAll();
|
|
disableAutoUrlDetect();
|
|
ieInternalDragAndDrop();
|
|
}
|
|
if (isGecko) {
|
|
removeHrOnBackspace();
|
|
focusBody();
|
|
removeStylesWhenDeletingAcrossBlockElements();
|
|
setGeckoEditingOptions();
|
|
addBrAfterLastLinks();
|
|
showBrokenImageIcon();
|
|
blockCmdArrowNavigation();
|
|
disableBackspaceIntoATable();
|
|
}
|
|
return {
|
|
refreshContentEditable: refreshContentEditable,
|
|
isHidden: isHidden
|
|
};
|
|
};
|
|
|
|
var isTextBlockNode = function (node) {
|
|
return NodeType.isElement(node) && isTextBlock(Element.fromDom(node));
|
|
};
|
|
var normalizeSelection$1 = function (editor) {
|
|
var rng = editor.selection.getRng();
|
|
var startPos = CaretPosition.fromRangeStart(rng);
|
|
var endPos = CaretPosition.fromRangeEnd(rng);
|
|
if (CaretPosition.isElementPosition(startPos)) {
|
|
var container = startPos.container();
|
|
if (isTextBlockNode(container)) {
|
|
CaretFinder.firstPositionIn(container).each(function (pos) {
|
|
return rng.setStart(pos.container(), pos.offset());
|
|
});
|
|
}
|
|
}
|
|
if (CaretPosition.isElementPosition(endPos)) {
|
|
var container = startPos.container();
|
|
if (isTextBlockNode(container)) {
|
|
CaretFinder.lastPositionIn(container).each(function (pos) {
|
|
return rng.setEnd(pos.container(), pos.offset());
|
|
});
|
|
}
|
|
}
|
|
editor.selection.setRng(RangeNormalizer.normalize(rng));
|
|
};
|
|
var setup$g = function (editor) {
|
|
editor.on('click', function (e) {
|
|
if (e.detail >= 3) {
|
|
normalizeSelection$1(editor);
|
|
}
|
|
});
|
|
};
|
|
|
|
var preventSummaryToggle = function (editor) {
|
|
editor.on('click', function (e) {
|
|
if (editor.dom.getParent(e.target, 'details')) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
};
|
|
var filterDetails = function (editor) {
|
|
editor.parser.addNodeFilter('details', function (elms) {
|
|
each(elms, function (details) {
|
|
details.attr('data-mce-open', details.attr('open'));
|
|
details.attr('open', 'open');
|
|
});
|
|
});
|
|
editor.serializer.addNodeFilter('details', function (elms) {
|
|
each(elms, function (details) {
|
|
var open = details.attr('data-mce-open');
|
|
details.attr('open', isString(open) ? open : null);
|
|
details.attr('data-mce-open', null);
|
|
});
|
|
});
|
|
};
|
|
var setup$h = function (editor) {
|
|
preventSummaryToggle(editor);
|
|
filterDetails(editor);
|
|
};
|
|
|
|
var DOM$3 = DOMUtils$1.DOM;
|
|
var appendStyle = function (editor, text) {
|
|
var head = Element.fromDom(editor.getDoc().head);
|
|
var tag = Element.fromTag('style');
|
|
set(tag, 'type', 'text/css');
|
|
append(tag, Element.fromText(text));
|
|
append(head, tag);
|
|
};
|
|
var createParser = function (editor) {
|
|
var parser = DomParser(editor.settings, editor.schema);
|
|
parser.addAttributeFilter('src,href,style,tabindex', function (nodes, name) {
|
|
var i = nodes.length, node;
|
|
var dom = editor.dom;
|
|
var value, internalName;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
value = node.attr(name);
|
|
internalName = 'data-mce-' + name;
|
|
if (!node.attr(internalName)) {
|
|
if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
|
|
continue;
|
|
}
|
|
if (name === 'style') {
|
|
value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
|
if (!value.length) {
|
|
value = null;
|
|
}
|
|
node.attr(internalName, value);
|
|
node.attr(name, value);
|
|
} else if (name === 'tabindex') {
|
|
node.attr(internalName, value);
|
|
node.attr(name, null);
|
|
} else {
|
|
node.attr(internalName, editor.convertURL(value, name, node.name));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
parser.addNodeFilter('script', function (nodes) {
|
|
var i = nodes.length, node, type;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
type = node.attr('type') || 'no/type';
|
|
if (type.indexOf('mce-') !== 0) {
|
|
node.attr('type', 'mce-' + type);
|
|
}
|
|
}
|
|
});
|
|
parser.addNodeFilter('#cdata', function (nodes) {
|
|
var i = nodes.length, node;
|
|
while (i--) {
|
|
node = nodes[i];
|
|
node.type = 8;
|
|
node.name = '#comment';
|
|
node.value = '[CDATA[' + node.value + ']]';
|
|
}
|
|
});
|
|
parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', function (nodes) {
|
|
var i = nodes.length, node;
|
|
var nonEmptyElements = editor.schema.getNonEmptyElements();
|
|
while (i--) {
|
|
node = nodes[i];
|
|
if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
|
|
node.append(new Node$1('br', 1)).shortEnded = true;
|
|
}
|
|
}
|
|
});
|
|
return parser;
|
|
};
|
|
var autoFocus = function (editor) {
|
|
if (editor.settings.auto_focus) {
|
|
Delay.setEditorTimeout(editor, function () {
|
|
var focusEditor;
|
|
if (editor.settings.auto_focus === true) {
|
|
focusEditor = editor;
|
|
} else {
|
|
focusEditor = editor.editorManager.get(editor.settings.auto_focus);
|
|
}
|
|
if (!focusEditor.destroyed) {
|
|
focusEditor.focus();
|
|
}
|
|
}, 100);
|
|
}
|
|
};
|
|
var initEditor = function (editor) {
|
|
editor.bindPendingEventDelegates();
|
|
editor.initialized = true;
|
|
editor.fire('init');
|
|
editor.focus(true);
|
|
editor.nodeChanged({ initial: true });
|
|
editor.execCallback('init_instance_callback', editor);
|
|
autoFocus(editor);
|
|
};
|
|
var getStyleSheetLoader = function (editor) {
|
|
return editor.inline ? DOM$3.styleSheetLoader : editor.dom.styleSheetLoader;
|
|
};
|
|
var initContentBody = function (editor, skipWrite) {
|
|
var settings = editor.settings;
|
|
var targetElm = editor.getElement();
|
|
var doc = editor.getDoc(), body, contentCssText;
|
|
if (!settings.inline) {
|
|
editor.getElement().style.visibility = editor.orgVisibility;
|
|
}
|
|
if (!skipWrite && !editor.inline) {
|
|
doc.open();
|
|
doc.write(editor.iframeHTML);
|
|
doc.close();
|
|
}
|
|
if (editor.inline) {
|
|
editor.on('remove', function () {
|
|
var bodyEl = this.getBody();
|
|
DOM$3.removeClass(bodyEl, 'mce-content-body');
|
|
DOM$3.removeClass(bodyEl, 'mce-edit-focus');
|
|
DOM$3.setAttrib(bodyEl, 'contentEditable', null);
|
|
});
|
|
DOM$3.addClass(targetElm, 'mce-content-body');
|
|
editor.contentDocument = doc = domGlobals.document;
|
|
editor.contentWindow = domGlobals.window;
|
|
editor.bodyElement = targetElm;
|
|
editor.contentAreaContainer = targetElm;
|
|
settings.root_name = targetElm.nodeName.toLowerCase();
|
|
}
|
|
body = editor.getBody();
|
|
body.disabled = true;
|
|
editor.readonly = settings.readonly;
|
|
if (!editor.readonly) {
|
|
if (editor.inline && DOM$3.getStyle(body, 'position', true) === 'static') {
|
|
body.style.position = 'relative';
|
|
}
|
|
body.contentEditable = editor.getParam('content_editable_state', true);
|
|
}
|
|
body.disabled = false;
|
|
editor.editorUpload = EditorUpload(editor);
|
|
editor.schema = Schema(settings);
|
|
editor.dom = DOMUtils$1(doc, {
|
|
keep_values: true,
|
|
url_converter: editor.convertURL,
|
|
url_converter_scope: editor,
|
|
hex_colors: settings.force_hex_style_colors,
|
|
update_styles: true,
|
|
root_element: editor.inline ? editor.getBody() : null,
|
|
collect: function () {
|
|
return editor.inline;
|
|
},
|
|
schema: editor.schema,
|
|
contentCssCors: Settings.shouldUseContentCssCors(editor),
|
|
referrerPolicy: Settings.getReferrerPolicy(editor),
|
|
onSetAttrib: function (e) {
|
|
editor.fire('SetAttrib', e);
|
|
}
|
|
});
|
|
editor.parser = createParser(editor);
|
|
editor.serializer = Serializer$1(settings, editor);
|
|
editor.selection = Selection$1(editor.dom, editor.getWin(), editor.serializer, editor);
|
|
editor.annotator = Annotator(editor);
|
|
editor.formatter = Formatter(editor);
|
|
editor.undoManager = UndoManager(editor);
|
|
editor._nodeChangeDispatcher = new NodeChange(editor);
|
|
editor._selectionOverrides = SelectionOverrides(editor);
|
|
setup$h(editor);
|
|
setup$g(editor);
|
|
KeyboardOverrides.setup(editor);
|
|
ForceBlocks.setup(editor);
|
|
editor.fire('PreInit');
|
|
if (!settings.browser_spellcheck && !settings.gecko_spellcheck) {
|
|
doc.body.spellcheck = false;
|
|
DOM$3.setAttrib(body, 'spellcheck', 'false');
|
|
}
|
|
editor.quirks = Quirks(editor);
|
|
editor.fire('PostRender');
|
|
var directionality = Settings.getDirectionality(editor);
|
|
if (directionality !== undefined) {
|
|
body.dir = directionality;
|
|
}
|
|
if (settings.protect) {
|
|
editor.on('BeforeSetContent', function (e) {
|
|
Tools.each(settings.protect, function (pattern) {
|
|
e.content = e.content.replace(pattern, function (str) {
|
|
return '<!--mce:protected ' + escape(str) + '-->';
|
|
});
|
|
});
|
|
});
|
|
}
|
|
editor.on('SetContent', function () {
|
|
editor.addVisual(editor.getBody());
|
|
});
|
|
editor.load({
|
|
initial: true,
|
|
format: 'html'
|
|
});
|
|
editor.startContent = editor.getContent({ format: 'raw' });
|
|
editor.on('compositionstart compositionend', function (e) {
|
|
editor.composing = e.type === 'compositionstart';
|
|
});
|
|
if (editor.contentStyles.length > 0) {
|
|
contentCssText = '';
|
|
Tools.each(editor.contentStyles, function (style) {
|
|
contentCssText += style + '\r\n';
|
|
});
|
|
editor.dom.addStyle(contentCssText);
|
|
}
|
|
getStyleSheetLoader(editor).loadAll(editor.contentCSS, function (_) {
|
|
initEditor(editor);
|
|
}, function (urls) {
|
|
initEditor(editor);
|
|
});
|
|
if (settings.content_style) {
|
|
appendStyle(editor, settings.content_style);
|
|
}
|
|
};
|
|
var InitContentBody = { initContentBody: initContentBody };
|
|
|
|
var DOM$4 = DOMUtils$1.DOM;
|
|
var relaxDomain = function (editor, ifr) {
|
|
if (domGlobals.document.domain !== domGlobals.window.location.hostname && Env.browser.isIE()) {
|
|
var bodyUuid = Uuid.uuid('mce');
|
|
editor[bodyUuid] = function () {
|
|
InitContentBody.initContentBody(editor);
|
|
};
|
|
var domainRelaxUrl = 'javascript:(function(){' + 'document.open();document.domain="' + domGlobals.document.domain + '";' + 'var ed = window.parent.tinymce.get("' + editor.id + '");document.write(ed.iframeHTML);' + 'document.close();ed.' + bodyUuid + '(true);})()';
|
|
DOM$4.setAttrib(ifr, 'src', domainRelaxUrl);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
var createIframeElement = function (id, title, height, customAttrs) {
|
|
var iframe = Element.fromTag('iframe');
|
|
setAll(iframe, customAttrs);
|
|
setAll(iframe, {
|
|
id: id + '_ifr',
|
|
frameBorder: '0',
|
|
allowTransparency: 'true',
|
|
title: title
|
|
});
|
|
add$3(iframe, 'tox-edit-area__iframe');
|
|
return iframe;
|
|
};
|
|
var getIframeHtml = function (editor) {
|
|
var bodyId, bodyClass, iframeHTML;
|
|
iframeHTML = Settings.getDocType(editor) + '<html><head>';
|
|
if (Settings.getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
|
|
iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
|
|
}
|
|
iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
|
|
bodyId = Settings.getBodyId(editor);
|
|
bodyClass = Settings.getBodyClass(editor);
|
|
if (Settings.getContentSecurityPolicy(editor)) {
|
|
iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + Settings.getContentSecurityPolicy(editor) + '" />';
|
|
}
|
|
iframeHTML += '</head><body id="' + bodyId + '" class="mce-content-body ' + bodyClass + '" data-id="' + editor.id + '"><br></body></html>';
|
|
return iframeHTML;
|
|
};
|
|
var createIframe = function (editor, o) {
|
|
var title = editor.editorManager.translate('Rich Text Area. Press ALT-0 for help.');
|
|
var ifr = createIframeElement(editor.id, title, o.height, Settings.getIframeAttrs(editor)).dom();
|
|
ifr.onload = function () {
|
|
ifr.onload = null;
|
|
editor.fire('load');
|
|
};
|
|
var isDomainRelaxed = relaxDomain(editor, ifr);
|
|
editor.contentAreaContainer = o.iframeContainer;
|
|
editor.iframeElement = ifr;
|
|
editor.iframeHTML = getIframeHtml(editor);
|
|
DOM$4.add(o.iframeContainer, ifr);
|
|
return isDomainRelaxed;
|
|
};
|
|
var init$1 = function (editor, boxInfo) {
|
|
var isDomainRelaxed = createIframe(editor, boxInfo);
|
|
if (boxInfo.editorContainer) {
|
|
DOM$4.get(boxInfo.editorContainer).style.display = editor.orgDisplay;
|
|
editor.hidden = DOM$4.isHidden(boxInfo.editorContainer);
|
|
}
|
|
editor.getElement().style.display = 'none';
|
|
DOM$4.setAttrib(editor.id, 'aria-hidden', 'true');
|
|
if (!isDomainRelaxed) {
|
|
InitContentBody.initContentBody(editor);
|
|
}
|
|
};
|
|
var InitIframe = { init: init$1 };
|
|
|
|
var isContentCssSkinName = function (url) {
|
|
return /^[a-z0-9\-]+$/i.test(url);
|
|
};
|
|
var getContentCssUrls = function (editor) {
|
|
var contentCss = Settings.getContentCss(editor);
|
|
var skinUrl = editor.editorManager.baseURL + '/skins/content';
|
|
var suffix = editor.editorManager.suffix;
|
|
var contentCssFile = 'content' + suffix + '.css';
|
|
var inline = editor.inline === true;
|
|
return map(contentCss, function (url) {
|
|
if (isContentCssSkinName(url) && !inline) {
|
|
return skinUrl + '/' + url + '/' + contentCssFile;
|
|
} else {
|
|
return editor.documentBaseURI.toAbsolute(url);
|
|
}
|
|
});
|
|
};
|
|
var appendContentCssFromSettings = function (editor) {
|
|
editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor));
|
|
};
|
|
|
|
var DOM$5 = DOMUtils$1.DOM;
|
|
var initPlugin = function (editor, initializedPlugins, plugin) {
|
|
var Plugin = PluginManager.get(plugin);
|
|
var pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
|
|
plugin = Tools.trim(plugin);
|
|
if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
|
|
Tools.each(PluginManager.dependencies(plugin), function (dep) {
|
|
initPlugin(editor, initializedPlugins, dep);
|
|
});
|
|
if (editor.plugins[plugin]) {
|
|
return;
|
|
}
|
|
try {
|
|
var pluginInstance = new Plugin(editor, pluginUrl, editor.$);
|
|
editor.plugins[plugin] = pluginInstance;
|
|
if (pluginInstance.init) {
|
|
pluginInstance.init(editor, pluginUrl);
|
|
initializedPlugins.push(plugin);
|
|
}
|
|
} catch (e) {
|
|
ErrorReporter.pluginInitError(editor, plugin, e);
|
|
}
|
|
}
|
|
};
|
|
var trimLegacyPrefix = function (name) {
|
|
return name.replace(/^\-/, '');
|
|
};
|
|
var initPlugins = function (editor) {
|
|
var initializedPlugins = [];
|
|
Tools.each(editor.settings.plugins.split(/[ ,]/), function (name) {
|
|
initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
|
|
});
|
|
};
|
|
var initIcons = function (editor) {
|
|
var iconPackName = Tools.trim(editor.settings.icons);
|
|
var currentIcons = editor.ui.registry.getAll().icons;
|
|
var defaultIcons = getAll();
|
|
var loadIcons = __assign(__assign({}, defaultIcons), IconManager.get(iconPackName).icons);
|
|
each$1(loadIcons, function (svgData, icon) {
|
|
if (!has(currentIcons, icon)) {
|
|
editor.ui.registry.addIcon(icon, svgData);
|
|
}
|
|
});
|
|
};
|
|
var initTheme = function (editor) {
|
|
var theme = editor.settings.theme;
|
|
if (isString(theme)) {
|
|
editor.settings.theme = trimLegacyPrefix(theme);
|
|
var Theme = ThemeManager.get(theme);
|
|
editor.theme = new Theme(editor, ThemeManager.urls[theme]);
|
|
if (editor.theme.init) {
|
|
editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''), editor.$);
|
|
}
|
|
} else {
|
|
editor.theme = {};
|
|
}
|
|
};
|
|
var renderFromLoadedTheme = function (editor) {
|
|
return editor.theme.renderUI();
|
|
};
|
|
var renderFromThemeFunc = function (editor) {
|
|
var elm = editor.getElement();
|
|
var theme = editor.settings.theme;
|
|
var info = theme(editor, elm);
|
|
if (info.editorContainer.nodeType) {
|
|
info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
|
|
}
|
|
if (info.iframeContainer && info.iframeContainer.nodeType) {
|
|
info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
|
|
}
|
|
info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
|
|
return info;
|
|
};
|
|
var createThemeFalseResult = function (element) {
|
|
return {
|
|
editorContainer: element,
|
|
iframeContainer: element
|
|
};
|
|
};
|
|
var renderThemeFalseIframe = function (targetElement) {
|
|
var iframeContainer = DOM$5.create('div');
|
|
DOM$5.insertAfter(iframeContainer, targetElement);
|
|
return createThemeFalseResult(iframeContainer);
|
|
};
|
|
var renderThemeFalse = function (editor) {
|
|
var targetElement = editor.getElement();
|
|
return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
|
|
};
|
|
var renderThemeUi = function (editor) {
|
|
var elm = editor.getElement();
|
|
editor.orgDisplay = elm.style.display;
|
|
if (isString(editor.settings.theme)) {
|
|
return renderFromLoadedTheme(editor);
|
|
} else if (isFunction(editor.settings.theme)) {
|
|
return renderFromThemeFunc(editor);
|
|
} else {
|
|
return renderThemeFalse(editor);
|
|
}
|
|
};
|
|
var init$2 = function (editor) {
|
|
editor.fire('ScriptsLoaded');
|
|
initIcons(editor);
|
|
initTheme(editor);
|
|
initPlugins(editor);
|
|
var boxInfo = renderThemeUi(editor);
|
|
editor.editorContainer = boxInfo.editorContainer ? boxInfo.editorContainer : null;
|
|
appendContentCssFromSettings(editor);
|
|
if (editor.inline) {
|
|
return InitContentBody.initContentBody(editor);
|
|
} else {
|
|
return InitIframe.init(editor, boxInfo);
|
|
}
|
|
};
|
|
var Init = { init: init$2 };
|
|
|
|
var DOM$6 = DOMUtils$1.DOM;
|
|
var hasSkipLoadPrefix = function (name) {
|
|
return name.charAt(0) === '-';
|
|
};
|
|
var loadLanguage = function (scriptLoader, editor) {
|
|
var languageCode = Settings.getLanguageCode(editor);
|
|
var languageUrl = Settings.getLanguageUrl(editor);
|
|
if (I18n.hasCode(languageCode) === false && languageCode !== 'en') {
|
|
var url_1 = languageUrl !== '' ? languageUrl : editor.editorManager.baseURL + '/langs/' + languageCode + '.js';
|
|
scriptLoader.add(url_1, noop, undefined, function () {
|
|
ErrorReporter.languageLoadError(url_1, languageCode);
|
|
});
|
|
}
|
|
};
|
|
var loadTheme = function (scriptLoader, editor, suffix, callback) {
|
|
var settings = editor.settings, theme = settings.theme;
|
|
if (isString(theme)) {
|
|
if (!hasSkipLoadPrefix(theme) && !ThemeManager.urls.hasOwnProperty(theme)) {
|
|
var themeUrl = settings.theme_url;
|
|
if (themeUrl) {
|
|
ThemeManager.load(theme, editor.documentBaseURI.toAbsolute(themeUrl));
|
|
} else {
|
|
ThemeManager.load(theme, 'themes/' + theme + '/theme' + suffix + '.js');
|
|
}
|
|
}
|
|
scriptLoader.loadQueue(function () {
|
|
ThemeManager.waitFor(theme, callback);
|
|
});
|
|
} else {
|
|
callback();
|
|
}
|
|
};
|
|
var getIconsUrlMetaFromUrl = function (editor) {
|
|
return Option.from(Settings.getIconsUrl(editor)).filter(function (url) {
|
|
return url.length > 0;
|
|
}).map(function (url) {
|
|
return {
|
|
url: url,
|
|
name: Option.none()
|
|
};
|
|
});
|
|
};
|
|
var getIconsUrlMetaFromName = function (editor) {
|
|
return Option.from(Settings.getIconPackName(editor)).filter(function (name) {
|
|
return name.length > 0 && !IconManager.has(name);
|
|
}).map(function (name) {
|
|
return {
|
|
url: editor.editorManager.baseURL + '/icons/' + name + '/icons.js',
|
|
name: Option.some(name)
|
|
};
|
|
});
|
|
};
|
|
var loadIcons = function (scriptLoader, editor) {
|
|
getIconsUrlMetaFromUrl(editor).orThunk(function () {
|
|
return getIconsUrlMetaFromName(editor);
|
|
}).each(function (urlMeta) {
|
|
scriptLoader.add(urlMeta.url, noop, undefined, function () {
|
|
ErrorReporter.iconsLoadError(urlMeta.url, urlMeta.name.getOrUndefined());
|
|
});
|
|
});
|
|
};
|
|
var loadPlugins = function (settings, suffix) {
|
|
if (isArray(settings.plugins)) {
|
|
settings.plugins = settings.plugins.join(' ');
|
|
}
|
|
Tools.each(settings.external_plugins, function (url, name) {
|
|
PluginManager.load(name, url, noop, undefined, function () {
|
|
ErrorReporter.pluginLoadError(name, url);
|
|
});
|
|
settings.plugins += ' ' + name;
|
|
});
|
|
Tools.each(settings.plugins.split(/[ ,]/), function (plugin) {
|
|
plugin = Tools.trim(plugin);
|
|
if (plugin && !PluginManager.urls[plugin]) {
|
|
if (hasSkipLoadPrefix(plugin)) {
|
|
plugin = plugin.substr(1, plugin.length);
|
|
var dependencies = PluginManager.dependencies(plugin);
|
|
Tools.each(dependencies, function (dep) {
|
|
var defaultSettings = {
|
|
prefix: 'plugins/',
|
|
resource: dep,
|
|
suffix: '/plugin' + suffix + '.js'
|
|
};
|
|
dep = PluginManager.createUrl(defaultSettings, dep);
|
|
PluginManager.load(dep.resource, dep, noop, undefined, function () {
|
|
ErrorReporter.pluginLoadError(dep.prefix + dep.resource + dep.suffix, dep.resource);
|
|
});
|
|
});
|
|
} else {
|
|
var url_2 = {
|
|
prefix: 'plugins/',
|
|
resource: plugin,
|
|
suffix: '/plugin' + suffix + '.js'
|
|
};
|
|
PluginManager.load(plugin, url_2, noop, undefined, function () {
|
|
ErrorReporter.pluginLoadError(url_2.prefix + url_2.resource + url_2.suffix, plugin);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
};
|
|
var loadScripts = function (editor, suffix) {
|
|
var scriptLoader = ScriptLoader.ScriptLoader;
|
|
loadTheme(scriptLoader, editor, suffix, function () {
|
|
loadLanguage(scriptLoader, editor);
|
|
loadIcons(scriptLoader, editor);
|
|
loadPlugins(editor.settings, suffix);
|
|
scriptLoader.loadQueue(function () {
|
|
if (!editor.removed) {
|
|
Init.init(editor);
|
|
}
|
|
}, editor, function () {
|
|
if (!editor.removed) {
|
|
Init.init(editor);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
var render = function (editor) {
|
|
var settings = editor.settings, id = editor.id;
|
|
I18n.setCode(Settings.getLanguageCode(editor));
|
|
var readyHandler = function () {
|
|
DOM$6.unbind(domGlobals.window, 'ready', readyHandler);
|
|
editor.render();
|
|
};
|
|
if (!EventUtils.Event.domLoaded) {
|
|
DOM$6.bind(domGlobals.window, 'ready', readyHandler);
|
|
return;
|
|
}
|
|
if (!editor.getElement()) {
|
|
return;
|
|
}
|
|
if (!Env.contentEditable) {
|
|
return;
|
|
}
|
|
if (!settings.inline) {
|
|
editor.orgVisibility = editor.getElement().style.visibility;
|
|
editor.getElement().style.visibility = 'hidden';
|
|
} else {
|
|
editor.inline = true;
|
|
}
|
|
var form = editor.getElement().form || DOM$6.getParent(id, 'form');
|
|
if (form) {
|
|
editor.formElement = form;
|
|
if (settings.hidden_input && !NodeType.isTextareaOrInput(editor.getElement())) {
|
|
DOM$6.insertAfter(DOM$6.create('input', {
|
|
type: 'hidden',
|
|
name: id
|
|
}), id);
|
|
editor.hasHiddenInput = true;
|
|
}
|
|
editor.formEventDelegate = function (e) {
|
|
editor.fire(e.type, e);
|
|
};
|
|
DOM$6.bind(form, 'submit reset', editor.formEventDelegate);
|
|
editor.on('reset', function () {
|
|
editor.resetContent();
|
|
});
|
|
if (settings.submit_patch && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
|
|
form._mceOldSubmit = form.submit;
|
|
form.submit = function () {
|
|
editor.editorManager.triggerSave();
|
|
editor.setDirty(false);
|
|
return form._mceOldSubmit(form);
|
|
};
|
|
}
|
|
}
|
|
editor.windowManager = WindowManager(editor);
|
|
editor.notificationManager = NotificationManager(editor);
|
|
if (settings.encoding === 'xml') {
|
|
editor.on('GetContent', function (e) {
|
|
if (e.save) {
|
|
e.content = DOM$6.encode(e.content);
|
|
}
|
|
});
|
|
}
|
|
if (settings.add_form_submit_trigger) {
|
|
editor.on('submit', function () {
|
|
if (editor.initialized) {
|
|
editor.save();
|
|
}
|
|
});
|
|
}
|
|
if (settings.add_unload_trigger) {
|
|
editor._beforeUnload = function () {
|
|
if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
|
|
editor.save({
|
|
format: 'raw',
|
|
no_events: true,
|
|
set_dirty: false
|
|
});
|
|
}
|
|
};
|
|
editor.editorManager.on('BeforeUnload', editor._beforeUnload);
|
|
}
|
|
editor.editorManager.add(editor);
|
|
loadScripts(editor, editor.suffix);
|
|
};
|
|
var Render = { render: render };
|
|
|
|
var internalContentEditableAttr = 'data-mce-contenteditable';
|
|
var toggleClass = function (elm, cls, state) {
|
|
if (has$2(elm, cls) && state === false) {
|
|
remove$4(elm, cls);
|
|
} else if (state) {
|
|
add$3(elm, cls);
|
|
}
|
|
};
|
|
var setEditorCommandState = function (editor, cmd, state) {
|
|
try {
|
|
editor.getDoc().execCommand(cmd, false, state);
|
|
} catch (ex) {
|
|
}
|
|
};
|
|
var setContentEditable = function (elm, state) {
|
|
elm.dom().contentEditable = state ? 'true' : 'false';
|
|
};
|
|
var switchOffContentEditableTrue = function (elm) {
|
|
each(descendants$1(elm, '*[contenteditable="true"]'), function (elm) {
|
|
set(elm, internalContentEditableAttr, 'true');
|
|
setContentEditable(elm, false);
|
|
});
|
|
};
|
|
var switchOnContentEditableTrue = function (elm) {
|
|
each(descendants$1(elm, '*[' + internalContentEditableAttr + '="true"]'), function (elm) {
|
|
remove(elm, internalContentEditableAttr);
|
|
setContentEditable(elm, true);
|
|
});
|
|
};
|
|
var removeFakeSelection = function (editor) {
|
|
Option.from(editor.selection.getNode()).each(function (elm) {
|
|
elm.removeAttribute('data-mce-selected');
|
|
});
|
|
};
|
|
var restoreFakeSelection = function (editor) {
|
|
editor.selection.setRng(editor.selection.getRng());
|
|
};
|
|
var toggleReadOnly = function (editor, state) {
|
|
var body = Element.fromDom(editor.getBody());
|
|
toggleClass(body, 'mce-content-readonly', state);
|
|
if (state) {
|
|
editor.selection.controlSelection.hideResizeRect();
|
|
editor._selectionOverrides.hideFakeCaret();
|
|
removeFakeSelection(editor);
|
|
editor.readonly = true;
|
|
setContentEditable(body, false);
|
|
switchOffContentEditableTrue(body);
|
|
} else {
|
|
editor.readonly = false;
|
|
setContentEditable(body, true);
|
|
switchOnContentEditableTrue(body);
|
|
setEditorCommandState(editor, 'StyleWithCSS', false);
|
|
setEditorCommandState(editor, 'enableInlineTableEditing', false);
|
|
setEditorCommandState(editor, 'enableObjectResizing', false);
|
|
if (EditorFocus.hasEditorOrUiFocus(editor)) {
|
|
editor.focus();
|
|
}
|
|
restoreFakeSelection(editor);
|
|
editor.nodeChanged();
|
|
}
|
|
};
|
|
var isReadOnly = function (editor) {
|
|
return editor.readonly === true;
|
|
};
|
|
var registerFilters = function (editor) {
|
|
editor.parser.addAttributeFilter('contenteditable', function (nodes) {
|
|
if (isReadOnly(editor)) {
|
|
each(nodes, function (node) {
|
|
node.attr(internalContentEditableAttr, node.attr('contenteditable'));
|
|
node.attr('contenteditable', 'false');
|
|
});
|
|
}
|
|
});
|
|
editor.serializer.addAttributeFilter(internalContentEditableAttr, function (nodes) {
|
|
if (isReadOnly(editor)) {
|
|
each(nodes, function (node) {
|
|
node.attr('contenteditable', node.attr(internalContentEditableAttr));
|
|
});
|
|
}
|
|
});
|
|
editor.serializer.addTempAttr(internalContentEditableAttr);
|
|
};
|
|
var registerReadOnlyContentFilters = function (editor) {
|
|
if (editor.serializer) {
|
|
registerFilters(editor);
|
|
} else {
|
|
editor.on('PreInit', function () {
|
|
registerFilters(editor);
|
|
});
|
|
}
|
|
};
|
|
var isClickEvent = function (e) {
|
|
return e.type === 'click';
|
|
};
|
|
var preventReadOnlyEvents = function (e) {
|
|
var target = e.target;
|
|
if (isClickEvent(e) && target.tagName === 'A' && !VK.metaKeyPressed(e)) {
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
var registerReadOnlySelectionBlockers = function (editor) {
|
|
editor.on('ShowCaret', function (e) {
|
|
if (isReadOnly(editor)) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
editor.on('ObjectSelected', function (e) {
|
|
if (isReadOnly(editor)) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
};
|
|
|
|
var defaultModes = [
|
|
'design',
|
|
'readonly'
|
|
];
|
|
var switchToMode = function (editor, activeMode, availableModes, mode) {
|
|
var oldMode = availableModes[activeMode.get()];
|
|
var newMode = availableModes[mode];
|
|
try {
|
|
newMode.activate();
|
|
} catch (e) {
|
|
domGlobals.console.error('problem while activating editor mode ' + mode + ':', e);
|
|
return;
|
|
}
|
|
oldMode.deactivate();
|
|
if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
|
|
toggleReadOnly(editor, newMode.editorReadOnly);
|
|
}
|
|
activeMode.set(mode);
|
|
Events.fireSwitchMode(editor, mode);
|
|
};
|
|
var setMode = function (editor, availableModes, activeMode, mode) {
|
|
if (mode === activeMode.get()) {
|
|
return;
|
|
} else if (!has(availableModes, mode)) {
|
|
throw new Error('Editor mode \'' + mode + '\' is invalid');
|
|
}
|
|
if (editor.initialized) {
|
|
switchToMode(editor, activeMode, availableModes, mode);
|
|
} else {
|
|
editor.on('init', function () {
|
|
return switchToMode(editor, activeMode, availableModes, mode);
|
|
});
|
|
}
|
|
};
|
|
var registerMode = function (availableModes, mode, api) {
|
|
var _a;
|
|
if (contains(defaultModes, mode)) {
|
|
throw new Error('Cannot override default mode ' + mode);
|
|
}
|
|
return __assign(__assign({}, availableModes), (_a = {}, _a[mode] = __assign(__assign({}, api), {
|
|
deactivate: function () {
|
|
try {
|
|
api.deactivate();
|
|
} catch (e) {
|
|
domGlobals.console.error('problem while deactivating editor mode ' + mode + ':', e);
|
|
}
|
|
}
|
|
}), _a));
|
|
};
|
|
|
|
var create$4 = function (editor) {
|
|
var activeMode = Cell('design');
|
|
var availableModes = Cell({
|
|
design: {
|
|
activate: noop,
|
|
deactivate: noop,
|
|
editorReadOnly: false
|
|
},
|
|
readonly: {
|
|
activate: noop,
|
|
deactivate: noop,
|
|
editorReadOnly: true
|
|
}
|
|
});
|
|
registerReadOnlyContentFilters(editor);
|
|
registerReadOnlySelectionBlockers(editor);
|
|
return {
|
|
isReadOnly: function () {
|
|
return isReadOnly(editor);
|
|
},
|
|
set: function (mode) {
|
|
return setMode(editor, availableModes.get(), activeMode, mode);
|
|
},
|
|
get: function () {
|
|
return activeMode.get();
|
|
},
|
|
register: function (mode, api) {
|
|
availableModes.set(registerMode(availableModes.get(), mode, api));
|
|
}
|
|
};
|
|
};
|
|
|
|
var hasOnlyOneChild$1 = function (node) {
|
|
return node.firstChild && node.firstChild === node.lastChild;
|
|
};
|
|
var isPaddingNode = function (node) {
|
|
return node.name === 'br' || node.value === '\xA0';
|
|
};
|
|
var isPaddedEmptyBlock = function (schema, node) {
|
|
var blockElements = schema.getBlockElements();
|
|
return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
|
|
};
|
|
var isEmptyFragmentElement = function (schema, node) {
|
|
var nonEmptyElements = schema.getNonEmptyElements();
|
|
return node && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
|
|
};
|
|
var isListFragment = function (schema, fragment) {
|
|
var firstChild = fragment.firstChild;
|
|
var lastChild = fragment.lastChild;
|
|
if (firstChild && firstChild.name === 'meta') {
|
|
firstChild = firstChild.next;
|
|
}
|
|
if (lastChild && lastChild.attr('id') === 'mce_marker') {
|
|
lastChild = lastChild.prev;
|
|
}
|
|
if (isEmptyFragmentElement(schema, lastChild)) {
|
|
lastChild = lastChild.prev;
|
|
}
|
|
if (!firstChild || firstChild !== lastChild) {
|
|
return false;
|
|
}
|
|
return firstChild.name === 'ul' || firstChild.name === 'ol';
|
|
};
|
|
var cleanupDomFragment = function (domFragment) {
|
|
var firstChild = domFragment.firstChild;
|
|
var lastChild = domFragment.lastChild;
|
|
if (firstChild && firstChild.nodeName === 'META') {
|
|
firstChild.parentNode.removeChild(firstChild);
|
|
}
|
|
if (lastChild && lastChild.id === 'mce_marker') {
|
|
lastChild.parentNode.removeChild(lastChild);
|
|
}
|
|
return domFragment;
|
|
};
|
|
var toDomFragment = function (dom, serializer, fragment) {
|
|
var html = serializer.serialize(fragment);
|
|
var domFragment = dom.createFragment(html);
|
|
return cleanupDomFragment(domFragment);
|
|
};
|
|
var listItems$1 = function (elm) {
|
|
return Tools.grep(elm.childNodes, function (child) {
|
|
return child.nodeName === 'LI';
|
|
});
|
|
};
|
|
var isPadding = function (node) {
|
|
return node.data === '\xA0' || NodeType.isBr(node);
|
|
};
|
|
var isListItemPadded = function (node) {
|
|
return node && node.firstChild && node.firstChild === node.lastChild && isPadding(node.firstChild);
|
|
};
|
|
var isEmptyOrPadded = function (elm) {
|
|
return !elm.firstChild || isListItemPadded(elm);
|
|
};
|
|
var trimListItems = function (elms) {
|
|
return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
|
|
};
|
|
var getParentLi = function (dom, node) {
|
|
var parentBlock = dom.getParent(node, dom.isBlock);
|
|
return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
|
|
};
|
|
var isParentBlockLi = function (dom, node) {
|
|
return !!getParentLi(dom, node);
|
|
};
|
|
var getSplit = function (parentNode, rng) {
|
|
var beforeRng = rng.cloneRange();
|
|
var afterRng = rng.cloneRange();
|
|
beforeRng.setStartBefore(parentNode);
|
|
afterRng.setEndAfter(parentNode);
|
|
return [
|
|
beforeRng.cloneContents(),
|
|
afterRng.cloneContents()
|
|
];
|
|
};
|
|
var findFirstIn = function (node, rootNode) {
|
|
var caretPos = CaretPosition$1.before(node);
|
|
var caretWalker = CaretWalker(rootNode);
|
|
var newCaretPos = caretWalker.next(caretPos);
|
|
return newCaretPos ? newCaretPos.toRange() : null;
|
|
};
|
|
var findLastOf = function (node, rootNode) {
|
|
var caretPos = CaretPosition$1.after(node);
|
|
var caretWalker = CaretWalker(rootNode);
|
|
var newCaretPos = caretWalker.prev(caretPos);
|
|
return newCaretPos ? newCaretPos.toRange() : null;
|
|
};
|
|
var insertMiddle = function (target, elms, rootNode, rng) {
|
|
var parts = getSplit(target, rng);
|
|
var parentElm = target.parentNode;
|
|
parentElm.insertBefore(parts[0], target);
|
|
Tools.each(elms, function (li) {
|
|
parentElm.insertBefore(li, target);
|
|
});
|
|
parentElm.insertBefore(parts[1], target);
|
|
parentElm.removeChild(target);
|
|
return findLastOf(elms[elms.length - 1], rootNode);
|
|
};
|
|
var insertBefore$1 = function (target, elms, rootNode) {
|
|
var parentElm = target.parentNode;
|
|
Tools.each(elms, function (elm) {
|
|
parentElm.insertBefore(elm, target);
|
|
});
|
|
return findFirstIn(target, rootNode);
|
|
};
|
|
var insertAfter$1 = function (target, elms, rootNode, dom) {
|
|
dom.insertAfter(elms.reverse(), target);
|
|
return findLastOf(elms[0], rootNode);
|
|
};
|
|
var insertAtCaret = function (serializer, dom, rng, fragment) {
|
|
var domFragment = toDomFragment(dom, serializer, fragment);
|
|
var liTarget = getParentLi(dom, rng.startContainer);
|
|
var liElms = trimListItems(listItems$1(domFragment.firstChild));
|
|
var BEGINNING = 1, END = 2;
|
|
var rootNode = dom.getRoot();
|
|
var isAt = function (location) {
|
|
var caretPos = CaretPosition$1.fromRangeStart(rng);
|
|
var caretWalker = CaretWalker(dom.getRoot());
|
|
var newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
|
|
return newPos ? getParentLi(dom, newPos.getNode()) !== liTarget : true;
|
|
};
|
|
if (isAt(BEGINNING)) {
|
|
return insertBefore$1(liTarget, liElms, rootNode);
|
|
} else if (isAt(END)) {
|
|
return insertAfter$1(liTarget, liElms, rootNode, dom);
|
|
}
|
|
return insertMiddle(liTarget, liElms, rootNode, rng);
|
|
};
|
|
var InsertList = {
|
|
isListFragment: isListFragment,
|
|
insertAtCaret: insertAtCaret,
|
|
isParentBlockLi: isParentBlockLi,
|
|
trimListItems: trimListItems,
|
|
listItems: listItems$1
|
|
};
|
|
|
|
var isAfterNbsp = function (container, offset) {
|
|
return NodeType.isText(container) && container.nodeValue[offset - 1] === '\xA0';
|
|
};
|
|
var trimOrPadLeftRight = function (rng, html) {
|
|
var container, offset;
|
|
container = rng.startContainer;
|
|
offset = rng.startOffset;
|
|
var hasSiblingText = function (siblingName) {
|
|
return container[siblingName] && container[siblingName].nodeType === 3;
|
|
};
|
|
if (container.nodeType === 3) {
|
|
if (offset > 0) {
|
|
html = html.replace(/^ /, ' ');
|
|
} else if (!hasSiblingText('previousSibling')) {
|
|
html = html.replace(/^ /, ' ');
|
|
}
|
|
if (offset < container.length) {
|
|
html = html.replace(/ (<br>|)$/, ' ');
|
|
} else if (!hasSiblingText('nextSibling')) {
|
|
html = html.replace(/( | )(<br>|)$/, ' ');
|
|
}
|
|
}
|
|
return html;
|
|
};
|
|
var trimNbspAfterDeleteAndPadValue = function (rng, value) {
|
|
var container, offset;
|
|
container = rng.startContainer;
|
|
offset = rng.startOffset;
|
|
if (container.nodeType === 3 && rng.collapsed) {
|
|
if (container.data[offset] === '\xA0') {
|
|
container.deleteData(offset, 1);
|
|
if (!/[\u00a0| ]$/.test(value)) {
|
|
value += ' ';
|
|
}
|
|
} else if (container.data[offset - 1] === '\xA0') {
|
|
container.deleteData(offset - 1, 1);
|
|
if (!/[\u00a0| ]$/.test(value)) {
|
|
value = ' ' + value;
|
|
}
|
|
}
|
|
}
|
|
return value;
|
|
};
|
|
|
|
var isTableCell$5 = NodeType.matchNodeNames([
|
|
'td',
|
|
'th'
|
|
]);
|
|
var selectionSetContent = function (editor, content) {
|
|
var rng = editor.selection.getRng();
|
|
var container = rng.startContainer;
|
|
var offset = rng.startOffset;
|
|
if (rng.collapsed && isAfterNbsp(container, offset) && NodeType.isText(container)) {
|
|
container.insertData(offset - 1, ' ');
|
|
container.deleteData(offset, 1);
|
|
rng.setStart(container, offset);
|
|
rng.setEnd(container, offset);
|
|
editor.selection.setRng(rng);
|
|
}
|
|
editor.selection.setContent(content);
|
|
};
|
|
var validInsertion = function (editor, value, parentNode) {
|
|
if (parentNode.getAttribute('data-mce-bogus') === 'all') {
|
|
parentNode.parentNode.insertBefore(editor.dom.createFragment(value), parentNode);
|
|
} else {
|
|
var node = parentNode.firstChild;
|
|
var node2 = parentNode.lastChild;
|
|
if (!node || node === node2 && node.nodeName === 'BR') {
|
|
editor.dom.setHTML(parentNode, value);
|
|
} else {
|
|
selectionSetContent(editor, value);
|
|
}
|
|
}
|
|
};
|
|
var trimBrsFromTableCell = function (dom, elm) {
|
|
Option.from(dom.getParent(elm, 'td,th')).map(Element.fromDom).each(PaddingBr.trimBlockTrailingBr);
|
|
};
|
|
var reduceInlineTextElements = function (editor, merge) {
|
|
var textInlineElements = editor.schema.getTextInlineElements();
|
|
var dom = editor.dom;
|
|
if (merge) {
|
|
var root_1 = editor.getBody(), elementUtils_1 = new ElementUtils(dom);
|
|
Tools.each(dom.select('*[data-mce-fragment]'), function (node) {
|
|
for (var testNode = node.parentNode; testNode && testNode !== root_1; testNode = testNode.parentNode) {
|
|
if (textInlineElements[node.nodeName.toLowerCase()] && elementUtils_1.compare(testNode, node)) {
|
|
dom.remove(node, true);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
var markFragmentElements = function (fragment) {
|
|
var node = fragment;
|
|
while (node = node.walk()) {
|
|
if (node.type === 1) {
|
|
node.attr('data-mce-fragment', '1');
|
|
}
|
|
}
|
|
};
|
|
var umarkFragmentElements = function (elm) {
|
|
Tools.each(elm.getElementsByTagName('*'), function (elm) {
|
|
elm.removeAttribute('data-mce-fragment');
|
|
});
|
|
};
|
|
var isPartOfFragment = function (node) {
|
|
return !!node.getAttribute('data-mce-fragment');
|
|
};
|
|
var canHaveChildren = function (editor, node) {
|
|
return node && !editor.schema.getShortEndedElements()[node.nodeName];
|
|
};
|
|
var moveSelectionToMarker = function (editor, marker) {
|
|
var parentEditableFalseElm, parentBlock, nextRng;
|
|
var dom = editor.dom, selection = editor.selection;
|
|
var node, node2;
|
|
var getContentEditableFalseParent = function (node) {
|
|
var root = editor.getBody();
|
|
for (; node && node !== root; node = node.parentNode) {
|
|
if (editor.dom.getContentEditable(node) === 'false') {
|
|
return node;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
if (!marker) {
|
|
return;
|
|
}
|
|
editor.selection.scrollIntoView(marker);
|
|
parentEditableFalseElm = getContentEditableFalseParent(marker);
|
|
if (parentEditableFalseElm) {
|
|
dom.remove(marker);
|
|
selection.select(parentEditableFalseElm);
|
|
return;
|
|
}
|
|
var rng = dom.createRng();
|
|
node = marker.previousSibling;
|
|
if (node && node.nodeType === 3) {
|
|
rng.setStart(node, node.nodeValue.length);
|
|
if (!Env.ie) {
|
|
node2 = marker.nextSibling;
|
|
if (node2 && node2.nodeType === 3) {
|
|
node.appendData(node2.data);
|
|
node2.parentNode.removeChild(node2);
|
|
}
|
|
}
|
|
} else {
|
|
rng.setStartBefore(marker);
|
|
rng.setEndBefore(marker);
|
|
}
|
|
var findNextCaretRng = function (rng) {
|
|
var caretPos = CaretPosition$1.fromRangeStart(rng);
|
|
var caretWalker = CaretWalker(editor.getBody());
|
|
caretPos = caretWalker.next(caretPos);
|
|
if (caretPos) {
|
|
return caretPos.toRange();
|
|
}
|
|
};
|
|
parentBlock = dom.getParent(marker, dom.isBlock);
|
|
dom.remove(marker);
|
|
if (parentBlock && dom.isEmpty(parentBlock)) {
|
|
editor.$(parentBlock).empty();
|
|
rng.setStart(parentBlock, 0);
|
|
rng.setEnd(parentBlock, 0);
|
|
if (!isTableCell$5(parentBlock) && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
|
|
rng = nextRng;
|
|
dom.remove(parentBlock);
|
|
} else {
|
|
dom.add(parentBlock, dom.create('br', { 'data-mce-bogus': '1' }));
|
|
}
|
|
}
|
|
selection.setRng(rng);
|
|
};
|
|
var insertHtmlAtCaret = function (editor, value, details) {
|
|
var parser, serializer, parentNode, rootNode, fragment, args;
|
|
var marker, rng, node, bookmarkHtml, merge;
|
|
var selection = editor.selection, dom = editor.dom;
|
|
if (/^ | $/.test(value)) {
|
|
value = trimOrPadLeftRight(selection.getRng(), value);
|
|
}
|
|
parser = editor.parser;
|
|
merge = details.merge;
|
|
serializer = Serializer({ validate: editor.settings.validate }, editor.schema);
|
|
bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">​</span>';
|
|
args = {
|
|
content: value,
|
|
format: 'html',
|
|
selection: true,
|
|
paste: details.paste
|
|
};
|
|
args = editor.fire('BeforeSetContent', args);
|
|
if (args.isDefaultPrevented()) {
|
|
editor.fire('SetContent', {
|
|
content: args.content,
|
|
format: 'html',
|
|
selection: true,
|
|
paste: details.paste
|
|
});
|
|
return;
|
|
}
|
|
value = args.content;
|
|
if (value.indexOf('{$caret}') === -1) {
|
|
value += '{$caret}';
|
|
}
|
|
value = value.replace(/\{\$caret\}/, bookmarkHtml);
|
|
rng = selection.getRng();
|
|
var caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
|
|
var body = editor.getBody();
|
|
if (caretElement === body && selection.isCollapsed()) {
|
|
if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
|
|
rng = dom.createRng();
|
|
rng.setStart(body.firstChild, 0);
|
|
rng.setEnd(body.firstChild, 0);
|
|
selection.setRng(rng);
|
|
}
|
|
}
|
|
if (!selection.isCollapsed()) {
|
|
editor.selection.setRng(RangeNormalizer.normalize(editor.selection.getRng()));
|
|
editor.getDoc().execCommand('Delete', false, null);
|
|
value = trimNbspAfterDeleteAndPadValue(editor.selection.getRng(), value);
|
|
}
|
|
parentNode = selection.getNode();
|
|
var parserArgs = {
|
|
context: parentNode.nodeName.toLowerCase(),
|
|
data: details.data,
|
|
insert: true
|
|
};
|
|
fragment = parser.parse(value, parserArgs);
|
|
if (details.paste === true && InsertList.isListFragment(editor.schema, fragment) && InsertList.isParentBlockLi(dom, parentNode)) {
|
|
rng = InsertList.insertAtCaret(serializer, dom, editor.selection.getRng(), fragment);
|
|
editor.selection.setRng(rng);
|
|
editor.fire('SetContent', args);
|
|
return;
|
|
}
|
|
markFragmentElements(fragment);
|
|
node = fragment.lastChild;
|
|
if (node.attr('id') === 'mce_marker') {
|
|
marker = node;
|
|
for (node = node.prev; node; node = node.walk(true)) {
|
|
if (node.type === 3 || !dom.isBlock(node.name)) {
|
|
if (editor.schema.isValidChild(node.parent.name, 'span')) {
|
|
node.parent.insert(marker, node, node.name === 'br');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
editor._selectionOverrides.showBlockCaretContainer(parentNode);
|
|
if (!parserArgs.invalid) {
|
|
value = serializer.serialize(fragment);
|
|
validInsertion(editor, value, parentNode);
|
|
} else {
|
|
selectionSetContent(editor, bookmarkHtml);
|
|
parentNode = selection.getNode();
|
|
rootNode = editor.getBody();
|
|
if (parentNode.nodeType === 9) {
|
|
parentNode = node = rootNode;
|
|
} else {
|
|
node = parentNode;
|
|
}
|
|
while (node !== rootNode) {
|
|
parentNode = node;
|
|
node = node.parentNode;
|
|
}
|
|
value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
|
|
value = serializer.serialize(parser.parse(value.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i, function () {
|
|
return serializer.serialize(fragment);
|
|
})));
|
|
if (parentNode === rootNode) {
|
|
dom.setHTML(rootNode, value);
|
|
} else {
|
|
dom.setOuterHTML(parentNode, value);
|
|
}
|
|
}
|
|
reduceInlineTextElements(editor, merge);
|
|
moveSelectionToMarker(editor, dom.get('mce_marker'));
|
|
umarkFragmentElements(editor.getBody());
|
|
trimBrsFromTableCell(editor.dom, editor.selection.getStart());
|
|
editor.fire('SetContent', args);
|
|
editor.addVisual();
|
|
};
|
|
var processValue = function (value) {
|
|
var details;
|
|
if (typeof value !== 'string') {
|
|
details = Tools.extend({
|
|
paste: value.paste,
|
|
data: { paste: value.paste }
|
|
}, value);
|
|
return {
|
|
content: value.content,
|
|
details: details
|
|
};
|
|
}
|
|
return {
|
|
content: value,
|
|
details: {}
|
|
};
|
|
};
|
|
var insertAtCaret$1 = function (editor, value) {
|
|
var result = processValue(value);
|
|
insertHtmlAtCaret(editor, result.content, result.details);
|
|
};
|
|
var InsertContent = { insertAtCaret: insertAtCaret$1 };
|
|
|
|
var nativeCommand = function (editor, command) {
|
|
editor.getDoc().execCommand(command, false, null);
|
|
};
|
|
var deleteCommand = function (editor) {
|
|
if (Outdent.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else if (CefDelete.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else if (CefBoundaryDelete.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else if (BoundaryDelete.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else if (BlockBoundaryDelete.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else if (TableDelete.backspaceDelete(editor)) {
|
|
return;
|
|
} else if (BlockRangeDelete.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else if (InlineFormatDelete.backspaceDelete(editor, false)) {
|
|
return;
|
|
} else {
|
|
nativeCommand(editor, 'Delete');
|
|
DeleteUtils.paddEmptyBody(editor);
|
|
}
|
|
};
|
|
var forwardDeleteCommand = function (editor) {
|
|
if (CefDelete.backspaceDelete(editor, true)) {
|
|
return;
|
|
} else if (CefBoundaryDelete.backspaceDelete(editor, true)) {
|
|
return;
|
|
} else if (BoundaryDelete.backspaceDelete(editor, true)) {
|
|
return;
|
|
} else if (BlockBoundaryDelete.backspaceDelete(editor, true)) {
|
|
return;
|
|
} else if (TableDelete.backspaceDelete(editor)) {
|
|
return;
|
|
} else if (BlockRangeDelete.backspaceDelete(editor, true)) {
|
|
return;
|
|
} else if (InlineFormatDelete.backspaceDelete(editor, true)) {
|
|
return;
|
|
} else {
|
|
nativeCommand(editor, 'ForwardDelete');
|
|
}
|
|
};
|
|
var DeleteCommands = {
|
|
deleteCommand: deleteCommand,
|
|
forwardDeleteCommand: forwardDeleteCommand
|
|
};
|
|
|
|
var getSpecifiedFontProp = function (propName, rootElm, elm) {
|
|
var getProperty = function (elm) {
|
|
return getRaw(elm, propName);
|
|
};
|
|
var isRoot = function (elm) {
|
|
return eq(Element.fromDom(rootElm), elm);
|
|
};
|
|
return closest(Element.fromDom(elm), function (elm) {
|
|
return getProperty(elm).isSome();
|
|
}, isRoot).bind(getProperty);
|
|
};
|
|
var round$1 = function (number, precision) {
|
|
var factor = Math.pow(10, precision);
|
|
return Math.round(number * factor) / factor;
|
|
};
|
|
var toPt = function (fontSize, precision) {
|
|
if (/[0-9.]+px$/.test(fontSize)) {
|
|
return round$1(parseInt(fontSize, 10) * 72 / 96, precision || 0) + 'pt';
|
|
}
|
|
return fontSize;
|
|
};
|
|
var normalizeFontFamily = function (fontFamily) {
|
|
return fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
|
|
};
|
|
var getComputedFontProp = function (propName, elm) {
|
|
return Option.from(DOMUtils$1.DOM.getStyle(elm, propName, true));
|
|
};
|
|
var getFontProp = function (propName) {
|
|
return function (rootElm, elm) {
|
|
return Option.from(elm).map(Element.fromDom).filter(isElement$1).bind(function (element) {
|
|
return getSpecifiedFontProp(propName, rootElm, element.dom()).or(getComputedFontProp(propName, element.dom()));
|
|
}).getOr('');
|
|
};
|
|
};
|
|
var FontInfo = {
|
|
getFontSize: getFontProp('font-size'),
|
|
getFontFamily: compose(normalizeFontFamily, getFontProp('font-family')),
|
|
toPt: toPt
|
|
};
|
|
|
|
var findFirstCaretElement = function (editor) {
|
|
return CaretFinder.firstPositionIn(editor.getBody()).map(function (caret) {
|
|
var container = caret.container();
|
|
return NodeType.isText(container) ? container.parentNode : container;
|
|
});
|
|
};
|
|
var isRangeAtStartOfNode = function (rng, root) {
|
|
return rng.startContainer === root && rng.startOffset === 0;
|
|
};
|
|
var getCaretElement = function (editor) {
|
|
return Option.from(editor.selection.getRng()).bind(function (rng) {
|
|
var root = editor.getBody();
|
|
return isRangeAtStartOfNode(rng, root) ? Option.none() : Option.from(editor.selection.getStart(true));
|
|
});
|
|
};
|
|
var fromFontSizeNumber = function (editor, value) {
|
|
if (/^[0-9\.]+$/.test(value)) {
|
|
var fontSizeNumber = parseInt(value, 10);
|
|
if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
|
|
var fontSizes = Settings.getFontStyleValues(editor);
|
|
var fontClasses = Settings.getFontSizeClasses(editor);
|
|
if (fontClasses) {
|
|
return fontClasses[fontSizeNumber - 1] || value;
|
|
} else {
|
|
return fontSizes[fontSizeNumber - 1] || value;
|
|
}
|
|
} else {
|
|
return value;
|
|
}
|
|
} else {
|
|
return value;
|
|
}
|
|
};
|
|
var normalizeFontNames = function (font) {
|
|
var fonts = font.split(/\s*,\s*/);
|
|
return map(fonts, function (font) {
|
|
if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, '\''))) {
|
|
return '\'' + font + '\'';
|
|
} else {
|
|
return font;
|
|
}
|
|
}).join(',');
|
|
};
|
|
var fontNameAction = function (editor, value) {
|
|
var font = fromFontSizeNumber(editor, value);
|
|
editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
|
|
editor.nodeChanged();
|
|
};
|
|
var fontNameQuery = function (editor) {
|
|
return getCaretElement(editor).fold(function () {
|
|
return findFirstCaretElement(editor).map(function (caretElement) {
|
|
return FontInfo.getFontFamily(editor.getBody(), caretElement);
|
|
}).getOr('');
|
|
}, function (caretElement) {
|
|
return FontInfo.getFontFamily(editor.getBody(), caretElement);
|
|
});
|
|
};
|
|
var fontSizeAction = function (editor, value) {
|
|
editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
|
|
editor.nodeChanged();
|
|
};
|
|
var fontSizeQuery = function (editor) {
|
|
return getCaretElement(editor).fold(function () {
|
|
return findFirstCaretElement(editor).map(function (caretElement) {
|
|
return FontInfo.getFontSize(editor.getBody(), caretElement);
|
|
}).getOr('');
|
|
}, function (caretElement) {
|
|
return FontInfo.getFontSize(editor.getBody(), caretElement);
|
|
});
|
|
};
|
|
|
|
var each$g = Tools.each;
|
|
var map$3 = Tools.map, inArray$2 = Tools.inArray;
|
|
var EditorCommands = function () {
|
|
function EditorCommands(editor) {
|
|
this.commands = {
|
|
state: {},
|
|
exec: {},
|
|
value: {}
|
|
};
|
|
this.editor = editor;
|
|
this.setupCommands(editor);
|
|
}
|
|
EditorCommands.prototype.execCommand = function (command, ui, value, args) {
|
|
var func, customCommand, state = false;
|
|
var self = this;
|
|
if (self.editor.removed) {
|
|
return;
|
|
}
|
|
if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(command) && (!args || !args.skip_focus)) {
|
|
self.editor.focus();
|
|
} else {
|
|
SelectionBookmark.restore(self.editor);
|
|
}
|
|
args = self.editor.fire('BeforeExecCommand', {
|
|
command: command,
|
|
ui: ui,
|
|
value: value
|
|
});
|
|
if (args.isDefaultPrevented()) {
|
|
return false;
|
|
}
|
|
customCommand = command.toLowerCase();
|
|
if (func = self.commands.exec[customCommand]) {
|
|
func(customCommand, ui, value);
|
|
self.editor.fire('ExecCommand', {
|
|
command: command,
|
|
ui: ui,
|
|
value: value
|
|
});
|
|
return true;
|
|
}
|
|
each$g(this.editor.plugins, function (p) {
|
|
if (p.execCommand && p.execCommand(command, ui, value)) {
|
|
self.editor.fire('ExecCommand', {
|
|
command: command,
|
|
ui: ui,
|
|
value: value
|
|
});
|
|
state = true;
|
|
return false;
|
|
}
|
|
});
|
|
if (state) {
|
|
return state;
|
|
}
|
|
if (self.editor.theme && self.editor.theme.execCommand && self.editor.theme.execCommand(command, ui, value)) {
|
|
self.editor.fire('ExecCommand', {
|
|
command: command,
|
|
ui: ui,
|
|
value: value
|
|
});
|
|
return true;
|
|
}
|
|
try {
|
|
state = self.editor.getDoc().execCommand(command, ui, value);
|
|
} catch (ex) {
|
|
}
|
|
if (state) {
|
|
self.editor.fire('ExecCommand', {
|
|
command: command,
|
|
ui: ui,
|
|
value: value
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
EditorCommands.prototype.queryCommandState = function (command) {
|
|
var func;
|
|
if (this.editor.quirks.isHidden() || this.editor.removed) {
|
|
return;
|
|
}
|
|
command = command.toLowerCase();
|
|
if (func = this.commands.state[command]) {
|
|
return func(command);
|
|
}
|
|
try {
|
|
return this.editor.getDoc().queryCommandState(command);
|
|
} catch (ex) {
|
|
}
|
|
return false;
|
|
};
|
|
EditorCommands.prototype.queryCommandValue = function (command) {
|
|
var func;
|
|
if (this.editor.quirks.isHidden() || this.editor.removed) {
|
|
return;
|
|
}
|
|
command = command.toLowerCase();
|
|
if (func = this.commands.value[command]) {
|
|
return func(command);
|
|
}
|
|
try {
|
|
return this.editor.getDoc().queryCommandValue(command);
|
|
} catch (ex) {
|
|
}
|
|
};
|
|
EditorCommands.prototype.addCommands = function (commandList, type) {
|
|
var self = this;
|
|
type = type || 'exec';
|
|
each$g(commandList, function (callback, command) {
|
|
each$g(command.toLowerCase().split(','), function (command) {
|
|
self.commands[type][command] = callback;
|
|
});
|
|
});
|
|
};
|
|
EditorCommands.prototype.addCommand = function (command, callback, scope) {
|
|
var _this = this;
|
|
command = command.toLowerCase();
|
|
this.commands.exec[command] = function (command, ui, value, args) {
|
|
return callback.call(scope || _this.editor, ui, value, args);
|
|
};
|
|
};
|
|
EditorCommands.prototype.queryCommandSupported = function (command) {
|
|
command = command.toLowerCase();
|
|
if (this.commands.exec[command]) {
|
|
return true;
|
|
}
|
|
try {
|
|
return this.editor.getDoc().queryCommandSupported(command);
|
|
} catch (ex) {
|
|
}
|
|
return false;
|
|
};
|
|
EditorCommands.prototype.addQueryStateHandler = function (command, callback, scope) {
|
|
var _this = this;
|
|
command = command.toLowerCase();
|
|
this.commands.state[command] = function () {
|
|
return callback.call(scope || _this.editor);
|
|
};
|
|
};
|
|
EditorCommands.prototype.addQueryValueHandler = function (command, callback, scope) {
|
|
var _this = this;
|
|
command = command.toLowerCase();
|
|
this.commands.value[command] = function () {
|
|
return callback.call(scope || _this.editor);
|
|
};
|
|
};
|
|
EditorCommands.prototype.hasCustomCommand = function (command) {
|
|
command = command.toLowerCase();
|
|
return !!this.commands.exec[command];
|
|
};
|
|
EditorCommands.prototype.execNativeCommand = function (command, ui, value) {
|
|
if (ui === undefined) {
|
|
ui = false;
|
|
}
|
|
if (value === undefined) {
|
|
value = null;
|
|
}
|
|
return this.editor.getDoc().execCommand(command, ui, value);
|
|
};
|
|
EditorCommands.prototype.isFormatMatch = function (name) {
|
|
return this.editor.formatter.match(name);
|
|
};
|
|
EditorCommands.prototype.toggleFormat = function (name, value) {
|
|
this.editor.formatter.toggle(name, value ? { value: value } : undefined);
|
|
this.editor.nodeChanged();
|
|
};
|
|
EditorCommands.prototype.storeSelection = function (type) {
|
|
this.selectionBookmark = this.editor.selection.getBookmark(type);
|
|
};
|
|
EditorCommands.prototype.restoreSelection = function () {
|
|
this.editor.selection.moveToBookmark(this.selectionBookmark);
|
|
};
|
|
EditorCommands.prototype.setupCommands = function (editor) {
|
|
var self = this;
|
|
this.addCommands({
|
|
'mceResetDesignMode,mceBeginUndoLevel': function () {
|
|
},
|
|
'mceEndUndoLevel,mceAddUndoLevel': function () {
|
|
editor.undoManager.add();
|
|
},
|
|
'Cut,Copy,Paste': function (command) {
|
|
var doc = editor.getDoc();
|
|
var failed;
|
|
try {
|
|
self.execNativeCommand(command);
|
|
} catch (ex) {
|
|
failed = true;
|
|
}
|
|
if (command === 'paste' && !doc.queryCommandEnabled(command)) {
|
|
failed = true;
|
|
}
|
|
if (failed || !doc.queryCommandSupported(command)) {
|
|
var msg = editor.translate('Your browser doesn\'t support direct access to the clipboard. ' + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
|
|
if (Env.mac) {
|
|
msg = msg.replace(/Ctrl\+/g, '\u2318+');
|
|
}
|
|
editor.notificationManager.open({
|
|
text: msg,
|
|
type: 'error'
|
|
});
|
|
}
|
|
},
|
|
'unlink': function () {
|
|
if (editor.selection.isCollapsed()) {
|
|
var elm = editor.dom.getParent(editor.selection.getStart(), 'a');
|
|
if (elm) {
|
|
editor.dom.remove(elm, true);
|
|
}
|
|
return;
|
|
}
|
|
editor.formatter.remove('link');
|
|
},
|
|
'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull,JustifyNone': function (command) {
|
|
var align = command.substring(7);
|
|
if (align === 'full') {
|
|
align = 'justify';
|
|
}
|
|
each$g('left,center,right,justify'.split(','), function (name) {
|
|
if (align !== name) {
|
|
editor.formatter.remove('align' + name);
|
|
}
|
|
});
|
|
if (align !== 'none') {
|
|
self.toggleFormat('align' + align);
|
|
}
|
|
},
|
|
'InsertUnorderedList,InsertOrderedList': function (command) {
|
|
var listElm, listParent;
|
|
self.execNativeCommand(command);
|
|
listElm = editor.dom.getParent(editor.selection.getNode(), 'ol,ul');
|
|
if (listElm) {
|
|
listParent = listElm.parentNode;
|
|
if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
|
|
self.storeSelection();
|
|
editor.dom.split(listParent, listElm);
|
|
self.restoreSelection();
|
|
}
|
|
}
|
|
},
|
|
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function (command) {
|
|
self.toggleFormat(command);
|
|
},
|
|
'ForeColor,HiliteColor': function (command, ui, value) {
|
|
self.toggleFormat(command, value);
|
|
},
|
|
'FontName': function (command, ui, value) {
|
|
fontNameAction(editor, value);
|
|
},
|
|
'FontSize': function (command, ui, value) {
|
|
fontSizeAction(editor, value);
|
|
},
|
|
'RemoveFormat': function (command) {
|
|
editor.formatter.remove(command);
|
|
},
|
|
'mceBlockQuote': function () {
|
|
self.toggleFormat('blockquote');
|
|
},
|
|
'FormatBlock': function (command, ui, value) {
|
|
return self.toggleFormat(value || 'p');
|
|
},
|
|
'mceCleanup': function () {
|
|
var bookmark = editor.selection.getBookmark();
|
|
editor.setContent(editor.getContent());
|
|
editor.selection.moveToBookmark(bookmark);
|
|
},
|
|
'mceRemoveNode': function (command, ui, value) {
|
|
var node = value || editor.selection.getNode();
|
|
if (node !== editor.getBody()) {
|
|
self.storeSelection();
|
|
editor.dom.remove(node, true);
|
|
self.restoreSelection();
|
|
}
|
|
},
|
|
'mceSelectNodeDepth': function (command, ui, value) {
|
|
var counter = 0;
|
|
editor.dom.getParent(editor.selection.getNode(), function (node) {
|
|
if (node.nodeType === 1 && counter++ === value) {
|
|
editor.selection.select(node);
|
|
return false;
|
|
}
|
|
}, editor.getBody());
|
|
},
|
|
'mceSelectNode': function (command, ui, value) {
|
|
editor.selection.select(value);
|
|
},
|
|
'mceInsertContent': function (command, ui, value) {
|
|
InsertContent.insertAtCaret(editor, value);
|
|
},
|
|
'mceInsertRawHTML': function (command, ui, value) {
|
|
editor.selection.setContent('tiny_mce_marker');
|
|
var content = editor.getContent();
|
|
editor.setContent(content.replace(/tiny_mce_marker/g, function () {
|
|
return value;
|
|
}));
|
|
},
|
|
'mceInsertNewLine': function (command, ui, value) {
|
|
InsertNewLine.insert(editor, value);
|
|
},
|
|
'mceToggleFormat': function (command, ui, value) {
|
|
self.toggleFormat(value);
|
|
},
|
|
'mceSetContent': function (command, ui, value) {
|
|
editor.setContent(value);
|
|
},
|
|
'Indent,Outdent': function (command) {
|
|
handle(editor, command);
|
|
},
|
|
'mceRepaint': function () {
|
|
},
|
|
'InsertHorizontalRule': function () {
|
|
editor.execCommand('mceInsertContent', false, '<hr />');
|
|
},
|
|
'mceToggleVisualAid': function () {
|
|
editor.hasVisual = !editor.hasVisual;
|
|
editor.addVisual();
|
|
},
|
|
'mceReplaceContent': function (command, ui, value) {
|
|
editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
|
|
},
|
|
'mceInsertLink': function (command, ui, value) {
|
|
var anchor;
|
|
if (typeof value === 'string') {
|
|
value = { href: value };
|
|
}
|
|
anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
|
|
value.href = value.href.replace(/ /g, '%20');
|
|
if (!anchor || !value.href) {
|
|
editor.formatter.remove('link');
|
|
}
|
|
if (value.href) {
|
|
editor.formatter.apply('link', value, anchor);
|
|
}
|
|
},
|
|
'selectAll': function () {
|
|
var editingHost = editor.dom.getParent(editor.selection.getStart(), NodeType.isContentEditableTrue);
|
|
if (editingHost) {
|
|
var rng = editor.dom.createRng();
|
|
rng.selectNodeContents(editingHost);
|
|
editor.selection.setRng(rng);
|
|
}
|
|
},
|
|
'delete': function () {
|
|
DeleteCommands.deleteCommand(editor);
|
|
},
|
|
'forwardDelete': function () {
|
|
DeleteCommands.forwardDeleteCommand(editor);
|
|
},
|
|
'mceNewDocument': function () {
|
|
editor.setContent('');
|
|
},
|
|
'InsertLineBreak': function (command, ui, value) {
|
|
InsertBr.insert(editor, value);
|
|
return true;
|
|
}
|
|
});
|
|
var alignStates = function (name) {
|
|
return function () {
|
|
var nodes = editor.selection.isCollapsed() ? [editor.dom.getParent(editor.selection.getNode(), editor.dom.isBlock)] : editor.selection.getSelectedBlocks();
|
|
var matches = map$3(nodes, function (node) {
|
|
return !!editor.formatter.matchNode(node, name);
|
|
});
|
|
return inArray$2(matches, true) !== -1;
|
|
};
|
|
};
|
|
self.addCommands({
|
|
'JustifyLeft': alignStates('alignleft'),
|
|
'JustifyCenter': alignStates('aligncenter'),
|
|
'JustifyRight': alignStates('alignright'),
|
|
'JustifyFull': alignStates('alignjustify'),
|
|
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': function (command) {
|
|
return self.isFormatMatch(command);
|
|
},
|
|
'mceBlockQuote': function () {
|
|
return self.isFormatMatch('blockquote');
|
|
},
|
|
'Outdent': function () {
|
|
return canOutdent(editor);
|
|
},
|
|
'InsertUnorderedList,InsertOrderedList': function (command) {
|
|
var list = editor.dom.getParent(editor.selection.getNode(), 'ul,ol');
|
|
return list && (command === 'insertunorderedlist' && list.tagName === 'UL' || command === 'insertorderedlist' && list.tagName === 'OL');
|
|
}
|
|
}, 'state');
|
|
self.addCommands({
|
|
Undo: function () {
|
|
editor.undoManager.undo();
|
|
},
|
|
Redo: function () {
|
|
editor.undoManager.redo();
|
|
}
|
|
});
|
|
self.addQueryValueHandler('FontName', function () {
|
|
return fontNameQuery(editor);
|
|
}, this);
|
|
self.addQueryValueHandler('FontSize', function () {
|
|
return fontSizeQuery(editor);
|
|
}, this);
|
|
};
|
|
return EditorCommands;
|
|
}();
|
|
|
|
var nativeEvents = Tools.makeMap('focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange ' + 'mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover ' + 'draggesture dragdrop drop drag submit ' + 'compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel', ' ');
|
|
var EventDispatcher = function () {
|
|
function EventDispatcher(settings) {
|
|
this.bindings = {};
|
|
this.settings = settings || {};
|
|
this.scope = this.settings.scope || this;
|
|
this.toggleEvent = this.settings.toggleEvent || never;
|
|
}
|
|
EventDispatcher.isNative = function (name) {
|
|
return !!nativeEvents[name.toLowerCase()];
|
|
};
|
|
EventDispatcher.prototype.fire = function (name, args) {
|
|
var handlers, i, l, callback;
|
|
name = name.toLowerCase();
|
|
args = args || {};
|
|
args.type = name;
|
|
if (!args.target) {
|
|
args.target = this.scope;
|
|
}
|
|
if (!args.preventDefault) {
|
|
args.preventDefault = function () {
|
|
args.isDefaultPrevented = always;
|
|
};
|
|
args.stopPropagation = function () {
|
|
args.isPropagationStopped = always;
|
|
};
|
|
args.stopImmediatePropagation = function () {
|
|
args.isImmediatePropagationStopped = always;
|
|
};
|
|
args.isDefaultPrevented = never;
|
|
args.isPropagationStopped = never;
|
|
args.isImmediatePropagationStopped = never;
|
|
}
|
|
if (this.settings.beforeFire) {
|
|
this.settings.beforeFire(args);
|
|
}
|
|
handlers = this.bindings[name];
|
|
if (handlers) {
|
|
for (i = 0, l = handlers.length; i < l; i++) {
|
|
callback = handlers[i];
|
|
if (callback.once) {
|
|
this.off(name, callback.func);
|
|
}
|
|
if (args.isImmediatePropagationStopped()) {
|
|
args.stopPropagation();
|
|
return args;
|
|
}
|
|
if (callback.func.call(this.scope, args) === false) {
|
|
args.preventDefault();
|
|
return args;
|
|
}
|
|
}
|
|
}
|
|
return args;
|
|
};
|
|
EventDispatcher.prototype.on = function (name, callback, prepend, extra) {
|
|
var handlers, names, i;
|
|
if (callback === false) {
|
|
callback = never;
|
|
}
|
|
if (callback) {
|
|
var wrappedCallback = { func: callback };
|
|
if (extra) {
|
|
Tools.extend(wrappedCallback, extra);
|
|
}
|
|
names = name.toLowerCase().split(' ');
|
|
i = names.length;
|
|
while (i--) {
|
|
name = names[i];
|
|
handlers = this.bindings[name];
|
|
if (!handlers) {
|
|
handlers = this.bindings[name] = [];
|
|
this.toggleEvent(name, true);
|
|
}
|
|
if (prepend) {
|
|
handlers.unshift(wrappedCallback);
|
|
} else {
|
|
handlers.push(wrappedCallback);
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
EventDispatcher.prototype.off = function (name, callback) {
|
|
var i, handlers, bindingName, names, hi;
|
|
if (name) {
|
|
names = name.toLowerCase().split(' ');
|
|
i = names.length;
|
|
while (i--) {
|
|
name = names[i];
|
|
handlers = this.bindings[name];
|
|
if (!name) {
|
|
for (bindingName in this.bindings) {
|
|
this.toggleEvent(bindingName, false);
|
|
delete this.bindings[bindingName];
|
|
}
|
|
return this;
|
|
}
|
|
if (handlers) {
|
|
if (!callback) {
|
|
handlers.length = 0;
|
|
} else {
|
|
hi = handlers.length;
|
|
while (hi--) {
|
|
if (handlers[hi].func === callback) {
|
|
handlers = handlers.slice(0, hi).concat(handlers.slice(hi + 1));
|
|
this.bindings[name] = handlers;
|
|
}
|
|
}
|
|
}
|
|
if (!handlers.length) {
|
|
this.toggleEvent(name, false);
|
|
delete this.bindings[name];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (name in this.bindings) {
|
|
this.toggleEvent(name, false);
|
|
}
|
|
this.bindings = {};
|
|
}
|
|
return this;
|
|
};
|
|
EventDispatcher.prototype.once = function (name, callback, prepend) {
|
|
return this.on(name, callback, prepend, { once: true });
|
|
};
|
|
EventDispatcher.prototype.has = function (name) {
|
|
name = name.toLowerCase();
|
|
return !(!this.bindings[name] || this.bindings[name].length === 0);
|
|
};
|
|
return EventDispatcher;
|
|
}();
|
|
|
|
var getEventDispatcher = function (obj) {
|
|
if (!obj._eventDispatcher) {
|
|
obj._eventDispatcher = new EventDispatcher({
|
|
scope: obj,
|
|
toggleEvent: function (name, state) {
|
|
if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
|
|
obj.toggleNativeEvent(name, state);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return obj._eventDispatcher;
|
|
};
|
|
var Observable = {
|
|
fire: function (name, args, bubble) {
|
|
var self = this;
|
|
if (self.removed && name !== 'remove' && name !== 'detach') {
|
|
return args;
|
|
}
|
|
var dispatcherArgs = getEventDispatcher(self).fire(name, args);
|
|
if (bubble !== false && self.parent) {
|
|
var parent = self.parent();
|
|
while (parent && !dispatcherArgs.isPropagationStopped()) {
|
|
parent.fire(name, dispatcherArgs, false);
|
|
parent = parent.parent();
|
|
}
|
|
}
|
|
return dispatcherArgs;
|
|
},
|
|
on: function (name, callback, prepend) {
|
|
return getEventDispatcher(this).on(name, callback, prepend);
|
|
},
|
|
off: function (name, callback) {
|
|
return getEventDispatcher(this).off(name, callback);
|
|
},
|
|
once: function (name, callback) {
|
|
return getEventDispatcher(this).once(name, callback);
|
|
},
|
|
hasEventListeners: function (name) {
|
|
return getEventDispatcher(this).has(name);
|
|
}
|
|
};
|
|
|
|
var DOM$7 = DOMUtils$1.DOM;
|
|
var customEventRootDelegates;
|
|
var getEventTarget = function (editor, eventName) {
|
|
if (eventName === 'selectionchange') {
|
|
return editor.getDoc();
|
|
}
|
|
if (!editor.inline && /^mouse|touch|click|contextmenu|drop|dragover|dragend/.test(eventName)) {
|
|
return editor.getDoc().documentElement;
|
|
}
|
|
if (editor.settings.event_root) {
|
|
if (!editor.eventRoot) {
|
|
editor.eventRoot = DOM$7.select(editor.settings.event_root)[0];
|
|
}
|
|
return editor.eventRoot;
|
|
}
|
|
return editor.getBody();
|
|
};
|
|
var isListening = function (editor) {
|
|
return !editor.hidden && !isReadOnly(editor);
|
|
};
|
|
var fireEvent = function (editor, eventName, e) {
|
|
if (isListening(editor)) {
|
|
editor.fire(eventName, e);
|
|
} else if (isReadOnly(editor)) {
|
|
preventReadOnlyEvents(e);
|
|
}
|
|
};
|
|
var bindEventDelegate = function (editor, eventName) {
|
|
var eventRootElm, delegate;
|
|
if (!editor.delegates) {
|
|
editor.delegates = {};
|
|
}
|
|
if (editor.delegates[eventName] || editor.removed) {
|
|
return;
|
|
}
|
|
eventRootElm = getEventTarget(editor, eventName);
|
|
if (editor.settings.event_root) {
|
|
if (!customEventRootDelegates) {
|
|
customEventRootDelegates = {};
|
|
editor.editorManager.on('removeEditor', function () {
|
|
var name;
|
|
if (!editor.editorManager.activeEditor) {
|
|
if (customEventRootDelegates) {
|
|
for (name in customEventRootDelegates) {
|
|
editor.dom.unbind(getEventTarget(editor, name));
|
|
}
|
|
customEventRootDelegates = null;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (customEventRootDelegates[eventName]) {
|
|
return;
|
|
}
|
|
delegate = function (e) {
|
|
var target = e.target;
|
|
var editors = editor.editorManager.get();
|
|
var i = editors.length;
|
|
while (i--) {
|
|
var body = editors[i].getBody();
|
|
if (body === target || DOM$7.isChildOf(target, body)) {
|
|
fireEvent(editors[i], eventName, e);
|
|
}
|
|
}
|
|
};
|
|
customEventRootDelegates[eventName] = delegate;
|
|
DOM$7.bind(eventRootElm, eventName, delegate);
|
|
} else {
|
|
delegate = function (e) {
|
|
fireEvent(editor, eventName, e);
|
|
};
|
|
DOM$7.bind(eventRootElm, eventName, delegate);
|
|
editor.delegates[eventName] = delegate;
|
|
}
|
|
};
|
|
var EditorObservable = __assign(__assign({}, Observable), {
|
|
bindPendingEventDelegates: function () {
|
|
var self = this;
|
|
Tools.each(self._pendingNativeEvents, function (name) {
|
|
bindEventDelegate(self, name);
|
|
});
|
|
},
|
|
toggleNativeEvent: function (name, state) {
|
|
var self = this;
|
|
if (name === 'focus' || name === 'blur') {
|
|
return;
|
|
}
|
|
if (state) {
|
|
if (self.initialized) {
|
|
bindEventDelegate(self, name);
|
|
} else {
|
|
if (!self._pendingNativeEvents) {
|
|
self._pendingNativeEvents = [name];
|
|
} else {
|
|
self._pendingNativeEvents.push(name);
|
|
}
|
|
}
|
|
} else if (self.initialized) {
|
|
self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
|
|
delete self.delegates[name];
|
|
}
|
|
},
|
|
unbindAllNativeEvents: function () {
|
|
var self = this;
|
|
var body = self.getBody();
|
|
var dom = self.dom;
|
|
var name;
|
|
if (self.delegates) {
|
|
for (name in self.delegates) {
|
|
self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
|
|
}
|
|
delete self.delegates;
|
|
}
|
|
if (!self.inline && body && dom) {
|
|
body.onload = null;
|
|
dom.unbind(self.getWin());
|
|
dom.unbind(self.getDoc());
|
|
}
|
|
if (dom) {
|
|
dom.unbind(body);
|
|
dom.unbind(self.getContainer());
|
|
}
|
|
}
|
|
});
|
|
|
|
var each$h = Tools.each, explode$3 = Tools.explode;
|
|
var keyCodeLookup = {
|
|
f1: 112,
|
|
f2: 113,
|
|
f3: 114,
|
|
f4: 115,
|
|
f5: 116,
|
|
f6: 117,
|
|
f7: 118,
|
|
f8: 119,
|
|
f9: 120,
|
|
f10: 121,
|
|
f11: 122,
|
|
f12: 123
|
|
};
|
|
var modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
|
|
var Shortcuts = function () {
|
|
function Shortcuts(editor) {
|
|
this.shortcuts = {};
|
|
this.pendingPatterns = [];
|
|
this.editor = editor;
|
|
var self = this;
|
|
editor.on('keyup keypress keydown', function (e) {
|
|
if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
|
|
each$h(self.shortcuts, function (shortcut) {
|
|
if (self.matchShortcut(e, shortcut)) {
|
|
self.pendingPatterns = shortcut.subpatterns.slice(0);
|
|
if (e.type === 'keydown') {
|
|
self.executeShortcutAction(shortcut);
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
if (self.matchShortcut(e, self.pendingPatterns[0])) {
|
|
if (self.pendingPatterns.length === 1) {
|
|
if (e.type === 'keydown') {
|
|
self.executeShortcutAction(self.pendingPatterns[0]);
|
|
}
|
|
}
|
|
self.pendingPatterns.shift();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
Shortcuts.prototype.add = function (pattern, desc, cmdFunc, scope) {
|
|
var self = this;
|
|
var cmd;
|
|
cmd = cmdFunc;
|
|
if (typeof cmdFunc === 'string') {
|
|
cmdFunc = function () {
|
|
self.editor.execCommand(cmd, false, null);
|
|
};
|
|
} else if (Tools.isArray(cmd)) {
|
|
cmdFunc = function () {
|
|
self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
|
|
};
|
|
}
|
|
each$h(explode$3(Tools.trim(pattern)), function (pattern) {
|
|
var shortcut = self.createShortcut(pattern, desc, cmdFunc, scope);
|
|
self.shortcuts[shortcut.id] = shortcut;
|
|
});
|
|
return true;
|
|
};
|
|
Shortcuts.prototype.remove = function (pattern) {
|
|
var shortcut = this.createShortcut(pattern);
|
|
if (this.shortcuts[shortcut.id]) {
|
|
delete this.shortcuts[shortcut.id];
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
Shortcuts.prototype.parseShortcut = function (pattern) {
|
|
var id, key;
|
|
var shortcut = {};
|
|
each$h(explode$3(pattern.toLowerCase(), '+'), function (value) {
|
|
if (value in modifierNames) {
|
|
shortcut[value] = true;
|
|
} else {
|
|
if (/^[0-9]{2,}$/.test(value)) {
|
|
shortcut.keyCode = parseInt(value, 10);
|
|
} else {
|
|
shortcut.charCode = value.charCodeAt(0);
|
|
shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
|
|
}
|
|
}
|
|
});
|
|
id = [shortcut.keyCode];
|
|
for (key in modifierNames) {
|
|
if (shortcut[key]) {
|
|
id.push(key);
|
|
} else {
|
|
shortcut[key] = false;
|
|
}
|
|
}
|
|
shortcut.id = id.join(',');
|
|
if (shortcut.access) {
|
|
shortcut.alt = true;
|
|
if (Env.mac) {
|
|
shortcut.ctrl = true;
|
|
} else {
|
|
shortcut.shift = true;
|
|
}
|
|
}
|
|
if (shortcut.meta) {
|
|
if (Env.mac) {
|
|
shortcut.meta = true;
|
|
} else {
|
|
shortcut.ctrl = true;
|
|
shortcut.meta = false;
|
|
}
|
|
}
|
|
return shortcut;
|
|
};
|
|
Shortcuts.prototype.createShortcut = function (pattern, desc, cmdFunc, scope) {
|
|
var shortcuts;
|
|
shortcuts = Tools.map(explode$3(pattern, '>'), this.parseShortcut);
|
|
shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
|
|
func: cmdFunc,
|
|
scope: scope || this.editor
|
|
});
|
|
return Tools.extend(shortcuts[0], {
|
|
desc: this.editor.translate(desc),
|
|
subpatterns: shortcuts.slice(1)
|
|
});
|
|
};
|
|
Shortcuts.prototype.hasModifier = function (e) {
|
|
return e.altKey || e.ctrlKey || e.metaKey;
|
|
};
|
|
Shortcuts.prototype.isFunctionKey = function (e) {
|
|
return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
|
|
};
|
|
Shortcuts.prototype.matchShortcut = function (e, shortcut) {
|
|
if (!shortcut) {
|
|
return false;
|
|
}
|
|
if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
|
|
return false;
|
|
}
|
|
if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
|
|
return false;
|
|
}
|
|
if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
|
|
e.preventDefault();
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
Shortcuts.prototype.executeShortcutAction = function (shortcut) {
|
|
return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
|
|
};
|
|
return Shortcuts;
|
|
}();
|
|
|
|
var each$i = Tools.each, trim$4 = Tools.trim;
|
|
var queryParts = 'source protocol authority userInfo user password host port relative path directory file query anchor'.split(' ');
|
|
var DEFAULT_PORTS = {
|
|
ftp: 21,
|
|
http: 80,
|
|
https: 443,
|
|
mailto: 25
|
|
};
|
|
var URI = function () {
|
|
function URI(url, settings) {
|
|
url = trim$4(url);
|
|
this.settings = settings || {};
|
|
var baseUri = this.settings.base_uri;
|
|
var self = this;
|
|
if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
|
|
self.source = url;
|
|
return;
|
|
}
|
|
var isProtocolRelative = url.indexOf('//') === 0;
|
|
if (url.indexOf('/') === 0 && !isProtocolRelative) {
|
|
url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
|
|
}
|
|
if (!/^[\w\-]*:?\/\//.test(url)) {
|
|
var baseUrl = this.settings.base_uri ? this.settings.base_uri.path : new URI(domGlobals.document.location.href).directory;
|
|
if (this.settings.base_uri && this.settings.base_uri.protocol == '') {
|
|
url = '//mce_host' + self.toAbsPath(baseUrl, url);
|
|
} else {
|
|
var match = /([^#?]*)([#?]?.*)/.exec(url);
|
|
url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
|
|
}
|
|
}
|
|
url = url.replace(/@@/g, '(mce_at)');
|
|
var urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
|
|
each$i(queryParts, function (v, i) {
|
|
var part = urlMatch[i];
|
|
if (part) {
|
|
part = part.replace(/\(mce_at\)/g, '@@');
|
|
}
|
|
self[v] = part;
|
|
});
|
|
if (baseUri) {
|
|
if (!self.protocol) {
|
|
self.protocol = baseUri.protocol;
|
|
}
|
|
if (!self.userInfo) {
|
|
self.userInfo = baseUri.userInfo;
|
|
}
|
|
if (!self.port && self.host === 'mce_host') {
|
|
self.port = baseUri.port;
|
|
}
|
|
if (!self.host || self.host === 'mce_host') {
|
|
self.host = baseUri.host;
|
|
}
|
|
self.source = '';
|
|
}
|
|
if (isProtocolRelative) {
|
|
self.protocol = '';
|
|
}
|
|
}
|
|
URI.parseDataUri = function (uri) {
|
|
var type;
|
|
var uriComponents = decodeURIComponent(uri).split(',');
|
|
var matches = /data:([^;]+)/.exec(uriComponents[0]);
|
|
if (matches) {
|
|
type = matches[1];
|
|
}
|
|
return {
|
|
type: type,
|
|
data: uriComponents[1]
|
|
};
|
|
};
|
|
URI.getDocumentBaseUrl = function (loc) {
|
|
var baseUrl;
|
|
if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
|
|
baseUrl = loc.href;
|
|
} else {
|
|
baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
|
|
}
|
|
if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
|
|
baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
|
if (!/[\/\\]$/.test(baseUrl)) {
|
|
baseUrl += '/';
|
|
}
|
|
}
|
|
return baseUrl;
|
|
};
|
|
URI.prototype.setPath = function (path) {
|
|
var pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
|
|
this.path = pathMatch[0];
|
|
this.directory = pathMatch[1];
|
|
this.file = pathMatch[2];
|
|
this.source = '';
|
|
this.getURI();
|
|
};
|
|
URI.prototype.toRelative = function (uri) {
|
|
var output;
|
|
if (uri === './') {
|
|
return uri;
|
|
}
|
|
var relativeUri = new URI(uri, { base_uri: this });
|
|
if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
|
|
return relativeUri.getURI();
|
|
}
|
|
var tu = this.getURI(), uu = relativeUri.getURI();
|
|
if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
|
|
return tu;
|
|
}
|
|
output = this.toRelPath(this.path, relativeUri.path);
|
|
if (relativeUri.query) {
|
|
output += '?' + relativeUri.query;
|
|
}
|
|
if (relativeUri.anchor) {
|
|
output += '#' + relativeUri.anchor;
|
|
}
|
|
return output;
|
|
};
|
|
URI.prototype.toAbsolute = function (uri, noHost) {
|
|
var absoluteUri = new URI(uri, { base_uri: this });
|
|
return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
|
|
};
|
|
URI.prototype.isSameOrigin = function (uri) {
|
|
if (this.host == uri.host && this.protocol == uri.protocol) {
|
|
if (this.port == uri.port) {
|
|
return true;
|
|
}
|
|
var defaultPort = DEFAULT_PORTS[this.protocol];
|
|
if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
URI.prototype.toRelPath = function (base, path) {
|
|
var items, breakPoint = 0, out = '', i, l;
|
|
var normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
|
|
items = path.split('/');
|
|
if (normalizedBase.length >= items.length) {
|
|
for (i = 0, l = normalizedBase.length; i < l; i++) {
|
|
if (i >= items.length || normalizedBase[i] !== items[i]) {
|
|
breakPoint = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (normalizedBase.length < items.length) {
|
|
for (i = 0, l = items.length; i < l; i++) {
|
|
if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
|
|
breakPoint = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (breakPoint === 1) {
|
|
return path;
|
|
}
|
|
for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
|
|
out += '../';
|
|
}
|
|
for (i = breakPoint - 1, l = items.length; i < l; i++) {
|
|
if (i !== breakPoint - 1) {
|
|
out += '/' + items[i];
|
|
} else {
|
|
out += items[i];
|
|
}
|
|
}
|
|
return out;
|
|
};
|
|
URI.prototype.toAbsPath = function (base, path) {
|
|
var i, nb = 0, o = [], tr, outPath;
|
|
tr = /\/$/.test(path) ? '/' : '';
|
|
var normalizedBase = base.split('/');
|
|
var normalizedPath = path.split('/');
|
|
each$i(normalizedBase, function (k) {
|
|
if (k) {
|
|
o.push(k);
|
|
}
|
|
});
|
|
normalizedBase = o;
|
|
for (i = normalizedPath.length - 1, o = []; i >= 0; i--) {
|
|
if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
|
|
continue;
|
|
}
|
|
if (normalizedPath[i] === '..') {
|
|
nb++;
|
|
continue;
|
|
}
|
|
if (nb > 0) {
|
|
nb--;
|
|
continue;
|
|
}
|
|
o.push(normalizedPath[i]);
|
|
}
|
|
i = normalizedBase.length - nb;
|
|
if (i <= 0) {
|
|
outPath = o.reverse().join('/');
|
|
} else {
|
|
outPath = normalizedBase.slice(0, i).join('/') + '/' + o.reverse().join('/');
|
|
}
|
|
if (outPath.indexOf('/') !== 0) {
|
|
outPath = '/' + outPath;
|
|
}
|
|
if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
|
|
outPath += tr;
|
|
}
|
|
return outPath;
|
|
};
|
|
URI.prototype.getURI = function (noProtoHost) {
|
|
if (noProtoHost === void 0) {
|
|
noProtoHost = false;
|
|
}
|
|
var s;
|
|
if (!this.source || noProtoHost) {
|
|
s = '';
|
|
if (!noProtoHost) {
|
|
if (this.protocol) {
|
|
s += this.protocol + '://';
|
|
} else {
|
|
s += '//';
|
|
}
|
|
if (this.userInfo) {
|
|
s += this.userInfo + '@';
|
|
}
|
|
if (this.host) {
|
|
s += this.host;
|
|
}
|
|
if (this.port) {
|
|
s += ':' + this.port;
|
|
}
|
|
}
|
|
if (this.path) {
|
|
s += this.path;
|
|
}
|
|
if (this.query) {
|
|
s += '?' + this.query;
|
|
}
|
|
if (this.anchor) {
|
|
s += '#' + this.anchor;
|
|
}
|
|
this.source = s;
|
|
}
|
|
return this.source;
|
|
};
|
|
return URI;
|
|
}();
|
|
|
|
var create$5 = function () {
|
|
var buttons = {};
|
|
var menuItems = {};
|
|
var popups = {};
|
|
var icons = {};
|
|
var contextMenus = {};
|
|
var contextToolbars = {};
|
|
var sidebars = {};
|
|
var add = function (collection, type) {
|
|
return function (name, spec) {
|
|
return collection[name.toLowerCase()] = __assign(__assign({}, spec), { type: type });
|
|
};
|
|
};
|
|
var addIcon = function (name, svgData) {
|
|
return icons[name.toLowerCase()] = svgData;
|
|
};
|
|
return {
|
|
addButton: add(buttons, 'button'),
|
|
addToggleButton: add(buttons, 'togglebutton'),
|
|
addMenuButton: add(buttons, 'menubutton'),
|
|
addSplitButton: add(buttons, 'splitbutton'),
|
|
addMenuItem: add(menuItems, 'menuitem'),
|
|
addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
|
|
addToggleMenuItem: add(menuItems, 'togglemenuitem'),
|
|
addAutocompleter: add(popups, 'autocompleter'),
|
|
addContextMenu: add(contextMenus, 'contextmenu'),
|
|
addContextToolbar: add(contextToolbars, 'contexttoolbar'),
|
|
addContextForm: add(contextToolbars, 'contextform'),
|
|
addSidebar: add(sidebars, 'sidebar'),
|
|
addIcon: addIcon,
|
|
getAll: function () {
|
|
return {
|
|
buttons: buttons,
|
|
menuItems: menuItems,
|
|
icons: icons,
|
|
popups: popups,
|
|
contextMenus: contextMenus,
|
|
contextToolbars: contextToolbars,
|
|
sidebars: sidebars
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
var registry = function () {
|
|
var bridge = create$5();
|
|
return {
|
|
addAutocompleter: bridge.addAutocompleter,
|
|
addButton: bridge.addButton,
|
|
addContextForm: bridge.addContextForm,
|
|
addContextMenu: bridge.addContextMenu,
|
|
addContextToolbar: bridge.addContextToolbar,
|
|
addIcon: bridge.addIcon,
|
|
addMenuButton: bridge.addMenuButton,
|
|
addMenuItem: bridge.addMenuItem,
|
|
addNestedMenuItem: bridge.addNestedMenuItem,
|
|
addSidebar: bridge.addSidebar,
|
|
addSplitButton: bridge.addSplitButton,
|
|
addToggleButton: bridge.addToggleButton,
|
|
addToggleMenuItem: bridge.addToggleMenuItem,
|
|
getAll: bridge.getAll
|
|
};
|
|
};
|
|
|
|
var DOM$8 = DOMUtils$1.DOM;
|
|
var extend$3 = Tools.extend, each$j = Tools.each;
|
|
var resolve$3 = Tools.resolve;
|
|
var ie$1 = Env.ie;
|
|
var Editor = function () {
|
|
function Editor(id, settings, editorManager) {
|
|
var _this = this;
|
|
this.plugins = {};
|
|
this.contentCSS = [];
|
|
this.contentStyles = [];
|
|
this.loadedCSS = {};
|
|
this.isNotDirty = false;
|
|
this.editorManager = editorManager;
|
|
this.documentBaseUrl = editorManager.documentBaseURL;
|
|
extend$3(this, EditorObservable);
|
|
this.settings = getEditorSettings(this, id, this.documentBaseUrl, editorManager.defaultSettings, settings);
|
|
if (this.settings.suffix) {
|
|
editorManager.suffix = this.settings.suffix;
|
|
}
|
|
this.suffix = editorManager.suffix;
|
|
if (this.settings.base_url) {
|
|
editorManager._setBaseUrl(this.settings.base_url);
|
|
}
|
|
this.baseUri = editorManager.baseURI;
|
|
if (this.settings.referrer_policy) {
|
|
ScriptLoader.ScriptLoader._setReferrerPolicy(this.settings.referrer_policy);
|
|
DOMUtils$1.DOM.styleSheetLoader._setReferrerPolicy(this.settings.referrer_policy);
|
|
}
|
|
AddOnManager$1.languageLoad = this.settings.language_load;
|
|
AddOnManager$1.baseURL = editorManager.baseURL;
|
|
this.id = id;
|
|
this.setDirty(false);
|
|
this.documentBaseURI = new URI(this.settings.document_base_url, { base_uri: this.baseUri });
|
|
this.baseURI = this.baseUri;
|
|
this.inline = !!this.settings.inline;
|
|
this.shortcuts = new Shortcuts(this);
|
|
this.editorCommands = new EditorCommands(this);
|
|
if (this.settings.cache_suffix) {
|
|
Env.cacheSuffix = this.settings.cache_suffix.replace(/^[\?\&]+/, '');
|
|
}
|
|
this.ui = { registry: registry() };
|
|
var self = this;
|
|
var modeInstance = create$4(self);
|
|
this.mode = modeInstance;
|
|
this.setMode = modeInstance.set;
|
|
editorManager.fire('SetupEditor', { editor: this });
|
|
this.execCallback('setup', this);
|
|
this.$ = DomQuery.overrideDefaults(function () {
|
|
return {
|
|
context: _this.inline ? _this.getBody() : _this.getDoc(),
|
|
element: _this.getBody()
|
|
};
|
|
});
|
|
}
|
|
Editor.prototype.render = function () {
|
|
Render.render(this);
|
|
};
|
|
Editor.prototype.focus = function (skipFocus) {
|
|
EditorFocus.focus(this, skipFocus);
|
|
};
|
|
Editor.prototype.hasFocus = function () {
|
|
return EditorFocus.hasFocus(this);
|
|
};
|
|
Editor.prototype.execCallback = function (name) {
|
|
var x = [];
|
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
x[_i - 1] = arguments[_i];
|
|
}
|
|
var self = this;
|
|
var callback = self.settings[name], scope;
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
if (self.callbackLookup && (scope = self.callbackLookup[name])) {
|
|
callback = scope.func;
|
|
scope = scope.scope;
|
|
}
|
|
if (typeof callback === 'string') {
|
|
scope = callback.replace(/\.\w+$/, '');
|
|
scope = scope ? resolve$3(scope) : 0;
|
|
callback = resolve$3(callback);
|
|
self.callbackLookup = self.callbackLookup || {};
|
|
self.callbackLookup[name] = {
|
|
func: callback,
|
|
scope: scope
|
|
};
|
|
}
|
|
return callback.apply(scope || self, Array.prototype.slice.call(arguments, 1));
|
|
};
|
|
Editor.prototype.translate = function (text) {
|
|
return I18n.translate(text);
|
|
};
|
|
Editor.prototype.getParam = function (name, defaultVal, type) {
|
|
return getParam(this, name, defaultVal, type);
|
|
};
|
|
Editor.prototype.nodeChanged = function (args) {
|
|
this._nodeChangeDispatcher.nodeChanged(args);
|
|
};
|
|
Editor.prototype.addCommand = function (name, callback, scope) {
|
|
this.editorCommands.addCommand(name, callback, scope);
|
|
};
|
|
Editor.prototype.addQueryStateHandler = function (name, callback, scope) {
|
|
this.editorCommands.addQueryStateHandler(name, callback, scope);
|
|
};
|
|
Editor.prototype.addQueryValueHandler = function (name, callback, scope) {
|
|
this.editorCommands.addQueryValueHandler(name, callback, scope);
|
|
};
|
|
Editor.prototype.addShortcut = function (pattern, desc, cmdFunc, scope) {
|
|
this.shortcuts.add(pattern, desc, cmdFunc, scope);
|
|
};
|
|
Editor.prototype.execCommand = function (cmd, ui, value, args) {
|
|
return this.editorCommands.execCommand(cmd, ui, value, args);
|
|
};
|
|
Editor.prototype.queryCommandState = function (cmd) {
|
|
return this.editorCommands.queryCommandState(cmd);
|
|
};
|
|
Editor.prototype.queryCommandValue = function (cmd) {
|
|
return this.editorCommands.queryCommandValue(cmd);
|
|
};
|
|
Editor.prototype.queryCommandSupported = function (cmd) {
|
|
return this.editorCommands.queryCommandSupported(cmd);
|
|
};
|
|
Editor.prototype.show = function () {
|
|
var self = this;
|
|
if (self.hidden) {
|
|
self.hidden = false;
|
|
if (self.inline) {
|
|
self.getBody().contentEditable = 'true';
|
|
} else {
|
|
DOM$8.show(self.getContainer());
|
|
DOM$8.hide(self.id);
|
|
}
|
|
self.load();
|
|
self.fire('show');
|
|
}
|
|
};
|
|
Editor.prototype.hide = function () {
|
|
var self = this, doc = self.getDoc();
|
|
if (!self.hidden) {
|
|
if (ie$1 && doc && !self.inline) {
|
|
doc.execCommand('SelectAll');
|
|
}
|
|
self.save();
|
|
if (self.inline) {
|
|
self.getBody().contentEditable = 'false';
|
|
if (self === self.editorManager.focusedEditor) {
|
|
self.editorManager.focusedEditor = null;
|
|
}
|
|
} else {
|
|
DOM$8.hide(self.getContainer());
|
|
DOM$8.setStyle(self.id, 'display', self.orgDisplay);
|
|
}
|
|
self.hidden = true;
|
|
self.fire('hide');
|
|
}
|
|
};
|
|
Editor.prototype.isHidden = function () {
|
|
return !!this.hidden;
|
|
};
|
|
Editor.prototype.setProgressState = function (state, time) {
|
|
this.fire('ProgressState', {
|
|
state: state,
|
|
time: time
|
|
});
|
|
};
|
|
Editor.prototype.load = function (args) {
|
|
var self = this;
|
|
var elm = self.getElement(), html;
|
|
if (self.removed) {
|
|
return '';
|
|
}
|
|
if (elm) {
|
|
args = args || {};
|
|
args.load = true;
|
|
var value = NodeType.isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
|
|
html = self.setContent(value, args);
|
|
args.element = elm;
|
|
if (!args.no_events) {
|
|
self.fire('LoadContent', args);
|
|
}
|
|
args.element = elm = null;
|
|
return html;
|
|
}
|
|
};
|
|
Editor.prototype.save = function (args) {
|
|
var self = this;
|
|
var elm = self.getElement(), html, form;
|
|
if (!elm || !self.initialized || self.removed) {
|
|
return;
|
|
}
|
|
args = args || {};
|
|
args.save = true;
|
|
args.element = elm;
|
|
html = args.content = self.getContent(args);
|
|
if (!args.no_events) {
|
|
self.fire('SaveContent', args);
|
|
}
|
|
if (args.format === 'raw') {
|
|
self.fire('RawSaveContent', args);
|
|
}
|
|
html = args.content;
|
|
if (!NodeType.isTextareaOrInput(elm)) {
|
|
if (args.is_removing || !self.inline) {
|
|
elm.innerHTML = html;
|
|
}
|
|
if (form = DOM$8.getParent(self.id, 'form')) {
|
|
each$j(form.elements, function (elm) {
|
|
if (elm.name === self.id) {
|
|
elm.value = html;
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
elm.value = html;
|
|
}
|
|
args.element = elm = null;
|
|
if (args.set_dirty !== false) {
|
|
self.setDirty(false);
|
|
}
|
|
return html;
|
|
};
|
|
Editor.prototype.setContent = function (content, args) {
|
|
return setContent(this, content, args);
|
|
};
|
|
Editor.prototype.getContent = function (args) {
|
|
return getContent(this, args);
|
|
};
|
|
Editor.prototype.insertContent = function (content, args) {
|
|
if (args) {
|
|
content = extend$3({ content: content }, args);
|
|
}
|
|
this.execCommand('mceInsertContent', false, content);
|
|
};
|
|
Editor.prototype.resetContent = function (initialContent) {
|
|
if (initialContent === undefined) {
|
|
setContent(this, this.startContent, { format: 'raw' });
|
|
} else {
|
|
setContent(this, initialContent);
|
|
}
|
|
this.undoManager.reset();
|
|
this.setDirty(false);
|
|
this.nodeChanged();
|
|
};
|
|
Editor.prototype.isDirty = function () {
|
|
return !this.isNotDirty;
|
|
};
|
|
Editor.prototype.setDirty = function (state) {
|
|
var oldState = !this.isNotDirty;
|
|
this.isNotDirty = !state;
|
|
if (state && state !== oldState) {
|
|
this.fire('dirty');
|
|
}
|
|
};
|
|
Editor.prototype.getContainer = function () {
|
|
var self = this;
|
|
if (!self.container) {
|
|
self.container = DOM$8.get(self.editorContainer || self.id + '_parent');
|
|
}
|
|
return self.container;
|
|
};
|
|
Editor.prototype.getContentAreaContainer = function () {
|
|
return this.contentAreaContainer;
|
|
};
|
|
Editor.prototype.getElement = function () {
|
|
if (!this.targetElm) {
|
|
this.targetElm = DOM$8.get(this.id);
|
|
}
|
|
return this.targetElm;
|
|
};
|
|
Editor.prototype.getWin = function () {
|
|
var self = this;
|
|
var elm;
|
|
if (!self.contentWindow) {
|
|
elm = self.iframeElement;
|
|
if (elm) {
|
|
self.contentWindow = elm.contentWindow;
|
|
}
|
|
}
|
|
return self.contentWindow;
|
|
};
|
|
Editor.prototype.getDoc = function () {
|
|
var self = this;
|
|
var win;
|
|
if (!self.contentDocument) {
|
|
win = self.getWin();
|
|
if (win) {
|
|
self.contentDocument = win.document;
|
|
}
|
|
}
|
|
return self.contentDocument;
|
|
};
|
|
Editor.prototype.getBody = function () {
|
|
var doc = this.getDoc();
|
|
return this.bodyElement || (doc ? doc.body : null);
|
|
};
|
|
Editor.prototype.convertURL = function (url, name, elm) {
|
|
var self = this, settings = self.settings;
|
|
if (settings.urlconverter_callback) {
|
|
return self.execCallback('urlconverter_callback', url, elm, true, name);
|
|
}
|
|
if (!settings.convert_urls || elm && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
|
|
return url;
|
|
}
|
|
if (settings.relative_urls) {
|
|
return self.documentBaseURI.toRelative(url);
|
|
}
|
|
url = self.documentBaseURI.toAbsolute(url, settings.remove_script_host);
|
|
return url;
|
|
};
|
|
Editor.prototype.addVisual = function (elm) {
|
|
var self = this;
|
|
var settings = self.settings;
|
|
var dom = self.dom;
|
|
var cls;
|
|
elm = elm || self.getBody();
|
|
if (self.hasVisual === undefined) {
|
|
self.hasVisual = settings.visual;
|
|
}
|
|
each$j(dom.select('table,a', elm), function (elm) {
|
|
var value;
|
|
switch (elm.nodeName) {
|
|
case 'TABLE':
|
|
cls = settings.visual_table_class || 'mce-item-table';
|
|
value = dom.getAttrib(elm, 'border');
|
|
if ((!value || value === '0') && self.hasVisual) {
|
|
dom.addClass(elm, cls);
|
|
} else {
|
|
dom.removeClass(elm, cls);
|
|
}
|
|
return;
|
|
case 'A':
|
|
if (!dom.getAttrib(elm, 'href')) {
|
|
value = dom.getAttrib(elm, 'name') || elm.id;
|
|
cls = settings.visual_anchor_class || 'mce-item-anchor';
|
|
if (value && self.hasVisual) {
|
|
dom.addClass(elm, cls);
|
|
} else {
|
|
dom.removeClass(elm, cls);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
});
|
|
self.fire('VisualAid', {
|
|
element: elm,
|
|
hasVisual: self.hasVisual
|
|
});
|
|
};
|
|
Editor.prototype.remove = function () {
|
|
remove$6(this);
|
|
};
|
|
Editor.prototype.destroy = function (automatic) {
|
|
destroy(this, automatic);
|
|
};
|
|
Editor.prototype.uploadImages = function (callback) {
|
|
return this.editorUpload.uploadImages(callback);
|
|
};
|
|
Editor.prototype._scanForImages = function () {
|
|
return this.editorUpload.scanForImages();
|
|
};
|
|
Editor.prototype.addButton = function () {
|
|
throw new Error('editor.addButton has been removed in tinymce 5x, use editor.ui.registry.addButton or editor.ui.registry.addToggleButton or editor.ui.registry.addSplitButton instead');
|
|
};
|
|
Editor.prototype.addSidebar = function () {
|
|
throw new Error('editor.addSidebar has been removed in tinymce 5x, use editor.ui.registry.addSidebar instead');
|
|
};
|
|
Editor.prototype.addMenuItem = function () {
|
|
throw new Error('editor.addMenuItem has been removed in tinymce 5x, use editor.ui.registry.addMenuItem instead');
|
|
};
|
|
Editor.prototype.addContextToolbar = function () {
|
|
throw new Error('editor.addContextToolbar has been removed in tinymce 5x, use editor.ui.registry.addContextToolbar instead');
|
|
};
|
|
return Editor;
|
|
}();
|
|
|
|
var DOM$9 = DOMUtils$1.DOM;
|
|
var explode$4 = Tools.explode, each$k = Tools.each, extend$4 = Tools.extend;
|
|
var instanceCounter = 0, boundGlobalEvents = false;
|
|
var beforeUnloadDelegate;
|
|
var legacyEditors = [];
|
|
var editors = [];
|
|
var isValidLegacyKey = function (id) {
|
|
return id !== 'length';
|
|
};
|
|
var globalEventDelegate = function (e) {
|
|
var type = e.type;
|
|
each$k(EditorManager.get(), function (editor) {
|
|
switch (type) {
|
|
case 'scroll':
|
|
editor.fire('ScrollWindow', e);
|
|
break;
|
|
case 'resize':
|
|
editor.fire('ResizeWindow', e);
|
|
break;
|
|
}
|
|
});
|
|
};
|
|
var toggleGlobalEvents = function (state) {
|
|
if (state !== boundGlobalEvents) {
|
|
if (state) {
|
|
DomQuery(window).on('resize scroll', globalEventDelegate);
|
|
} else {
|
|
DomQuery(window).off('resize scroll', globalEventDelegate);
|
|
}
|
|
boundGlobalEvents = state;
|
|
}
|
|
};
|
|
var removeEditorFromList = function (targetEditor) {
|
|
var oldEditors = editors;
|
|
delete legacyEditors[targetEditor.id];
|
|
for (var i = 0; i < legacyEditors.length; i++) {
|
|
if (legacyEditors[i] === targetEditor) {
|
|
legacyEditors.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
editors = filter(editors, function (editor) {
|
|
return targetEditor !== editor;
|
|
});
|
|
if (EditorManager.activeEditor === targetEditor) {
|
|
EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
|
|
}
|
|
if (EditorManager.focusedEditor === targetEditor) {
|
|
EditorManager.focusedEditor = null;
|
|
}
|
|
return oldEditors.length !== editors.length;
|
|
};
|
|
var purgeDestroyedEditor = function (editor) {
|
|
if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
|
|
removeEditorFromList(editor);
|
|
editor.unbindAllNativeEvents();
|
|
editor.destroy(true);
|
|
editor.removed = true;
|
|
editor = null;
|
|
}
|
|
return editor;
|
|
};
|
|
var isQuirksMode = domGlobals.document.compatMode !== 'CSS1Compat';
|
|
var EditorManager = __assign(__assign({}, Observable), {
|
|
baseURI: null,
|
|
baseURL: null,
|
|
defaultSettings: {},
|
|
documentBaseURL: null,
|
|
suffix: null,
|
|
$: DomQuery,
|
|
majorVersion: '5',
|
|
minorVersion: '1.4',
|
|
releaseDate: '2019-12-11',
|
|
editors: legacyEditors,
|
|
i18n: I18n,
|
|
activeEditor: null,
|
|
focusedEditor: null,
|
|
settings: {},
|
|
setup: function () {
|
|
var self = this;
|
|
var baseURL, documentBaseURL, suffix = '';
|
|
documentBaseURL = URI.getDocumentBaseUrl(domGlobals.document.location);
|
|
if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
|
|
documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
|
if (!/[\/\\]$/.test(documentBaseURL)) {
|
|
documentBaseURL += '/';
|
|
}
|
|
}
|
|
var preInit = window.tinymce || window.tinyMCEPreInit;
|
|
if (preInit) {
|
|
baseURL = preInit.base || preInit.baseURL;
|
|
suffix = preInit.suffix;
|
|
} else {
|
|
var scripts = domGlobals.document.getElementsByTagName('script');
|
|
for (var i = 0; i < scripts.length; i++) {
|
|
var src = scripts[i].src || '';
|
|
if (src === '') {
|
|
continue;
|
|
}
|
|
var srcScript = src.substring(src.lastIndexOf('/'));
|
|
if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
|
|
if (srcScript.indexOf('.min') !== -1) {
|
|
suffix = '.min';
|
|
}
|
|
baseURL = src.substring(0, src.lastIndexOf('/'));
|
|
break;
|
|
}
|
|
}
|
|
if (!baseURL && domGlobals.document.currentScript) {
|
|
var src = domGlobals.document.currentScript.src;
|
|
if (src.indexOf('.min') !== -1) {
|
|
suffix = '.min';
|
|
}
|
|
baseURL = src.substring(0, src.lastIndexOf('/'));
|
|
}
|
|
}
|
|
self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
|
|
self.documentBaseURL = documentBaseURL;
|
|
self.baseURI = new URI(self.baseURL);
|
|
self.suffix = suffix;
|
|
FocusController.setup(self);
|
|
},
|
|
overrideDefaults: function (defaultSettings) {
|
|
var baseUrl, suffix;
|
|
baseUrl = defaultSettings.base_url;
|
|
if (baseUrl) {
|
|
this._setBaseUrl(baseUrl);
|
|
}
|
|
suffix = defaultSettings.suffix;
|
|
if (defaultSettings.suffix) {
|
|
this.suffix = suffix;
|
|
}
|
|
this.defaultSettings = defaultSettings;
|
|
var pluginBaseUrls = defaultSettings.plugin_base_urls;
|
|
for (var name in pluginBaseUrls) {
|
|
AddOnManager$1.PluginManager.urls[name] = pluginBaseUrls[name];
|
|
}
|
|
},
|
|
init: function (settings) {
|
|
var self = this;
|
|
var result, invalidInlineTargets;
|
|
invalidInlineTargets = Tools.makeMap('area base basefont br col frame hr img input isindex link meta param embed source wbr track ' + 'colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu', ' ');
|
|
var isInvalidInlineTarget = function (settings, elm) {
|
|
return settings.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
|
|
};
|
|
var createId = function (elm) {
|
|
var id = elm.id;
|
|
if (!id) {
|
|
id = elm.name;
|
|
if (id && !DOM$9.get(id)) {
|
|
id = elm.name;
|
|
} else {
|
|
id = DOM$9.uniqueId();
|
|
}
|
|
elm.setAttribute('id', id);
|
|
}
|
|
return id;
|
|
};
|
|
var execCallback = function (name) {
|
|
var callback = settings[name];
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
return callback.apply(self, Array.prototype.slice.call(arguments, 2));
|
|
};
|
|
var hasClass = function (elm, className) {
|
|
return className.constructor === RegExp ? className.test(elm.className) : DOM$9.hasClass(elm, className);
|
|
};
|
|
var findTargets = function (settings) {
|
|
var l, targets = [];
|
|
if (Env.browser.isIE() && Env.browser.version.major < 11) {
|
|
ErrorReporter.initError('TinyMCE does not support the browser you are using. For a list of supported' + ' browsers please see: https://www.tinymce.com/docs/get-started/system-requirements/');
|
|
return [];
|
|
} else if (isQuirksMode) {
|
|
ErrorReporter.initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
|
|
return [];
|
|
}
|
|
if (settings.types) {
|
|
each$k(settings.types, function (type) {
|
|
targets = targets.concat(DOM$9.select(type.selector));
|
|
});
|
|
return targets;
|
|
} else if (settings.selector) {
|
|
return DOM$9.select(settings.selector);
|
|
} else if (settings.target) {
|
|
return [settings.target];
|
|
}
|
|
switch (settings.mode) {
|
|
case 'exact':
|
|
l = settings.elements || '';
|
|
if (l.length > 0) {
|
|
each$k(explode$4(l), function (id) {
|
|
var elm;
|
|
if (elm = DOM$9.get(id)) {
|
|
targets.push(elm);
|
|
} else {
|
|
each$k(domGlobals.document.forms, function (f) {
|
|
each$k(f.elements, function (e) {
|
|
if (e.name === id) {
|
|
id = 'mce_editor_' + instanceCounter++;
|
|
DOM$9.setAttrib(e, 'id', id);
|
|
targets.push(e);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case 'textareas':
|
|
case 'specific_textareas':
|
|
each$k(DOM$9.select('textarea'), function (elm) {
|
|
if (settings.editor_deselector && hasClass(elm, settings.editor_deselector)) {
|
|
return;
|
|
}
|
|
if (!settings.editor_selector || hasClass(elm, settings.editor_selector)) {
|
|
targets.push(elm);
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
return targets;
|
|
};
|
|
var provideResults = function (editors) {
|
|
result = editors;
|
|
};
|
|
var initEditors = function () {
|
|
var initCount = 0;
|
|
var editors = [];
|
|
var targets;
|
|
var createEditor = function (id, settings, targetElm) {
|
|
var editor = new Editor(id, settings, self);
|
|
editors.push(editor);
|
|
editor.on('init', function () {
|
|
if (++initCount === targets.length) {
|
|
provideResults(editors);
|
|
}
|
|
});
|
|
editor.targetElm = editor.targetElm || targetElm;
|
|
editor.render();
|
|
};
|
|
DOM$9.unbind(window, 'ready', initEditors);
|
|
execCallback('onpageload');
|
|
targets = DomQuery.unique(findTargets(settings));
|
|
if (settings.types) {
|
|
each$k(settings.types, function (type) {
|
|
Tools.each(targets, function (elm) {
|
|
if (DOM$9.is(elm, type.selector)) {
|
|
createEditor(createId(elm), extend$4({}, settings, type), elm);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
});
|
|
return;
|
|
}
|
|
Tools.each(targets, function (elm) {
|
|
purgeDestroyedEditor(self.get(elm.id));
|
|
});
|
|
targets = Tools.grep(targets, function (elm) {
|
|
return !self.get(elm.id);
|
|
});
|
|
if (targets.length === 0) {
|
|
provideResults([]);
|
|
} else {
|
|
each$k(targets, function (elm) {
|
|
if (isInvalidInlineTarget(settings, elm)) {
|
|
ErrorReporter.initError('Could not initialize inline editor on invalid inline target element', elm);
|
|
} else {
|
|
createEditor(createId(elm), settings, elm);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
self.settings = settings;
|
|
DOM$9.bind(window, 'ready', initEditors);
|
|
return new promiseObj(function (resolve) {
|
|
if (result) {
|
|
resolve(result);
|
|
} else {
|
|
provideResults = function (editors) {
|
|
resolve(editors);
|
|
};
|
|
}
|
|
});
|
|
},
|
|
get: function (id) {
|
|
if (arguments.length === 0) {
|
|
return editors.slice(0);
|
|
} else if (isString(id)) {
|
|
return find(editors, function (editor) {
|
|
return editor.id === id;
|
|
}).getOr(null);
|
|
} else if (isNumber(id)) {
|
|
return editors[id] ? editors[id] : null;
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
add: function (editor) {
|
|
var self = this;
|
|
var existingEditor;
|
|
existingEditor = legacyEditors[editor.id];
|
|
if (existingEditor === editor) {
|
|
return editor;
|
|
}
|
|
if (self.get(editor.id) === null) {
|
|
if (isValidLegacyKey(editor.id)) {
|
|
legacyEditors[editor.id] = editor;
|
|
}
|
|
legacyEditors.push(editor);
|
|
editors.push(editor);
|
|
}
|
|
toggleGlobalEvents(true);
|
|
self.activeEditor = editor;
|
|
self.fire('AddEditor', { editor: editor });
|
|
if (!beforeUnloadDelegate) {
|
|
beforeUnloadDelegate = function (e) {
|
|
var event = self.fire('BeforeUnload');
|
|
if (event.returnValue) {
|
|
e.preventDefault();
|
|
e.returnValue = event.returnValue;
|
|
return event.returnValue;
|
|
}
|
|
};
|
|
window.addEventListener('beforeunload', beforeUnloadDelegate);
|
|
}
|
|
return editor;
|
|
},
|
|
createEditor: function (id, settings) {
|
|
return this.add(new Editor(id, settings, this));
|
|
},
|
|
remove: function (selector) {
|
|
var self = this;
|
|
var i, editor;
|
|
if (!selector) {
|
|
for (i = editors.length - 1; i >= 0; i--) {
|
|
self.remove(editors[i]);
|
|
}
|
|
return;
|
|
}
|
|
if (isString(selector)) {
|
|
each$k(DOM$9.select(selector), function (elm) {
|
|
editor = self.get(elm.id);
|
|
if (editor) {
|
|
self.remove(editor);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
editor = selector;
|
|
if (isNull(self.get(editor.id))) {
|
|
return null;
|
|
}
|
|
if (removeEditorFromList(editor)) {
|
|
self.fire('RemoveEditor', { editor: editor });
|
|
}
|
|
if (editors.length === 0) {
|
|
window.removeEventListener('beforeunload', beforeUnloadDelegate);
|
|
}
|
|
editor.remove();
|
|
toggleGlobalEvents(editors.length > 0);
|
|
return editor;
|
|
},
|
|
execCommand: function (cmd, ui, value) {
|
|
var self = this, editor = self.get(value);
|
|
switch (cmd) {
|
|
case 'mceAddEditor':
|
|
if (!self.get(value)) {
|
|
new Editor(value, self.settings, self).render();
|
|
}
|
|
return true;
|
|
case 'mceRemoveEditor':
|
|
if (editor) {
|
|
editor.remove();
|
|
}
|
|
return true;
|
|
case 'mceToggleEditor':
|
|
if (!editor) {
|
|
self.execCommand('mceAddEditor', 0, value);
|
|
return true;
|
|
}
|
|
if (editor.isHidden()) {
|
|
editor.show();
|
|
} else {
|
|
editor.hide();
|
|
}
|
|
return true;
|
|
}
|
|
if (self.activeEditor) {
|
|
return self.activeEditor.execCommand(cmd, ui, value);
|
|
}
|
|
return false;
|
|
},
|
|
triggerSave: function () {
|
|
each$k(editors, function (editor) {
|
|
editor.save();
|
|
});
|
|
},
|
|
addI18n: function (code, items) {
|
|
I18n.add(code, items);
|
|
},
|
|
translate: function (text) {
|
|
return I18n.translate(text);
|
|
},
|
|
setActive: function (editor) {
|
|
var activeEditor = this.activeEditor;
|
|
if (this.activeEditor !== editor) {
|
|
if (activeEditor) {
|
|
activeEditor.fire('deactivate', { relatedTarget: editor });
|
|
}
|
|
editor.fire('activate', { relatedTarget: activeEditor });
|
|
}
|
|
this.activeEditor = editor;
|
|
},
|
|
_setBaseUrl: function (baseUrl) {
|
|
this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
|
|
this.baseURI = new URI(this.baseURL);
|
|
}
|
|
});
|
|
EditorManager.setup();
|
|
|
|
function RangeUtils(dom) {
|
|
var walk = function (rng, callback) {
|
|
return RangeWalk.walk(dom, rng, callback);
|
|
};
|
|
var split = split$1;
|
|
var normalize = function (rng) {
|
|
return NormalizeRange.normalize(dom, rng).fold(constant(false), function (normalizedRng) {
|
|
rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
|
|
rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
|
|
return true;
|
|
});
|
|
};
|
|
return {
|
|
walk: walk,
|
|
split: split,
|
|
normalize: normalize
|
|
};
|
|
}
|
|
(function (RangeUtils) {
|
|
RangeUtils.compareRanges = RangeCompare.isEq;
|
|
RangeUtils.getCaretRangeFromPoint = CaretRangeFromPoint.fromPoint;
|
|
RangeUtils.getSelectedNode = getSelectedNode;
|
|
RangeUtils.getNode = getNode;
|
|
}(RangeUtils || (RangeUtils = {})));
|
|
var RangeUtils$1 = RangeUtils;
|
|
|
|
var awaiter = function (resolveCb, rejectCb, timeout) {
|
|
if (timeout === void 0) {
|
|
timeout = 1000;
|
|
}
|
|
var done = false;
|
|
var timer = null;
|
|
var complete = function (completer) {
|
|
return function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (!done) {
|
|
done = true;
|
|
if (timer !== null) {
|
|
domGlobals.clearTimeout(timer);
|
|
timer = null;
|
|
}
|
|
completer.apply(null, args);
|
|
}
|
|
};
|
|
};
|
|
var resolve = complete(resolveCb);
|
|
var reject = complete(rejectCb);
|
|
var start = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
if (!done && timer === null) {
|
|
timer = domGlobals.setTimeout(function () {
|
|
return reject.apply(null, args);
|
|
}, timeout);
|
|
}
|
|
};
|
|
return {
|
|
start: start,
|
|
resolve: resolve,
|
|
reject: reject
|
|
};
|
|
};
|
|
var create$6 = function () {
|
|
var tasks = {};
|
|
var resultFns = {};
|
|
var load = function (id, url) {
|
|
var loadErrMsg = 'Script at URL "' + url + '" failed to load';
|
|
var runErrMsg = 'Script at URL "' + url + '" did not call `tinymce.Resource.add(\'' + id + '\', data)` within 1 second';
|
|
if (tasks[id] !== undefined) {
|
|
return tasks[id];
|
|
} else {
|
|
var task = new promiseObj(function (resolve, reject) {
|
|
var waiter = awaiter(resolve, reject);
|
|
resultFns[id] = waiter.resolve;
|
|
ScriptLoader.ScriptLoader.loadScript(url, function () {
|
|
return waiter.start(runErrMsg);
|
|
}, function () {
|
|
return waiter.reject(loadErrMsg);
|
|
});
|
|
});
|
|
tasks[id] = task;
|
|
return task;
|
|
}
|
|
};
|
|
var add = function (id, data) {
|
|
if (resultFns[id] !== undefined) {
|
|
resultFns[id](data);
|
|
delete resultFns[id];
|
|
}
|
|
tasks[id] = promiseObj.resolve(data);
|
|
};
|
|
return {
|
|
load: load,
|
|
add: add
|
|
};
|
|
};
|
|
var Resource = create$6();
|
|
|
|
var min = Math.min, max = Math.max, round$2 = Math.round;
|
|
var relativePosition = function (rect, targetRect, rel) {
|
|
var x, y, w, h, targetW, targetH;
|
|
x = targetRect.x;
|
|
y = targetRect.y;
|
|
w = rect.w;
|
|
h = rect.h;
|
|
targetW = targetRect.w;
|
|
targetH = targetRect.h;
|
|
rel = (rel || '').split('');
|
|
if (rel[0] === 'b') {
|
|
y += targetH;
|
|
}
|
|
if (rel[1] === 'r') {
|
|
x += targetW;
|
|
}
|
|
if (rel[0] === 'c') {
|
|
y += round$2(targetH / 2);
|
|
}
|
|
if (rel[1] === 'c') {
|
|
x += round$2(targetW / 2);
|
|
}
|
|
if (rel[3] === 'b') {
|
|
y -= h;
|
|
}
|
|
if (rel[4] === 'r') {
|
|
x -= w;
|
|
}
|
|
if (rel[3] === 'c') {
|
|
y -= round$2(h / 2);
|
|
}
|
|
if (rel[4] === 'c') {
|
|
x -= round$2(w / 2);
|
|
}
|
|
return create$7(x, y, w, h);
|
|
};
|
|
var findBestRelativePosition = function (rect, targetRect, constrainRect, rels) {
|
|
var pos, i;
|
|
for (i = 0; i < rels.length; i++) {
|
|
pos = relativePosition(rect, targetRect, rels[i]);
|
|
if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x && pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
|
|
return rels[i];
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var inflate = function (rect, w, h) {
|
|
return create$7(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
|
|
};
|
|
var intersect = function (rect, cropRect) {
|
|
var x1, y1, x2, y2;
|
|
x1 = max(rect.x, cropRect.x);
|
|
y1 = max(rect.y, cropRect.y);
|
|
x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
|
|
y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
|
|
if (x2 - x1 < 0 || y2 - y1 < 0) {
|
|
return null;
|
|
}
|
|
return create$7(x1, y1, x2 - x1, y2 - y1);
|
|
};
|
|
var clamp$1 = function (rect, clampRect, fixedSize) {
|
|
var underflowX1, underflowY1, overflowX2, overflowY2, x1, y1, x2, y2, cx2, cy2;
|
|
x1 = rect.x;
|
|
y1 = rect.y;
|
|
x2 = rect.x + rect.w;
|
|
y2 = rect.y + rect.h;
|
|
cx2 = clampRect.x + clampRect.w;
|
|
cy2 = clampRect.y + clampRect.h;
|
|
underflowX1 = max(0, clampRect.x - x1);
|
|
underflowY1 = max(0, clampRect.y - y1);
|
|
overflowX2 = max(0, x2 - cx2);
|
|
overflowY2 = max(0, y2 - cy2);
|
|
x1 += underflowX1;
|
|
y1 += underflowY1;
|
|
if (fixedSize) {
|
|
x2 += underflowX1;
|
|
y2 += underflowY1;
|
|
x1 -= overflowX2;
|
|
y1 -= overflowY2;
|
|
}
|
|
x2 -= overflowX2;
|
|
y2 -= overflowY2;
|
|
return create$7(x1, y1, x2 - x1, y2 - y1);
|
|
};
|
|
var create$7 = function (x, y, w, h) {
|
|
return {
|
|
x: x,
|
|
y: y,
|
|
w: w,
|
|
h: h
|
|
};
|
|
};
|
|
var fromClientRect = function (clientRect) {
|
|
return create$7(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
|
|
};
|
|
var Rect = {
|
|
inflate: inflate,
|
|
relativePosition: relativePosition,
|
|
findBestRelativePosition: findBestRelativePosition,
|
|
intersect: intersect,
|
|
clamp: clamp$1,
|
|
create: create$7,
|
|
fromClientRect: fromClientRect
|
|
};
|
|
|
|
var each$l = Tools.each, extend$5 = Tools.extend;
|
|
var extendClass, initializing;
|
|
var Class = function () {
|
|
};
|
|
Class.extend = extendClass = function (prop) {
|
|
var self = this;
|
|
var _super = self.prototype;
|
|
var prototype, name, member;
|
|
var Class = function () {
|
|
var i, mixins, mixin;
|
|
var self = this;
|
|
if (!initializing) {
|
|
if (self.init) {
|
|
self.init.apply(self, arguments);
|
|
}
|
|
mixins = self.Mixins;
|
|
if (mixins) {
|
|
i = mixins.length;
|
|
while (i--) {
|
|
mixin = mixins[i];
|
|
if (mixin.init) {
|
|
mixin.init.apply(self, arguments);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var dummy = function () {
|
|
return this;
|
|
};
|
|
var createMethod = function (name, fn) {
|
|
return function () {
|
|
var self = this;
|
|
var tmp = self._super;
|
|
var ret;
|
|
self._super = _super[name];
|
|
ret = fn.apply(self, arguments);
|
|
self._super = tmp;
|
|
return ret;
|
|
};
|
|
};
|
|
initializing = true;
|
|
prototype = new self();
|
|
initializing = false;
|
|
if (prop.Mixins) {
|
|
each$l(prop.Mixins, function (mixin) {
|
|
for (var name_1 in mixin) {
|
|
if (name_1 !== 'init') {
|
|
prop[name_1] = mixin[name_1];
|
|
}
|
|
}
|
|
});
|
|
if (_super.Mixins) {
|
|
prop.Mixins = _super.Mixins.concat(prop.Mixins);
|
|
}
|
|
}
|
|
if (prop.Methods) {
|
|
each$l(prop.Methods.split(','), function (name) {
|
|
prop[name] = dummy;
|
|
});
|
|
}
|
|
if (prop.Properties) {
|
|
each$l(prop.Properties.split(','), function (name) {
|
|
var fieldName = '_' + name;
|
|
prop[name] = function (value) {
|
|
var self = this;
|
|
if (value !== undefined) {
|
|
self[fieldName] = value;
|
|
return self;
|
|
}
|
|
return self[fieldName];
|
|
};
|
|
});
|
|
}
|
|
if (prop.Statics) {
|
|
each$l(prop.Statics, function (func, name) {
|
|
Class[name] = func;
|
|
});
|
|
}
|
|
if (prop.Defaults && _super.Defaults) {
|
|
prop.Defaults = extend$5({}, _super.Defaults, prop.Defaults);
|
|
}
|
|
for (name in prop) {
|
|
member = prop[name];
|
|
if (typeof member === 'function' && _super[name]) {
|
|
prototype[name] = createMethod(name, member);
|
|
} else {
|
|
prototype[name] = member;
|
|
}
|
|
}
|
|
Class.prototype = prototype;
|
|
Class.constructor = Class;
|
|
Class.extend = extendClass;
|
|
return Class;
|
|
};
|
|
|
|
var min$1 = Math.min, max$1 = Math.max, round$3 = Math.round;
|
|
var Color = function (value) {
|
|
var self = {};
|
|
var r = 0, g = 0, b = 0;
|
|
var rgb2hsv = function (r, g, b) {
|
|
var h, s, v, d, minRGB, maxRGB;
|
|
h = 0;
|
|
s = 0;
|
|
v = 0;
|
|
r = r / 255;
|
|
g = g / 255;
|
|
b = b / 255;
|
|
minRGB = min$1(r, min$1(g, b));
|
|
maxRGB = max$1(r, max$1(g, b));
|
|
if (minRGB === maxRGB) {
|
|
v = minRGB;
|
|
return {
|
|
h: 0,
|
|
s: 0,
|
|
v: v * 100
|
|
};
|
|
}
|
|
d = r === minRGB ? g - b : b === minRGB ? r - g : b - r;
|
|
h = r === minRGB ? 3 : b === minRGB ? 1 : 5;
|
|
h = 60 * (h - d / (maxRGB - minRGB));
|
|
s = (maxRGB - minRGB) / maxRGB;
|
|
v = maxRGB;
|
|
return {
|
|
h: round$3(h),
|
|
s: round$3(s * 100),
|
|
v: round$3(v * 100)
|
|
};
|
|
};
|
|
var hsvToRgb = function (hue, saturation, brightness) {
|
|
var side, chroma, x, match;
|
|
hue = (parseInt(hue, 10) || 0) % 360;
|
|
saturation = parseInt(saturation, 10) / 100;
|
|
brightness = parseInt(brightness, 10) / 100;
|
|
saturation = max$1(0, min$1(saturation, 1));
|
|
brightness = max$1(0, min$1(brightness, 1));
|
|
if (saturation === 0) {
|
|
r = g = b = round$3(255 * brightness);
|
|
return;
|
|
}
|
|
side = hue / 60;
|
|
chroma = brightness * saturation;
|
|
x = chroma * (1 - Math.abs(side % 2 - 1));
|
|
match = brightness - chroma;
|
|
switch (Math.floor(side)) {
|
|
case 0:
|
|
r = chroma;
|
|
g = x;
|
|
b = 0;
|
|
break;
|
|
case 1:
|
|
r = x;
|
|
g = chroma;
|
|
b = 0;
|
|
break;
|
|
case 2:
|
|
r = 0;
|
|
g = chroma;
|
|
b = x;
|
|
break;
|
|
case 3:
|
|
r = 0;
|
|
g = x;
|
|
b = chroma;
|
|
break;
|
|
case 4:
|
|
r = x;
|
|
g = 0;
|
|
b = chroma;
|
|
break;
|
|
case 5:
|
|
r = chroma;
|
|
g = 0;
|
|
b = x;
|
|
break;
|
|
default:
|
|
r = g = b = 0;
|
|
}
|
|
r = round$3(255 * (r + match));
|
|
g = round$3(255 * (g + match));
|
|
b = round$3(255 * (b + match));
|
|
};
|
|
var toHex = function () {
|
|
var hex = function (val) {
|
|
val = parseInt(val, 10).toString(16);
|
|
return val.length > 1 ? val : '0' + val;
|
|
};
|
|
return '#' + hex(r) + hex(g) + hex(b);
|
|
};
|
|
var toRgb = function () {
|
|
return {
|
|
r: r,
|
|
g: g,
|
|
b: b
|
|
};
|
|
};
|
|
var toHsv = function () {
|
|
return rgb2hsv(r, g, b);
|
|
};
|
|
var parse = function (value) {
|
|
var matches;
|
|
if (typeof value === 'object') {
|
|
if ('r' in value) {
|
|
r = value.r;
|
|
g = value.g;
|
|
b = value.b;
|
|
} else if ('v' in value) {
|
|
hsvToRgb(value.h, value.s, value.v);
|
|
}
|
|
} else {
|
|
if (matches = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)[^\)]*\)/gi.exec(value)) {
|
|
r = parseInt(matches[1], 10);
|
|
g = parseInt(matches[2], 10);
|
|
b = parseInt(matches[3], 10);
|
|
} else if (matches = /#([0-F]{2})([0-F]{2})([0-F]{2})/gi.exec(value)) {
|
|
r = parseInt(matches[1], 16);
|
|
g = parseInt(matches[2], 16);
|
|
b = parseInt(matches[3], 16);
|
|
} else if (matches = /#([0-F])([0-F])([0-F])/gi.exec(value)) {
|
|
r = parseInt(matches[1] + matches[1], 16);
|
|
g = parseInt(matches[2] + matches[2], 16);
|
|
b = parseInt(matches[3] + matches[3], 16);
|
|
}
|
|
}
|
|
r = r < 0 ? 0 : r > 255 ? 255 : r;
|
|
g = g < 0 ? 0 : g > 255 ? 255 : g;
|
|
b = b < 0 ? 0 : b > 255 ? 255 : b;
|
|
return self;
|
|
};
|
|
if (value) {
|
|
parse(value);
|
|
}
|
|
self.toRgb = toRgb;
|
|
self.toHsv = toHsv;
|
|
self.toHex = toHex;
|
|
self.parse = parse;
|
|
return self;
|
|
};
|
|
|
|
var serialize = function (obj) {
|
|
var data = JSON.stringify(obj);
|
|
if (!isString(data)) {
|
|
return data;
|
|
}
|
|
return data.replace(/[\u0080-\uFFFF]/g, function (match) {
|
|
var hexCode = match.charCodeAt(0).toString(16);
|
|
return '\\u' + '0000'.substring(hexCode.length) + hexCode;
|
|
});
|
|
};
|
|
var JSONUtils = {
|
|
serialize: serialize,
|
|
parse: function (text) {
|
|
try {
|
|
return JSON.parse(text);
|
|
} catch (ex) {
|
|
}
|
|
}
|
|
};
|
|
|
|
var JSONP = {
|
|
callbacks: {},
|
|
count: 0,
|
|
send: function (settings) {
|
|
var self = this, dom = DOMUtils$1.DOM, count = settings.count !== undefined ? settings.count : self.count;
|
|
var id = 'tinymce_jsonp_' + count;
|
|
self.callbacks[count] = function (json) {
|
|
dom.remove(id);
|
|
delete self.callbacks[count];
|
|
settings.callback(json);
|
|
};
|
|
dom.add(dom.doc.body, 'script', {
|
|
id: id,
|
|
src: settings.url,
|
|
type: 'text/javascript'
|
|
});
|
|
self.count++;
|
|
}
|
|
};
|
|
|
|
var XHR = __assign(__assign({}, Observable), {
|
|
send: function (settings) {
|
|
var xhr, count = 0;
|
|
var ready = function () {
|
|
if (!settings.async || xhr.readyState === 4 || count++ > 10000) {
|
|
if (settings.success && count < 10000 && xhr.status === 200) {
|
|
settings.success.call(settings.success_scope, '' + xhr.responseText, xhr, settings);
|
|
} else if (settings.error) {
|
|
settings.error.call(settings.error_scope, count > 10000 ? 'TIMED_OUT' : 'GENERAL', xhr, settings);
|
|
}
|
|
xhr = null;
|
|
} else {
|
|
Delay.setTimeout(ready, 10);
|
|
}
|
|
};
|
|
settings.scope = settings.scope || this;
|
|
settings.success_scope = settings.success_scope || settings.scope;
|
|
settings.error_scope = settings.error_scope || settings.scope;
|
|
settings.async = settings.async !== false;
|
|
settings.data = settings.data || '';
|
|
XHR.fire('beforeInitialize', { settings: settings });
|
|
xhr = new domGlobals.XMLHttpRequest();
|
|
if (xhr) {
|
|
if (xhr.overrideMimeType) {
|
|
xhr.overrideMimeType(settings.content_type);
|
|
}
|
|
xhr.open(settings.type || (settings.data ? 'POST' : 'GET'), settings.url, settings.async);
|
|
if (settings.crossDomain) {
|
|
xhr.withCredentials = true;
|
|
}
|
|
if (settings.content_type) {
|
|
xhr.setRequestHeader('Content-Type', settings.content_type);
|
|
}
|
|
if (settings.requestheaders) {
|
|
Tools.each(settings.requestheaders, function (header) {
|
|
xhr.setRequestHeader(header.key, header.value);
|
|
});
|
|
}
|
|
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
|
xhr = XHR.fire('beforeSend', {
|
|
xhr: xhr,
|
|
settings: settings
|
|
}).xhr;
|
|
xhr.send(settings.data);
|
|
if (!settings.async) {
|
|
return ready();
|
|
}
|
|
Delay.setTimeout(ready, 10);
|
|
}
|
|
}
|
|
});
|
|
|
|
var extend$6 = Tools.extend;
|
|
var JSONRequest = function () {
|
|
function JSONRequest(settings) {
|
|
this.settings = extend$6({}, settings);
|
|
this.count = 0;
|
|
}
|
|
JSONRequest.sendRPC = function (o) {
|
|
return new JSONRequest().send(o);
|
|
};
|
|
JSONRequest.prototype.send = function (args) {
|
|
var ecb = args.error, scb = args.success;
|
|
var xhrArgs = extend$6(this.settings, args);
|
|
xhrArgs.success = function (c, x) {
|
|
c = JSONUtils.parse(c);
|
|
if (typeof c === 'undefined') {
|
|
c = { error: 'JSON Parse error.' };
|
|
}
|
|
if (c.error) {
|
|
ecb.call(xhrArgs.error_scope || xhrArgs.scope, c.error, x);
|
|
} else {
|
|
scb.call(xhrArgs.success_scope || xhrArgs.scope, c.result);
|
|
}
|
|
};
|
|
xhrArgs.error = function (ty, x) {
|
|
if (ecb) {
|
|
ecb.call(xhrArgs.error_scope || xhrArgs.scope, ty, x);
|
|
}
|
|
};
|
|
xhrArgs.data = JSONUtils.serialize({
|
|
id: args.id || 'c' + this.count++,
|
|
method: args.method,
|
|
params: args.params
|
|
});
|
|
xhrArgs.content_type = 'application/json';
|
|
XHR.send(xhrArgs);
|
|
};
|
|
return JSONRequest;
|
|
}();
|
|
|
|
var create$8 = function () {
|
|
return function () {
|
|
var data = {};
|
|
var keys = [];
|
|
var storage = {
|
|
getItem: function (key) {
|
|
var item = data[key];
|
|
return item ? item : null;
|
|
},
|
|
setItem: function (key, value) {
|
|
keys.push(key);
|
|
data[key] = String(value);
|
|
},
|
|
key: function (index) {
|
|
return keys[index];
|
|
},
|
|
removeItem: function (key) {
|
|
keys = keys.filter(function (k) {
|
|
return k === key;
|
|
});
|
|
delete data[key];
|
|
},
|
|
clear: function () {
|
|
keys = [];
|
|
data = {};
|
|
},
|
|
length: 0
|
|
};
|
|
Object.defineProperty(storage, 'length', {
|
|
get: function () {
|
|
return keys.length;
|
|
},
|
|
configurable: false,
|
|
enumerable: false
|
|
});
|
|
return storage;
|
|
}();
|
|
};
|
|
|
|
var localStorage;
|
|
try {
|
|
localStorage = domGlobals.window.localStorage;
|
|
} catch (e) {
|
|
localStorage = create$8();
|
|
}
|
|
var LocalStorage = localStorage;
|
|
|
|
var publicApi = {
|
|
geom: { Rect: Rect },
|
|
util: {
|
|
Promise: promiseObj,
|
|
Delay: Delay,
|
|
Tools: Tools,
|
|
VK: VK,
|
|
URI: URI,
|
|
Class: Class,
|
|
EventDispatcher: EventDispatcher,
|
|
Observable: Observable,
|
|
I18n: I18n,
|
|
XHR: XHR,
|
|
JSON: JSONUtils,
|
|
JSONRequest: JSONRequest,
|
|
JSONP: JSONP,
|
|
LocalStorage: LocalStorage,
|
|
Color: Color
|
|
},
|
|
dom: {
|
|
EventUtils: EventUtils,
|
|
Sizzle: Sizzle,
|
|
DomQuery: DomQuery,
|
|
TreeWalker: TreeWalker,
|
|
DOMUtils: DOMUtils$1,
|
|
ScriptLoader: ScriptLoader,
|
|
RangeUtils: RangeUtils$1,
|
|
Serializer: Serializer$1,
|
|
ControlSelection: ControlSelection,
|
|
BookmarkManager: BookmarkManager$1,
|
|
Selection: Selection$1,
|
|
Event: EventUtils.Event
|
|
},
|
|
html: {
|
|
Styles: Styles,
|
|
Entities: Entities,
|
|
Node: Node$1,
|
|
Schema: Schema,
|
|
SaxParser: SaxParser$1,
|
|
DomParser: DomParser,
|
|
Writer: Writer,
|
|
Serializer: Serializer
|
|
},
|
|
Env: Env,
|
|
AddOnManager: AddOnManager$1,
|
|
Annotator: Annotator,
|
|
Formatter: Formatter,
|
|
UndoManager: UndoManager,
|
|
EditorCommands: EditorCommands,
|
|
WindowManager: WindowManager,
|
|
NotificationManager: NotificationManager,
|
|
EditorObservable: EditorObservable,
|
|
Shortcuts: Shortcuts,
|
|
Editor: Editor,
|
|
FocusManager: FocusManager,
|
|
EditorManager: EditorManager,
|
|
DOM: DOMUtils$1.DOM,
|
|
ScriptLoader: ScriptLoader.ScriptLoader,
|
|
PluginManager: AddOnManager$1.PluginManager,
|
|
ThemeManager: AddOnManager$1.ThemeManager,
|
|
IconManager: IconManager,
|
|
Resource: Resource,
|
|
trim: Tools.trim,
|
|
isArray: Tools.isArray,
|
|
is: Tools.is,
|
|
toArray: Tools.toArray,
|
|
makeMap: Tools.makeMap,
|
|
each: Tools.each,
|
|
map: Tools.map,
|
|
grep: Tools.grep,
|
|
inArray: Tools.inArray,
|
|
extend: Tools.extend,
|
|
create: Tools.create,
|
|
walk: Tools.walk,
|
|
createNS: Tools.createNS,
|
|
resolve: Tools.resolve,
|
|
explode: Tools.explode,
|
|
_addCacheSuffix: Tools._addCacheSuffix,
|
|
isOpera: Env.opera,
|
|
isWebKit: Env.webkit,
|
|
isIE: Env.ie,
|
|
isGecko: Env.gecko,
|
|
isMac: Env.mac
|
|
};
|
|
var tinymce = Tools.extend(EditorManager, publicApi);
|
|
|
|
var exportToModuleLoaders = function (tinymce) {
|
|
if (typeof module === 'object') {
|
|
try {
|
|
module.exports = tinymce;
|
|
} catch (_) {
|
|
}
|
|
}
|
|
};
|
|
var exportToWindowGlobal = function (tinymce) {
|
|
window.tinymce = tinymce;
|
|
window.tinyMCE = tinymce;
|
|
};
|
|
exportToWindowGlobal(tinymce);
|
|
exportToModuleLoaders(tinymce);
|
|
|
|
}(window));
|
|
|
|
|
|
|
|
/**
|
|
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
|
* Licensed under the LGPL or a commercial license.
|
|
* For LGPL see License.txt in the project root for license information.
|
|
* For commercial licenses see https://www.tiny.cloud/
|
|
*/
|
|
/**
|
|
* Jquery integration plugin.
|
|
*
|
|
* @class tinymce.core.JqueryIntegration
|
|
* @private
|
|
*/
|
|
!function(){var f,c,u,p,d,s=[];d="undefined"!=typeof global?global:window,p=d.jQuery;function v(){
|
|
// Reference to tinymce needs to be lazily evaluated since tinymce
|
|
// might be loaded through the compressor or other means
|
|
return d.tinymce}p.fn.tinymce=function(o){var e,t,i,l=this,r="";
|
|
// No match then just ignore the call
|
|
if(!l.length)return l;
|
|
// Get editor instance
|
|
if(!o)return v()?v().get(l[0].id):null;l.css("visibility","hidden");function n(){var a=[],c=0;
|
|
// Apply patches to the jQuery object, only once
|
|
u||(m(),u=!0),
|
|
// Create an editor instance for each matched node
|
|
l.each(function(e,t){var n,i=t.id,r=o.oninit;
|
|
// Generate unique id for target element if needed
|
|
i||(t.id=i=v().DOM.uniqueId()),
|
|
// Only init the editor once
|
|
v().get(i)||(
|
|
// Create editor instance and render it
|
|
n=v().createEditor(i,o),a.push(n),n.on("init",function(){var e,t=r;l.css("visibility",""),
|
|
// Run this if the oninit setting is defined
|
|
// this logic will fire the oninit callback ones each
|
|
// matched editor instance is initialized
|
|
r&&++c==a.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:v().resolve(t.replace(/\.\w+$/,"")),t=v().resolve(t)),
|
|
// Call the oninit function with the object
|
|
t.apply(e||v(),a))}))}),
|
|
// Render the editor instances in a separate loop since we
|
|
// need to have the full editors array used in the onInit calls
|
|
p.each(a,function(e,t){t.render()})}
|
|
// Load TinyMCE on demand, if we need to
|
|
if(d.tinymce||c||!(e=o.script_url))
|
|
// Delay the init call until tinymce is loaded
|
|
1===c?s.push(n):n();else{c=1,t=e.substring(0,e.lastIndexOf("/")),
|
|
// Check if it's a dev/src version they want to load then
|
|
// make sure that all plugins, themes etc are loaded in source mode as well
|
|
-1!=e.indexOf(".min")&&(r=".min"),
|
|
// Setup tinyMCEPreInit object this will later be used by the TinyMCE
|
|
// core script to locate other resources like CSS files, dialogs etc
|
|
// You can also predefined a tinyMCEPreInit object and then it will use that instead
|
|
d.tinymce=d.tinyMCEPreInit||{base:t,suffix:r},
|
|
// url contains gzip then we assume it's a compressor
|
|
-1!=e.indexOf("gzip")&&(i=o.language||"en",e=e+(/\?/.test(e)?"&":"?")+"js=true&core=true&suffix="+escape(r)+"&themes="+escape(o.theme||"modern")+"&plugins="+escape(o.plugins||"")+"&languages="+(i||""),
|
|
// Check if compressor script is already loaded otherwise setup a basic one
|
|
d.tinyMCE_GZ||(d.tinyMCE_GZ={start:function(){function n(e){v().ScriptLoader.markDone(v().baseURI.toAbsolute(e))}
|
|
// Add core languages
|
|
n("langs/"+i+".js"),
|
|
// Add themes with languages
|
|
n("themes/"+o.theme+"/theme"+r+".js"),n("themes/"+o.theme+"/langs/"+i+".js"),
|
|
// Add plugins with languages
|
|
p.each(o.plugins.split(","),function(e,t){t&&(n("plugins/"+t+"/plugin"+r+".js"),n("plugins/"+t+"/langs/"+i+".js"))})},end:function(){}}));var a=document.createElement("script");a.type="text/javascript",a.onload=a.onreadystatechange=function(e){e=e||window.event,2===c||"load"!=e.type&&!/complete|loaded/.test(a.readyState)||(v().dom.Event.domLoaded=1,c=2,
|
|
// Execute callback after mainscript has been loaded and before the initialization occurs
|
|
o.script_loaded&&o.script_loaded(),n(),p.each(s,function(e,t){t()}))},a.src=e,document.body.appendChild(a)}return l},
|
|
// Add :tinymce pseudo selector this will select elements that has been converted into editor instances
|
|
// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
|
|
p.extend(p.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in d&&(t=v().get(e.id))&&t.editorManager===v())}});
|
|
// This function patches internal jQuery functions so that if
|
|
// you for example remove an div element containing an editor it's
|
|
// automatically destroyed by the TinyMCE API
|
|
var m=function(){function r(e){
|
|
// If the function is remove
|
|
"remove"===e&&this.each(function(e,t){var n=u(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=v().get(t.id.replace(/_parent$/,""));n&&n.remove()})}function o(i){var e,t=this;
|
|
// Handle set value
|
|
/*jshint eqnull:true */if(null!=i)r.call(t),
|
|
// Saves the contents before get/set value of textarea/div
|
|
t.each(function(e,t){var n;(n=v().get(t.id))&&n.setContent(i)});else if(0<t.length&&(e=v().get(t[0].id)))return e.getContent()}function l(e){return!!(e&&e.length&&d.tinymce&&e.is(":tinymce"))}
|
|
// Removes any child editor instances by looking for editor wrapper elements
|
|
var u=function(e){var t=null;return e&&e.id&&d.tinymce&&(t=v().get(e.id)),t},s={};
|
|
// Loads or saves contents from/to textarea if the value
|
|
// argument is defined it will set the TinyMCE internal contents
|
|
// Patch some setter/getter functions these will
|
|
// now be able to set/get the contents of editor instances for
|
|
// example $('#editorid').html('Content'); will update the TinyMCE iframe instance
|
|
p.each(["text","html","val"],function(e,t){var a=s[t]=p.fn[t],c="text"===t;p.fn[t]=function(e){var t=this;if(!l(t))return a.apply(t,arguments);if(e!==f)return o.call(t.filter(":tinymce"),e),a.apply(t.not(":tinymce"),arguments),t;// return original set for chaining
|
|
var i="",r=arguments;return(c?t:t.eq(0)).each(function(e,t){var n=u(t);i+=n?c?n.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):n.getContent({save:!0}):a.apply(p(t),r)}),i}}),
|
|
// Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
|
|
p.each(["append","prepend"],function(e,t){var n=s[t]=p.fn[t],r="prepend"===t;p.fn[t]=function(i){var e=this;return l(e)?i!==f?("string"==typeof i&&e.filter(":tinymce").each(function(e,t){var n=u(t);n&&n.setContent(r?i+n.getContent():n.getContent()+i)}),n.apply(e.not(":tinymce"),arguments),e):void 0:n.apply(e,arguments)}}),
|
|
// Makes sure that the editor instance gets properly destroyed when the parent element is removed
|
|
p.each(["remove","replaceWith","replaceAll","empty"],function(e,t){var n=s[t]=p.fn[t];p.fn[t]=function(){return r.call(this,t),n.apply(this,arguments)}}),s.attr=p.fn.attr,
|
|
// Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
|
|
p.fn.attr=function(e,t){var n=this,i=arguments;if(!e||"value"!==e||!l(n))return s.attr.apply(n,i);if(t!==f)return o.call(n.filter(":tinymce"),t),s.attr.apply(n.not(":tinymce"),i),n;// return original set for chaining
|
|
var r=n[0],a=u(r);return a?a.getContent({save:!0}):s.attr.apply(p(r),i)}}}();
|
|
|
|
|
|
/*!
|
|
* Modernizr v2.7.1
|
|
* www.modernizr.com
|
|
*
|
|
* Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
|
|
* Available under the BSD and MIT licenses: www.modernizr.com/license/
|
|
*/
|
|
|
|
/*
|
|
* Modernizr tests which native CSS3 and HTML5 features are available in
|
|
* the current UA and makes the results available to you in two ways:
|
|
* as properties on a global Modernizr object, and as classes on the
|
|
* <html> element. This information allows you to progressively enhance
|
|
* your pages with a granular level of control over the experience.
|
|
*
|
|
* Modernizr has an optional (not included) conditional resource loader
|
|
* called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
|
|
* To get a build that includes Modernizr.load(), as well as choosing
|
|
* which tests to include, go to www.modernizr.com/download/
|
|
*
|
|
* Authors Faruk Ates, Paul Irish, Alex Sexton
|
|
* Contributors Ryan Seddon, Ben Alman
|
|
*/
|
|
|
|
window.Modernizr = (function( window, document, undefined ) {
|
|
|
|
var version = '2.7.1',
|
|
|
|
Modernizr = {},
|
|
|
|
/*>>cssclasses*/
|
|
// option for enabling the HTML classes to be added
|
|
enableClasses = true,
|
|
/*>>cssclasses*/
|
|
|
|
docElement = document.documentElement,
|
|
|
|
/**
|
|
* Create our "modernizr" element that we do most feature tests on.
|
|
*/
|
|
mod = 'modernizr',
|
|
modElem = document.createElement(mod),
|
|
mStyle = modElem.style,
|
|
|
|
/**
|
|
* Create the input element for various Web Forms feature tests.
|
|
*/
|
|
inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ ,
|
|
|
|
/*>>smile*/
|
|
smile = ':)',
|
|
/*>>smile*/
|
|
|
|
toString = {}.toString,
|
|
|
|
// TODO :: make the prefixes more granular
|
|
/*>>prefixes*/
|
|
// List of property values to set for css tests. See ticket #21
|
|
prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
|
|
/*>>prefixes*/
|
|
|
|
/*>>domprefixes*/
|
|
// Following spec is to expose vendor-specific style properties as:
|
|
// elem.style.WebkitBorderRadius
|
|
// and the following would be incorrect:
|
|
// elem.style.webkitBorderRadius
|
|
|
|
// Webkit ghosts their properties in lowercase but Opera & Moz do not.
|
|
// Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
|
|
// erik.eae.net/archives/2008/03/10/21.48.10/
|
|
|
|
// More here: github.com/Modernizr/Modernizr/issues/issue/21
|
|
omPrefixes = 'Webkit Moz O ms',
|
|
|
|
cssomPrefixes = omPrefixes.split(' '),
|
|
|
|
domPrefixes = omPrefixes.toLowerCase().split(' '),
|
|
/*>>domprefixes*/
|
|
|
|
/*>>ns*/
|
|
ns = {'svg': 'http://www.w3.org/2000/svg'},
|
|
/*>>ns*/
|
|
|
|
tests = {},
|
|
inputs = {},
|
|
attrs = {},
|
|
|
|
classes = [],
|
|
|
|
slice = classes.slice,
|
|
|
|
featureName, // used in testing loop
|
|
|
|
|
|
/*>>teststyles*/
|
|
// Inject element with style element and some CSS rules
|
|
injectElementWithStyles = function( rule, callback, nodes, testnames ) {
|
|
|
|
var style, ret, node, docOverflow,
|
|
div = document.createElement('div'),
|
|
// After page load injecting a fake body doesn't work so check if body exists
|
|
body = document.body,
|
|
// IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
|
|
fakeBody = body || document.createElement('body');
|
|
|
|
if ( parseInt(nodes, 10) ) {
|
|
// In order not to give false positives we create a node for each test
|
|
// This also allows the method to scale for unspecified uses
|
|
while ( nodes-- ) {
|
|
node = document.createElement('div');
|
|
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
|
|
div.appendChild(node);
|
|
}
|
|
}
|
|
|
|
// <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
|
|
// when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
|
|
// with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
|
|
// msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
|
|
// Documents served as xml will throw if using ­ so use xml friendly encoded version. See issue #277
|
|
style = ['­','<style id="s', mod, '">', rule, '</style>'].join('');
|
|
div.id = mod;
|
|
// IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
|
|
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
|
|
(body ? div : fakeBody).innerHTML += style;
|
|
fakeBody.appendChild(div);
|
|
if ( !body ) {
|
|
//avoid crashing IE8, if background image is used
|
|
fakeBody.style.background = '';
|
|
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
|
|
fakeBody.style.overflow = 'hidden';
|
|
docOverflow = docElement.style.overflow;
|
|
docElement.style.overflow = 'hidden';
|
|
docElement.appendChild(fakeBody);
|
|
}
|
|
|
|
ret = callback(div, rule);
|
|
// If this is done after page load we don't want to remove the body so check if body exists
|
|
if ( !body ) {
|
|
fakeBody.parentNode.removeChild(fakeBody);
|
|
docElement.style.overflow = docOverflow;
|
|
} else {
|
|
div.parentNode.removeChild(div);
|
|
}
|
|
|
|
return !!ret;
|
|
|
|
},
|
|
/*>>teststyles*/
|
|
|
|
/*>>mq*/
|
|
// adapted from matchMedia polyfill
|
|
// by Scott Jehl and Paul Irish
|
|
// gist.github.com/786768
|
|
testMediaQuery = function( mq ) {
|
|
|
|
var matchMedia = window.matchMedia || window.msMatchMedia;
|
|
if ( matchMedia ) {
|
|
return matchMedia(mq).matches;
|
|
}
|
|
|
|
var bool;
|
|
|
|
injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
|
|
bool = (window.getComputedStyle ?
|
|
getComputedStyle(node, null) :
|
|
node.currentStyle)['position'] == 'absolute';
|
|
});
|
|
|
|
return bool;
|
|
|
|
},
|
|
/*>>mq*/
|
|
|
|
|
|
/*>>hasevent*/
|
|
//
|
|
// isEventSupported determines if a given element supports the given event
|
|
// kangax.github.com/iseventsupported/
|
|
//
|
|
// The following results are known incorrects:
|
|
// Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
|
|
// Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
|
|
// ...
|
|
isEventSupported = (function() {
|
|
|
|
var TAGNAMES = {
|
|
'select': 'input', 'change': 'input',
|
|
'submit': 'form', 'reset': 'form',
|
|
'error': 'img', 'load': 'img', 'abort': 'img'
|
|
};
|
|
|
|
function isEventSupported( eventName, element ) {
|
|
|
|
element = element || document.createElement(TAGNAMES[eventName] || 'div');
|
|
eventName = 'on' + eventName;
|
|
|
|
// When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
|
|
var isSupported = eventName in element;
|
|
|
|
if ( !isSupported ) {
|
|
// If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
|
|
if ( !element.setAttribute ) {
|
|
element = document.createElement('div');
|
|
}
|
|
if ( element.setAttribute && element.removeAttribute ) {
|
|
element.setAttribute(eventName, '');
|
|
isSupported = is(element[eventName], 'function');
|
|
|
|
// If property was created, "remove it" (by setting value to `undefined`)
|
|
if ( !is(element[eventName], 'undefined') ) {
|
|
element[eventName] = undefined;
|
|
}
|
|
element.removeAttribute(eventName);
|
|
}
|
|
}
|
|
|
|
element = null;
|
|
return isSupported;
|
|
}
|
|
return isEventSupported;
|
|
})(),
|
|
/*>>hasevent*/
|
|
|
|
// TODO :: Add flag for hasownprop ? didn't last time
|
|
|
|
// hasOwnProperty shim by kangax needed for Safari 2.0 support
|
|
_hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
|
|
|
|
if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
|
|
hasOwnProp = function (object, property) {
|
|
return _hasOwnProperty.call(object, property);
|
|
};
|
|
}
|
|
else {
|
|
hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
|
|
return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
|
|
};
|
|
}
|
|
|
|
// Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
|
|
// es5.github.com/#x15.3.4.5
|
|
|
|
if (!Function.prototype.bind) {
|
|
Function.prototype.bind = function bind(that) {
|
|
|
|
var target = this;
|
|
|
|
if (typeof target != "function") {
|
|
throw new TypeError();
|
|
}
|
|
|
|
var args = slice.call(arguments, 1),
|
|
bound = function () {
|
|
|
|
if (this instanceof bound) {
|
|
|
|
var F = function(){};
|
|
F.prototype = target.prototype;
|
|
var self = new F();
|
|
|
|
var result = target.apply(
|
|
self,
|
|
args.concat(slice.call(arguments))
|
|
);
|
|
if (Object(result) === result) {
|
|
return result;
|
|
}
|
|
return self;
|
|
|
|
} else {
|
|
|
|
return target.apply(
|
|
that,
|
|
args.concat(slice.call(arguments))
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return bound;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* setCss applies given styles to the Modernizr DOM node.
|
|
*/
|
|
function setCss( str ) {
|
|
mStyle.cssText = str;
|
|
}
|
|
|
|
/**
|
|
* setCssAll extrapolates all vendor-specific css strings.
|
|
*/
|
|
function setCssAll( str1, str2 ) {
|
|
return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
|
|
}
|
|
|
|
/**
|
|
* is returns a boolean for if typeof obj is exactly type.
|
|
*/
|
|
function is( obj, type ) {
|
|
return typeof obj === type;
|
|
}
|
|
|
|
/**
|
|
* contains returns a boolean for if substr is found within str.
|
|
*/
|
|
function contains( str, substr ) {
|
|
return !!~('' + str).indexOf(substr);
|
|
}
|
|
|
|
/*>>testprop*/
|
|
|
|
// testProps is a generic CSS / DOM property test.
|
|
|
|
// In testing support for a given CSS property, it's legit to test:
|
|
// `elem.style[styleName] !== undefined`
|
|
// If the property is supported it will return an empty string,
|
|
// if unsupported it will return undefined.
|
|
|
|
// We'll take advantage of this quick test and skip setting a style
|
|
// on our modernizr element, but instead just testing undefined vs
|
|
// empty string.
|
|
|
|
// Because the testing of the CSS property names (with "-", as
|
|
// opposed to the camelCase DOM properties) is non-portable and
|
|
// non-standard but works in WebKit and IE (but not Gecko or Opera),
|
|
// we explicitly reject properties with dashes so that authors
|
|
// developing in WebKit or IE first don't end up with
|
|
// browser-specific content by accident.
|
|
|
|
function testProps( props, prefixed ) {
|
|
for ( var i in props ) {
|
|
var prop = props[i];
|
|
if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
|
|
return prefixed == 'pfx' ? prop : true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/*>>testprop*/
|
|
|
|
// TODO :: add testDOMProps
|
|
/**
|
|
* testDOMProps is a generic DOM property test; if a browser supports
|
|
* a certain property, it won't return undefined for it.
|
|
*/
|
|
function testDOMProps( props, obj, elem ) {
|
|
for ( var i in props ) {
|
|
var item = obj[props[i]];
|
|
if ( item !== undefined) {
|
|
|
|
// return the property name as a string
|
|
if (elem === false) return props[i];
|
|
|
|
// let's bind a function
|
|
if (is(item, 'function')){
|
|
// default to autobind unless override
|
|
return item.bind(elem || obj);
|
|
}
|
|
|
|
// return the unbound function or obj or value
|
|
return item;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*>>testallprops*/
|
|
/**
|
|
* testPropsAll tests a list of DOM properties we want to check against.
|
|
* We specify literally ALL possible (known and/or likely) properties on
|
|
* the element including the non-vendor prefixed one, for forward-
|
|
* compatibility.
|
|
*/
|
|
function testPropsAll( prop, prefixed, elem ) {
|
|
|
|
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
|
|
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
|
|
|
|
// did they call .prefixed('boxSizing') or are we just testing a prop?
|
|
if(is(prefixed, "string") || is(prefixed, "undefined")) {
|
|
return testProps(props, prefixed);
|
|
|
|
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
|
|
} else {
|
|
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
|
|
return testDOMProps(props, prefixed, elem);
|
|
}
|
|
}
|
|
/*>>testallprops*/
|
|
|
|
|
|
/**
|
|
* Tests
|
|
* -----
|
|
*/
|
|
|
|
// The *new* flexbox
|
|
// dev.w3.org/csswg/css3-flexbox
|
|
|
|
tests['flexbox'] = function() {
|
|
return testPropsAll('flexWrap');
|
|
};
|
|
|
|
// The *old* flexbox
|
|
// www.w3.org/TR/2009/WD-css3-flexbox-20090723/
|
|
|
|
tests['flexboxlegacy'] = function() {
|
|
return testPropsAll('boxDirection');
|
|
};
|
|
|
|
// On the S60 and BB Storm, getContext exists, but always returns undefined
|
|
// so we actually have to call getContext() to verify
|
|
// github.com/Modernizr/Modernizr/issues/issue/97/
|
|
|
|
tests['canvas'] = function() {
|
|
var elem = document.createElement('canvas');
|
|
return !!(elem.getContext && elem.getContext('2d'));
|
|
};
|
|
|
|
tests['canvastext'] = function() {
|
|
return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
|
|
};
|
|
|
|
// webk.it/70117 is tracking a legit WebGL feature detect proposal
|
|
|
|
// We do a soft detect which may false positive in order to avoid
|
|
// an expensive context creation: bugzil.la/732441
|
|
|
|
tests['webgl'] = function() {
|
|
return !!window.WebGLRenderingContext;
|
|
};
|
|
|
|
/*
|
|
* The Modernizr.touch test only indicates if the browser supports
|
|
* touch events, which does not necessarily reflect a touchscreen
|
|
* device, as evidenced by tablets running Windows 7 or, alas,
|
|
* the Palm Pre / WebOS (touch) phones.
|
|
*
|
|
* Additionally, Chrome (desktop) used to lie about its support on this,
|
|
* but that has since been rectified: crbug.com/36415
|
|
*
|
|
* We also test for Firefox 4 Multitouch Support.
|
|
*
|
|
* For more info, see: modernizr.github.com/Modernizr/touch.html
|
|
*/
|
|
|
|
tests['touch'] = function() {
|
|
var bool;
|
|
|
|
if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
|
|
bool = true;
|
|
} else {
|
|
injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
|
|
bool = node.offsetTop === 9;
|
|
});
|
|
}
|
|
|
|
return bool;
|
|
};
|
|
|
|
|
|
// geolocation is often considered a trivial feature detect...
|
|
// Turns out, it's quite tricky to get right:
|
|
//
|
|
// Using !!navigator.geolocation does two things we don't want. It:
|
|
// 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
|
|
// 2. Disables page caching in WebKit: webk.it/43956
|
|
//
|
|
// Meanwhile, in Firefox < 8, an about:config setting could expose
|
|
// a false positive that would throw an exception: bugzil.la/688158
|
|
|
|
tests['geolocation'] = function() {
|
|
return 'geolocation' in navigator;
|
|
};
|
|
|
|
|
|
tests['postmessage'] = function() {
|
|
return !!window.postMessage;
|
|
};
|
|
|
|
|
|
// Chrome incognito mode used to throw an exception when using openDatabase
|
|
// It doesn't anymore.
|
|
tests['websqldatabase'] = function() {
|
|
return !!window.openDatabase;
|
|
};
|
|
|
|
// Vendors had inconsistent prefixing with the experimental Indexed DB:
|
|
// - Webkit's implementation is accessible through webkitIndexedDB
|
|
// - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
|
|
// For speed, we don't test the legacy (and beta-only) indexedDB
|
|
tests['indexedDB'] = function() {
|
|
return !!testPropsAll("indexedDB", window);
|
|
};
|
|
|
|
// documentMode logic from YUI to filter out IE8 Compat Mode
|
|
// which false positives.
|
|
tests['hashchange'] = function() {
|
|
return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
|
|
};
|
|
|
|
// Per 1.6:
|
|
// This used to be Modernizr.historymanagement but the longer
|
|
// name has been deprecated in favor of a shorter and property-matching one.
|
|
// The old API is still available in 1.6, but as of 2.0 will throw a warning,
|
|
// and in the first release thereafter disappear entirely.
|
|
tests['history'] = function() {
|
|
return !!(window.history && history.pushState);
|
|
};
|
|
|
|
tests['draganddrop'] = function() {
|
|
var div = document.createElement('div');
|
|
return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
|
|
};
|
|
|
|
// FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
|
|
// will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
|
|
// FF10 still uses prefixes, so check for it until then.
|
|
// for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
|
|
tests['websockets'] = function() {
|
|
return 'WebSocket' in window || 'MozWebSocket' in window;
|
|
};
|
|
|
|
|
|
// css-tricks.com/rgba-browser-support/
|
|
tests['rgba'] = function() {
|
|
// Set an rgba() color and check the returned value
|
|
|
|
setCss('background-color:rgba(150,255,150,.5)');
|
|
|
|
return contains(mStyle.backgroundColor, 'rgba');
|
|
};
|
|
|
|
tests['hsla'] = function() {
|
|
// Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
|
|
// except IE9 who retains it as hsla
|
|
|
|
setCss('background-color:hsla(120,40%,100%,.5)');
|
|
|
|
return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
|
|
};
|
|
|
|
tests['multiplebgs'] = function() {
|
|
// Setting multiple images AND a color on the background shorthand property
|
|
// and then querying the style.background property value for the number of
|
|
// occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
|
|
|
|
setCss('background:url(https://),url(https://),red url(https://)');
|
|
|
|
// If the UA supports multiple backgrounds, there should be three occurrences
|
|
// of the string "url(" in the return value for elemStyle.background
|
|
|
|
return (/(url\s*\(.*?){3}/).test(mStyle.background);
|
|
};
|
|
|
|
|
|
|
|
// this will false positive in Opera Mini
|
|
// github.com/Modernizr/Modernizr/issues/396
|
|
|
|
tests['backgroundsize'] = function() {
|
|
return testPropsAll('backgroundSize');
|
|
};
|
|
|
|
tests['borderimage'] = function() {
|
|
return testPropsAll('borderImage');
|
|
};
|
|
|
|
|
|
// Super comprehensive table about all the unique implementations of
|
|
// border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
|
|
|
|
tests['borderradius'] = function() {
|
|
return testPropsAll('borderRadius');
|
|
};
|
|
|
|
// WebOS unfortunately false positives on this test.
|
|
tests['boxshadow'] = function() {
|
|
return testPropsAll('boxShadow');
|
|
};
|
|
|
|
// FF3.0 will false positive on this test
|
|
tests['textshadow'] = function() {
|
|
return document.createElement('div').style.textShadow === '';
|
|
};
|
|
|
|
|
|
tests['opacity'] = function() {
|
|
// Browsers that actually have CSS Opacity implemented have done so
|
|
// according to spec, which means their return values are within the
|
|
// range of [0.0,1.0] - including the leading zero.
|
|
|
|
setCssAll('opacity:.55');
|
|
|
|
// The non-literal . in this regex is intentional:
|
|
// German Chrome returns this value as 0,55
|
|
// github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
|
|
return (/^0.55$/).test(mStyle.opacity);
|
|
};
|
|
|
|
|
|
// Note, Android < 4 will pass this test, but can only animate
|
|
// a single property at a time
|
|
// daneden.me/2011/12/putting-up-with-androids-bullshit/
|
|
tests['cssanimations'] = function() {
|
|
return testPropsAll('animationName');
|
|
};
|
|
|
|
|
|
tests['csscolumns'] = function() {
|
|
return testPropsAll('columnCount');
|
|
};
|
|
|
|
|
|
tests['cssgradients'] = function() {
|
|
/**
|
|
* For CSS Gradients syntax, please see:
|
|
* webkit.org/blog/175/introducing-css-gradients/
|
|
* developer.mozilla.org/en/CSS/-moz-linear-gradient
|
|
* developer.mozilla.org/en/CSS/-moz-radial-gradient
|
|
* dev.w3.org/csswg/css3-images/#gradients-
|
|
*/
|
|
|
|
var str1 = 'background-image:',
|
|
str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
|
|
str3 = 'linear-gradient(left top,#9f9, white);';
|
|
|
|
setCss(
|
|
// legacy webkit syntax (FIXME: remove when syntax not in use anymore)
|
|
(str1 + '-webkit- '.split(' ').join(str2 + str1) +
|
|
// standard syntax // trailing 'background-image:'
|
|
prefixes.join(str3 + str1)).slice(0, -str1.length)
|
|
);
|
|
|
|
return contains(mStyle.backgroundImage, 'gradient');
|
|
};
|
|
|
|
|
|
tests['cssreflections'] = function() {
|
|
return testPropsAll('boxReflect');
|
|
};
|
|
|
|
|
|
tests['csstransforms'] = function() {
|
|
return !!testPropsAll('transform');
|
|
};
|
|
|
|
|
|
tests['csstransforms3d'] = function() {
|
|
|
|
var ret = !!testPropsAll('perspective');
|
|
|
|
// Webkit's 3D transforms are passed off to the browser's own graphics renderer.
|
|
// It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
|
|
// some conditions. As a result, Webkit typically recognizes the syntax but
|
|
// will sometimes throw a false positive, thus we must do a more thorough check:
|
|
if ( ret && 'webkitPerspective' in docElement.style ) {
|
|
|
|
// Webkit allows this media query to succeed only if the feature is enabled.
|
|
// `@media (transform-3d),(-webkit-transform-3d){ ... }`
|
|
injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
|
|
ret = node.offsetLeft === 9 && node.offsetHeight === 3;
|
|
});
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
|
|
tests['csstransitions'] = function() {
|
|
return testPropsAll('transition');
|
|
};
|
|
|
|
|
|
/*>>fontface*/
|
|
// @font-face detection routine by Diego Perini
|
|
// javascript.nwbox.com/CSSSupport/
|
|
|
|
// false positives:
|
|
// WebOS github.com/Modernizr/Modernizr/issues/342
|
|
// WP7 github.com/Modernizr/Modernizr/issues/538
|
|
tests['fontface'] = function() {
|
|
var bool;
|
|
|
|
injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
|
|
var style = document.getElementById('smodernizr'),
|
|
sheet = style.sheet || style.styleSheet,
|
|
cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
|
|
|
|
bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
|
|
});
|
|
|
|
return bool;
|
|
};
|
|
/*>>fontface*/
|
|
|
|
// CSS generated content detection
|
|
tests['generatedcontent'] = function() {
|
|
var bool;
|
|
|
|
injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
|
|
bool = node.offsetHeight >= 3;
|
|
});
|
|
|
|
return bool;
|
|
};
|
|
|
|
|
|
|
|
// These tests evaluate support of the video/audio elements, as well as
|
|
// testing what types of content they support.
|
|
//
|
|
// We're using the Boolean constructor here, so that we can extend the value
|
|
// e.g. Modernizr.video // true
|
|
// Modernizr.video.ogg // 'probably'
|
|
//
|
|
// Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
|
|
// thx to NielsLeenheer and zcorpan
|
|
|
|
// Note: in some older browsers, "no" was a return value instead of empty string.
|
|
// It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
|
|
// It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
|
|
|
|
tests['video'] = function() {
|
|
var elem = document.createElement('video'),
|
|
bool = false;
|
|
|
|
// IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
|
|
try {
|
|
if ( bool = !!elem.canPlayType ) {
|
|
bool = new Boolean(bool);
|
|
bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,'');
|
|
|
|
// Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
|
|
bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
|
|
|
|
bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
|
|
}
|
|
|
|
} catch(e) { }
|
|
|
|
return bool;
|
|
};
|
|
|
|
tests['audio'] = function() {
|
|
var elem = document.createElement('audio'),
|
|
bool = false;
|
|
|
|
try {
|
|
if ( bool = !!elem.canPlayType ) {
|
|
bool = new Boolean(bool);
|
|
bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
|
|
bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,'');
|
|
|
|
// Mimetypes accepted:
|
|
// developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
|
|
// bit.ly/iphoneoscodecs
|
|
bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,'');
|
|
bool.m4a = ( elem.canPlayType('audio/x-m4a;') ||
|
|
elem.canPlayType('audio/aac;')) .replace(/^no$/,'');
|
|
}
|
|
} catch(e) { }
|
|
|
|
return bool;
|
|
};
|
|
|
|
|
|
// In FF4, if disabled, window.localStorage should === null.
|
|
|
|
// Normally, we could not test that directly and need to do a
|
|
// `('localStorage' in window) && ` test first because otherwise Firefox will
|
|
// throw bugzil.la/365772 if cookies are disabled
|
|
|
|
// Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
|
|
// will throw the exception:
|
|
// QUOTA_EXCEEDED_ERRROR DOM Exception 22.
|
|
// Peculiarly, getItem and removeItem calls do not throw.
|
|
|
|
// Because we are forced to try/catch this, we'll go aggressive.
|
|
|
|
// Just FWIW: IE8 Compat mode supports these features completely:
|
|
// www.quirksmode.org/dom/html5.html
|
|
// But IE8 doesn't support either with local files
|
|
|
|
tests['localstorage'] = function() {
|
|
try {
|
|
localStorage.setItem(mod, mod);
|
|
localStorage.removeItem(mod);
|
|
return true;
|
|
} catch(e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
tests['sessionstorage'] = function() {
|
|
try {
|
|
sessionStorage.setItem(mod, mod);
|
|
sessionStorage.removeItem(mod);
|
|
return true;
|
|
} catch(e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
tests['webworkers'] = function() {
|
|
return !!window.Worker;
|
|
};
|
|
|
|
|
|
tests['applicationcache'] = function() {
|
|
return !!window.applicationCache;
|
|
};
|
|
|
|
|
|
// Thanks to Erik Dahlstrom
|
|
tests['svg'] = function() {
|
|
return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
|
|
};
|
|
|
|
// specifically for SVG inline in HTML, not within XHTML
|
|
// test page: paulirish.com/demo/inline-svg
|
|
tests['inlinesvg'] = function() {
|
|
var div = document.createElement('div');
|
|
div.innerHTML = '<svg/>';
|
|
return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
|
|
};
|
|
|
|
// SVG SMIL animation
|
|
tests['smil'] = function() {
|
|
return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
|
|
};
|
|
|
|
// This test is only for clip paths in SVG proper, not clip paths on HTML content
|
|
// demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
|
|
|
|
// However read the comments to dig into applying SVG clippaths to HTML content here:
|
|
// github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
|
|
tests['svgclippaths'] = function() {
|
|
return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
|
|
};
|
|
|
|
/*>>webforms*/
|
|
// input features and input types go directly onto the ret object, bypassing the tests loop.
|
|
// Hold this guy to execute in a moment.
|
|
function webforms() {
|
|
/*>>input*/
|
|
// Run through HTML5's new input attributes to see if the UA understands any.
|
|
// We're using f which is the <input> element created early on
|
|
// Mike Taylr has created a comprehensive resource for testing these attributes
|
|
// when applied to all input types:
|
|
// miketaylr.com/code/input-type-attr.html
|
|
// spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
|
|
|
|
// Only input placeholder is tested while textarea's placeholder is not.
|
|
// Currently Safari 4 and Opera 11 have support only for the input placeholder
|
|
// Both tests are available in feature-detects/forms-placeholder.js
|
|
Modernizr['input'] = (function( props ) {
|
|
for ( var i = 0, len = props.length; i < len; i++ ) {
|
|
attrs[ props[i] ] = !!(props[i] in inputElem);
|
|
}
|
|
if (attrs.list){
|
|
// safari false positive's on datalist: webk.it/74252
|
|
// see also github.com/Modernizr/Modernizr/issues/146
|
|
attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
|
|
}
|
|
return attrs;
|
|
})('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
|
|
/*>>input*/
|
|
|
|
/*>>inputtypes*/
|
|
// Run through HTML5's new input types to see if the UA understands any.
|
|
// This is put behind the tests runloop because it doesn't return a
|
|
// true/false like all the other tests; instead, it returns an object
|
|
// containing each input type with its corresponding true/false value
|
|
|
|
// Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
|
|
Modernizr['inputtypes'] = (function(props) {
|
|
|
|
for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
|
|
|
|
inputElem.setAttribute('type', inputElemType = props[i]);
|
|
bool = inputElem.type !== 'text';
|
|
|
|
// We first check to see if the type we give it sticks..
|
|
// If the type does, we feed it a textual value, which shouldn't be valid.
|
|
// If the value doesn't stick, we know there's input sanitization which infers a custom UI
|
|
if ( bool ) {
|
|
|
|
inputElem.value = smile;
|
|
inputElem.style.cssText = 'position:absolute;visibility:hidden;';
|
|
|
|
if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
|
|
|
|
docElement.appendChild(inputElem);
|
|
defaultView = document.defaultView;
|
|
|
|
// Safari 2-4 allows the smiley as a value, despite making a slider
|
|
bool = defaultView.getComputedStyle &&
|
|
defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
|
|
// Mobile android web browser has false positive, so must
|
|
// check the height to see if the widget is actually there.
|
|
(inputElem.offsetHeight !== 0);
|
|
|
|
docElement.removeChild(inputElem);
|
|
|
|
} else if ( /^(search|tel)$/.test(inputElemType) ){
|
|
// Spec doesn't define any special parsing or detectable UI
|
|
// behaviors so we pass these through as true
|
|
|
|
// Interestingly, opera fails the earlier test, so it doesn't
|
|
// even make it here.
|
|
|
|
} else if ( /^(url|email)$/.test(inputElemType) ) {
|
|
// Real url and email support comes with prebaked validation.
|
|
bool = inputElem.checkValidity && inputElem.checkValidity() === false;
|
|
|
|
} else {
|
|
// If the upgraded input compontent rejects the :) text, we got a winner
|
|
bool = inputElem.value != smile;
|
|
}
|
|
}
|
|
|
|
inputs[ props[i] ] = !!bool;
|
|
}
|
|
return inputs;
|
|
})('search tel url email datetime date month week time datetime-local number range color'.split(' '));
|
|
/*>>inputtypes*/
|
|
}
|
|
/*>>webforms*/
|
|
|
|
|
|
// End of test definitions
|
|
// -----------------------
|
|
|
|
|
|
|
|
// Run through all tests and detect their support in the current UA.
|
|
// todo: hypothetically we could be doing an array of tests and use a basic loop here.
|
|
for ( var feature in tests ) {
|
|
if ( hasOwnProp(tests, feature) ) {
|
|
// run the test, throw the return value into the Modernizr,
|
|
// then based on that boolean, define an appropriate className
|
|
// and push it into an array of classes we'll join later.
|
|
featureName = feature.toLowerCase();
|
|
Modernizr[featureName] = tests[feature]();
|
|
|
|
classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
|
|
}
|
|
}
|
|
|
|
/*>>webforms*/
|
|
// input tests need to run.
|
|
Modernizr.input || webforms();
|
|
/*>>webforms*/
|
|
|
|
|
|
/**
|
|
* addTest allows the user to define their own feature tests
|
|
* the result will be added onto the Modernizr object,
|
|
* as well as an appropriate className set on the html element
|
|
*
|
|
* @param feature - String naming the feature
|
|
* @param test - Function returning true if feature is supported, false if not
|
|
*/
|
|
Modernizr.addTest = function ( feature, test ) {
|
|
if ( typeof feature == 'object' ) {
|
|
for ( var key in feature ) {
|
|
if ( hasOwnProp( feature, key ) ) {
|
|
Modernizr.addTest( key, feature[ key ] );
|
|
}
|
|
}
|
|
} else {
|
|
|
|
feature = feature.toLowerCase();
|
|
|
|
if ( Modernizr[feature] !== undefined ) {
|
|
// we're going to quit if you're trying to overwrite an existing test
|
|
// if we were to allow it, we'd do this:
|
|
// var re = new RegExp("\\b(no-)?" + feature + "\\b");
|
|
// docElement.className = docElement.className.replace( re, '' );
|
|
// but, no rly, stuff 'em.
|
|
return Modernizr;
|
|
}
|
|
|
|
test = typeof test == 'function' ? test() : test;
|
|
|
|
if (typeof enableClasses !== "undefined" && enableClasses) {
|
|
docElement.className += ' ' + (test ? '' : 'no-') + feature;
|
|
}
|
|
Modernizr[feature] = test;
|
|
|
|
}
|
|
|
|
return Modernizr; // allow chaining.
|
|
};
|
|
|
|
|
|
// Reset modElem.cssText to nothing to reduce memory footprint.
|
|
setCss('');
|
|
modElem = inputElem = null;
|
|
|
|
/*>>shiv*/
|
|
/**
|
|
* @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
|
*/
|
|
;(function(window, document) {
|
|
/*jshint evil:true */
|
|
/** version */
|
|
var version = '3.7.0';
|
|
|
|
/** Preset options */
|
|
var options = window.html5 || {};
|
|
|
|
/** Used to skip problem elements */
|
|
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
|
|
|
|
/** Not all elements can be cloned in IE **/
|
|
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
|
|
|
|
/** Detect whether the browser supports default html5 styles */
|
|
var supportsHtml5Styles;
|
|
|
|
/** Name of the expando, to work with multiple documents or to re-shiv one document */
|
|
var expando = '_html5shiv';
|
|
|
|
/** The id for the the documents expando */
|
|
var expanID = 0;
|
|
|
|
/** Cached data for each document */
|
|
var expandoData = {};
|
|
|
|
/** Detect whether the browser supports unknown elements */
|
|
var supportsUnknownElements;
|
|
|
|
(function() {
|
|
try {
|
|
var a = document.createElement('a');
|
|
a.innerHTML = '<xyz></xyz>';
|
|
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
|
|
supportsHtml5Styles = ('hidden' in a);
|
|
|
|
supportsUnknownElements = a.childNodes.length == 1 || (function() {
|
|
// assign a false positive if unable to shiv
|
|
(document.createElement)('a');
|
|
var frag = document.createDocumentFragment();
|
|
return (
|
|
typeof frag.cloneNode == 'undefined' ||
|
|
typeof frag.createDocumentFragment == 'undefined' ||
|
|
typeof frag.createElement == 'undefined'
|
|
);
|
|
}());
|
|
} catch(e) {
|
|
// assign a false positive if detection fails => unable to shiv
|
|
supportsHtml5Styles = true;
|
|
supportsUnknownElements = true;
|
|
}
|
|
|
|
}());
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a style sheet with the given CSS text and adds it to the document.
|
|
* @private
|
|
* @param {Document} ownerDocument The document.
|
|
* @param {String} cssText The CSS text.
|
|
* @returns {StyleSheet} The style element.
|
|
*/
|
|
function addStyleSheet(ownerDocument, cssText) {
|
|
var p = ownerDocument.createElement('p'),
|
|
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
|
|
|
|
p.innerHTML = 'x<style>' + cssText + '</style>';
|
|
return parent.insertBefore(p.lastChild, parent.firstChild);
|
|
}
|
|
|
|
/**
|
|
* Returns the value of `html5.elements` as an array.
|
|
* @private
|
|
* @returns {Array} An array of shived element node names.
|
|
*/
|
|
function getElements() {
|
|
var elements = html5.elements;
|
|
return typeof elements == 'string' ? elements.split(' ') : elements;
|
|
}
|
|
|
|
/**
|
|
* Returns the data associated to the given document
|
|
* @private
|
|
* @param {Document} ownerDocument The document.
|
|
* @returns {Object} An object of data.
|
|
*/
|
|
function getExpandoData(ownerDocument) {
|
|
var data = expandoData[ownerDocument[expando]];
|
|
if (!data) {
|
|
data = {};
|
|
expanID++;
|
|
ownerDocument[expando] = expanID;
|
|
expandoData[expanID] = data;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* returns a shived element for the given nodeName and document
|
|
* @memberOf html5
|
|
* @param {String} nodeName name of the element
|
|
* @param {Document} ownerDocument The context document.
|
|
* @returns {Object} The shived element.
|
|
*/
|
|
function createElement(nodeName, ownerDocument, data){
|
|
if (!ownerDocument) {
|
|
ownerDocument = document;
|
|
}
|
|
if(supportsUnknownElements){
|
|
return ownerDocument.createElement(nodeName);
|
|
}
|
|
if (!data) {
|
|
data = getExpandoData(ownerDocument);
|
|
}
|
|
var node;
|
|
|
|
if (data.cache[nodeName]) {
|
|
node = data.cache[nodeName].cloneNode();
|
|
} else if (saveClones.test(nodeName)) {
|
|
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
|
|
} else {
|
|
node = data.createElem(nodeName);
|
|
}
|
|
|
|
// Avoid adding some elements to fragments in IE < 9 because
|
|
// * Attributes like `name` or `type` cannot be set/changed once an element
|
|
// is inserted into a document/fragment
|
|
// * Link elements with `src` attributes that are inaccessible, as with
|
|
// a 403 response, will cause the tab/window to crash
|
|
// * Script elements appended to fragments will execute when their `src`
|
|
// or `text` property is set
|
|
return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
|
|
}
|
|
|
|
/**
|
|
* returns a shived DocumentFragment for the given document
|
|
* @memberOf html5
|
|
* @param {Document} ownerDocument The context document.
|
|
* @returns {Object} The shived DocumentFragment.
|
|
*/
|
|
function createDocumentFragment(ownerDocument, data){
|
|
if (!ownerDocument) {
|
|
ownerDocument = document;
|
|
}
|
|
if(supportsUnknownElements){
|
|
return ownerDocument.createDocumentFragment();
|
|
}
|
|
data = data || getExpandoData(ownerDocument);
|
|
var clone = data.frag.cloneNode(),
|
|
i = 0,
|
|
elems = getElements(),
|
|
l = elems.length;
|
|
for(;i<l;i++){
|
|
clone.createElement(elems[i]);
|
|
}
|
|
return clone;
|
|
}
|
|
|
|
/**
|
|
* Shivs the `createElement` and `createDocumentFragment` methods of the document.
|
|
* @private
|
|
* @param {Document|DocumentFragment} ownerDocument The document.
|
|
* @param {Object} data of the document.
|
|
*/
|
|
function shivMethods(ownerDocument, data) {
|
|
if (!data.cache) {
|
|
data.cache = {};
|
|
data.createElem = ownerDocument.createElement;
|
|
data.createFrag = ownerDocument.createDocumentFragment;
|
|
data.frag = data.createFrag();
|
|
}
|
|
|
|
|
|
ownerDocument.createElement = function(nodeName) {
|
|
//abort shiv
|
|
if (!html5.shivMethods) {
|
|
return data.createElem(nodeName);
|
|
}
|
|
return createElement(nodeName, ownerDocument, data);
|
|
};
|
|
|
|
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
|
|
'var n=f.cloneNode(),c=n.createElement;' +
|
|
'h.shivMethods&&(' +
|
|
// unroll the `createElement` calls
|
|
getElements().join().replace(/[\w\-]+/g, function(nodeName) {
|
|
data.createElem(nodeName);
|
|
data.frag.createElement(nodeName);
|
|
return 'c("' + nodeName + '")';
|
|
}) +
|
|
');return n}'
|
|
)(html5, data.frag);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Shivs the given document.
|
|
* @memberOf html5
|
|
* @param {Document} ownerDocument The document to shiv.
|
|
* @returns {Document} The shived document.
|
|
*/
|
|
function shivDocument(ownerDocument) {
|
|
if (!ownerDocument) {
|
|
ownerDocument = document;
|
|
}
|
|
var data = getExpandoData(ownerDocument);
|
|
|
|
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
|
|
data.hasCSS = !!addStyleSheet(ownerDocument,
|
|
// corrects block display not defined in IE6/7/8/9
|
|
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
|
|
// adds styling not present in IE6/7/8/9
|
|
'mark{background:#FF0;color:#000}' +
|
|
// hides non-rendered elements
|
|
'template{display:none}'
|
|
);
|
|
}
|
|
if (!supportsUnknownElements) {
|
|
shivMethods(ownerDocument, data);
|
|
}
|
|
return ownerDocument;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* The `html5` object is exposed so that more elements can be shived and
|
|
* existing shiving can be detected on iframes.
|
|
* @type Object
|
|
* @example
|
|
*
|
|
* // options can be changed before the script is included
|
|
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
|
|
*/
|
|
var html5 = {
|
|
|
|
/**
|
|
* An array or space separated string of node names of the elements to shiv.
|
|
* @memberOf html5
|
|
* @type Array|String
|
|
*/
|
|
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video',
|
|
|
|
/**
|
|
* current version of html5shiv
|
|
*/
|
|
'version': version,
|
|
|
|
/**
|
|
* A flag to indicate that the HTML5 style sheet should be inserted.
|
|
* @memberOf html5
|
|
* @type Boolean
|
|
*/
|
|
'shivCSS': (options.shivCSS !== false),
|
|
|
|
/**
|
|
* Is equal to true if a browser supports creating unknown/HTML5 elements
|
|
* @memberOf html5
|
|
* @type boolean
|
|
*/
|
|
'supportsUnknownElements': supportsUnknownElements,
|
|
|
|
/**
|
|
* A flag to indicate that the document's `createElement` and `createDocumentFragment`
|
|
* methods should be overwritten.
|
|
* @memberOf html5
|
|
* @type Boolean
|
|
*/
|
|
'shivMethods': (options.shivMethods !== false),
|
|
|
|
/**
|
|
* A string to describe the type of `html5` object ("default" or "default print").
|
|
* @memberOf html5
|
|
* @type String
|
|
*/
|
|
'type': 'default',
|
|
|
|
// shivs the document according to the specified `html5` object options
|
|
'shivDocument': shivDocument,
|
|
|
|
//creates a shived element
|
|
createElement: createElement,
|
|
|
|
//creates a shived documentFragment
|
|
createDocumentFragment: createDocumentFragment
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// expose html5
|
|
window.html5 = html5;
|
|
|
|
// shiv the document
|
|
shivDocument(document);
|
|
|
|
}(this, document));
|
|
/*>>shiv*/
|
|
|
|
// Assign private properties to the return object with prefix
|
|
Modernizr._version = version;
|
|
|
|
// expose these for the plugin API. Look in the source for how to join() them against your input
|
|
/*>>prefixes*/
|
|
Modernizr._prefixes = prefixes;
|
|
/*>>prefixes*/
|
|
/*>>domprefixes*/
|
|
Modernizr._domPrefixes = domPrefixes;
|
|
Modernizr._cssomPrefixes = cssomPrefixes;
|
|
/*>>domprefixes*/
|
|
|
|
/*>>mq*/
|
|
// Modernizr.mq tests a given media query, live against the current state of the window
|
|
// A few important notes:
|
|
// * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
|
|
// * A max-width or orientation query will be evaluated against the current state, which may change later.
|
|
// * You must specify values. Eg. If you are testing support for the min-width media query use:
|
|
// Modernizr.mq('(min-width:0)')
|
|
// usage:
|
|
// Modernizr.mq('only screen and (max-width:768)')
|
|
Modernizr.mq = testMediaQuery;
|
|
/*>>mq*/
|
|
|
|
/*>>hasevent*/
|
|
// Modernizr.hasEvent() detects support for a given event, with an optional element to test on
|
|
// Modernizr.hasEvent('gesturestart', elem)
|
|
Modernizr.hasEvent = isEventSupported;
|
|
/*>>hasevent*/
|
|
|
|
/*>>testprop*/
|
|
// Modernizr.testProp() investigates whether a given style property is recognized
|
|
// Note that the property names must be provided in the camelCase variant.
|
|
// Modernizr.testProp('pointerEvents')
|
|
Modernizr.testProp = function(prop){
|
|
return testProps([prop]);
|
|
};
|
|
/*>>testprop*/
|
|
|
|
/*>>testallprops*/
|
|
// Modernizr.testAllProps() investigates whether a given style property,
|
|
// or any of its vendor-prefixed variants, is recognized
|
|
// Note that the property names must be provided in the camelCase variant.
|
|
// Modernizr.testAllProps('boxSizing')
|
|
Modernizr.testAllProps = testPropsAll;
|
|
/*>>testallprops*/
|
|
|
|
|
|
/*>>teststyles*/
|
|
// Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
|
|
// Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
|
|
Modernizr.testStyles = injectElementWithStyles;
|
|
/*>>teststyles*/
|
|
|
|
|
|
/*>>prefixed*/
|
|
// Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
|
|
// Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
|
|
|
|
// Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
|
|
// Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
|
|
//
|
|
// str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
|
|
|
|
// If you're trying to ascertain which transition end event to bind to, you might do something like...
|
|
//
|
|
// var transEndEventNames = {
|
|
// 'WebkitTransition' : 'webkitTransitionEnd',
|
|
// 'MozTransition' : 'transitionend',
|
|
// 'OTransition' : 'oTransitionEnd',
|
|
// 'msTransition' : 'MSTransitionEnd',
|
|
// 'transition' : 'transitionend'
|
|
// },
|
|
// transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
|
|
|
|
Modernizr.prefixed = function(prop, obj, elem){
|
|
if(!obj) {
|
|
return testPropsAll(prop, 'pfx');
|
|
} else {
|
|
// Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
|
|
return testPropsAll(prop, obj, elem);
|
|
}
|
|
};
|
|
/*>>prefixed*/
|
|
|
|
|
|
/*>>cssclasses*/
|
|
// Remove "no-js" class from <html> element, if it exists:
|
|
docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
|
|
|
|
// Add the new classes to the <html> element.
|
|
(enableClasses ? ' js ' + classes.join(' ') : '');
|
|
/*>>cssclasses*/
|
|
|
|
return Modernizr;
|
|
|
|
})(this, this.document);
|
|
/* @preserve
|
|
* Leaflet 1.5.1, a JS library for interactive maps. http://leafletjs.com
|
|
* (c) 2010-2018 Vladimir Agafonkin, (c) 2010-2011 CloudMade
|
|
*/
|
|
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";var i=Object.freeze;function h(t){var i,e,n,o;for(e=1,n=arguments.length;e<n;e++)for(i in o=arguments[e])t[i]=o[i];return t}Object.freeze=function(t){return t};var s=Object.create||function(t){return e.prototype=t,new e};function e(){}function a(t,i){var e=Array.prototype.slice;if(t.bind)return t.bind.apply(t,e.call(arguments,1));var n=e.call(arguments,2);return function(){return t.apply(i,n.length?n.concat(e.call(arguments)):arguments)}}var n=0;function u(t){return t._leaflet_id=t._leaflet_id||++n,t._leaflet_id}function o(t,i,e){var n,o,s,r;return r=function(){n=!1,o&&(s.apply(e,o),o=!1)},s=function(){n?o=arguments:(t.apply(e,arguments),setTimeout(r,i),n=!0)}}function r(t,i,e){var n=i[1],o=i[0],s=n-o;return t===n&&e?t:((t-o)%s+s)%s+o}function l(){return!1}function c(t,i){return i=void 0===i?6:i,+(Math.round(t+"e+"+i)+"e-"+i)}function _(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function d(t){return _(t).split(/\s+/)}function p(t,i){for(var e in t.hasOwnProperty("options")||(t.options=t.options?s(t.options):{}),i)t.options[e]=i[e];return t.options}function m(t,i,e){var n=[];for(var o in t)n.push(encodeURIComponent(e?o.toUpperCase():o)+"="+encodeURIComponent(t[o]));return(i&&-1!==i.indexOf("?")?"&":"?")+n.join("&")}var f=/\{ *([\w_-]+) *\}/g;function g(t,n){return t.replace(f,function(t,i){var e=n[i];if(void 0===e)throw new Error("No value provided for variable "+t);return"function"==typeof e&&(e=e(n)),e})}var v=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)};function y(t,i){for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1}var x="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";function w(t){return window["webkit"+t]||window["moz"+t]||window["ms"+t]}var P=0;function b(t){var i=+new Date,e=Math.max(0,16-(i-P));return P=i+e,window.setTimeout(t,e)}var T=window.requestAnimationFrame||w("RequestAnimationFrame")||b,z=window.cancelAnimationFrame||w("CancelAnimationFrame")||w("CancelRequestAnimationFrame")||function(t){window.clearTimeout(t)};function M(t,i,e){if(!e||T!==b)return T.call(window,a(t,i));t.call(i)}function C(t){t&&z.call(window,t)}var S=(Object.freeze||Object)({freeze:i,extend:h,create:s,bind:a,lastId:n,stamp:u,throttle:o,wrapNum:r,falseFn:l,formatNum:c,trim:_,splitWords:d,setOptions:p,getParamString:m,template:g,isArray:v,indexOf:y,emptyImageUrl:x,requestFn:T,cancelFn:z,requestAnimFrame:M,cancelAnimFrame:C});function Z(){}Z.extend=function(t){function i(){this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()}var e=i.__super__=this.prototype,n=s(e);for(var o in(n.constructor=i).prototype=n,this)this.hasOwnProperty(o)&&"prototype"!==o&&"__super__"!==o&&(i[o]=this[o]);return t.statics&&(h(i,t.statics),delete t.statics),t.includes&&(function(t){if("undefined"==typeof L||!L||!L.Mixin)return;t=v(t)?t:[t];for(var i=0;i<t.length;i++)t[i]===L.Mixin.Events&&console.warn("Deprecated include of L.Mixin.Events: this property will be removed in future releases, please inherit from L.Evented instead.",(new Error).stack)}(t.includes),h.apply(null,[n].concat(t.includes)),delete t.includes),n.options&&(t.options=h(s(n.options),t.options)),h(n,t),n._initHooks=[],n.callInitHooks=function(){if(!this._initHooksCalled){e.callInitHooks&&e.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,i=n._initHooks.length;t<i;t++)n._initHooks[t].call(this)}},i},Z.include=function(t){return h(this.prototype,t),this},Z.mergeOptions=function(t){return h(this.prototype.options,t),this},Z.addInitHook=function(t){var i=Array.prototype.slice.call(arguments,1),e="function"==typeof t?t:function(){this[t].apply(this,i)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(e),this};var E={on:function(t,i,e){if("object"==typeof t)for(var n in t)this._on(n,t[n],i);else for(var o=0,s=(t=d(t)).length;o<s;o++)this._on(t[o],i,e);return this},off:function(t,i,e){if(t)if("object"==typeof t)for(var n in t)this._off(n,t[n],i);else for(var o=0,s=(t=d(t)).length;o<s;o++)this._off(t[o],i,e);else delete this._events;return this},_on:function(t,i,e){this._events=this._events||{};var n=this._events[t];n||(n=[],this._events[t]=n),e===this&&(e=void 0);for(var o={fn:i,ctx:e},s=n,r=0,a=s.length;r<a;r++)if(s[r].fn===i&&s[r].ctx===e)return;s.push(o)},_off:function(t,i,e){var n,o,s;if(this._events&&(n=this._events[t]))if(i){if(e===this&&(e=void 0),n)for(o=0,s=n.length;o<s;o++){var r=n[o];if(r.ctx===e&&r.fn===i)return r.fn=l,this._firingCount&&(this._events[t]=n=n.slice()),void n.splice(o,1)}}else{for(o=0,s=n.length;o<s;o++)n[o].fn=l;delete this._events[t]}},fire:function(t,i,e){if(!this.listens(t,e))return this;var n=h({},i,{type:t,target:this,sourceTarget:i&&i.sourceTarget||this});if(this._events){var o=this._events[t];if(o){this._firingCount=this._firingCount+1||1;for(var s=0,r=o.length;s<r;s++){var a=o[s];a.fn.call(a.ctx||this,n)}this._firingCount--}}return e&&this._propagateEvent(n),this},listens:function(t,i){var e=this._events&&this._events[t];if(e&&e.length)return!0;if(i)for(var n in this._eventParents)if(this._eventParents[n].listens(t,i))return!0;return!1},once:function(t,i,e){if("object"==typeof t){for(var n in t)this.once(n,t[n],i);return this}var o=a(function(){this.off(t,i,e).off(t,o,e)},this);return this.on(t,i,e).on(t,o,e)},addEventParent:function(t){return this._eventParents=this._eventParents||{},this._eventParents[u(t)]=t,this},removeEventParent:function(t){return this._eventParents&&delete this._eventParents[u(t)],this},_propagateEvent:function(t){for(var i in this._eventParents)this._eventParents[i].fire(t.type,h({layer:t.target,propagatedFrom:t.target},t),!0)}};E.addEventListener=E.on,E.removeEventListener=E.clearAllEventListeners=E.off,E.addOneTimeEventListener=E.once,E.fireEvent=E.fire,E.hasEventListeners=E.listens;var k=Z.extend(E);function B(t,i,e){this.x=e?Math.round(t):t,this.y=e?Math.round(i):i}var A=Math.trunc||function(t){return 0<t?Math.floor(t):Math.ceil(t)};function I(t,i,e){return t instanceof B?t:v(t)?new B(t[0],t[1]):null==t?t:"object"==typeof t&&"x"in t&&"y"in t?new B(t.x,t.y):new B(t,i,e)}function O(t,i){if(t)for(var e=i?[t,i]:t,n=0,o=e.length;n<o;n++)this.extend(e[n])}function R(t,i){return!t||t instanceof O?t:new O(t,i)}function N(t,i){if(t)for(var e=i?[t,i]:t,n=0,o=e.length;n<o;n++)this.extend(e[n])}function D(t,i){return t instanceof N?t:new N(t,i)}function j(t,i,e){if(isNaN(t)||isNaN(i))throw new Error("Invalid LatLng object: ("+t+", "+i+")");this.lat=+t,this.lng=+i,void 0!==e&&(this.alt=+e)}function W(t,i,e){return t instanceof j?t:v(t)&&"object"!=typeof t[0]?3===t.length?new j(t[0],t[1],t[2]):2===t.length?new j(t[0],t[1]):null:null==t?t:"object"==typeof t&&"lat"in t?new j(t.lat,"lng"in t?t.lng:t.lon,t.alt):void 0===i?null:new j(t,i,e)}B.prototype={clone:function(){return new B(this.x,this.y)},add:function(t){return this.clone()._add(I(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(I(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new B(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new B(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},trunc:function(){return this.clone()._trunc()},_trunc:function(){return this.x=A(this.x),this.y=A(this.y),this},distanceTo:function(t){var i=(t=I(t)).x-this.x,e=t.y-this.y;return Math.sqrt(i*i+e*e)},equals:function(t){return(t=I(t)).x===this.x&&t.y===this.y},contains:function(t){return t=I(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+c(this.x)+", "+c(this.y)+")"}},O.prototype={extend:function(t){return t=I(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new B((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new B(this.min.x,this.max.y)},getTopRight:function(){return new B(this.max.x,this.min.y)},getTopLeft:function(){return this.min},getBottomRight:function(){return this.max},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var i,e;return(t="number"==typeof t[0]||t instanceof B?I(t):R(t))instanceof O?(i=t.min,e=t.max):i=e=t,i.x>=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.x<e.x,r=o.y>i.y&&n.y<e.y;return s&&r},isValid:function(){return!(!this.min||!this.max)}},N.prototype={extend:function(t){var i,e,n=this._southWest,o=this._northEast;if(t instanceof j)e=i=t;else{if(!(t instanceof N))return t?this.extend(W(t)||D(t)):this;if(i=t._southWest,e=t._northEast,!i||!e)return this}return n||o?(n.lat=Math.min(i.lat,n.lat),n.lng=Math.min(i.lng,n.lng),o.lat=Math.max(e.lat,o.lat),o.lng=Math.max(e.lng,o.lng)):(this._southWest=new j(i.lat,i.lng),this._northEast=new j(e.lat,e.lng)),this},pad:function(t){var i=this._southWest,e=this._northEast,n=Math.abs(i.lat-e.lat)*t,o=Math.abs(i.lng-e.lng)*t;return new N(new j(i.lat-n,i.lng-o),new j(e.lat+n,e.lng+o))},getCenter:function(){return new j((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new j(this.getNorth(),this.getWest())},getSouthEast:function(){return new j(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t="number"==typeof t[0]||t instanceof j||"lat"in t?W(t):D(t);var i,e,n=this._southWest,o=this._northEast;return t instanceof N?(i=t.getSouthWest(),e=t.getNorthEast()):i=e=t,i.lat>=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lat<e.lat,r=o.lng>i.lng&&n.lng<e.lng;return s&&r},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",")},equals:function(t,i){return!!t&&(t=D(t),this._southWest.equals(t.getSouthWest(),i)&&this._northEast.equals(t.getNorthEast(),i))},isValid:function(){return!(!this._southWest||!this._northEast)}};var H,F={latLngToPoint:function(t,i){var e=this.projection.project(t),n=this.scale(i);return this.transformation._transform(e,n)},pointToLatLng:function(t,i){var e=this.scale(i),n=this.transformation.untransform(t,e);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},unproject:function(t){return this.projection.unproject(t)},scale:function(t){return 256*Math.pow(2,t)},zoom:function(t){return Math.log(t/256)/Math.LN2},getProjectedBounds:function(t){if(this.infinite)return null;var i=this.projection.bounds,e=this.scale(t);return new O(this.transformation.transform(i.min,e),this.transformation.transform(i.max,e))},infinite:!(j.prototype={equals:function(t,i){return!!t&&(t=W(t),Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng))<=(void 0===i?1e-9:i))},toString:function(t){return"LatLng("+c(this.lat,t)+", "+c(this.lng,t)+")"},distanceTo:function(t){return U.distance(this,W(t))},wrap:function(){return U.wrapLatLng(this)},toBounds:function(t){var i=180*t/40075017,e=i/Math.cos(Math.PI/180*this.lat);return D([this.lat-i,this.lng-e],[this.lat+i,this.lng+e])},clone:function(){return new j(this.lat,this.lng,this.alt)}}),wrapLatLng:function(t){var i=this.wrapLng?r(t.lng,this.wrapLng,!0):t.lng;return new j(this.wrapLat?r(t.lat,this.wrapLat,!0):t.lat,i,t.alt)},wrapLatLngBounds:function(t){var i=t.getCenter(),e=this.wrapLatLng(i),n=i.lat-e.lat,o=i.lng-e.lng;if(0==n&&0==o)return t;var s=t.getSouthWest(),r=t.getNorthEast();return new N(new j(s.lat-n,s.lng-o),new j(r.lat-n,r.lng-o))}},U=h({},F,{wrapLng:[-180,180],R:6371e3,distance:function(t,i){var e=Math.PI/180,n=t.lat*e,o=i.lat*e,s=Math.sin((i.lat-t.lat)*e/2),r=Math.sin((i.lng-t.lng)*e/2),a=s*s+Math.cos(n)*Math.cos(o)*r*r,h=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));return this.R*h}}),V=6378137,q={R:V,MAX_LATITUDE:85.0511287798,project:function(t){var i=Math.PI/180,e=this.MAX_LATITUDE,n=Math.max(Math.min(e,t.lat),-e),o=Math.sin(n*i);return new B(this.R*t.lng*i,this.R*Math.log((1+o)/(1-o))/2)},unproject:function(t){var i=180/Math.PI;return new j((2*Math.atan(Math.exp(t.y/this.R))-Math.PI/2)*i,t.x*i/this.R)},bounds:(H=V*Math.PI,new O([-H,-H],[H,H]))};function G(t,i,e,n){if(v(t))return this._a=t[0],this._b=t[1],this._c=t[2],void(this._d=t[3]);this._a=t,this._b=i,this._c=e,this._d=n}function K(t,i,e,n){return new G(t,i,e,n)}G.prototype={transform:function(t,i){return this._transform(t.clone(),i)},_transform:function(t,i){return i=i||1,t.x=i*(this._a*t.x+this._b),t.y=i*(this._c*t.y+this._d),t},untransform:function(t,i){return i=i||1,new B((t.x/i-this._b)/this._a,(t.y/i-this._d)/this._c)}};var Y,X=h({},U,{code:"EPSG:3857",projection:q,transformation:(Y=.5/(Math.PI*q.R),K(Y,.5,-Y,.5))}),J=h({},X,{code:"EPSG:900913"});function $(t){return document.createElementNS("http://www.w3.org/2000/svg",t)}function Q(t,i){var e,n,o,s,r,a,h="";for(e=0,o=t.length;e<o;e++){for(n=0,s=(r=t[e]).length;n<s;n++)h+=(n?"L":"M")+(a=r[n]).x+" "+a.y;h+=i?Zt?"z":"x":""}return h||"M0 0"}var tt=document.documentElement.style,it="ActiveXObject"in window,et=it&&!document.addEventListener,nt="msLaunchUri"in navigator&&!("documentMode"in document),ot=kt("webkit"),st=kt("android"),rt=kt("android 2")||kt("android 3"),at=parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1],10),ht=st&&kt("Google")&&at<537&&!("AudioNode"in window),ut=!!window.opera,lt=kt("chrome"),ct=kt("gecko")&&!ot&&!ut&&!it,_t=!lt&&kt("safari"),dt=kt("phantom"),pt="OTransition"in tt,mt=0===navigator.platform.indexOf("Win"),ft=it&&"transition"in tt,gt="WebKitCSSMatrix"in window&&"m11"in new window.WebKitCSSMatrix&&!rt,vt="MozPerspective"in tt,yt=!window.L_DISABLE_3D&&(ft||gt||vt)&&!pt&&!dt,xt="undefined"!=typeof orientation||kt("mobile"),wt=xt&&ot,Pt=xt&>,Lt=!window.PointerEvent&&window.MSPointerEvent,bt=!(!window.PointerEvent&&!Lt),Tt=!window.L_NO_TOUCH&&(bt||"ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),zt=xt&&ut,Mt=xt&&ct,Ct=1<(window.devicePixelRatio||window.screen.deviceXDPI/window.screen.logicalXDPI),St=!!document.createElement("canvas").getContext,Zt=!(!document.createElementNS||!$("svg").createSVGRect),Et=!Zt&&function(){try{var t=document.createElement("div");t.innerHTML='<v:shape adj="1"/>';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt=(Object.freeze||Object)({ie:it,ielt9:et,edge:nt,webkit:ot,android:st,android23:rt,androidStock:ht,opera:ut,chrome:lt,gecko:ct,safari:_t,phantom:dt,opera12:pt,win:mt,ie3d:ft,webkit3d:gt,gecko3d:vt,any3d:yt,mobile:xt,mobileWebkit:wt,mobileWebkit3d:Pt,msPointer:Lt,pointer:bt,touch:Tt,mobileOpera:zt,mobileGecko:Mt,retina:Ct,canvas:St,svg:Zt,vml:Et}),At=Lt?"MSPointerDown":"pointerdown",It=Lt?"MSPointerMove":"pointermove",Ot=Lt?"MSPointerUp":"pointerup",Rt=Lt?"MSPointerCancel":"pointercancel",Nt=["INPUT","SELECT","OPTION"],Dt={},jt=!1,Wt=0;function Ht(t,i,e,n){return"touchstart"===i?function(t,i,e){var n=a(function(t){if("mouse"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(Nt.indexOf(t.target.tagName)<0))return;Di(t)}qt(t,i)});t["_leaflet_touchstart"+e]=n,t.addEventListener(At,n,!1),jt||(document.documentElement.addEventListener(At,Ft,!0),document.documentElement.addEventListener(It,Ut,!0),document.documentElement.addEventListener(Ot,Vt,!0),document.documentElement.addEventListener(Rt,Vt,!0),jt=!0)}(t,e,n):"touchmove"===i?function(t,i,e){var n=function(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&qt(t,i)};t["_leaflet_touchmove"+e]=n,t.addEventListener(It,n,!1)}(t,e,n):"touchend"===i&&function(t,i,e){var n=function(t){qt(t,i)};t["_leaflet_touchend"+e]=n,t.addEventListener(Ot,n,!1),t.addEventListener(Rt,n,!1)}(t,e,n),this}function Ft(t){Dt[t.pointerId]=t,Wt++}function Ut(t){Dt[t.pointerId]&&(Dt[t.pointerId]=t)}function Vt(t){delete Dt[t.pointerId],Wt--}function qt(t,i){for(var e in t.touches=[],Dt)t.touches.push(Dt[e]);t.changedTouches=[t],i(t)}var Gt=Lt?"MSPointerDown":bt?"pointerdown":"touchstart",Kt=Lt?"MSPointerUp":bt?"pointerup":"touchend",Yt="_leaflet_";function Xt(t,o,i){var s,r,a=!1;function e(t){var i;if(bt){if(!nt||"mouse"===t.pointerType)return;i=Wt}else i=t.touches.length;if(!(1<i)){var e=Date.now(),n=e-(s||e);r=t.touches?t.touches[0]:t,a=0<n&&n<=250,s=e}}function n(t){if(a&&!r.cancelBubble){if(bt){if(!nt||"mouse"===t.pointerType)return;var i,e,n={};for(e in r)i=r[e],n[e]=i&&i.bind?i.bind(r):i;r=n}r.type="dblclick",r.button=0,o(r),s=null}}return t[Yt+Gt+i]=e,t[Yt+Kt+i]=n,t[Yt+"dblclick"+i]=o,t.addEventListener(Gt,e,!1),t.addEventListener(Kt,n,!1),t.addEventListener("dblclick",o,!1),this}function Jt(t,i){var e=t[Yt+Gt+i],n=t[Yt+Kt+i],o=t[Yt+"dblclick"+i];return t.removeEventListener(Gt,e,!1),t.removeEventListener(Kt,n,!1),nt||t.removeEventListener("dblclick",o,!1),this}var $t,Qt,ti,ii,ei,ni=yi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),oi=yi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),si="webkitTransition"===oi||"OTransition"===oi?oi+"End":"transitionend";function ri(t){return"string"==typeof t?document.getElementById(t):t}function ai(t,i){var e=t.style[i]||t.currentStyle&&t.currentStyle[i];if((!e||"auto"===e)&&document.defaultView){var n=document.defaultView.getComputedStyle(t,null);e=n?n[i]:null}return"auto"===e?null:e}function hi(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ui(t){var i=t.parentNode;i&&i.removeChild(t)}function li(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function ci(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function _i(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function di(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=gi(t);return 0<e.length&&new RegExp("(^|\\s)"+i+"(\\s|$)").test(e)}function pi(t,i){if(void 0!==t.classList)for(var e=d(i),n=0,o=e.length;n<o;n++)t.classList.add(e[n]);else if(!di(t,i)){var s=gi(t);fi(t,(s?s+" ":"")+i)}}function mi(t,i){void 0!==t.classList?t.classList.remove(i):fi(t,_((" "+gi(t)+" ").replace(" "+i+" "," ")))}function fi(t,i){void 0===t.className.baseVal?t.className=i:t.className.baseVal=i}function gi(t){return t.correspondingElement&&(t=t.correspondingElement),void 0===t.className.baseVal?t.className:t.className.baseVal}function vi(t,i){"opacity"in t.style?t.style.opacity=i:"filter"in t.style&&function(t,i){var e=!1,n="DXImageTransform.Microsoft.Alpha";try{e=t.filters.item(n)}catch(t){if(1===i)return}i=Math.round(100*i),e?(e.Enabled=100!==i,e.Opacity=i):t.style.filter+=" progid:"+n+"(opacity="+i+")"}(t,i)}function yi(t){for(var i=document.documentElement.style,e=0;e<t.length;e++)if(t[e]in i)return t[e];return!1}function xi(t,i,e){var n=i||new B(0,0);t.style[ni]=(ft?"translate("+n.x+"px,"+n.y+"px)":"translate3d("+n.x+"px,"+n.y+"px,0)")+(e?" scale("+e+")":"")}function wi(t,i){t._leaflet_pos=i,yt?xi(t,i):(t.style.left=i.x+"px",t.style.top=i.y+"px")}function Pi(t){return t._leaflet_pos||new B(0,0)}if("onselectstart"in document)$t=function(){Ei(window,"selectstart",Di)},Qt=function(){Bi(window,"selectstart",Di)};else{var Li=yi(["userSelect","WebkitUserSelect","OUserSelect","MozUserSelect","msUserSelect"]);$t=function(){if(Li){var t=document.documentElement.style;ti=t[Li],t[Li]="none"}},Qt=function(){Li&&(document.documentElement.style[Li]=ti,ti=void 0)}}function bi(){Ei(window,"dragstart",Di)}function Ti(){Bi(window,"dragstart",Di)}function zi(t){for(;-1===t.tabIndex;)t=t.parentNode;t.style&&(Mi(),ei=(ii=t).style.outline,t.style.outline="none",Ei(window,"keydown",Mi))}function Mi(){ii&&(ii.style.outline=ei,ei=ii=void 0,Bi(window,"keydown",Mi))}function Ci(t){for(;!((t=t.parentNode).offsetWidth&&t.offsetHeight||t===document.body););return t}function Si(t){var i=t.getBoundingClientRect();return{x:i.width/t.offsetWidth||1,y:i.height/t.offsetHeight||1,boundingClientRect:i}}var Zi=(Object.freeze||Object)({TRANSFORM:ni,TRANSITION:oi,TRANSITION_END:si,get:ri,getStyle:ai,create:hi,remove:ui,empty:li,toFront:ci,toBack:_i,hasClass:di,addClass:pi,removeClass:mi,setClass:fi,getClass:gi,setOpacity:vi,testProp:yi,setTransform:xi,setPosition:wi,getPosition:Pi,disableTextSelection:$t,enableTextSelection:Qt,disableImageDrag:bi,enableImageDrag:Ti,preventOutline:zi,restoreOutline:Mi,getSizedParentNode:Ci,getScale:Si});function Ei(t,i,e,n){if("object"==typeof i)for(var o in i)Ai(t,o,i[o],e);else for(var s=0,r=(i=d(i)).length;s<r;s++)Ai(t,i[s],e,n);return this}var ki="_leaflet_events";function Bi(t,i,e,n){if("object"==typeof i)for(var o in i)Ii(t,o,i[o],e);else if(i)for(var s=0,r=(i=d(i)).length;s<r;s++)Ii(t,i[s],e,n);else{for(var a in t[ki])Ii(t,a,t[ki][a]);delete t[ki]}return this}function Ai(i,t,e,n){var o=t+u(e)+(n?"_"+u(n):"");if(i[ki]&&i[ki][o])return this;var s=function(t){return e.call(n||i,t||window.event)},r=s;bt&&0===t.indexOf("touch")?Ht(i,t,s,o):!Tt||"dblclick"!==t||bt&<?"addEventListener"in i?"mousewheel"===t?i.addEventListener("onwheel"in i?"wheel":"mousewheel",s,!1):"mouseenter"===t||"mouseleave"===t?(s=function(t){t=t||window.event,Ki(i,t)&&r(t)},i.addEventListener("mouseenter"===t?"mouseover":"mouseout",s,!1)):("click"===t&&st&&(s=function(t){!function(t,i){var e=t.timeStamp||t.originalEvent&&t.originalEvent.timeStamp,n=Ui&&e-Ui;if(n&&100<n&&n<500||t.target._simulatedClick&&!t._simulated)return ji(t);Ui=e,i(t)}(t,r)}),i.addEventListener(t,s,!1)):"attachEvent"in i&&i.attachEvent("on"+t,s):Xt(i,s,o),i[ki]=i[ki]||{},i[ki][o]=s}function Ii(t,i,e,n){var o=i+u(e)+(n?"_"+u(n):""),s=t[ki]&&t[ki][o];if(!s)return this;bt&&0===i.indexOf("touch")?function(t,i,e){var n=t["_leaflet_"+i+e];"touchstart"===i?t.removeEventListener(At,n,!1):"touchmove"===i?t.removeEventListener(It,n,!1):"touchend"===i&&(t.removeEventListener(Ot,n,!1),t.removeEventListener(Rt,n,!1))}(t,i,o):!Tt||"dblclick"!==i||bt&<?"removeEventListener"in t?"mousewheel"===i?t.removeEventListener("onwheel"in t?"wheel":"mousewheel",s,!1):t.removeEventListener("mouseenter"===i?"mouseover":"mouseleave"===i?"mouseout":i,s,!1):"detachEvent"in t&&t.detachEvent("on"+i,s):Jt(t,o),t[ki][o]=null}function Oi(t){return t.stopPropagation?t.stopPropagation():t.originalEvent?t.originalEvent._stopped=!0:t.cancelBubble=!0,Gi(t),this}function Ri(t){return Ai(t,"mousewheel",Oi),this}function Ni(t){return Ei(t,"mousedown touchstart dblclick",Oi),Ai(t,"click",qi),this}function Di(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this}function ji(t){return Di(t),Oi(t),this}function Wi(t,i){if(!i)return new B(t.clientX,t.clientY);var e=Si(i),n=e.boundingClientRect;return new B((t.clientX-n.left)/e.x-i.clientLeft,(t.clientY-n.top)/e.y-i.clientTop)}var Hi=mt&<?2*window.devicePixelRatio:ct?window.devicePixelRatio:1;function Fi(t){return nt?t.wheelDeltaY/2:t.deltaY&&0===t.deltaMode?-t.deltaY/Hi:t.deltaY&&1===t.deltaMode?20*-t.deltaY:t.deltaY&&2===t.deltaMode?60*-t.deltaY:t.deltaX||t.deltaZ?0:t.wheelDelta?(t.wheelDeltaY||t.wheelDelta)/2:t.detail&&Math.abs(t.detail)<32765?20*-t.detail:t.detail?t.detail/-32765*60:0}var Ui,Vi={};function qi(t){Vi[t.type]=!0}function Gi(t){var i=Vi[t.type];return Vi[t.type]=!1,i}function Ki(t,i){var e=i.relatedTarget;if(!e)return!0;try{for(;e&&e!==t;)e=e.parentNode}catch(t){return!1}return e!==t}var Yi=(Object.freeze||Object)({on:Ei,off:Bi,stopPropagation:Oi,disableScrollPropagation:Ri,disableClickPropagation:Ni,preventDefault:Di,stop:ji,getMousePosition:Wi,getWheelDelta:Fi,fakeStop:qi,skipped:Gi,isExternalTarget:Ki,addListener:Ei,removeListener:Bi}),Xi=k.extend({run:function(t,i,e,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=e||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=Pi(t),this._offset=i.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=M(this._animate,this),this._step()},_step:function(t){var i=+new Date-this._startTime,e=1e3*this._duration;i<e?this._runFrame(this._easeOut(i/e),t):(this._runFrame(1),this._complete())},_runFrame:function(t,i){var e=this._startPos.add(this._offset.multiplyBy(t));i&&e._round(),wi(this._el,e),this.fire("step")},_complete:function(){C(this._animId),this._inProgress=!1,this.fire("end")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),Ji=k.extend({options:{crs:X,center:void 0,zoom:void 0,minZoom:void 0,maxZoom:void 0,layers:[],maxBounds:void 0,renderer:void 0,zoomAnimation:!0,zoomAnimationThreshold:4,fadeAnimation:!0,markerZoomAnimation:!0,transform3DLimit:8388608,zoomSnap:1,zoomDelta:1,trackResize:!0},initialize:function(t,i){i=p(this,i),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._sizeChanged=!0,this._initContainer(t),this._initLayout(),this._onResize=a(this._onResize,this),this._initEvents(),i.maxBounds&&this.setMaxBounds(i.maxBounds),void 0!==i.zoom&&(this._zoom=this._limitZoom(i.zoom)),i.center&&void 0!==i.zoom&&this.setView(W(i.center),i.zoom,{reset:!0}),this.callInitHooks(),this._zoomAnimated=oi&&yt&&!zt&&this.options.zoomAnimation,this._zoomAnimated&&(this._createAnimProxy(),Ei(this._proxy,si,this._catchTransitionEnd,this)),this._addLayers(this.options.layers)},setView:function(t,i,e){if((i=void 0===i?this._zoom:this._limitZoom(i),t=this._limitCenter(W(t),i,this.options.maxBounds),e=e||{},this._stop(),this._loaded&&!e.reset&&!0!==e)&&(void 0!==e.animate&&(e.zoom=h({animate:e.animate},e.zoom),e.pan=h({animate:e.animate,duration:e.duration},e.pan)),this._zoom!==i?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,i,e.zoom):this._tryAnimatedPan(t,e.pan)))return clearTimeout(this._sizeTimer),this;return this._resetView(t,i),this},setZoom:function(t,i){return this._loaded?this.setView(this.getCenter(),t,{zoom:i}):(this._zoom=t,this)},zoomIn:function(t,i){return t=t||(yt?this.options.zoomDelta:1),this.setZoom(this._zoom+t,i)},zoomOut:function(t,i){return t=t||(yt?this.options.zoomDelta:1),this.setZoom(this._zoom-t,i)},setZoomAround:function(t,i,e){var n=this.getZoomScale(i),o=this.getSize().divideBy(2),s=(t instanceof B?t:this.latLngToContainerPoint(t)).subtract(o).multiplyBy(1-1/n),r=this.containerPointToLatLng(o.add(s));return this.setView(r,i,{zoom:e})},_getBoundsCenterZoom:function(t,i){i=i||{},t=t.getBounds?t.getBounds():D(t);var e=I(i.paddingTopLeft||i.padding||[0,0]),n=I(i.paddingBottomRight||i.padding||[0,0]),o=this.getBoundsZoom(t,!1,e.add(n));if((o="number"==typeof i.maxZoom?Math.min(i.maxZoom,o):o)===1/0)return{center:t.getCenter(),zoom:o};var s=n.subtract(e).divideBy(2),r=this.project(t.getSouthWest(),o),a=this.project(t.getNorthEast(),o);return{center:this.unproject(r.add(a).divideBy(2).add(s),o),zoom:o}},fitBounds:function(t,i){if(!(t=D(t)).isValid())throw new Error("Bounds are not valid.");var e=this._getBoundsCenterZoom(t,i);return this.setView(e.center,e.zoom,i)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,i){return this.setView(t,this._zoom,{pan:i})},panBy:function(t,i){if(i=i||{},!(t=I(t).round()).x&&!t.y)return this.fire("moveend");if(!0!==i.animate&&!this.getSize().contains(t))return this._resetView(this.unproject(this.project(this.getCenter()).add(t)),this.getZoom()),this;if(this._panAnim||(this._panAnim=new Xi,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),i.noMoveStart||this.fire("movestart"),!1!==i.animate){pi(this._mapPane,"leaflet-pan-anim");var e=this._getMapPanePos().subtract(t).round();this._panAnim.run(this._mapPane,e,i.duration||.25,i.easeLinearity)}else this._rawPanBy(t),this.fire("move").fire("moveend");return this},flyTo:function(n,o,t){if(!1===(t=t||{}).animate||!yt)return this.setView(n,o,t);this._stop();var s=this.project(this.getCenter()),r=this.project(n),i=this.getSize(),a=this._zoom;n=W(n),o=void 0===o?a:o;var h=Math.max(i.x,i.y),u=h*this.getZoomScale(a,o),l=r.distanceTo(s)||1,c=1.42,_=c*c;function e(t){var i=(u*u-h*h+(t?-1:1)*_*_*l*l)/(2*(t?u:h)*_*l),e=Math.sqrt(i*i+1)-i;return e<1e-9?-18:Math.log(e)}function d(t){return(Math.exp(t)-Math.exp(-t))/2}function p(t){return(Math.exp(t)+Math.exp(-t))/2}var m=e(0);function f(t){return h*(p(m)*function(t){return d(t)/p(t)}(m+c*t)-d(m))/_}var g=Date.now(),v=(e(1)-m)/c,y=t.duration?1e3*t.duration:1e3*v*.8;return this._moveStart(!0,t.noMoveStart),function t(){var i=(Date.now()-g)/y,e=function(t){return 1-Math.pow(1-t,1.5)}(i)*v;i<=1?(this._flyToFrame=M(t,this),this._move(this.unproject(s.add(r.subtract(s).multiplyBy(f(e)/l)),a),this.getScaleZoom(h/function(t){return h*(p(m)/p(m+c*t))}(e),a),{flyTo:!0})):this._move(n,o)._moveEnd(!0)}.call(this),this},flyToBounds:function(t,i){var e=this._getBoundsCenterZoom(t,i);return this.flyTo(e.center,e.zoom,i)},setMaxBounds:function(t){return(t=D(t)).isValid()?(this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this.options.maxBounds=t,this._loaded&&this._panInsideMaxBounds(),this.on("moveend",this._panInsideMaxBounds)):(this.options.maxBounds=null,this.off("moveend",this._panInsideMaxBounds))},setMinZoom:function(t){var i=this.options.minZoom;return this.options.minZoom=t,this._loaded&&i!==t&&(this.fire("zoomlevelschange"),this.getZoom()<this.options.minZoom)?this.setZoom(t):this},setMaxZoom:function(t){var i=this.options.maxZoom;return this.options.maxZoom=t,this._loaded&&i!==t&&(this.fire("zoomlevelschange"),this.getZoom()>this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,D(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e=I((i=i||{}).paddingTopLeft||i.padding||[0,0]),n=I(i.paddingBottomRight||i.padding||[0,0]),o=this.getCenter(),s=this.project(o),r=this.project(t),a=this.getPixelBounds(),h=a.getSize().divideBy(2),u=R([a.min.add(e),a.max.subtract(n)]);if(!u.contains(r)){this._enforcingBounds=!0;var l=s.subtract(r),c=I(r.x+l.x,r.y+l.y);(r.x<u.min.x||r.x>u.max.x)&&(c.x=s.x-l.x,0<l.x?c.x+=h.x-e.x:c.x-=h.x-n.x),(r.y<u.min.y||r.y>u.max.y)&&(c.y=s.y-l.y,0<l.y?c.y+=h.y-e.y:c.y-=h.y-n.y),this.panTo(this.unproject(c),i),this._enforcingBounds=!1}return this},invalidateSize:function(t){if(!this._loaded)return this;t=h({animate:!1,pan:!0},!0===t?{animate:!0}:t);var i=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var e=this.getSize(),n=i.divideBy(2).round(),o=e.divideBy(2).round(),s=n.subtract(o);return s.x||s.y?(t.animate&&t.pan?this.panBy(s):(t.pan&&this._rawPanBy(s),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:i,newSize:e})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=h({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var i=a(this._handleGeolocationResponse,this),e=a(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(i,e,t):navigator.geolocation.getCurrentPosition(i,e,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var i=t.code,e=t.message||(1===i?"permission denied":2===i?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:i,message:"Geolocation error: "+e+"."})},_handleGeolocationResponse:function(t){var i=new j(t.coords.latitude,t.coords.longitude),e=i.toBounds(2*t.coords.accuracy),n=this._locateOptions;if(n.setView){var o=this.getBoundsZoom(e);this.setView(i,n.maxZoom?Math.min(o,n.maxZoom):o)}var s={latlng:i,bounds:e,timestamp:t.timestamp};for(var r in t.coords)"number"==typeof t.coords[r]&&(s[r]=t.coords[r]);this.fire("locationfound",s)},addHandler:function(t,i){if(!i)return this;var e=this[t]=new i(this);return this._handlers.push(e),this.options[t]&&e.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}var t;for(t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),ui(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(C(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)ui(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,i){var e=hi("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),i||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new N(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,i,e){t=D(t),e=I(e||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),a=t.getSouthEast(),h=this.getSize().subtract(e),u=R(this.project(a,n),this.project(r,n)).getSize(),l=yt?this.options.zoomSnap:1,c=h.x/u.x,_=h.y/u.y,d=i?Math.max(c,_):Math.min(c,_);return n=this.getScaleZoom(d,n),l&&(n=Math.round(n/(l/100))*(l/100),n=i?Math.ceil(n/l)*l:Math.floor(n/l)*l),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new B(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,i){var e=this._getTopLeftPoint(t,i);return new O(e,e.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,i){var e=this.options.crs;return i=void 0===i?this._zoom:i,e.scale(t)/e.scale(i)},getScaleZoom:function(t,i){var e=this.options.crs;i=void 0===i?this._zoom:i;var n=e.zoom(t*e.scale(i));return isNaN(n)?1/0:n},project:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.latLngToPoint(W(t),i)},unproject:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.pointToLatLng(I(t),i)},layerPointToLatLng:function(t){var i=I(t).add(this.getPixelOrigin());return this.unproject(i)},latLngToLayerPoint:function(t){return this.project(W(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(W(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(D(t))},distance:function(t,i){return this.options.crs.distance(W(t),W(i))},containerPointToLayerPoint:function(t){return I(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return I(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var i=this.containerPointToLayerPoint(I(t));return this.layerPointToLatLng(i)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(W(t)))},mouseEventToContainerPoint:function(t){return Wi(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var i=this._container=ri(t);if(!i)throw new Error("Map container not found.");if(i._leaflet_id)throw new Error("Map container is already initialized.");Ei(i,"scroll",this._onScroll,this),this._containerId=u(i)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&yt,pi(t,"leaflet-container"+(Tt?" leaflet-touch":"")+(Ct?" leaflet-retina":"")+(et?" leaflet-oldie":"")+(_t?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var i=ai(t,"position");"absolute"!==i&&"relative"!==i&&"fixed"!==i&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),wi(this._mapPane,new B(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(pi(t.markerPane,"leaflet-zoom-hide"),pi(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,i){wi(this._mapPane,new B(0,0));var e=!this._loaded;this._loaded=!0,i=this._limitZoom(i),this.fire("viewprereset");var n=this._zoom!==i;this._moveStart(n,!1)._move(t,i)._moveEnd(n),this.fire("viewreset"),e&&this.fire("load")},_moveStart:function(t,i){return t&&this.fire("zoomstart"),i||this.fire("movestart"),this},_move:function(t,i,e){void 0===i&&(i=this._zoom);var n=this._zoom!==i;return this._zoom=i,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(n||e&&e.pinch)&&this.fire("zoom",e),this.fire("move",e)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return C(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){wi(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var i=t?Bi:Ei;i((this._targets[u(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&i(window,"resize",this._onResize,this),yt&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){C(this._resizeRequest),this._resizeRequest=M(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[u(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Ki(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Ki(s,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!Gi(t)){var i=t.type;"mousedown"!==i&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||zi(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){if("click"===t.type){var n=h({},t);n.type="preclick",this._fireDOMEvent(n,n.type,e)}if(!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Di(t);var s={originalEvent:t};if("keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type){var r=o.getLatLng&&(!o._radius||o._radius<=10);s.containerPoint=r?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),s.layerPoint=this.containerPointToLayerPoint(s.containerPoint),s.latlng=r?o.getLatLng():this.layerPointToLatLng(s.layerPoint)}for(var a=0;a<e.length;a++)if(e[a].fire(i,s,!0),s.originalEvent._stopped||!1===e[a].options.bubblingMouseEvents&&-1!==y(this._mouseEvents,i))return}},_draggableMoved:function(t){return(t=t.dragging&&t.dragging.enabled()?t:this).dragging&&t.dragging.moved()||this.boxZoom&&this.boxZoom.moved()},_clearHandlers:function(){for(var t=0,i=this._handlers.length;t<i;t++)this._handlers[t].disable()},whenReady:function(t,i){return this._loaded?t.call(i||this,{target:this}):this.on("load",t,i),this},_getMapPanePos:function(){return Pi(this._mapPane)||new B(0,0)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(t,i){return(t&&void 0!==i?this._getNewPixelOrigin(t,i):this.getPixelOrigin()).subtract(this._getMapPanePos())},_getNewPixelOrigin:function(t,i){var e=this.getSize()._divideBy(2);return this.project(t,i)._subtract(e)._add(this._getMapPanePos())._round()},_latLngToNewLayerPoint:function(t,i,e){var n=this._getNewPixelOrigin(e,i);return this.project(t,i)._subtract(n)},_latLngBoundsToNewLayerBounds:function(t,i,e){var n=this._getNewPixelOrigin(e,i);return R([this.project(t.getSouthWest(),i)._subtract(n),this.project(t.getNorthWest(),i)._subtract(n),this.project(t.getSouthEast(),i)._subtract(n),this.project(t.getNorthEast(),i)._subtract(n)])},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitCenter:function(t,i,e){if(!e)return t;var n=this.project(t,i),o=this.getSize().divideBy(2),s=new O(n.subtract(o),n.add(o)),r=this._getBoundsOffset(s,e,i);return r.round().equals([0,0])?t:this.unproject(n.add(r),i)},_limitOffset:function(t,i){if(!i)return t;var e=this.getPixelBounds(),n=new O(e.min.add(t),e.max.add(t));return t.add(this._getBoundsOffset(n,i))},_getBoundsOffset:function(t,i,e){var n=R(this.project(i.getNorthEast(),e),this.project(i.getSouthWest(),e)),o=n.min.subtract(t.min),s=n.max.subtract(t.max);return new B(this._rebound(o.x,-s.x),this._rebound(o.y,-s.y))},_rebound:function(t,i){return 0<t+i?Math.round(t-i)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(i))},_limitZoom:function(t){var i=this.getMinZoom(),e=this.getMaxZoom(),n=yt?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(i,Math.min(e,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){mi(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,i){var e=this._getCenterOffset(t)._trunc();return!(!0!==(i&&i.animate)&&!this.getSize().contains(e))&&(this.panBy(e,i),!0)},_createAnimProxy:function(){var t=this._proxy=hi("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(t){var i=ni,e=this._proxy.style[i];xi(this._proxy,this.project(t.center,t.zoom),this.getZoomScale(t.zoom,1)),e===this._proxy.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var t=this.getCenter(),i=this.getZoom();xi(this._proxy,this.project(t,i),this.getZoomScale(i,1))},this),this._on("unload",this._destroyAnimProxy,this)},_destroyAnimProxy:function(){ui(this._proxy),delete this._proxy},_catchTransitionEnd:function(t){this._animatingZoom&&0<=t.propertyName.indexOf("transform")&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,i,e){if(this._animatingZoom)return!0;if(e=e||{},!this._zoomAnimated||!1===e.animate||this._nothingToAnimate()||Math.abs(i-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,pi(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&mi(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function $i(t){return new Qi(t)}var Qi=Z.extend({options:{position:"topright"},initialize:function(t){p(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return pi(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ui(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0<t.screenX&&0<t.screenY&&this._map.getContainer().focus()}});Ji.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){var n=this._controlCorners={},o="leaflet-",s=this._controlContainer=hi("div",o+"control-container",this._container);function t(t,i){var e=o+t+" "+o+i;n[t+i]=hi("div",e,s)}t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){for(var t in this._controlCorners)ui(this._controlCorners[t]);ui(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var te=Qi.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,i,e,n){return e<n?-1:n<e?1:0}},initialize:function(t,i,e){for(var n in p(this,e),this._layerControlInputs=[],this._layers=[],this._lastZIndex=0,this._handlingClick=!1,t)this._addLayer(t[n],n);for(n in i)this._addLayer(i[n],n,!0)},onAdd:function(t){this._initLayout(),this._update(),(this._map=t).on("zoomend",this._checkDisabledLayers,this);for(var i=0;i<this._layers.length;i++)this._layers[i].layer.on("add remove",this._onLayerChange,this);return this._container},addTo:function(t){return Qi.prototype.addTo.call(this,t),this._expandIfNotCollapsed()},onRemove:function(){this._map.off("zoomend",this._checkDisabledLayers,this);for(var t=0;t<this._layers.length;t++)this._layers[t].layer.off("add remove",this._onLayerChange,this)},addBaseLayer:function(t,i){return this._addLayer(t,i),this._map?this._update():this},addOverlay:function(t,i){return this._addLayer(t,i,!0),this._map?this._update():this},removeLayer:function(t){t.off("add remove",this._onLayerChange,this);var i=this._getLayer(u(t));return i&&this._layers.splice(this._layers.indexOf(i),1),this._map?this._update():this},expand:function(){pi(this._container,"leaflet-control-layers-expanded"),this._section.style.height=null;var t=this._map.getSize().y-(this._container.offsetTop+50);return t<this._section.clientHeight?(pi(this._section,"leaflet-control-layers-scrollbar"),this._section.style.height=t+"px"):mi(this._section,"leaflet-control-layers-scrollbar"),this._checkDisabledLayers(),this},collapse:function(){return mi(this._container,"leaflet-control-layers-expanded"),this},_initLayout:function(){var t="leaflet-control-layers",i=this._container=hi("div",t),e=this.options.collapsed;i.setAttribute("aria-haspopup",!0),Ni(i),Ri(i);var n=this._section=hi("section",t+"-list");e&&(this._map.on("click",this.collapse,this),st||Ei(i,{mouseenter:this.expand,mouseleave:this.collapse},this));var o=this._layersLink=hi("a",t+"-toggle",i);o.href="#",o.title="Layers",Tt?(Ei(o,"click",ji),Ei(o,"click",this.expand,this)):Ei(o,"focus",this.expand,this),e||this.expand(),this._baseLayersList=hi("div",t+"-base",n),this._separator=hi("div",t+"-separator",n),this._overlaysList=hi("div",t+"-overlays",n),i.appendChild(n)},_getLayer:function(t){for(var i=0;i<this._layers.length;i++)if(this._layers[i]&&u(this._layers[i].layer)===t)return this._layers[i]},_addLayer:function(t,i,e){this._map&&t.on("add remove",this._onLayerChange,this),this._layers.push({layer:t,name:i,overlay:e}),this.options.sortLayers&&this._layers.sort(a(function(t,i){return this.options.sortFunction(t.layer,i.layer,t.name,i.name)},this)),this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex)),this._expandIfNotCollapsed()},_update:function(){if(!this._container)return this;li(this._baseLayersList),li(this._overlaysList),this._layerControlInputs=[];var t,i,e,n,o=0;for(e=0;e<this._layers.length;e++)n=this._layers[e],this._addItem(n),i=i||n.overlay,t=t||!n.overlay,o+=n.overlay?0:1;return this.options.hideSingleBase&&(t=t&&1<o,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=i&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var i=this._getLayer(u(t.target)),e=i.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;e&&this._map.fire(e,i)},_createRadioElement:function(t,i){var e='<input type="radio" class="leaflet-control-layers-selector" name="'+t+'"'+(i?' checked="checked"':"")+"/>",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+u(this),n),this._layerControlInputs.push(i),i.layerId=u(t.layer),Ei(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;s<o.length;s++)this._map.hasLayer(o[s])&&this._map.removeLayer(o[s]);for(s=0;s<n.length;s++)this._map.hasLayer(n[s])||this._map.addLayer(n[s]);this._handlingClick=!1,this._refocusOnMap()},_checkDisabledLayers:function(){for(var t,i,e=this._layerControlInputs,n=this._map.getZoom(),o=e.length-1;0<=o;o--)t=e[o],i=this._getLayer(t.layerId).layer,t.disabled=void 0!==i.options.minZoom&&n<i.options.minZoom||void 0!==i.options.maxZoom&&n>i.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),ie=Qi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=hi("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoom<this._map.getMaxZoom()&&this._map.zoomIn(this._map.options.zoomDelta*(t.shiftKey?3:1))},_zoomOut:function(t){!this._disabled&&this._map._zoom>this._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=hi("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Ni(s),Ei(s,"click",ji),Ei(s,"click",o,this),Ei(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";mi(this._zoomInButton,i),mi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||pi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||pi(this._zoomInButton,i)}});Ji.mergeOptions({zoomControl:!0}),Ji.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new ie,this.addControl(this.zoomControl))});var ee=Qi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=hi("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=hi("div",i,e)),t.imperial&&(this._iScale=hi("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280<o?(i=o/5280,e=this._getRoundNum(i),this._updateScale(this._iScale,e+" mi",e/i)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,i,e){t.style.width=Math.round(this.options.maxWidth*e)+"px",t.innerHTML=i},_getRoundNum:function(t){var i=Math.pow(10,(Math.floor(t)+"").length-1),e=t/i;return i*(e=10<=e?10:5<=e?5:3<=e?3:2<=e?2:1)}}),ne=Qi.extend({options:{position:"bottomright",prefix:'<a href="https://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'},initialize:function(t){p(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=hi("div","leaflet-control-attribution"),Ni(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ji.mergeOptions({attributionControl:!0}),Ji.addInitHook(function(){this.options.attributionControl&&(new ne).addTo(this)});Qi.Layers=te,Qi.Zoom=ie,Qi.Scale=ee,Qi.Attribution=ne,$i.layers=function(t,i,e){return new te(t,i,e)},$i.zoom=function(t){return new ie(t)},$i.scale=function(t){return new ee(t)},$i.attribution=function(t){return new ne(t)};var oe=Z.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});oe.addTo=function(t,i){return t.addHandler(i,this),this};var se,re={Events:E},ae=Tt?"touchstart mousedown":"mousedown",he={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},ue={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},le=k.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){p(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(Ei(this._dragStartTarget,ae,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(le._dragging===this&&this.finishDrag(),Bi(this._dragStartTarget,ae,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!di(this._element,"leaflet-zoom-anim")&&!(le._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((le._dragging=this)._preventOutline&&zi(this._element),bi(),$t(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t,e=Ci(this._element);this._startPoint=new B(i.clientX,i.clientY),this._parentScale=Si(e),Ei(document,ue[t.type],this._onMove,this),Ei(document,he[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled)if(t.touches&&1<t.touches.length)this._moved=!0;else{var i=t.touches&&1===t.touches.length?t.touches[0]:t,e=new B(i.clientX,i.clientY)._subtract(this._startPoint);(e.x||e.y)&&(Math.abs(e.x)+Math.abs(e.y)<this.options.clickTolerance||(e.x/=this._parentScale.x,e.y/=this._parentScale.y,Di(t),this._moved||(this.fire("dragstart"),this._moved=!0,this._startPos=Pi(this._element).subtract(e),pi(document.body,"leaflet-dragging"),this._lastTarget=t.target||t.srcElement,window.SVGElementInstance&&this._lastTarget instanceof SVGElementInstance&&(this._lastTarget=this._lastTarget.correspondingUseElement),pi(this._lastTarget,"leaflet-drag-target")),this._newPos=this._startPos.add(e),this._moving=!0,C(this._animRequest),this._lastEvent=t,this._animRequest=M(this._updatePosition,this,!0)))}},_updatePosition:function(){var t={originalEvent:this._lastEvent};this.fire("predrag",t),wi(this._element,this._newPos),this.fire("drag",t)},_onUp:function(t){!t._simulated&&this._enabled&&this.finishDrag()},finishDrag:function(){for(var t in mi(document.body,"leaflet-dragging"),this._lastTarget&&(mi(this._lastTarget,"leaflet-drag-target"),this._lastTarget=null),ue)Bi(document,ue[t],this._onMove,this),Bi(document,he[t],this._onUp,this);Ti(),Qt(),this._moved&&this._moving&&(C(this._animRequest),this.fire("dragend",{distance:this._newPos.distanceTo(this._startPos)})),this._moving=!1,le._dragging=!1}});function ce(t,i){if(!i||!t.length)return t.slice();var e=i*i;return t=function(t,i){var e=t.length,n=new(typeof Uint8Array!=void 0+""?Uint8Array:Array)(e);n[0]=n[e-1]=1,function t(i,e,n,o,s){var r,a,h,u=0;for(a=o+1;a<=s-1;a++)h=fe(i[a],i[o],i[s],!0),u<h&&(r=a,u=h);n<u&&(e[r]=1,t(i,e,n,o,r),t(i,e,n,r,s))}(t,n,i,0,e-1);var o,s=[];for(o=0;o<e;o++)n[o]&&s.push(t[o]);return s}(t=function(t,i){for(var e=[t[0]],n=1,o=0,s=t.length;n<s;n++)r=t[n],a=t[o],void 0,h=a.x-r.x,u=a.y-r.y,i<h*h+u*u&&(e.push(t[n]),o=n);var r,a,h,u;o<s-1&&e.push(t[s-1]);return e}(t,e),e)}function _e(t,i,e){return Math.sqrt(fe(t,i,e,!0))}function de(t,i,e,n,o){var s,r,a,h=n?se:me(t,e),u=me(i,e);for(se=u;;){if(!(h|u))return[t,i];if(h&u)return!1;a=me(r=pe(t,i,s=h||u,e,o),e),s===h?(t=r,h=a):(i=r,u=a)}}function pe(t,i,e,n,o){var s,r,a=i.x-t.x,h=i.y-t.y,u=n.min,l=n.max;return 8&e?(s=t.x+a*(l.y-t.y)/h,r=l.y):4&e?(s=t.x+a*(u.y-t.y)/h,r=u.y):2&e?(s=l.x,r=t.y+h*(l.x-t.x)/a):1&e&&(s=u.x,r=t.y+h*(u.x-t.x)/a),new B(s,r,o)}function me(t,i){var e=0;return t.x<i.min.x?e|=1:t.x>i.max.x&&(e|=2),t.y<i.min.y?e|=4:t.y>i.max.y&&(e|=8),e}function fe(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0<u&&(1<(o=((t.x-s)*a+(t.y-r)*h)/u)?(s=e.x,r=e.y):0<o&&(s+=a*o,r+=h*o)),a=t.x-s,h=t.y-r,n?a*a+h*h:new B(s,r)}function ge(t){return!v(t[0])||"object"!=typeof t[0][0]&&void 0!==t[0][0]}function ve(t){return console.warn("Deprecated use of _flat, please use L.LineUtil.isFlat instead."),ge(t)}var ye=(Object.freeze||Object)({simplify:ce,pointToSegmentDistance:_e,closestPointOnSegment:function(t,i,e){return fe(t,i,e)},clipSegment:de,_getEdgeIntersection:pe,_getBitCode:me,_sqClosestPointOnSegment:fe,isFlat:ge,_flat:ve});function xe(t,i,e){var n,o,s,r,a,h,u,l,c,_=[1,4,2,8];for(o=0,u=t.length;o<u;o++)t[o]._code=me(t[o],i);for(r=0;r<4;r++){for(l=_[r],n=[],o=0,s=(u=t.length)-1;o<u;s=o++)a=t[o],h=t[s],a._code&l?h._code&l||((c=pe(h,a,l,i,e))._code=me(c,i),n.push(c)):(h._code&l&&((c=pe(h,a,l,i,e))._code=me(c,i),n.push(c)),n.push(a));t=n}return t}var we,Pe=(Object.freeze||Object)({clipPolygon:xe}),Le={project:function(t){return new B(t.lng,t.lat)},unproject:function(t){return new j(t.y,t.x)},bounds:new O([-180,-90],[180,90])},be={R:6378137,R_MINOR:6356752.314245179,bounds:new O([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(t){var i=Math.PI/180,e=this.R,n=t.lat*i,o=this.R_MINOR/e,s=Math.sqrt(1-o*o),r=s*Math.sin(n),a=Math.tan(Math.PI/4-n/2)/Math.pow((1-r)/(1+r),s/2);return n=-e*Math.log(Math.max(a,1e-10)),new B(t.lng*i*e,n)},unproject:function(t){for(var i,e=180/Math.PI,n=this.R,o=this.R_MINOR/n,s=Math.sqrt(1-o*o),r=Math.exp(-t.y/n),a=Math.PI/2-2*Math.atan(r),h=0,u=.1;h<15&&1e-7<Math.abs(u);h++)i=s*Math.sin(a),i=Math.pow((1-i)/(1+i),s/2),a+=u=Math.PI/2-2*Math.atan(r*i)-a;return new j(a*e,t.x*e/n)}},Te=(Object.freeze||Object)({LonLat:Le,Mercator:be,SphericalMercator:q}),ze=h({},U,{code:"EPSG:3395",projection:be,transformation:(we=.5/(Math.PI*be.R),K(we,.5,-we,.5))}),Me=h({},U,{code:"EPSG:4326",projection:Le,transformation:K(1/180,1,-1/180,.5)}),Ce=h({},F,{projection:Le,transformation:K(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,i){var e=i.lng-t.lng,n=i.lat-t.lat;return Math.sqrt(e*e+n*n)},infinite:!0});F.Earth=U,F.EPSG3395=ze,F.EPSG3857=X,F.EPSG900913=J,F.EPSG4326=Me,F.Simple=Ce;var Se=k.extend({options:{pane:"overlayPane",attribution:null,bubblingMouseEvents:!0},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[u(t)]=this},removeInteractiveTarget:function(t){return delete this._map._targets[u(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var i=t.target;if(i.hasLayer(this)){if(this._map=i,this._zoomAnimated=i._zoomAnimated,this.getEvents){var e=this.getEvents();i.on(e,this),this.once("remove",function(){i.off(e,this)},this)}this.onAdd(i),this.getAttribution&&i.attributionControl&&i.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),i.fire("layeradd",{layer:this})}}});Ji.include({addLayer:function(t){if(!t._layerAdd)throw new Error("The provided object is not a Layer.");var i=u(t);return this._layers[i]||((this._layers[i]=t)._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t)),this},removeLayer:function(t){var i=u(t);return this._layers[i]&&(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[i],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null),this},hasLayer:function(t){return!!t&&u(t)in this._layers},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},_addLayers:function(t){for(var i=0,e=(t=t?v(t)?t:[t]:[]).length;i<e;i++)this.addLayer(t[i])},_addZoomLimit:function(t){!isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[u(t)]=t,this._updateZoomLevels())},_removeZoomLimit:function(t){var i=u(t);this._zoomBoundLayers[i]&&(delete this._zoomBoundLayers[i],this._updateZoomLevels())},_updateZoomLevels:function(){var t=1/0,i=-1/0,e=this._getZoomSpan();for(var n in this._zoomBoundLayers){var o=this._zoomBoundLayers[n].options;t=void 0===o.minZoom?t:Math.min(t,o.minZoom),i=void 0===o.maxZoom?i:Math.max(i,o.maxZoom)}this._layersMaxZoom=i===-1/0?void 0:i,this._layersMinZoom=t===1/0?void 0:t,e!==this._getZoomSpan()&&this.fire("zoomlevelschange"),void 0===this.options.maxZoom&&this._layersMaxZoom&&this.getZoom()>this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()<this._layersMinZoom&&this.setZoom(this._layersMinZoom)}});var Ze=Se.extend({initialize:function(t,i){var e,n;if(p(this,i),this._layers={},t)for(e=0,n=t.length;e<n;e++)this.addLayer(t[e])},addLayer:function(t){var i=this.getLayerId(t);return this._layers[i]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var i=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[i]&&this._map.removeLayer(this._layers[i]),delete this._layers[i],this},hasLayer:function(t){return!!t&&(t in this._layers||this.getLayerId(t)in this._layers)},clearLayers:function(){return this.eachLayer(this.removeLayer,this)},invoke:function(t){var i,e,n=Array.prototype.slice.call(arguments,1);for(i in this._layers)(e=this._layers[i])[t]&&e[t].apply(e,n);return this},onAdd:function(t){this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t)},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];return this.eachLayer(t.push,t),t},setZIndex:function(t){return this.invoke("setZIndex",t)},getLayerId:function(t){return u(t)}}),Ee=Ze.extend({addLayer:function(t){return this.hasLayer(t)?this:(t.addEventParent(this),Ze.prototype.addLayer.call(this,t),this.fire("layeradd",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.removeEventParent(this),Ze.prototype.removeLayer.call(this,t),this.fire("layerremove",{layer:t})):this},setStyle:function(t){return this.invoke("setStyle",t)},bringToFront:function(){return this.invoke("bringToFront")},bringToBack:function(){return this.invoke("bringToBack")},getBounds:function(){var t=new N;for(var i in this._layers){var e=this._layers[i];t.extend(e.getBounds?e.getBounds():e.getLatLng())}return t}}),ke=Z.extend({options:{popupAnchor:[0,0],tooltipAnchor:[0,0]},initialize:function(t){p(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,i){var e=this._getIconUrl(t);if(!e){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(e,i&&"IMG"===i.tagName?i:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,i){var e=this.options,n=e[i+"Size"];"number"==typeof n&&(n=[n,n]);var o=I(n),s=I("shadow"===i&&e.shadowAnchor||e.iconAnchor||o&&o.divideBy(2,!0));t.className="leaflet-marker-"+i+" "+(e.className||""),s&&(t.style.marginLeft=-s.x+"px",t.style.marginTop=-s.y+"px"),o&&(t.style.width=o.x+"px",t.style.height=o.y+"px")},_createImg:function(t,i){return(i=i||document.createElement("img")).src=t,i},_getIconUrl:function(t){return Ct&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}});var Be=ke.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return Be.imagePath||(Be.imagePath=this._detectIconPath()),(this.options.imagePath||Be.imagePath)+ke.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=hi("div","leaflet-default-icon-path",document.body),i=ai(t,"background-image")||ai(t,"backgroundImage");return document.body.removeChild(t),i=null===i||0!==i.indexOf("url")?"":i.replace(/^url\(["']?/,"").replace(/marker-icon\.png["']?\)$/,"")}}),Ae=oe.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new le(t,t,!0)),this._draggable.on({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).enable(),pi(t,"leaflet-marker-draggable")},removeHooks:function(){this._draggable.off({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).disable(),this._marker._icon&&mi(this._marker._icon,"leaflet-marker-draggable")},moved:function(){return this._draggable&&this._draggable._moved},_adjustPan:function(t){var i=this._marker,e=i._map,n=this._marker.options.autoPanSpeed,o=this._marker.options.autoPanPadding,s=Pi(i._icon),r=e.getPixelBounds(),a=e.getPixelOrigin(),h=R(r.min._subtract(a).add(o),r.max._subtract(a).subtract(o));if(!h.contains(s)){var u=I((Math.max(h.max.x,s.x)-h.max.x)/(r.max.x-h.max.x)-(Math.min(h.min.x,s.x)-h.min.x)/(r.min.x-h.min.x),(Math.max(h.max.y,s.y)-h.max.y)/(r.max.y-h.max.y)-(Math.min(h.min.y,s.y)-h.min.y)/(r.min.y-h.min.y)).multiplyBy(n);e.panBy(u,{animate:!1}),this._draggable._newPos._add(u),this._draggable._startPos._add(u),wi(i._icon,this._draggable._newPos),this._onDrag(t),this._panRequest=M(this._adjustPan.bind(this,t))}},_onDragStart:function(){this._oldLatLng=this._marker.getLatLng(),this._marker.closePopup().fire("movestart").fire("dragstart")},_onPreDrag:function(t){this._marker.options.autoPan&&(C(this._panRequest),this._panRequest=M(this._adjustPan.bind(this,t)))},_onDrag:function(t){var i=this._marker,e=i._shadow,n=Pi(i._icon),o=i._map.layerPointToLatLng(n);e&&wi(e,n),i._latlng=o,t.latlng=o,t.oldLatLng=this._oldLatLng,i.fire("move",t).fire("drag",t)},_onDragEnd:function(t){C(this._panRequest),delete this._oldLatLng,this._marker.fire("moveend").fire("dragend",t)}}),Ie=Se.extend({options:{icon:new Be,interactive:!0,keyboard:!0,title:"",alt:"",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",shadowPane:"shadowPane",bubblingMouseEvents:!1,draggable:!1,autoPan:!1,autoPanPadding:[50,50],autoPanSpeed:10},initialize:function(t,i){p(this,i),this._latlng=W(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),delete this.dragging,this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var i=this._latlng;return this._latlng=W(t),this.update(),this.fire("move",{oldLatLng:i,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},getIcon:function(){return this.options.icon},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon&&this._map){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,i="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),e=t.icon.createIcon(this._icon),n=!1;e!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(e.title=t.title),"IMG"===e.tagName&&(e.alt=t.alt||"")),pi(e,i),t.keyboard&&(e.tabIndex="0"),this._icon=e,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var o=t.icon.createShadow(this._shadow),s=!1;o!==this._shadow&&(this._removeShadow(),s=!0),o&&(pi(o,i),o.alt=""),this._shadow=o,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),o&&s&&this.getPane(t.shadowPane).appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),ui(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&ui(this._shadow),this._shadow=null},_setPos:function(t){wi(this._icon,t),this._shadow&&wi(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(i)},_initInteraction:function(){if(this.options.interactive&&(pi(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),Ae)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new Ae(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;this._icon&&vi(this._icon,t),this._shadow&&vi(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor}});var Oe=Se.extend({options:{stroke:!0,color:"#3388ff",weight:3,opacity:1,lineCap:"round",lineJoin:"round",dashArray:null,dashOffset:null,fill:!1,fillColor:null,fillOpacity:.2,fillRule:"evenodd",interactive:!0,bubblingMouseEvents:!0},beforeAdd:function(t){this._renderer=t.getRenderer(this)},onAdd:function(){this._renderer._initPath(this),this._reset(),this._renderer._addPath(this)},onRemove:function(){this._renderer._removePath(this)},redraw:function(){return this._map&&this._renderer._updatePath(this),this},setStyle:function(t){return p(this,t),this._renderer&&(this._renderer._updateStyle(this),this.options.stroke&&t.hasOwnProperty("weight")&&this._updateBounds()),this},bringToFront:function(){return this._renderer&&this._renderer._bringToFront(this),this},bringToBack:function(){return this._renderer&&this._renderer._bringToBack(this),this},getElement:function(){return this._path},_reset:function(){this._project(),this._update()},_clickTolerance:function(){return(this.options.stroke?this.options.weight/2:0)+this._renderer.options.tolerance}}),Re=Oe.extend({options:{fill:!0,radius:10},initialize:function(t,i){p(this,i),this._latlng=W(t),this._radius=this.options.radius},setLatLng:function(t){return this._latlng=W(t),this.redraw(),this.fire("move",{latlng:this._latlng})},getLatLng:function(){return this._latlng},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()},getRadius:function(){return this._radius},setStyle:function(t){var i=t&&t.radius||this._radius;return Oe.prototype.setStyle.call(this,t),this.setRadius(i),this},_project:function(){this._point=this._map.latLngToLayerPoint(this._latlng),this._updateBounds()},_updateBounds:function(){var t=this._radius,i=this._radiusY||t,e=this._clickTolerance(),n=[t+e,i+e];this._pxBounds=new O(this._point.subtract(n),this._point.add(n))},_update:function(){this._map&&this._updatePath()},_updatePath:function(){this._renderer._updateCircle(this)},_empty:function(){return this._radius&&!this._renderer._bounds.intersects(this._pxBounds)},_containsPoint:function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()}});var Ne=Re.extend({initialize:function(t,i,e){if("number"==typeof i&&(i=h({},e,{radius:i})),p(this,i),this._latlng=W(t),isNaN(this.options.radius))throw new Error("Circle radius cannot be NaN");this._mRadius=this.options.radius},setRadius:function(t){return this._mRadius=t,this.redraw()},getRadius:function(){return this._mRadius},getBounds:function(){var t=[this._radius,this._radiusY||this._radius];return new N(this._map.layerPointToLatLng(this._point.subtract(t)),this._map.layerPointToLatLng(this._point.add(t)))},setStyle:Oe.prototype.setStyle,_project:function(){var t=this._latlng.lng,i=this._latlng.lat,e=this._map,n=e.options.crs;if(n.distance===U.distance){var o=Math.PI/180,s=this._mRadius/U.R/o,r=e.project([i+s,t]),a=e.project([i-s,t]),h=r.add(a).divideBy(2),u=e.unproject(h).lat,l=Math.acos((Math.cos(s*o)-Math.sin(i*o)*Math.sin(u*o))/(Math.cos(i*o)*Math.cos(u*o)))/o;!isNaN(l)&&0!==l||(l=s/Math.cos(Math.PI/180*i)),this._point=h.subtract(e.getPixelOrigin()),this._radius=isNaN(l)?0:h.x-e.project([u,t-l]).x,this._radiusY=h.y-r.y}else{var c=n.unproject(n.project(this._latlng).subtract([this._mRadius,0]));this._point=e.latLngToLayerPoint(this._latlng),this._radius=this._point.x-e.latLngToLayerPoint(c).x}this._updateBounds()}});var De=Oe.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,i){p(this,i),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var i,e,n=1/0,o=null,s=fe,r=0,a=this._parts.length;r<a;r++)for(var h=this._parts[r],u=1,l=h.length;u<l;u++){var c=s(t,i=h[u-1],e=h[u],!0);c<n&&(n=c,o=s(t,i,e))}return o&&(o.distance=Math.sqrt(n)),o},getCenter:function(){if(!this._map)throw new Error("Must add layer to map before using getCenter()");var t,i,e,n,o,s,r,a=this._rings[0],h=a.length;if(!h)return null;for(i=t=0;t<h-1;t++)i+=a[t].distanceTo(a[t+1])/2;if(0===i)return this._map.layerPointToLatLng(a[0]);for(n=t=0;t<h-1;t++)if(o=a[t],s=a[t+1],i<(n+=e=o.distanceTo(s)))return r=(n-i)/e,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,i){return i=i||this._defaultShape(),t=W(t),i.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new N,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return ge(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var i=[],e=ge(t),n=0,o=t.length;n<o;n++)e?(i[n]=W(t[n]),this._bounds.extend(i[n])):i[n]=this._convertLatLngs(t[n]);return i},_project:function(){var t=new O;this._rings=[],this._projectLatlngs(this._latlngs,this._rings,t),this._bounds.isValid()&&t.isValid()&&(this._rawPxBounds=t,this._updateBounds())},_updateBounds:function(){var t=this._clickTolerance(),i=new B(t,t);this._pxBounds=new O([this._rawPxBounds.min.subtract(i),this._rawPxBounds.max.add(i)])},_projectLatlngs:function(t,i,e){var n,o,s=t[0]instanceof j,r=t.length;if(s){for(o=[],n=0;n<r;n++)o[n]=this._map.latLngToLayerPoint(t[n]),e.extend(o[n]);i.push(o)}else for(n=0;n<r;n++)this._projectLatlngs(t[n],i,e)},_clipPoints:function(){var t=this._renderer._bounds;if(this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else{var i,e,n,o,s,r,a,h=this._parts;for(n=i=0,o=this._rings.length;i<o;i++)for(e=0,s=(a=this._rings[i]).length;e<s-1;e++)(r=de(a[e],a[e+1],t,e,!0))&&(h[n]=h[n]||[],h[n].push(r[0]),r[1]===a[e+1]&&e!==s-2||(h[n].push(r[1]),n++))}},_simplifyPoints:function(){for(var t=this._parts,i=this.options.smoothFactor,e=0,n=t.length;e<n;e++)t[e]=ce(t[e],i)},_update:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),this._updatePath())},_updatePath:function(){this._renderer._updatePoly(this)},_containsPoint:function(t,i){var e,n,o,s,r,a,h=this._clickTolerance();if(!this._pxBounds||!this._pxBounds.contains(t))return!1;for(e=0,s=this._parts.length;e<s;e++)for(n=0,o=(r=(a=this._parts[e]).length)-1;n<r;o=n++)if((i||0!==n)&&_e(t,a[o],a[n])<=h)return!0;return!1}});De._flat=ve;var je=De.extend({options:{fill:!0},isEmpty:function(){return!this._latlngs.length||!this._latlngs[0].length},getCenter:function(){if(!this._map)throw new Error("Must add layer to map before using getCenter()");var t,i,e,n,o,s,r,a,h,u=this._rings[0],l=u.length;if(!l)return null;for(s=r=a=0,t=0,i=l-1;t<l;i=t++)e=u[t],n=u[i],o=e.y*n.x-n.y*e.x,r+=(e.x+n.x)*o,a+=(e.y+n.y)*o,s+=3*o;return h=0===s?u[0]:[r/s,a/s],this._map.layerPointToLatLng(h)},_convertLatLngs:function(t){var i=De.prototype._convertLatLngs.call(this,t),e=i.length;return 2<=e&&i[0]instanceof j&&i[0].equals(i[e-1])&&i.pop(),i},_setLatLngs:function(t){De.prototype._setLatLngs.call(this,t),ge(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return ge(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,i=this.options.weight,e=new B(i,i);if(t=new O(t.min.subtract(e),t.max.add(e)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else for(var n,o=0,s=this._rings.length;o<s;o++)(n=xe(this._rings[o],t,!0)).length&&this._parts.push(n)},_updatePath:function(){this._renderer._updatePoly(this,!0)},_containsPoint:function(t){var i,e,n,o,s,r,a,h,u=!1;if(!this._pxBounds||!this._pxBounds.contains(t))return!1;for(o=0,a=this._parts.length;o<a;o++)for(s=0,r=(h=(i=this._parts[o]).length)-1;s<h;r=s++)e=i[s],n=i[r],e.y>t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||De.prototype._containsPoint.call(this,t,!0)}});var We=Ee.extend({initialize:function(t,i){p(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=v(t)?t:t.features;if(o){for(i=0,e=o.length;i<e;i++)((n=o[i]).geometries||n.geometry||n.features||n.coordinates)&&this.addData(n);return this}var s=this.options;if(s.filter&&!s.filter(t))return this;var r=He(t,s);return r?(r.feature=Ke(t),r.defaultOptions=r.options,this.resetStyle(r),s.onEachFeature&&s.onEachFeature(t,r),this.addLayer(r)):this},resetStyle:function(t){return t.options=h({},t.defaultOptions),this._setLayerStyle(t,this.options.style),this},setStyle:function(i){return this.eachLayer(function(t){this._setLayerStyle(t,i)},this)},_setLayerStyle:function(t,i){t.setStyle&&("function"==typeof i&&(i=i(t.feature)),t.setStyle(i))}});function He(t,i){var e,n,o,s,r="Feature"===t.type?t.geometry:t,a=r?r.coordinates:null,h=[],u=i&&i.pointToLayer,l=i&&i.coordsToLatLng||Fe;if(!a&&!r)return null;switch(r.type){case"Point":return e=l(a),u?u(t,e):new Ie(e);case"MultiPoint":for(o=0,s=a.length;o<s;o++)e=l(a[o]),h.push(u?u(t,e):new Ie(e));return new Ee(h);case"LineString":case"MultiLineString":return n=Ue(a,"LineString"===r.type?0:1,l),new De(n,i);case"Polygon":case"MultiPolygon":return n=Ue(a,"Polygon"===r.type?1:2,l),new je(n,i);case"GeometryCollection":for(o=0,s=r.geometries.length;o<s;o++){var c=He({geometry:r.geometries[o],type:"Feature",properties:t.properties},i);c&&h.push(c)}return new Ee(h);default:throw new Error("Invalid GeoJSON object.")}}function Fe(t){return new j(t[1],t[0],t[2])}function Ue(t,i,e){for(var n,o=[],s=0,r=t.length;s<r;s++)n=i?Ue(t[s],i-1,e):(e||Fe)(t[s]),o.push(n);return o}function Ve(t,i){return i="number"==typeof i?i:6,void 0!==t.alt?[c(t.lng,i),c(t.lat,i),c(t.alt,i)]:[c(t.lng,i),c(t.lat,i)]}function qe(t,i,e,n){for(var o=[],s=0,r=t.length;s<r;s++)o.push(i?qe(t[s],i-1,e,n):Ve(t[s],n));return!i&&e&&o.push(o[0]),o}function Ge(t,i){return t.feature?h({},t.feature,{geometry:i}):Ke(i)}function Ke(t){return"Feature"===t.type||"FeatureCollection"===t.type?t:{type:"Feature",properties:{},geometry:t}}var Ye={toGeoJSON:function(t){return Ge(this,{type:"Point",coordinates:Ve(this.getLatLng(),t)})}};function Xe(t,i){return new We(t,i)}Ie.include(Ye),Ne.include(Ye),Re.include(Ye),De.include({toGeoJSON:function(t){var i=!ge(this._latlngs);return Ge(this,{type:(i?"Multi":"")+"LineString",coordinates:qe(this._latlngs,i?1:0,!1,t)})}}),je.include({toGeoJSON:function(t){var i=!ge(this._latlngs),e=i&&!ge(this._latlngs[0]),n=qe(this._latlngs,e?2:i?1:0,!0,t);return i||(n=[n]),Ge(this,{type:(e?"Multi":"")+"Polygon",coordinates:n})}}),Ze.include({toMultiPoint:function(i){var e=[];return this.eachLayer(function(t){e.push(t.toGeoJSON(i).geometry.coordinates)}),Ge(this,{type:"MultiPoint",coordinates:e})},toGeoJSON:function(n){var t=this.feature&&this.feature.geometry&&this.feature.geometry.type;if("MultiPoint"===t)return this.toMultiPoint(n);var o="GeometryCollection"===t,s=[];return this.eachLayer(function(t){if(t.toGeoJSON){var i=t.toGeoJSON(n);if(o)s.push(i.geometry);else{var e=Ke(i);"FeatureCollection"===e.type?s.push.apply(s,e.features):s.push(e)}}}),o?Ge(this,{geometries:s,type:"GeometryCollection"}):{type:"FeatureCollection",features:s}}});var Je=Xe,$e=Se.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1,errorOverlayUrl:"",zIndex:1,className:""},initialize:function(t,i,e){this._url=t,this._bounds=D(i),p(this,e)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(pi(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){ui(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&ci(this._image),this},bringToBack:function(){return this._map&&_i(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=D(t),this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t="IMG"===this._url.tagName,i=this._image=t?this._url:hi("img");pi(i,"leaflet-image-layer"),this._zoomAnimated&&pi(i,"leaflet-zoom-animated"),this.options.className&&pi(i,this.options.className),i.onselectstart=l,i.onmousemove=l,i.onload=a(this.fire,this,"load"),i.onerror=a(this._overlayOnError,this,"error"),!this.options.crossOrigin&&""!==this.options.crossOrigin||(i.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),this.options.zIndex&&this._updateZIndex(),t?this._url=i.src:(i.src=this._url,i.alt=this.options.alt)},_animateZoom:function(t){var i=this._map.getZoomScale(t.zoom),e=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;xi(this._image,e,i)},_reset:function(){var t=this._image,i=new O(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),e=i.getSize();wi(t,i.min),t.style.width=e.x+"px",t.style.height=e.y+"px"},_updateOpacity:function(){vi(this._image,this.options.opacity)},_updateZIndex:function(){this._image&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._image.style.zIndex=this.options.zIndex)},_overlayOnError:function(){this.fire("error");var t=this.options.errorOverlayUrl;t&&this._url!==t&&(this._url=t,this._image.src=t)}}),Qe=$e.extend({options:{autoplay:!0,loop:!0,keepAspectRatio:!0},_initImage:function(){var t="VIDEO"===this._url.tagName,i=this._image=t?this._url:hi("video");if(pi(i,"leaflet-image-layer"),this._zoomAnimated&&pi(i,"leaflet-zoom-animated"),i.onselectstart=l,i.onmousemove=l,i.onloadeddata=a(this.fire,this,"load"),t){for(var e=i.getElementsByTagName("source"),n=[],o=0;o<e.length;o++)n.push(e[o].src);this._url=0<e.length?n:[i.src]}else{v(this._url)||(this._url=[this._url]),!this.options.keepAspectRatio&&i.style.hasOwnProperty("objectFit")&&(i.style.objectFit="fill"),i.autoplay=!!this.options.autoplay,i.loop=!!this.options.loop;for(var s=0;s<this._url.length;s++){var r=hi("source");r.src=this._url[s],i.appendChild(r)}}}});var tn=$e.extend({_initImage:function(){var t=this._image=this._url;pi(t,"leaflet-image-layer"),this._zoomAnimated&&pi(t,"leaflet-zoom-animated"),t.onselectstart=l,t.onmousemove=l}});var en=Se.extend({options:{offset:[0,7],className:"",pane:"popupPane"},initialize:function(t,i){p(this,t),this._source=i},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&vi(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&vi(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(vi(this._container,0),this._removeTimeout=setTimeout(a(ui,void 0,this._container),200)):ui(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=W(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&ci(this._container),this},bringToBack:function(){return this._map&&_i(this._container),this},_prepareOpen:function(t,i,e){if(i instanceof Se||(e=i,i=t),i instanceof Ee)for(var n in t._layers){i=t._layers[n];break}if(!e)if(i.getCenter)e=i.getCenter();else{if(!i.getLatLng)throw new Error("Unable to get source layer LatLng.");e=i.getLatLng()}return this._source=i,this.update(),e},_updateContent:function(){if(this._content){var t=this._contentNode,i="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof i)t.innerHTML=i;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(i)}this.fire("contentupdate")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),i=I(this.options.offset),e=this._getAnchor();this._zoomAnimated?wi(this._container,t.add(e)):i=i.add(t).add(e);var n=this._containerBottom=-i.y,o=this._containerLeft=-Math.round(this._containerWidth/2)+i.x;this._container.style.bottom=n+"px",this._container.style.left=o+"px"}},_getAnchor:function(){return[0,0]}}),nn=en.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,closeOnEscapeKey:!0,className:""},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){en.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof Oe||this._source.on("preclick",Oi))},onRemove:function(t){en.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof Oe||this._source.off("preclick",Oi))},getEvents:function(){var t=en.prototype.getEvents.call(this);return(void 0!==this.options.closeOnClick?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t="leaflet-popup",i=this._container=hi("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated"),e=this._wrapper=hi("div",t+"-content-wrapper",i);if(this._contentNode=hi("div",t+"-content",e),Ni(e),Ri(this._contentNode),Ei(e,"contextmenu",Oi),this._tipContainer=hi("div",t+"-tip-container",i),this._tip=hi("div",t+"-tip",this._tipContainer),this.options.closeButton){var n=this._closeButton=hi("a",t+"-close-button",i);n.href="#close",n.innerHTML="×",Ei(n,"click",this._onCloseButtonClick,this)}},_updateLayout:function(){var t=this._contentNode,i=t.style;i.width="",i.whiteSpace="nowrap";var e=t.offsetWidth;e=Math.min(e,this.options.maxWidth),e=Math.max(e,this.options.minWidth),i.width=e+1+"px",i.whiteSpace="",i.height="";var n=t.offsetHeight,o=this.options.maxHeight,s="leaflet-popup-scrolled";o&&o<n?(i.height=o+"px",pi(t,s)):mi(t,s),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),e=this._getAnchor();wi(this._container,i.add(e))},_adjustPan:function(){if(this.options.autoPan){this._map._panAnim&&this._map._panAnim.stop();var t=this._map,i=parseInt(ai(this._container,"marginBottom"),10)||0,e=this._container.offsetHeight+i,n=this._containerWidth,o=new B(this._containerLeft,-e-this._containerBottom);o._add(Pi(this._container));var s=t.layerPointToContainerPoint(o),r=I(this.options.autoPanPadding),a=I(this.options.autoPanPaddingTopLeft||r),h=I(this.options.autoPanPaddingBottomRight||r),u=t.getSize(),l=0,c=0;s.x+n+h.x>u.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),ji(t)},_getAnchor:function(){return I(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ji.mergeOptions({closePopupOnClick:!0}),Ji.include({openPopup:function(t,i,e){return t instanceof nn||(t=new nn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Se.include({bindPopup:function(t,i){return t instanceof nn?(p(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new nn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(ji(t),i instanceof Oe?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var on=en.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){en.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){en.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=en.prototype.getEvents.call(this);return Tt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=hi("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=I(this.options.offset),u=this._getAnchor();t="top"===s?t.add(I(-r/2+h.x,-a+h.y+u.y,!0)):"bottom"===s?t.subtract(I(r/2-h.x,-h.y,!0)):"center"===s?t.subtract(I(r/2+h.x,a/2-u.y+h.y,!0)):"right"===s||"auto"===s&&o.x<n.x?(s="right",t.add(I(h.x+u.x,u.y-a/2+h.y,!0))):(s="left",t.subtract(I(r+u.x-h.x,a/2-u.y-h.y,!0))),mi(e,"leaflet-tooltip-right"),mi(e,"leaflet-tooltip-left"),mi(e,"leaflet-tooltip-top"),mi(e,"leaflet-tooltip-bottom"),pi(e,"leaflet-tooltip-"+s),wi(e,t)},_updatePosition:function(){var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(t)},setOpacity:function(t){this.options.opacity=t,this._container&&vi(this._container,t)},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(i)},_getAnchor:function(){return I(this._source&&this._source._getTooltipAnchor&&!this.options.sticky?this._source._getTooltipAnchor():[0,0])}});Ji.include({openTooltip:function(t,i,e){return t instanceof on||(t=new on(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:this.addLayer(t)},closeTooltip:function(t){return t&&this.removeLayer(t),this}}),Se.include({bindTooltip:function(t,i){return t instanceof on?(p(t,i),(this._tooltip=t)._source=this):(this._tooltip&&!i||(this._tooltip=new on(i,this)),this._tooltip.setContent(t)),this._initTooltipInteractions(),this._tooltip.options.permanent&&this._map&&this._map.hasLayer(this)&&this.openTooltip(),this},unbindTooltip:function(){return this._tooltip&&(this._initTooltipInteractions(!0),this.closeTooltip(),this._tooltip=null),this},_initTooltipInteractions:function(t){if(t||!this._tooltipHandlersAdded){var i=t?"off":"on",e={remove:this.closeTooltip,move:this._moveTooltip};this._tooltip.options.permanent?e.add=this._openTooltip:(e.mouseover=this._openTooltip,e.mouseout=this.closeTooltip,this._tooltip.options.sticky&&(e.mousemove=this._moveTooltip),Tt&&(e.click=this._openTooltip)),this[i](e),this._tooltipHandlersAdded=!t}},openTooltip:function(t,i){return this._tooltip&&this._map&&(i=this._tooltip._prepareOpen(this,t,i),this._map.openTooltip(this._tooltip,i),this._tooltip.options.interactive&&this._tooltip._container&&(pi(this._tooltip._container,"leaflet-clickable"),this.addInteractiveTarget(this._tooltip._container))),this},closeTooltip:function(){return this._tooltip&&(this._tooltip._close(),this._tooltip.options.interactive&&this._tooltip._container&&(mi(this._tooltip._container,"leaflet-clickable"),this.removeInteractiveTarget(this._tooltip._container))),this},toggleTooltip:function(t){return this._tooltip&&(this._tooltip._map?this.closeTooltip():this.openTooltip(t)),this},isTooltipOpen:function(){return this._tooltip.isOpen()},setTooltipContent:function(t){return this._tooltip&&this._tooltip.setContent(t),this},getTooltip:function(){return this._tooltip},_openTooltip:function(t){var i=t.layer||t.target;this._tooltip&&this._map&&this.openTooltip(i,this._tooltip.options.sticky?t.latlng:void 0)},_moveTooltip:function(t){var i,e,n=t.latlng;this._tooltip.options.sticky&&t.originalEvent&&(i=this._map.mouseEventToContainerPoint(t.originalEvent),e=this._map.containerPointToLayerPoint(i),n=this._map.layerPointToLatLng(e)),this._tooltip.setLatLng(n)}});var sn=ke.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:document.createElement("div"),e=this.options;if(e.html instanceof Element?(li(i),i.appendChild(e.html)):i.innerHTML=!1!==e.html?e.html:"",e.bgPos){var n=I(e.bgPos);i.style.backgroundPosition=-n.x+"px "+-n.y+"px"}return this._setIconStyles(i,"icon"),i},createShadow:function(){return null}});ke.Default=Be;var rn=Se.extend({options:{tileSize:256,opacity:1,updateWhenIdle:xt,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:void 0,maxNativeZoom:void 0,minNativeZoom:void 0,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){p(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),ui(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=void 0},bringToFront:function(){return this._map&&(ci(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(_i(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return document.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof B?t:new B(t,t)},_updateZIndex:function(){this._container&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var i,e=this.getPane().children,n=-t(-1/0,1/0),o=0,s=e.length;o<s;o++)i=e[o].style.zIndex,e[o]!==this._container&&i&&(n=t(n,+i));isFinite(n)&&(this.options.zIndex=n+t(-1,1),this._updateZIndex())},_updateOpacity:function(){if(this._map&&!et){vi(this._container,this.options.opacity);var t=+new Date,i=!1,e=!1;for(var n in this._tiles){var o=this._tiles[n];if(o.current&&o.loaded){var s=Math.min(1,(t-o.loaded)/200);vi(o.el,s),s<1?i=!0:(o.active?e=!0:this._onOpaqueTile(o),o.active=!0)}}e&&!this._noPrune&&this._pruneTiles(),i&&(C(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this))}},_onOpaqueTile:l,_initContainer:function(){this._container||(this._container=hi("div","leaflet-layer "+(this.options.className||"")),this._updateZIndex(),this.options.opacity<1&&this._updateOpacity(),this.getPane().appendChild(this._container))},_updateLevels:function(){var t=this._tileZoom,i=this.options.maxZoom;if(void 0!==t){for(var e in this._levels)this._levels[e].el.children.length||e===t?(this._levels[e].el.style.zIndex=i-Math.abs(t-e),this._onUpdateLevel(e)):(ui(this._levels[e].el),this._removeTilesAtZoom(e),this._onRemoveLevel(e),delete this._levels[e]);var n=this._levels[t],o=this._map;return n||((n=this._levels[t]={}).el=hi("div","leaflet-tile-container leaflet-zoom-animated",this._container),n.el.style.zIndex=i,n.origin=o.project(o.unproject(o.getPixelOrigin()),t).round(),n.zoom=t,this._setZoomTransform(n,o.getCenter(),o.getZoom()),n.el.offsetWidth,this._onCreateLevel(n)),this._level=n}},_onUpdateLevel:l,_onRemoveLevel:l,_onCreateLevel:l,_pruneTiles:function(){if(this._map){var t,i,e=this._map.getZoom();if(e>this.options.maxZoom||e<this.options.minZoom)this._removeAllTiles();else{for(t in this._tiles)(i=this._tiles[t]).retain=i.current;for(t in this._tiles)if((i=this._tiles[t]).current&&!i.active){var n=i.coords;this._retainParent(n.x,n.y,n.z,n.z-5)||this._retainChildren(n.x,n.y,n.z,n.z+2)}for(t in this._tiles)this._tiles[t].retain||this._removeTile(t)}}},_removeTilesAtZoom:function(t){for(var i in this._tiles)this._tiles[i].coords.z===t&&this._removeTile(i)},_removeAllTiles:function(){for(var t in this._tiles)this._removeTile(t)},_invalidateAll:function(){for(var t in this._levels)ui(this._levels[t].el),this._onRemoveLevel(t),delete this._levels[t];this._removeAllTiles(),this._tileZoom=void 0},_retainParent:function(t,i,e,n){var o=Math.floor(t/2),s=Math.floor(i/2),r=e-1,a=new B(+o,+s);a.z=+r;var h=this._tileCoordsToKey(a),u=this._tiles[h];return u&&u.active?u.retain=!0:(u&&u.loaded&&(u.retain=!0),n<r&&this._retainParent(o,s,r,n))},_retainChildren:function(t,i,e,n){for(var o=2*t;o<2*t+2;o++)for(var s=2*i;s<2*i+2;s++){var r=new B(o,s);r.z=e+1;var a=this._tileCoordsToKey(r),h=this._tiles[a];h&&h.active?h.retain=!0:(h&&h.loaded&&(h.retain=!0),e+1<n&&this._retainChildren(o,s,e+1,n))}},_resetView:function(t){var i=t&&(t.pinch||t.flyTo);this._setView(this._map.getCenter(),this._map.getZoom(),i,i)},_animateZoom:function(t){this._setView(t.center,t.zoom,!0,t.noUpdate)},_clampZoom:function(t){var i=this.options;return void 0!==i.minNativeZoom&&t<i.minNativeZoom?i.minNativeZoom:void 0!==i.maxNativeZoom&&i.maxNativeZoom<t?i.maxNativeZoom:t},_setView:function(t,i,e,n){var o=this._clampZoom(Math.round(i));(void 0!==this.options.maxZoom&&o>this.options.maxZoom||void 0!==this.options.minZoom&&o<this.options.minZoom)&&(o=void 0);var s=this.options.updateWhenZooming&&o!==this._tileZoom;n&&!s||(this._tileZoom=o,this._abortLoading&&this._abortLoading(),this._updateLevels(),this._resetGrid(),void 0!==o&&this._update(t),e||this._pruneTiles(),this._noPrune=!!e),this._setZoomTransforms(t,i)},_setZoomTransforms:function(t,i){for(var e in this._levels)this._setZoomTransform(this._levels[e],t,i)},_setZoomTransform:function(t,i,e){var n=this._map.getZoomScale(e,t.zoom),o=t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(i,e)).round();yt?xi(t.el,o,n):wi(t.el,o)},_resetGrid:function(){var t=this._map,i=t.options.crs,e=this._tileSize=this.getTileSize(),n=this._tileZoom,o=this._map.getPixelWorldBounds(this._tileZoom);o&&(this._globalTileRange=this._pxBoundsToTileRange(o)),this._wrapX=i.wrapLng&&!this.options.noWrap&&[Math.floor(t.project([0,i.wrapLng[0]],n).x/e.x),Math.ceil(t.project([0,i.wrapLng[1]],n).x/e.y)],this._wrapY=i.wrapLat&&!this.options.noWrap&&[Math.floor(t.project([i.wrapLat[0],0],n).y/e.x),Math.ceil(t.project([i.wrapLat[1],0],n).y/e.y)]},_onMoveEnd:function(){this._map&&!this._map._animatingZoom&&this._update()},_getTiledPixelBounds:function(t){var i=this._map,e=i._animatingZoom?Math.max(i._animateToZoom,i.getZoom()):i.getZoom(),n=i.getZoomScale(e,this._tileZoom),o=i.project(t,this._tileZoom).floor(),s=i.getSize().divideBy(2*n);return new O(o.subtract(s),o.add(s))},_update:function(t){var i=this._map;if(i){var e=this._clampZoom(i.getZoom());if(void 0===t&&(t=i.getCenter()),void 0!==this._tileZoom){var n=this._getTiledPixelBounds(t),o=this._pxBoundsToTileRange(n),s=o.getCenter(),r=[],a=this.options.keepBuffer,h=new O(o.getBottomLeft().subtract([a,-a]),o.getTopRight().add([a,-a]));if(!(isFinite(o.min.x)&&isFinite(o.min.y)&&isFinite(o.max.x)&&isFinite(o.max.y)))throw new Error("Attempted to load an infinite number of tiles");for(var u in this._tiles){var l=this._tiles[u].coords;l.z===this._tileZoom&&h.contains(new B(l.x,l.y))||(this._tiles[u].current=!1)}if(1<Math.abs(e-this._tileZoom))this._setView(t,e);else{for(var c=o.min.y;c<=o.max.y;c++)for(var _=o.min.x;_<=o.max.x;_++){var d=new B(_,c);if(d.z=this._tileZoom,this._isValidTile(d)){var p=this._tiles[this._tileCoordsToKey(d)];p?p.current=!0:r.push(d)}}if(r.sort(function(t,i){return t.distanceTo(s)-i.distanceTo(s)}),0!==r.length){this._loading||(this._loading=!0,this.fire("loading"));var m=document.createDocumentFragment();for(_=0;_<r.length;_++)this._addTile(r[_],m);this._level.el.appendChild(m)}}}}},_isValidTile:function(t){var i=this._map.options.crs;if(!i.infinite){var e=this._globalTileRange;if(!i.wrapLng&&(t.x<e.min.x||t.x>e.max.x)||!i.wrapLat&&(t.y<e.min.y||t.y>e.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return D(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new N(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new B(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ui(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){pi(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=l,t.onmousemove=l,et&&this.options.opacity<1&&vi(t,this.options.opacity),st&&!rt&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(a(this._tileReady,this,t,null,o)),wi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(vi(e.el,0),C(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(pi(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),et||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new B(this._wrapX?r(t.x,this._wrapX):t.x,this._wrapY?r(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new O(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var an=rn.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=p(this,i)).detectRetina&&Ct&&0<i.maxZoom&&(i.tileSize=Math.floor(i.tileSize/2),i.zoomReverse?(i.zoomOffset--,i.minZoom++):(i.zoomOffset++,i.maxZoom--),i.minZoom=Math.max(0,i.minZoom)),"string"==typeof i.subdomains&&(i.subdomains=i.subdomains.split("")),st||this.on("tileunload",this._onTileRemove)},setUrl:function(t,i){return this._url===t&&void 0===i&&(i=!0),this._url=t,i||this.redraw(),this},createTile:function(t,i){var e=document.createElement("img");return Ei(e,"load",a(this._tileOnLoad,this,i,e)),Ei(e,"error",a(this._tileOnError,this,i,e)),!this.options.crossOrigin&&""!==this.options.crossOrigin||(e.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),e.alt="",e.setAttribute("role","presentation"),e.src=this.getTileUrl(t),e},getTileUrl:function(t){var i={r:Ct?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var e=this._globalTileRange.max.y-t.y;this.options.tms&&(i.y=e),i["-y"]=e}return g(this._url,h(i,this.options))},_tileOnLoad:function(t,i){et?setTimeout(a(t,this,null,i),0):t(null,i)},_tileOnError:function(t,i,e){var n=this.options.errorTileUrl;n&&i.getAttribute("src")!==n&&(i.src=n),t(e,i)},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,i=this.options.maxZoom;return this.options.zoomReverse&&(t=i-t),t+this.options.zoomOffset},_getSubdomain:function(t){var i=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[i]},_abortLoading:function(){var t,i;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&((i=this._tiles[t].el).onload=l,i.onerror=l,i.complete||(i.src=x,ui(i),delete this._tiles[t]))},_removeTile:function(t){var i=this._tiles[t];if(i)return ht||i.el.setAttribute("src",x),rn.prototype._removeTile.call(this,t)},_tileReady:function(t,i,e){if(this._map&&(!e||e.getAttribute("src")!==x))return rn.prototype._tileReady.call(this,t,i,e)}});function hn(t,i){return new an(t,i)}var un=an.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,i){this._url=t;var e=h({},this.defaultWmsParams);for(var n in i)n in this.options||(e[n]=i[n]);var o=(i=p(this,i)).detectRetina&&Ct?2:1,s=this.getTileSize();e.width=s.x*o,e.height=s.y*o,this.wmsParams=e},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var i=1.3<=this._wmsVersion?"crs":"srs";this.wmsParams[i]=this._crs.code,an.prototype.onAdd.call(this,t)},getTileUrl:function(t){var i=this._tileCoordsToNwSe(t),e=this._crs,n=R(e.project(i[0]),e.project(i[1])),o=n.min,s=n.max,r=(1.3<=this._wmsVersion&&this._crs===Me?[o.y,o.x,s.y,s.x]:[o.x,o.y,s.x,s.y]).join(","),a=an.prototype.getTileUrl.call(this,t);return a+m(this.wmsParams,a,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+r},setParams:function(t,i){return h(this.wmsParams,t),i||this.redraw(),this}});an.WMS=un,hn.wms=function(t,i){return new un(t,i)};var ln=Se.extend({options:{padding:.1,tolerance:0},initialize:function(t){p(this,t),u(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&pi(this._container,"leaflet-zoom-animated")),this.getPane().appendChild(this._container),this._update(),this.on("update",this._updatePaths,this)},onRemove:function(){this.off("update",this._updatePaths,this),this._destroyContainer()},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,i){var e=this._map.getZoomScale(i,this._zoom),n=Pi(this._container),o=this._map.getSize().multiplyBy(.5+this.options.padding),s=this._map.project(this._center,i),r=this._map.project(t,i).subtract(s),a=o.multiplyBy(-e).add(n).add(o).subtract(r);yt?xi(this._container,a,e):wi(this._container,a)},_reset:function(){for(var t in this._update(),this._updateTransform(this._center,this._zoom),this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,i=this._map.getSize(),e=this._map.containerPointToLayerPoint(i.multiplyBy(-t)).round();this._bounds=new O(e,e.add(i.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),cn=ln.extend({getEvents:function(){var t=ln.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){ln.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=document.createElement("canvas");Ei(t,"mousemove",o(this._onMouseMove,32,this),this),Ei(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this),Ei(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_destroyContainer:function(){C(this._redrawRequest),delete this._ctx,ui(this._container),Bi(this._container),delete this._container},_updatePaths:function(){if(!this._postponeUpdatePaths){for(var t in this._redrawBounds=null,this._layers)this._layers[t]._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){ln.prototype._update.call(this);var t=this._bounds,i=this._container,e=t.getSize(),n=Ct?2:1;wi(i,t.min),i.width=n*e.x,i.height=n*e.y,i.style.width=e.x+"px",i.style.height=e.y+"px",Ct&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_reset:function(){ln.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t);var i=(this._layers[u(t)]=t)._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=i),this._drawLast=i,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var i=t._order,e=i.next,n=i.prev;e?e.prev=n:this._drawLast=n,n?n.next=e:this._drawFirst=e,delete t._order,delete this._layers[u(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if("string"==typeof t.options.dashArray){var i,e,n=t.options.dashArray.split(/[, ]+/),o=[];for(e=0;e<n.length;e++){if(i=Number(n[e]),isNaN(i))return;o.push(i)}t.options._dashArray=o}else t.options._dashArray=t.options.dashArray},_requestRedraw:function(t){this._map&&(this._extendRedrawBounds(t),this._redrawRequest=this._redrawRequest||M(this._redraw,this))},_extendRedrawBounds:function(t){if(t._pxBounds){var i=(t.options.weight||0)+1;this._redrawBounds=this._redrawBounds||new O,this._redrawBounds.extend(t._pxBounds.min.subtract([i,i])),this._redrawBounds.extend(t._pxBounds.max.add([i,i]))}},_redraw:function(){this._redrawRequest=null,this._redrawBounds&&(this._redrawBounds.min._floor(),this._redrawBounds.max._ceil()),this._clear(),this._draw(),this._redrawBounds=null},_clear:function(){var t=this._redrawBounds;if(t){var i=t.getSize();this._ctx.clearRect(t.min.x,t.min.y,i.x,i.y)}else this._ctx.clearRect(0,0,this._container.width,this._container.height)},_draw:function(){var t,i=this._redrawBounds;if(this._ctx.save(),i){var e=i.getSize();this._ctx.beginPath(),this._ctx.rect(i.min.x,i.min.y,e.x,e.y),this._ctx.clip()}this._drawing=!0;for(var n=this._drawFirst;n;n=n.next)t=n.layer,(!i||t._pxBounds&&t._pxBounds.intersects(i))&&t._updatePath();this._drawing=!1,this._ctx.restore()},_updatePoly:function(t,i){if(this._drawing){var e,n,o,s,r=t._parts,a=r.length,h=this._ctx;if(a){for(h.beginPath(),e=0;e<a;e++){for(n=0,o=r[e].length;n<o;n++)s=r[e][n],h[n?"lineTo":"moveTo"](s.x,s.y);i&&h.closePath()}this._fillStroke(h,t)}}},_updateCircle:function(t){if(this._drawing&&!t._empty()){var i=t._point,e=this._ctx,n=Math.max(Math.round(t._radius),1),o=(Math.max(Math.round(t._radiusY),1)||n)/n;1!=o&&(e.save(),e.scale(1,o)),e.beginPath(),e.arc(i.x,i.y/o,n,0,2*Math.PI,!1),1!=o&&e.restore(),this._fillStroke(e,t)}},_fillStroke:function(t,i){var e=i.options;e.fill&&(t.globalAlpha=e.fillOpacity,t.fillStyle=e.fillColor||e.color,t.fill(e.fillRule||"evenodd")),e.stroke&&0!==e.weight&&(t.setLineDash&&t.setLineDash(i.options&&i.options._dashArray||[]),t.globalAlpha=e.opacity,t.lineWidth=e.weight,t.strokeStyle=e.color,t.lineCap=e.lineCap,t.lineJoin=e.lineJoin,t.stroke())},_onClick:function(t){for(var i,e,n=this._map.mouseEventToLayerPoint(t),o=this._drawFirst;o;o=o.next)(i=o.layer).options.interactive&&i._containsPoint(n)&&!this._map._draggableMoved(i)&&(e=i);e&&(qi(t),this._fireEvent([e],t))},_onMouseMove:function(t){if(this._map&&!this._map.dragging.moving()&&!this._map._animatingZoom){var i=this._map.mouseEventToLayerPoint(t);this._handleMouseHover(t,i)}},_handleMouseOut:function(t){var i=this._hoveredLayer;i&&(mi(this._container,"leaflet-interactive"),this._fireEvent([i],t,"mouseout"),this._hoveredLayer=null)},_handleMouseHover:function(t,i){for(var e,n,o=this._drawFirst;o;o=o.next)(e=o.layer).options.interactive&&e._containsPoint(i)&&(n=e);n!==this._hoveredLayer&&(this._handleMouseOut(t),n&&(pi(this._container,"leaflet-interactive"),this._fireEvent([n],t,"mouseover"),this._hoveredLayer=n)),this._hoveredLayer&&this._fireEvent([this._hoveredLayer],t)},_fireEvent:function(t,i,e){this._map._fireDOMEvent(i,e||i.type,t)},_bringToFront:function(t){var i=t._order;if(i){var e=i.next,n=i.prev;e&&((e.prev=n)?n.next=e:e&&(this._drawFirst=e),i.prev=this._drawLast,(this._drawLast.next=i).next=null,this._drawLast=i,this._requestRedraw(t))}},_bringToBack:function(t){var i=t._order;if(i){var e=i.next,n=i.prev;n&&((n.next=e)?e.prev=n:n&&(this._drawLast=n),i.prev=null,i.next=this._drawFirst,this._drawFirst.prev=i,this._drawFirst=i,this._requestRedraw(t))}}});function _n(t){return St?new cn(t):null}var dn=function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return document.createElement("<lvml:"+t+' class="lvml">')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),pn={_initContainer:function(){this._container=hi("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(ln.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=dn("shape");pi(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=dn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ui(i),t.removeInteractiveTarget(i),delete this._layers[u(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=dn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=v(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=dn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){ci(t._container)},_bringToBack:function(t){_i(t._container)}},mn=Et?dn:$,fn=ln.extend({getEvents:function(){var t=ln.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=mn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=mn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ui(this._container),Bi(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){ln.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),wi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update")}},_initPath:function(t){var i=t._path=mn("path");t.options.className&&pi(i,t.options.className),t.options.interactive&&pi(i,"leaflet-interactive"),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ui(t._path),t.removeInteractiveTarget(t._path),delete this._layers[u(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,Q(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){ci(t._path)},_bringToBack:function(t){_i(t._path)}});function gn(t){return Zt||Et?new fn(t):null}Et&&fn.include(pn),Ji.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this._createRenderer()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&_n(t)||gn(t)}});var vn=je.extend({initialize:function(t,i){je.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=D(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});fn.create=mn,fn.pointsToPath=Q,We.geometryToLayer=He,We.coordsToLatLng=Fe,We.coordsToLatLngs=Ue,We.latLngToCoords=Ve,We.latLngsToCoords=qe,We.getFeature=Ge,We.asFeature=Ke,Ji.mergeOptions({boxZoom:!0});var yn=oe.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){Ei(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Bi(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ui(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),$t(),bi(),this._startPoint=this._map.mouseEventToContainerPoint(t),Ei(document,{contextmenu:ji,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=hi("div","leaflet-zoom-box",this._container),pi(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new O(this._point,this._startPoint),e=i.getSize();wi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ui(this._box),mi(this._container,"leaflet-crosshair")),Qt(),Ti(),Bi(document,{contextmenu:ji,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0);var i=new N(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ji.addInitHook("addHandler","boxZoom",yn),Ji.mergeOptions({doubleClickZoom:!0});var xn=oe.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ji.addInitHook("addHandler","doubleClickZoom",xn),Ji.mergeOptions({dragging:!0,inertia:!rt,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var wn=oe.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new le(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}pi(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){mi(this._map._container,"leaflet-grab"),mi(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=D(this._map.options.maxBounds);this._offsetLimit=R(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),this._prunePositions(i)}this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1<this._positions.length&&50<t-this._times[0];)this._positions.shift(),this._times.shift()},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),i=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=i.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,i){return t-(t-i)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),i=this._offsetLimit;t.x<i.min.x&&(t.x=this._viscousLimit(t.x,i.min.x)),t.y<i.min.y&&(t.y=this._viscousLimit(t.y,i.min.y)),t.x>i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)<Math.abs(s+e)?o:s;this._draggable._absPos=this._draggable._newPos.clone(),this._draggable._newPos.x=r},_onDragEnd:function(t){var i=this._map,e=i.options,n=!e.inertia||this._times.length<2;if(i.fire("dragend",t),n)i.fire("moveend");else{this._prunePositions(+new Date);var o=this._lastPos.subtract(this._positions[0]),s=(this._lastTime-this._times[0])/1e3,r=e.easeLinearity,a=o.multiplyBy(r/s),h=a.distanceTo([0,0]),u=Math.min(e.inertiaMaxSpeed,h),l=a.multiplyBy(u/h),c=u/(e.inertiaDeceleration*r),_=l.multiplyBy(-c/2).round();_.x||_.y?(_=i._limitOffset(_,i.options.maxBounds),M(function(){i.panBy(_,{duration:c,easeLinearity:r,noMoveStart:!0,animate:!0})})):i.fire("moveend")}}});Ji.addInitHook("addHandler","dragging",wn),Ji.mergeOptions({keyboard:!0,keyboardPanDelta:80});var Pn=oe.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),Ei(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),Bi(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var t=document.body,i=document.documentElement,e=t.scrollTop||i.scrollTop,n=t.scrollLeft||i.scrollLeft;this._map._container.focus(),window.scrollTo(n,e)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){var i,e,n=this._panKeys={},o=this.keyCodes;for(i=0,e=o.left.length;i<e;i++)n[o.left[i]]=[-1*t,0];for(i=0,e=o.right.length;i<e;i++)n[o.right[i]]=[t,0];for(i=0,e=o.down.length;i<e;i++)n[o.down[i]]=[0,t];for(i=0,e=o.up.length;i<e;i++)n[o.up[i]]=[0,-1*t]},_setZoomDelta:function(t){var i,e,n=this._zoomKeys={},o=this.keyCodes;for(i=0,e=o.zoomIn.length;i<e;i++)n[o.zoomIn[i]]=t;for(i=0,e=o.zoomOut.length;i<e;i++)n[o.zoomOut[i]]=-t},_addHooks:function(){Ei(document,"keydown",this._onKeyDown,this)},_removeHooks:function(){Bi(document,"keydown",this._onKeyDown,this)},_onKeyDown:function(t){if(!(t.altKey||t.ctrlKey||t.metaKey)){var i,e=t.keyCode,n=this._map;if(e in this._panKeys)n._panAnim&&n._panAnim._inProgress||(i=this._panKeys[e],t.shiftKey&&(i=I(i).multiplyBy(3)),n.panBy(i),n.options.maxBounds&&n.panInsideBounds(n.options.maxBounds));else if(e in this._zoomKeys)n.setZoom(n.getZoom()+(t.shiftKey?3:1)*this._zoomKeys[e]);else{if(27!==e||!n._popup||!n._popup.options.closeOnEscapeKey)return;n.closePopup()}ji(t)}}});Ji.addInitHook("addHandler","keyboard",Pn),Ji.mergeOptions({scrollWheelZoom:!0,wheelDebounceTime:40,wheelPxPerZoomLevel:60});var Ln=oe.extend({addHooks:function(){Ei(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0},removeHooks:function(){Bi(this._map._container,"mousewheel",this._onWheelScroll,this)},_onWheelScroll:function(t){var i=Fi(t),e=this._map.options.wheelDebounceTime;this._delta+=i,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var n=Math.max(e-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(a(this._performZoom,this),n),ji(t)},_performZoom:function(){var t=this._map,i=t.getZoom(),e=this._map.options.zoomSnap||0;t._stop();var n=this._delta/(4*this._map.options.wheelPxPerZoomLevel),o=4*Math.log(2/(1+Math.exp(-Math.abs(n))))/Math.LN2,s=e?Math.ceil(o/e)*e:o,r=t._limitZoom(i+(0<this._delta?s:-s))-i;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});Ji.addInitHook("addHandler","scrollWheelZoom",Ln),Ji.mergeOptions({tap:!0,tapTolerance:15});var bn=oe.extend({addHooks:function(){Ei(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){Bi(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(Di(t),this._fireClick=!0,1<t.touches.length)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],e=i.target;this._startPos=this._newPos=new B(i.clientX,i.clientY),e.tagName&&"a"===e.tagName.toLowerCase()&&pi(e,"leaflet-active"),this._holdTimeout=setTimeout(a(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),Ei(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),Bi(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&"a"===e.tagName.toLowerCase()&&mi(e,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new B(i.clientX,i.clientY),this._simulateEvent("mousemove",i)},_simulateEvent:function(t,i){var e=document.createEvent("MouseEvents");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});Tt&&!bt&&Ji.addInitHook("addHandler","tap",bn),Ji.mergeOptions({touchZoom:Tt&&!rt,bounceAtZoomLimits:!0});var Tn=oe.extend({addHooks:function(){pi(this._map._container,"leaflet-touch-zoom"),Ei(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){mi(this._map._container,"leaflet-touch-zoom"),Bi(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),Ei(document,"touchmove",this._onTouchMove,this),Ei(document,"touchend",this._onTouchEnd,this),Di(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]),o=e.distanceTo(n)/this._startDist;if(this._zoom=i.getScaleZoom(o,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoom<i.getMinZoom()&&o<1||this._zoom>i.getMaxZoom()&&1<o)&&(this._zoom=i._limitZoom(this._zoom)),"center"===i.options.touchZoom){if(this._center=this._startLatLng,1==o)return}else{var s=e._add(n)._divideBy(2)._subtract(this._centerPoint);if(1==o&&0===s.x&&0===s.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(s),this._zoom)}this._moved||(i._moveStart(!0,!1),this._moved=!0),C(this._animRequest);var r=a(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=M(r,this,!0),Di(t)}},_onTouchEnd:function(){this._moved&&this._zooming?(this._zooming=!1,C(this._animRequest),Bi(document,"touchmove",this._onTouchMove),Bi(document,"touchend",this._onTouchEnd),this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom))):this._zooming=!1}});Ji.addInitHook("addHandler","touchZoom",Tn),Ji.BoxZoom=yn,Ji.DoubleClickZoom=xn,Ji.Drag=wn,Ji.Keyboard=Pn,Ji.ScrollWheelZoom=Ln,Ji.Tap=bn,Ji.TouchZoom=Tn,Object.freeze=i,t.version="1.5.1",t.Control=Qi,t.control=$i,t.Browser=Bt,t.Evented=k,t.Mixin=re,t.Util=S,t.Class=Z,t.Handler=oe,t.extend=h,t.bind=a,t.stamp=u,t.setOptions=p,t.DomEvent=Yi,t.DomUtil=Zi,t.PosAnimation=Xi,t.Draggable=le,t.LineUtil=ye,t.PolyUtil=Pe,t.Point=B,t.point=I,t.Bounds=O,t.bounds=R,t.Transformation=G,t.transformation=K,t.Projection=Te,t.LatLng=j,t.latLng=W,t.LatLngBounds=N,t.latLngBounds=D,t.CRS=F,t.GeoJSON=We,t.geoJSON=Xe,t.geoJson=Je,t.Layer=Se,t.LayerGroup=Ze,t.layerGroup=function(t,i){return new Ze(t,i)},t.FeatureGroup=Ee,t.featureGroup=function(t){return new Ee(t)},t.ImageOverlay=$e,t.imageOverlay=function(t,i,e){return new $e(t,i,e)},t.VideoOverlay=Qe,t.videoOverlay=function(t,i,e){return new Qe(t,i,e)},t.SVGOverlay=tn,t.svgOverlay=function(t,i,e){return new tn(t,i,e)},t.DivOverlay=en,t.Popup=nn,t.popup=function(t,i){return new nn(t,i)},t.Tooltip=on,t.tooltip=function(t,i){return new on(t,i)},t.Icon=ke,t.icon=function(t){return new ke(t)},t.DivIcon=sn,t.divIcon=function(t){return new sn(t)},t.Marker=Ie,t.marker=function(t,i){return new Ie(t,i)},t.TileLayer=an,t.tileLayer=hn,t.GridLayer=rn,t.gridLayer=function(t){return new rn(t)},t.SVG=fn,t.svg=gn,t.Renderer=ln,t.Canvas=cn,t.canvas=_n,t.Path=Oe,t.CircleMarker=Re,t.circleMarker=function(t,i){return new Re(t,i)},t.Circle=Ne,t.circle=function(t,i,e){return new Ne(t,i,e)},t.Polyline=De,t.polyline=function(t,i){return new De(t,i)},t.Polygon=je,t.polygon=function(t,i){return new je(t,i)},t.Rectangle=vn,t.rectangle=function(t,i){return new vn(t,i)},t.Map=Ji,t.map=function(t,i){return new Ji(t,i)};var zn=window.L;t.noConflict=function(){return window.L=zn,this},window.L=t});
|
|
/*
|
|
* Leaflet.markercluster 1.4.1+master.37ab9a2,
|
|
* Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps.
|
|
* https://github.com/Leaflet/Leaflet.markercluster
|
|
* (c) 2012-2017, Dave Leaver, smartrak
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
(factory((global.Leaflet = global.Leaflet || {}, global.Leaflet.markercluster = global.Leaflet.markercluster || {})));
|
|
}(this, (function (exports) { 'use strict';
|
|
|
|
/*
|
|
* L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within
|
|
*/
|
|
|
|
var MarkerClusterGroup = L.MarkerClusterGroup = L.FeatureGroup.extend({
|
|
|
|
options: {
|
|
maxClusterRadius: 80, //A cluster will cover at most this many pixels from its center
|
|
iconCreateFunction: null,
|
|
clusterPane: L.Marker.prototype.options.pane,
|
|
|
|
spiderfyOnMaxZoom: true,
|
|
showCoverageOnHover: true,
|
|
zoomToBoundsOnClick: true,
|
|
singleMarkerMode: false,
|
|
|
|
disableClusteringAtZoom: null,
|
|
|
|
// Setting this to false prevents the removal of any clusters outside of the viewpoint, which
|
|
// is the default behaviour for performance reasons.
|
|
removeOutsideVisibleBounds: true,
|
|
|
|
// Set to false to disable all animations (zoom and spiderfy).
|
|
// If false, option animateAddingMarkers below has no effect.
|
|
// If L.DomUtil.TRANSITION is falsy, this option has no effect.
|
|
animate: true,
|
|
|
|
//Whether to animate adding markers after adding the MarkerClusterGroup to the map
|
|
// If you are adding individual markers set to true, if adding bulk markers leave false for massive performance gains.
|
|
animateAddingMarkers: false,
|
|
|
|
//Increase to increase the distance away that spiderfied markers appear from the center
|
|
spiderfyDistanceMultiplier: 1,
|
|
|
|
// Make it possible to specify a polyline options on a spider leg
|
|
spiderLegPolylineOptions: { weight: 1.5, color: '#222', opacity: 0.5 },
|
|
|
|
// When bulk adding layers, adds markers in chunks. Means addLayers may not add all the layers in the call, others will be loaded during setTimeouts
|
|
chunkedLoading: false,
|
|
chunkInterval: 200, // process markers for a maximum of ~ n milliseconds (then trigger the chunkProgress callback)
|
|
chunkDelay: 50, // at the end of each interval, give n milliseconds back to system/browser
|
|
chunkProgress: null, // progress callback: function(processed, total, elapsed) (e.g. for a progress indicator)
|
|
|
|
//Options to pass to the L.Polygon constructor
|
|
polygonOptions: {}
|
|
},
|
|
|
|
initialize: function (options) {
|
|
L.Util.setOptions(this, options);
|
|
if (!this.options.iconCreateFunction) {
|
|
this.options.iconCreateFunction = this._defaultIconCreateFunction;
|
|
}
|
|
|
|
this._featureGroup = L.featureGroup();
|
|
this._featureGroup.addEventParent(this);
|
|
|
|
this._nonPointGroup = L.featureGroup();
|
|
this._nonPointGroup.addEventParent(this);
|
|
|
|
this._inZoomAnimation = 0;
|
|
this._needsClustering = [];
|
|
this._needsRemoving = []; //Markers removed while we aren't on the map need to be kept track of
|
|
//The bounds of the currently shown area (from _getExpandedVisibleBounds) Updated on zoom/move
|
|
this._currentShownBounds = null;
|
|
|
|
this._queue = [];
|
|
|
|
this._childMarkerEventHandlers = {
|
|
'dragstart': this._childMarkerDragStart,
|
|
'move': this._childMarkerMoved,
|
|
'dragend': this._childMarkerDragEnd,
|
|
};
|
|
|
|
// Hook the appropriate animation methods.
|
|
var animate = L.DomUtil.TRANSITION && this.options.animate;
|
|
L.extend(this, animate ? this._withAnimation : this._noAnimation);
|
|
// Remember which MarkerCluster class to instantiate (animated or not).
|
|
this._markerCluster = animate ? L.MarkerCluster : L.MarkerClusterNonAnimated;
|
|
},
|
|
|
|
addLayer: function (layer) {
|
|
|
|
if (layer instanceof L.LayerGroup) {
|
|
return this.addLayers([layer]);
|
|
}
|
|
|
|
//Don't cluster non point data
|
|
if (!layer.getLatLng) {
|
|
this._nonPointGroup.addLayer(layer);
|
|
this.fire('layeradd', { layer: layer });
|
|
return this;
|
|
}
|
|
|
|
if (!this._map) {
|
|
this._needsClustering.push(layer);
|
|
this.fire('layeradd', { layer: layer });
|
|
return this;
|
|
}
|
|
|
|
if (this.hasLayer(layer)) {
|
|
return this;
|
|
}
|
|
|
|
|
|
//If we have already clustered we'll need to add this one to a cluster
|
|
|
|
if (this._unspiderfy) {
|
|
this._unspiderfy();
|
|
}
|
|
|
|
this._addLayer(layer, this._maxZoom);
|
|
this.fire('layeradd', { layer: layer });
|
|
|
|
// Refresh bounds and weighted positions.
|
|
this._topClusterLevel._recalculateBounds();
|
|
|
|
this._refreshClustersIcons();
|
|
|
|
//Work out what is visible
|
|
var visibleLayer = layer,
|
|
currentZoom = this._zoom;
|
|
if (layer.__parent) {
|
|
while (visibleLayer.__parent._zoom >= currentZoom) {
|
|
visibleLayer = visibleLayer.__parent;
|
|
}
|
|
}
|
|
|
|
if (this._currentShownBounds.contains(visibleLayer.getLatLng())) {
|
|
if (this.options.animateAddingMarkers) {
|
|
this._animationAddLayer(layer, visibleLayer);
|
|
} else {
|
|
this._animationAddLayerNonAnimated(layer, visibleLayer);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
removeLayer: function (layer) {
|
|
|
|
if (layer instanceof L.LayerGroup) {
|
|
return this.removeLayers([layer]);
|
|
}
|
|
|
|
//Non point layers
|
|
if (!layer.getLatLng) {
|
|
this._nonPointGroup.removeLayer(layer);
|
|
this.fire('layerremove', { layer: layer });
|
|
return this;
|
|
}
|
|
|
|
if (!this._map) {
|
|
if (!this._arraySplice(this._needsClustering, layer) && this.hasLayer(layer)) {
|
|
this._needsRemoving.push({ layer: layer, latlng: layer._latlng });
|
|
}
|
|
this.fire('layerremove', { layer: layer });
|
|
return this;
|
|
}
|
|
|
|
if (!layer.__parent) {
|
|
return this;
|
|
}
|
|
|
|
if (this._unspiderfy) {
|
|
this._unspiderfy();
|
|
this._unspiderfyLayer(layer);
|
|
}
|
|
|
|
//Remove the marker from clusters
|
|
this._removeLayer(layer, true);
|
|
this.fire('layerremove', { layer: layer });
|
|
|
|
// Refresh bounds and weighted positions.
|
|
this._topClusterLevel._recalculateBounds();
|
|
|
|
this._refreshClustersIcons();
|
|
|
|
layer.off(this._childMarkerEventHandlers, this);
|
|
|
|
if (this._featureGroup.hasLayer(layer)) {
|
|
this._featureGroup.removeLayer(layer);
|
|
if (layer.clusterShow) {
|
|
layer.clusterShow();
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
//Takes an array of markers and adds them in bulk
|
|
addLayers: function (layersArray, skipLayerAddEvent) {
|
|
if (!L.Util.isArray(layersArray)) {
|
|
return this.addLayer(layersArray);
|
|
}
|
|
|
|
var fg = this._featureGroup,
|
|
npg = this._nonPointGroup,
|
|
chunked = this.options.chunkedLoading,
|
|
chunkInterval = this.options.chunkInterval,
|
|
chunkProgress = this.options.chunkProgress,
|
|
l = layersArray.length,
|
|
offset = 0,
|
|
originalArray = true,
|
|
m;
|
|
|
|
if (this._map) {
|
|
var started = (new Date()).getTime();
|
|
var process = L.bind(function () {
|
|
var start = (new Date()).getTime();
|
|
for (; offset < l; offset++) {
|
|
if (chunked && offset % 200 === 0) {
|
|
// every couple hundred markers, instrument the time elapsed since processing started:
|
|
var elapsed = (new Date()).getTime() - start;
|
|
if (elapsed > chunkInterval) {
|
|
break; // been working too hard, time to take a break :-)
|
|
}
|
|
}
|
|
|
|
m = layersArray[offset];
|
|
|
|
// Group of layers, append children to layersArray and skip.
|
|
// Side effects:
|
|
// - Total increases, so chunkProgress ratio jumps backward.
|
|
// - Groups are not included in this group, only their non-group child layers (hasLayer).
|
|
// Changing array length while looping does not affect performance in current browsers:
|
|
// http://jsperf.com/for-loop-changing-length/6
|
|
if (m instanceof L.LayerGroup) {
|
|
if (originalArray) {
|
|
layersArray = layersArray.slice();
|
|
originalArray = false;
|
|
}
|
|
this._extractNonGroupLayers(m, layersArray);
|
|
l = layersArray.length;
|
|
continue;
|
|
}
|
|
|
|
//Not point data, can't be clustered
|
|
if (!m.getLatLng) {
|
|
npg.addLayer(m);
|
|
if (!skipLayerAddEvent) {
|
|
this.fire('layeradd', { layer: m });
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (this.hasLayer(m)) {
|
|
continue;
|
|
}
|
|
|
|
this._addLayer(m, this._maxZoom);
|
|
if (!skipLayerAddEvent) {
|
|
this.fire('layeradd', { layer: m });
|
|
}
|
|
|
|
//If we just made a cluster of size 2 then we need to remove the other marker from the map (if it is) or we never will
|
|
if (m.__parent) {
|
|
if (m.__parent.getChildCount() === 2) {
|
|
var markers = m.__parent.getAllChildMarkers(),
|
|
otherMarker = markers[0] === m ? markers[1] : markers[0];
|
|
fg.removeLayer(otherMarker);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (chunkProgress) {
|
|
// report progress and time elapsed:
|
|
chunkProgress(offset, l, (new Date()).getTime() - started);
|
|
}
|
|
|
|
// Completed processing all markers.
|
|
if (offset === l) {
|
|
|
|
// Refresh bounds and weighted positions.
|
|
this._topClusterLevel._recalculateBounds();
|
|
|
|
this._refreshClustersIcons();
|
|
|
|
this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
|
|
} else {
|
|
setTimeout(process, this.options.chunkDelay);
|
|
}
|
|
}, this);
|
|
|
|
process();
|
|
} else {
|
|
var needsClustering = this._needsClustering;
|
|
|
|
for (; offset < l; offset++) {
|
|
m = layersArray[offset];
|
|
|
|
// Group of layers, append children to layersArray and skip.
|
|
if (m instanceof L.LayerGroup) {
|
|
if (originalArray) {
|
|
layersArray = layersArray.slice();
|
|
originalArray = false;
|
|
}
|
|
this._extractNonGroupLayers(m, layersArray);
|
|
l = layersArray.length;
|
|
continue;
|
|
}
|
|
|
|
//Not point data, can't be clustered
|
|
if (!m.getLatLng) {
|
|
npg.addLayer(m);
|
|
continue;
|
|
}
|
|
|
|
if (this.hasLayer(m)) {
|
|
continue;
|
|
}
|
|
|
|
needsClustering.push(m);
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
//Takes an array of markers and removes them in bulk
|
|
removeLayers: function (layersArray) {
|
|
var i, m,
|
|
l = layersArray.length,
|
|
fg = this._featureGroup,
|
|
npg = this._nonPointGroup,
|
|
originalArray = true;
|
|
|
|
if (!this._map) {
|
|
for (i = 0; i < l; i++) {
|
|
m = layersArray[i];
|
|
|
|
// Group of layers, append children to layersArray and skip.
|
|
if (m instanceof L.LayerGroup) {
|
|
if (originalArray) {
|
|
layersArray = layersArray.slice();
|
|
originalArray = false;
|
|
}
|
|
this._extractNonGroupLayers(m, layersArray);
|
|
l = layersArray.length;
|
|
continue;
|
|
}
|
|
|
|
this._arraySplice(this._needsClustering, m);
|
|
npg.removeLayer(m);
|
|
if (this.hasLayer(m)) {
|
|
this._needsRemoving.push({ layer: m, latlng: m._latlng });
|
|
}
|
|
this.fire('layerremove', { layer: m });
|
|
}
|
|
return this;
|
|
}
|
|
|
|
if (this._unspiderfy) {
|
|
this._unspiderfy();
|
|
|
|
// Work on a copy of the array, so that next loop is not affected.
|
|
var layersArray2 = layersArray.slice(),
|
|
l2 = l;
|
|
for (i = 0; i < l2; i++) {
|
|
m = layersArray2[i];
|
|
|
|
// Group of layers, append children to layersArray and skip.
|
|
if (m instanceof L.LayerGroup) {
|
|
this._extractNonGroupLayers(m, layersArray2);
|
|
l2 = layersArray2.length;
|
|
continue;
|
|
}
|
|
|
|
this._unspiderfyLayer(m);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < l; i++) {
|
|
m = layersArray[i];
|
|
|
|
// Group of layers, append children to layersArray and skip.
|
|
if (m instanceof L.LayerGroup) {
|
|
if (originalArray) {
|
|
layersArray = layersArray.slice();
|
|
originalArray = false;
|
|
}
|
|
this._extractNonGroupLayers(m, layersArray);
|
|
l = layersArray.length;
|
|
continue;
|
|
}
|
|
|
|
if (!m.__parent) {
|
|
npg.removeLayer(m);
|
|
this.fire('layerremove', { layer: m });
|
|
continue;
|
|
}
|
|
|
|
this._removeLayer(m, true, true);
|
|
this.fire('layerremove', { layer: m });
|
|
|
|
if (fg.hasLayer(m)) {
|
|
fg.removeLayer(m);
|
|
if (m.clusterShow) {
|
|
m.clusterShow();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Refresh bounds and weighted positions.
|
|
this._topClusterLevel._recalculateBounds();
|
|
|
|
this._refreshClustersIcons();
|
|
|
|
//Fix up the clusters and markers on the map
|
|
this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds);
|
|
|
|
return this;
|
|
},
|
|
|
|
//Removes all layers from the MarkerClusterGroup
|
|
clearLayers: function () {
|
|
//Need our own special implementation as the LayerGroup one doesn't work for us
|
|
|
|
//If we aren't on the map (yet), blow away the markers we know of
|
|
if (!this._map) {
|
|
this._needsClustering = [];
|
|
this._needsRemoving = [];
|
|
delete this._gridClusters;
|
|
delete this._gridUnclustered;
|
|
}
|
|
|
|
if (this._noanimationUnspiderfy) {
|
|
this._noanimationUnspiderfy();
|
|
}
|
|
|
|
//Remove all the visible layers
|
|
this._featureGroup.clearLayers();
|
|
this._nonPointGroup.clearLayers();
|
|
|
|
this.eachLayer(function (marker) {
|
|
marker.off(this._childMarkerEventHandlers, this);
|
|
delete marker.__parent;
|
|
}, this);
|
|
|
|
if (this._map) {
|
|
//Reset _topClusterLevel and the DistanceGrids
|
|
this._generateInitialClusters();
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
//Override FeatureGroup.getBounds as it doesn't work
|
|
getBounds: function () {
|
|
var bounds = new L.LatLngBounds();
|
|
|
|
if (this._topClusterLevel) {
|
|
bounds.extend(this._topClusterLevel._bounds);
|
|
}
|
|
|
|
for (var i = this._needsClustering.length - 1; i >= 0; i--) {
|
|
bounds.extend(this._needsClustering[i].getLatLng());
|
|
}
|
|
|
|
bounds.extend(this._nonPointGroup.getBounds());
|
|
|
|
return bounds;
|
|
},
|
|
|
|
//Overrides LayerGroup.eachLayer
|
|
eachLayer: function (method, context) {
|
|
var markers = this._needsClustering.slice(),
|
|
needsRemoving = this._needsRemoving,
|
|
thisNeedsRemoving, i, j;
|
|
|
|
if (this._topClusterLevel) {
|
|
this._topClusterLevel.getAllChildMarkers(markers);
|
|
}
|
|
|
|
for (i = markers.length - 1; i >= 0; i--) {
|
|
thisNeedsRemoving = true;
|
|
|
|
for (j = needsRemoving.length - 1; j >= 0; j--) {
|
|
if (needsRemoving[j].layer === markers[i]) {
|
|
thisNeedsRemoving = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (thisNeedsRemoving) {
|
|
method.call(context, markers[i]);
|
|
}
|
|
}
|
|
|
|
this._nonPointGroup.eachLayer(method, context);
|
|
},
|
|
|
|
//Overrides LayerGroup.getLayers
|
|
getLayers: function () {
|
|
var layers = [];
|
|
this.eachLayer(function (l) {
|
|
layers.push(l);
|
|
});
|
|
return layers;
|
|
},
|
|
|
|
//Overrides LayerGroup.getLayer, WARNING: Really bad performance
|
|
getLayer: function (id) {
|
|
var result = null;
|
|
|
|
id = parseInt(id, 10);
|
|
|
|
this.eachLayer(function (l) {
|
|
if (L.stamp(l) === id) {
|
|
result = l;
|
|
}
|
|
});
|
|
|
|
return result;
|
|
},
|
|
|
|
//Returns true if the given layer is in this MarkerClusterGroup
|
|
hasLayer: function (layer) {
|
|
if (!layer) {
|
|
return false;
|
|
}
|
|
|
|
var i, anArray = this._needsClustering;
|
|
|
|
for (i = anArray.length - 1; i >= 0; i--) {
|
|
if (anArray[i] === layer) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
anArray = this._needsRemoving;
|
|
for (i = anArray.length - 1; i >= 0; i--) {
|
|
if (anArray[i].layer === layer) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer);
|
|
},
|
|
|
|
//Zoom down to show the given layer (spiderfying if necessary) then calls the callback
|
|
zoomToShowLayer: function (layer, callback) {
|
|
|
|
if (typeof callback !== 'function') {
|
|
callback = function () {};
|
|
}
|
|
|
|
var showMarker = function () {
|
|
if ((layer._icon || layer.__parent._icon) && !this._inZoomAnimation) {
|
|
this._map.off('moveend', showMarker, this);
|
|
this.off('animationend', showMarker, this);
|
|
|
|
if (layer._icon) {
|
|
callback();
|
|
} else if (layer.__parent._icon) {
|
|
this.once('spiderfied', callback, this);
|
|
layer.__parent.spiderfy();
|
|
}
|
|
}
|
|
};
|
|
|
|
if (layer._icon && this._map.getBounds().contains(layer.getLatLng())) {
|
|
//Layer is visible ond on screen, immediate return
|
|
callback();
|
|
} else if (layer.__parent._zoom < Math.round(this._map._zoom)) {
|
|
//Layer should be visible at this zoom level. It must not be on screen so just pan over to it
|
|
this._map.on('moveend', showMarker, this);
|
|
this._map.panTo(layer.getLatLng());
|
|
} else {
|
|
this._map.on('moveend', showMarker, this);
|
|
this.on('animationend', showMarker, this);
|
|
layer.__parent.zoomToBounds();
|
|
}
|
|
},
|
|
|
|
//Overrides FeatureGroup.onAdd
|
|
onAdd: function (map) {
|
|
this._map = map;
|
|
var i, l, layer;
|
|
|
|
if (!isFinite(this._map.getMaxZoom())) {
|
|
throw "Map has no maxZoom specified";
|
|
}
|
|
|
|
this._featureGroup.addTo(map);
|
|
this._nonPointGroup.addTo(map);
|
|
|
|
if (!this._gridClusters) {
|
|
this._generateInitialClusters();
|
|
}
|
|
|
|
this._maxLat = map.options.crs.projection.MAX_LATITUDE;
|
|
|
|
//Restore all the positions as they are in the MCG before removing them
|
|
for (i = 0, l = this._needsRemoving.length; i < l; i++) {
|
|
layer = this._needsRemoving[i];
|
|
layer.newlatlng = layer.layer._latlng;
|
|
layer.layer._latlng = layer.latlng;
|
|
}
|
|
//Remove them, then restore their new positions
|
|
for (i = 0, l = this._needsRemoving.length; i < l; i++) {
|
|
layer = this._needsRemoving[i];
|
|
this._removeLayer(layer.layer, true);
|
|
layer.layer._latlng = layer.newlatlng;
|
|
}
|
|
this._needsRemoving = [];
|
|
|
|
//Remember the current zoom level and bounds
|
|
this._zoom = Math.round(this._map._zoom);
|
|
this._currentShownBounds = this._getExpandedVisibleBounds();
|
|
|
|
this._map.on('zoomend', this._zoomEnd, this);
|
|
this._map.on('moveend', this._moveEnd, this);
|
|
|
|
if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely
|
|
this._spiderfierOnAdd();
|
|
}
|
|
|
|
this._bindEvents();
|
|
|
|
//Actually add our markers to the map:
|
|
l = this._needsClustering;
|
|
this._needsClustering = [];
|
|
this.addLayers(l, true);
|
|
},
|
|
|
|
//Overrides FeatureGroup.onRemove
|
|
onRemove: function (map) {
|
|
map.off('zoomend', this._zoomEnd, this);
|
|
map.off('moveend', this._moveEnd, this);
|
|
|
|
this._unbindEvents();
|
|
|
|
//In case we are in a cluster animation
|
|
this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', '');
|
|
|
|
if (this._spiderfierOnRemove) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely
|
|
this._spiderfierOnRemove();
|
|
}
|
|
|
|
delete this._maxLat;
|
|
|
|
//Clean up all the layers we added to the map
|
|
this._hideCoverage();
|
|
this._featureGroup.remove();
|
|
this._nonPointGroup.remove();
|
|
|
|
this._featureGroup.clearLayers();
|
|
|
|
this._map = null;
|
|
},
|
|
|
|
getVisibleParent: function (marker) {
|
|
var vMarker = marker;
|
|
while (vMarker && !vMarker._icon) {
|
|
vMarker = vMarker.__parent;
|
|
}
|
|
return vMarker || null;
|
|
},
|
|
|
|
//Remove the given object from the given array
|
|
_arraySplice: function (anArray, obj) {
|
|
for (var i = anArray.length - 1; i >= 0; i--) {
|
|
if (anArray[i] === obj) {
|
|
anArray.splice(i, 1);
|
|
return true;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Removes a marker from all _gridUnclustered zoom levels, starting at the supplied zoom.
|
|
* @param marker to be removed from _gridUnclustered.
|
|
* @param z integer bottom start zoom level (included)
|
|
* @private
|
|
*/
|
|
_removeFromGridUnclustered: function (marker, z) {
|
|
var map = this._map,
|
|
gridUnclustered = this._gridUnclustered,
|
|
minZoom = Math.floor(this._map.getMinZoom());
|
|
|
|
for (; z >= minZoom; z--) {
|
|
if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) {
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
_childMarkerDragStart: function (e) {
|
|
e.target.__dragStart = e.target._latlng;
|
|
},
|
|
|
|
_childMarkerMoved: function (e) {
|
|
if (!this._ignoreMove && !e.target.__dragStart) {
|
|
var isPopupOpen = e.target._popup && e.target._popup.isOpen();
|
|
|
|
this._moveChild(e.target, e.oldLatLng, e.latlng);
|
|
|
|
if (isPopupOpen) {
|
|
e.target.openPopup();
|
|
}
|
|
}
|
|
},
|
|
|
|
_moveChild: function (layer, from, to) {
|
|
layer._latlng = from;
|
|
this.removeLayer(layer);
|
|
|
|
layer._latlng = to;
|
|
this.addLayer(layer);
|
|
},
|
|
|
|
_childMarkerDragEnd: function (e) {
|
|
var dragStart = e.target.__dragStart;
|
|
delete e.target.__dragStart;
|
|
if (dragStart) {
|
|
this._moveChild(e.target, dragStart, e.target._latlng);
|
|
}
|
|
},
|
|
|
|
|
|
//Internal function for removing a marker from everything.
|
|
//dontUpdateMap: set to true if you will handle updating the map manually (for bulk functions)
|
|
_removeLayer: function (marker, removeFromDistanceGrid, dontUpdateMap) {
|
|
var gridClusters = this._gridClusters,
|
|
gridUnclustered = this._gridUnclustered,
|
|
fg = this._featureGroup,
|
|
map = this._map,
|
|
minZoom = Math.floor(this._map.getMinZoom());
|
|
|
|
//Remove the marker from distance clusters it might be in
|
|
if (removeFromDistanceGrid) {
|
|
this._removeFromGridUnclustered(marker, this._maxZoom);
|
|
}
|
|
|
|
//Work our way up the clusters removing them as we go if required
|
|
var cluster = marker.__parent,
|
|
markers = cluster._markers,
|
|
otherMarker;
|
|
|
|
//Remove the marker from the immediate parents marker list
|
|
this._arraySplice(markers, marker);
|
|
|
|
while (cluster) {
|
|
cluster._childCount--;
|
|
cluster._boundsNeedUpdate = true;
|
|
|
|
if (cluster._zoom < minZoom) {
|
|
//Top level, do nothing
|
|
break;
|
|
} else if (removeFromDistanceGrid && cluster._childCount <= 1) { //Cluster no longer required
|
|
//We need to push the other marker up to the parent
|
|
otherMarker = cluster._markers[0] === marker ? cluster._markers[1] : cluster._markers[0];
|
|
|
|
//Update distance grid
|
|
gridClusters[cluster._zoom].removeObject(cluster, map.project(cluster._cLatLng, cluster._zoom));
|
|
gridUnclustered[cluster._zoom].addObject(otherMarker, map.project(otherMarker.getLatLng(), cluster._zoom));
|
|
|
|
//Move otherMarker up to parent
|
|
this._arraySplice(cluster.__parent._childClusters, cluster);
|
|
cluster.__parent._markers.push(otherMarker);
|
|
otherMarker.__parent = cluster.__parent;
|
|
|
|
if (cluster._icon) {
|
|
//Cluster is currently on the map, need to put the marker on the map instead
|
|
fg.removeLayer(cluster);
|
|
if (!dontUpdateMap) {
|
|
fg.addLayer(otherMarker);
|
|
}
|
|
}
|
|
} else {
|
|
cluster._iconNeedsUpdate = true;
|
|
}
|
|
|
|
cluster = cluster.__parent;
|
|
}
|
|
|
|
delete marker.__parent;
|
|
},
|
|
|
|
_isOrIsParent: function (el, oel) {
|
|
while (oel) {
|
|
if (el === oel) {
|
|
return true;
|
|
}
|
|
oel = oel.parentNode;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
//Override L.Evented.fire
|
|
fire: function (type, data, propagate) {
|
|
if (data && data.layer instanceof L.MarkerCluster) {
|
|
//Prevent multiple clustermouseover/off events if the icon is made up of stacked divs (Doesn't work in ie <= 8, no relatedTarget)
|
|
if (data.originalEvent && this._isOrIsParent(data.layer._icon, data.originalEvent.relatedTarget)) {
|
|
return;
|
|
}
|
|
type = 'cluster' + type;
|
|
}
|
|
|
|
L.FeatureGroup.prototype.fire.call(this, type, data, propagate);
|
|
},
|
|
|
|
//Override L.Evented.listens
|
|
listens: function (type, propagate) {
|
|
return L.FeatureGroup.prototype.listens.call(this, type, propagate) || L.FeatureGroup.prototype.listens.call(this, 'cluster' + type, propagate);
|
|
},
|
|
|
|
//Default functionality
|
|
_defaultIconCreateFunction: function (cluster) {
|
|
var childCount = cluster.getChildCount();
|
|
|
|
var c = ' marker-cluster-';
|
|
if (childCount < 10) {
|
|
c += 'small';
|
|
} else if (childCount < 100) {
|
|
c += 'medium';
|
|
} else {
|
|
c += 'large';
|
|
}
|
|
|
|
return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
|
|
},
|
|
|
|
_bindEvents: function () {
|
|
var map = this._map,
|
|
spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom,
|
|
showCoverageOnHover = this.options.showCoverageOnHover,
|
|
zoomToBoundsOnClick = this.options.zoomToBoundsOnClick;
|
|
|
|
//Zoom on cluster click or spiderfy if we are at the lowest level
|
|
if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
|
|
this.on('clusterclick', this._zoomOrSpiderfy, this);
|
|
}
|
|
|
|
//Show convex hull (boundary) polygon on mouse over
|
|
if (showCoverageOnHover) {
|
|
this.on('clustermouseover', this._showCoverage, this);
|
|
this.on('clustermouseout', this._hideCoverage, this);
|
|
map.on('zoomend', this._hideCoverage, this);
|
|
}
|
|
},
|
|
|
|
_zoomOrSpiderfy: function (e) {
|
|
var cluster = e.layer,
|
|
bottomCluster = cluster;
|
|
|
|
while (bottomCluster._childClusters.length === 1) {
|
|
bottomCluster = bottomCluster._childClusters[0];
|
|
}
|
|
|
|
if (bottomCluster._zoom === this._maxZoom &&
|
|
bottomCluster._childCount === cluster._childCount &&
|
|
this.options.spiderfyOnMaxZoom) {
|
|
|
|
// All child markers are contained in a single cluster from this._maxZoom to this cluster.
|
|
cluster.spiderfy();
|
|
} else if (this.options.zoomToBoundsOnClick) {
|
|
cluster.zoomToBounds();
|
|
}
|
|
|
|
// Focus the map again for keyboard users.
|
|
if (e.originalEvent && e.originalEvent.keyCode === 13) {
|
|
this._map._container.focus();
|
|
}
|
|
},
|
|
|
|
_showCoverage: function (e) {
|
|
var map = this._map;
|
|
if (this._inZoomAnimation) {
|
|
return;
|
|
}
|
|
if (this._shownPolygon) {
|
|
map.removeLayer(this._shownPolygon);
|
|
}
|
|
if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) {
|
|
this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions);
|
|
map.addLayer(this._shownPolygon);
|
|
}
|
|
},
|
|
|
|
_hideCoverage: function () {
|
|
if (this._shownPolygon) {
|
|
this._map.removeLayer(this._shownPolygon);
|
|
this._shownPolygon = null;
|
|
}
|
|
},
|
|
|
|
_unbindEvents: function () {
|
|
var spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom,
|
|
showCoverageOnHover = this.options.showCoverageOnHover,
|
|
zoomToBoundsOnClick = this.options.zoomToBoundsOnClick,
|
|
map = this._map;
|
|
|
|
if (spiderfyOnMaxZoom || zoomToBoundsOnClick) {
|
|
this.off('clusterclick', this._zoomOrSpiderfy, this);
|
|
}
|
|
if (showCoverageOnHover) {
|
|
this.off('clustermouseover', this._showCoverage, this);
|
|
this.off('clustermouseout', this._hideCoverage, this);
|
|
map.off('zoomend', this._hideCoverage, this);
|
|
}
|
|
},
|
|
|
|
_zoomEnd: function () {
|
|
if (!this._map) { //May have been removed from the map by a zoomEnd handler
|
|
return;
|
|
}
|
|
this._mergeSplitClusters();
|
|
|
|
this._zoom = Math.round(this._map._zoom);
|
|
this._currentShownBounds = this._getExpandedVisibleBounds();
|
|
},
|
|
|
|
_moveEnd: function () {
|
|
if (this._inZoomAnimation) {
|
|
return;
|
|
}
|
|
|
|
var newBounds = this._getExpandedVisibleBounds();
|
|
|
|
this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), this._zoom, newBounds);
|
|
this._topClusterLevel._recursivelyAddChildrenToMap(null, Math.round(this._map._zoom), newBounds);
|
|
|
|
this._currentShownBounds = newBounds;
|
|
return;
|
|
},
|
|
|
|
_generateInitialClusters: function () {
|
|
var maxZoom = Math.ceil(this._map.getMaxZoom()),
|
|
minZoom = Math.floor(this._map.getMinZoom()),
|
|
radius = this.options.maxClusterRadius,
|
|
radiusFn = radius;
|
|
|
|
//If we just set maxClusterRadius to a single number, we need to create
|
|
//a simple function to return that number. Otherwise, we just have to
|
|
//use the function we've passed in.
|
|
if (typeof radius !== "function") {
|
|
radiusFn = function () { return radius; };
|
|
}
|
|
|
|
if (this.options.disableClusteringAtZoom !== null) {
|
|
maxZoom = this.options.disableClusteringAtZoom - 1;
|
|
}
|
|
this._maxZoom = maxZoom;
|
|
this._gridClusters = {};
|
|
this._gridUnclustered = {};
|
|
|
|
//Set up DistanceGrids for each zoom
|
|
for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
|
|
this._gridClusters[zoom] = new L.DistanceGrid(radiusFn(zoom));
|
|
this._gridUnclustered[zoom] = new L.DistanceGrid(radiusFn(zoom));
|
|
}
|
|
|
|
// Instantiate the appropriate L.MarkerCluster class (animated or not).
|
|
this._topClusterLevel = new this._markerCluster(this, minZoom - 1);
|
|
},
|
|
|
|
//Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom)
|
|
_addLayer: function (layer, zoom) {
|
|
var gridClusters = this._gridClusters,
|
|
gridUnclustered = this._gridUnclustered,
|
|
minZoom = Math.floor(this._map.getMinZoom()),
|
|
markerPoint, z;
|
|
|
|
if (this.options.singleMarkerMode) {
|
|
this._overrideMarkerIcon(layer);
|
|
}
|
|
|
|
layer.on(this._childMarkerEventHandlers, this);
|
|
|
|
//Find the lowest zoom level to slot this one in
|
|
for (; zoom >= minZoom; zoom--) {
|
|
markerPoint = this._map.project(layer.getLatLng(), zoom); // calculate pixel position
|
|
|
|
//Try find a cluster close by
|
|
var closest = gridClusters[zoom].getNearObject(markerPoint);
|
|
if (closest) {
|
|
closest._addChild(layer);
|
|
layer.__parent = closest;
|
|
return;
|
|
}
|
|
|
|
//Try find a marker close by to form a new cluster with
|
|
closest = gridUnclustered[zoom].getNearObject(markerPoint);
|
|
if (closest) {
|
|
var parent = closest.__parent;
|
|
if (parent) {
|
|
this._removeLayer(closest, false);
|
|
}
|
|
|
|
//Create new cluster with these 2 in it
|
|
|
|
var newCluster = new this._markerCluster(this, zoom, closest, layer);
|
|
gridClusters[zoom].addObject(newCluster, this._map.project(newCluster._cLatLng, zoom));
|
|
closest.__parent = newCluster;
|
|
layer.__parent = newCluster;
|
|
|
|
//First create any new intermediate parent clusters that don't exist
|
|
var lastParent = newCluster;
|
|
for (z = zoom - 1; z > parent._zoom; z--) {
|
|
lastParent = new this._markerCluster(this, z, lastParent);
|
|
gridClusters[z].addObject(lastParent, this._map.project(closest.getLatLng(), z));
|
|
}
|
|
parent._addChild(lastParent);
|
|
|
|
//Remove closest from this zoom level and any above that it is in, replace with newCluster
|
|
this._removeFromGridUnclustered(closest, zoom);
|
|
|
|
return;
|
|
}
|
|
|
|
//Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards
|
|
gridUnclustered[zoom].addObject(layer, markerPoint);
|
|
}
|
|
|
|
//Didn't get in anything, add us to the top
|
|
this._topClusterLevel._addChild(layer);
|
|
layer.__parent = this._topClusterLevel;
|
|
return;
|
|
},
|
|
|
|
/**
|
|
* Refreshes the icon of all "dirty" visible clusters.
|
|
* Non-visible "dirty" clusters will be updated when they are added to the map.
|
|
* @private
|
|
*/
|
|
_refreshClustersIcons: function () {
|
|
this._featureGroup.eachLayer(function (c) {
|
|
if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) {
|
|
c._updateIcon();
|
|
}
|
|
});
|
|
},
|
|
|
|
//Enqueue code to fire after the marker expand/contract has happened
|
|
_enqueue: function (fn) {
|
|
this._queue.push(fn);
|
|
if (!this._queueTimeout) {
|
|
this._queueTimeout = setTimeout(L.bind(this._processQueue, this), 300);
|
|
}
|
|
},
|
|
_processQueue: function () {
|
|
for (var i = 0; i < this._queue.length; i++) {
|
|
this._queue[i].call(this);
|
|
}
|
|
this._queue.length = 0;
|
|
clearTimeout(this._queueTimeout);
|
|
this._queueTimeout = null;
|
|
},
|
|
|
|
//Merge and split any existing clusters that are too big or small
|
|
_mergeSplitClusters: function () {
|
|
var mapZoom = Math.round(this._map._zoom);
|
|
|
|
//In case we are starting to split before the animation finished
|
|
this._processQueue();
|
|
|
|
if (this._zoom < mapZoom && this._currentShownBounds.intersects(this._getExpandedVisibleBounds())) { //Zoom in, split
|
|
this._animationStart();
|
|
//Remove clusters now off screen
|
|
this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), this._zoom, this._getExpandedVisibleBounds());
|
|
|
|
this._animationZoomIn(this._zoom, mapZoom);
|
|
|
|
} else if (this._zoom > mapZoom) { //Zoom out, merge
|
|
this._animationStart();
|
|
|
|
this._animationZoomOut(this._zoom, mapZoom);
|
|
} else {
|
|
this._moveEnd();
|
|
}
|
|
},
|
|
|
|
//Gets the maps visible bounds expanded in each direction by the size of the screen (so the user cannot see an area we do not cover in one pan)
|
|
_getExpandedVisibleBounds: function () {
|
|
if (!this.options.removeOutsideVisibleBounds) {
|
|
return this._mapBoundsInfinite;
|
|
} else if (L.Browser.mobile) {
|
|
return this._checkBoundsMaxLat(this._map.getBounds());
|
|
}
|
|
|
|
return this._checkBoundsMaxLat(this._map.getBounds().pad(1)); // Padding expands the bounds by its own dimensions but scaled with the given factor.
|
|
},
|
|
|
|
/**
|
|
* Expands the latitude to Infinity (or -Infinity) if the input bounds reach the map projection maximum defined latitude
|
|
* (in the case of Web/Spherical Mercator, it is 85.0511287798 / see https://en.wikipedia.org/wiki/Web_Mercator#Formulas).
|
|
* Otherwise, the removeOutsideVisibleBounds option will remove markers beyond that limit, whereas the same markers without
|
|
* this option (or outside MCG) will have their position floored (ceiled) by the projection and rendered at that limit,
|
|
* making the user think that MCG "eats" them and never displays them again.
|
|
* @param bounds L.LatLngBounds
|
|
* @returns {L.LatLngBounds}
|
|
* @private
|
|
*/
|
|
_checkBoundsMaxLat: function (bounds) {
|
|
var maxLat = this._maxLat;
|
|
|
|
if (maxLat !== undefined) {
|
|
if (bounds.getNorth() >= maxLat) {
|
|
bounds._northEast.lat = Infinity;
|
|
}
|
|
if (bounds.getSouth() <= -maxLat) {
|
|
bounds._southWest.lat = -Infinity;
|
|
}
|
|
}
|
|
|
|
return bounds;
|
|
},
|
|
|
|
//Shared animation code
|
|
_animationAddLayerNonAnimated: function (layer, newCluster) {
|
|
if (newCluster === layer) {
|
|
this._featureGroup.addLayer(layer);
|
|
} else if (newCluster._childCount === 2) {
|
|
newCluster._addToMap();
|
|
|
|
var markers = newCluster.getAllChildMarkers();
|
|
this._featureGroup.removeLayer(markers[0]);
|
|
this._featureGroup.removeLayer(markers[1]);
|
|
} else {
|
|
newCluster._updateIcon();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Extracts individual (i.e. non-group) layers from a Layer Group.
|
|
* @param group to extract layers from.
|
|
* @param output {Array} in which to store the extracted layers.
|
|
* @returns {*|Array}
|
|
* @private
|
|
*/
|
|
_extractNonGroupLayers: function (group, output) {
|
|
var layers = group.getLayers(),
|
|
i = 0,
|
|
layer;
|
|
|
|
output = output || [];
|
|
|
|
for (; i < layers.length; i++) {
|
|
layer = layers[i];
|
|
|
|
if (layer instanceof L.LayerGroup) {
|
|
this._extractNonGroupLayers(layer, output);
|
|
continue;
|
|
}
|
|
|
|
output.push(layer);
|
|
}
|
|
|
|
return output;
|
|
},
|
|
|
|
/**
|
|
* Implements the singleMarkerMode option.
|
|
* @param layer Marker to re-style using the Clusters iconCreateFunction.
|
|
* @returns {L.Icon} The newly created icon.
|
|
* @private
|
|
*/
|
|
_overrideMarkerIcon: function (layer) {
|
|
var icon = layer.options.icon = this.options.iconCreateFunction({
|
|
getChildCount: function () {
|
|
return 1;
|
|
},
|
|
getAllChildMarkers: function () {
|
|
return [layer];
|
|
}
|
|
});
|
|
|
|
return icon;
|
|
}
|
|
});
|
|
|
|
// Constant bounds used in case option "removeOutsideVisibleBounds" is set to false.
|
|
L.MarkerClusterGroup.include({
|
|
_mapBoundsInfinite: new L.LatLngBounds(new L.LatLng(-Infinity, -Infinity), new L.LatLng(Infinity, Infinity))
|
|
});
|
|
|
|
L.MarkerClusterGroup.include({
|
|
_noAnimation: {
|
|
//Non Animated versions of everything
|
|
_animationStart: function () {
|
|
//Do nothing...
|
|
},
|
|
_animationZoomIn: function (previousZoomLevel, newZoomLevel) {
|
|
this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel);
|
|
this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
|
|
|
|
//We didn't actually animate, but we use this event to mean "clustering animations have finished"
|
|
this.fire('animationend');
|
|
},
|
|
_animationZoomOut: function (previousZoomLevel, newZoomLevel) {
|
|
this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel);
|
|
this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
|
|
|
|
//We didn't actually animate, but we use this event to mean "clustering animations have finished"
|
|
this.fire('animationend');
|
|
},
|
|
_animationAddLayer: function (layer, newCluster) {
|
|
this._animationAddLayerNonAnimated(layer, newCluster);
|
|
}
|
|
},
|
|
|
|
_withAnimation: {
|
|
//Animated versions here
|
|
_animationStart: function () {
|
|
this._map._mapPane.className += ' leaflet-cluster-anim';
|
|
this._inZoomAnimation++;
|
|
},
|
|
|
|
_animationZoomIn: function (previousZoomLevel, newZoomLevel) {
|
|
var bounds = this._getExpandedVisibleBounds(),
|
|
fg = this._featureGroup,
|
|
minZoom = Math.floor(this._map.getMinZoom()),
|
|
i;
|
|
|
|
this._ignoreMove = true;
|
|
|
|
//Add all children of current clusters to map and remove those clusters from map
|
|
this._topClusterLevel._recursively(bounds, previousZoomLevel, minZoom, function (c) {
|
|
var startPos = c._latlng,
|
|
markers = c._markers,
|
|
m;
|
|
|
|
if (!bounds.contains(startPos)) {
|
|
startPos = null;
|
|
}
|
|
|
|
if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { //Immediately add the new child and remove us
|
|
fg.removeLayer(c);
|
|
c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds);
|
|
} else {
|
|
//Fade out old cluster
|
|
c.clusterHide();
|
|
c._recursivelyAddChildrenToMap(startPos, newZoomLevel, bounds);
|
|
}
|
|
|
|
//Remove all markers that aren't visible any more
|
|
//TODO: Do we actually need to do this on the higher levels too?
|
|
for (i = markers.length - 1; i >= 0; i--) {
|
|
m = markers[i];
|
|
if (!bounds.contains(m._latlng)) {
|
|
fg.removeLayer(m);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
this._forceLayout();
|
|
|
|
//Update opacities
|
|
this._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel);
|
|
//TODO Maybe? Update markers in _recursivelyBecomeVisible
|
|
fg.eachLayer(function (n) {
|
|
if (!(n instanceof L.MarkerCluster) && n._icon) {
|
|
n.clusterShow();
|
|
}
|
|
});
|
|
|
|
//update the positions of the just added clusters/markers
|
|
this._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) {
|
|
c._recursivelyRestoreChildPositions(newZoomLevel);
|
|
});
|
|
|
|
this._ignoreMove = false;
|
|
|
|
//Remove the old clusters and close the zoom animation
|
|
this._enqueue(function () {
|
|
//update the positions of the just added clusters/markers
|
|
this._topClusterLevel._recursively(bounds, previousZoomLevel, minZoom, function (c) {
|
|
fg.removeLayer(c);
|
|
c.clusterShow();
|
|
});
|
|
|
|
this._animationEnd();
|
|
});
|
|
},
|
|
|
|
_animationZoomOut: function (previousZoomLevel, newZoomLevel) {
|
|
this._animationZoomOutSingle(this._topClusterLevel, previousZoomLevel - 1, newZoomLevel);
|
|
|
|
//Need to add markers for those that weren't on the map before but are now
|
|
this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds());
|
|
//Remove markers that were on the map before but won't be now
|
|
this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, Math.floor(this._map.getMinZoom()), previousZoomLevel, this._getExpandedVisibleBounds());
|
|
},
|
|
|
|
_animationAddLayer: function (layer, newCluster) {
|
|
var me = this,
|
|
fg = this._featureGroup;
|
|
|
|
fg.addLayer(layer);
|
|
if (newCluster !== layer) {
|
|
if (newCluster._childCount > 2) { //Was already a cluster
|
|
|
|
newCluster._updateIcon();
|
|
this._forceLayout();
|
|
this._animationStart();
|
|
|
|
layer._setPos(this._map.latLngToLayerPoint(newCluster.getLatLng()));
|
|
layer.clusterHide();
|
|
|
|
this._enqueue(function () {
|
|
fg.removeLayer(layer);
|
|
layer.clusterShow();
|
|
|
|
me._animationEnd();
|
|
});
|
|
|
|
} else { //Just became a cluster
|
|
this._forceLayout();
|
|
|
|
me._animationStart();
|
|
me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._zoom);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// Private methods for animated versions.
|
|
_animationZoomOutSingle: function (cluster, previousZoomLevel, newZoomLevel) {
|
|
var bounds = this._getExpandedVisibleBounds(),
|
|
minZoom = Math.floor(this._map.getMinZoom());
|
|
|
|
//Animate all of the markers in the clusters to move to their cluster center point
|
|
cluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, minZoom, previousZoomLevel + 1, newZoomLevel);
|
|
|
|
var me = this;
|
|
|
|
//Update the opacity (If we immediately set it they won't animate)
|
|
this._forceLayout();
|
|
cluster._recursivelyBecomeVisible(bounds, newZoomLevel);
|
|
|
|
//TODO: Maybe use the transition timing stuff to make this more reliable
|
|
//When the animations are done, tidy up
|
|
this._enqueue(function () {
|
|
|
|
//This cluster stopped being a cluster before the timeout fired
|
|
if (cluster._childCount === 1) {
|
|
var m = cluster._markers[0];
|
|
//If we were in a cluster animation at the time then the opacity and position of our child could be wrong now, so fix it
|
|
this._ignoreMove = true;
|
|
m.setLatLng(m.getLatLng());
|
|
this._ignoreMove = false;
|
|
if (m.clusterShow) {
|
|
m.clusterShow();
|
|
}
|
|
} else {
|
|
cluster._recursively(bounds, newZoomLevel, minZoom, function (c) {
|
|
c._recursivelyRemoveChildrenFromMap(bounds, minZoom, previousZoomLevel + 1);
|
|
});
|
|
}
|
|
me._animationEnd();
|
|
});
|
|
},
|
|
|
|
_animationEnd: function () {
|
|
if (this._map) {
|
|
this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', '');
|
|
}
|
|
this._inZoomAnimation--;
|
|
this.fire('animationend');
|
|
},
|
|
|
|
//Force a browser layout of stuff in the map
|
|
// Should apply the current opacity and location to all elements so we can update them again for an animation
|
|
_forceLayout: function () {
|
|
//In my testing this works, infact offsetWidth of any element seems to work.
|
|
//Could loop all this._layers and do this for each _icon if it stops working
|
|
|
|
L.Util.falseFn(document.body.offsetWidth);
|
|
}
|
|
});
|
|
|
|
L.markerClusterGroup = function (options) {
|
|
return new L.MarkerClusterGroup(options);
|
|
};
|
|
|
|
var MarkerCluster = L.MarkerCluster = L.Marker.extend({
|
|
options: L.Icon.prototype.options,
|
|
|
|
initialize: function (group, zoom, a, b) {
|
|
|
|
L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0),
|
|
{ icon: this, pane: group.options.clusterPane });
|
|
|
|
this._group = group;
|
|
this._zoom = zoom;
|
|
|
|
this._markers = [];
|
|
this._childClusters = [];
|
|
this._childCount = 0;
|
|
this._iconNeedsUpdate = true;
|
|
this._boundsNeedUpdate = true;
|
|
|
|
this._bounds = new L.LatLngBounds();
|
|
|
|
if (a) {
|
|
this._addChild(a);
|
|
}
|
|
if (b) {
|
|
this._addChild(b);
|
|
}
|
|
},
|
|
|
|
//Recursively retrieve all child markers of this cluster
|
|
getAllChildMarkers: function (storageArray, ignoreDraggedMarker) {
|
|
storageArray = storageArray || [];
|
|
|
|
for (var i = this._childClusters.length - 1; i >= 0; i--) {
|
|
this._childClusters[i].getAllChildMarkers(storageArray);
|
|
}
|
|
|
|
for (var j = this._markers.length - 1; j >= 0; j--) {
|
|
if (ignoreDraggedMarker && this._markers[j].__dragStart) {
|
|
continue;
|
|
}
|
|
storageArray.push(this._markers[j]);
|
|
}
|
|
|
|
return storageArray;
|
|
},
|
|
|
|
//Returns the count of how many child markers we have
|
|
getChildCount: function () {
|
|
return this._childCount;
|
|
},
|
|
|
|
//Zoom to the minimum of showing all of the child markers, or the extents of this cluster
|
|
zoomToBounds: function (fitBoundsOptions) {
|
|
var childClusters = this._childClusters.slice(),
|
|
map = this._group._map,
|
|
boundsZoom = map.getBoundsZoom(this._bounds),
|
|
zoom = this._zoom + 1,
|
|
mapZoom = map.getZoom(),
|
|
i;
|
|
|
|
//calculate how far we need to zoom down to see all of the markers
|
|
while (childClusters.length > 0 && boundsZoom > zoom) {
|
|
zoom++;
|
|
var newClusters = [];
|
|
for (i = 0; i < childClusters.length; i++) {
|
|
newClusters = newClusters.concat(childClusters[i]._childClusters);
|
|
}
|
|
childClusters = newClusters;
|
|
}
|
|
|
|
if (boundsZoom > zoom) {
|
|
this._group._map.setView(this._latlng, zoom);
|
|
} else if (boundsZoom <= mapZoom) { //If fitBounds wouldn't zoom us down, zoom us down instead
|
|
this._group._map.setView(this._latlng, mapZoom + 1);
|
|
} else {
|
|
this._group._map.fitBounds(this._bounds, fitBoundsOptions);
|
|
}
|
|
},
|
|
|
|
getBounds: function () {
|
|
var bounds = new L.LatLngBounds();
|
|
bounds.extend(this._bounds);
|
|
return bounds;
|
|
},
|
|
|
|
_updateIcon: function () {
|
|
this._iconNeedsUpdate = true;
|
|
if (this._icon) {
|
|
this.setIcon(this);
|
|
}
|
|
},
|
|
|
|
//Cludge for Icon, we pretend to be an icon for performance
|
|
createIcon: function () {
|
|
if (this._iconNeedsUpdate) {
|
|
this._iconObj = this._group.options.iconCreateFunction(this);
|
|
this._iconNeedsUpdate = false;
|
|
}
|
|
return this._iconObj.createIcon();
|
|
},
|
|
createShadow: function () {
|
|
return this._iconObj.createShadow();
|
|
},
|
|
|
|
|
|
_addChild: function (new1, isNotificationFromChild) {
|
|
|
|
this._iconNeedsUpdate = true;
|
|
|
|
this._boundsNeedUpdate = true;
|
|
this._setClusterCenter(new1);
|
|
|
|
if (new1 instanceof L.MarkerCluster) {
|
|
if (!isNotificationFromChild) {
|
|
this._childClusters.push(new1);
|
|
new1.__parent = this;
|
|
}
|
|
this._childCount += new1._childCount;
|
|
} else {
|
|
if (!isNotificationFromChild) {
|
|
this._markers.push(new1);
|
|
}
|
|
this._childCount++;
|
|
}
|
|
|
|
if (this.__parent) {
|
|
this.__parent._addChild(new1, true);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Makes sure the cluster center is set. If not, uses the child center if it is a cluster, or the marker position.
|
|
* @param child L.MarkerCluster|L.Marker that will be used as cluster center if not defined yet.
|
|
* @private
|
|
*/
|
|
_setClusterCenter: function (child) {
|
|
if (!this._cLatLng) {
|
|
// when clustering, take position of the first point as the cluster center
|
|
this._cLatLng = child._cLatLng || child._latlng;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Assigns impossible bounding values so that the next extend entirely determines the new bounds.
|
|
* This method avoids having to trash the previous L.LatLngBounds object and to create a new one, which is much slower for this class.
|
|
* As long as the bounds are not extended, most other methods would probably fail, as they would with bounds initialized but not extended.
|
|
* @private
|
|
*/
|
|
_resetBounds: function () {
|
|
var bounds = this._bounds;
|
|
|
|
if (bounds._southWest) {
|
|
bounds._southWest.lat = Infinity;
|
|
bounds._southWest.lng = Infinity;
|
|
}
|
|
if (bounds._northEast) {
|
|
bounds._northEast.lat = -Infinity;
|
|
bounds._northEast.lng = -Infinity;
|
|
}
|
|
},
|
|
|
|
_recalculateBounds: function () {
|
|
var markers = this._markers,
|
|
childClusters = this._childClusters,
|
|
latSum = 0,
|
|
lngSum = 0,
|
|
totalCount = this._childCount,
|
|
i, child, childLatLng, childCount;
|
|
|
|
// Case where all markers are removed from the map and we are left with just an empty _topClusterLevel.
|
|
if (totalCount === 0) {
|
|
return;
|
|
}
|
|
|
|
// Reset rather than creating a new object, for performance.
|
|
this._resetBounds();
|
|
|
|
// Child markers.
|
|
for (i = 0; i < markers.length; i++) {
|
|
childLatLng = markers[i]._latlng;
|
|
|
|
this._bounds.extend(childLatLng);
|
|
|
|
latSum += childLatLng.lat;
|
|
lngSum += childLatLng.lng;
|
|
}
|
|
|
|
// Child clusters.
|
|
for (i = 0; i < childClusters.length; i++) {
|
|
child = childClusters[i];
|
|
|
|
// Re-compute child bounds and weighted position first if necessary.
|
|
if (child._boundsNeedUpdate) {
|
|
child._recalculateBounds();
|
|
}
|
|
|
|
this._bounds.extend(child._bounds);
|
|
|
|
childLatLng = child._wLatLng;
|
|
childCount = child._childCount;
|
|
|
|
latSum += childLatLng.lat * childCount;
|
|
lngSum += childLatLng.lng * childCount;
|
|
}
|
|
|
|
this._latlng = this._wLatLng = new L.LatLng(latSum / totalCount, lngSum / totalCount);
|
|
|
|
// Reset dirty flag.
|
|
this._boundsNeedUpdate = false;
|
|
},
|
|
|
|
//Set our markers position as given and add it to the map
|
|
_addToMap: function (startPos) {
|
|
if (startPos) {
|
|
this._backupLatlng = this._latlng;
|
|
this.setLatLng(startPos);
|
|
}
|
|
this._group._featureGroup.addLayer(this);
|
|
},
|
|
|
|
_recursivelyAnimateChildrenIn: function (bounds, center, maxZoom) {
|
|
this._recursively(bounds, this._group._map.getMinZoom(), maxZoom - 1,
|
|
function (c) {
|
|
var markers = c._markers,
|
|
i, m;
|
|
for (i = markers.length - 1; i >= 0; i--) {
|
|
m = markers[i];
|
|
|
|
//Only do it if the icon is still on the map
|
|
if (m._icon) {
|
|
m._setPos(center);
|
|
m.clusterHide();
|
|
}
|
|
}
|
|
},
|
|
function (c) {
|
|
var childClusters = c._childClusters,
|
|
j, cm;
|
|
for (j = childClusters.length - 1; j >= 0; j--) {
|
|
cm = childClusters[j];
|
|
if (cm._icon) {
|
|
cm._setPos(center);
|
|
cm.clusterHide();
|
|
}
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
_recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, mapMinZoom, previousZoomLevel, newZoomLevel) {
|
|
this._recursively(bounds, newZoomLevel, mapMinZoom,
|
|
function (c) {
|
|
c._recursivelyAnimateChildrenIn(bounds, c._group._map.latLngToLayerPoint(c.getLatLng()).round(), previousZoomLevel);
|
|
|
|
//TODO: depthToAnimateIn affects _isSingleParent, if there is a multizoom we may/may not be.
|
|
//As a hack we only do a animation free zoom on a single level zoom, if someone does multiple levels then we always animate
|
|
if (c._isSingleParent() && previousZoomLevel - 1 === newZoomLevel) {
|
|
c.clusterShow();
|
|
c._recursivelyRemoveChildrenFromMap(bounds, mapMinZoom, previousZoomLevel); //Immediately remove our children as we are replacing them. TODO previousBounds not bounds
|
|
} else {
|
|
c.clusterHide();
|
|
}
|
|
|
|
c._addToMap();
|
|
}
|
|
);
|
|
},
|
|
|
|
_recursivelyBecomeVisible: function (bounds, zoomLevel) {
|
|
this._recursively(bounds, this._group._map.getMinZoom(), zoomLevel, null, function (c) {
|
|
c.clusterShow();
|
|
});
|
|
},
|
|
|
|
_recursivelyAddChildrenToMap: function (startPos, zoomLevel, bounds) {
|
|
this._recursively(bounds, this._group._map.getMinZoom() - 1, zoomLevel,
|
|
function (c) {
|
|
if (zoomLevel === c._zoom) {
|
|
return;
|
|
}
|
|
|
|
//Add our child markers at startPos (so they can be animated out)
|
|
for (var i = c._markers.length - 1; i >= 0; i--) {
|
|
var nm = c._markers[i];
|
|
|
|
if (!bounds.contains(nm._latlng)) {
|
|
continue;
|
|
}
|
|
|
|
if (startPos) {
|
|
nm._backupLatlng = nm.getLatLng();
|
|
|
|
nm.setLatLng(startPos);
|
|
if (nm.clusterHide) {
|
|
nm.clusterHide();
|
|
}
|
|
}
|
|
|
|
c._group._featureGroup.addLayer(nm);
|
|
}
|
|
},
|
|
function (c) {
|
|
c._addToMap(startPos);
|
|
}
|
|
);
|
|
},
|
|
|
|
_recursivelyRestoreChildPositions: function (zoomLevel) {
|
|
//Fix positions of child markers
|
|
for (var i = this._markers.length - 1; i >= 0; i--) {
|
|
var nm = this._markers[i];
|
|
if (nm._backupLatlng) {
|
|
nm.setLatLng(nm._backupLatlng);
|
|
delete nm._backupLatlng;
|
|
}
|
|
}
|
|
|
|
if (zoomLevel - 1 === this._zoom) {
|
|
//Reposition child clusters
|
|
for (var j = this._childClusters.length - 1; j >= 0; j--) {
|
|
this._childClusters[j]._restorePosition();
|
|
}
|
|
} else {
|
|
for (var k = this._childClusters.length - 1; k >= 0; k--) {
|
|
this._childClusters[k]._recursivelyRestoreChildPositions(zoomLevel);
|
|
}
|
|
}
|
|
},
|
|
|
|
_restorePosition: function () {
|
|
if (this._backupLatlng) {
|
|
this.setLatLng(this._backupLatlng);
|
|
delete this._backupLatlng;
|
|
}
|
|
},
|
|
|
|
//exceptBounds: If set, don't remove any markers/clusters in it
|
|
_recursivelyRemoveChildrenFromMap: function (previousBounds, mapMinZoom, zoomLevel, exceptBounds) {
|
|
var m, i;
|
|
this._recursively(previousBounds, mapMinZoom - 1, zoomLevel - 1,
|
|
function (c) {
|
|
//Remove markers at every level
|
|
for (i = c._markers.length - 1; i >= 0; i--) {
|
|
m = c._markers[i];
|
|
if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
|
|
c._group._featureGroup.removeLayer(m);
|
|
if (m.clusterShow) {
|
|
m.clusterShow();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
function (c) {
|
|
//Remove child clusters at just the bottom level
|
|
for (i = c._childClusters.length - 1; i >= 0; i--) {
|
|
m = c._childClusters[i];
|
|
if (!exceptBounds || !exceptBounds.contains(m._latlng)) {
|
|
c._group._featureGroup.removeLayer(m);
|
|
if (m.clusterShow) {
|
|
m.clusterShow();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
//Run the given functions recursively to this and child clusters
|
|
// boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to
|
|
// zoomLevelToStart: zoom level to start running functions (inclusive)
|
|
// zoomLevelToStop: zoom level to stop running functions (inclusive)
|
|
// runAtEveryLevel: function that takes an L.MarkerCluster as an argument that should be applied on every level
|
|
// runAtBottomLevel: function that takes an L.MarkerCluster as an argument that should be applied at only the bottom level
|
|
_recursively: function (boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) {
|
|
var childClusters = this._childClusters,
|
|
zoom = this._zoom,
|
|
i, c;
|
|
|
|
if (zoomLevelToStart <= zoom) {
|
|
if (runAtEveryLevel) {
|
|
runAtEveryLevel(this);
|
|
}
|
|
if (runAtBottomLevel && zoom === zoomLevelToStop) {
|
|
runAtBottomLevel(this);
|
|
}
|
|
}
|
|
|
|
if (zoom < zoomLevelToStart || zoom < zoomLevelToStop) {
|
|
for (i = childClusters.length - 1; i >= 0; i--) {
|
|
c = childClusters[i];
|
|
if (c._boundsNeedUpdate) {
|
|
c._recalculateBounds();
|
|
}
|
|
if (boundsToApplyTo.intersects(c._bounds)) {
|
|
c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
//Returns true if we are the parent of only one cluster and that cluster is the same as us
|
|
_isSingleParent: function () {
|
|
//Don't need to check this._markers as the rest won't work if there are any
|
|
return this._childClusters.length > 0 && this._childClusters[0]._childCount === this._childCount;
|
|
}
|
|
});
|
|
|
|
/*
|
|
* Extends L.Marker to include two extra methods: clusterHide and clusterShow.
|
|
*
|
|
* They work as setOpacity(0) and setOpacity(1) respectively, but
|
|
* don't overwrite the options.opacity
|
|
*
|
|
*/
|
|
|
|
L.Marker.include({
|
|
clusterHide: function () {
|
|
var backup = this.options.opacity;
|
|
this.setOpacity(0);
|
|
this.options.opacity = backup;
|
|
return this;
|
|
},
|
|
|
|
clusterShow: function () {
|
|
return this.setOpacity(this.options.opacity);
|
|
}
|
|
});
|
|
|
|
L.DistanceGrid = function (cellSize) {
|
|
this._cellSize = cellSize;
|
|
this._sqCellSize = cellSize * cellSize;
|
|
this._grid = {};
|
|
this._objectPoint = { };
|
|
};
|
|
|
|
L.DistanceGrid.prototype = {
|
|
|
|
addObject: function (obj, point) {
|
|
var x = this._getCoord(point.x),
|
|
y = this._getCoord(point.y),
|
|
grid = this._grid,
|
|
row = grid[y] = grid[y] || {},
|
|
cell = row[x] = row[x] || [],
|
|
stamp = L.Util.stamp(obj);
|
|
|
|
this._objectPoint[stamp] = point;
|
|
|
|
cell.push(obj);
|
|
},
|
|
|
|
updateObject: function (obj, point) {
|
|
this.removeObject(obj);
|
|
this.addObject(obj, point);
|
|
},
|
|
|
|
//Returns true if the object was found
|
|
removeObject: function (obj, point) {
|
|
var x = this._getCoord(point.x),
|
|
y = this._getCoord(point.y),
|
|
grid = this._grid,
|
|
row = grid[y] = grid[y] || {},
|
|
cell = row[x] = row[x] || [],
|
|
i, len;
|
|
|
|
delete this._objectPoint[L.Util.stamp(obj)];
|
|
|
|
for (i = 0, len = cell.length; i < len; i++) {
|
|
if (cell[i] === obj) {
|
|
|
|
cell.splice(i, 1);
|
|
|
|
if (len === 1) {
|
|
delete row[x];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
eachObject: function (fn, context) {
|
|
var i, j, k, len, row, cell, removed,
|
|
grid = this._grid;
|
|
|
|
for (i in grid) {
|
|
row = grid[i];
|
|
|
|
for (j in row) {
|
|
cell = row[j];
|
|
|
|
for (k = 0, len = cell.length; k < len; k++) {
|
|
removed = fn.call(context, cell[k]);
|
|
if (removed) {
|
|
k--;
|
|
len--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
getNearObject: function (point) {
|
|
var x = this._getCoord(point.x),
|
|
y = this._getCoord(point.y),
|
|
i, j, k, row, cell, len, obj, dist,
|
|
objectPoint = this._objectPoint,
|
|
closestDistSq = this._sqCellSize,
|
|
closest = null;
|
|
|
|
for (i = y - 1; i <= y + 1; i++) {
|
|
row = this._grid[i];
|
|
if (row) {
|
|
|
|
for (j = x - 1; j <= x + 1; j++) {
|
|
cell = row[j];
|
|
if (cell) {
|
|
|
|
for (k = 0, len = cell.length; k < len; k++) {
|
|
obj = cell[k];
|
|
dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point);
|
|
if (dist < closestDistSq ||
|
|
dist <= closestDistSq && closest === null) {
|
|
closestDistSq = dist;
|
|
closest = obj;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return closest;
|
|
},
|
|
|
|
_getCoord: function (x) {
|
|
var coord = Math.floor(x / this._cellSize);
|
|
return isFinite(coord) ? coord : x;
|
|
},
|
|
|
|
_sqDist: function (p, p2) {
|
|
var dx = p2.x - p.x,
|
|
dy = p2.y - p.y;
|
|
return dx * dx + dy * dy;
|
|
}
|
|
};
|
|
|
|
/* Copyright (c) 2012 the authors listed at the following URL, and/or
|
|
the authors of referenced articles or incorporated external code:
|
|
http://en.literateprograms.org/Quickhull_(Javascript)?action=history&offset=20120410175256
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Retrieved from: http://en.literateprograms.org/Quickhull_(Javascript)?oldid=18434
|
|
*/
|
|
|
|
(function () {
|
|
L.QuickHull = {
|
|
|
|
/*
|
|
* @param {Object} cpt a point to be measured from the baseline
|
|
* @param {Array} bl the baseline, as represented by a two-element
|
|
* array of latlng objects.
|
|
* @returns {Number} an approximate distance measure
|
|
*/
|
|
getDistant: function (cpt, bl) {
|
|
var vY = bl[1].lat - bl[0].lat,
|
|
vX = bl[0].lng - bl[1].lng;
|
|
return (vX * (cpt.lat - bl[0].lat) + vY * (cpt.lng - bl[0].lng));
|
|
},
|
|
|
|
/*
|
|
* @param {Array} baseLine a two-element array of latlng objects
|
|
* representing the baseline to project from
|
|
* @param {Array} latLngs an array of latlng objects
|
|
* @returns {Object} the maximum point and all new points to stay
|
|
* in consideration for the hull.
|
|
*/
|
|
findMostDistantPointFromBaseLine: function (baseLine, latLngs) {
|
|
var maxD = 0,
|
|
maxPt = null,
|
|
newPoints = [],
|
|
i, pt, d;
|
|
|
|
for (i = latLngs.length - 1; i >= 0; i--) {
|
|
pt = latLngs[i];
|
|
d = this.getDistant(pt, baseLine);
|
|
|
|
if (d > 0) {
|
|
newPoints.push(pt);
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (d > maxD) {
|
|
maxD = d;
|
|
maxPt = pt;
|
|
}
|
|
}
|
|
|
|
return { maxPoint: maxPt, newPoints: newPoints };
|
|
},
|
|
|
|
|
|
/*
|
|
* Given a baseline, compute the convex hull of latLngs as an array
|
|
* of latLngs.
|
|
*
|
|
* @param {Array} latLngs
|
|
* @returns {Array}
|
|
*/
|
|
buildConvexHull: function (baseLine, latLngs) {
|
|
var convexHullBaseLines = [],
|
|
t = this.findMostDistantPointFromBaseLine(baseLine, latLngs);
|
|
|
|
if (t.maxPoint) { // if there is still a point "outside" the base line
|
|
convexHullBaseLines =
|
|
convexHullBaseLines.concat(
|
|
this.buildConvexHull([baseLine[0], t.maxPoint], t.newPoints)
|
|
);
|
|
convexHullBaseLines =
|
|
convexHullBaseLines.concat(
|
|
this.buildConvexHull([t.maxPoint, baseLine[1]], t.newPoints)
|
|
);
|
|
return convexHullBaseLines;
|
|
} else { // if there is no more point "outside" the base line, the current base line is part of the convex hull
|
|
return [baseLine[0]];
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Given an array of latlngs, compute a convex hull as an array
|
|
* of latlngs
|
|
*
|
|
* @param {Array} latLngs
|
|
* @returns {Array}
|
|
*/
|
|
getConvexHull: function (latLngs) {
|
|
// find first baseline
|
|
var maxLat = false, minLat = false,
|
|
maxLng = false, minLng = false,
|
|
maxLatPt = null, minLatPt = null,
|
|
maxLngPt = null, minLngPt = null,
|
|
maxPt = null, minPt = null,
|
|
i;
|
|
|
|
for (i = latLngs.length - 1; i >= 0; i--) {
|
|
var pt = latLngs[i];
|
|
if (maxLat === false || pt.lat > maxLat) {
|
|
maxLatPt = pt;
|
|
maxLat = pt.lat;
|
|
}
|
|
if (minLat === false || pt.lat < minLat) {
|
|
minLatPt = pt;
|
|
minLat = pt.lat;
|
|
}
|
|
if (maxLng === false || pt.lng > maxLng) {
|
|
maxLngPt = pt;
|
|
maxLng = pt.lng;
|
|
}
|
|
if (minLng === false || pt.lng < minLng) {
|
|
minLngPt = pt;
|
|
minLng = pt.lng;
|
|
}
|
|
}
|
|
|
|
if (minLat !== maxLat) {
|
|
minPt = minLatPt;
|
|
maxPt = maxLatPt;
|
|
} else {
|
|
minPt = minLngPt;
|
|
maxPt = maxLngPt;
|
|
}
|
|
|
|
var ch = [].concat(this.buildConvexHull([minPt, maxPt], latLngs),
|
|
this.buildConvexHull([maxPt, minPt], latLngs));
|
|
return ch;
|
|
}
|
|
};
|
|
}());
|
|
|
|
L.MarkerCluster.include({
|
|
getConvexHull: function () {
|
|
var childMarkers = this.getAllChildMarkers(),
|
|
points = [],
|
|
p, i;
|
|
|
|
for (i = childMarkers.length - 1; i >= 0; i--) {
|
|
p = childMarkers[i].getLatLng();
|
|
points.push(p);
|
|
}
|
|
|
|
return L.QuickHull.getConvexHull(points);
|
|
}
|
|
});
|
|
|
|
//This code is 100% based on https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet
|
|
//Huge thanks to jawj for implementing it first to make my job easy :-)
|
|
|
|
L.MarkerCluster.include({
|
|
|
|
_2PI: Math.PI * 2,
|
|
_circleFootSeparation: 25, //related to circumference of circle
|
|
_circleStartAngle: 0,
|
|
|
|
_spiralFootSeparation: 28, //related to size of spiral (experiment!)
|
|
_spiralLengthStart: 11,
|
|
_spiralLengthFactor: 5,
|
|
|
|
_circleSpiralSwitchover: 9, //show spiral instead of circle from this marker count upwards.
|
|
// 0 -> always spiral; Infinity -> always circle
|
|
|
|
spiderfy: function () {
|
|
if (this._group._spiderfied === this || this._group._inZoomAnimation) {
|
|
return;
|
|
}
|
|
|
|
var childMarkers = this.getAllChildMarkers(null, true),
|
|
group = this._group,
|
|
map = group._map,
|
|
center = map.latLngToLayerPoint(this._latlng),
|
|
positions;
|
|
|
|
this._group._unspiderfy();
|
|
this._group._spiderfied = this;
|
|
|
|
//TODO Maybe: childMarkers order by distance to center
|
|
|
|
if (childMarkers.length >= this._circleSpiralSwitchover) {
|
|
positions = this._generatePointsSpiral(childMarkers.length, center);
|
|
} else {
|
|
center.y += 10; // Otherwise circles look wrong => hack for standard blue icon, renders differently for other icons.
|
|
positions = this._generatePointsCircle(childMarkers.length, center);
|
|
}
|
|
|
|
this._animationSpiderfy(childMarkers, positions);
|
|
},
|
|
|
|
unspiderfy: function (zoomDetails) {
|
|
/// <param Name="zoomDetails">Argument from zoomanim if being called in a zoom animation or null otherwise</param>
|
|
if (this._group._inZoomAnimation) {
|
|
return;
|
|
}
|
|
this._animationUnspiderfy(zoomDetails);
|
|
|
|
this._group._spiderfied = null;
|
|
},
|
|
|
|
_generatePointsCircle: function (count, centerPt) {
|
|
var circumference = this._group.options.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count),
|
|
legLength = circumference / this._2PI, //radius from circumference
|
|
angleStep = this._2PI / count,
|
|
res = [],
|
|
i, angle;
|
|
|
|
legLength = Math.max(legLength, 35); // Minimum distance to get outside the cluster icon.
|
|
|
|
res.length = count;
|
|
|
|
for (i = 0; i < count; i++) { // Clockwise, like spiral.
|
|
angle = this._circleStartAngle + i * angleStep;
|
|
res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round();
|
|
}
|
|
|
|
return res;
|
|
},
|
|
|
|
_generatePointsSpiral: function (count, centerPt) {
|
|
var spiderfyDistanceMultiplier = this._group.options.spiderfyDistanceMultiplier,
|
|
legLength = spiderfyDistanceMultiplier * this._spiralLengthStart,
|
|
separation = spiderfyDistanceMultiplier * this._spiralFootSeparation,
|
|
lengthFactor = spiderfyDistanceMultiplier * this._spiralLengthFactor * this._2PI,
|
|
angle = 0,
|
|
res = [],
|
|
i;
|
|
|
|
res.length = count;
|
|
|
|
// Higher index, closer position to cluster center.
|
|
for (i = count; i >= 0; i--) {
|
|
// Skip the first position, so that we are already farther from center and we avoid
|
|
// being under the default cluster icon (especially important for Circle Markers).
|
|
if (i < count) {
|
|
res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round();
|
|
}
|
|
angle += separation / legLength + i * 0.0005;
|
|
legLength += lengthFactor / angle;
|
|
}
|
|
return res;
|
|
},
|
|
|
|
_noanimationUnspiderfy: function () {
|
|
var group = this._group,
|
|
map = group._map,
|
|
fg = group._featureGroup,
|
|
childMarkers = this.getAllChildMarkers(null, true),
|
|
m, i;
|
|
|
|
group._ignoreMove = true;
|
|
|
|
this.setOpacity(1);
|
|
for (i = childMarkers.length - 1; i >= 0; i--) {
|
|
m = childMarkers[i];
|
|
|
|
fg.removeLayer(m);
|
|
|
|
if (m._preSpiderfyLatlng) {
|
|
m.setLatLng(m._preSpiderfyLatlng);
|
|
delete m._preSpiderfyLatlng;
|
|
}
|
|
if (m.setZIndexOffset) {
|
|
m.setZIndexOffset(0);
|
|
}
|
|
|
|
if (m._spiderLeg) {
|
|
map.removeLayer(m._spiderLeg);
|
|
delete m._spiderLeg;
|
|
}
|
|
}
|
|
|
|
group.fire('unspiderfied', {
|
|
cluster: this,
|
|
markers: childMarkers
|
|
});
|
|
group._ignoreMove = false;
|
|
group._spiderfied = null;
|
|
}
|
|
});
|
|
|
|
//Non Animated versions of everything
|
|
L.MarkerClusterNonAnimated = L.MarkerCluster.extend({
|
|
_animationSpiderfy: function (childMarkers, positions) {
|
|
var group = this._group,
|
|
map = group._map,
|
|
fg = group._featureGroup,
|
|
legOptions = this._group.options.spiderLegPolylineOptions,
|
|
i, m, leg, newPos;
|
|
|
|
group._ignoreMove = true;
|
|
|
|
// Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
|
|
// The reverse order trick no longer improves performance on modern browsers.
|
|
for (i = 0; i < childMarkers.length; i++) {
|
|
newPos = map.layerPointToLatLng(positions[i]);
|
|
m = childMarkers[i];
|
|
|
|
// Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
|
|
leg = new L.Polyline([this._latlng, newPos], legOptions);
|
|
map.addLayer(leg);
|
|
m._spiderLeg = leg;
|
|
|
|
// Now add the marker.
|
|
m._preSpiderfyLatlng = m._latlng;
|
|
m.setLatLng(newPos);
|
|
if (m.setZIndexOffset) {
|
|
m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING
|
|
}
|
|
|
|
fg.addLayer(m);
|
|
}
|
|
this.setOpacity(0.3);
|
|
|
|
group._ignoreMove = false;
|
|
group.fire('spiderfied', {
|
|
cluster: this,
|
|
markers: childMarkers
|
|
});
|
|
},
|
|
|
|
_animationUnspiderfy: function () {
|
|
this._noanimationUnspiderfy();
|
|
}
|
|
});
|
|
|
|
//Animated versions here
|
|
L.MarkerCluster.include({
|
|
|
|
_animationSpiderfy: function (childMarkers, positions) {
|
|
var me = this,
|
|
group = this._group,
|
|
map = group._map,
|
|
fg = group._featureGroup,
|
|
thisLayerLatLng = this._latlng,
|
|
thisLayerPos = map.latLngToLayerPoint(thisLayerLatLng),
|
|
svg = L.Path.SVG,
|
|
legOptions = L.extend({}, this._group.options.spiderLegPolylineOptions), // Copy the options so that we can modify them for animation.
|
|
finalLegOpacity = legOptions.opacity,
|
|
i, m, leg, legPath, legLength, newPos;
|
|
|
|
if (finalLegOpacity === undefined) {
|
|
finalLegOpacity = L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity;
|
|
}
|
|
|
|
if (svg) {
|
|
// If the initial opacity of the spider leg is not 0 then it appears before the animation starts.
|
|
legOptions.opacity = 0;
|
|
|
|
// Add the class for CSS transitions.
|
|
legOptions.className = (legOptions.className || '') + ' leaflet-cluster-spider-leg';
|
|
} else {
|
|
// Make sure we have a defined opacity.
|
|
legOptions.opacity = finalLegOpacity;
|
|
}
|
|
|
|
group._ignoreMove = true;
|
|
|
|
// Add markers and spider legs to map, hidden at our center point.
|
|
// Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition.
|
|
// The reverse order trick no longer improves performance on modern browsers.
|
|
for (i = 0; i < childMarkers.length; i++) {
|
|
m = childMarkers[i];
|
|
|
|
newPos = map.layerPointToLatLng(positions[i]);
|
|
|
|
// Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it.
|
|
leg = new L.Polyline([thisLayerLatLng, newPos], legOptions);
|
|
map.addLayer(leg);
|
|
m._spiderLeg = leg;
|
|
|
|
// Explanations: https://jakearchibald.com/2013/animated-line-drawing-svg/
|
|
// In our case the transition property is declared in the CSS file.
|
|
if (svg) {
|
|
legPath = leg._path;
|
|
legLength = legPath.getTotalLength() + 0.1; // Need a small extra length to avoid remaining dot in Firefox.
|
|
legPath.style.strokeDasharray = legLength; // Just 1 length is enough, it will be duplicated.
|
|
legPath.style.strokeDashoffset = legLength;
|
|
}
|
|
|
|
// If it is a marker, add it now and we'll animate it out
|
|
if (m.setZIndexOffset) {
|
|
m.setZIndexOffset(1000000); // Make normal markers appear on top of EVERYTHING
|
|
}
|
|
if (m.clusterHide) {
|
|
m.clusterHide();
|
|
}
|
|
|
|
// Vectors just get immediately added
|
|
fg.addLayer(m);
|
|
|
|
if (m._setPos) {
|
|
m._setPos(thisLayerPos);
|
|
}
|
|
}
|
|
|
|
group._forceLayout();
|
|
group._animationStart();
|
|
|
|
// Reveal markers and spider legs.
|
|
for (i = childMarkers.length - 1; i >= 0; i--) {
|
|
newPos = map.layerPointToLatLng(positions[i]);
|
|
m = childMarkers[i];
|
|
|
|
//Move marker to new position
|
|
m._preSpiderfyLatlng = m._latlng;
|
|
m.setLatLng(newPos);
|
|
|
|
if (m.clusterShow) {
|
|
m.clusterShow();
|
|
}
|
|
|
|
// Animate leg (animation is actually delegated to CSS transition).
|
|
if (svg) {
|
|
leg = m._spiderLeg;
|
|
legPath = leg._path;
|
|
legPath.style.strokeDashoffset = 0;
|
|
//legPath.style.strokeOpacity = finalLegOpacity;
|
|
leg.setStyle({opacity: finalLegOpacity});
|
|
}
|
|
}
|
|
this.setOpacity(0.3);
|
|
|
|
group._ignoreMove = false;
|
|
|
|
setTimeout(function () {
|
|
group._animationEnd();
|
|
group.fire('spiderfied', {
|
|
cluster: me,
|
|
markers: childMarkers
|
|
});
|
|
}, 200);
|
|
},
|
|
|
|
_animationUnspiderfy: function (zoomDetails) {
|
|
var me = this,
|
|
group = this._group,
|
|
map = group._map,
|
|
fg = group._featureGroup,
|
|
thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng),
|
|
childMarkers = this.getAllChildMarkers(null, true),
|
|
svg = L.Path.SVG,
|
|
m, i, leg, legPath, legLength, nonAnimatable;
|
|
|
|
group._ignoreMove = true;
|
|
group._animationStart();
|
|
|
|
//Make us visible and bring the child markers back in
|
|
this.setOpacity(1);
|
|
for (i = childMarkers.length - 1; i >= 0; i--) {
|
|
m = childMarkers[i];
|
|
|
|
//Marker was added to us after we were spiderfied
|
|
if (!m._preSpiderfyLatlng) {
|
|
continue;
|
|
}
|
|
|
|
//Close any popup on the marker first, otherwise setting the location of the marker will make the map scroll
|
|
m.closePopup();
|
|
|
|
//Fix up the location to the real one
|
|
m.setLatLng(m._preSpiderfyLatlng);
|
|
delete m._preSpiderfyLatlng;
|
|
|
|
//Hack override the location to be our center
|
|
nonAnimatable = true;
|
|
if (m._setPos) {
|
|
m._setPos(thisLayerPos);
|
|
nonAnimatable = false;
|
|
}
|
|
if (m.clusterHide) {
|
|
m.clusterHide();
|
|
nonAnimatable = false;
|
|
}
|
|
if (nonAnimatable) {
|
|
fg.removeLayer(m);
|
|
}
|
|
|
|
// Animate the spider leg back in (animation is actually delegated to CSS transition).
|
|
if (svg) {
|
|
leg = m._spiderLeg;
|
|
legPath = leg._path;
|
|
legLength = legPath.getTotalLength() + 0.1;
|
|
legPath.style.strokeDashoffset = legLength;
|
|
leg.setStyle({opacity: 0});
|
|
}
|
|
}
|
|
|
|
group._ignoreMove = false;
|
|
|
|
setTimeout(function () {
|
|
//If we have only <= one child left then that marker will be shown on the map so don't remove it!
|
|
var stillThereChildCount = 0;
|
|
for (i = childMarkers.length - 1; i >= 0; i--) {
|
|
m = childMarkers[i];
|
|
if (m._spiderLeg) {
|
|
stillThereChildCount++;
|
|
}
|
|
}
|
|
|
|
|
|
for (i = childMarkers.length - 1; i >= 0; i--) {
|
|
m = childMarkers[i];
|
|
|
|
if (!m._spiderLeg) { //Has already been unspiderfied
|
|
continue;
|
|
}
|
|
|
|
if (m.clusterShow) {
|
|
m.clusterShow();
|
|
}
|
|
if (m.setZIndexOffset) {
|
|
m.setZIndexOffset(0);
|
|
}
|
|
|
|
if (stillThereChildCount > 1) {
|
|
fg.removeLayer(m);
|
|
}
|
|
|
|
map.removeLayer(m._spiderLeg);
|
|
delete m._spiderLeg;
|
|
}
|
|
group._animationEnd();
|
|
group.fire('unspiderfied', {
|
|
cluster: me,
|
|
markers: childMarkers
|
|
});
|
|
}, 200);
|
|
}
|
|
});
|
|
|
|
|
|
L.MarkerClusterGroup.include({
|
|
//The MarkerCluster currently spiderfied (if any)
|
|
_spiderfied: null,
|
|
|
|
unspiderfy: function () {
|
|
this._unspiderfy.apply(this, arguments);
|
|
},
|
|
|
|
_spiderfierOnAdd: function () {
|
|
this._map.on('click', this._unspiderfyWrapper, this);
|
|
|
|
if (this._map.options.zoomAnimation) {
|
|
this._map.on('zoomstart', this._unspiderfyZoomStart, this);
|
|
}
|
|
//Browsers without zoomAnimation or a big zoom don't fire zoomstart
|
|
this._map.on('zoomend', this._noanimationUnspiderfy, this);
|
|
|
|
if (!L.Browser.touch) {
|
|
this._map.getRenderer(this);
|
|
//Needs to happen in the pageload, not after, or animations don't work in webkit
|
|
// http://stackoverflow.com/questions/8455200/svg-animate-with-dynamically-added-elements
|
|
//Disable on touch browsers as the animation messes up on a touch zoom and isn't very noticable
|
|
}
|
|
},
|
|
|
|
_spiderfierOnRemove: function () {
|
|
this._map.off('click', this._unspiderfyWrapper, this);
|
|
this._map.off('zoomstart', this._unspiderfyZoomStart, this);
|
|
this._map.off('zoomanim', this._unspiderfyZoomAnim, this);
|
|
this._map.off('zoomend', this._noanimationUnspiderfy, this);
|
|
|
|
//Ensure that markers are back where they should be
|
|
// Use no animation to avoid a sticky leaflet-cluster-anim class on mapPane
|
|
this._noanimationUnspiderfy();
|
|
},
|
|
|
|
//On zoom start we add a zoomanim handler so that we are guaranteed to be last (after markers are animated)
|
|
//This means we can define the animation they do rather than Markers doing an animation to their actual location
|
|
_unspiderfyZoomStart: function () {
|
|
if (!this._map) { //May have been removed from the map by a zoomEnd handler
|
|
return;
|
|
}
|
|
|
|
this._map.on('zoomanim', this._unspiderfyZoomAnim, this);
|
|
},
|
|
|
|
_unspiderfyZoomAnim: function (zoomDetails) {
|
|
//Wait until the first zoomanim after the user has finished touch-zooming before running the animation
|
|
if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) {
|
|
return;
|
|
}
|
|
|
|
this._map.off('zoomanim', this._unspiderfyZoomAnim, this);
|
|
this._unspiderfy(zoomDetails);
|
|
},
|
|
|
|
_unspiderfyWrapper: function () {
|
|
/// <summary>_unspiderfy but passes no arguments</summary>
|
|
this._unspiderfy();
|
|
},
|
|
|
|
_unspiderfy: function (zoomDetails) {
|
|
if (this._spiderfied) {
|
|
this._spiderfied.unspiderfy(zoomDetails);
|
|
}
|
|
},
|
|
|
|
_noanimationUnspiderfy: function () {
|
|
if (this._spiderfied) {
|
|
this._spiderfied._noanimationUnspiderfy();
|
|
}
|
|
},
|
|
|
|
//If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc
|
|
_unspiderfyLayer: function (layer) {
|
|
if (layer._spiderLeg) {
|
|
this._featureGroup.removeLayer(layer);
|
|
|
|
if (layer.clusterShow) {
|
|
layer.clusterShow();
|
|
}
|
|
//Position will be fixed up immediately in _animationUnspiderfy
|
|
if (layer.setZIndexOffset) {
|
|
layer.setZIndexOffset(0);
|
|
}
|
|
|
|
this._map.removeLayer(layer._spiderLeg);
|
|
delete layer._spiderLeg;
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Adds 1 public method to MCG and 1 to L.Marker to facilitate changing
|
|
* markers' icon options and refreshing their icon and their parent clusters
|
|
* accordingly (case where their iconCreateFunction uses data of childMarkers
|
|
* to make up the cluster icon).
|
|
*/
|
|
|
|
|
|
L.MarkerClusterGroup.include({
|
|
/**
|
|
* Updates the icon of all clusters which are parents of the given marker(s).
|
|
* In singleMarkerMode, also updates the given marker(s) icon.
|
|
* @param layers L.MarkerClusterGroup|L.LayerGroup|Array(L.Marker)|Map(L.Marker)|
|
|
* L.MarkerCluster|L.Marker (optional) list of markers (or single marker) whose parent
|
|
* clusters need to be updated. If not provided, retrieves all child markers of this.
|
|
* @returns {L.MarkerClusterGroup}
|
|
*/
|
|
refreshClusters: function (layers) {
|
|
if (!layers) {
|
|
layers = this._topClusterLevel.getAllChildMarkers();
|
|
} else if (layers instanceof L.MarkerClusterGroup) {
|
|
layers = layers._topClusterLevel.getAllChildMarkers();
|
|
} else if (layers instanceof L.LayerGroup) {
|
|
layers = layers._layers;
|
|
} else if (layers instanceof L.MarkerCluster) {
|
|
layers = layers.getAllChildMarkers();
|
|
} else if (layers instanceof L.Marker) {
|
|
layers = [layers];
|
|
} // else: must be an Array(L.Marker)|Map(L.Marker)
|
|
this._flagParentsIconsNeedUpdate(layers);
|
|
this._refreshClustersIcons();
|
|
|
|
// In case of singleMarkerMode, also re-draw the markers.
|
|
if (this.options.singleMarkerMode) {
|
|
this._refreshSingleMarkerModeMarkers(layers);
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Simply flags all parent clusters of the given markers as having a "dirty" icon.
|
|
* @param layers Array(L.Marker)|Map(L.Marker) list of markers.
|
|
* @private
|
|
*/
|
|
_flagParentsIconsNeedUpdate: function (layers) {
|
|
var id, parent;
|
|
|
|
// Assumes layers is an Array or an Object whose prototype is non-enumerable.
|
|
for (id in layers) {
|
|
// Flag parent clusters' icon as "dirty", all the way up.
|
|
// Dumb process that flags multiple times upper parents, but still
|
|
// much more efficient than trying to be smart and make short lists,
|
|
// at least in the case of a hierarchy following a power law:
|
|
// http://jsperf.com/flag-nodes-in-power-hierarchy/2
|
|
parent = layers[id].__parent;
|
|
while (parent) {
|
|
parent._iconNeedsUpdate = true;
|
|
parent = parent.__parent;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Re-draws the icon of the supplied markers.
|
|
* To be used in singleMarkerMode only.
|
|
* @param layers Array(L.Marker)|Map(L.Marker) list of markers.
|
|
* @private
|
|
*/
|
|
_refreshSingleMarkerModeMarkers: function (layers) {
|
|
var id, layer;
|
|
|
|
for (id in layers) {
|
|
layer = layers[id];
|
|
|
|
// Make sure we do not override markers that do not belong to THIS group.
|
|
if (this.hasLayer(layer)) {
|
|
// Need to re-create the icon first, then re-draw the marker.
|
|
layer.setIcon(this._overrideMarkerIcon(layer));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
L.Marker.include({
|
|
/**
|
|
* Updates the given options in the marker's icon and refreshes the marker.
|
|
* @param options map object of icon options.
|
|
* @param directlyRefreshClusters boolean (optional) true to trigger
|
|
* MCG.refreshClustersOf() right away with this single marker.
|
|
* @returns {L.Marker}
|
|
*/
|
|
refreshIconOptions: function (options, directlyRefreshClusters) {
|
|
var icon = this.options.icon;
|
|
|
|
L.setOptions(icon, options);
|
|
|
|
this.setIcon(icon);
|
|
|
|
// Shortcut to refresh the associated MCG clusters right away.
|
|
// To be used when refreshing a single marker.
|
|
// Otherwise, better use MCG.refreshClusters() once at the end with
|
|
// the list of modified markers.
|
|
if (directlyRefreshClusters && this.__parent) {
|
|
this.__parent._group.refreshClusters(this);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
});
|
|
|
|
exports.MarkerClusterGroup = MarkerClusterGroup;
|
|
exports.MarkerCluster = MarkerCluster;
|
|
|
|
})));
|
|
/*
|
|
Leaflet.AwesomeMarkers, a plugin that adds colorful iconic markers for Leaflet, based on the Font Awesome icons
|
|
(c) 2012-2013, Lennard Voogdt
|
|
|
|
http://leafletjs.com
|
|
https://github.com/lvoogdt
|
|
*/
|
|
|
|
/*global L*/
|
|
|
|
(function (window, document, undefined) {
|
|
"use strict";
|
|
/*
|
|
* Leaflet.AwesomeMarkers assumes that you have already included the Leaflet library.
|
|
*/
|
|
|
|
L.AwesomeMarkers = {};
|
|
|
|
L.AwesomeMarkers.version = '2.0.1';
|
|
|
|
L.AwesomeMarkers.Icon = L.Icon.extend({
|
|
options: {
|
|
iconSize: [35, 45],
|
|
iconAnchor: [17, 42],
|
|
popupAnchor: [1, -32],
|
|
shadowAnchor: [10, 12],
|
|
shadowSize: [36, 16],
|
|
className: 'awesome-marker',
|
|
prefix: 'glyphicon',
|
|
spinClass: 'fa-spin',
|
|
extraClasses: '',
|
|
icon: 'home',
|
|
markerColor: 'blue',
|
|
iconColor: 'white'
|
|
},
|
|
|
|
initialize: function (options) {
|
|
options = L.Util.setOptions(this, options);
|
|
},
|
|
|
|
createIcon: function () {
|
|
var div = document.createElement('div'),
|
|
options = this.options;
|
|
|
|
if (options.icon) {
|
|
div.innerHTML = this._createInner();
|
|
}
|
|
|
|
if (options.bgPos) {
|
|
div.style.backgroundPosition =
|
|
(-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px';
|
|
}
|
|
|
|
this._setIconStyles(div, 'icon-' + options.markerColor);
|
|
return div;
|
|
},
|
|
|
|
_createInner: function() {
|
|
var iconClass, iconSpinClass = "", iconColorClass = "", iconColorStyle = "", options = this.options;
|
|
|
|
if(options.icon.slice(0,options.prefix.length+1) === options.prefix + "-") {
|
|
iconClass = options.icon;
|
|
} else {
|
|
iconClass = options.prefix + "-" + options.icon;
|
|
}
|
|
|
|
if(options.spin && typeof options.spinClass === "string") {
|
|
iconSpinClass = options.spinClass;
|
|
}
|
|
|
|
if(options.iconColor) {
|
|
if(options.iconColor === 'white' || options.iconColor === 'black') {
|
|
iconColorClass = "icon-" + options.iconColor;
|
|
} else {
|
|
iconColorStyle = "style='color: " + options.iconColor + "' ";
|
|
}
|
|
}
|
|
|
|
return "<i " + iconColorStyle + "class='" + options.extraClasses + " " + options.prefix + " " + iconClass + " " + iconSpinClass + " " + iconColorClass + "'></i>";
|
|
},
|
|
|
|
_setIconStyles: function (img, name) {
|
|
var options = this.options,
|
|
size = L.point(options[name === 'shadow' ? 'shadowSize' : 'iconSize']),
|
|
anchor;
|
|
|
|
if (name === 'shadow') {
|
|
anchor = L.point(options.shadowAnchor || options.iconAnchor);
|
|
} else {
|
|
anchor = L.point(options.iconAnchor);
|
|
}
|
|
|
|
if (!anchor && size) {
|
|
anchor = size.divideBy(2, true);
|
|
}
|
|
|
|
img.className = 'awesome-marker-' + name + ' ' + options.className;
|
|
|
|
if (anchor) {
|
|
img.style.marginLeft = (-anchor.x) + 'px';
|
|
img.style.marginTop = (-anchor.y) + 'px';
|
|
}
|
|
|
|
if (size) {
|
|
img.style.width = size.x + 'px';
|
|
img.style.height = size.y + 'px';
|
|
}
|
|
},
|
|
|
|
createShadow: function () {
|
|
var div = document.createElement('div');
|
|
|
|
this._setIconStyles(div, 'shadow');
|
|
return div;
|
|
}
|
|
});
|
|
|
|
L.AwesomeMarkers.icon = function (options) {
|
|
return new L.AwesomeMarkers.Icon(options);
|
|
};
|
|
|
|
}(this, document));
|
|
|
|
|
|
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
$('#event_start_time').change(function() {
|
|
if ($('#event_start_time').val() >= $('#event_end_time').val()) {
|
|
return $('#event_end_time').val($('#event_start_time').val());
|
|
}
|
|
});
|
|
$('#event_end_time').change(function() {
|
|
if ($('#event_start_time').val() >= $('#event_end_time').val()) {
|
|
return $('#event_start_time').val($('#event_end_time').val());
|
|
}
|
|
});
|
|
$('#event_repeat').each(function() {
|
|
if ($(this).val() === '0') {
|
|
$('.field.rule').hide();
|
|
}
|
|
return $(this).change(function() {
|
|
if ($(this).val() > 0) {
|
|
$('.field.rule').show();
|
|
return $('.field.rule input').attr('required', 'required');
|
|
} else {
|
|
$('.field.rule').hide();
|
|
return $('.field.rule input').removeAttr('required');
|
|
}
|
|
});
|
|
});
|
|
return $('#event_tags').each(function() {
|
|
var elt;
|
|
elt = $(this);
|
|
return $.ajax({
|
|
url: '/tags.json'
|
|
}).done(function(data) {
|
|
var tags;
|
|
return tags = jQuery.map(data, function(n) {
|
|
return n[0];
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
$('body.pages form :input').prop('disabled', false);
|
|
return $('form').submit(function() {
|
|
$('input[name=utf8]').prop('disabled', true);
|
|
return $('button').prop('disabled', true);
|
|
});
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {});
|
|
|
|
}).call(this);
|
|
|
|
/*
|
|
@licstart The following is the entire license notice for the JavaScript code in this page.
|
|
|
|
frTypo, la typographie française simplifiée
|
|
|
|
Copyright (C) 2013 acoeuro
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
@licend The above is the entire license notice for the JavaScript code in this page.
|
|
*/
|
|
|
|
(function() {
|
|
var regexp, regexpPost;
|
|
|
|
regexp = /(^|[\wàéèêç])\s*([!?:;»%€¢]+)(\s|[^\w\/]|$)/g;
|
|
|
|
regexpPost = /([«])\s*([\w])/g;
|
|
|
|
$(document).on('turbolinks:load', function() {
|
|
if ($('html').attr('lang') === 'fr') {
|
|
return $('body *').contents().filter(function() {
|
|
return this.nodeType === Node.TEXT_NODE;
|
|
}).filter(function() {
|
|
return 0 > ['CODE', 'PRE', 'STYLE', 'TEXTAREA'].indexOf(this.parentNode.tagName);
|
|
}).filter(function() {
|
|
return !$(this).parent().hasClass('finePre') && !$(this).parent().hasClass('start_time') && !$(this).parent().hasClass('end_time');
|
|
}).filter(function() {
|
|
return (this.nodeValue.match(regexp) != null) || (this.nodeValue.match(regexpPost) != null);
|
|
}).each(function() {
|
|
return $(this).replaceWith(function() {
|
|
return this.nodeValue.replace(regexp, '$1<span class="finePre">$2</span>$3').replace(regexpPost, '<span class="finePost">$1</span>$2');
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
$('#map.list').each(function() {
|
|
var controls, map;
|
|
map = L.map('map');
|
|
map.fitBounds([[60, -20], [30, 30]]);
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© <a href="https://osm.org/copyright">OpenStreetMap</a>'
|
|
}).addTo(map);
|
|
controls = L.control.layers(null, null, {
|
|
collapsed: false
|
|
}).addTo(map);
|
|
return $('li a', this).each(function() {
|
|
var markerColor, text, url;
|
|
url = $(this).attr('href');
|
|
text = $(this).html();
|
|
markerColor = $('.awesome-marker', this).attr('class').substr('awesome-marker awesome-marker-icon-'.length);
|
|
if (location.search && url.indexOf('?') >= 0) {
|
|
url += '&' + location.search.substr(1);
|
|
} else {
|
|
url += location.search;
|
|
}
|
|
return $.getJSON(url, function(json) {
|
|
var layer;
|
|
if (!(json != null ? json.length : void 0)) {
|
|
return;
|
|
}
|
|
layer = L.markerClusterGroup({
|
|
maxClusterRadius: 30
|
|
}).addLayer(L.geoJson(json, {
|
|
pointToLayer: function(feature, latlng) {
|
|
var marker;
|
|
marker = L.AwesomeMarkers.icon({
|
|
prefix: 'fa',
|
|
icon: feature.properties.icon || 'calendar',
|
|
markerColor: markerColor
|
|
});
|
|
return L.marker(latlng, {
|
|
icon: marker
|
|
});
|
|
},
|
|
onEachFeature: function(feature, layer) {
|
|
if (feature.properties && feature.properties.popupContent) {
|
|
return layer.bindPopup(feature.properties.popupContent);
|
|
}
|
|
}
|
|
}));
|
|
map.addLayer(layer);
|
|
controls.addOverlay(layer, text + ' - ' + json.length);
|
|
if ((/maps\//.test(location.href) || /maps.json/.test(url)) && layer.getBounds()._northEast && layer.getBounds()._southWest) {
|
|
return map.fitBounds(layer.getBounds());
|
|
}
|
|
});
|
|
});
|
|
});
|
|
return $('#map.event, #map.orga').each(function() {
|
|
var coord, map, marker, url;
|
|
coord = [$(this).data('latitude'), $(this).data('longitude')];
|
|
map = L.map('map').setView([coord[0], coord[1]], 16);
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© <a href="https://osm.org/copyright">OpenStreetMap</a>'
|
|
}).addTo(map);
|
|
url = $(this).data('url');
|
|
if (location.search && url.indexOf('?') >= 0) {
|
|
url += '&' + location.search.substr(1);
|
|
} else {
|
|
url += location.search;
|
|
}
|
|
marker = L.AwesomeMarkers.icon({
|
|
prefix: 'fa',
|
|
icon: $(this).data('icon') || 'calendar',
|
|
markerColor: 'darkred'
|
|
});
|
|
L.marker([coord[0], coord[1]], {
|
|
icon: marker
|
|
}).addTo(map);
|
|
return $.getJSON(url, function(json) {
|
|
var layer;
|
|
layer = L.markerClusterGroup({
|
|
maxClusterRadius: 30
|
|
}).addLayer(L.geoJson(json, {
|
|
pointToLayer: function(feature, latlng) {
|
|
marker = L.AwesomeMarkers.icon({
|
|
prefix: 'fa',
|
|
icon: feature.properties.icon || 'calendar',
|
|
markerColor: 'blue'
|
|
});
|
|
return L.marker(latlng, {
|
|
icon: marker
|
|
});
|
|
},
|
|
onEachFeature: function(feature, layer) {
|
|
if (feature.properties && feature.properties.popupContent) {
|
|
return layer.bindPopup(feature.properties.popupContent);
|
|
}
|
|
}
|
|
}));
|
|
return map.addLayer(layer);
|
|
});
|
|
});
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
$('body.moderations .radios label').click(function() {
|
|
return $('body.moderations #event_reason').parent().slideUp();
|
|
});
|
|
return $('body.moderations .radios label:last-child').click(function() {
|
|
return $('body.moderations #event_reason').parent().slideDown();
|
|
});
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
|
|
|
|
}).call(this);
|
|
(function() {
|
|
|
|
|
|
}).call(this);
|
|
(function() {
|
|
var showPosition;
|
|
|
|
$(document).on('turbolinks:load', function() {
|
|
if (!navigator.geolocation) {
|
|
return;
|
|
}
|
|
return $('a.near-me').click(function(event) {
|
|
event.preventDefault();
|
|
window.goto = event.target.href;
|
|
return navigator.geolocation.getCurrentPosition(showPosition, function(error) {
|
|
switch (error.code) {
|
|
case error.PERMISSION_DENIED:
|
|
return $('ul.regions li#near-me').remove();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
showPosition = function(position) {
|
|
return location.replace(window.goto.replace('[me]', "[" + position.coords.latitude + ", " + position.coords.longitude + "]"));
|
|
};
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
return $('.pagination .next a').attr('data-remote', true).each(function() {
|
|
return $(document).scroll((function(_this) {
|
|
return function() {
|
|
if ($(_this).visible(true, true)) {
|
|
return $(_this).click().parents('.pagination').hide();
|
|
}
|
|
};
|
|
})(this));
|
|
});
|
|
});
|
|
|
|
$(document).on('ajax:success', '.pagination .next a', function(event, data) {
|
|
var next;
|
|
$(this).parents('tfoot').prev().append($('tbody tr', data));
|
|
next = $('.pagination .next a', data).attr('href');
|
|
if (next != null) {
|
|
return $(this).attr('href', next).parents('.pagination').show();
|
|
}
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
return tinyMCE.init({
|
|
width: '100%',
|
|
height: '40em',
|
|
menubar: false,
|
|
branding: false,
|
|
language: 'fr_FR',
|
|
selector: 'input.description',
|
|
content_css: '/assets/application-8002eadc07c8d58b56bad6f45a5e2607344c903abacfe94121bd35aa25f764a8.css',
|
|
entity_encoding: 'raw',
|
|
add_unload_trigger: true,
|
|
browser_spellcheck: true,
|
|
style_formats_autohide: true,
|
|
toolbar: [' cut copy paste | undo redo | link image media charmap table | code visualblocks searchreplace', ' removeformat bold italic strikethrough superscript subscript | bullist numlist outdent indent | alignleft aligncenter alignright alignjustify alignnone'],
|
|
plugins: 'lists advlist autolink link image charmap paste print preview table fullscreen searchreplace media insertdatetime visualblocks wordcount code'
|
|
});
|
|
});
|
|
|
|
$(document).on('turbolinks:before-cache', function() {
|
|
return tinymce.remove();
|
|
});
|
|
|
|
}).call(this);
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
$('table.list.dates tbody tr').each(function() {
|
|
var vals;
|
|
vals = $(this).find('td.quantity').map(function() {
|
|
var val;
|
|
val = $(this).find('a').html().replace(' ', '').trim();
|
|
if (val && val !== '') {
|
|
return parseInt(val);
|
|
} else {
|
|
return 0;
|
|
}
|
|
});
|
|
return $(this).find('.sparkline').sparkline(vals, {
|
|
width: '5em'
|
|
});
|
|
});
|
|
return $('table.list.dates tfoot').each(function() {
|
|
var vals;
|
|
vals = $(this).find('th.quantity').map(function() {
|
|
return parseInt($(this).html().replace(' ', ''));
|
|
});
|
|
return $(this).find('.sparkline').sparkline(vals, {
|
|
type: 'bar',
|
|
height: '3em',
|
|
barWidth: '100%',
|
|
barColor: '#9CC5EE',
|
|
barSpacing: 2
|
|
});
|
|
});
|
|
});
|
|
|
|
}).call(this);
|
|
tinymce.addI18n('fr_FR',{
|
|
"Redo": "R\u00e9tablir",
|
|
"Undo": "Annuler",
|
|
"Cut": "Couper",
|
|
"Copy": "Copier",
|
|
"Paste": "Coller",
|
|
"Select all": "Tout s\u00e9lectionner",
|
|
"New document": "Nouveau document",
|
|
"Ok": "Ok",
|
|
"Cancel": "Annuler",
|
|
"Visual aids": "Aides visuelle",
|
|
"Bold": "Gras",
|
|
"Italic": "Italique",
|
|
"Underline": "Soulign\u00e9",
|
|
"Strikethrough": "Barr\u00e9",
|
|
"Superscript": "Exposant",
|
|
"Subscript": "Indice",
|
|
"Clear formatting": "Effacer la mise en forme",
|
|
"Align left": "Aligner \u00e0 gauche",
|
|
"Align center": "Centrer",
|
|
"Align right": "Aligner \u00e0 droite",
|
|
"Justify": "Justifier",
|
|
"Bullet list": "Puces",
|
|
"Numbered list": "Num\u00e9rotation",
|
|
"Decrease indent": "Diminuer le retrait",
|
|
"Increase indent": "Augmenter le retrait",
|
|
"Close": "Fermer",
|
|
"Formats": "Formats",
|
|
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Votre navigateur ne supporte pas la copie directe. Merci d'utiliser les touches Ctrl+X\/C\/V.",
|
|
"Headers": "Titres",
|
|
"Header 1": "Titre 1",
|
|
"Header 2": "Titre 2",
|
|
"Header 3": "Titre 3",
|
|
"Header 4": "Titre 4",
|
|
"Header 5": "Titre 5",
|
|
"Header 6": "Titre 6",
|
|
"Headings": "En-t\u00eates",
|
|
"Heading 1": "En-t\u00eate 1",
|
|
"Heading 2": "En-t\u00eate 2",
|
|
"Heading 3": "En-t\u00eate 3",
|
|
"Heading 4": "En-t\u00eate 4",
|
|
"Heading 5": "En-t\u00eate 5",
|
|
"Heading 6": "En-t\u00eate 6",
|
|
"Preformatted": "Pr\u00e9-formatt\u00e9",
|
|
"Div": "Div",
|
|
"Pre": "Pre",
|
|
"Code": "Code",
|
|
"Paragraph": "Paragraphe",
|
|
"Blockquote": "Citation",
|
|
"Inline": "En ligne",
|
|
"Blocks": "Blocs",
|
|
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Le presse-papiers est maintenant en mode \"texte plein\". Les contenus seront coll\u00e9s sans retenir les formatages jusqu'\u00e0 ce que vous d\u00e9sactiviez cette option.",
|
|
"Fonts": "Polices",
|
|
"Font Sizes": "Taille de police",
|
|
"Class": "Classe",
|
|
"Browse for an image": "Parcourir pour s\u00e9lectionner une image",
|
|
"OR": "OU",
|
|
"Drop an image here": "Glisser une image ici",
|
|
"Upload": "D\u00e9poser",
|
|
"Block": "Bloquer",
|
|
"Align": "Aligner",
|
|
"Default": "Par d\u00e9faut",
|
|
"Circle": "Cercle",
|
|
"Disc": "Disque",
|
|
"Square": "Carr\u00e9",
|
|
"Lower Alpha": "Alpha minuscule",
|
|
"Lower Greek": "Grec minuscule",
|
|
"Lower Roman": "Romain minuscule",
|
|
"Upper Alpha": "Alpha majuscule",
|
|
"Upper Roman": "Romain majuscule",
|
|
"Anchor...": "Ancre...",
|
|
"Name": "Nom",
|
|
"Id": "Id",
|
|
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "L'Id doit commencer par une lettre suivi par des lettres, nombres, tirets, points, deux-points ou underscores",
|
|
"You have unsaved changes are you sure you want to navigate away?": "Vous avez des modifications non enregistr\u00e9es, \u00eates-vous s\u00fbr de quitter la page?",
|
|
"Restore last draft": "Restaurer le dernier brouillon",
|
|
"Special characters...": "Caract\u00e8res sp\u00e9ciaux...",
|
|
"Source code": "Code source",
|
|
"Insert\/Edit code sample": "Ins\u00e9rer \/ modifier une exemple de code",
|
|
"Language": "Langue",
|
|
"Code sample...": "Extrait de code...",
|
|
"Color Picker": "S\u00e9lecteur de couleur",
|
|
"R": "R",
|
|
"G": "V",
|
|
"B": "B",
|
|
"Left to right": "Gauche \u00e0 droite",
|
|
"Right to left": "Droite \u00e0 gauche",
|
|
"Emoticons...": "\u00c9motic\u00f4nes...",
|
|
"Metadata and Document Properties": "M\u00e9tadonn\u00e9es et propri\u00e9t\u00e9s du document",
|
|
"Title": "Titre",
|
|
"Keywords": "Mots-cl\u00e9s",
|
|
"Description": "Description",
|
|
"Robots": "Robots",
|
|
"Author": "Auteur",
|
|
"Encoding": "Encodage",
|
|
"Fullscreen": "Plein \u00e9cran",
|
|
"Action": "Action",
|
|
"Shortcut": "Raccourci",
|
|
"Help": "Aide",
|
|
"Address": "Adresse",
|
|
"Focus to menubar": "Cibler la barre de menu",
|
|
"Focus to toolbar": "Cibler la barre d'outils",
|
|
"Focus to element path": "Cibler le chemin vers l'\u00e9l\u00e9ment",
|
|
"Focus to contextual toolbar": "Cibler la barre d'outils contextuelle",
|
|
"Insert link (if link plugin activated)": "Ins\u00e9rer un lien (si le module link est activ\u00e9)",
|
|
"Save (if save plugin activated)": "Enregistrer (si le module save est activ\u00e9)",
|
|
"Find (if searchreplace plugin activated)": "Rechercher (si le module searchreplace est activ\u00e9)",
|
|
"Plugins installed ({0}):": "Modules install\u00e9s ({0}) : ",
|
|
"Premium plugins:": "Modules premium :",
|
|
"Learn more...": "En savoir plus...",
|
|
"You are using {0}": "Vous utilisez {0}",
|
|
"Plugins": "Plugins",
|
|
"Handy Shortcuts": "Raccourcis utiles",
|
|
"Horizontal line": "Ligne horizontale",
|
|
"Insert\/edit image": "Ins\u00e9rer\/modifier une image",
|
|
"Image description": "Description de l'image",
|
|
"Source": "Source",
|
|
"Dimensions": "Dimensions",
|
|
"Constrain proportions": "Conserver les proportions",
|
|
"General": "G\u00e9n\u00e9ral",
|
|
"Advanced": "Avanc\u00e9",
|
|
"Style": "Style",
|
|
"Vertical space": "Espacement vertical",
|
|
"Horizontal space": "Espacement horizontal",
|
|
"Border": "Bordure",
|
|
"Insert image": "Ins\u00e9rer une image",
|
|
"Image...": "Image...",
|
|
"Image list": "Liste d'images",
|
|
"Rotate counterclockwise": "Rotation anti-horaire",
|
|
"Rotate clockwise": "Rotation horaire",
|
|
"Flip vertically": "Retournement vertical",
|
|
"Flip horizontally": "Retournement horizontal",
|
|
"Edit image": "Modifier l'image",
|
|
"Image options": "Options de l'image",
|
|
"Zoom in": "Zoomer",
|
|
"Zoom out": "D\u00e9zoomer",
|
|
"Crop": "Rogner",
|
|
"Resize": "Redimensionner",
|
|
"Orientation": "Orientation",
|
|
"Brightness": "Luminosit\u00e9",
|
|
"Sharpen": "Affiner",
|
|
"Contrast": "Contraste",
|
|
"Color levels": "Niveaux de couleur",
|
|
"Gamma": "Gamma",
|
|
"Invert": "Inverser",
|
|
"Apply": "Appliquer",
|
|
"Back": "Retour",
|
|
"Insert date\/time": "Ins\u00e9rer date\/heure",
|
|
"Date\/time": "Date\/heure",
|
|
"Insert\/Edit Link": "Ins\u00e9rer\/Modifier un lien",
|
|
"Insert\/edit link": "Ins\u00e9rer\/modifier un lien",
|
|
"Text to display": "Texte \u00e0 afficher",
|
|
"Url": "Url",
|
|
"Open link in...": "Ouvrir le lien dans...",
|
|
"Current window": "Fen\u00eatre courante",
|
|
"None": "n\/a",
|
|
"New window": "Nouvelle fen\u00eatre",
|
|
"Remove link": "Enlever le lien",
|
|
"Anchors": "Ancres",
|
|
"Link...": "Lien...",
|
|
"Paste or type a link": "Coller ou taper un lien",
|
|
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "L'URL que vous avez entr\u00e9e semble \u00eatre une adresse e-mail. Voulez-vous ajouter le pr\u00e9fixe mailto: n\u00e9cessaire?",
|
|
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "L'URL que vous avez entr\u00e9e semble \u00eatre un lien externe. Voulez-vous ajouter le pr\u00e9fixe http:\/\/ n\u00e9cessaire?",
|
|
"Link list": "Liste de liens",
|
|
"Insert video": "Ins\u00e9rer une vid\u00e9o",
|
|
"Insert\/edit video": "Ins\u00e9rer\/modifier une vid\u00e9o",
|
|
"Insert\/edit media": "Ins\u00e9rer\/modifier un m\u00e9dia",
|
|
"Alternative source": "Source alternative",
|
|
"Alternative source URL": "Source alternative",
|
|
"Media poster (Image URL)": "Affiche de m\u00e9dia (URL d'image)",
|
|
"Paste your embed code below:": "Collez votre code d'int\u00e9gration ci-dessous :",
|
|
"Embed": "Int\u00e9grer",
|
|
"Media...": "M\u00e9dia...",
|
|
"Nonbreaking space": "Espace ins\u00e9cable",
|
|
"Page break": "Saut de page",
|
|
"Paste as text": "Coller comme texte",
|
|
"Preview": "Pr\u00e9visualiser",
|
|
"Print...": "Imprimer...",
|
|
"Save": "Enregistrer",
|
|
"Find": "Chercher",
|
|
"Replace with": "Remplacer par",
|
|
"Replace": "Remplacer",
|
|
"Replace all": "Tout remplacer",
|
|
"Previous": "Pr\u00e9c\u00e9dent",
|
|
"Next": "Suiv",
|
|
"Find and replace...": "Chercher et remplacer...",
|
|
"Could not find the specified string.": "Impossible de trouver la cha\u00eene sp\u00e9cifi\u00e9e.",
|
|
"Match case": "Respecter la casse",
|
|
"Find whole words only": "Chercher uniquement les mots entiers",
|
|
"Spell check": "Lancer la correction orthographique",
|
|
"Ignore": "Ignorer",
|
|
"Ignore all": "Tout ignorer",
|
|
"Finish": "Finie",
|
|
"Add to Dictionary": "Ajouter au dictionnaire",
|
|
"Insert table": "Ins\u00e9rer un tableau",
|
|
"Table properties": "Propri\u00e9t\u00e9s du tableau",
|
|
"Delete table": "Supprimer le tableau",
|
|
"Cell": "Cellule",
|
|
"Row": "Ligne",
|
|
"Column": "Colonne",
|
|
"Cell properties": "Propri\u00e9t\u00e9s de la cellule",
|
|
"Merge cells": "Fusionner les cellules",
|
|
"Split cell": "Diviser la cellule",
|
|
"Insert row before": "Ins\u00e9rer une ligne avant",
|
|
"Insert row after": "Ins\u00e9rer une ligne apr\u00e8s",
|
|
"Delete row": "Effacer la ligne",
|
|
"Row properties": "Propri\u00e9t\u00e9s de la ligne",
|
|
"Cut row": "Couper la ligne",
|
|
"Copy row": "Copier la ligne",
|
|
"Paste row before": "Coller la ligne avant",
|
|
"Paste row after": "Coller la ligne apr\u00e8s",
|
|
"Insert column before": "Ins\u00e9rer une colonne avant",
|
|
"Insert column after": "Ins\u00e9rer une colonne apr\u00e8s",
|
|
"Delete column": "Effacer la colonne",
|
|
"Cols": "Colonnes",
|
|
"Rows": "Lignes",
|
|
"Width": "Largeur",
|
|
"Height": "Hauteur",
|
|
"Cell spacing": "Espacement inter-cellulles",
|
|
"Cell padding": "Espacement interne cellule",
|
|
"Show caption": "Afficher le sous-titre",
|
|
"Left": "Gauche",
|
|
"Center": "Centr\u00e9",
|
|
"Right": "Droite",
|
|
"Cell type": "Type de cellule",
|
|
"Scope": "Etendue",
|
|
"Alignment": "Alignement",
|
|
"H Align": "Alignement H",
|
|
"V Align": "Alignement V",
|
|
"Top": "Haut",
|
|
"Middle": "Milieu",
|
|
"Bottom": "Bas",
|
|
"Header cell": "Cellule d'en-t\u00eate",
|
|
"Row group": "Groupe de lignes",
|
|
"Column group": "Groupe de colonnes",
|
|
"Row type": "Type de ligne",
|
|
"Header": "En-t\u00eate",
|
|
"Body": "Corps",
|
|
"Footer": "Pied",
|
|
"Border color": "Couleur de la bordure",
|
|
"Insert template...": "Ins\u00e9rer un mod\u00e8le...",
|
|
"Templates": "Th\u00e8mes",
|
|
"Template": "Mod\u00e8le",
|
|
"Text color": "Couleur du texte",
|
|
"Background color": "Couleur d'arri\u00e8re-plan",
|
|
"Custom...": "Personnalis\u00e9...",
|
|
"Custom color": "Couleur personnalis\u00e9e",
|
|
"No color": "Aucune couleur",
|
|
"Remove color": "Supprimer la couleur",
|
|
"Table of Contents": "Table des mati\u00e8res",
|
|
"Show blocks": "Afficher les blocs",
|
|
"Show invisible characters": "Afficher les caract\u00e8res invisibles",
|
|
"Word count": "Nombre de mots",
|
|
"Words: {0}": "Mots : {0}",
|
|
"{0} words": "{0} mots",
|
|
"File": "Fichier",
|
|
"Edit": "Editer",
|
|
"Insert": "Ins\u00e9rer",
|
|
"View": "Voir",
|
|
"Format": "Format",
|
|
"Table": "Tableau",
|
|
"Tools": "Outils",
|
|
"Powered by {0}": "Propuls\u00e9 par {0}",
|
|
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Zone Texte Riche. Appuyer sur ALT-F9 pour le menu. Appuyer sur ALT-F10 pour la barre d'outils. Appuyer sur ALT-0 pour de l'aide.",
|
|
"Image title": "Titre d'image",
|
|
"Border width": "\u00c9paisseur de la bordure",
|
|
"Border style": "Style de la bordure",
|
|
"Error": "\u00c9rreur",
|
|
"Warn": "Avertissement",
|
|
"Valid": "Valide",
|
|
"To open the popup, press Shift+Enter": "Pour ouvrir la popup, presser Shift+Entr\u00e9e",
|
|
"Rich Text Area. Press ALT-0 for help.": "Zone de texte riche. Presser ALT-0 pour l'aide.",
|
|
"System Font": "Police syst\u00e8me",
|
|
"Failed to upload image: {0}": "\u00c9chec d'envoi de l'image : {0}",
|
|
"Failed to load plugin: {0} from url {1}": "\u00c9chec de chargement du module : {0} \u00e0 partir de l'URL {1}",
|
|
"Failed to load plugin url: {0}": "\u00c9chec de chargement de l'URL de module : {0}",
|
|
"Failed to initialize plugin: {0}": "\u00c9chec d'initialisation du module : {0}",
|
|
"example": "exemple",
|
|
"Search": "Rechercher",
|
|
"All": "Tous",
|
|
"Currency": "Mon\u00e9taire",
|
|
"Text": "Texte",
|
|
"Quotations": "Citations",
|
|
"Mathematical": "Math\u00e9matique",
|
|
"Extended Latin": "Latin \u00e9tendu",
|
|
"Symbols": "Symboles",
|
|
"Arrows": "Fl\u00e8ches",
|
|
"User Defined": "D\u00e9fini par l'utilisateur",
|
|
"dollar sign": "Symbole dollar",
|
|
"currency sign": "Symbole devise",
|
|
"euro-currency sign": "Symbole euro",
|
|
"colon sign": "Symbole col\u00f3n",
|
|
"cruzeiro sign": "Symbole cruzeiro",
|
|
"french franc sign": "Symbole franc fran\u00e7ais",
|
|
"lira sign": "Symbole lire",
|
|
"mill sign": "Symbole milli\u00e8me",
|
|
"naira sign": "Symbole naira",
|
|
"peseta sign": "Symbole peseta",
|
|
"rupee sign": "Symbole roupie",
|
|
"won sign": "Symbole won",
|
|
"new sheqel sign": "Symbole nouveau ch\u00e9kel",
|
|
"dong sign": "Symbole dong",
|
|
"kip sign": "Symbole kip",
|
|
"tugrik sign": "Symbole tougrik",
|
|
"drachma sign": "Symbole drachme",
|
|
"german penny symbol": "Symbole pfennig",
|
|
"peso sign": "Symbole peso",
|
|
"guarani sign": "Symbole guarani",
|
|
"austral sign": "Symbole austral",
|
|
"hryvnia sign": "Symbole hryvnia",
|
|
"cedi sign": "Symbole cedi",
|
|
"livre tournois sign": "Symbole livre tournois",
|
|
"spesmilo sign": "Symbole spesmilo",
|
|
"tenge sign": "Symbole tenge",
|
|
"indian rupee sign": "Symbole roupie indienne",
|
|
"turkish lira sign": "Symbole lire turque",
|
|
"nordic mark sign": "Symbole du mark nordique",
|
|
"manat sign": "Symbole manat",
|
|
"ruble sign": "Symbole rouble",
|
|
"yen character": "Sinogramme Yen",
|
|
"yuan character": "Sinogramme Yuan",
|
|
"yuan character, in hong kong and taiwan": "Sinogramme Yuan, Hong Kong et Taiwan",
|
|
"yen\/yuan character variant one": "Symbole Yen\/Yuan",
|
|
"Loading emoticons...": "Chargement des \u00e9motic\u00f4nes...",
|
|
"Could not load emoticons": "\u00c9chec de chargement des \u00e9motic\u00f4nes",
|
|
"People": "Smileys et personnes",
|
|
"Animals and Nature": "Animaux & nature",
|
|
"Food and Drink": "Nourriture & boisson",
|
|
"Activity": "Activit\u00e9",
|
|
"Travel and Places": "Voyages & lieux",
|
|
"Objects": "Objets",
|
|
"Flags": "Drapeaux",
|
|
"Characters": "Caract\u00e8res",
|
|
"Characters (no spaces)": "Caract\u00e8res (espaces non compris)",
|
|
"Error: Form submit field collision.": "Erreur : conflit de champ lors de la soumission du formulaire",
|
|
"Error: No form element found.": "Erreur : aucun \u00e9l\u00e9ment de formulaire trouv\u00e9.",
|
|
"Update": "Mettre \u00e0 jour",
|
|
"Color swatch": "Palette de couleurs",
|
|
"Turquoise": "Turquoise",
|
|
"Green": "Vert",
|
|
"Blue": "Bleu",
|
|
"Purple": "Violet",
|
|
"Navy Blue": "Bleu oc\u00e9an",
|
|
"Dark Turquoise": "Turquoise fonc\u00e9",
|
|
"Dark Green": "Vert fonc\u00e9",
|
|
"Medium Blue": "Bleu moyen",
|
|
"Medium Purple": "Violet moyen",
|
|
"Midnight Blue": "Bleu nuit",
|
|
"Yellow": "Jaune",
|
|
"Orange": "Orange",
|
|
"Red": "Rouge",
|
|
"Light Gray": "Gris clair",
|
|
"Gray": "Gris",
|
|
"Dark Yellow": "Jaune fonc\u00e9",
|
|
"Dark Orange": "Orange fonc\u00e9",
|
|
"Dark Red": "Rouge fonc\u00e9",
|
|
"Medium Gray": "Gris moyen",
|
|
"Dark Gray": "Gris fonc\u00e9",
|
|
"Black": "Noir",
|
|
"White": "Blanc",
|
|
"Switch to or from fullscreen mode": "Activer ou quitter le mode plein \u00e9cran",
|
|
"Open help dialog": "Ouvrir l'aide",
|
|
"history": "historique",
|
|
"styles": "styles",
|
|
"formatting": "mise en forme",
|
|
"alignment": "alignement",
|
|
"indentation": "indentation",
|
|
"permanent pen": "crayon ind\u00e9l\u00e9bile",
|
|
"comments": "commentaires",
|
|
"Anchor": "Ancre",
|
|
"Special character": "Caract\u00e8res sp\u00e9ciaux",
|
|
"Code sample": "Extrait de code",
|
|
"Color": "Couleur",
|
|
"Emoticons": "Emotic\u00f4nes",
|
|
"Document properties": "Propri\u00e9t\u00e9 du document",
|
|
"Image": "Image",
|
|
"Insert link": "Ins\u00e9rer un lien",
|
|
"Target": "Cible",
|
|
"Link": "Lien",
|
|
"Poster": "Publier",
|
|
"Media": "M\u00e9dia",
|
|
"Print": "Imprimer",
|
|
"Prev": "Pr\u00e9c ",
|
|
"Find and replace": "Trouver et remplacer",
|
|
"Whole words": "Mots entiers",
|
|
"Spellcheck": "V\u00e9rification orthographique",
|
|
"Caption": "Titre",
|
|
"Insert template": "Ajouter un th\u00e8me"
|
|
});
|
|
(function() {
|
|
$(document).on('turbolinks:load', function() {
|
|
if (!Modernizr.testAllProps('forceBrokenImageIcon')) {
|
|
$('img.favicon').one('error', function() {
|
|
return $(this).css({
|
|
visibility: 'hidden'
|
|
});
|
|
});
|
|
}
|
|
return $('.field.tags input').tagsInput({
|
|
delimiter: ' ',
|
|
defaultText: '',
|
|
autocomplete_url: '/tags.json',
|
|
onChange: function() {
|
|
var value;
|
|
value = $(this).val();
|
|
if (value.indexOf(',') >= 0) {
|
|
return $(this).val(value.replace(/,/, ''));
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
}).call(this);
|