Skip to content

Commit

Permalink
feat: ship default preview drawers for <tr> and <li> tags.
Browse files Browse the repository at this point in the history
  • Loading branch information
3cp committed Feb 13, 2018
1 parent ca26b94 commit 38443f0
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 23 deletions.
4 changes: 4 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ interface TargetOptions {
element?: Element;
}

type PreviewDrawer = (Element) => Element?;

export declare class DndService {
readonly isProcessing: boolean;
readonly model: any;
Expand All @@ -61,4 +63,6 @@ export declare class DndService {

addTarget(targetDelegate: TargetDelegate, options?: TargetOptions): void;
removeTarget(target: TargetDelegate | Element): void;

addPreviewDrawer(drawer: PreviewDrawer): void;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"version": "standard-changelog && git add CHANGELOG.md",
"postversion": "git push && git push --tags && npm publish",
"pretest": "npm run lint",
"test": "env BABEL_ENV=test browserify -t babelify test/dnd.spec.js | tape-run"
"test": "env BABEL_ENV=test browserify -t babelify test/dnd.spec.js test/preview-drawers.spec.js | tape-run"
},
"main": "dist/index.js",
"types": "index.d.ts",
Expand Down
43 changes: 21 additions & 22 deletions src/dnd-service.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* global global, self */
// borrowed many code from https://github.com/bevacqua/dragula.git

import _global from './global';
import {EventAggregator} from 'aurelia-event-aggregator';
import {trPreview, liInUlPreview, liInOlPreview, defaultPreview} from './preview-drawers';

// Ideally should be using aurelia-pal, but it doesn't support
// enough DOM features for bcx-aurelia-dnd to work.
Expand All @@ -11,21 +11,6 @@ import {EventAggregator} from 'aurelia-event-aggregator';
// for aurelia component testing in nodejs, feed constructor with a mock DndService.
//

// copied from https://github.com/aurelia/pal/blob/master/src/index.js
const _global = (function() {
// Workers don’t have `window`, only `self`
if (typeof self !== 'undefined') {
return self;
}

if (typeof global !== 'undefined') {
return global;
}

// Not all environments allow eval and Function
// Use only as a last resort:
return new Function('return this')();
})();

const doc = _global.document;
const documentElement = doc && doc.documentElement;
Expand Down Expand Up @@ -311,11 +296,16 @@ export class DndService {

dndSources = []
dndTargets = []
previewDrawers = [];

constructor(ea) {
this.ea = ea;

injectStyles();
this.addPreviewDrawer(defaultPreview);
this.addPreviewDrawer(liInUlPreview);
this.addPreviewDrawer(liInOlPreview);
this.addPreviewDrawer(trPreview);

this._grab = this._grab.bind(this);
this._release = this._release.bind(this);
Expand All @@ -332,6 +322,10 @@ export class DndService {
// dnd end handler for mobile (touch event) on source element
}

addPreviewDrawer(drawer) {
this.previewDrawers.unshift(drawer);
}

addSource(delegate, options) {
this.dndSources.push(new DndSource(delegate, options));
}
Expand Down Expand Up @@ -717,17 +711,22 @@ export class DndService {
const el = this._sourceElement;
if (!el) return;

const rect = el.getBoundingClientRect();
this._preview = el.cloneNode(true);
const computed = _global.getComputedStyle(el);
this._preview.style.width = computed.width;
this._preview.style.height = computed.height;
for (let i = 0; i < this.previewDrawers.length; i++) {
this._preview = this.previewDrawers[i](el);
if (this._preview) break;
}

if (!this._preview) return;
}

classes.add(this._preview, 'bcx-dnd-preview');
doc.body.appendChild(this._preview);
classes.add(doc.body, 'bcx-dnd-unselectable');

if (_global.getComputedStyle(this._preview).backgroundColor === 'rgba(0, 0, 0, 0)') {
this._preview.style.backgroundColor = 'white';
}

if (this._hideCursor) {
classes.add(doc.body, 'bcx-dnd-hide-cursor');
}
Expand Down
18 changes: 18 additions & 0 deletions src/global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* global global, self */
// copied from https://github.com/aurelia/pal/blob/master/src/index.js
const _global = (function() {
// Workers don’t have `window`, only `self`
if (typeof self !== 'undefined') {
return self;
}

if (typeof global !== 'undefined') {
return global;
}

// Not all environments allow eval and Function
// Use only as a last resort:
return new Function('return this')();
})();

export default _global;
82 changes: 82 additions & 0 deletions src/preview-drawers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import _global from './global';

export function trPreview(el) {
if (el.tagName !== 'TR') return;
if (!el.parentNode) return;
if (!el.parentNode.parentNode || el.parentNode.parentNode.tagName !== 'TABLE') return;

const newTr = el.cloneNode(true);

const tdCount /* or th */ = el.childElementCount;

for(let i = 0; i < tdCount - 1; i++) {
// sync width of all td's width but not the last td
const computed = _global.getComputedStyle(el.children[i]);
newTr.children[i].style.width = computed.width;
newTr.children[i].style.height = computed.height;
}

const section = el.parentNode; // thead/tbody/tfoot
let newSection = section.cloneNode();
newSection.appendChild(newTr);

const table = section.parentNode;
let newTable = table.cloneNode(); // table
newTable.appendChild(newSection);

const tableComputed = _global.getComputedStyle(table);
newTable.style.width = tableComputed.width;

return newTable;
}

export function liInUlPreview(el) {
if (el.tagName !== 'LI') return;
if (!el.parentNode || el.parentNode.tagName !== 'UL') return;

const newLi = el.cloneNode(true);
const computed = _global.getComputedStyle(el);
newLi.style.width = computed.width;
newLi.style.height = computed.height;

let newUl = el.parentNode.cloneNode();
newUl.appendChild(newLi);
newUl.style.width = 'auto';
newUl.style.height = 'auto';

return newUl;
}

export function liInOlPreview(el) {
if (el.tagName !== 'LI') return;
if (!el.parentNode || el.parentNode.tagName !== 'OL') return;

const computed = _global.getComputedStyle(el);

const ol = el.parentNode;
const newOl = ol.cloneNode(true);

newOl.style.width = 'auto';
newOl.style.height = 'auto';

const liCount = ol.childElementCount;
for(let i = 0; i < liCount; i++) {
const newLi = newOl.children[i];
if (ol.children[i] === el) {
newLi.style.width = computed.width;
newLi.style.height = computed.height;
} else {
newLi.style.display = 'none'; // hide all other li.
}
}

return newOl;
}

export function defaultPreview(el) {
const preview = el.cloneNode(true);
const computed = _global.getComputedStyle(el);
preview.style.width = computed.width;
preview.style.height = computed.height;
return preview;
}
103 changes: 103 additions & 0 deletions test/preview-drawers.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import test from 'tape';
import $ from 'jquery';
import _global from '../src/global';
import {trPreview, liInUlPreview, liInOlPreview, defaultPreview} from '../src/preview-drawers';

const doc = _global.document;
const documentElement = doc && doc.documentElement;

function buildHtml(domStr) {
$('body').empty();
const dom = $(domStr);
dom.appendTo('body');
}

test('trPreview ignore element not tr tag', t => {
buildHtml('<p>lorem</p>');
t.notOk(trPreview(doc.querySelector('p')));
t.end();
});

test('trPreview ignore malformed table', t => {
buildHtml('<tr><td></td></tr>');
t.notOk(trPreview(doc.querySelector('tr')));
t.end();
});

test('trPreview copies table', t => {
buildHtml(`<table class="t"><tr class="r"><td>1</td><td>two</td><td>3</td></tr></table>`);
const newTable = trPreview(doc.querySelector('tr'));
t.equal(newTable.tagName, 'TABLE');
t.equal(newTable.style.width,
_global.getComputedStyle(doc.querySelector('table')).width);

const tds = doc.querySelectorAll('table tr td');
t.equal($(newTable).find('td').first().css('width'),
_global.getComputedStyle(tds[0]).width);
t.equal($(newTable).find('td').first().css('height'),
_global.getComputedStyle(tds[0]).height);
t.equal($(newTable).find('td:nth-child(2)').css('width'),
_global.getComputedStyle(tds[1]).width);
t.equal($(newTable).find('td:nth-child(2)').css('height'),
_global.getComputedStyle(tds[1]).height);
t.end();
});

test('liInUlPreview ignore element not li tag', t => {
buildHtml('<p>lorem</p>');
t.notOk(liInUlPreview(doc.querySelector('p')));
t.end();
});

test('liInUlPreview ignore li in ol', t => {
buildHtml('<ol><li>1</li></ol>');
t.notOk(liInUlPreview(doc.querySelector('li')));
t.end();
});

test('liInUlPreview copies li in ul', t => {
buildHtml('<ul><li>0</li><li>1</li><li>2</li></ul>');
const li = doc.querySelectorAll('li')[1];
const newLiInUl = liInUlPreview(li);
t.equal(newLiInUl.tagName, 'UL');
t.equal(newLiInUl.style.width, 'auto');
t.equal(newLiInUl.style.height, 'auto');

t.equal(newLiInUl.childElementCount, 1);
const newLi = newLiInUl.children[0];
t.equal(newLi.innerText, '1');
t.equal(newLi.style.width, _global.getComputedStyle(li).width);
t.equal(newLi.style.height, _global.getComputedStyle(li).height);
t.end();
});

test('liInOlPreview ignore element not li tag', t => {
buildHtml('<p>lorem</p>');
t.notOk(liInOlPreview(doc.querySelector('p')));
t.end();
});

test('liInOlPreview ignore li in ul', t => {
buildHtml('<ul><li>1</li></ul>');
t.notOk(liInOlPreview(doc.querySelector('li')));
t.end();
});

test('liInOlPreview copies li in ol', t => {
buildHtml('<ol><li>0</li><li>1</li><li>2</li></ol>');
const li = doc.querySelectorAll('li')[1];
const newLiInOl = liInOlPreview(li);

t.equal(newLiInOl.tagName, 'OL');
t.equal(newLiInOl.style.width, 'auto');
t.equal(newLiInOl.style.height, 'auto');

t.equal(newLiInOl.childElementCount, 3);
t.equal(newLiInOl.children[0].style.display, 'none');
t.equal(newLiInOl.children[2].style.display, 'none');
const newLi = newLiInOl.children[1];
t.equal(newLi.innerText, '1');
t.equal(newLi.style.width, _global.getComputedStyle(li).width);
t.equal(newLi.style.height, _global.getComputedStyle(li).height);
t.end();
});

0 comments on commit 38443f0

Please sign in to comment.