You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
7.9 KiB
JavaScript
239 lines
7.9 KiB
JavaScript
define([
|
|
"require",
|
|
"dojo/_base/array", // array.forEach
|
|
"dojo/_base/connect", // remove for 2.0
|
|
"dojo/_base/declare", // declare
|
|
"dojo/_base/lang", // lang.getObject
|
|
"dojo/mouse",
|
|
"dojo/on",
|
|
"dojo/touch",
|
|
"./_WidgetBase"
|
|
], function(require, array, connect, declare, lang, mouse, on, touch, _WidgetBase){
|
|
|
|
// module:
|
|
// dijit/_AttachMixin
|
|
|
|
// Map from string name like "mouseenter" to synthetic event like mouse.enter
|
|
var synthEvents = lang.delegate(touch, {
|
|
"mouseenter": mouse.enter,
|
|
"mouseleave": mouse.leave,
|
|
"keypress": connect._keypress // remove for 2.0
|
|
});
|
|
|
|
// To be lightweight, _AttachMixin doesn't require() dijit/a11yclick.
|
|
// If the subclass has a template using "ondijitclick", it must load dijit/a11yclick itself.
|
|
// In that case, the a11yclick variable below will get set to point to that synthetic event.
|
|
var a11yclick;
|
|
|
|
var _AttachMixin = declare("dijit._AttachMixin", null, {
|
|
// summary:
|
|
// Mixin for widgets to attach to dom nodes and setup events via
|
|
// convenient data-dojo-attach-point and data-dojo-attach-event DOM attributes.
|
|
//
|
|
// Superclass of _TemplatedMixin, and can also be used standalone when templates are pre-rendered on the
|
|
// server.
|
|
//
|
|
// Does not [yet] handle widgets like ContentPane with this.containerNode set. It should skip
|
|
// scanning for data-dojo-attach-point and data-dojo-attach-event inside this.containerNode, but it
|
|
// doesn't.
|
|
|
|
/*=====
|
|
// _attachPoints: [private] String[]
|
|
// List of widget attribute names associated with data-dojo-attach-point=... in the
|
|
// template, ex: ["containerNode", "labelNode"]
|
|
_attachPoints: [],
|
|
|
|
// _attachEvents: [private] Handle[]
|
|
// List of connections associated with data-dojo-attach-event=... in the
|
|
// template
|
|
_attachEvents: [],
|
|
|
|
// attachScope: [public] Object
|
|
// Object to which attach points and events will be scoped. Defaults
|
|
// to 'this'.
|
|
attachScope: undefined,
|
|
|
|
// searchContainerNode: [protected] Boolean
|
|
// Search descendants of this.containerNode for data-dojo-attach-point and data-dojo-attach-event.
|
|
// Should generally be left false (the default value) both for performance and to avoid failures when
|
|
// this.containerNode holds other _AttachMixin instances with their own attach points and events.
|
|
searchContainerNode: false,
|
|
=====*/
|
|
|
|
constructor: function(/*===== params, srcNodeRef =====*/){
|
|
// summary:
|
|
// Create the widget.
|
|
// params: Object|null
|
|
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
|
|
// and functions, typically callbacks like onClick.
|
|
// The hash can contain any of the widget's properties, excluding read-only properties.
|
|
// srcNodeRef: DOMNode|String?
|
|
// If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree.
|
|
|
|
this._attachPoints = [];
|
|
this._attachEvents = [];
|
|
},
|
|
|
|
|
|
buildRendering: function(){
|
|
// summary:
|
|
// Attach to DOM nodes marked with special attributes.
|
|
// tags:
|
|
// protected
|
|
|
|
this.inherited(arguments);
|
|
|
|
// recurse through the node, looking for, and attaching to, our
|
|
// attachment points and events, which should be defined on the template node.
|
|
this._attachTemplateNodes(this.domNode);
|
|
|
|
this._beforeFillContent(); // hook for _WidgetsInTemplateMixin
|
|
},
|
|
|
|
_beforeFillContent: function(){
|
|
},
|
|
|
|
_attachTemplateNodes: function(rootNode){
|
|
// summary:
|
|
// Iterate through the dom nodes and attach functions and nodes accordingly.
|
|
// description:
|
|
// Map widget properties and functions to the handlers specified in
|
|
// the dom node and it's descendants. This function iterates over all
|
|
// nodes and looks for these properties:
|
|
//
|
|
// - dojoAttachPoint/data-dojo-attach-point
|
|
// - dojoAttachEvent/data-dojo-attach-event
|
|
// rootNode: DomNode
|
|
// The node to search for properties. All descendants will be searched.
|
|
// tags:
|
|
// private
|
|
|
|
// DFS to process all nodes except those inside of this.containerNode
|
|
var node = rootNode;
|
|
while(true){
|
|
if(node.nodeType == 1 && (this._processTemplateNode(node, function(n,p){ return n.getAttribute(p); },
|
|
this._attach) || this.searchContainerNode) && node.firstChild){
|
|
node = node.firstChild;
|
|
}else{
|
|
if(node == rootNode){ return; }
|
|
while(!node.nextSibling){
|
|
node = node.parentNode;
|
|
if(node == rootNode){ return; }
|
|
}
|
|
node = node.nextSibling;
|
|
}
|
|
}
|
|
},
|
|
|
|
_processTemplateNode: function(/*DOMNode|Widget*/ baseNode, getAttrFunc, attachFunc){
|
|
// summary:
|
|
// Process data-dojo-attach-point and data-dojo-attach-event for given node or widget.
|
|
// Returns true if caller should process baseNode's children too.
|
|
|
|
var ret = true;
|
|
|
|
// Process data-dojo-attach-point
|
|
var _attachScope = this.attachScope || this,
|
|
attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");
|
|
if(attachPoint){
|
|
var point, points = attachPoint.split(/\s*,\s*/);
|
|
while((point = points.shift())){
|
|
if(lang.isArray(_attachScope[point])){
|
|
_attachScope[point].push(baseNode);
|
|
}else{
|
|
_attachScope[point] = baseNode;
|
|
}
|
|
ret = (point != "containerNode");
|
|
this._attachPoints.push(point);
|
|
}
|
|
}
|
|
|
|
// Process data-dojo-attach-event
|
|
var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");
|
|
if(attachEvent){
|
|
// NOTE: we want to support attributes that have the form
|
|
// "domEvent: nativeEvent; ..."
|
|
var event, events = attachEvent.split(/\s*,\s*/);
|
|
var trim = lang.trim;
|
|
while((event = events.shift())){
|
|
if(event){
|
|
var thisFunc = null;
|
|
if(event.indexOf(":") != -1){
|
|
// oh, if only JS had tuple assignment
|
|
var funcNameArr = event.split(":");
|
|
event = trim(funcNameArr[0]);
|
|
thisFunc = trim(funcNameArr[1]);
|
|
}else{
|
|
event = trim(event);
|
|
}
|
|
if(!thisFunc){
|
|
thisFunc = event;
|
|
}
|
|
|
|
this._attachEvents.push(attachFunc(baseNode, event, lang.hitch(_attachScope, thisFunc)));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
|
|
_attach: function(node, type, func){
|
|
// summary:
|
|
// Roughly corresponding to dojo/on, this is the default function for processing a
|
|
// data-dojo-attach-event. Meant to attach to DOMNodes, not to widgets.
|
|
// node: DOMNode
|
|
// The node to setup a listener on.
|
|
// type: String
|
|
// Event name like "click".
|
|
// getAttrFunc: Function
|
|
// Function to get the specified property for a given DomNode/Widget.
|
|
// attachFunc: Function?
|
|
// Attaches an event handler from the specified node/widget to specified function.
|
|
|
|
// Map special type names like "mouseenter" to synthetic events.
|
|
// Subclasses are responsible to require() dijit/a11yclick if they want to use it.
|
|
type = type.replace(/^on/, "").toLowerCase();
|
|
if(type == "dijitclick"){
|
|
type = a11yclick || (a11yclick = require("./a11yclick"));
|
|
}else{
|
|
type = synthEvents[type] || type;
|
|
}
|
|
|
|
return on(node, type, func);
|
|
},
|
|
|
|
_detachTemplateNodes: function() {
|
|
// summary:
|
|
// Detach and clean up the attachments made in _attachtempalteNodes.
|
|
|
|
// Delete all attach points to prevent IE6 memory leaks.
|
|
var _attachScope = this.attachScope || this;
|
|
array.forEach(this._attachPoints, function(point){
|
|
delete _attachScope[point];
|
|
});
|
|
this._attachPoints = [];
|
|
|
|
// And same for event handlers
|
|
array.forEach(this._attachEvents, function(handle){ handle.remove(); });
|
|
this._attachEvents = [];
|
|
},
|
|
|
|
destroyRendering: function(){
|
|
this._detachTemplateNodes();
|
|
this.inherited(arguments);
|
|
}
|
|
});
|
|
|
|
// These arguments can be specified for widgets which are used in templates.
|
|
// Since any widget can be specified as sub widgets in template, mix it
|
|
// into the base widget class. (This is a hack, but it's effective.).
|
|
// Remove for 2.0. Also, hide from API doc parser.
|
|
lang.extend(_WidgetBase, /*===== {} || =====*/ {
|
|
dojoAttachEvent: "",
|
|
dojoAttachPoint: ""
|
|
});
|
|
|
|
return _AttachMixin;
|
|
});
|