]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/dnd/Container.js.uncompressed.js
1 define("dojo/dnd/Container", [
19 array
, declare
, event
, kernel
, lang
, win
,
20 dom
, domClass
, domConstruct
, Evented
, has
, on
, query
, ready
, touch
, dnd
){
28 "Over" - mouse over a container
29 Container item states:
31 "Over" - mouse over a container item
36 var Container
= declare("dojo.dnd.Container", Evented
, {
38 // a Container object, which knows when mouse hovers over it,
39 // and over which element it hovers
41 // object attributes (for markup)
43 // allowNested: Boolean
44 // Indicates whether to allow dnd item nodes to be nested within other elements.
45 // By default this is false, indicating that only direct children of the container can
46 // be draggable dnd item nodes
50 // The DOM node the mouse is currently hovered over
53 // map: Hash<String, Container.Item>
54 // Map from an item's id (which is also the DOMNode's id) to
55 // the dojo/dnd/Container.Item itself.
59 constructor: function(node
, params
){
61 // a constructor of the Container
63 // node or node's id to build the container on
64 // params: Container.__ContainerArgs
65 // a dictionary of parameters
66 this.node
= dom
.byId(node
);
67 if(!params
){ params
= {}; }
68 this.creator
= params
.creator
|| null;
69 this.skipForm
= params
.skipForm
;
70 this.parent
= params
.dropParent
&& dom
.byId(params
.dropParent
);
72 // class-specific variables
77 this.containerState
= "";
78 domClass
.add(this.node
, "dojoDndContainer");
81 if(!(params
&& params
._skipStartup
)){
87 on(this.node
, touch
.over
, lang
.hitch(this, "onMouseOver")),
88 on(this.node
, touch
.out
, lang
.hitch(this, "onMouseOut")),
89 // cancel text selection and text dragging
90 on(this.node
, "dragstart", lang
.hitch(this, "onSelectStart")),
91 on(this.node
, "selectstart", lang
.hitch(this, "onSelectStart"))
95 // object attributes (for markup)
98 // creator function, dummy at the moment
101 // abstract access to the map
102 getItem: function(/*String*/ key
){
104 // returns a data item by its key (id)
105 return this.map
[key
]; // Container.Item
107 setItem: function(/*String*/ key
, /*Container.Item*/ data
){
109 // associates a data item with its key (id)
110 this.map
[key
] = data
;
112 delItem: function(/*String*/ key
){
114 // removes a data item from the map by its key (id)
115 delete this.map
[key
];
117 forInItems: function(/*Function*/ f
, /*Object?*/ o
){
119 // iterates over a data map skipping members that
120 // are present in the empty object (IE and/or 3rd-party libraries).
121 o
= o
|| kernel
.global
;
122 var m
= this.map
, e
= dnd
._empty
;
124 if(i
in e
){ continue; }
125 f
.call(o
, m
[i
], i
, this);
129 clearItems: function(){
131 // removes all data items from the map
136 getAllNodes: function(){
138 // returns a list (an array) of all valid child nodes
139 return query((this.allowNested
? "" : "> ") + ".dojoDndItem", this.parent
); // NodeList
143 // sync up the node list with the data map
145 this.getAllNodes().forEach(function(node
){
147 var item
= this.getItem(node
.id
);
153 node
.id
= dnd
.getUniqueId();
155 var type
= node
.getAttribute("dndType"),
156 data
= node
.getAttribute("dndData");
158 data
: data
|| node
.innerHTML
,
159 type
: type
? type
.split(/\s*,\s*/) : ["text"]
165 insertNodes: function(data
, before
, anchor
){
167 // inserts an array of new nodes before/after an anchor node
169 // a list of data items, which should be processed by the creator function
171 // insert before the anchor, if true, and after the anchor otherwise
173 // the anchor node to be used as a point of insertion
174 if(!this.parent
.firstChild
){
178 anchor
= this.parent
.firstChild
;
182 anchor
= anchor
.nextSibling
;
187 for(i
= 0; i
< data
.length
; ++i
){
188 t
= this._normalizedCreator(data
[i
]);
189 this.setItem(t
.node
.id
, {data
: t
.data
, type
: t
.type
});
190 anchor
.parentNode
.insertBefore(t
.node
, anchor
);
193 for(i
= 0; i
< data
.length
; ++i
){
194 t
= this._normalizedCreator(data
[i
]);
195 this.setItem(t
.node
.id
, {data
: t
.data
, type
: t
.type
});
196 this.parent
.appendChild(t
.node
);
203 // prepares this object to be garbage-collected
204 array
.forEach(this.events
, function(handle
){ handle
.remove(); });
206 this.node
= this.parent
= this.current
= null;
210 markupFactory: function(params
, node
, Ctor
){
211 params
._skipStartup
= true;
212 return new Ctor(node
, params
);
216 // collects valid child items and populate the map
218 // set up the real parent node
220 // use the standard algorithm, if not assigned
221 this.parent
= this.node
;
222 if(this.parent
.tagName
.toLowerCase() == "table"){
223 var c
= this.parent
.getElementsByTagName("tbody");
224 if(c
&& c
.length
){ this.parent
= c
[0]; }
227 this.defaultCreator
= dnd
._defaultCreator(this.parent
);
229 // process specially marked children
234 onMouseOver: function(e
){
236 // event processor for onmouseover or touch, to mark that element as the current element
239 var n
= e
.relatedTarget
;
241 if(n
== this.node
){ break; }
249 this._changeState("Container", "Over");
252 n
= this._getChildByEvent(e
);
253 if(this.current
== n
){ return; }
254 if(this.current
){ this._removeItemClass(this.current
, "Over"); }
255 if(n
){ this._addItemClass(n
, "Over"); }
258 onMouseOut: function(e
){
260 // event processor for onmouseout
263 for(var n
= e
.relatedTarget
; n
;){
264 if(n
== this.node
){ return; }
272 this._removeItemClass(this.current
, "Over");
275 this._changeState("Container", "");
278 onSelectStart: function(e
){
280 // event processor for onselectevent and ondragevent
283 if(!this.skipForm
|| !dnd
.isFormElement(e
)){
289 onOverEvent: function(){
291 // this function is called once, when mouse is over our container
293 onOutEvent: function(){
295 // this function is called once, when mouse is out of our container
297 _changeState: function(type
, newState
){
299 // changes a named state to new state value
301 // a name of the state to change
304 var prefix
= "dojoDnd" + type
;
305 var state
= type
.toLowerCase() + "State";
306 //domClass.replace(this.node, prefix + newState, prefix + this[state]);
307 domClass
.replace(this.node
, prefix
+ newState
, prefix
+ this[state
]);
308 this[state
] = newState
;
310 _addItemClass: function(node
, type
){
312 // adds a class with prefix "dojoDndItem"
316 // a variable suffix for a class name
317 domClass
.add(node
, "dojoDndItem" + type
);
319 _removeItemClass: function(node
, type
){
321 // removes a class with prefix "dojoDndItem"
325 // a variable suffix for a class name
326 domClass
.remove(node
, "dojoDndItem" + type
);
328 _getChildByEvent: function(e
){
330 // gets a child, which is under the mouse at the moment, or null
335 for(var parent
= node
.parentNode
; parent
; node
= parent
, parent
= node
.parentNode
){
336 if((parent
== this.parent
|| this.allowNested
) && domClass
.contains(node
, "dojoDndItem")){ return node
; }
341 _normalizedCreator: function(/*Container.Item*/ item
, /*String*/ hint
){
343 // adds all necessary data to the output of the user-supplied creator function
344 var t
= (this.creator
|| this.defaultCreator
).call(this, item
, hint
);
345 if(!lang
.isArray(t
.type
)){ t
.type
= ["text"]; }
346 if(!t
.node
.id
){ t
.node
.id
= dnd
.getUniqueId(); }
347 domClass
.add(t
.node
, "dojoDndItem");
352 dnd
._createNode = function(tag
){
354 // returns a function, which creates an element of given tag
355 // (SPAN by default) and sets its innerHTML to given text
357 // a tag name or empty for SPAN
358 if(!tag
){ return dnd
._createSpan
; }
359 return function(text
){ // Function
360 return domConstruct
.create(tag
, {innerHTML
: text
}); // Node
364 dnd
._createTrTd = function(text
){
366 // creates a TR/TD structure with given text as an innerHTML of TD
369 var tr
= domConstruct
.create("tr");
370 domConstruct
.create("td", {innerHTML
: text
}, tr
);
374 dnd
._createSpan = function(text
){
376 // creates a SPAN element with given text as its innerHTML
379 return domConstruct
.create("span", {innerHTML
: text
}); // Node
382 // dnd._defaultCreatorNodes: Object
383 // a dictionary that maps container tag names to child tag names
384 dnd
._defaultCreatorNodes
= {ul
: "li", ol
: "li", div
: "div", p
: "div"};
386 dnd
._defaultCreator = function(node
){
388 // takes a parent node, and returns an appropriate creator function
391 var tag
= node
.tagName
.toLowerCase();
392 var c
= tag
== "tbody" || tag
== "thead" ? dnd
._createTrTd
:
393 dnd
._createNode(dnd
._defaultCreatorNodes
[tag
]);
394 return function(item
, hint
){ // Function
395 var isObj
= item
&& lang
.isObject(item
), data
, type
, n
;
396 if(isObj
&& item
.tagName
&& item
.nodeType
&& item
.getAttribute
){
397 // process a DOM node
398 data
= item
.getAttribute("dndData") || item
.innerHTML
;
399 type
= item
.getAttribute("dndType");
400 type
= type
? type
.split(/\s*,\s*/) : ["text"];
401 n
= item
; // this node is going to be moved rather than copied
403 // process a DnD item object or a string
404 data
= (isObj
&& item
.data
) ? item
.data
: item
;
405 type
= (isObj
&& item
.type
) ? item
.type
: ["text"];
406 n
= (hint
== "avatar" ? dnd
._createSpan
: c
)(String(data
));
409 n
.id
= dnd
.getUniqueId();
411 return {node
: n
, data
: data
, type
: type
};
416 Container.__ContainerArgs = declare([], {
419 // a creator function, which takes a data item, and returns an object like that:
420 // {node: newNode, data: usedData, type: arrayOfStrings}
424 // don't start the drag operation, if clicked on form elements
427 // dropParent: Node||String
428 // node or node's id to use as the parent node for dropped items
429 // (must be underneath the 'node' parameter in the DOM)
432 // _skipStartup: Boolean
433 // skip startup(), which collects children, for deferred initialization
434 // (this is used in the markup mode)
438 Container.Item = function(){
440 // Represents (one of) the source node(s) being dragged.
441 // Contains (at least) the "type" and "data" attributes.
443 // Type(s) of this item, by default this is ["text"]
445 // Logical representation of the object being dragged.
446 // If the drag object's type is "text" then data is a String,
447 // if it's another type then data could be a different Object,
448 // perhaps a name/value hash.