remove submodules

This commit is contained in:
Nathan Cahill
2018-11-04 14:32:14 -07:00
parent 7c3619675a
commit f1d912e4bd
25 changed files with 8229 additions and 1 deletions

Submodule packages/splitjs deleted from c7120b9b12

View File

@@ -0,0 +1,9 @@
language: node_js
node_js:
- "node"
before_script:
- npm install -g browserstack-runner
- npm run build
script:
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then browserstack-runner; fi'
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then BROWSERSTACK_JSON=test/ie8/browserstack.json; browserstack-runner; fi'

View File

@@ -0,0 +1,19 @@
Copyright (c) 2018 Nathan Cahill
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.

606
packages/splitjs/README.md Normal file
View File

@@ -0,0 +1,606 @@
<p align="center">
<img alt="Split.js" title="Split.js" src="https://cdn.rawgit.com/nathancahill/split/master/packages/splitjs/logo.svg" width="430">
<br><br>
<a href="https://travis-ci.org/nathancahill/Split.js"><img src="https://travis-ci.org/nathancahill/Split.js.svg" alt="Build Status"></a>
<img src="https://img.badgesize.io/https://unpkg.com/split.js/split.min.js?compression=gzip&label=size&v=1.5.7" alt="File Size">
<img src="https://badge.fury.io/js/split.js.svg" alt="npm version">
<img src="https://david-dm.org/nathancahill/split/status.svg" alt="Dependencies">
<img src = "https://opencollective.com/splitjs/backers/badge.svg" alt="Backers on Open Collective"/>
<img src = "https://opencollective.com/splitjs/sponsors/badge.svg" alt="Sponsors on Open Collective"/>
</p>
# Split.js
> 2kb unopinionated utility for resizeable split views.
- **Zero Deps**
- **Tiny:** Weights 2kb gzipped.
- **Fast:** No overhead or attached window event listeners, uses pure CSS for resizing.
- **Unopinionated:** Plays nicely with `calc`, `flex` and `grid`.
- **Compatible:** Works great in IE9, and _even loads in IE8_ with polyfills. Early Firefox/Chrome/Safari/Opera supported too.
## Table of Contents
- [Installation](#installation)
- [Documentation](#documentation)
- [Important Note](#important-note)
- [Options](#options)
- [Examples](#usage-examples)
- [Saving State](#saving-state)
- [Flexbox](#flexbox)
- [API](#api)
- [CSS](#css)
- [React](#react)
- [Browser Support](#browser-support)
- [Credits](#credits)
- [License](#license)
## Installation
Yarn:
```bash
$ yarn add split.js
```
npm:
```bash
$ npm install --save split.js
```
Bower:
```bash
$ bower install --save Split.js
```
Include with a module bundler like [rollup](http://rollupjs.org/) or [webpack](https://webpack.github.io/):
```js
// using ES6 modules
import Split from 'split.js'
// using CommonJS modules
var Split = require('split.js')
```
The [UMD](https://github.com/umdjs/umd) build is also available on [unpkg](http://unpkg.com/):
```html
<script src="https://unpkg.com/split.js/split.min.js"></script>
```
You can find the library on `window.Split`.
## Documentation
```js
var split = Split(<HTMLElement|selector[]> elements, <options> options?)
```
| Options | Type | Default | Description |
| -------------- | --------------- | -------------- | -------------------------------------------------------- |
| `sizes` | Array | | Initial sizes of each element in percents or CSS values. |
| `minSize` | Number or Array | `100` | Minimum size of each element. |
| `expandToMin` | Boolean | `false` | Grow initial sizes to `minSize` |
| `gutterSize` | Number | `10` | Gutter size in pixels. |
| `gutterAlign` | String | `'center'` | Gutter alignment between elements. |
| `snapOffset` | Number | `30` | Snap to minimum size offset in pixels. |
| `dragInterval` | Number | `1` | Number of pixels to drag. |
| `direction` | String | `'horizontal'` | Direction to split: horizontal or vertical. |
| `cursor` | String | `'col-resize'` | Cursor to display while dragging. |
| `gutter` | Function | | Called to create each gutter element |
| `elementStyle` | Function | | Called to set the style of each element. |
| `gutterStyle` | Function | | Called to set the style of the gutter. |
| `onDrag` | Function | | Callback on drag. |
| `onDragStart` | Function | | Callback on drag start. |
| `onDragEnd` | Function | | Callback on drag end. |
## Important Note
Split.js does not set CSS beyond the minimum needed to manage the width or height of the elements.
This is by design. It makes Split.js flexible and useful in many different situations.
If you create a horizontal split, you are responsible for (likely) floating the elements and the gutter,
and setting their heights. See the [CSS](#css) section below. If your gutters are not showing up, check the applied CSS styles.
**THIS IS THE #1 QUESTION ABOUT THE LIBRARY**.
## Options
#### sizes
An array of initial sizes of the elements, specified as percentage values. Example: Setting the initial sizes to `25%` and `75%`.
```js
Split(['#one', '#two'], {
sizes: [25, 75],
})
```
#### minSize. Default: `100`
An array of minimum sizes of the elements, specified as pixel values. Example: Setting the minimum sizes to `100px` and `300px`, respectively.
```js
Split(['#one', '#two'], {
minSize: [100, 300],
})
```
If a number is passed instead of an array, all elements are set to the same minimum size:
```js
Split(['#one', '#two'], {
minSize: 100,
})
```
#### expandToMin. Default: `false`
When the split is created, if `expandToMin` is `true`, the minSize for each element overrides the percentage value from the `sizes` option.
Example: The first element (`#one`) is set to 25% width of the parent container. However, it's `minSize` is `300px`. Using `expandToMin: true` means that
the first element will always load at at least `300px`, even if `25%` were smaller.
```js
Split(['#one', '#two'], {
sizes: [25, 75],
minSize: [300, 100],
expanedToMin: true,
})
```
#### gutterSize. Default: `10`
Gutter size in pixels. Example: Setting the gutter size to `20px`.
```js
Split(['#one', '#two'], {
gutterSize: 20,
})
```
#### gutterAlign. Default: `'center'`
Possible options are `'start'`, `'end'` and `'center'`. Determines how the gutter aligns between the two elements.
`'start'` shrinks the first element to fit the gutter, `'end'` shrinks the second element to fit the gutter and `'center'` shrinks both
elements by the same amount so the gutter sits between. Added in v1.5.3.
Example: move gutter to the side of the second element:
```js
Split(['#one', '#two'], {
gutterAlign: 'end',
})
```
#### snapOffset. Default: `30`
Snap to minimum size at this offset in pixels. Example: Set to `0` to disable to snap effect.
```js
Split(['#one', '#two'], {
snapOffset: 0,
})
```
#### dragInterval. Default: `1`
Drag this number of pixels at a time. Defaults to `1` for smooth dragging, but can be set to a pixel value to
give more control over the resulting sizes. Works particularly well when the `gutterSize` is set to the same size.
Added in v1.5.3. Example: Drag 20px at a time:
```js
Split(['#one', '#two'], {
dragInterval: 20,
})
```
#### direction. Default: `'horizontal'`
Direction to split in. Can be `'vertical'` or `'horizontal'`. Determines which CSS properties are applied (ie. width/height) to each element and gutter. Example: split vertically:
```js
Split(['#one', '#two'], {
direction: 'vertical',
})
```
#### cursor. Default: `'col-resize'`
Cursor to show on the gutter (also applied to the body on dragging to prevent flickering). Defaults to `'col-resize'`for `direction: 'horizontal'` and `'row-resize'` for `direction: 'vertical'`:
```js
Split(['#one', '#two'], {
direction: 'vertical',
cursor: 'row-resize',
})
```
#### gutter
Optional function called to create each gutter element. The signature looks like this:
```js
;(index, direction, pairElement) => HTMLElement
```
Defaults to creating a `div` with `class="gutter gutter-horizontal"` or `class="gutter gutter-vertical"`, depending on the direction. The default gutter function looks like this:
```js
;(index, direction) => {
const gutter = document.createElement('div')
gutter.className = `gutter gutter-${direction}`
return gutter
}
```
The returned element is then inserted into the DOM, and it's width or height are set. This option can be used to clone an existing DOM element, or to create a new element with custom styles.
Returning a falsey value like `null` or `false` will not insert a gutter. This behavior was added in v1.4.1.
An additional argument, `pairElement`, is passed to the gutter function: this is the DOM element after (to the right or below) the gutter. This argument was added in v1.4.1.
This final argument makes it easy to return the gutter that has already been created, for example, if `split.destroy()` was called with the option to preserve the gutters.
```js
;(index, direction, pairElement) => pairElement.previousSibling
```
#### elementStyle
Optional function called setting the CSS style of the elements. The signature looks like this:
```js
;(dimension, elementSize, gutterSize, index) => Object
```
Dimension will be a string, `'width'` or `'height'`, and can be used in the return style. `elementSize` is the target percentage value of the element, and `gutterSize` is the target pixel value of the gutter.
It should return an object with CSS properties to apply to the element. For horizontal splits, the return object looks like this:
```js
{
'width': 'calc(50% - 5px)'
}
```
A vertical split style would look like this:
```js
{
'height': 'calc(50% - 5px)'
}
```
Use this function if you're using a different layout like flexbox or grid (see [Flexbox](#flexbox)). A flexbox style for a horizontal split would look like this:
```js
{
'flex-basis': 'calc(50% - 5px)'
}
```
#### gutterStyle
Optional function called when setting the CSS style of the gutters. The signature looks like this:
```js
;(dimension, gutterSize, index) => Object
```
Dimension is a string, either `'width'` or `'height'`, and `gutterSize` is a pixel value representing the width of the gutter.
It should return a similar object as `elementStyle`, an object with CSS properties to apply to the gutter. Since gutters have fixed widths, it will generally look like this:
```js
{
'width': '10px'
}
```
Both `elementStyle` and `gutterStyle` are called continously while dragging, so don't do anything besides return the style object in these functions. Both of these functions should be _pure_, returning the same values for the same inputs and not modifying any external state.
#### onDrag, onDragStart, onDragEnd
Callbacks that can be added on drag (fired continously), drag start and drag end. If doing more than basic operations in `onDrag`, add a debounce function to rate limit the callback.
`onDragStart` and `onDragEnd` are passed the initial and final sizes of the split since it's a common pattern to access the sizes this way.
Their function signature looks like this, where `sizes` is an array of percentage values like returned by `getSizes()`:
```js
sizes => {}
```
## Usage Examples
Reference HTML for examples. Gutters are inserted automatically:
```html
<div>
<div id="one">content one</div>
<div id="two">content two</div>
<div id="three">content three</div>
</div>
```
A split with two elements, starting at `25%` and `75%` wide, with `200px` minimum width.
```js
Split(['#one', '#two'], {
sizes: [25, 75],
minSize: 200,
})
```
A split with three elements, starting with even (default) widths and minimum widths set to `100px`, `100px` and `300px`, respectively.
```js
Split(['#one', '#two', '#three'], {
minSize: [100, 100, 300],
})
```
A vertical split with two elements.
```js
Split(['#one', '#two'], {
direction: 'vertical',
})
```
## Saving State
Use local storage to save the most recent state:
```js
var sizes = localStorage.getItem('split-sizes')
if (sizes) {
sizes = JSON.parse(sizes)
} else {
sizes = [50, 50] // default sizes
}
var split = Split(['#one', '#two'], {
sizes: sizes,
onDragEnd: function(sizes) {
localStorage.setItem('split-sizes', JSON.stringify(sizes))
},
})
```
## Flex Layout
Flex layout is supported easily by adding a `display: flex` to the parent element. The `width` or `height` CSS values
assigned by default by Split.js work well with flex.
```html
<div id="flex">
<div id="flex-1"></div>
<div id="flex-2"></div>
</div>
```
And CSS style like this:
```css
#flex {
display: flex;
flex-direction: row;
}
```
For more complicated flex layouts, the `elementStyle` and `gutterStyle` can be used to set flex-basis:
```js
Split(['#flex-1', '#flex-2'], {
elementStyle: function(dimension, size, gutterSize) {
return {
'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)',
}
},
gutterStyle: function(dimension, gutterSize) {
return {
'flex-basis': gutterSize + 'px',
}
},
})
```
## API
Split.js returns an instance with a couple of functions. The instance is returned on creation:
```js
var instance = Split([], ...)
```
#### `.setSizes([])`
setSizes behaves the same as the `sizes` configuration option, passing an array of percentages. It updates the sizes of the elements in the split. Added in v1.1.0:
```js
instance.setSizes([25, 75])
```
#### `.getSizes()`
getSizes returns an array of percents, suitable for using with `setSizes` or creation. Not supported in IE8. Added in v1.1.2:
```js
instance.getSizes() > [25, 75]
```
#### `.collapse(index)`
collapse changes the size of element at `index` to it's `minSize`. Every element except the last is collapsed towards the front (left or top). The last is collapsed towards the back. Not supported in IE8. Added in v1.1.0:
```js
instance.collapse(0)
```
#### `.destroy(preserveStyles? = false, preserveGutters? = false)`
Destroy the instance. It removes the gutter elements, and the size CSS styles Split.js set. Added in v1.1.1.
Passing `preserveStyles = true` does not remove the CSS styles. Option added in v1.4.0.
Passing `preserveGutters = true` does not remove the gutter elements. Option added in v1.4.1.
```js
instance.destroy()
```
## CSS
In being non-opionionated, the only CSS Split.js sets is the widths or heights of the elements. Everything else is left up to you. You must set the elements and gutter heights when using horizontal mode. The gutters will not be visible if their height is 0px. Here's some basic CSS to style the gutters with, although it's not required. Both grip images are included in this repo:
```css
.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
}
.gutter.gutter-horizontal {
background-image: url('grips/vertical.png');
cursor: col-resize;
}
.gutter.gutter-vertical {
background-image: url('grips/horizontal.png');
cursor: row-resize;
}
```
The grip images are small files and can be included with base64 instead:
```css
.gutter.gutter-vertical {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
}
.gutter.gutter-horizontal {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
}
```
Split.js also works best when the elements are sized using `border-box`. The `split` class would have to be added manually to apply these styles:
```css
.split {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
```
And for horizontal splits, make sure the layout allows elements (including gutters) to be displayed side-by-side. Floating the elements is one option:
```css
.split,
.gutter.gutter-horizontal {
float: left;
}
```
If you use floats, set the height of the elements including the gutters. The gutters will not be visible otherwise if the height is set to 0px.
```css
.split,
.gutter.gutter-horizontal {
height: 300px;
}
```
Overflow can be handled as well, to get scrolling within the elements:
```css
.split {
overflow-y: auto;
overflow-x: hidden;
}
```
## React
Split.js is also available as a React component: [react-split](https://github.com/nathancahill/react-split). The component accepts the same options as the Split.js constructor:
```js
import Split from 'react-split'
ReactDOM.render(
<Split sizes={[25, 75]}>
<Component />
<Component />
</Split>,
)
```
## Browser Support
This library uses [CSS calc()](https://developer.mozilla.org/en-US/docs/Web/CSS/calc#AutoCompatibilityTable), [CSS box-sizing](https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing#AutoCompatibilityTable) and [JS getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#AutoCompatibilityTable). These features are supported in the following browsers:
| <img src="http://i.imgur.com/dJC1GUv.png" width="48px" height="48px" alt="Chrome logo"> | <img src="http://i.imgur.com/o1m5RcQ.png" width="48px" height="48px" alt="Firefox logo"> | <img src="http://i.imgur.com/8h3iz5H.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="http://i.imgur.com/iQV4nmJ.png" width="48px" height="48px" alt="Opera logo"> | <img src="http://i.imgur.com/j3tgNKJ.png" width="48px" height="48px" alt="Safari logo"> | [<img src="http://i.imgur.com/70as3qf.png" height="48px" alt="BrowserStack logo">](http://browserstack.com/) |
| :-------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------- |
| 22+ ✔ | 6+ ✔ | 9+ ✔ | 15+ ✔ | 6.2+ ✔ | Sponsored ✔ |
Gracefully falls back in IE 8 and below to only setting the initial widths/heights and not allowing dragging. IE 8 requires polyfills for `Array.isArray()`, `Array.forEach`, `Array.map`, `Array.filter`, `Object.keys()` and `getComputedStyle`. This script from [Polyfill.io](https://polyfill.io/) includes all of these, adding 1.91 kb to the gzipped size.
This is **ONLY NEEDED** if you are supporting **IE8:**
```html
<script src="///polyfill.io/v2/polyfill.min.js?features=Array.isArray,Array.prototype.forEach,Array.prototype.map,Object.keys,Array.prototype.filter,getComputedStyle"></script>
```
This project's tests are run on multiple desktop and mobile browsers sponsored by [BrowserStack](http://browserstack.com/).
## Credits
### Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="graphs/contributors"><img src="https://opencollective.com/splitjs/contributors.svg?width=890&button=false" /></a>
### Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/splitjs#backer)]
<a href="https://opencollective.com/splitjs#backers" target="_blank"><img src="https://opencollective.com/splitjs/backers.svg?width=890"></a>
### Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/splitjs#sponsor)]
<a href="https://opencollective.com/splitjs/sponsor/0/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/1/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/2/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/3/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/4/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/5/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/6/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/7/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/8/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/splitjs/sponsor/9/website" target="_blank"><img src="https://opencollective.com/splitjs/sponsor/9/avatar.svg"></a>
## License
Copyright (c) 2018 Nathan Cahill
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

96
packages/splitjs/index.d.ts vendored Normal file
View File

@@ -0,0 +1,96 @@
// Type definitions for split.js 1.3
// Project: https://github.com/nathancahill/Split.js
// Definitions by: Ilia Choly <https://github.com/icholy>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1
// Global variable outside module loader
export as namespace Split;
// Module loader
export = Split;
declare function Split(
elements: Array<string | HTMLElement>,
options?: Split.Options
): Split.Instance;
declare namespace Split {
type Partial<T> = {[P in keyof T]?: T[P]};
type CSSStyleDeclarationPartial = Partial<CSSStyleDeclaration>;
interface Options {
// Initial sizes of each element in percents or CSS values.
sizes?: number[];
// Minimum size of each element.
minSize?: number | number[];
expandToMin?: boolean;
// Gutter size in pixels.
gutterSize?: number;
gutterAlign?: string;
// Snap to minimum size offset in pixels.
snapOffset?: number;
dragInterval?: number;
// Direction to split: horizontal or vertical.
direction?: 'horizontal' | 'vertical';
// Cursor to display while dragging.
cursor?: 'col-resize' | 'row-resize';
// Callback on drag.
onDrag?(): void;
// Callback on drag start.
onDragStart?(): void;
// Callback on drag end.
onDragEnd?(): void;
// Called to create each gutter element
gutter?(
index: number,
direction: 'horizontal' | 'vertical'
): HTMLElement;
// Called to set the style of each element.
elementStyle?(
dimension: 'width' | 'height',
elementSize: number,
gutterSize: number,
index: number,
): CSSStyleDeclarationPartial;
// Called to set the style of the gutter.
gutterStyle?(
dimension: 'width' | 'height',
gutterSize: number,
index: number,
): CSSStyleDeclarationPartial;
}
interface Instance {
// setSizes behaves the same as the sizes configuration option, passing an array of percents or CSS values.
// It updates the sizes of the elements in the split.
setSizes(sizes: number[]): void;
// getSizes returns an array of percents, suitable for using with setSizes or creation.
// Not supported in IE8.
getSizes(): number[];
// collapse changes the size of element at index to 0.
// Every element except the last is collapsed towards the front (left or top).
// The last is collapsed towards the back.
// Not supported in IE8.
collapse(index: number): void;
// Destroy the instance. It removes the gutter elements, and the size CSS styles Split.js set.
destroy(preserveStyles?: boolean, preserveGutters?: boolean): void;
}
}

View File

@@ -0,0 +1,8 @@
module.exports = config => {
config.set({
frameworks: ['jasmine'],
browsers: ['FirefoxHeadless', 'ChromeHeadless'],
singleRun: true,
files: ['dist/split.js', 'test/split.spec.js'],
})
}

View File

@@ -0,0 +1 @@
<svg viewBox="0 0 416 139" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M295 109.488V95.66c3.555 3.164 7.227 5.537 11.016 7.12 3.79 1.58 7.714 2.372 11.777 2.372 5.586 0 9.482-1.455 11.69-4.365 2.206-2.91 3.31-8.33 3.31-16.26V35.543H310.47v-9.96h34.16v58.944c0 11.016-2.062 18.81-6.183 23.38-4.12 4.57-11.006 6.855-20.654 6.855-3.75 0-7.48-.43-11.19-1.29-3.712-.86-7.58-2.187-11.603-3.984zM410.156 28.57v12.012c-3.594-2.305-7.197-4.043-10.81-5.215-3.614-1.172-7.256-1.758-10.928-1.758-5.586 0-10 1.298-13.242 3.896-3.242 2.598-4.863 6.103-4.863 10.517 0 3.868 1.064 6.817 3.193 8.848 2.13 2.032 6.103 3.732 11.924 5.1l6.21 1.405c8.204 1.914 14.18 4.922 17.93 9.023 3.75 4.102 5.625 9.688 5.625 16.758 0 8.32-2.578 14.668-7.734 19.043-5.155 4.374-12.655 6.562-22.5 6.562-4.1 0-8.222-.44-12.362-1.32-4.14-.878-8.3-2.196-12.48-3.954V96.89c4.49 2.852 8.74 4.942 12.743 6.27 4.005 1.328 8.038 1.992 12.1 1.992 5.978 0 10.626-1.338 13.946-4.013 3.32-2.677 4.98-6.417 4.98-11.222 0-4.375-1.142-7.715-3.427-10.02-2.286-2.304-6.26-4.082-11.925-5.332l-6.328-1.464c-8.125-1.836-14.023-4.61-17.695-8.32-3.672-3.712-5.508-8.692-5.508-14.942 0-7.813 2.627-14.072 7.88-18.78 5.255-4.707 12.237-7.06 20.948-7.06 3.36 0 6.895.38 10.606 1.143 3.71.76 7.617 1.904 11.718 3.427zM51.152 28.57v12.012c-3.593-2.305-7.197-4.043-10.81-5.215-3.614-1.172-7.256-1.758-10.928-1.758-5.586 0-10 1.298-13.242 3.896-3.242 2.598-4.863 6.103-4.863 10.517 0 3.868 1.063 6.817 3.192 8.848 2.13 2.032 6.103 3.732 11.924 5.1l6.21 1.405c8.204 1.914 14.18 4.922 17.93 9.023 3.75 4.102 5.625 9.688 5.625 16.758 0 8.32-2.577 14.668-7.733 19.043-5.156 4.374-12.656 6.562-22.5 6.562-4.102 0-8.223-.44-12.363-1.32-4.14-.878-8.3-2.196-12.48-3.954V96.89c4.49 2.852 8.74 4.942 12.743 6.27 4.004 1.328 8.038 1.992 12.1 1.992 5.977 0 10.625-1.338 13.945-4.013 3.32-2.677 4.98-6.417 4.98-11.222 0-4.375-1.142-7.715-3.427-10.02-2.285-2.304-6.26-4.082-11.924-5.332l-6.327-1.464c-8.125-1.836-14.023-4.61-17.695-8.32C1.836 61.07 0 56.09 0 49.84c0-7.813 2.627-14.072 7.88-18.78C13.136 26.354 20.118 24 28.83 24c3.36 0 6.895.38 10.606 1.143 3.71.76 7.617 1.904 11.718 3.427zm26.328 6.74v32.87h13.71c5.47 0 9.738-1.446 12.804-4.336 3.067-2.89 4.6-6.934 4.6-12.13 0-5.194-1.524-9.228-4.57-12.1-3.047-2.87-7.325-4.305-12.833-4.305H77.48zM65.645 25.58H91.19c9.767 0 17.17 2.217 22.208 6.65 5.04 4.434 7.56 10.928 7.56 19.483 0 8.633-2.51 15.156-7.53 19.57-5.02 4.414-12.432 6.62-22.237 6.62H77.48v35.157H65.645v-87.48zm63.3 0h11.895v77.52h42.246v9.96h-54.14v-87.48z" fill="#34495E"/><path d="M207 6v127" stroke="#34495E" stroke-width="12" stroke-linecap="square"/><path d="M244.795 68.91l-11.088-11.087c-.55-.55-1.2-.823-1.95-.823s-1.4.274-1.95.823c-.547.548-.82 1.198-.82 1.95v5.543h-44.354v-5.544c0-.75-.275-1.4-.824-1.95-.55-.548-1.2-.822-1.95-.822s-1.4.274-1.95.823L168.824 68.91c-.55.55-.823 1.2-.823 1.95s.274 1.4.823 1.95l11.088 11.087c.55.548 1.2.823 1.95.823s1.4-.275 1.95-.823c.548-.548.823-1.198.823-1.95v-5.544h44.353v5.545c0 .75.274 1.4.822 1.95.55.547 1.2.822 1.95.822s1.4-.275 1.95-.823l11.087-11.088c.55-.55.823-1.2.823-1.95s-.274-1.4-.823-1.95z" fill="#34495E" fill-rule="nonzero"/><path fill="#34495E" d="M285.14 113.48h-11.894V35.96H231V26h54.14"/></g></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,37 @@
{
"name": "split.js",
"version": "1.5.7",
"description": "2kb unopinionated utility for resizeable split views",
"main": "dist/split.js",
"minified:main": "dist/split.min.js",
"repository": {
"type": "git",
"url": "git+https://github.com/nathancahill/Split.js.git"
},
"keywords": ["css", "split", "flexbox", "tiny", "split-layout"],
"author": "Nathan Cahill <nathan@nathancahill.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/nathancahill/Split.js/issues"
},
"homepage": "https://split.js.org/",
"scripts": {
"lint": "eslint src",
"test": "karma start",
"build": "rollup -c && npm run size",
"watch": "rollup -cw",
"size": "echo \"gzip size: $(gzip-size --raw $npm_package_minified_main) bytes\""
},
"browserslist": [
"Chrome >= 22",
"Firefox >= 6",
"Opera >= 15",
"Safari >= 6.2",
"IE >= 9",
"IE 8"
],
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/splitjs"
}
}

View File

@@ -0,0 +1,36 @@
import buble from 'rollup-plugin-buble'
import { uglify } from 'rollup-plugin-uglify'
const pkg = require('./package.json')
const output = {
format: 'umd',
file: pkg.main,
name: 'Split',
sourcemap: false,
banner: `/*! Split.js - v${pkg.version} */\n`,
}
export default [
{
input: 'src/split.js',
output,
plugins: [buble()],
},
{
input: 'src/split.js',
output: {
...output,
sourcemap: true,
file: pkg['minified:main'],
},
plugins: [
buble(),
uglify({
output: {
comments: /^!/,
},
}),
],
},
]

View File

@@ -0,0 +1,756 @@
// The programming goals of Split.js are to deliver readable, understandable and
// maintainable code, while at the same time manually optimizing for tiny minified file size,
// browser compatibility without additional requirements, graceful fallback (IE8 is supported)
// and very few assumptions about the user's page layout.
const global = window
const { document } = global
// Save a couple long function names that are used frequently.
// This optimization saves around 400 bytes.
const addEventListener = 'addEventListener'
const removeEventListener = 'removeEventListener'
const getBoundingClientRect = 'getBoundingClientRect'
const gutterStartDragging = '_a'
const aGutterSize = '_b'
const bGutterSize = '_c'
const HORIZONTAL = 'horizontal'
const NOOP = () => false
// Figure out if we're in IE8 or not. IE8 will still render correctly,
// but will be static instead of draggable.
const isIE8 = global.attachEvent && !global[addEventListener]
// Helper function determines which prefixes of CSS calc we need.
// We only need to do this once on startup, when this anonymous function is called.
//
// Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
// http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
const calc = `${['', '-webkit-', '-moz-', '-o-']
.filter(prefix => {
const el = document.createElement('div')
el.style.cssText = `width:${prefix}calc(9px)`
return !!el.style.length
})
.shift()}calc`
// Helper function checks if its argument is a string-like type
const isString = v => typeof v === 'string' || v instanceof String
// Helper function allows elements and string selectors to be used
// interchangeably. In either case an element is returned. This allows us to
// do `Split([elem1, elem2])` as well as `Split(['#id1', '#id2'])`.
const elementOrSelector = el => {
if (isString(el)) {
const ele = document.querySelector(el)
if (!ele) {
throw new Error(`Selector ${el} did not match a DOM element`)
}
return ele
}
return el
}
// Helper function gets a property from the properties object, with a default fallback
const getOption = (options, propName, def) => {
const value = options[propName]
if (value !== undefined) {
return value
}
return def
}
const getGutterSize = (gutterSize, isFirst, isLast, gutterAlign) => {
if (isFirst) {
if (gutterAlign === 'end') {
return 0
}
if (gutterAlign === 'center') {
return gutterSize / 2
}
} else if (isLast) {
if (gutterAlign === 'start') {
return 0
}
if (gutterAlign === 'center') {
return gutterSize / 2
}
}
return gutterSize
}
// Default options
const defaultGutterFn = (i, gutterDirection) => {
const gut = document.createElement('div')
gut.className = `gutter gutter-${gutterDirection}`
return gut
}
const defaultElementStyleFn = (dim, size, gutSize) => {
const style = {}
if (!isString(size)) {
if (!isIE8) {
style[dim] = `${calc}(${size}% - ${gutSize}px)`
} else {
style[dim] = `${size}%`
}
} else {
style[dim] = size
}
return style
}
const defaultGutterStyleFn = (dim, gutSize) => ({ [dim]: `${gutSize}px` })
// The main function to initialize a split. Split.js thinks about each pair
// of elements as an independant pair. Dragging the gutter between two elements
// only changes the dimensions of elements in that pair. This is key to understanding
// how the following functions operate, since each function is bound to a pair.
//
// A pair object is shaped like this:
//
// {
// a: DOM element,
// b: DOM element,
// aMin: Number,
// bMin: Number,
// dragging: Boolean,
// parent: DOM element,
// direction: 'horizontal' | 'vertical'
// }
//
// The basic sequence:
//
// 1. Set defaults to something sane. `options` doesn't have to be passed at all.
// 2. Initialize a bunch of strings based on the direction we're splitting.
// A lot of the behavior in the rest of the library is paramatized down to
// rely on CSS strings and classes.
// 3. Define the dragging helper functions, and a few helpers to go with them.
// 4. Loop through the elements while pairing them off. Every pair gets an
// `pair` object and a gutter.
// 5. Actually size the pair elements, insert gutters and attach event listeners.
const Split = (idsOption, options = {}) => {
let ids = idsOption
let dimension
let clientAxis
let position
let positionEnd
let clientSize
let elements
// Allow HTMLCollection to be used as an argument when supported
if (Array.from) {
ids = Array.from(ids)
}
// All DOM elements in the split should have a common parent. We can grab
// the first elements parent and hope users read the docs because the
// behavior will be whacky otherwise.
const firstElement = elementOrSelector(ids[0])
const parent = firstElement.parentNode
const parentFlexDirection = getComputedStyle
? getComputedStyle(parent).flexDirection
: null
// Set default options.sizes to equal percentages of the parent element.
let sizes = getOption(options, 'sizes') || ids.map(() => 100 / ids.length)
// Standardize minSize to an array if it isn't already. This allows minSize
// to be passed as a number.
const minSize = getOption(options, 'minSize', 100)
const minSizes = Array.isArray(minSize) ? minSize : ids.map(() => minSize)
// Get other options
const expandToMin = getOption(options, 'expandToMin', false)
const gutterSize = getOption(options, 'gutterSize', 10)
const gutterAlign = getOption(options, 'gutterAlign', 'center')
const snapOffset = getOption(options, 'snapOffset', 30)
const dragInterval = getOption(options, 'dragInterval', 1)
const direction = getOption(options, 'direction', HORIZONTAL)
const cursor = getOption(
options,
'cursor',
direction === HORIZONTAL ? 'col-resize' : 'row-resize',
)
const gutter = getOption(options, 'gutter', defaultGutterFn)
const elementStyle = getOption(
options,
'elementStyle',
defaultElementStyleFn,
)
const gutterStyle = getOption(options, 'gutterStyle', defaultGutterStyleFn)
// 2. Initialize a bunch of strings based on the direction we're splitting.
// A lot of the behavior in the rest of the library is paramatized down to
// rely on CSS strings and classes.
if (direction === HORIZONTAL) {
dimension = 'width'
clientAxis = 'clientX'
position = 'left'
positionEnd = 'right'
clientSize = 'clientWidth'
} else if (direction === 'vertical') {
dimension = 'height'
clientAxis = 'clientY'
position = 'top'
positionEnd = 'bottom'
clientSize = 'clientHeight'
}
// 3. Define the dragging helper functions, and a few helpers to go with them.
// Each helper is bound to a pair object that contains its metadata. This
// also makes it easy to store references to listeners that that will be
// added and removed.
//
// Even though there are no other functions contained in them, aliasing
// this to self saves 50 bytes or so since it's used so frequently.
//
// The pair object saves metadata like dragging state, position and
// event listener references.
function setElementSize(el, size, gutSize, i) {
// Split.js allows setting sizes via numbers (ideally), or if you must,
// by string, like '300px'. This is less than ideal, because it breaks
// the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
// make sure you calculate the gutter size by hand.
const style = elementStyle(dimension, size, gutSize, i)
Object.keys(style).forEach(prop => {
// eslint-disable-next-line no-param-reassign
el.style[prop] = style[prop]
})
}
function setGutterSize(gutterElement, gutSize, i) {
const style = gutterStyle(dimension, gutSize, i)
Object.keys(style).forEach(prop => {
// eslint-disable-next-line no-param-reassign
gutterElement.style[prop] = style[prop]
})
}
function getSizes() {
return elements.map(element => element.size)
}
// Supports touch events, but not multitouch, so only the first
// finger `touches[0]` is counted.
function getMousePosition(e) {
if ('touches' in e) return e.touches[0][clientAxis]
return e[clientAxis]
}
// Actually adjust the size of elements `a` and `b` to `offset` while dragging.
// calc is used to allow calc(percentage + gutterpx) on the whole split instance,
// which allows the viewport to be resized without additional logic.
// Element a's size is the same as offset. b's size is total size - a size.
// Both sizes are calculated from the initial parent percentage,
// then the gutter size is subtracted.
function adjust(offset) {
const a = elements[this.a]
const b = elements[this.b]
const percentage = a.size + b.size
a.size = (offset / this.size) * percentage
b.size = percentage - (offset / this.size) * percentage
setElementSize(a.element, a.size, this[aGutterSize], a.i)
setElementSize(b.element, b.size, this[bGutterSize], b.i)
}
// drag, where all the magic happens. The logic is really quite simple:
//
// 1. Ignore if the pair is not dragging.
// 2. Get the offset of the event.
// 3. Snap offset to min if within snappable range (within min + snapOffset).
// 4. Actually adjust each element in the pair to offset.
//
// ---------------------------------------------------------------------
// | | <- a.minSize || b.minSize -> | |
// | | | <- this.snapOffset || this.snapOffset -> | | |
// | | | || | | |
// | | | || | | |
// ---------------------------------------------------------------------
// | <- this.start this.size -> |
function drag(e) {
let offset
const a = elements[this.a]
const b = elements[this.b]
if (!this.dragging) return
// Get the offset of the event from the first side of the
// pair `this.start`. Then offset by the initial position of the
// mouse compared to the gutter size.
offset =
getMousePosition(e) -
this.start +
(this[aGutterSize] - this.dragOffset)
if (dragInterval > 1) {
offset = Math.round(offset / dragInterval) * dragInterval
}
// If within snapOffset of min or max, set offset to min or max.
// snapOffset buffers a.minSize and b.minSize, so logic is opposite for both.
// Include the appropriate gutter sizes to prevent overflows.
if (offset <= a.minSize + snapOffset + this[aGutterSize]) {
offset = a.minSize + this[aGutterSize]
} else if (
offset >=
this.size - (b.minSize + snapOffset + this[bGutterSize])
) {
offset = this.size - (b.minSize + this[bGutterSize])
}
// Actually adjust the size.
adjust.call(this, offset)
// Call the drag callback continously. Don't do anything too intensive
// in this callback.
getOption(options, 'onDrag', NOOP)()
}
// Cache some important sizes when drag starts, so we don't have to do that
// continously:
//
// `size`: The total size of the pair. First + second + first gutter + second gutter.
// `start`: The leading side of the first element.
//
// ------------------------------------------------
// | aGutterSize -> ||| |
// | ||| |
// | ||| |
// | ||| <- bGutterSize |
// ------------------------------------------------
// | <- start size -> |
function calculateSizes() {
// Figure out the parent size minus padding.
const a = elements[this.a].element
const b = elements[this.b].element
const aBounds = a[getBoundingClientRect]()
const bBounds = b[getBoundingClientRect]()
this.size =
aBounds[dimension] +
bBounds[dimension] +
this[aGutterSize] +
this[bGutterSize]
this.start = aBounds[position]
this.end = aBounds[positionEnd]
}
function innerSize(element) {
// Return nothing if getComputedStyle is not supported (< IE9)
if (!getComputedStyle) return null
const computedStyle = getComputedStyle(element)
let size = element[clientSize]
if (direction === HORIZONTAL) {
size -=
parseFloat(computedStyle.paddingLeft) +
parseFloat(computedStyle.paddingRight)
} else {
size -=
parseFloat(computedStyle.paddingTop) +
parseFloat(computedStyle.paddingBottom)
}
return size
}
// When specifying percentage sizes that are less than the computed
// size of the element minus the gutter, the lesser percentages must be increased
// (and decreased from the other elements) to make space for the pixels
// subtracted by the gutters.
function trimToMin(sizesToTrim) {
// Try to get inner size of parent element.
// If it's no supported, return original sizes.
const parentSize = innerSize(parent)
if (parentSize === null) {
return sizesToTrim
}
// Keep track of the excess pixels, the amount of pixels over the desired percentage
// Also keep track of the elements with pixels to spare, to decrease after if needed
let excessPixels = 0
const toSpare = []
const pixelSizes = sizesToTrim.map((size, i) => {
// Convert requested percentages to pixel sizes
const pixelSize = (parentSize * size) / 100
const elementGutterSize = getGutterSize(
gutterSize,
i === 0,
i === sizesToTrim.length - 1,
gutterAlign,
)
const elementMinSize = minSizes[i] + elementGutterSize
// If element is too smal, increase excess pixels by the difference
// and mark that it has no pixels to spare
if (pixelSize < elementMinSize) {
excessPixels += elementMinSize - pixelSize
toSpare.push(0)
return elementMinSize
}
// Otherwise, mark the pixels it has to spare and return it's original size
toSpare.push(pixelSize - elementMinSize)
return pixelSize
})
// If nothing was adjusted, return the original sizes
if (excessPixels === 0) {
return sizesToTrim
}
return pixelSizes.map((pixelSize, i) => {
let newPixelSize = pixelSize
// While there's still pixels to take, and there's enough pixels to spare,
// take as many as possible up to the total excess pixels
if (excessPixels > 0 && toSpare[i] - excessPixels > 0) {
const takenPixels = Math.min(
excessPixels,
toSpare[i] - excessPixels,
)
// Subtract the amount taken for the next iteration
excessPixels -= takenPixels
newPixelSize = pixelSize - takenPixels
}
// Return the pixel size adjusted as a percentage
return (newPixelSize / parentSize) * 100
})
}
// stopDragging is very similar to startDragging in reverse.
function stopDragging() {
const self = this
const a = elements[self.a].element
const b = elements[self.b].element
if (self.dragging) {
getOption(options, 'onDragEnd', NOOP)(getSizes())
}
self.dragging = false
// Remove the stored event listeners. This is why we store them.
global[removeEventListener]('mouseup', self.stop)
global[removeEventListener]('touchend', self.stop)
global[removeEventListener]('touchcancel', self.stop)
global[removeEventListener]('mousemove', self.move)
global[removeEventListener]('touchmove', self.move)
// Clear bound function references
self.stop = null
self.move = null
a[removeEventListener]('selectstart', NOOP)
a[removeEventListener]('dragstart', NOOP)
b[removeEventListener]('selectstart', NOOP)
b[removeEventListener]('dragstart', NOOP)
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 = ''
document.body.style.cursor = ''
}
// startDragging calls `calculateSizes` to store the inital size in the pair object.
// It also adds event listeners for mouse/touch events,
// and prevents selection while dragging so avoid the selecting text.
function startDragging(e) {
// Right-clicking can't start dragging.
if ('button' in e && e.button !== 0) {
return
}
// Alias frequently used variables to save space. 200 bytes.
const self = this
const a = elements[self.a].element
const b = elements[self.b].element
// Call the onDragStart callback.
if (!self.dragging) {
getOption(options, 'onDragStart', NOOP)(getSizes())
}
// Don't actually drag the element. We emulate that in the drag function.
e.preventDefault()
// Set the dragging property of the pair object.
self.dragging = true
// Create two event listeners bound to the same pair object and store
// them in the pair object.
self.move = drag.bind(self)
self.stop = stopDragging.bind(self)
// All the binding. `window` gets the stop events in case we drag out of the elements.
global[addEventListener]('mouseup', self.stop)
global[addEventListener]('touchend', self.stop)
global[addEventListener]('touchcancel', self.stop)
global[addEventListener]('mousemove', self.move)
global[addEventListener]('touchmove', self.move)
// Disable selection. Disable!
a[addEventListener]('selectstart', NOOP)
a[addEventListener]('dragstart', NOOP)
b[addEventListener]('selectstart', NOOP)
b[addEventListener]('dragstart', NOOP)
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'
// Set the cursor at multiple levels
self.gutter.style.cursor = cursor
self.parent.style.cursor = cursor
document.body.style.cursor = cursor
// Cache the initial sizes of the pair.
calculateSizes.call(self)
// Determine the position of the mouse compared to the gutter
self.dragOffset = getMousePosition(e) - self.end
}
// adjust sizes to ensure percentage is within min size and gutter.
sizes = trimToMin(sizes)
// 5. Create pair and element objects. Each pair has an index reference to
// elements `a` and `b` of the pair (first and second elements).
// Loop through the elements while pairing them off. Every pair gets a
// `pair` object and a gutter.
//
// Basic logic:
//
// - Starting with the second element `i > 0`, create `pair` objects with
// `a = i - 1` and `b = i`
// - Set gutter sizes based on the _pair_ being first/last. The first and last
// pair have gutterSize / 2, since they only have one half gutter, and not two.
// - Create gutter elements and add event listeners.
// - Set the size of the elements, minus the gutter sizes.
//
// -----------------------------------------------------------------------
// | i=0 | i=1 | i=2 | i=3 |
// | | | | |
// | pair 0 pair 1 pair 2 |
// | | | | |
// -----------------------------------------------------------------------
const pairs = []
elements = ids.map((id, i) => {
// Create the element object.
const element = {
element: elementOrSelector(id),
size: sizes[i],
minSize: minSizes[i],
i,
}
let pair
if (i > 0) {
// Create the pair object with its metadata.
pair = {
a: i - 1,
b: i,
dragging: false,
direction,
parent,
}
pair[aGutterSize] = getGutterSize(
gutterSize,
i - 1 === 0,
false,
gutterAlign,
)
pair[bGutterSize] = getGutterSize(
gutterSize,
false,
i === ids.length - 1,
gutterAlign,
)
// if the parent has a reverse flex-direction, switch the pair elements.
if (
parentFlexDirection === 'row-reverse' ||
parentFlexDirection === 'column-reverse'
) {
const temp = pair.a
pair.a = pair.b
pair.b = temp
}
}
// Determine the size of the current element. IE8 is supported by
// staticly assigning sizes without draggable gutters. Assigns a string
// to `size`.
//
// IE9 and above
if (!isIE8) {
// Create gutter elements for each pair.
if (i > 0) {
const gutterElement = gutter(i, direction, element.element)
setGutterSize(gutterElement, gutterSize, i)
// Save bound event listener for removal later
pair[gutterStartDragging] = startDragging.bind(pair)
// Attach bound event listener
gutterElement[addEventListener](
'mousedown',
pair[gutterStartDragging],
)
gutterElement[addEventListener](
'touchstart',
pair[gutterStartDragging],
)
parent.insertBefore(gutterElement, element.element)
pair.gutter = gutterElement
}
}
setElementSize(
element.element,
element.size,
getGutterSize(
gutterSize,
i === 0,
i === ids.length - 1,
gutterAlign,
),
)
// After the first iteration, and we have a pair object, append it to the
// list of pairs.
if (i > 0) {
pairs.push(pair)
}
return element
})
function adjustToMin(element) {
const isLast = element.i === pairs.length
const pair = isLast ? pairs[element.i - 1] : pairs[element.i]
calculateSizes.call(pair)
const size = isLast
? pair.size - element.minSize - pair[bGutterSize]
: element.minSize + pair[aGutterSize]
adjust.call(pair, size)
}
elements.forEach(element => {
const computedSize = element.element[getBoundingClientRect]()[dimension]
if (computedSize < element.minSize) {
if (expandToMin) {
adjustToMin(element)
} else {
// eslint-disable-next-line no-param-reassign
element.minSize = computedSize
}
}
})
function setSizes(newSizes) {
const trimmed = trimToMin(newSizes)
trimmed.forEach((newSize, i) => {
if (i > 0) {
const pair = pairs[i - 1]
const a = elements[pair.a]
const b = elements[pair.b]
a.size = trimmed[i - 1]
b.size = newSize
setElementSize(a.element, a.size, pair[aGutterSize])
setElementSize(b.element, b.size, pair[bGutterSize])
}
})
}
function destroy(preserveStyles, preserveGutter) {
pairs.forEach(pair => {
if (preserveGutter !== true) {
pair.parent.removeChild(pair.gutter)
} else {
pair.gutter[removeEventListener](
'mousedown',
pair[gutterStartDragging],
)
pair.gutter[removeEventListener](
'touchstart',
pair[gutterStartDragging],
)
}
if (preserveStyles !== true) {
const style = elementStyle(
dimension,
pair.a.size,
pair[aGutterSize],
)
Object.keys(style).forEach(prop => {
elements[pair.a].element.style[prop] = ''
elements[pair.b].element.style[prop] = ''
})
}
})
}
if (isIE8) {
return {
setSizes,
destroy,
}
}
return {
setSizes,
getSizes,
collapse(i) {
adjustToMin(elements[i])
},
destroy,
parent,
pairs,
}
}
export default Split

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jasmine Spec Runner v2.6.4</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-2.6.4/jasmine_favicon.png">
<link rel="stylesheet" href="lib/jasmine-2.6.4/jasmine.css">
<script src="lib/jasmine-2.6.4/jasmine.js"></script>
<script src="lib/jasmine-2.6.4/jasmine-html.js"></script>
<script src="lib/jasmine-2.6.4/boot.js"></script>
<script src="../dist/split.js"></script>
<script src="split.spec.js"></script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,48 @@
{
"test_framework": "jasmine2",
"test_path": "test/SpecRunner.html",
"browsers": [
{
"browser": "chrome",
"browser_version": "22",
"os": "OS X",
"os_version": "Mountain Lion"
},
{
"browser": "firefox",
"browser_version": "6",
"os": "OS X",
"os_version": "Mountain Lion"
},
{
"browser": "ie",
"browser_version": "9",
"os": "Windows",
"os_version": "7"
},
{
"browser": "ie",
"browser_version": "10",
"os": "Windows",
"os_version": "7"
},
{
"browser": "ie",
"browser_version": "11",
"os": "Windows",
"os_version": "7"
},
{
"browser": "opera",
"browser_version": "16",
"os": "OS X",
"os_version": "Mountain Lion"
},
{
"browser": "safari",
"browser_version": "6.2",
"os": "OS X",
"os_version": "Mountain Lion"
}
]
}

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jasmine Spec Runner v2.6.4</title>
<link rel="shortcut icon" type="image/png" href="../lib/jasmine-2.6.4/jasmine_favicon.png">
<link rel="stylesheet" href="../lib/jasmine-2.6.4/jasmine.css">
<script src="../lib/jasmine-2.6.4/jasmine.js"></script>
<script src="../lib/jasmine-2.6.4/jasmine-html.js"></script>
<script src="../lib/jasmine-2.6.4/boot.js"></script>
<script src="polyfills.js"></script>
<script src="../../dist/split.js"></script>
<script src="split.spec.js"></script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,12 @@
{
"test_framework": "jasmine2",
"test_path": "test/ie8/SpecRunner.html",
"browsers": [
{
"browser": "ie",
"browser_version": "8",
"os": "Windows",
"os_version": "7"
}
]
}

View File

@@ -0,0 +1,342 @@
/* Polyfill service v3.18.1
* For detailed credits and licence information see https://github.com/financial-times/polyfill-service.
*
* UA detected: firefox/53.0.0
* Features requested: Array.isArray,Array.prototype.filter,Array.prototype.forEach,Array.prototype.map,Object.keys,getComputedStyle
*
* - Object.defineProperty, License: CC0 (required by "Array.isArray")
* - Array.isArray, License: CC0
* - Array.prototype.filter, License: CC0
* - Array.prototype.forEach, License: CC0
* - Array.prototype.map, License: CC0
* - Object.keys, License: CC0
* - Window, License: CC0 (required by "getComputedStyle")
* - getComputedStyle, License: CC0 */
(function(undefined) {
// Object.defineProperty
(function (nativeDefineProperty) {
var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
var ERR_ACCESSORS_NOT_SUPPORTED = 'Getters & setters cannot be defined on this javascript engine';
var ERR_VALUE_ACCESSORS = 'A property cannot both have accessors and be writable or have a value';
Object.defineProperty = function defineProperty(object, property, descriptor) {
// Where native support exists, assume it
if (nativeDefineProperty && (object === window || object === document || object === Element.prototype || object instanceof Element)) {
return nativeDefineProperty(object, property, descriptor);
}
if (object === null || !(object instanceof Object || typeof object === 'object')) {
throw new TypeError('Object.defineProperty called on non-object');
}
if (!(descriptor instanceof Object)) {
throw new TypeError('Property description must be an object');
}
var propertyString = String(property);
var hasValueOrWritable = 'value' in descriptor || 'writable' in descriptor;
var getterType = 'get' in descriptor && typeof descriptor.get;
var setterType = 'set' in descriptor && typeof descriptor.set;
// handle descriptor.get
if (getterType) {
if (getterType !== 'function') {
throw new TypeError('Getter must be a function');
}
if (!supportsAccessors) {
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
}
if (hasValueOrWritable) {
throw new TypeError(ERR_VALUE_ACCESSORS);
}
object.__defineGetter__(propertyString, descriptor.get);
} else {
object[propertyString] = descriptor.value;
}
// handle descriptor.set
if (setterType) {
if (setterType !== 'function') {
throw new TypeError('Setter must be a function');
}
if (!supportsAccessors) {
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
}
if (hasValueOrWritable) {
throw new TypeError(ERR_VALUE_ACCESSORS);
}
object.__defineSetter__(propertyString, descriptor.set);
}
// OK to define value unconditionally - if a getter has been specified as well, an error would be thrown above
if ('value' in descriptor) {
object[propertyString] = descriptor.value;
}
return object;
};
}(Object.defineProperty));
// Array.isArray
(function (toString) {
Object.defineProperty(Array, 'isArray', {
configurable: true,
value: function isArray(object) {
return toString.call(object) === '[object Array]';
},
writable: true
});
}(Object.prototype.toString));
// Array.prototype.filter
Array.prototype.filter = function filter(callback) {
if (this === undefined || this === null) {
throw new TypeError(this + ' is not an object');
}
if (!(callback instanceof Function)) {
throw new TypeError(callback + ' is not a function');
}
var
object = Object(this),
scope = arguments[1],
arraylike = object instanceof String ? object.split('') : object,
length = Math.max(Math.min(arraylike.length, 9007199254740991), 0) || 0,
index = -1,
result = [],
element;
while (++index < length) {
element = arraylike[index];
if (index in arraylike && callback.call(scope, element, index, object)) {
result.push(element);
}
}
return result;
};
// Array.prototype.forEach
Array.prototype.forEach = function forEach(callback) {
if (this === undefined || this === null) {
throw new TypeError(this + ' is not an object');
}
if (!(callback instanceof Function)) {
throw new TypeError(callback + ' is not a function');
}
var
object = Object(this),
scope = arguments[1],
arraylike = object instanceof String ? object.split('') : object,
length = Math.max(Math.min(arraylike.length, 9007199254740991), 0) || 0,
index = -1;
while (++index < length) {
if (index in arraylike) {
callback.call(scope, arraylike[index], index, object);
}
}
};
// Array.prototype.map
Array.prototype.map = function map(callback) {
if (this === undefined || this === null) {
throw new TypeError(this + ' is not an object');
}
if (!(callback instanceof Function)) {
throw new TypeError(callback + ' is not a function');
}
var
object = Object(this),
scope = arguments[1],
arraylike = object instanceof String ? object.split('') : object,
length = Math.max(Math.min(arraylike.length, 9007199254740991), 0) || 0,
index = -1,
result = [];
while (++index < length) {
if (index in arraylike) {
result[index] = callback.call(scope, arraylike[index], index, object);
}
}
return result;
};
// Object.keys
Object.keys = (function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function(obj) {
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
var result = [], prop, i;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}());
// Window
(function(global) {
if (global.constructor) {
global.Window = global.constructor;
} else {
(global.Window = global.constructor = new Function('return function Window() {}')()).prototype = this;
}
}(this));
// getComputedStyle
(function (global) {
function getComputedStylePixel(element, property, fontSize) {
var
// Internet Explorer sometimes struggles to read currentStyle until the element's document is accessed.
value = element.document && element.currentStyle[property].match(/([\d\.]+)(%|cm|em|in|mm|pc|pt|)/) || [0, 0, ''],
size = value[1],
suffix = value[2],
rootSize;
fontSize = !fontSize ? fontSize : /%|em/.test(suffix) && element.parentElement ? getComputedStylePixel(element.parentElement, 'fontSize', null) : 16;
rootSize = property == 'fontSize' ? fontSize : /width/i.test(property) ? element.clientWidth : element.clientHeight;
return suffix == '%' ? size / 100 * rootSize :
suffix == 'cm' ? size * 0.3937 * 96 :
suffix == 'em' ? size * fontSize :
suffix == 'in' ? size * 96 :
suffix == 'mm' ? size * 0.3937 * 96 / 10 :
suffix == 'pc' ? size * 12 * 96 / 72 :
suffix == 'pt' ? size * 96 / 72 :
size;
}
function setShortStyleProperty(style, property) {
var
borderSuffix = property == 'border' ? 'Width' : '',
t = property + 'Top' + borderSuffix,
r = property + 'Right' + borderSuffix,
b = property + 'Bottom' + borderSuffix,
l = property + 'Left' + borderSuffix;
style[property] = (style[t] == style[r] && style[t] == style[b] && style[t] == style[l] ? [ style[t] ] :
style[t] == style[b] && style[l] == style[r] ? [ style[t], style[r] ] :
style[l] == style[r] ? [ style[t], style[r], style[b] ] :
[ style[t], style[r], style[b], style[l] ]).join(' ');
}
// <CSSStyleDeclaration>
function CSSStyleDeclaration(element) {
var
style = this,
currentStyle = element.currentStyle,
fontSize = getComputedStylePixel(element, 'fontSize'),
unCamelCase = function (match) {
return '-' + match.toLowerCase();
},
property;
for (property in currentStyle) {
Array.prototype.push.call(style, property == 'styleFloat' ? 'float' : property.replace(/[A-Z]/, unCamelCase));
if (property == 'width') {
style[property] = element.offsetWidth + 'px';
} else if (property == 'height') {
style[property] = element.offsetHeight + 'px';
} else if (property == 'styleFloat') {
style.float = currentStyle[property];
} else if (/margin.|padding.|border.+W/.test(property) && style[property] != 'auto') {
style[property] = Math.round(getComputedStylePixel(element, property, fontSize)) + 'px';
} else if (/^outline/.test(property)) {
// errors on checking outline
try {
style[property] = currentStyle[property];
} catch (error) {
style.outlineColor = currentStyle.color;
style.outlineStyle = style.outlineStyle || 'none';
style.outlineWidth = style.outlineWidth || '0px';
style.outline = [style.outlineColor, style.outlineWidth, style.outlineStyle].join(' ');
}
} else {
style[property] = currentStyle[property];
}
}
setShortStyleProperty(style, 'margin');
setShortStyleProperty(style, 'padding');
setShortStyleProperty(style, 'border');
style.fontSize = Math.round(fontSize) + 'px';
}
CSSStyleDeclaration.prototype = {
constructor: CSSStyleDeclaration,
// <CSSStyleDeclaration>.getPropertyPriority
getPropertyPriority: function () {
throw new Error('NotSupportedError: DOM Exception 9');
},
// <CSSStyleDeclaration>.getPropertyValue
getPropertyValue: function (property) {
return this[property.replace(/-\w/g, function (match) {
return match[1].toUpperCase();
})];
},
// <CSSStyleDeclaration>.item
item: function (index) {
return this[index];
},
// <CSSStyleDeclaration>.removeProperty
removeProperty: function () {
throw new Error('NoModificationAllowedError: DOM Exception 7');
},
// <CSSStyleDeclaration>.setProperty
setProperty: function () {
throw new Error('NoModificationAllowedError: DOM Exception 7');
},
// <CSSStyleDeclaration>.getPropertyCSSValue
getPropertyCSSValue: function () {
throw new Error('NotSupportedError: DOM Exception 9');
}
};
// <Global>.getComputedStyle
global.getComputedStyle = function getComputedStyle(element) {
return new CSSStyleDeclaration(element);
};
}(this));
})
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});

View File

@@ -0,0 +1,141 @@
/* eslint-env jasmine */
/* global Split */
/* eslint-disable no-var, func-names, prefer-arrow-callback, object-shorthand, prefer-template */
describe('Split', function() {
beforeEach(function() {
document.body.style.width = '800px'
document.body.style.height = '600px'
this.a = document.createElement('div')
this.b = document.createElement('div')
this.c = document.createElement('div')
this.a.id = 'a'
this.b.id = 'b'
this.c.id = 'c'
document.body.appendChild(this.a)
document.body.appendChild(this.b)
document.body.appendChild(this.c)
})
afterEach(function() {
document.body.removeChild(this.a)
document.body.removeChild(this.b)
document.body.removeChild(this.c)
})
it('splits in two when given two elements', function() {
Split(['#a', '#b'])
expect(this.a.style.width).toBe('50%')
expect(this.b.style.width).toBe('50%')
})
it('splits in three when given three elements', function() {
Split(['#a', '#b', '#c'])
expect(this.a.style.width).toBe('33.33%')
expect(this.b.style.width).toBe('33.33%')
expect(this.c.style.width).toBe('33.33%')
})
it('splits vertically when direction is vertical', function() {
Split(['#a', '#b'], {
direction: 'vertical',
})
expect(this.a.style.height).toBe('50%')
expect(this.b.style.height).toBe('50%')
})
it('splits in percentages when given sizes', function() {
Split(['#a', '#b'], {
sizes: [25, 75],
})
expect(this.a.style.width).toBe('25%')
expect(this.b.style.width).toBe('75%')
})
it('splits in percentages when given sizes', function() {
Split(['#a', '#b'], {
sizes: [25, 75],
})
expect(this.a.style.width).toBe('25%')
expect(this.b.style.width).toBe('75%')
})
it('accounts for gutter size', function() {
Split(['#a', '#b'], {
gutterSize: 20,
})
expect(this.a.style.width).toBe('50%')
expect(this.b.style.width).toBe('50%')
})
it('accounts for gutter size with more than two elements', function() {
Split(['#a', '#b', '#c'], {
gutterSize: 20,
})
expect(this.a.style.width).toBe('33.33%')
expect(this.b.style.width).toBe('33.33%')
expect(this.c.style.width).toBe('33.33%')
})
it('accounts for gutter size when direction is vertical', function() {
Split(['#a', '#b'], {
direction: 'vertical',
gutterSize: 20,
})
expect(this.a.style.height).toBe('50%')
expect(this.b.style.height).toBe('50%')
})
it('accounts for gutter size with more than two elements when direction is vertical', function() {
Split(['#a', '#b', '#c'], {
direction: 'vertical',
gutterSize: 20,
})
expect(this.a.style.height).toBe('33.33%')
expect(this.b.style.height).toBe('33.33%')
expect(this.c.style.height).toBe('33.33%')
})
it('set size directly when given css values', function() {
Split(['#a', '#b'], {
sizes: ['150px', '640px'],
})
expect(this.a.style.width).toBe('150px')
expect(this.b.style.width).toBe('640px')
})
it('adjusts sizes using setSizes', function() {
var split = Split(['#a', '#b'])
split.setSizes([70, 30])
expect(this.a.style.width).toBe('70%')
expect(this.b.style.width).toBe('30%')
})
it('sets element styles using the elementStyle function', function() {
Split(['#a', '#b'], {
elementStyle: function(dimension, size) {
return {
width: size + '%',
}
},
})
expect(this.a.style.width).toBe('50%')
expect(this.b.style.width).toBe('50%')
})
})

View File

@@ -0,0 +1,133 @@
/**
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
*/
(function() {
/**
* ## Require &amp; Instantiate
*
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
*/
window.jasmine = jasmineRequire.core(jasmineRequire);
/**
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
*/
jasmineRequire.html(jasmine);
/**
* Create the Jasmine environment. This is used to run all specs in a project.
*/
var env = jasmine.getEnv();
/**
* ## The Global Interface
*
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
*/
var jasmineInterface = jasmineRequire.interface(jasmine, env);
/**
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
extend(window, jasmineInterface);
/**
* ## Runner Parameters
*
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
*/
var queryString = new jasmine.QueryString({
getWindowLocation: function() { return window.location; }
});
var filterSpecs = !!queryString.getParam("spec");
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
var throwingExpectationFailures = queryString.getParam("throwFailures");
env.throwOnExpectationFailure(throwingExpectationFailures);
var random = queryString.getParam("random");
env.randomizeTests(random);
var seed = queryString.getParam("seed");
if (seed) {
env.seed(seed);
}
/**
* ## Reporters
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
timer: new jasmine.Timer(),
filterSpecs: filterSpecs
});
/**
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
*/
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
/**
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
*/
var specFilter = new jasmine.HtmlSpecFilter({
filterString: function() { return queryString.getParam("spec"); }
});
env.specFilter = function(spec) {
return specFilter.matches(spec.getFullName());
};
/**
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
*/
window.setTimeout = window.setTimeout;
window.setInterval = window.setInterval;
window.clearTimeout = window.clearTimeout;
window.clearInterval = window.clearInterval;
/**
* ## Execution
*
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
*/
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
htmlReporter.initialize();
env.execute();
};
/**
* Helper function for readability above.
*/
function extend(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
}
}());

View File

@@ -0,0 +1,190 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
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.
*/
function getJasmineRequireObj() {
if (typeof module !== 'undefined' && module.exports) {
return exports;
} else {
window.jasmineRequire = window.jasmineRequire || {};
return window.jasmineRequire;
}
}
getJasmineRequireObj().console = function(jRequire, j$) {
j$.ConsoleReporter = jRequire.ConsoleReporter();
};
getJasmineRequireObj().ConsoleReporter = function() {
var noopTimer = {
start: function(){},
elapsed: function(){ return 0; }
};
function ConsoleReporter(options) {
var print = options.print,
showColors = options.showColors || false,
onComplete = options.onComplete || function() {},
timer = options.timer || noopTimer,
specCount,
failureCount,
failedSpecs = [],
pendingCount,
ansi = {
green: '\x1B[32m',
red: '\x1B[31m',
yellow: '\x1B[33m',
none: '\x1B[0m'
},
failedSuites = [];
print('ConsoleReporter is deprecated and will be removed in a future version.');
this.jasmineStarted = function() {
specCount = 0;
failureCount = 0;
pendingCount = 0;
print('Started');
printNewline();
timer.start();
};
this.jasmineDone = function() {
printNewline();
for (var i = 0; i < failedSpecs.length; i++) {
specFailureDetails(failedSpecs[i]);
}
if(specCount > 0) {
printNewline();
var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' +
failureCount + ' ' + plural('failure', failureCount);
if (pendingCount) {
specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount);
}
print(specCounts);
} else {
print('No specs found');
}
printNewline();
var seconds = timer.elapsed() / 1000;
print('Finished in ' + seconds + ' ' + plural('second', seconds));
printNewline();
for(i = 0; i < failedSuites.length; i++) {
suiteFailureDetails(failedSuites[i]);
}
onComplete(failureCount === 0);
};
this.specDone = function(result) {
specCount++;
if (result.status == 'pending') {
pendingCount++;
print(colored('yellow', '*'));
return;
}
if (result.status == 'passed') {
print(colored('green', '.'));
return;
}
if (result.status == 'failed') {
failureCount++;
failedSpecs.push(result);
print(colored('red', 'F'));
}
};
this.suiteDone = function(result) {
if (result.failedExpectations && result.failedExpectations.length > 0) {
failureCount++;
failedSuites.push(result);
}
};
return this;
function printNewline() {
print('\n');
}
function colored(color, str) {
return showColors ? (ansi[color] + str + ansi.none) : str;
}
function plural(str, count) {
return count == 1 ? str : str + 's';
}
function repeat(thing, times) {
var arr = [];
for (var i = 0; i < times; i++) {
arr.push(thing);
}
return arr;
}
function indent(str, spaces) {
var lines = (str || '').split('\n');
var newArr = [];
for (var i = 0; i < lines.length; i++) {
newArr.push(repeat(' ', spaces).join('') + lines[i]);
}
return newArr.join('\n');
}
function specFailureDetails(result) {
printNewline();
print(result.fullName);
for (var i = 0; i < result.failedExpectations.length; i++) {
var failedExpectation = result.failedExpectations[i];
printNewline();
print(indent(failedExpectation.message, 2));
print(indent(failedExpectation.stack, 2));
}
printNewline();
}
function suiteFailureDetails(result) {
for (var i = 0; i < result.failedExpectations.length; i++) {
printNewline();
print(colored('red', 'An error was thrown in an afterAll'));
printNewline();
print(colored('red', 'AfterAll ' + result.failedExpectations[i].message));
}
printNewline();
}
}
return ConsoleReporter;
};

View File

@@ -0,0 +1,499 @@
/*
Copyright (c) 2008-2017 Pivotal Labs
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.
*/
jasmineRequire.html = function(j$) {
j$.ResultsNode = jasmineRequire.ResultsNode();
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
j$.QueryString = jasmineRequire.QueryString();
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
};
jasmineRequire.HtmlReporter = function(j$) {
var noopTimer = {
start: function() {},
elapsed: function() { return 0; }
};
function HtmlReporter(options) {
var env = options.env || {},
getContainer = options.getContainer,
createElement = options.createElement,
createTextNode = options.createTextNode,
onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
onRandomClick = options.onRandomClick || function() {},
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
filterSpecs = options.filterSpecs,
timer = options.timer || noopTimer,
results = [],
specsExecuted = 0,
failureCount = 0,
pendingSpecCount = 0,
htmlReporterMain,
symbols,
failedSuites = [];
this.initialize = function() {
clearPrior();
htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'},
createDom('div', {className: 'jasmine-banner'},
createDom('a', {className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank'}),
createDom('span', {className: 'jasmine-version'}, j$.version)
),
createDom('ul', {className: 'jasmine-symbol-summary'}),
createDom('div', {className: 'jasmine-alert'}),
createDom('div', {className: 'jasmine-results'},
createDom('div', {className: 'jasmine-failures'})
)
);
getContainer().appendChild(htmlReporterMain);
};
var totalSpecsDefined;
this.jasmineStarted = function(options) {
totalSpecsDefined = options.totalSpecsDefined || 0;
timer.start();
};
var summary = createDom('div', {className: 'jasmine-summary'});
var topResults = new j$.ResultsNode({}, '', null),
currentParent = topResults;
this.suiteStarted = function(result) {
currentParent.addChild(result, 'suite');
currentParent = currentParent.last();
};
this.suiteDone = function(result) {
if (result.status == 'failed') {
failedSuites.push(result);
}
if (currentParent == topResults) {
return;
}
currentParent = currentParent.parent;
};
this.specStarted = function(result) {
currentParent.addChild(result, 'spec');
};
var failures = [];
this.specDone = function(result) {
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
}
if (result.status != 'disabled') {
specsExecuted++;
}
if (!symbols){
symbols = find('.jasmine-symbol-summary');
}
symbols.appendChild(createDom('li', {
className: noExpectations(result) ? 'jasmine-empty' : 'jasmine-' + result.status,
id: 'spec_' + result.id,
title: result.fullName
}
));
if (result.status == 'failed') {
failureCount++;
var failure =
createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
createDom('div', {className: 'jasmine-description'},
createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName)
),
createDom('div', {className: 'jasmine-messages'})
);
var messages = failure.childNodes[1];
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
messages.appendChild(createDom('div', {className: 'jasmine-result-message'}, expectation.message));
messages.appendChild(createDom('div', {className: 'jasmine-stack-trace'}, expectation.stack));
}
failures.push(failure);
}
if (result.status == 'pending') {
pendingSpecCount++;
}
};
this.jasmineDone = function(doneResult) {
var banner = find('.jasmine-banner');
var alert = find('.jasmine-alert');
var order = doneResult && doneResult.order;
alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
banner.appendChild(
createDom('div', { className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom('div', { className: 'jasmine-payload' },
createDom('div', { className: 'jasmine-exceptions' },
createDom('input', {
className: 'jasmine-raise',
id: 'jasmine-raise-exceptions',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-raise-exceptions' }, 'raise exceptions')),
createDom('div', { className: 'jasmine-throw-failures' },
createDom('input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure')),
createDom('div', { className: 'jasmine-random-order' },
createDom('input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order'))
)
));
var raiseCheckbox = find('#jasmine-raise-exceptions');
raiseCheckbox.checked = !env.catchingExceptions();
raiseCheckbox.onclick = onRaiseExceptionsClick;
var throwCheckbox = find('#jasmine-throw-failures');
throwCheckbox.checked = env.throwingExpectationFailures();
throwCheckbox.onclick = onThrowExpectationsClick;
var randomCheckbox = find('#jasmine-random-order');
randomCheckbox.checked = env.randomTests();
randomCheckbox.onclick = onRandomClick;
var optionsMenu = find('.jasmine-run-options'),
optionsTrigger = optionsMenu.querySelector('.jasmine-trigger'),
optionsPayload = optionsMenu.querySelector('.jasmine-payload'),
isOpen = /\bjasmine-open\b/;
optionsTrigger.onclick = function() {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
} else {
optionsPayload.className += ' jasmine-open';
}
};
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedLink = order && order.random ? '?random=true' : '?';
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)
)
);
}
var statusBarMessage = '';
var statusBarClassName = 'jasmine-bar ';
if (totalSpecsDefined > 0) {
statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount);
if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); }
statusBarClassName += (failureCount > 0) ? 'jasmine-failed' : 'jasmine-passed';
} else {
statusBarClassName += 'jasmine-skipped';
statusBarMessage += 'No specs found';
}
var seedBar;
if (order && order.random) {
seedBar = createDom('span', {className: 'jasmine-seed-bar'},
', randomized with seed ',
createDom('a', {title: 'randomized with seed ' + order.seed, href: seedHref(order.seed)}, order.seed)
);
}
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar));
var errorBarClassName = 'jasmine-bar jasmine-errored';
var errorBarMessagePrefix = 'AfterAll ';
for(var i = 0; i < failedSuites.length; i++) {
var failedSuite = failedSuites[i];
for(var j = 0; j < failedSuite.failedExpectations.length; j++) {
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failedSuite.failedExpectations[j].message));
}
}
var globalFailures = (doneResult && doneResult.failedExpectations) || [];
for(i = 0; i < globalFailures.length; i++) {
var failure = globalFailures[i];
alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessagePrefix + failure.message));
}
var results = find('.jasmine-results');
results.appendChild(summary);
summaryList(topResults, summary);
function summaryList(resultsTree, domParent) {
var specListNode;
for (var i = 0; i < resultsTree.children.length; i++) {
var resultNode = resultsTree.children[i];
if (filterSpecs && !hasActiveSpec(resultNode)) {
continue;
}
if (resultNode.type == 'suite') {
var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
createDom('li', {className: 'jasmine-suite-detail'},
createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description)
)
);
summaryList(resultNode, suiteListNode);
domParent.appendChild(suiteListNode);
}
if (resultNode.type == 'spec') {
if (domParent.getAttribute('class') != 'jasmine-specs') {
specListNode = createDom('ul', {className: 'jasmine-specs'});
domParent.appendChild(specListNode);
}
var specDescription = resultNode.result.description;
if(noExpectations(resultNode.result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if(resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '') {
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
}
specListNode.appendChild(
createDom('li', {
className: 'jasmine-' + resultNode.result.status,
id: 'spec-' + resultNode.result.id
},
createDom('a', {href: specHref(resultNode.result)}, specDescription)
)
);
}
}
}
if (failures.length) {
alert.appendChild(
createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-spec-list'},
createDom('span', {}, 'Spec List | '),
createDom('a', {className: 'jasmine-failures-menu', href: '#'}, 'Failures')));
alert.appendChild(
createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-failure-list'},
createDom('a', {className: 'jasmine-spec-list-menu', href: '#'}, 'Spec List'),
createDom('span', {}, ' | Failures ')));
find('.jasmine-failures-menu').onclick = function() {
setMenuModeTo('jasmine-failure-list');
};
find('.jasmine-spec-list-menu').onclick = function() {
setMenuModeTo('jasmine-spec-list');
};
setMenuModeTo('jasmine-failure-list');
var failureNode = find('.jasmine-failures');
for (i = 0; i < failures.length; i++) {
failureNode.appendChild(failures[i]);
}
}
};
return this;
function find(selector) {
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
}
function clearPrior() {
// return the reporter
var oldReporter = find('');
if(oldReporter) {
getContainer().removeChild(oldReporter);
}
}
function createDom(type, attrs, childrenVarArgs) {
var el = createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
for (var attr in attrs) {
if (attr == 'className') {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
function pluralize(singular, count) {
var word = (count == 1 ? singular : singular + 's');
return '' + count + ' ' + word;
}
function specHref(result) {
return addToExistingQueryString('spec', result.fullName);
}
function seedHref(seed) {
return addToExistingQueryString('seed', seed);
}
function defaultQueryString(key, value) {
return '?' + key + '=' + value;
}
function setMenuModeTo(mode) {
htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
}
function noExpectations(result) {
return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
result.status === 'passed';
}
function hasActiveSpec(resultNode) {
if (resultNode.type == 'spec' && resultNode.result.status != 'disabled') {
return true;
}
if (resultNode.type == 'suite') {
for (var i = 0, j = resultNode.children.length; i < j; i++) {
if (hasActiveSpec(resultNode.children[i])) {
return true;
}
}
}
}
}
return HtmlReporter;
};
jasmineRequire.HtmlSpecFilter = function() {
function HtmlSpecFilter(options) {
var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
var filterPattern = new RegExp(filterString);
this.matches = function(specName) {
return filterPattern.test(specName);
};
}
return HtmlSpecFilter;
};
jasmineRequire.ResultsNode = function() {
function ResultsNode(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
this.addChild = function(result, type) {
this.children.push(new ResultsNode(result, type, this));
};
this.last = function() {
return this.children[this.children.length - 1];
};
}
return ResultsNode;
};
jasmineRequire.QueryString = function() {
function QueryString(options) {
this.navigateWithNewParam = function(key, value) {
options.getWindowLocation().search = this.fullStringWithNewParam(key, value);
};
this.fullStringWithNewParam = function(key, value) {
var paramMap = queryStringToParamMap();
paramMap[key] = value;
return toQueryString(paramMap);
};
this.getParam = function(key) {
return queryStringToParamMap()[key];
};
return this;
function toQueryString(paramMap) {
var qStrPairs = [];
for (var prop in paramMap) {
qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]));
}
return '?' + qStrPairs.join('&');
}
function queryStringToParamMap() {
var paramStr = options.getWindowLocation().search.substring(1),
params = [],
paramMap = {};
if (paramStr.length > 0) {
params = paramStr.split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
var value = decodeURIComponent(p[1]);
if (value === 'true' || value === 'false') {
value = JSON.parse(value);
}
paramMap[decodeURIComponent(p[0])] = value;
}
}
return paramMap;
}
}
return QueryString;
};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,196 @@
/* eslint-env jasmine */
/* global Split */
/* eslint-disable no-var, func-names, prefer-arrow-callback, object-shorthand, prefer-template */
function calcParts(expr) {
var re = /calc\(([\d]*\.?[\d]*?)%\s?-\s?([\d]+)px\)/
var m = re.exec(expr)
return {
percentage: parseFloat(m[1]),
pixels: parseInt(m[2], 10),
}
}
describe('Split', function() {
beforeEach(function() {
document.body.style.width = '800px'
document.body.style.height = '600px'
this.a = document.createElement('div')
this.b = document.createElement('div')
this.c = document.createElement('div')
this.a.id = 'a'
this.b.id = 'b'
this.c.id = 'c'
document.body.appendChild(this.a)
document.body.appendChild(this.b)
document.body.appendChild(this.c)
})
afterEach(function() {
document.body.removeChild(this.a)
document.body.removeChild(this.b)
document.body.removeChild(this.c)
})
it('splits in two when given two elements', function() {
Split(['#a', '#b'])
expect(this.a.style.width).toContain('calc(50% - 5px)')
expect(this.b.style.width).toContain('calc(50% - 5px)')
})
it('splits in three when given three elements', function() {
Split(['#a', '#b', '#c'])
expect(calcParts(this.a.style.width).percentage).toBeCloseTo(33.33)
expect(calcParts(this.b.style.width).percentage).toBeCloseTo(33.33)
expect(calcParts(this.c.style.width).percentage).toBeCloseTo(33.33)
expect(calcParts(this.a.style.width).pixels).toBe(5)
expect(calcParts(this.b.style.width).pixels).toBe(10)
expect(calcParts(this.c.style.width).pixels).toBe(5)
})
it('splits vertically when direction is vertical', function() {
Split(['#a', '#b'], {
direction: 'vertical',
})
expect(this.a.style.height).toContain('calc(50% - 5px)')
expect(this.b.style.height).toContain('calc(50% - 5px)')
})
it('splits in percentages when given sizes', function() {
Split(['#a', '#b'], {
sizes: [25, 75],
})
expect(this.a.style.width).toContain('calc(25% - 5px)')
expect(this.b.style.width).toContain('calc(75% - 5px)')
})
it('splits in percentages when given sizes', function() {
Split(['#a', '#b'], {
sizes: [25, 75],
})
expect(this.a.style.width).toContain('calc(25% - 5px)')
expect(this.b.style.width).toContain('calc(75% - 5px)')
})
it('accounts for gutter size', function() {
Split(['#a', '#b'], {
gutterSize: 20,
})
expect(this.a.style.width).toContain('calc(50% - 10px)')
expect(this.b.style.width).toContain('calc(50% - 10px)')
})
it('accounts for gutter size with more than two elements', function() {
Split(['#a', '#b', '#c'], {
gutterSize: 20,
})
expect(calcParts(this.a.style.width).percentage).toBeCloseTo(33.33)
expect(calcParts(this.b.style.width).percentage).toBeCloseTo(33.33)
expect(calcParts(this.c.style.width).percentage).toBeCloseTo(33.33)
expect(calcParts(this.a.style.width).pixels).toBe(10)
expect(calcParts(this.b.style.width).pixels).toBe(20)
expect(calcParts(this.c.style.width).pixels).toBe(10)
})
it('accounts for gutter size when direction is vertical', function() {
Split(['#a', '#b'], {
direction: 'vertical',
gutterSize: 20,
})
expect(this.a.style.height).toContain('calc(50% - 10px)')
expect(this.b.style.height).toContain('calc(50% - 10px)')
})
it('accounts for gutter size with more than two elements when direction is vertical', function() {
Split(['#a', '#b', '#c'], {
direction: 'vertical',
gutterSize: 20,
})
expect(calcParts(this.a.style.height).percentage).toBeCloseTo(33.33)
expect(calcParts(this.b.style.height).percentage).toBeCloseTo(33.33)
expect(calcParts(this.c.style.height).percentage).toBeCloseTo(33.33)
expect(calcParts(this.a.style.height).pixels).toBe(10)
expect(calcParts(this.b.style.height).pixels).toBe(20)
expect(calcParts(this.c.style.height).pixels).toBe(10)
})
it('set size directly when given css values', function() {
Split(['#a', '#b'], {
sizes: ['150px', '640px'],
})
expect(this.a.style.width).toBe('150px')
expect(this.b.style.width).toBe('640px')
})
it('adjusts sizes using setSizes', function() {
var split = Split(['#a', '#b'])
split.setSizes([70, 30])
expect(this.a.style.width).toContain('calc(70% - 5px)')
expect(this.b.style.width).toContain('calc(30% - 5px)')
})
it('collapse splits', function() {
var split = Split(['#a', '#b'])
split.collapse(0)
expect(this.a.getBoundingClientRect().width).toBeCloseTo(100, 0)
expect(this.b.getBoundingClientRect().width).toBeCloseTo(
800 - 100 - 10,
0,
)
split.collapse(1)
expect(this.a.getBoundingClientRect().width).toBeCloseTo(
800 - 100 - 10,
0,
)
expect(this.b.getBoundingClientRect().width).toBeCloseTo(100, 0)
})
it('returns sizes', function() {
var split = Split(['#a', '#b'])
var sizes = split.getSizes()
expect(sizes).toEqual([50, 50])
split.setSizes([70, 30])
sizes = split.getSizes()
expect(sizes).toEqual([70, 30])
})
it('sets element styles using the elementStyle function', function() {
Split(['#a', '#b'], {
elementStyle: function(dimension, size) {
return {
width: size + '%',
}
},
})
expect(this.a.style.width).toBe('50%')
expect(this.b.style.width).toBe('50%')
})
})