Skip to content

Commit

Permalink
added clone(), fixed up some ender bridge derps
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg committed Jan 31, 2013
1 parent 01f5401 commit 211f2cd
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 47 deletions.
16 changes: 13 additions & 3 deletions src/bonzo.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
return node
}


/**
* @param {string} c a class name to test
* @return {boolean}
Expand Down Expand Up @@ -553,6 +552,17 @@
return this.remove()
}

/**
* @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)
* @return {Bonzo}
*/
, clone: function (opt_host) {
var ret = [] // don't change original array
, l, i
for (i = 0, l = this.length; i < l; i++) ret[i] = cloneNode(opt_host || this, this[i])
return bonzo(ret)
}

// class management

/**
Expand Down Expand Up @@ -705,7 +715,7 @@
* @return {Element|Node}
*/
, related: function (method) {
return this.map(
return bonzo(this.map(
function (el) {
el = el[method]
while (el && el.nodeType !== 1) {
Expand All @@ -716,7 +726,7 @@
function (el) {
return el
}
)
))
}


Expand Down
8 changes: 8 additions & 0 deletions src/ender.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@
return $(b(this).previous())
}

, related: function (t) {
return $(b(this).related(t))
}

, appendTo: function (t) {
return b(this.selector).appendTo(t, this)
}
Expand All @@ -90,6 +94,10 @@
return b(this.selector).insertBefore(t, this)
}

, clone: function () {
return $(b(this).clone(this))
}

