Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding prepend function on metal-dom #306

Closed
wants to merge 11 commits into from
28 changes: 28 additions & 0 deletions packages/metal-dom/src/domNamed.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,34 @@ export function parent(element, selector) {
return closest(element.parentNode, selector);
}

/**
* Inserts a node before first child of the parent. If child is a HTML string
* it will be converted to document fragment before prepending it to the parent.
* @param {!Element} parent The node to prepend to.
* @param {!(Element|NodeList|string)} child The thing who must be prepended
* @return {!Element} The prepended child
*/
export function prepend(parent, child) {
if (isString(child)) {
child = buildFragment(child);
}

if (!isNodeListLike(child) && !isDefAndNotNull(parent.firstChild)) {
parent.appendChild(child);
}

if (isNodeListLike(child)) {
const childArr = Array.prototype.slice.call(child);
for (let i = 0; i < childArr.length; i++) {
parent.appendChild(childArr[i]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you add a node list to a parent that already has a child this won't work, this test will currently fail as an example.

        it('should prepend a node list to parent element', function() {
            let parent = document.createElement('div');
            let child = document.createElement('div');

            dom.addClasses(child, 'child');
            dom.append(parent, child);

            let childFrag = dom.buildFragment(
                '<div class="myChild">el1</div><div class="myChild2">el2</div><div class="myChild3">el3</div>'
            );

            dom.prepend(parent, childFrag.childNodes);

            assert.strictEqual(4, parent.childNodes.length);
            assert.strictEqual('myChild', parent.childNodes[0].className);
            assert.strictEqual('myChild2', parent.childNodes[1].className);
            assert.strictEqual('myChild3', parent.childNodes[2].className);
            assert.strictEqual('child', parent.childNodes[3].className);
        });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've corrected this using insertBefore instead appendChild

}
} else {
parent.insertBefore(child, parent.firstChild);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When calling this on a parent that has no children, this block will run even though line 537 has already added the child.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Robert-Frampton , what do you think that function return parent? User probably can get info about childNodes easily, instead actually returning child. I've sent a commit that fixes the problem on running though and returns parent.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @diegonvs, we should probably keep it the same as the dom.append method which returns the child.

}

return child;
}

/**
* Registers a custom event.
* @param {string} eventName The name of the custom event.
Expand Down
60 changes: 60 additions & 0 deletions packages/metal-dom/test/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,66 @@ describe('dom', function() {
assert.strictEqual('myChild2', parent.childNodes[1].className);
});

it('should prepend an element into a div without first child', function() {
let parent = document.createElement('div');
let elem = dom.buildFragment('<p>Hello World</p>');

dom.prepend(parent, elem);

assert.strictEqual('<p>Hello World</p>', parent.innerHTML);
});

it('should prepend an element into a div', function() {
let parent = document.createElement('div');
let p = document.createElement('p');
let span = document.createElement('span');

dom.append(parent, p);
dom.prepend(parent, span);

assert.strictEqual(parent.innerHTML, '<span></span><p></p>');
});

it('should prepend a text into a div', function() {
let parent = document.createElement('div');

dom.append(parent, 'Some text');
dom.prepend(parent, 'Headline: ');

assert.strictEqual(parent.innerHTML, 'Headline: Some text');
});

it('should prepend a node list to parent element', function() {
let parent = document.createElement('div');

let childFrag = dom.buildFragment(
'<div class="myChild">el1</div><div class="myChild2">el2</div><div class="myChild3">el3</div>'
);

dom.prepend(parent, childFrag.childNodes);

assert.strictEqual(3, parent.childNodes.length);
assert.strictEqual('myChild', parent.childNodes[0].className);
assert.strictEqual('myChild2', parent.childNodes[1].className);
assert.strictEqual('myChild3', parent.childNodes[2].className);

let parent2 = document.createElement('div');

dom.prepend(
parent2,
dom.buildFragment(
'<div class="myChild"></div><div class="myChild2"></div><div class="myChild3"></div>'
).childNodes
);
dom.prepend(parent2, dom.buildFragment('<div class="container"></div>'));

assert.strictEqual(4, parent2.childNodes.length);
assert.strictEqual('container', parent2.childNodes[0].className);
assert.strictEqual('myChild', parent2.childNodes[1].className);
assert.strictEqual('myChild2', parent2.childNodes[2].className);
assert.strictEqual('myChild3', parent2.childNodes[3].className);
});

it('should replace an element with a requested element', function() {
let element1 = document.createElement('div');
let element2 = document.createElement('div');
Expand Down