1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-06-09 19:24:58 +02:00
php-web-maker/lib/split.js
2016-05-02 17:13:18 +05:30

362 lines
12 KiB
JavaScript

'use strict';
(function() {
var global = this
, addEventListener = 'addEventListener'
, removeEventListener = 'removeEventListener'
, getBoundingClientRect = 'getBoundingClientRect'
, isIE8 = global.attachEvent && !global[addEventListener]
, document = global.document
, calc = (function () {
var el
, prefixes = ["", "-webkit-", "-moz-", "-o-"]
for (var i = 0; i < prefixes.length; i++) {
el = document.createElement('div')
el.style.cssText = "width:" + prefixes[i] + "calc(9px)"
if (el.style.length) {
return prefixes[i] + "calc"
}
}
})()
, elementOrSelector = function (el) {
if (typeof el === 'string' || el instanceof String) {
return document.querySelector(el)
} else {
return el
}
}
, Split = function (ids, options) {
var dimension
, i
, clientDimension
, clientAxis
, position
, gutterClass
, paddingA
, paddingB
, pairs = []
// Set defaults
options = typeof options !== 'undefined' ? options : {}
if (typeof options.gutterSize === 'undefined') options.gutterSize = 10
if (typeof options.minSize === 'undefined') options.minSize = 100
if (typeof options.snapOffset === 'undefined') options.snapOffset = 30
if (typeof options.direction === 'undefined') options.direction = 'horizontal'
if (options.direction == 'horizontal') {
dimension = 'width'
clientDimension = 'clientWidth'
clientAxis = 'clientX'
position = 'left'
gutterClass = 'gutter gutter-horizontal'
paddingA = 'paddingLeft'
paddingB = 'paddingRight'
if (!options.cursor) options.cursor = 'ew-resize'
} else if (options.direction == 'vertical') {
dimension = 'height'
clientDimension = 'clientHeight'
clientAxis = 'clientY'
position = 'top'
gutterClass = 'gutter gutter-vertical'
paddingA = 'paddingTop'
paddingB = 'paddingBottom'
if (!options.cursor) options.cursor = 'ns-resize'
}
// Event listeners for drag events, bound to a pair object.
// Calculate the pair's position and size when dragging starts.
// Prevent selection on start and re-enable it when done.
var startDragging = function (e) {
var self = this
, a = self.a
, b = self.b
if (!self.dragging && options.onDragStart) {
options.onDragStart()
}
e.preventDefault()
self.dragging = true
self.move = drag.bind(self)
self.stop = stopDragging.bind(self)
global[addEventListener]('mouseup', self.stop)
global[addEventListener]('touchend', self.stop)
global[addEventListener]('touchcancel', self.stop)
self.parent[addEventListener]('mousemove', self.move)
self.parent[addEventListener]('touchmove', self.move)
a[addEventListener]('selectstart', preventSelection)
a[addEventListener]('dragstart', preventSelection)
b[addEventListener]('selectstart', preventSelection)
b[addEventListener]('dragstart', preventSelection)
a.style.userSelect = 'none'
a.style.webkitUserSelect = 'none'
a.style.MozUserSelect = 'none'
a.style.pointerEvents = 'none'
b.style.userSelect = 'none'
b.style.webkitUserSelect = 'none'
b.style.MozUserSelect = 'none'
b.style.pointerEvents = 'none'
self.gutter.style.cursor = options.cursor
self.parent.style.cursor = options.cursor
calculateSizes.call(self)
}
, stopDragging = function () {
var self = this
, a = self.a
, b = self.b
if (self.dragging && options.onDragEnd) {
options.onDragEnd()
}
self.dragging = false
global[removeEventListener]('mouseup', self.stop)
global[removeEventListener]('touchend', self.stop)
global[removeEventListener]('touchcancel', self.stop)
self.parent[removeEventListener]('mousemove', self.move)
self.parent[removeEventListener]('touchmove', self.move)
delete self.stop
delete self.move
a[removeEventListener]('selectstart', preventSelection)
a[removeEventListener]('dragstart', preventSelection)
b[removeEventListener]('selectstart', preventSelection)
b[removeEventListener]('dragstart', preventSelection)
a.style.userSelect = ''
a.style.webkitUserSelect = ''
a.style.MozUserSelect = ''
a.style.pointerEvents = ''
b.style.userSelect = ''
b.style.webkitUserSelect = ''
b.style.MozUserSelect = ''
b.style.pointerEvents = ''
self.gutter.style.cursor = ''
self.parent.style.cursor = ''
}
, drag = function (e) {
var offset
if (!this.dragging) return
// Get the relative position of the event from the first side of the
// pair.
if ('touches' in e) {
offset = e.touches[0][clientAxis] - this.start
} else {
offset = e[clientAxis] - this.start
}
// If within snapOffset of min or max, set offset to min or max
if (offset <= this.aMin + options.snapOffset) {
offset = this.aMin
} else if (offset >= this.size - this.bMin - options.snapOffset) {
offset = this.size - this.bMin
}
adjust.call(this, offset)
if (options.onDrag) {
options.onDrag()
}
}
, calculateSizes = function () {
// Calculate the pairs size, and percentage of the parent size
var computedStyle = global.getComputedStyle(this.parent)
, parentSize = this.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
this.size = this.a[getBoundingClientRect]()[dimension] + this.b[getBoundingClientRect]()[dimension] + this.aGutterSize + this.bGutterSize
this.percentage = Math.min(this.size / parentSize * 100, 100)
this.start = this.a[getBoundingClientRect]()[position]
}
, adjust = function (offset) {
// A size is the same as offset. B size is total size - A size.
// Both sizes are calculated from the initial parent percentage.
this.a.style[dimension] = calc + '(' + (offset / this.size * this.percentage) + '% - ' + this.aGutterSize + 'px)'
this.b.style[dimension] = calc + '(' + (this.percentage - (offset / this.size * this.percentage)) + '% - ' + this.bGutterSize + 'px)'
}
, fitMin = function () {
var self = this
, a = self.a
, b = self.b
if (a[getBoundingClientRect]()[dimension] < self.aMin) {
a.style[dimension] = (self.aMin - self.aGutterSize) + 'px'
b.style[dimension] = (self.size - self.aMin - self.aGutterSize) + 'px'
} else if (b[getBoundingClientRect]()[dimension] < self.bMin) {
a.style[dimension] = (self.size - self.bMin - self.bGutterSize) + 'px'
b.style[dimension] = (self.bMin - self.bGutterSize) + 'px'
}
}
, fitMinReverse = function () {
var self = this
, a = self.a
, b = self.b
if (b[getBoundingClientRect]()[dimension] < self.bMin) {
a.style[dimension] = (self.size - self.bMin - self.bGutterSize) + 'px'
b.style[dimension] = (self.bMin - self.bGutterSize) + 'px'
} else if (a[getBoundingClientRect]()[dimension] < self.aMin) {
a.style[dimension] = (self.aMin - self.aGutterSize) + 'px'
b.style[dimension] = (self.size - self.aMin - self.aGutterSize) + 'px'
}
}
, balancePairs = function (pairs) {
for (var i = 0; i < pairs.length; i++) {
calculateSizes.call(pairs[i])
fitMin.call(pairs[i])
}
for (i = pairs.length - 1; i >= 0; i--) {
calculateSizes.call(pairs[i])
fitMinReverse.call(pairs[i])
}
}
, preventSelection = function () { return false }
, parent = elementOrSelector(ids[0]).parentNode
if (!options.sizes) {
var percent = 100 / ids.length
options.sizes = []
for (i = 0; i < ids.length; i++) {
options.sizes.push(percent)
}
}
if (!Array.isArray(options.minSize)) {
var minSizes = []
for (i = 0; i < ids.length; i++) {
minSizes.push(options.minSize)
}
options.minSize = minSizes
}
for (i = 0; i < ids.length; i++) {
var el = elementOrSelector(ids[i])
, isFirst = (i == 1)
, isLast = (i == ids.length - 1)
, size
, gutterSize = options.gutterSize
, pair
, parentFlexDirection = window.getComputedStyle(parent).flexDirection
, temp
if (i > 0) {
pair = {
a: elementOrSelector(ids[i - 1]),
b: el,
aMin: options.minSize[i - 1],
bMin: options.minSize[i],
dragging: false,
parent: parent,
isFirst: isFirst,
isLast: isLast,
direction: options.direction
}
// For first and last pairs, first and last gutter width is half.
pair.aGutterSize = options.gutterSize
pair.bGutterSize = options.gutterSize
if (isFirst) {
pair.aGutterSize = options.gutterSize / 2
}
if (isLast) {
pair.bGutterSize = options.gutterSize / 2
}
// if the parent has a reverse flex-direction, switch the pair elements.
if (parentFlexDirection === 'row-reverse' || parentFlexDirection === 'column-reverse') {
temp = pair.a;
pair.a = pair.b;
pair.b = temp;
}
}
// IE9 and above
if (!isIE8) {
if (i > 0) {
var gutter = document.createElement('div')
gutter.className = gutterClass
gutter.style[dimension] = options.gutterSize + 'px'
gutter[addEventListener]('mousedown', startDragging.bind(pair))
gutter[addEventListener]('touchstart', startDragging.bind(pair))
parent.insertBefore(gutter, el)
pair.gutter = gutter
}
if (i === 0 || i == ids.length - 1) {
gutterSize = options.gutterSize / 2
}
if (typeof options.sizes[i] === 'string' || options.sizes[i] instanceof String) {
size = options.sizes[i]
} else {
size = calc + '(' + options.sizes[i] + '% - ' + gutterSize + 'px)'
}
// IE8 and below
} else {
if (typeof options.sizes[i] === 'string' || options.sizes[i] instanceof String) {
size = options.sizes[i]
} else {
size = options.sizes[i] + '%'
}
}
el.style[dimension] = size
if (i > 0) {
pairs.push(pair)
}
}
balancePairs(pairs)
}
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = Split
}
exports.Split = Split
} else {
global.Split = Split
}
}).call(window);