Skip to content

Commit

Permalink
more robust object type checks, taken from jQuery
Browse files Browse the repository at this point in the history
This fixes operating on DOM elements within iframe.

Fixes madrobby#667

Thanks:
* John Resig
* John-David Dalton
* Rafaël Blais Masson
* Robert Katić
* Ariel Flesler
  • Loading branch information
mislav authored and lopper committed Apr 24, 2013
1 parent f9b71b4 commit cc3eea7
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 13 deletions.
50 changes: 37 additions & 13 deletions src/zepto.js
Expand Up @@ -28,7 +28,8 @@ var Zepto = (function() {
classSelectorRE = /^\.([\w-]+)$/,
idSelectorRE = /^#([\w-]*)$/,
tagSelectorRE = /^[\w-]+$/,
toString = {}.toString,
class2type = {},
toString = class2type.toString,
zepto = {},
camelize, uniq,
tempParent = document.createElement('div')
Expand All @@ -46,10 +47,17 @@ var Zepto = (function() {
return match
}

function isFunction(value) { return toString.call(value) == "[object Function]" }
function isObject(value) { return value instanceof Object }
function isPlainObject(value) {
return isObject(value) && value != window && value.__proto__ == Object.prototype
function type(obj) {
return obj == null ? String(obj) :
class2type[toString.call(obj)] || "object"
}

function isFunction(value) { return type(value) == "function" }
function isWindow(obj) { return obj != null && obj == obj.window }
function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
function isObject(obj) { return type(obj) == "object" }
function isPlainObject(obj) {
return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype
}
function isArray(value) { return value instanceof Array }
function likeArray(obj) { return typeof obj.length == 'number' }
Expand Down Expand Up @@ -201,7 +209,7 @@ var Zepto = (function() {
// This method can be overriden in plugins.
zepto.qsa = function(element, selector){
var found
return (element === document && idSelectorRE.test(selector)) ?
return (isDocument(element) && idSelectorRE.test(selector)) ?
( (found = element.getElementById(RegExp.$1)) ? [found] : [] ) :
(element.nodeType !== 1 && element.nodeType !== 9) ? [] :
slice.call(
Expand Down Expand Up @@ -259,11 +267,18 @@ var Zepto = (function() {
}
}

$.type = type
$.isFunction = isFunction
$.isObject = isObject
$.isArray = isArray
$.isPlainObject = isPlainObject

$.isEmptyObject = function(obj) {
var name
for (name in obj) return false
return true
}

$.inArray = function(elem, array, i){
return emptyArray.indexOf.call(array, elem, i)
}
Expand Down Expand Up @@ -310,6 +325,11 @@ var Zepto = (function() {

if (window.JSON) $.parseJSON = JSON.parse

// Populate the class2type map
$.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase()
})

// Define methods that will be available on all
// Zepto collections
$.fn = {
Expand Down Expand Up @@ -417,14 +437,14 @@ var Zepto = (function() {
closest: function(selector, context){
var node = this[0]
while (node && !zepto.matches(node, selector))
node = node !== context && node !== document && node.parentNode
node = node !== context && !isDocument(node) && node.parentNode
return $(node)
},
parents: function(selector){
var ancestors = [], nodes = this
while (nodes.length > 0)
nodes = $.map(nodes, function(node){
if ((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0) {
if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
ancestors.push(node)
return node
}
Expand Down Expand Up @@ -687,12 +707,13 @@ var Zepto = (function() {
// Generate the `width` and `height` functions
;['width', 'height'].forEach(function(dimension){
$.fn[dimension] = function(value){
var offset, Dimension = dimension.replace(/./, function(m){ return m[0].toUpperCase() })
if (value === undefined) return this[0] == window ? window['inner' + Dimension] :
this[0] == document ? document.documentElement['offset' + Dimension] :
var offset, el = this[0],
Dimension = dimension.replace(/./, function(m){ return m[0].toUpperCase() })
if (value === undefined) return isWindow(el) ? el['inner' + Dimension] :
isDocument(el) ? el.documentElement['offset' + Dimension] :
(offset = this.offset()) && offset[dimension]
else return this.each(function(idx){
var el = $(this)
el = $(this)
el.css(dimension, funcArg(this, value, idx, el[dimension]()))
})
}
Expand All @@ -710,7 +731,10 @@ var Zepto = (function() {

$.fn[operator] = function(){
// arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
var nodes = $.map(arguments, function(n){ return isObject(n) ? n : zepto.fragment(n) }),
var argType, nodes = $.map(arguments, function(arg) {
argType = type(arg)
return argType == "object" || argType == "array" ? arg : zepto.fragment(arg)
}),
parent, copyByClone = this.length > 1
if (nodes.length < 1) return this

Expand Down
24 changes: 24 additions & 0 deletions test/zepto.html
Expand Up @@ -226,6 +226,8 @@ <h1>Zepto DOM unit tests</h1>

<svg></svg>

<iframe src="fixtures/iframe_document.html"></iframe>

</div><!-- fixtures -->

<script>
Expand Down Expand Up @@ -562,6 +564,20 @@ <h1>Zepto DOM unit tests</h1>
t.assertEqual(Node.DOCUMENT_FRAGMENT_NODE, documentFragment.get(0).nodeType)
},

testDollarWithElementInIframe: function(t){
var iframe = $('#fixtures iframe').get(0),
iframeWin = iframe.contentWindow,
iframeDoc = iframe.contentDocument,
iframeBody = iframeDoc.body,
iframeEl = $(iframeBody).find('b')

t.assertIdentical(iframeWin, $(iframeWin).get(0))
t.assertIdentical(iframeDoc, $(iframeDoc).get(0))
t.assertIdentical(iframeBody, $(iframeBody).get(0))
t.assertEqual('B', iframeEl.pluck('tagName').join(','))
t.assertEqual('Hello from iframe!', iframeEl.text())
},

testDollarWithFragment: function(t){
var fragment = $("<div>")
t.assertLength(1, fragment)
Expand Down Expand Up @@ -1021,6 +1037,14 @@ <h1>Zepto DOM unit tests</h1>
t.assertEqualCollection($(expected), $('#li2').parents('ul'))
},

testParentsIframe: function(t){
var iframeBody = $('iframe').get(0).contentDocument.body
t.assertEqualCollection(
[iframeBody, iframeBody.parentNode],
$(iframeBody).find('b').first().parents()
)
},

testParent: function(t){
var el = $('#li1')
t.assertEqualCollection($('#parents'), el.parent())
Expand Down

0 comments on commit cc3eea7

Please sign in to comment.