Skip to content

Commit

Permalink
margin support CSS '5px 10px 0 20px' format
Browse files Browse the repository at this point in the history
* can now specify multiple margin values like CSS for all sides
  • Loading branch information
adumesny committed Nov 5, 2020
1 parent 3ad2b31 commit b1eb1da
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 29 deletions.
1 change: 1 addition & 0 deletions doc/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Change log
- add `data-gs-static-grid` attribute
- fix getting DOM element by id with number works (api that uses `GridStackElement` handle more string formats)
- fix setting `marginTop` (or any 4 sides) to cause resize to break. Thanks [@deadivan](https://github.com/deadivan) for suggested fix.
- add `margin` support multi CSS format `'5px 10px 0 20px'` or `'5em 10em'`

## 2.1.0 (2020-10-28)

Expand Down
10 changes: 6 additions & 4 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ Return list of GridItem HTML dom elements (excluding temporary placeholder)

### getMargin()

returns current margin value.
returns current margin value (undefined if all 4 sides don't match).

### isAreaEmpty(x, y, width, height)

Expand Down Expand Up @@ -423,9 +423,11 @@ grid.makeWidget('#gsi-1');

### margin(value: numberOrString)

set the top/right/bottom/left margin between grid item and content. Parameters:
- `value` - new margin value. see `cellHeight` for possible value formats.
Note: you can instead use `marginTop | marginBottom | marginLeft | marginRight` so set the sides separately.
gap between grid item and content (default?: 10). This will set all 4 sides and support the CSS formats below
- an `integer` (px)
- a string with possible units (ex: `'5'`, `'2em'`, `'20px'`, `'2rem'`)
- string with space separated values (ex: `'5px 10px 0 20px'` for all 4 sides, or `'5em 10em'` for top/bottom and left/right pairs like CSS).
- Note: all sides must have same units (last one wins, default px)

### maxHeight(el, val)

Expand Down
42 changes: 41 additions & 1 deletion spec/gridstack-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,7 @@ describe('gridstack', function() {
let grid: any = GridStack.init(options);
expect(grid.getMargin()).toBe(5);
spyOn(grid, '_updateStyles');
grid.margin('5px', false);
grid.margin('5px');
expect(grid._updateStyles).not.toHaveBeenCalled();
expect(grid.getMargin()).toBe(5);
});
Expand Down Expand Up @@ -1237,6 +1237,46 @@ describe('gridstack', function() {
expect(grid.opts.marginLeft).toBe(5);
expect(grid.opts.marginRight).toBe(5);
});
it('init 2 values', function() {
let options = {
cellHeight: 80,
margin: '5px 10'
};
let grid: any = GridStack.init(options);
expect(grid.getMargin()).toBe(undefined);
expect(grid.opts.marginTop).toBe(5);
expect(grid.opts.marginBottom).toBe(5);
expect(grid.opts.marginLeft).toBe(10);
expect(grid.opts.marginRight).toBe(10);
});
it('init 4 values', function() {
let options = {
cellHeight: 80,
margin: '1 2 0em 3'
};
let grid: any = GridStack.init(options);
expect(grid.getMargin()).toBe(undefined);
expect(grid.opts.marginTop).toBe(1);
expect(grid.opts.marginRight).toBe(2);
expect(grid.opts.marginBottom).toBe(0);
expect(grid.opts.marginLeft).toBe(3);
});
it('set 2 values, should update style', function() {
let options = {
cellHeight: 80,
margin: 5
};
let grid = GridStack.init(options);
expect(grid.getMargin()).toBe(5);
spyOn(grid as any, '_updateStyles');
grid.margin('1px 0');
expect((grid as any)._updateStyles).toHaveBeenCalled();
expect(grid.getMargin()).toBe(undefined);
expect(grid.opts.marginTop).toBe(1);
expect(grid.opts.marginBottom).toBe(1);
expect(grid.opts.marginLeft).toBe(0);
expect(grid.opts.marginRight).toBe(0);
});
});

