3674dfba7092e97f100f3ee50812fb3ce9be0ee4
[roojs1] / Roo / bootstrap / Card.js
1 /*
2  *  - LGPL
3  *
4  *  This is BS4's Card element.. - similar to our containers probably..
5  * 
6  */
7 /**
8  * @class Roo.bootstrap.Card
9  * @extends Roo.bootstrap.Component
10  * Bootstrap Card class
11  *
12  *
13  * possible... may not be implemented..
14  * @cfg {String} header_image  src url of image.
15  * @cfg {String|Object} header
16  * @cfg {Number} header_size (0|1|2|3|4|5) H1 or H2 etc.. 0 indicates default
17  * 
18  * @cfg {String} title
19  * @cfg {String} subtitle
20  * @cfg {String} html -- html contents - or just use children..
21  * @cfg {String} footer
22  
23  * @cfg {String} weight (primary|warning|info|danger|secondary|success|light|dark)
24  * 
25  * @cfg {String} margin (0|1|2|3|4|5|auto)
26  * @cfg {String} margin_top (0|1|2|3|4|5|auto)
27  * @cfg {String} margin_bottom (0|1|2|3|4|5|auto)
28  * @cfg {String} margin_left (0|1|2|3|4|5|auto)
29  * @cfg {String} margin_right (0|1|2|3|4|5|auto)
30  * @cfg {String} margin_x (0|1|2|3|4|5|auto)
31  * @cfg {String} margin_y (0|1|2|3|4|5|auto)
32  *
33  * @cfg {String} padding (0|1|2|3|4|5)
34  * @cfg {String} padding_top (0|1|2|3|4|5)
35  * @cfg {String} padding_bottom (0|1|2|3|4|5)
36  * @cfg {String} padding_left (0|1|2|3|4|5)
37  * @cfg {String} padding_right (0|1|2|3|4|5)
38  * @cfg {String} padding_x (0|1|2|3|4|5)
39  * @cfg {String} padding_y (0|1|2|3|4|5)
40  *
41  * @cfg {String} display (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
42  * @cfg {String} display_xs (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
43  * @cfg {String} display_sm (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
44  * @cfg {String} display_lg (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
45  * @cfg {String} display_xl (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
46  
47  * @config {Boolean} dragable  if this card can be dragged.
48  * @config {String} drag_group  group for drag
49  * @config {Boolean} dropable  if this card can recieve other cards being dropped onto it..
50  * @config {String} drop_group  group for drag
51  * 
52  
53  * @constructor
54  * Create a new Container
55  * @param {Object} config The config object
56  */
57
58 Roo.bootstrap.Card = function(config){
59     Roo.bootstrap.Card.superclass.constructor.call(this, config);
60     
61     this.addEvents({
62         
63     });
64 };
65
66
67 Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
68     
69     
70     weight : '',
71     
72     margin: '', /// may be better in component?
73     margin_top: '', 
74     margin_bottom: '', 
75     margin_left: '',
76     margin_right: '',
77     margin_x: '',
78     margin_y: '',
79     
80     padding : '',
81     padding_top: '', 
82     padding_bottom: '', 
83     padding_left: '',
84     padding_right: '',
85     padding_x: '',
86     padding_y: '',
87     
88     display: '', 
89     display_xs: '', 
90     display_sm: '', 
91     display_lg: '',
92     display_xl: '',
93  
94     header_image  : '',
95     header : '',
96     header_size : 0,
97     title : '',
98     subtitle : '',
99     html : '',
100     footer: '',
101     
102     dragable : false,
103     drag_group : false,
104     dropable : false,
105     drop_group : false,
106     childContainer : false,
107
108     layoutCls : function()
109     {
110         var cls = '';
111         var t = this;
112         Roo.log(this.margin_bottom.length);
113         ['', 'top', 'bottom', 'left', 'right', 'x', 'y' ].forEach(function(v) {
114             // in theory these can do margin_top : ml-xs-3 ??? but we don't support that yet
115             
116             if (('' + t['margin' + (v.length ? '_' : '') + v]).length) {
117                 cls += ' m' +  (v.length ? v[0]  : '') + '-' +  t['margin' + (v.length ? '_' : '') + v];
118             }
119             if (('' + t['padding' + (v.length ? '_' : '') + v]).length) {
120                 cls += ' p' +  (v.length ? v[0]  : '') + '-' +  t['padding' + (v.length ? '_' : '') + v];
121             }
122         });
123         
124         ['', 'xs', 'sm', 'lg', 'xl'].forEach(function(v) {
125             if (('' + t['display' + (v.length ? '_' : '') + v]).length) {
126                 cls += ' d' +  (v.length ? '-' : '') + v + '-' + t['margin' + (v.length ? '_' : '') + v]
127             }
128         });
129         
130         // more generic support?
131         if (this.hidden) {
132             cls += ' d-none';
133         }
134         
135         return cls;
136     },
137  
138        // Roo.log("Call onRender: " + this.xtype);
139         /*  We are looking at something like this.
140 <div class="card">
141     <img src="..." class="card-img-top" alt="...">
142     <div class="card-body">
143         <h5 class="card-title">Card title</h5>
144          <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
145
146         >> this bit is really the body...
147         <div> << we will ad dthis in hopefully it will not break shit.
148         
149         ** card text does not actually have any styling...
150         
151             <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
152         
153         </div> <<
154           <a href="#" class="card-link">Card link</a>
155           
156     </div>
157     <div class="card-footer">
158         <small class="text-muted">Last updated 3 mins ago</small>
159     </div>
160 </div>
161          */
162     getAutoCreate : function(){
163         
164         var cfg = {
165             tag : 'div',
166             cls : 'card',
167             cn : [ ]
168         };
169         
170         if (this.weight.length && this.weight != 'light') {
171             cfg.cls += ' text-white';
172         } else {
173             cfg.cls += ' text-dark'; // need as it's nested..
174         }
175         if (this.weight.length) {
176             cfg.cls += ' bg-' + this.weight;
177         }
178         
179         cfg.cls += this.layoutCls(); 
180         
181         if (this.header.length) {
182             cfg.cn.push({
183                 tag : this.header_size > 0 ? 'h' + this.header_size : 'div',
184                 cls : 'card-header',
185                 html : this.header // escape?
186             });
187         } else {
188             cfg.cn.push({
189                 tag : 'div',
190                 cls : 'card-header d-none'
191             });
192         }
193         if (this.header_image.length) {
194             cfg.cn.push({
195                 tag : 'img',
196                 cls : 'card-img-top',
197                 src: this.header_image // escape?
198             });
199         } else {
200             cfg.cn.push({
201                 tag : 'div',
202                 cls : 'card-img-top d-none' 
203             });
204         }
205         
206         var body = {
207             tag : 'div',
208             cls : 'card-body',
209             cn : []
210         };
211         cfg.cn.push(body);
212         
213         if (this.title.length) {
214             body.cn.push({
215                 tag : 'div',
216                 cls : 'card-title',
217                 src: this.title // escape?
218             });
219         }
220         
221         if (this.subtitle.length) {
222             body.cn.push({
223                 tag : 'div',
224                 cls : 'card-title',
225                 src: this.subtitle // escape?
226             });
227         }
228         
229         body.cn.push({
230             tag : 'div',
231             cls : 'roo-card-body-ctr'
232         });
233         
234         if (this.html.length) {
235             body.cn.push({
236                 tag: 'div',
237                 html : this.html
238             });
239         }
240         // fixme ? handle objects?
241         if (this.footer.length) {
242             cfg.cn.push({
243                 tag : 'div',
244                 cls : 'card-footer',
245                 html: this.footer // escape?
246             });
247         }
248         // footer...
249         
250         return cfg;
251     },
252     
253     
254     getCardHeader : function()
255     {
256         var  ret = this.el.select('.card-header',true).first();
257         if (ret.hasClass('d-none')) {
258             ret.removeClass('d-none');
259         }
260         
261         return ret;
262     },
263     
264     getCardImageTop : function()
265     {
266         var  ret = this.el.select('.card-img-top',true).first();
267         if (ret.hasClass('d-none')) {
268             ret.removeClass('d-none');
269         }
270         
271         return ret;
272     },
273     
274     getChildContainer : function()
275     {
276         
277         if(!this.el){
278             return false;
279         }
280         return this.el.select('.roo-card-body-ctr',true).first();    
281     },
282     
283     initEvents: function() 
284     {
285         
286         this.bodyEl = this.getChildContainer();
287         if(this.dragable){
288             this.dragZone = new Roo.dd.DragZone(this.getEl(), {
289                     containerScroll: true,
290                     ddGroup: this.drag_group || 'default_card_drag_group'
291             });
292             this.dragZone.getDragData = this.getDragData.createDelegate(this);
293         }
294         if (this.dropable) {
295             this.dropZone = new Roo.dd.DropZone(this.getChildContainer(), {
296                     containerScroll: true,
297                     ddGroup: this.drop_group || 'default_card_drag_group'
298             });
299             this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
300             this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
301             this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
302             this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
303             this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
304         }
305         
306         
307     },
308     getDragData : function(e) {
309         var target = this.getEl();
310         if (target) {
311             //this.handleSelection(e);
312             
313             var dragData = {
314                 source: this,
315                 copy: false,
316                 nodes: this.getEl(),
317                 records: []
318             };
319             
320             
321             dragData.ddel = target.dom ;        // the div element
322             Roo.log(target.getWidth( ));
323              dragData.ddel.style.width = target.getWidth() + 'px';
324             
325             return dragData;
326         }
327         return false;
328     },
329     /**
330  *      Part of the Roo.dd.DropZone interface. If no target node is found, the
331  *      whole Element becomes the target, and this causes the drop gesture to append.
332  */
333     getTargetFromEvent : function(e)
334     {
335         var target = e.getTarget();
336         while ((target !== null) && (target.parentNode != this.bodyEl.dom)) {
337             target = target.parentNode;
338         }
339         // see if target is one of the 'cards'...
340         var ctarget = false;
341         var cards = [];
342         for (var i = 0;i< this.items.length;i++) {
343             if (this.items[i].xtype != 'Card') {
344                 continue;
345             }
346             cards.push(this.items[i].el.dom)
347             if (target == this.items[i].el.dom) {
348                 ctarget = target;
349                 break;
350             }
351         }
352         
353         if (!ctarget) {
354             ctarget = cards[cards.length-1] || this.el.dom;
355         }
356         
357         
358         Roo.log(['getTargetFromEvent', ctarget]);
359         return ctarget;
360     },
361     
362     onNodeEnter : function(n, dd, e, data){
363         return false;
364     },
365     onNodeOver : function(n, dd, e, data)
366     {
367         var pt = this.getDropPoint(e, n, dd);
368         // set the insert point style on the target node
369         //var dragElClass = this.dropNotAllowed;
370         if (pt) {
371             Roo.log(pt);
372         }
373         return false; //dragElClass;
374     },
375     onNodeOut : function(n, dd, e, data){
376         //this.removeDropIndicators(n);
377     },
378     onNodeDrop : function(n, dd, e, data)
379     {
380         return false;
381         
382         if (this.fireEvent("drop", this, n, dd, e, data) === false) {
383                 return false;
384         }
385         var pt = this.getDropPoint(e, n, dd);
386         var insertAt = (n == this.bodyEl.dom) ? this.items.length : n.nodeIndex;
387         if (pt == "below") {
388             insertAt++;
389         }
390         for (var i = 0; i < this.items.length; i++) {
391             var r = this.items[i];
392             //var dup = this.store.getById(r.id);
393             if (dup && (dd != this.dragZone)) {
394                     Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
395             } else {
396                 if (data.copy) {
397                     this.store.insert(insertAt++, r.copy());
398                 } else {
399                     data.source.isDirtyFlag = true;
400                     r.store.remove(r);
401                     this.store.insert(insertAt++, r);
402                 }
403                 this.isDirtyFlag = true;
404             }
405         }
406         this.dragZone.cachedTarget = null;
407         return true;
408     },
409     
410     /** Decide whether to drop above or below a View node. */
411     getDropPoint : function(e, n, dd)
412     {
413         if (n == this.bodyEl.dom) {
414                 return "above";
415         }
416         var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
417         var c = t + (b - t) / 2;
418         var y = Roo.lib.Event.getPageY(e);
419         if(y <= c) {
420                 return "above";
421         }else{
422                 return "below";
423         }
424     },
425
426     
427 });
428