, siblings: function () {
var i, l, p, r = []
for (i = 0, l = this.length; i < l; i++) {
Expand Down
25 changes: 25 additions & 0 deletions tests/dommanip-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,29 @@ sink('DOM Manipulation', function(test, ok, before, after, assert) {
ok($(document.createElement('div')).detach(), 'can call detach on already detached elements')
} catch (e) { ok(false, 'error detaching detached element: ' + e); console && console.log(e,e.stack) }
})

test('should clone() detached node list', 8, function () {
var orig = $.create('<div><a href="http://foo/">foo</a></div><p id="paragraphtastic"><span>spantastic</span></p>')
, clone = $(orig).clone()

ok(orig.length == 2, 'sanity check, original fixture has 2 parent elements')
ok(orig.length == clone.length, 'clone has 2 parent elements')
ok(orig[0] !== clone[0], 'clone element !== original element')
ok(orig[1] !== clone[1], 'clone element !== original element')
ok(orig[0].childNodes[0] !== clone[0].childNodes[0], 'clone element !== original element (child node)')
ok(orig[1].childNodes[0] !== clone[1].childNodes[0], 'clone element !== original element (child node)')
ok(clone[0].childNodes[0].href == 'http://foo/', 'cloned attributes')
ok(clone[1].id == 'paragraphtastic', 'cloned attributes')
})

test('should clone() attached node list', 2, function () {
var html = Q('#clonesrc')[0].innerHTML.toLowerCase().replace(/\s/g, '')
var src = $(Q('#clonesrc > *'))
src.clone().appendTo('#clonedst')
var newhtml = Q('#clonedst')[0].innerHTML.toLowerCase().replace(/\s/g, '')
ok(html == newhtml, 'cloning attached node duplicates HTML')
src.clone().appendTo('#clonedst') // do it again!
newhtml = Q('#clonedst')[0].innerHTML.toLowerCase().replace(/\s/g, '')
ok(html + html == newhtml, 'cloning attached node duplicates HTML (again!)')
})
})
1 change: 1 addition & 0 deletions tests/dommanip_insertions-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2271,6 +2271,7 @@ sink('DOM Manipulation - insertions', function(test, ok, before, after, assert)
*/
test('nodes with text nodes being appended with $.create', function (complete) {
var tree = $.create('<span>hey</span> there')
console.log(tree)
ok(tree.length == 2, 'created two nodes')
ok(tree[0] && tree[0].nodeType == 1, 'first node is an element')
ok(tree[1] && tree[1].nodeType == 3, 'second node is a text node')
Expand Down
9 changes: 5 additions & 4 deletions tests/emptycollection-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ sink('Empty-collection safety', function (test, ok) {
// FUNCTION NAME ARGUMENT SIGNATURE ARGUMENTS ARRAY EXPECTED RESULT MATCHER
first: { str: '', args: [], expect: isEmptyContainer }
, last: { str: '', args: [], expect: isEmptyContainer }
, parent: { str: '', args: [], expect: isEmptyArray }
, next: { str: '', args: [], expect: isEmptyArray }
, previous: { str: '', args: [], expect: isEmptyArray }
, parent: { str: '', args: [], expect: isEmptyContainer }
, next: { str: '', args: [], expect: isEmptyContainer }
, previous: { str: '', args: [], expect: isEmptyContainer }
, dim: { str: '', args: [], expect: function(r) { return r.height === 0 && r.width === 0 } }
, get: { str: 'index', args: [0], expect: isNull }
, detach: { str: '', args: [], expect: isSameContainer }
Expand Down Expand Up @@ -74,12 +74,13 @@ sink('Empty-collection safety', function (test, ok) {
, prepend: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, appendTo: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, prependTo: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, related: { str: 'method', args: ['parentNode'], expect: isEmptyArray }
, related: { str: 'method', args: ['parentNode'], expect: isEmptyContainer }
, before: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, after: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, insertBefore: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, insertAfter: { str: 'html', args: ['<a/>'], expect: isSameContainer }
, replaceWith: { str: 'html', args: ['<a/>'], expect: isEmptyContainer }
, clone: { str: '', args: [], expect: isEmptyContainer }
, css: [ { str: 'prop', args: ['color'], expect: isNull } // not sure about this one, depending on the browser you might get "" for an empty property on a real element and undefined for an unknown property on a real element
, { str: 'prop, val', args: ['color', 'red'], expect: isSameContainer }
, { str: '{prop: val}', args: [{color: 'red'}], expect: isSameContainer }
Expand Down
115 changes: 75 additions & 40 deletions tests/ender-js.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*!
* Ender: open module JavaScript framework (client-lib)
* copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat)
* http://ender.no.de
* copyright Dustin Diaz & Jacob Thornton 2011-2012 (@ded @fat)
* http://ender.jit.su
* License MIT
*/
!function (context) {
(function (context) {

// a global object for node.js module compatiblity
// ============================================
Expand All @@ -16,17 +16,20 @@
// ============================================

var modules = {}
, old = context.$
, old = context['$']
, oldEnder = context['ender']
, oldRequire = context['require']
, oldProvide = context['provide']

function require (identifier) {
// modules can be required from ender's build system, or found on the window
var module = modules[identifier] || window[identifier]
if (!module) throw new Error("Requested module '" + identifier + "' has not been defined.")
var module = modules['$' + identifier] || window[identifier]
if (!module) throw new Error("Ender Error: Requested module '" + identifier + "' has not been defined.")
return module
}

function provide (name, what) {
return (modules[name] = what)
return (modules['$' + name] = what)
}

context['provide'] = provide
Expand All @@ -37,48 +40,80 @@
return o
}

function boosh(s, r, els) {
/**
* main Ender return object
* @constructor
* @param {Array|Node|string} s a CSS selector or DOM node(s)
* @param {Array.|Node} r a root node(s)
*/
function Ender(s, r) {
var elements
, i

this.selector = s
// string || node || nodelist || window
if (typeof s == 'string' || s.nodeName || (s.length && 'item' in s) || s == window) {
els = ender._select(s, r)
els.selector = s
} else els = isFinite(s.length) ? s : [s]
return aug(els, boosh)
if (typeof s == 'undefined') {
elements = []
this.selector = ''
} else if (typeof s == 'string' || s.nodeName || (s.length && 'item' in s) || s == window) {
elements = ender._select(s, r)
} else {
elements = isFinite(s.length) ? s : [s]
}
this.length = elements.length
for (i = this.length; i--;) this[i] = elements[i]
}

/**
* @param {function(el, i, inst)} fn
* @param {Object} opt_scope
* @returns {Ender}
*/
Ender.prototype['forEach'] = function (fn, opt_scope) {
var i, l
// opt out of native forEach so we can intentionally call our own scope
// defaulting to the current item and be able to return self
for (i = 0, l = this.length; i < l; ++i) i in this && fn.call(opt_scope || this[i], this[i], i, this)
// return self for chaining
return this
}

Ender.prototype.$ = ender // handy reference to self


function ender(s, r) {
return boosh(s, r)
return new Ender(s, r)
}

aug(ender, {
_VERSION: '0.3.6'
, fn: boosh // for easy compat to jQuery plugins
, ender: function (o, chain) {
aug(chain ? boosh : ender, o)
}
, _select: function (s, r) {
return (r || document).querySelectorAll(s)
}
})

aug(boosh, {
forEach: function (fn, scope, i) {
// opt out of native forEach so we can intentionally call our own scope
// defaulting to the current item and be able to return self
for (i = 0, l = this.length; i < l; ++i) i in this && fn.call(scope || this[i], this[i], i, this)
// return self for chaining
return this
},
$: ender // handy reference to self
})

ender.noConflict = function () {
context.$ = old
ender['_VERSION'] = '0.4.3-dev'

ender.fn = Ender.prototype // for easy compat to jQuery plugins

ender.ender = function (o, chain) {
aug(chain ? Ender.prototype : ender, o)
}

ender._select = function (s, r) {
if (typeof s == 'string') return (r || document).querySelectorAll(s)
if (s.nodeName) return [s]
return s
}


// use callback to receive Ender's require & provide and remove them from global
ender.noConflict = function (callback) {
context['$'] = old
if (callback) {
context['provide'] = oldProvide
context['require'] = oldRequire
context['ender'] = oldEnder
if (typeof callback == 'function') callback(require, provide, this)
}
return this
}

if (typeof module !== 'undefined' && module.exports) module.exports = ender
// use subscript notation as extern for Closure compilation
context['ender'] = context['$'] = context['ender'] || ender
context['ender'] = context['$'] = ender

}(this);
}(this));
2 changes: 2 additions & 0 deletions tests/tests.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
<div id="data-temp"></div>
<div id="insertiontasticSource"></div>
<div id="insertiontastic"></div>
<div id="clonesrc"><div><p>TEXT</p><span><b>foo</b></span></div><div>second child</div></div>
<div id="clonedst"></div>
</div>

<!-- special fixtures -->
Expand Down

0 comments on commit 211f2cd

Please sign in to comment.