can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
162 lines (153 loc) • 4.45 kB
JavaScript
steal('can/util', "can/view",function (can) {
var doc = typeof document !== "undefined" ? document: null;
var selectsCommentNodes = doc && (function(){
return can.$(document.createComment('~')).length === 1;
})();
/**
* @property {Object} can.view.elements
* @parent can.view
*
* Provides helper methods for and information about the behavior
* of DOM elements.
*/
var elements = {
tagToContentPropMap: {
option: ( doc && "textContent" in document.createElement("option") ) ? "textContent" : "innerText",
textarea: 'value'
},
/**
* @property {Object.<String,(String|Boolean|function)>} can.view.elements.attrMap
* @parent can.view.elements
*
*
* A mapping of
* special attributes to their JS property. For example:
*
* "class" : "className"
*
* means get or set `element.className`. And:
*
* "checked" : true
*
* means set `element.checked = true`.
*
*
* If the attribute name is not found, it's assumed to use
* `element.getAttribute` and `element.setAttribute`.
*/
// 3.0 TODO: remove
attrMap: can.attr.map,
// matches the attrName of a regexp
attrReg: /([^\s=]+)[\s]*=[\s]*/,
// 3.0 TODO: remove
defaultValue: can.attr.defaultValue,
// a map of parent element to child elements
/**
* @property {Object.<String,String>} can.view.elements.tagMap
* @parent can.view.elements
*
* A mapping of parent node names to child node names that can be inserted within
* the parent node name. For example: `table: "tbody"` means that
* if you want a placeholder element within a `table`, a `tbody` will be
* created.
*/
tagMap: {
'': 'span',
colgroup: 'col',
table: 'tbody',
tr: 'td',
ol: 'li',
ul: 'li',
tbody: 'tr',
thead: 'tr',
tfoot: 'tr',
select: 'option',
optgroup: 'option'
},
// a tag's parent element
reverseTagMap: {
col: 'colgroup',
tr: 'tbody',
option: 'select',
td: 'tr',
th: 'tr',
li: 'ul'
},
// tags that should be handled as self-closing and should not have content in them
// when generated as part of binding hookup
selfClosingTags: {
col: true
},
// Used to determine the parentNode if el is directly within a documentFragment
getParentNode: function (el, defaultParentNode) {
return defaultParentNode && el.parentNode.nodeType === 11 ? defaultParentNode : el.parentNode;
},
// 3.0 TODO: remove
setAttr: can.attr.set,
// 3.0 TODO: remove
getAttr: can.attr.get,
// 3.0 TODO: remove
removeAttr: can.attr.remove,
// Gets a "pretty" value for something
contentText: function (text) {
if (typeof text === 'string') {
return text;
}
// If has no value, return an empty string.
if (!text && text !== 0) {
return '';
}
return '' + text;
},
/**
* @function can.view.elements.after
* @parent can.view.elements
*
* Inserts newFrag after oldElements.
*
* @param {Array.<HTMLElement>} oldElements
* @param {DocumentFragment} newFrag
*/
after: function (oldElements, newFrag) {
var last = oldElements[oldElements.length - 1];
// Insert it in the `document` or `documentFragment`
if (last.nextSibling) {
can.insertBefore(last.parentNode, newFrag, last.nextSibling, can.document);
} else {
can.appendChild(last.parentNode, newFrag, can.document);
}
},
/**
* @function can.view.elements.replace
* @parent can.view.elements
*
* Replaces `oldElements` with `newFrag`
*
* @param {Array.<HTMLElement>} oldElements
* @param {DocumentFragment} newFrag
*/
replace: function (oldElements, newFrag) {
// The following helps make sure that a selected <option> remains
// the same by removing `selected` from the currently selected option
// and adding selected to an option that has the same value.
var selectedValue,
parentNode = oldElements[0].parentNode;
if(parentNode.nodeName.toUpperCase() === "SELECT" && parentNode.selectedIndex >= 0) {
selectedValue = parentNode.value;
}
elements.after(oldElements, newFrag);
if(can.remove(can.$(oldElements)).length < oldElements.length && !selectsCommentNodes) {
can.each(oldElements, function(el) {
if(el.nodeType === 8) {
el.parentNode.removeChild(el);
}
});
}
if(selectedValue !== undefined) {
parentNode.value = selectedValue;
}
}
};
can.view.elements = elements;
return elements;
});