describe('grid.opts.rtl', function() {
Expand Down
55 changes: 37 additions & 18 deletions src/gridstack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { GridStackEngine } from './gridstack-engine';
import { obsoleteOpts, obsoleteOptsDel, obsoleteAttr, obsolete, Utils } from './utils';
import { obsoleteOpts, obsoleteOptsDel, obsoleteAttr, obsolete, Utils, HeightData } from './utils';
import { GridItemHTMLElement, GridStackWidget, GridStackNode, GridStackOptions, numberOrString, ColumnOptions } from './types';
import { GridStackDD } from './gridstack-dd';

Expand Down Expand Up @@ -1021,27 +1021,27 @@ export class GridStack {
}

/**
* Updates the margins which will set all 4 sides at once - see `GridStackOptions.margin` for format options.
* @param value new vertical margin value
* Note: you can instead use `marginTop | marginBottom | marginLeft | marginRight` GridStackOptions to set the sides separately.
* Updates the margins which will set all 4 sides at once - see `GridStackOptions.margin` for format options (CSS string format of 1,2,4 values or single number).
* @param value margin value
*/
public margin(value: numberOrString): GridStack {
let data = Utils.parseHeight(value);
if (this.opts.marginUnit === data.unit && this.opts.margin === data.height) {
return;
}
this.opts.marginUnit = data.unit;
this.opts.marginTop =
this.opts.marginBottom =
this.opts.marginLeft =
this.opts.marginRight =
this.opts.margin = data.height;
let isMultiValue = (typeof value === 'string' && value.split(' ').length > 1);
// check if we can skip re-creating our CSS file... won't check if multi values (too much hassle)
if (!isMultiValue) {
let data = Utils.parseHeight(value);
if (this.opts.marginUnit === data.unit && this.opts.margin === data.height) return;
}
// re-use existing margin handling
this.opts.margin = value;
this.opts.marginTop = this.opts.marginBottom = this.opts.marginLeft = this.opts.marginRight = undefined;
this.initMargin();

this._updateStyles(true); // true = force re-create

return this;
}

/** returns current margin value (undefined if all 4 sides don't match) */
/** returns current margin number value (undefined if 4 sides don't match) */
public getMargin(): number { return this.opts.margin as number; }

/**
Expand Down Expand Up @@ -1818,9 +1818,28 @@ export class GridStack {

/** @internal initialize margin top/bottom/left/right and units */
private initMargin(): GridStack {
let data = Utils.parseHeight(this.opts.margin);
this.opts.marginUnit = data.unit;
let margin = this.opts.margin = data.height;

let data: HeightData;
let margin = 0;

// support passing multiple values like CSS (ex: '5px 10px 0 20px')
let margins: string[] = [];
if (typeof this.opts.margin === 'string') {
margins = this.opts.margin.split(' ')
}
if (margins.length === 2) { // top/bot, left/right like CSS
this.opts.marginTop = this.opts.marginBottom = margins[0];
this.opts.marginLeft = this.opts.marginRight = margins[1];
} else if (margins.length === 4) { // Clockwise like CSS
this.opts.marginTop = margins[0];
this.opts.marginRight = margins[1];
this.opts.marginBottom = margins[2];
this.opts.marginLeft = margins[3];
} else {
data = Utils.parseHeight(this.opts.margin);
this.opts.marginUnit = data.unit;
margin = this.opts.margin = data.height;
}

// see if top/bottom/left/right need to be set as well
if (this.opts.marginTop === undefined) {
Expand Down
8 changes: 5 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,15 @@ export interface GridStackOptions {
itemClass?: string;

/**
* gap size between grid item and content (default?: 10). see also marginTop, marginRight,... Can be:
* gap between grid item and content (default?: 10). This will set all 4 sides and support the CSS formats below
* an integer (px)
* a string (ex: '2em', '20px', '2rem')
* a string with possible units (ex: '2em', '20px', '2rem')
* string with space separated values (ex: '5px 10px 0 20px' for all 4 sides, or '5em 10em' for top/bottom and left/right pairs like CSS).
* Note: all sides must have same units (last one wins, default px)
*/
margin?: numberOrString;

/** optional way to specify each individual margin side - default to margin */
/** OLD way to optionally set each side - use margin: '5px 10px 0 20px' instead. Used internally to store each side. */
marginTop?: numberOrString;
marginRight?: numberOrString;
marginBottom?: numberOrString;
Expand Down
6 changes: 3 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,18 +140,18 @@ export class Utils {

static parseHeight(val: numberOrString): HeightData {
let height: number;
let heightUnit = 'px';
let unit = 'px';
if (typeof val === 'string') {
let match = val.match(/^(-[0-9]+\.[0-9]+|[0-9]*\.[0-9]+|-[0-9]+|[0-9]+)(px|em|rem|vh|vw|%)?$/);
if (!match) {
throw new Error('Invalid height');
}
heightUnit = match[2] || 'px';
unit = match[2] || 'px';
height = parseFloat(match[1]);
} else {
height = val;
}
return { height, unit: heightUnit }
return { height, unit };
}

/** copies unset fields in target to use the given default sources values */
Expand Down

0 comments on commit b1eb1da

Please sign in to comment.