+ if (how != DELETE)\r
+ frag = doc.createDocumentFragment();\r
+\r
+ n = _traverseLeftBoundary(startAncestor, how);\r
+ if (frag)\r
+ frag.appendChild(n);\r
+\r
+ commonParent = startAncestor.parentNode;\r
+ startOffset = nodeIndex(startAncestor);\r
+ endOffset = nodeIndex(endAncestor);\r
+ ++startOffset;\r
+\r
+ cnt = endOffset - startOffset;\r
+ sibling = startAncestor.nextSibling;\r
+\r
+ while (cnt > 0) {\r
+ nextSibling = sibling.nextSibling;\r
+ n = _traverseFullySelected(sibling, how);\r
+\r
+ if (frag)\r
+ frag.appendChild(n);\r
+\r
+ sibling = nextSibling;\r
+ --cnt;\r
+ }\r
+\r
+ n = _traverseRightBoundary(endAncestor, how);\r
+\r
+ if (frag)\r
+ frag.appendChild(n);\r
+\r
+ if (how != CLONE) {\r
+ t.setStartAfter(startAncestor);\r
+ t.collapse(TRUE);\r
+ }\r
+\r
+ return frag;\r
+ };\r
+\r
+ function _traverseRightBoundary(root, how) {\r
+ var next = _getSelectedNode(t[END_CONTAINER], t[END_OFFSET] - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != t[END_CONTAINER];\r
+\r
+ if (next == root)\r
+ return _traverseNode(next, isFullySelected, FALSE, how);\r
+\r
+ parent = next.parentNode;\r
+ clonedParent = _traverseNode(parent, FALSE, FALSE, how);\r
+\r
+ while (parent) {\r
+ while (next) {\r
+ prevSibling = next.previousSibling;\r
+ clonedChild = _traverseNode(next, isFullySelected, FALSE, how);\r
+\r
+ if (how != DELETE)\r
+ clonedParent.insertBefore(clonedChild, clonedParent.firstChild);\r
+\r
+ isFullySelected = TRUE;\r
+ next = prevSibling;\r
+ }\r
+\r
+ if (parent == root)\r
+ return clonedParent;\r
+\r
+ next = parent.previousSibling;\r
+ parent = parent.parentNode;\r
+\r
+ clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how);\r
+\r
+ if (how != DELETE)\r
+ clonedGrandParent.appendChild(clonedParent);\r
+\r
+ clonedParent = clonedGrandParent;\r
+ }\r
+ };\r
+\r
+ function _traverseLeftBoundary(root, how) {\r
+ var next = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]), isFullySelected = next != t[START_CONTAINER], parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;\r
+\r
+ if (next == root)\r
+ return _traverseNode(next, isFullySelected, TRUE, how);\r
+\r
+ parent = next.parentNode;\r
+ clonedParent = _traverseNode(parent, FALSE, TRUE, how);\r
+\r
+ while (parent) {\r
+ while (next) {\r
+ nextSibling = next.nextSibling;\r
+ clonedChild = _traverseNode(next, isFullySelected, TRUE, how);\r
+\r
+ if (how != DELETE)\r
+ clonedParent.appendChild(clonedChild);\r
+\r
+ isFullySelected = TRUE;\r
+ next = nextSibling;\r
+ }\r
+\r
+ if (parent == root)\r
+ return clonedParent;\r
+\r
+ next = parent.nextSibling;\r
+ parent = parent.parentNode;\r
+\r
+ clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how);\r
+\r
+ if (how != DELETE)\r
+ clonedGrandParent.appendChild(clonedParent);\r
+\r
+ clonedParent = clonedGrandParent;\r
+ }\r
+ };\r
+\r
+ function _traverseNode(n, isFullySelected, isLeft, how) {\r
+ var txtValue, newNodeValue, oldNodeValue, offset, newNode;\r
+\r
+ if (isFullySelected)\r
+ return _traverseFullySelected(n, how);\r
+\r
+ if (n.nodeType == 3 /* TEXT_NODE */) {\r
+ txtValue = n.nodeValue;\r
+\r
+ if (isLeft) {\r
+ offset = t[START_OFFSET];\r
+ newNodeValue = txtValue.substring(offset);\r
+ oldNodeValue = txtValue.substring(0, offset);\r
+ } else {\r
+ offset = t[END_OFFSET];\r
+ newNodeValue = txtValue.substring(0, offset);\r
+ oldNodeValue = txtValue.substring(offset);\r
+ }\r
+\r
+ if (how != CLONE)\r
+ n.nodeValue = oldNodeValue;\r
+\r
+ if (how == DELETE)\r
+ return;\r
+\r
+ newNode = n.cloneNode(FALSE);\r
+ newNode.nodeValue = newNodeValue;\r
+\r
+ return newNode;\r
+ }\r
+\r
+ if (how == DELETE)\r
+ return;\r
+\r
+ return n.cloneNode(FALSE);\r
+ };\r
+\r
+ function _traverseFullySelected(n, how) {\r
+ if (how != DELETE)\r
+ return how == CLONE ? n.cloneNode(TRUE) : n;\r
+\r
+ n.parentNode.removeChild(n);\r
+ };\r
+ };\r
+\r
+ ns.Range = Range;\r
+})(tinymce.dom);\r
+\r
+(function() {\r
+ function Selection(selection) {\r
+ var self = this, dom = selection.dom, TRUE = true, FALSE = false;\r
+\r
+ function getPosition(rng, start) {\r
+ var checkRng, startIndex = 0, endIndex, inside,\r
+ children, child, offset, index, position = -1, parent;\r
+\r
+ // Setup test range, collapse it and get the parent\r
+ checkRng = rng.duplicate();\r
+ checkRng.collapse(start);\r
+ parent = checkRng.parentElement();\r
+\r
+ // Check if the selection is within the right document\r
+ if (parent.ownerDocument !== selection.dom.doc)\r
+ return;\r
+\r
+ // IE will report non editable elements as it's parent so look for an editable one\r
+ while (parent.contentEditable === "false") {\r
+ parent = parent.parentNode;\r
+ }\r
+\r
+ // If parent doesn't have any children then return that we are inside the element\r
+ if (!parent.hasChildNodes()) {\r
+ return {node : parent, inside : 1};\r
+ }\r
+\r
+ // Setup node list and endIndex\r
+ children = parent.children;\r
+ endIndex = children.length - 1;\r
+\r
+ // Perform a binary search for the position\r
+ while (startIndex <= endIndex) {\r
+ index = Math.floor((startIndex + endIndex) / 2);\r
+\r
+ // Move selection to node and compare the ranges\r
+ child = children[index];\r
+ checkRng.moveToElementText(child);\r
+ position = checkRng.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', rng);\r
+\r
+ // Before/after or an exact match\r
+ if (position > 0) {\r
+ endIndex = index - 1;\r
+ } else if (position < 0) {\r
+ startIndex = index + 1;\r
+ } else {\r
+ return {node : child};\r
+ }\r
+ }\r
+\r
+ // Check if child position is before or we didn't find a position\r
+ if (position < 0) {\r
+ // No element child was found use the parent element and the offset inside that\r
+ if (!child) {\r
+ checkRng.moveToElementText(parent);\r
+ checkRng.collapse(true);\r
+ child = parent;\r
+ inside = true;\r
+ } else\r
+ checkRng.collapse(false);\r
+\r
+ checkRng.setEndPoint(start ? 'EndToStart' : 'EndToEnd', rng);\r
+\r
+ // Fix for edge case: <div style="width: 100px; height:100px;"><table>..</table>ab|c</div>\r
+ if (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) > 0) {\r
+ checkRng = rng.duplicate();\r
+ checkRng.collapse(start);\r
+\r
+ offset = -1;\r
+ while (parent == checkRng.parentElement()) {\r
+ if (checkRng.move('character', -1) == 0)\r
+ break;\r
+\r
+ offset++;\r
+ }\r
+ }\r
+\r
+ offset = offset || checkRng.text.replace('\r\n', ' ').length;\r
+ } else {\r
+ // Child position is after the selection endpoint\r
+ checkRng.collapse(true);\r
+ checkRng.setEndPoint(start ? 'StartToStart' : 'StartToEnd', rng);\r
+\r
+ // Get the length of the text to find where the endpoint is relative to it's container\r
+ offset = checkRng.text.replace('\r\n', ' ').length;\r
+ }\r
+\r
+ return {node : child, position : position, offset : offset, inside : inside};\r
+ };\r
+\r
+ // Returns a W3C DOM compatible range object by using the IE Range API\r
+ function getRange() {\r
+ var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed, tmpRange, element2, bookmark, fail;\r
+\r
+ // If selection is outside the current document just return an empty range\r
+ element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();\r
+ if (element.ownerDocument != dom.doc)\r
+ return domRange;\r
+\r
+ collapsed = selection.isCollapsed();\r
+\r
+ // Handle control selection\r
+ if (ieRange.item) {\r
+ domRange.setStart(element.parentNode, dom.nodeIndex(element));\r
+ domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);\r
+\r
+ return domRange;\r
+ }\r
+\r
+ function findEndPoint(start) {\r
+ var endPoint = getPosition(ieRange, start), container, offset, textNodeOffset = 0, sibling, undef, nodeValue;\r
+\r
+ container = endPoint.node;\r
+ offset = endPoint.offset;\r
+\r
+ if (endPoint.inside && !container.hasChildNodes()) {\r
+ domRange[start ? 'setStart' : 'setEnd'](container, 0);\r
+ return;\r
+ }\r
+\r
+ if (offset === undef) {\r
+ domRange[start ? 'setStartBefore' : 'setEndAfter'](container);\r
+ return;\r
+ }\r
+\r
+ if (endPoint.position < 0) {\r
+ sibling = endPoint.inside ? container.firstChild : container.nextSibling;\r
+\r
+ if (!sibling) {\r
+ domRange[start ? 'setStartAfter' : 'setEndAfter'](container);\r
+ return;\r
+ }\r
+\r
+ if (!offset) {\r
+ if (sibling.nodeType == 3)\r
+ domRange[start ? 'setStart' : 'setEnd'](sibling, 0);\r
+ else\r
+ domRange[start ? 'setStartBefore' : 'setEndBefore'](sibling);\r
+\r
+ return;\r
+ }\r
+\r
+ // Find the text node and offset\r
+ while (sibling) {\r
+ nodeValue = sibling.nodeValue;\r
+ textNodeOffset += nodeValue.length;\r
+\r
+ // We are at or passed the position we where looking for\r
+ if (textNodeOffset >= offset) {\r
+ container = sibling;\r
+ textNodeOffset -= offset;\r
+ textNodeOffset = nodeValue.length - textNodeOffset;\r
+ break;\r
+ }\r
+\r
+ sibling = sibling.nextSibling;\r
+ }\r
+ } else {\r
+ // Find the text node and offset\r
+ sibling = container.previousSibling;\r
+\r
+ if (!sibling)\r
+ return domRange[start ? 'setStartBefore' : 'setEndBefore'](container);\r
+\r
+ // If there isn't any text to loop then use the first position\r
+ if (!offset) {\r
+ if (container.nodeType == 3)\r
+ domRange[start ? 'setStart' : 'setEnd'](sibling, container.nodeValue.length);\r
+ else\r
+ domRange[start ? 'setStartAfter' : 'setEndAfter'](sibling);\r
+\r
+ return;\r
+ }\r
+\r
+ while (sibling) {\r
+ textNodeOffset += sibling.nodeValue.length;\r
+\r
+ // We are at or passed the position we where looking for\r
+ if (textNodeOffset >= offset) {\r
+ container = sibling;\r
+ textNodeOffset -= offset;\r
+ break;\r
+ }\r
+\r
+ sibling = sibling.previousSibling;\r
+ }\r
+ }\r
+\r
+ domRange[start ? 'setStart' : 'setEnd'](container, textNodeOffset);\r
+ };\r
+\r
+ try {\r
+ // Find start point\r
+ findEndPoint(true);\r
+\r
+ // Find end point if needed\r
+ if (!collapsed)\r
+ findEndPoint();\r
+ } catch (ex) {\r
+ // IE has a nasty bug where text nodes might throw "invalid argument" when you\r
+ // access the nodeValue or other properties of text nodes. This seems to happend when\r
+ // text nodes are split into two nodes by a delete/backspace call. So lets detect it and try to fix it.\r
+ if (ex.number == -2147024809) {\r
+ // Get the current selection\r
+ bookmark = self.getBookmark(2);\r
+\r
+ // Get start element\r
+ tmpRange = ieRange.duplicate();\r
+ tmpRange.collapse(true);\r
+ element = tmpRange.parentElement();\r
+\r
+ // Get end element\r
+ if (!collapsed) {\r
+ tmpRange = ieRange.duplicate();\r
+ tmpRange.collapse(false);\r
+ element2 = tmpRange.parentElement();\r
+ element2.innerHTML = element2.innerHTML;\r
+ }\r
+\r
+ // Remove the broken elements\r
+ element.innerHTML = element.innerHTML;\r
+\r
+ // Restore the selection\r
+ self.moveToBookmark(bookmark);\r
+\r
+ // Since the range has moved we need to re-get it\r
+ ieRange = selection.getRng();\r
+\r
+ // Find start point\r
+ findEndPoint(true);\r
+\r
+ // Find end point if needed\r
+ if (!collapsed)\r
+ findEndPoint();\r
+ } else\r
+ throw ex; // Throw other errors\r
+ }\r
+\r
+ return domRange;\r
+ };\r
+\r
+ this.getBookmark = function(type) {\r
+ var rng = selection.getRng(), start, end, bookmark = {};\r
+\r
+ function getIndexes(node) {\r
+ var node, parent, root, children, i, indexes = [];\r
+\r
+ parent = node.parentNode;\r
+ root = dom.getRoot().parentNode;\r
+\r
+ while (parent != root) {\r
+ children = parent.children;\r
+\r
+ i = children.length;\r
+ while (i--) {\r
+ if (node === children[i]) {\r
+ indexes.push(i);\r
+ break;\r
+ }\r
+ }\r
+\r
+ node = parent;\r
+ parent = parent.parentNode;\r
+ }\r
+\r
+ return indexes;\r
+ };\r
+\r
+ function getBookmarkEndPoint(start) {\r
+ var position;\r
+\r
+ position = getPosition(rng, start);\r
+ if (position) {\r
+ return {\r
+ position : position.position,\r
+ offset : position.offset,\r
+ indexes : getIndexes(position.node),\r
+ inside : position.inside\r
+ };\r
+ }\r
+ };\r
+\r
+ // Non ubstructive bookmark\r
+ if (type === 2) {\r
+ // Handle text selection\r
+ if (!rng.item) {\r
+ bookmark.start = getBookmarkEndPoint(true);\r
+\r
+ if (!selection.isCollapsed())\r
+ bookmark.end = getBookmarkEndPoint();\r
+ } else\r
+ bookmark.start = {ctrl : true, indexes : getIndexes(rng.item(0))};\r
+ }\r
+\r
+ return bookmark;\r
+ };\r
+\r
+ this.moveToBookmark = function(bookmark) {\r
+ var rng, body = dom.doc.body;\r
+\r
+ function resolveIndexes(indexes) {\r
+ var node, i, idx, children;\r
+\r
+ node = dom.getRoot();\r
+ for (i = indexes.length - 1; i >= 0; i--) {\r
+ children = node.children;\r
+ idx = indexes[i];\r
+\r
+ if (idx <= children.length - 1) {\r
+ node = children[idx];\r
+ }\r
+ }\r
+\r
+ return node;\r
+ };\r
+ \r
+ function setBookmarkEndPoint(start) {\r
+ var endPoint = bookmark[start ? 'start' : 'end'], moveLeft, moveRng, undef;\r
+\r
+ if (endPoint) {\r
+ moveLeft = endPoint.position > 0;\r
+\r
+ moveRng = body.createTextRange();\r
+ moveRng.moveToElementText(resolveIndexes(endPoint.indexes));\r
+\r
+ offset = endPoint.offset;\r
+ if (offset !== undef) {\r
+ moveRng.collapse(endPoint.inside || moveLeft);\r
+ moveRng.moveStart('character', moveLeft ? -offset : offset);\r
+ } else\r
+ moveRng.collapse(start);\r
+\r
+ rng.setEndPoint(start ? 'StartToStart' : 'EndToStart', moveRng);\r
+\r
+ if (start)\r
+ rng.collapse(true);\r
+ }\r
+ };\r
+\r
+ if (bookmark.start) {\r
+ if (bookmark.start.ctrl) {\r
+ rng = body.createControlRange();\r
+ rng.addElement(resolveIndexes(bookmark.start.indexes));\r
+ rng.select();\r
+ } else {\r
+ rng = body.createTextRange();\r
+ setBookmarkEndPoint(true);\r
+ setBookmarkEndPoint();\r
+ rng.select();\r
+ }\r
+ }\r
+ };\r
+\r
+ this.addRange = function(rng) {\r
+ var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, doc = selection.dom.doc, body = doc.body;\r
+\r
+ function setEndPoint(start) {\r
+ var container, offset, marker, tmpRng, nodes;\r
+\r
+ marker = dom.create('a');\r
+ container = start ? startContainer : endContainer;\r
+ offset = start ? startOffset : endOffset;\r
+ tmpRng = ieRng.duplicate();\r
+\r
+ if (container == doc || container == doc.documentElement) {\r
+ container = body;\r
+ offset = 0;\r
+ }\r
+\r
+ if (container.nodeType == 3) {\r
+ container.parentNode.insertBefore(marker, container);\r
+ tmpRng.moveToElementText(marker);\r
+ tmpRng.moveStart('character', offset);\r
+ dom.remove(marker);\r
+ ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);\r
+ } else {\r
+ nodes = container.childNodes;\r
+\r
+ if (nodes.length) {\r
+ if (offset >= nodes.length) {\r
+ dom.insertAfter(marker, nodes[nodes.length - 1]);\r
+ } else {\r
+ container.insertBefore(marker, nodes[offset]);\r
+ }\r
+\r
+ tmpRng.moveToElementText(marker);\r
+ } else {\r
+ // Empty node selection for example <div>|</div>\r
+ marker = doc.createTextNode('\uFEFF');\r
+ container.appendChild(marker);\r
+ tmpRng.moveToElementText(marker.parentNode);\r
+ tmpRng.collapse(TRUE);\r
+ }\r
+\r
+ ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);\r
+ dom.remove(marker);\r
+ }\r
+ }\r
+\r
+ // Setup some shorter versions\r
+ startContainer = rng.startContainer;\r
+ startOffset = rng.startOffset;\r
+ endContainer = rng.endContainer;\r
+ endOffset = rng.endOffset;\r
+ ieRng = body.createTextRange();\r
+\r
+ // If single element selection then try making a control selection out of it\r
+ if (startContainer == endContainer && startContainer.nodeType == 1 && startOffset == endOffset - 1) {\r
+ if (startOffset == endOffset - 1) {\r
+ try {\r
+ ctrlRng = body.createControlRange();\r
+ ctrlRng.addElement(startContainer.childNodes[startOffset]);\r
+ ctrlRng.select();\r
+ return;\r
+ } catch (ex) {\r
+ // Ignore\r
+ }\r
+ }\r
+ }\r
+\r
+ // Set start/end point of selection\r
+ setEndPoint(true);\r
+ setEndPoint();\r
+\r
+ // Select the new range and scroll it into view\r
+ ieRng.select();\r
+ };\r
+\r
+ // Expose range method\r
+ this.getRangeAt = getRange;\r
+ };\r
+\r
+ // Expose the selection object\r
+ tinymce.dom.TridentSelection = Selection;\r
+})();\r
+\r
+\r
+/*\r
+ * Sizzle CSS Selector Engine - v1.0\r
+ * Copyright 2009, The Dojo Foundation\r
+ * Released under the MIT, BSD, and GPL Licenses.\r
+ * More information: http://sizzlejs.com/\r
+ */\r
+(function(){\r
+\r
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,\r
+ done = 0,\r
+ toString = Object.prototype.toString,\r
+ hasDuplicate = false,\r
+ baseHasDuplicate = true;\r
+\r
+// Here we check if the JavaScript engine is using some sort of\r
+// optimization where it does not always call our comparision\r
+// function. If that is the case, discard the hasDuplicate value.\r
+// Thus far that includes Google Chrome.\r
+[0, 0].sort(function(){\r
+ baseHasDuplicate = false;\r
+ return 0;\r
+});\r
+\r
+var Sizzle = function(selector, context, results, seed) {\r
+ results = results || [];\r
+ context = context || document;\r
+\r
+ var origContext = context;\r
+\r
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {\r
+ return [];\r
+ }\r
+ \r
+ if ( !selector || typeof selector !== "string" ) {\r
+ return results;\r
+ }\r
+\r
+ var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context),\r
+ soFar = selector, ret, cur, pop, i;\r
+ \r
+ // Reset the position of the chunker regexp (start from head)\r
+ do {\r
+ chunker.exec("");\r
+ m = chunker.exec(soFar);\r
+\r
+ if ( m ) {\r
+ soFar = m[3];\r
+ \r
+ parts.push( m[1] );\r
+ \r
+ if ( m[2] ) {\r
+ extra = m[3];\r
+ break;\r
+ }\r
+ }\r
+ } while ( m );\r
+\r
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {\r
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\r
+ set = posProcess( parts[0] + parts[1], context );\r
+ } else {\r
+ set = Expr.relative[ parts[0] ] ?\r
+ [ context ] :\r
+ Sizzle( parts.shift(), context );\r
+\r
+ while ( parts.length ) {\r
+ selector = parts.shift();\r
+\r
+ if ( Expr.relative[ selector ] ) {\r
+ selector += parts.shift();\r
+ }\r
+ \r
+ set = posProcess( selector, set );\r
+ }\r
+ }\r
+ } else {\r
+ // Take a shortcut and set the context if the root selector is an ID\r
+ // (but not if it'll be faster if the inner selector is an ID)\r
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\r
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\r
+ ret = Sizzle.find( parts.shift(), context, contextXML );\r
+ context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];\r
+ }\r
+\r
+ if ( context ) {\r
+ ret = seed ?\r
+ { expr: parts.pop(), set: makeArray(seed) } :\r
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );\r
+ set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;\r
+\r
+ if ( parts.length > 0 ) {\r
+ checkSet = makeArray(set);\r
+ } else {\r
+ prune = false;\r
+ }\r
+\r
+ while ( parts.length ) {\r
+ cur = parts.pop();\r
+ pop = cur;\r
+\r
+ if ( !Expr.relative[ cur ] ) {\r
+ cur = "";\r
+ } else {\r
+ pop = parts.pop();\r
+ }\r
+\r
+ if ( pop == null ) {\r
+ pop = context;\r
+ }\r
+\r
+ Expr.relative[ cur ]( checkSet, pop, contextXML );\r
+ }\r
+ } else {\r
+ checkSet = parts = [];\r
+ }\r
+ }\r
+\r
+ if ( !checkSet ) {\r
+ checkSet = set;\r
+ }\r
+\r
+ if ( !checkSet ) {\r
+ Sizzle.error( cur || selector );\r
+ }\r
+\r
+ if ( toString.call(checkSet) === "[object Array]" ) {\r
+ if ( !prune ) {\r
+ results.push.apply( results, checkSet );\r
+ } else if ( context && context.nodeType === 1 ) {\r
+ for ( i = 0; checkSet[i] != null; i++ ) {\r
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {\r
+ results.push( set[i] );\r
+ }\r
+ }\r
+ } else {\r
+ for ( i = 0; checkSet[i] != null; i++ ) {\r
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {\r
+ results.push( set[i] );\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ makeArray( checkSet, results );\r
+ }\r
+\r
+ if ( extra ) {\r
+ Sizzle( extra, origContext, results, seed );\r
+ Sizzle.uniqueSort( results );\r
+ }\r
+\r
+ return results;\r
+};\r
+\r
+Sizzle.uniqueSort = function(results){\r
+ if ( sortOrder ) {\r
+ hasDuplicate = baseHasDuplicate;\r
+ results.sort(sortOrder);\r
+\r
+ if ( hasDuplicate ) {\r
+ for ( var i = 1; i < results.length; i++ ) {\r
+ if ( results[i] === results[i-1] ) {\r
+ results.splice(i--, 1);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return results;\r
+};\r
+\r
+Sizzle.matches = function(expr, set){\r
+ return Sizzle(expr, null, null, set);\r
+};\r
+\r
+Sizzle.find = function(expr, context, isXML){\r
+ var set;\r
+\r
+ if ( !expr ) {\r
+ return [];\r
+ }\r
+\r
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {\r
+ var type = Expr.order[i], match;\r
+ \r
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\r
+ var left = match[1];\r
+ match.splice(1,1);\r
+\r
+ if ( left.substr( left.length - 1 ) !== "\\" ) {\r
+ match[1] = (match[1] || "").replace(/\\/g, "");\r
+ set = Expr.find[ type ]( match, context, isXML );\r
+ if ( set != null ) {\r
+ expr = expr.replace( Expr.match[ type ], "" );\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if ( !set ) {\r
+ set = context.getElementsByTagName("*");\r
+ }\r
+\r
+ return {set: set, expr: expr};\r
+};\r
+\r
+Sizzle.filter = function(expr, set, inplace, not){\r
+ var old = expr, result = [], curLoop = set, match, anyFound,\r
+ isXMLFilter = set && set[0] && Sizzle.isXML(set[0]);\r
+\r
+ while ( expr && set.length ) {\r
+ for ( var type in Expr.filter ) {\r
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\r
+ var filter = Expr.filter[ type ], found, item, left = match[1];\r
+ anyFound = false;\r
+\r
+ match.splice(1,1);\r
+\r
+ if ( left.substr( left.length - 1 ) === "\\" ) {\r
+ continue;\r
+ }\r
+\r
+ if ( curLoop === result ) {\r
+ result = [];\r
+ }\r
+\r
+ if ( Expr.preFilter[ type ] ) {\r
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\r
+\r
+ if ( !match ) {\r
+ anyFound = found = true;\r
+ } else if ( match === true ) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if ( match ) {\r
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {\r
+ if ( item ) {\r
+ found = filter( item, match, i, curLoop );\r
+ var pass = not ^ !!found;\r
+\r
+ if ( inplace && found != null ) {\r
+ if ( pass ) {\r
+ anyFound = true;\r
+ } else {\r
+ curLoop[i] = false;\r
+ }\r
+ } else if ( pass ) {\r
+ result.push( item );\r
+ anyFound = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if ( found !== undefined ) {\r
+ if ( !inplace ) {\r
+ curLoop = result;\r
+ }\r
+\r
+ expr = expr.replace( Expr.match[ type ], "" );\r
+\r
+ if ( !anyFound ) {\r
+ return [];\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Improper expression\r
+ if ( expr === old ) {\r
+ if ( anyFound == null ) {\r
+ Sizzle.error( expr );\r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+\r
+ old = expr;\r
+ }\r
+\r
+ return curLoop;\r
+};\r
+\r
+Sizzle.error = function( msg ) {\r
+ throw "Syntax error, unrecognized expression: " + msg;\r
+};\r
+\r
+var Expr = Sizzle.selectors = {\r
+ order: [ "ID", "NAME", "TAG" ],\r
+ match: {\r
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,\r
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,\r
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,\r
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,\r
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,\r
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,\r
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,\r
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/\r
+ },\r
+ leftMatch: {},\r
+ attrMap: {\r
+ "class": "className",\r
+ "for": "htmlFor"\r
+ },\r
+ attrHandle: {\r
+ href: function(elem){\r
+ return elem.getAttribute("href");\r
+ }\r
+ },\r
+ relative: {\r
+ "+": function(checkSet, part){\r
+ var isPartStr = typeof part === "string",\r
+ isTag = isPartStr && !/\W/.test(part),\r
+ isPartStrNotTag = isPartStr && !isTag;\r
+\r
+ if ( isTag ) {\r
+ part = part.toLowerCase();\r
+ }\r
+\r
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\r
+ if ( (elem = checkSet[i]) ) {\r
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\r
+\r
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\r
+ elem || false :\r
+ elem === part;\r
+ }\r
+ }\r
+\r
+ if ( isPartStrNotTag ) {\r
+ Sizzle.filter( part, checkSet, true );\r
+ }\r
+ },\r
+ ">": function(checkSet, part){\r
+ var isPartStr = typeof part === "string",\r
+ elem, i = 0, l = checkSet.length;\r
+\r
+ if ( isPartStr && !/\W/.test(part) ) {\r
+ part = part.toLowerCase();\r
+\r
+ for ( ; i < l; i++ ) {\r
+ elem = checkSet[i];\r
+ if ( elem ) {\r
+ var parent = elem.parentNode;\r
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\r
+ }\r
+ }\r
+ } else {\r
+ for ( ; i < l; i++ ) {\r
+ elem = checkSet[i];\r
+ if ( elem ) {\r
+ checkSet[i] = isPartStr ?\r
+ elem.parentNode :\r
+ elem.parentNode === part;\r
+ }\r
+ }\r
+\r
+ if ( isPartStr ) {\r
+ Sizzle.filter( part, checkSet, true );\r
+ }\r
+ }\r
+ },\r
+ "": function(checkSet, part, isXML){\r
+ var doneName = done++, checkFn = dirCheck, nodeCheck;\r
+\r
+ if ( typeof part === "string" && !/\W/.test(part) ) {\r
+ part = part.toLowerCase();\r
+ nodeCheck = part;\r
+ checkFn = dirNodeCheck;\r
+ }\r
+\r
+ checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);\r
+ },\r
+ "~": function(checkSet, part, isXML){\r
+ var doneName = done++, checkFn = dirCheck, nodeCheck;\r
+\r
+ if ( typeof part === "string" && !/\W/.test(part) ) {\r
+ part = part.toLowerCase();\r
+ nodeCheck = part;\r
+ checkFn = dirNodeCheck;\r
+ }\r
+\r
+ checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);\r
+ }\r
+ },\r
+ find: {\r
+ ID: function(match, context, isXML){\r
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {\r
+ var m = context.getElementById(match[1]);\r
+ return m ? [m] : [];\r
+ }\r
+ },\r
+ NAME: function(match, context){\r
+ if ( typeof context.getElementsByName !== "undefined" ) {\r
+ var ret = [], results = context.getElementsByName(match[1]);\r
+\r
+ for ( var i = 0, l = results.length; i < l; i++ ) {\r
+ if ( results[i].getAttribute("name") === match[1] ) {\r
+ ret.push( results[i] );\r
+ }\r
+ }\r
+\r
+ return ret.length === 0 ? null : ret;\r
+ }\r
+ },\r
+ TAG: function(match, context){\r
+ return context.getElementsByTagName(match[1]);\r
+ }\r
+ },\r
+ preFilter: {\r
+ CLASS: function(match, curLoop, inplace, result, not, isXML){\r
+ match = " " + match[1].replace(/\\/g, "") + " ";\r
+\r
+ if ( isXML ) {\r
+ return match;\r
+ }\r
+\r
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\r
+ if ( elem ) {\r
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {\r
+ if ( !inplace ) {\r
+ result.push( elem );\r
+ }\r
+ } else if ( inplace ) {\r
+ curLoop[i] = false;\r
+ }\r
+ }\r
+ }\r
+\r
+ return false;\r
+ },\r
+ ID: function(match){\r
+ return match[1].replace(/\\/g, "");\r
+ },\r
+ TAG: function(match, curLoop){\r
+ return match[1].toLowerCase();\r
+ },\r
+ CHILD: function(match){\r
+ if ( match[1] === "nth" ) {\r
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\r
+ var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(\r
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||\r
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);\r
+\r
+ // calculate the numbers (first)n+(last) including if they are negative\r
+ match[2] = (test[1] + (test[2] || 1)) - 0;\r
+ match[3] = test[3] - 0;\r
+ }\r
+\r
+ // TODO: Move to normal caching system\r
+ match[0] = done++;\r
+\r
+ return match;\r
+ },\r
+ ATTR: function(match, curLoop, inplace, result, not, isXML){\r
+ var name = match[1].replace(/\\/g, "");\r
+ \r
+ if ( !isXML && Expr.attrMap[name] ) {\r
+ match[1] = Expr.attrMap[name];\r
+ }\r
+\r
+ if ( match[2] === "~=" ) {\r
+ match[4] = " " + match[4] + " ";\r
+ }\r
+\r
+ return match;\r
+ },\r
+ PSEUDO: function(match, curLoop, inplace, result, not){\r
+ if ( match[1] === "not" ) {\r
+ // If we're dealing with a complex expression, or a simple one\r
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {\r
+ match[3] = Sizzle(match[3], null, null, curLoop);\r
+ } else {\r
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\r
+ if ( !inplace ) {\r
+ result.push.apply( result, ret );\r
+ }\r
+ return false;\r
+ }\r
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\r
+ return true;\r
+ }\r
+ \r
+ return match;\r
+ },\r
+ POS: function(match){\r
+ match.unshift( true );\r
+ return match;\r
+ }\r
+ },\r
+ filters: {\r
+ enabled: function(elem){\r
+ return elem.disabled === false && elem.type !== "hidden";\r
+ },\r
+ disabled: function(elem){\r
+ return elem.disabled === true;\r
+ },\r
+ checked: function(elem){\r
+ return elem.checked === true;\r
+ },\r
+ selected: function(elem){\r
+ // Accessing this property makes selected-by-default\r
+ // options in Safari work properly\r
+ elem.parentNode.selectedIndex;\r
+ return elem.selected === true;\r
+ },\r
+ parent: function(elem){\r
+ return !!elem.firstChild;\r
+ },\r
+ empty: function(elem){\r
+ return !elem.firstChild;\r
+ },\r
+ has: function(elem, i, match){\r
+ return !!Sizzle( match[3], elem ).length;\r
+ },\r
+ header: function(elem){\r
+ return (/h\d/i).test( elem.nodeName );\r
+ },\r
+ text: function(elem){\r
+ return "text" === elem.type;\r
+ },\r
+ radio: function(elem){\r
+ return "radio" === elem.type;\r
+ },\r
+ checkbox: function(elem){\r
+ return "checkbox" === elem.type;\r
+ },\r
+ file: function(elem){\r
+ return "file" === elem.type;\r
+ },\r
+ password: function(elem){\r
+ return "password" === elem.type;\r
+ },\r
+ submit: function(elem){\r
+ return "submit" === elem.type;\r
+ },\r
+ image: function(elem){\r
+ return "image" === elem.type;\r
+ },\r
+ reset: function(elem){\r
+ return "reset" === elem.type;\r
+ },\r
+ button: function(elem){\r
+ return "button" === elem.type || elem.nodeName.toLowerCase() === "button";\r
+ },\r
+ input: function(elem){\r
+ return (/input|select|textarea|button/i).test(elem.nodeName);\r
+ }\r
+ },\r
+ setFilters: {\r
+ first: function(elem, i){\r
+ return i === 0;\r
+ },\r
+ last: function(elem, i, match, array){\r
+ return i === array.length - 1;\r
+ },\r
+ even: function(elem, i){\r
+ return i % 2 === 0;\r
+ },\r
+ odd: function(elem, i){\r
+ return i % 2 === 1;\r
+ },\r
+ lt: function(elem, i, match){\r
+ return i < match[3] - 0;\r
+ },\r
+ gt: function(elem, i, match){\r
+ return i > match[3] - 0;\r
+ },\r
+ nth: function(elem, i, match){\r
+ return match[3] - 0 === i;\r
+ },\r
+ eq: function(elem, i, match){\r
+ return match[3] - 0 === i;\r
+ }\r
+ },\r
+ filter: {\r
+ PSEUDO: function(elem, match, i, array){\r
+ var name = match[1], filter = Expr.filters[ name ];\r
+\r
+ if ( filter ) {\r
+ return filter( elem, i, match, array );\r
+ } else if ( name === "contains" ) {\r
+ return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;\r
+ } else if ( name === "not" ) {\r
+ var not = match[3];\r
+\r
+ for ( var j = 0, l = not.length; j < l; j++ ) {\r
+ if ( not[j] === elem ) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ return true;\r
+ } else {\r
+ Sizzle.error( "Syntax error, unrecognized expression: " + name );\r
+ }\r
+ },\r
+ CHILD: function(elem, match){\r
+ var type = match[1], node = elem;\r
+ switch (type) {\r
+ case 'only':\r
+ case 'first':\r
+ while ( (node = node.previousSibling) ) {\r
+ if ( node.nodeType === 1 ) { \r
+ return false; \r
+ }\r
+ }\r
+ if ( type === "first" ) { \r
+ return true; \r
+ }\r
+ node = elem;\r
+ case 'last':\r
+ while ( (node = node.nextSibling) ) {\r
+ if ( node.nodeType === 1 ) { \r
+ return false; \r
+ }\r
+ }\r
+ return true;\r
+ case 'nth':\r
+ var first = match[2], last = match[3];\r
+\r
+ if ( first === 1 && last === 0 ) {\r
+ return true;\r
+ }\r
+ \r
+ var doneName = match[0],\r
+ parent = elem.parentNode;\r
+ \r
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {\r
+ var count = 0;\r
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {\r
+ if ( node.nodeType === 1 ) {\r
+ node.nodeIndex = ++count;\r
+ }\r
+ } \r
+ parent.sizcache = doneName;\r
+ }\r
+ \r
+ var diff = elem.nodeIndex - last;\r
+ if ( first === 0 ) {\r
+ return diff === 0;\r
+ } else {\r
+ return ( diff % first === 0 && diff / first >= 0 );\r
+ }\r
+ }\r
+ },\r
+ ID: function(elem, match){\r
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;\r
+ },\r
+ TAG: function(elem, match){\r
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;\r
+ },\r
+ CLASS: function(elem, match){\r
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")\r
+ .indexOf( match ) > -1;\r
+ },\r
+ ATTR: function(elem, match){\r
+ var name = match[1],\r
+ result = Expr.attrHandle[ name ] ?\r
+ Expr.attrHandle[ name ]( elem ) :\r
+ elem[ name ] != null ?\r
+ elem[ name ] :\r
+ elem.getAttribute( name ),\r
+ value = result + "",\r
+ type = match[2],\r
+ check = match[4];\r
+\r
+ return result == null ?\r
+ type === "!=" :\r
+ type === "=" ?\r
+ value === check :\r
+ type === "*=" ?\r
+ value.indexOf(check) >= 0 :\r
+ type === "~=" ?\r
+ (" " + value + " ").indexOf(check) >= 0 :\r
+ !check ?\r
+ value && result !== false :\r
+ type === "!=" ?\r
+ value !== check :\r
+ type === "^=" ?\r
+ value.indexOf(check) === 0 :\r
+ type === "$=" ?\r
+ value.substr(value.length - check.length) === check :\r
+ type === "|=" ?\r
+ value === check || value.substr(0, check.length + 1) === check + "-" :\r
+ false;\r
+ },\r
+ POS: function(elem, match, i, array){\r
+ var name = match[2], filter = Expr.setFilters[ name ];\r
+\r
+ if ( filter ) {\r
+ return filter( elem, i, match, array );\r
+ }\r
+ }\r
+ }\r
+};\r