Skip to content

Commit 25df618

Browse files
authored
Merge branch 'master' into master
2 parents ad29402 + 684ec6a commit 25df618

File tree

7 files changed

+301
-156
lines changed

7 files changed

+301
-156
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ TODO UPDATE CHANGELOG
4141
* Bounds checking for dragging and resizing
4242
* Widgets may be added or removed without rebuilding grid
4343
* Layout can be serialized and restored
44+
* Automatic RTL support
4445

4546

4647
## Installation
@@ -138,4 +139,4 @@ If you have a feature request, please add it as an issue or make a pull request.
138139
- [x] Draggable grid items
139140
- [x] Resizable grid items
140141
- [ ] Static elements
141-
- [x] Min/max w/h per item
142+
- [x] Min/max w/h per item

dist/vue-grid-layout.js

Lines changed: 133 additions & 121 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vue-grid-layout.min.js

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vue-grid-layout.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
<button @click="decreaseWidth">Decrease Width</button>
1717
<button @click="increaseWidth">Increase Width</button>
1818
<button @click="addItem">Add an item</button>
19+
<!-- Add to show rtl support -->
20+
<button @click="changeDirection">Change Direction</button>
1921
<br/>
2022
<grid-layout
2123
:layout="layout"
@@ -48,6 +50,7 @@
4850
import GridLayout from './GridLayout.vue';
4951
//import ResponsiveGridLayout from './ResponsiveGridLayout.vue';
5052
import TestElement from './TestElement.vue';
53+
var eventBus = require('./eventBus');
5154
5255
var testLayout = [
5356
{"x":0,"y":0,"w":2,"h":2,"i":"0"},
@@ -119,7 +122,7 @@
119122
resize: function(i, newH, newW){
120123
console.log(i, newH, newW)
121124
},
122-
/**
125+
/**
123126
* Add change direction button
124127
*/
125128
changeDirection() {

src/GridItem.vue

Lines changed: 106 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
:style="style"
66
>
77
<slot></slot>
8-
<span v-if="isResizable" ref="handle" class="vue-resizable-handle"></span>
8+
<span v-if="isResizable" ref="handle" :class="resizableHandleClass"></span>
99
</div>
1010
</template>
1111
<style>
1212
.vue-grid-item {
1313
transition: all 200ms ease;
14-
transition-property: left, top;
14+
transition-property: left, top, right;
15+
/* add right for rtl */
1516
}
1617
.vue-grid-item.cssTransforms {
1718
transition-property: transform;
@@ -52,9 +53,21 @@
5253
box-sizing: border-box;
5354
cursor: se-resize;
5455
}
56+
57+
.vue-grid-item > .vue-rtl-resizable-handle {
58+
bottom: 0;
59+
left: 0;
60+
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAuMDAwMDAwMDAwMDAwMDAyIiBoZWlnaHQ9IjEwLjAwMDAwMDAwMDAwMDAwMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDwhLS0gQ3JlYXRlZCB3aXRoIE1ldGhvZCBEcmF3IC0gaHR0cDovL2dpdGh1Yi5jb20vZHVvcGl4ZWwvTWV0aG9kLURyYXcvIC0tPgogPGc+CiAgPHRpdGxlPmJhY2tncm91bmQ8L3RpdGxlPgogIDxyZWN0IGZpbGw9Im5vbmUiIGlkPSJjYW52YXNfYmFja2dyb3VuZCIgaGVpZ2h0PSIxMiIgd2lkdGg9IjEyIiB5PSItMSIgeD0iLTEiLz4KICA8ZyBkaXNwbGF5PSJub25lIiBvdmVyZmxvdz0idmlzaWJsZSIgeT0iMCIgeD0iMCIgaGVpZ2h0PSIxMDAlIiB3aWR0aD0iMTAwJSIgaWQ9ImNhbnZhc0dyaWQiPgogICA8cmVjdCBmaWxsPSJ1cmwoI2dyaWRwYXR0ZXJuKSIgc3Ryb2tlLXdpZHRoPSIwIiB5PSIwIiB4PSIwIiBoZWlnaHQ9IjEwMCUiIHdpZHRoPSIxMDAlIi8+CiAgPC9nPgogPC9nPgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxsaW5lIGNhbnZhcz0iI2ZmZmZmZiIgY2FudmFzLW9wYWNpdHk9IjEiIHN0cm9rZS1saW5lY2FwPSJ1bmRlZmluZWQiIHN0cm9rZS1saW5lam9pbj0idW5kZWZpbmVkIiBpZD0ic3ZnXzEiIHkyPSItNzAuMTc4NDA3IiB4Mj0iMTI0LjQ2NDE3NSIgeTE9Ii0zOC4zOTI3MzciIHgxPSIxNDQuODIxMjg5IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlPSIjMDAwIiBmaWxsPSJub25lIi8+CiAgPGxpbmUgc3Ryb2tlPSIjNjY2NjY2IiBzdHJva2UtbGluZWNhcD0idW5kZWZpbmVkIiBzdHJva2UtbGluZWpvaW49InVuZGVmaW5lZCIgaWQ9InN2Z181IiB5Mj0iOS4xMDY5NTciIHgyPSIwLjk0NzI0NyIgeTE9Ii0wLjAxODEyOCIgeDE9IjAuOTQ3MjQ3IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiLz4KICA8bGluZSBzdHJva2UtbGluZWNhcD0idW5kZWZpbmVkIiBzdHJva2UtbGluZWpvaW49InVuZGVmaW5lZCIgaWQ9InN2Z183IiB5Mj0iOSIgeDI9IjEwLjA3MzUyOSIgeTE9IjkiIHgxPSItMC42NTU2NCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM2NjY2NjYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+);
61+
background-position: bottom left;
62+
padding-left: 3px;
63+
background-repeat: no-repeat;
64+
background-origin: content-box;
65+
cursor: sw-resize;
66+
right: auto;
67+
}
5568
</style>
5669
<script>
57-
import {setTopLeft, setTransform, createMarkup, getLayoutItem} from './utils';
70+
import {setTopLeft, setTopRight, setTransformRtl, setTransform, createMarkup, getLayoutItem} from './utils';
5871
import {getControlPosition, offsetXYFromParentOf, createCoreData} from './draggableUtils';
5972
var eventBus = require('./eventBus');
6073
@@ -140,7 +153,7 @@
140153
},
141154
i: {
142155
required: true
143-
},
156+
}
144157
},
145158
data: function() {
146159
return {
@@ -161,7 +174,8 @@
161174
lastY: NaN,
162175
lastW: NaN,
163176
lastH: NaN,
164-
style: {}
177+
style: {},
178+
rtl: false
165179
}
166180
},
167181
created () {
@@ -172,6 +186,17 @@
172186
eventBus.$on('compact', function(layout) {
173187
self.compact(layout);
174188
});
189+
var direction = (document.dir !=undefined) ?
190+
document.dir :
191+
document.getElementsByTagName("html")[0].getAttribute("dir");
192+
this.rtl = (direction == "rtl");
193+
eventBus.$on('directionchange', (direction) => {
194+
var direction = (document.dir != undefined) ?
195+
document.dir :
196+
document.getElementsByTagName("html")[0].getAttribute("dir");
197+
this.rtl = (direction == "rtl");
198+
this.compact();
199+
});
175200
},
176201
mounted: function() {
177202
this.cols = this.$parent.colNum;
@@ -231,6 +256,13 @@
231256
}
232257
},
233258
computed: {
259+
resizableHandleClass() {
260+
if (this.rtl) {
261+
return 'vue-resizable-handle vue-rtl-resizable-handle';
262+
} else {
263+
return 'vue-resizable-handle';
264+
}
265+
}
234266
},
235267
methods: {
236268
createStyle: function() {
@@ -243,7 +275,12 @@
243275
244276
if (this.isDragging) {
245277
pos.top = this.dragging.top;
246-
pos.left = this.dragging.left;
278+
// Add rtl support
279+
if (this.rtl) {
280+
pos.right = this.dragging.left;
281+
} else {
282+
pos.left = this.dragging.left;
283+
}
247284
}
248285
if (this.isResizing) {
249286
pos.width = this.resizing.width;
@@ -253,11 +290,22 @@
253290
let style;
254291
// CSS Transforms support (default)
255292
if (this.useCssTransforms) {
256-
style = setTransform(pos.top, pos.left, pos.width, pos.height);
293+
// Add rtl support
294+
if (this.rtl) {
295+
style = setTransformRtl(pos.top, pos.right, pos.width, pos.height);
296+
} else {
297+
style = setTransform(pos.top, pos.left, pos.width, pos.height);
298+
}
299+
257300
}
258301
// top,left (slow)
259302
else {
260-
style = setTopLeft(pos.top, pos.left, pos.width, pos.height);
303+
// Add rtl support
304+
if (this.rtl) {
305+
style = setTopRight(pos.top, pos.right, pos.width, pos.height);
306+
} else {
307+
style = setTopLeft(pos.top, pos.left, pos.width, pos.height);
308+
}
261309
}
262310
this.style = style;
263311
@@ -280,7 +328,11 @@
280328
case "resizemove":
281329
// console.log("### resize => " + event.type + ", lastW=" + this.lastW + ", lastH=" + this.lastH);
282330
const coreEvent = createCoreData(this.lastW, this.lastH, x, y);
283-
newSize.width = this.resizing.width + coreEvent.deltaX;
331+
if (this.rtl) {
332+
newSize.width = this.resizing.width - coreEvent.deltaX;
333+
} else {
334+
newSize.width = this.resizing.width + coreEvent.deltaX;
335+
}
284336
newSize.height = this.resizing.height + coreEvent.deltaY;
285337
286338
///console.log("### resize => " + event.type + ", deltaX=" + coreEvent.deltaX + ", deltaY=" + coreEvent.deltaY);
@@ -335,13 +387,16 @@
335387
const {x, y} = position;
336388
337389
var shouldUpdate = false;
338-
339390
const newPosition = {top: 0, left: 0};
340391
switch (event.type) {
341392
case "dragstart":
342393
var parentRect = event.target.offsetParent.getBoundingClientRect();
343394
var clientRect = event.target.getBoundingClientRect();
344-
newPosition.left = clientRect.left - parentRect.left;
395+
if (this.rtl) {
396+
newPosition.left = (clientRect.right - parentRect.right) * -1;
397+
} else {
398+
newPosition.left = clientRect.left - parentRect.left;
399+
}
345400
newPosition.top = clientRect.top - parentRect.top;
346401
this.dragging = newPosition;
347402
this.isDragging = true;
@@ -350,7 +405,12 @@
350405
if (!this.isDragging) return;
351406
parentRect = event.target.offsetParent.getBoundingClientRect();
352407
clientRect = event.target.getBoundingClientRect();
353-
newPosition.left = clientRect.left - parentRect.left;
408+
// Add rtl support
409+
if (this.rtl) {
410+
newPosition.left = (clientRect.right - parentRect.right) * -1;
411+
} else {
412+
newPosition.left = clientRect.left - parentRect.left;
413+
}
354414
newPosition.top = clientRect.top - parentRect.top;
355415
// console.log("### drag end => " + JSON.stringify(newPosition));
356416
// console.log("### DROP: " + JSON.stringify(newPosition));
@@ -360,7 +420,12 @@
360420
break;
361421
case "dragmove":
362422
const coreEvent = createCoreData(this.lastX, this.lastY, x, y);
363-
newPosition.left = this.dragging.left + coreEvent.deltaX;
423+
// Add rtl support
424+
if (this.rtl) {
425+
newPosition.left = this.dragging.left - coreEvent.deltaX;
426+
} else {
427+
newPosition.left = this.dragging.left + coreEvent.deltaX;
428+
}
364429
newPosition.top = this.dragging.top + coreEvent.deltaY;
365430
// console.log("### drag => " + event.type + ", x=" + x + ", y=" + y);
366431
// console.log("### drag => " + event.type + ", deltaX=" + coreEvent.deltaX + ", deltaY=" + coreEvent.deltaY);
@@ -370,7 +435,11 @@
370435
}
371436
372437
// Get new XY
373-
var pos = this.calcXY(newPosition.top, newPosition.left);
438+
if (this.rtl) {
439+
var pos = this.calcXY(newPosition.top, newPosition.left);
440+
} else {
441+
var pos = this.calcXY(newPosition.top, newPosition.left);
442+
}
374443
375444
this.lastX = x;
376445
this.lastY = y;
@@ -380,16 +449,29 @@
380449
},
381450
calcPosition: function(x, y, w, h) {
382451
const colWidth = this.calcColWidth();
452+
// add rtl support
453+
if (this.rtl) {
454+
var out = {
455+
right: Math.round(colWidth * x + (x + 1) * this.margin[0]),
456+
top: Math.round(this.rowHeight * y + (y + 1) * this.margin[1]),
457+
// 0 * Infinity === NaN, which causes problems with resize constriants;
458+
// Fix this if it occurs.
459+
// Note we do it here rather than later because Math.round(Infinity) causes deopt
460+
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * this.margin[0]),
461+
height: h === Infinity ? h : Math.round(this.rowHeight * h + Math.max(0, h - 1) * this.margin[1])
462+
};
463+
} else {
464+
var out = {
465+
left: Math.round(colWidth * x + (x + 1) * this.margin[0]),
466+
top: Math.round(this.rowHeight * y + (y + 1) * this.margin[1]),
467+
// 0 * Infinity === NaN, which causes problems with resize constriants;
468+
// Fix this if it occurs.
469+
// Note we do it here rather than later because Math.round(Infinity) causes deopt
470+
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * this.margin[0]),
471+
height: h === Infinity ? h : Math.round(this.rowHeight * h + Math.max(0, h - 1) * this.margin[1])
472+
};
473+
}
383474
384-
const out = {
385-
left: Math.round(colWidth * x + (x + 1) * this.margin[0]),
386-
top: Math.round(this.rowHeight * y + (y + 1) * this.margin[1]),
387-
// 0 * Infinity === NaN, which causes problems with resize constriants;
388-
// Fix this if it occurs.
389-
// Note we do it here rather than later because Math.round(Infinity) causes deopt
390-
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * this.margin[0]),
391-
height: h === Infinity ? h : Math.round(this.rowHeight * h + Math.max(0, h - 1) * this.margin[1])
392-
};
393475
394476
return out;
395477
},
@@ -399,6 +481,7 @@
399481
* @param {Number} left Left position (relative to parent) in pixels.
400482
* @return {Object} x and y in grid units.
401483
*/
484+
// TODO check if this function needs change in order to support rtl.
402485
calcXY(top, left) {
403486
const colWidth = this.calcColWidth();
404487

src/utils.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export type Size = {width: number, height: number};
1717
export type ResizeEvent = {e: Event, node: HTMLElement, size: Size};
1818

1919
const isProduction = process.env.NODE_ENV === 'production';
20-
2120
/**
2221
* Return the bottom coordinate of the layout.
2322
*
@@ -27,7 +26,7 @@ const isProduction = process.env.NODE_ENV === 'production';
2726
export function bottom(layout: Layout): number {
2827
let max = 0, bottomY;
2928
for (let i = 0, len = layout.length; i < len; i++) {
30-
bottomY = layout[i].y + layout[i].h;
29+
bottomY = layout[i]. y + layout[i].h;
3130
if (bottomY > max) max = bottomY;
3231
}
3332
return max;
@@ -307,6 +306,29 @@ export function setTransform(top, left, width, height): Object {
307306
position: 'absolute'
308307
};
309308
}
309+
/**
310+
* Just like the setTransform method, but instead it will return a negative value of right.
311+
*
312+
* @param top
313+
* @param right
314+
* @param width
315+
* @param height
316+
* @returns {{transform: string, WebkitTransform: string, MozTransform: string, msTransform: string, OTransform: string, width: string, height: string, position: string}}
317+
*/
318+
export function setTransformRtl(top, right, width, height): Object {
319+
// Replace unitless items with px
320+
const translate = "translate(" + right * -1 + "px," + top + "px)";
321+
return {
322+
transform: translate,
323+
WebkitTransform: translate,
324+
MozTransform: translate,
325+
msTransform: translate,
326+
OTransform: translate,
327+
width: width + "px",
328+
height: height + "px",
329+
position: 'absolute'
330+
};
331+
}
310332

311333
export function setTopLeft(top, left, width, height): Object {
312334
return {
@@ -317,6 +339,25 @@ export function setTopLeft(top, left, width, height): Object {
317339
position: 'absolute'
318340
};
319341
}
342+
/**
343+
* Just like the setTopLeft method, but instead, it will return a right property instead of left.
344+
*
345+
* @param top
346+
* @param right
347+
* @param width
348+
* @param height
349+
* @returns {{top: string, right: string, width: string, height: string, position: string}}
350+
*/
351+
export function setTopRight(top, right, width, height): Object {
352+
return {
353+
top: top + "px",
354+
right: right+ "px",
355+
width: width + "px",
356+
height: height + "px",
357+
position: 'absolute'
358+
};
359+
}
360+
320361

321362
/**
322363
* Get layout items sorted from top left to right and down.
@@ -527,4 +568,4 @@ export function findAndRemove(array, property, value) {
527568
array.splice(index, 1);
528569
}
529570
});
530-
}
571+
}

0 commit comments

Comments
 (0)