4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
19 * Do not use directly - it does not do anything..
20 * @param {Object} config The config object
25 Roo.bootstrap.Component = function(config){
26 Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
32 allowDomMove : false, // to stop relocations in parent onRender...
40 initEvents : function() { },
47 // returns the parent component..
48 return Roo.ComponentMgr.get(this.parentId)
54 onRender : function(ct, position)
56 // Roo.log("Call onRender: " + this.xtype);
58 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
61 if (this.el.attr('xtype')) {
62 this.el.dom.removeAttribute('xtype');
71 var cfg = Roo.apply({}, this.getAutoCreate());
74 // fill in the extra attributes
75 if (this.xattr && typeof(this.xattr) =='object') {
76 for (var i in this.xattr) {
77 cfg[i] = this.xattr[i];
82 cfg.cls += ' ' + this.cls;
84 if (this.style) { // fixme needs to support more complex style data.
85 cfg.style = this.style;
87 this.el = ct.createChild(cfg, position);
88 if(this.tabIndex !== undefined){
89 this.el.dom.setAttribute('tabIndex', this.tabIndex);
96 getChildContainer : function()
101 addxtype : function (tree, cntr) {
103 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
105 // render the element if it's not BODY.
106 if (tree.xtype != 'Body') {
108 cn = Roo.factory(tree);
110 cn.parentType = this.xtype; //??
111 cn.parentId = this.id;
113 // does the container contain child eleemnts with 'xtype' attributes.
114 // that match this xtype..
115 // note - when we render we create these as well..
116 // so we should check to see if body has xtype set.
117 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
119 var echild = Roo.get(this[cntr]()).child('*[xtype]');
121 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
123 //echild.dom.removeAttribute('xtype');
125 Roo.log("missing child for " + this.xtype);
128 cn.render(this[cntr]());
129 // then add the element..
136 if (typeof (tree.menu) != 'undefined') {
137 tree.menu.parentType = cn.xtype;
138 tree.menu.triggerEl = cn.el;
139 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
143 if (!tree.items || !tree.items.length) {
147 var items = tree.items;
150 //Roo.log(items.length);
152 for(var i =0;i < items.length;i++) {
153 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
173 Roo.bootstrap.Body = function(config){
174 Roo.bootstrap.Body.superclass.constructor.call(this, config);
175 this.el = Roo.get(document.body);
178 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
183 onRender : function(ct, position){
186 //this.el.addClass([this.fieldClass, this.cls]);
204 * @class Roo.bootstrap.ButtonGroup
205 * @extends Roo.bootstrap.Component
206 * Bootstrap ButtonGroup class
207 * @cfg {String} size lg | sm | xs (default empty normal)
208 * @cfg {String} align vertical | justified (default none)
209 * @cfg {String} direction up | down (default down)
210 * @cfg {Boolean} toolbar false | true
211 * @cfg {Boolean} btn true | false
216 * @param {Object} config The config object
219 Roo.bootstrap.ButtonGroup = function(config){
220 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
223 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
231 getAutoCreate : function(){
237 cfg.html = this.html || cfg.html;
248 if (['vertical','justified'].indexOf(this.align)!==-1) {
249 cfg.cls = 'btn-group-' + this.align;
251 if (this.align == 'justified') {
252 console.log(this.items);
256 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
257 cfg.cls += ' btn-group-' + this.size;
260 if (this.direction == 'up') {
261 cfg.cls += ' dropup' ;
277 * @class Roo.bootstrap.Button
278 * @extends Roo.bootstrap.Component
279 * Bootstrap Button class
280 * @cfg {String} html The button content
281 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
282 * @cfg {String} size empty | lg | sm | xs
283 * @cfg {String} tag empty | a | input | submit
284 * @cfg {String} href empty or href
285 * @cfg {Boolean} disabled false | true
286 * @cfg {Boolean} isClose false | true
287 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
288 * @cfg {String} badge text for badge
289 * @cfg {String} theme default (or empty) | glow
290 * @cfg {Boolean} inverse false | true
291 * @cfg {Boolean} toggle false | true
292 * @cfg {String} ontext text for on toggle state
293 * @cfg {String} offtext text for off toggle state
294 * @cfg {Boolean} defaulton true | false
297 * Create a new button
298 * @param {Object} config The config object
302 Roo.bootstrap.Button = function(config){
303 Roo.bootstrap.Button.superclass.constructor.call(this, config);
308 * The raw click event for the entire grid.
309 * @param {Roo.EventObject} e
315 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
334 getAutoCreate : function(){
342 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
343 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
348 cfg.html = this.html || cfg.html;
350 if (this.toggle===true) {
353 cls: 'slider-frame roo-button',
358 'data-off-text':'OFF',
359 cls: 'slider-button',
365 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
366 cfg.cls += ' '+this.weight;
375 cfg["aria-hidden"] = true;
377 cfg.html = "×";
383 if (this.theme==='default') {
384 cfg.cls = 'btn roo-button';
386 if (this.parentType != 'Navbar') {
387 this.weight = this.weight.length ? this.weight : 'default';
389 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
391 cfg.cls += ' btn-' + this.weight;
393 } else if (this.theme==='glow') {
396 cfg.cls = 'btn-glow roo-button';
398 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
400 cfg.cls += ' ' + this.weight;
406 this.cls += ' inverse';
411 cfg.cls += ' active';
414 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
416 //gsRoo.log(this.parentType);
417 if (this.parentType === 'Navbar') {
425 href : this.href || '#'
428 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
429 cfg.cls += ' dropdown';
434 } else if (this.menu) {
436 cfg.cls += ' dropdown test';
442 cfg.disabled = 'disabled';
446 Roo.log('changing to ul' );
448 this.glyphicon = 'caret';
451 if (this.glyphicon) {
452 cfg.html = ' ' + cfg.html;
457 cls: 'glyphicon glyphicon-' + this.glyphicon
467 cfg.cls='btn roo-button';
483 if (cfg.tag !== 'a' && this.href !== '') {
484 throw "Tag must be a to set href.";
485 } else if (this.href.length > 0) {
486 cfg.href = this.href;
491 initEvents: function() {
492 // Roo.log('init events?');
493 // Roo.log(this.el.dom);
494 if (this.el.hasClass('roo-button')) {
495 this.el.on('click', this.onClick, this);
497 this.el.select('.roo-button').on('click', this.onClick, this);
503 onClick : function(e)
505 Roo.log('button on click ');
507 this.fireEvent('click', this, e);
521 * @class Roo.bootstrap.Column
522 * @extends Roo.bootstrap.Component
523 * Bootstrap Column class
524 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
525 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
526 * @cfg {Number} md colspan out of 12 for computer-sized screens
527 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
528 * @cfg {String} html content of column.
531 * Create a new Column
532 * @param {Object} config The config object
535 Roo.bootstrap.Column = function(config){
536 Roo.bootstrap.Column.superclass.constructor.call(this, config);
539 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
548 getAutoCreate : function(){
549 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
557 ['xs','sm','md','lg'].map(function(size){
558 if (settings[size]) {
559 cfg.cls += ' col-' + size + '-' + settings[size];
562 if (this.html.length) {
563 cfg.html = this.html;
582 * @class Roo.bootstrap.Container
583 * @extends Roo.bootstrap.Component
584 * Bootstrap Container class
585 * @cfg {Boolean} jumbotron is it a jumbotron element
586 * @cfg {String} html content of element
587 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
588 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
589 * @cfg {String} header content of header (for panel)
590 * @cfg {String} footer content of footer (for panel)
591 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
594 * Create a new Container
595 * @param {Object} config The config object
598 Roo.bootstrap.Container = function(config){
599 Roo.bootstrap.Container.superclass.constructor.call(this, config);
602 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
612 getChildContainer : function() {
613 if (this.panel.length) {
614 return this.el.select('.panel-body',true).first();
621 getAutoCreate : function(){
627 if (this.jumbotron) {
628 cfg.cls = 'jumbotron';
631 cfg.cls = this.cls + '';
634 if (this.sticky.length) {
635 var bd = Roo.get(document.body);
636 if (!bd.hasClass('bootstrap-sticky')) {
637 bd.addClass('bootstrap-sticky');
638 Roo.select('html',true).setStyle('height', '100%');
641 cfg.cls += 'bootstrap-sticky-' + this.sticky;
645 if (this.well.length) {
649 cfg.cls +=' well well-' +this.well;
659 if (this.panel.length) {
660 cfg.cls += 'panel panel-' + this.panel;
662 if (this.header.length) {
665 cls : 'panel-heading',
681 if (this.footer.length) {
683 cls : 'panel-footer',
691 body.html = this.html || cfg.html;
693 if (!cfg.cls.length) {
694 cfg.cls = 'container';
711 * @class Roo.bootstrap.Img
712 * @extends Roo.bootstrap.Component
713 * Bootstrap Img class
714 * @cfg {Boolean} imgResponsive false | true
715 * @cfg {String} border rounded | circle | thumbnail
716 * @cfg {String} src image source
717 * @cfg {String} alt image alternative text
721 * @param {Object} config The config object
724 Roo.bootstrap.Img = function(config){
725 Roo.bootstrap.Img.superclass.constructor.call(this, config);
728 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
734 getAutoCreate : function(){
738 cls: 'img-responsive',
742 cfg.html = this.html || cfg.html;
744 cfg.src = this.src || cfg.src;
746 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
747 cfg.cls += ' img-' + this.border;
767 * @class Roo.bootstrap.Header
768 * @extends Roo.bootstrap.Component
769 * Bootstrap Header class
770 * @cfg {String} html content of header
771 * @cfg {Number} level (1|2|3|4|5|6) default 1
774 * Create a new Header
775 * @param {Object} config The config object
779 Roo.bootstrap.Header = function(config){
780 Roo.bootstrap.Header.superclass.constructor.call(this, config);
783 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
791 getAutoCreate : function(){
794 tag: 'h' + (1 *this.level),
795 html: this.html || 'fill in html'
813 * @class Roo.bootstrap.Menu
814 * @extends Roo.bootstrap.Component
815 * Bootstrap Menu class - container for MenuItems
816 * @cfg {String} type type of menu
820 * @param {Object} config The config object
824 Roo.bootstrap.Menu = function(config){
825 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
828 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
836 getChildContainer : function() {
840 getAutoCreate : function(){
842 //if (['right'].indexOf(this.align)!==-1) {
843 // cfg.cn[1].cls += ' pull-right'
847 cls : 'dropdown-menu'
851 if (this.type==='submenu') {
852 cfg.cls='submenu active'
857 initEvents : function() {
858 // Roo.log("ADD event");
859 // Roo.log(this.triggerEl.dom);
860 this.triggerEl.on('click', this.toggle, this);
861 this.triggerEl.addClass('dropdown-toggle');
866 //Roo.log(e.getTarget());
867 // Roo.log(this.triggerEl.dom);
868 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
871 var isActive = this.triggerEl.hasClass('open');
872 // if disabled.. ingore
874 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
875 // if mobile we use a backdrop because click events don't delegate
876 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
879 //var relatedTarget = { relatedTarget: this }
880 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
882 //if (e.isDefaultPrevented()) return;
884 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
886 // .trigger('shown.bs.dropdown', relatedTarget)
888 this.triggerEl.focus();
894 clearMenus : function()
896 //$(backdrop).remove()
897 Roo.select('.dropdown-toggle',true).each(function(aa) {
898 if (!aa.hasClass('open')) {
902 aa.removeClass('open');
903 //var parent = getParent($(this))
904 //var relatedTarget = { relatedTarget: this }
906 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
907 //if (e.isDefaultPrevented()) return
908 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
926 * @class Roo.bootstrap.MenuItem
927 * @extends Roo.bootstrap.Component
928 * Bootstrap MenuItem class
929 * @cfg {String} html the menu label
930 * @cfg {String} href the link
934 * Create a new MenuItem
935 * @param {Object} config The config object
939 Roo.bootstrap.MenuItem = function(config){
940 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
943 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
948 getAutoCreate : function(){
960 cfg.cn[0].href = this.href || cfg.cn[0].href ;
961 cfg.cn[0].html = this.html || cfg.cn[0].html ;
978 * @class Roo.bootstrap.MenuSeparator
979 * @extends Roo.bootstrap.Component
980 * Bootstrap MenuSeparator class
983 * Create a new MenuItem
984 * @param {Object} config The config object
988 Roo.bootstrap.MenuSeparator = function(config){
989 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
992 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
994 getAutoCreate : function(){
1009 <div class="modal fade">
1010 <div class="modal-dialog">
1011 <div class="modal-content">
1012 <div class="modal-header">
1013 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1014 <h4 class="modal-title">Modal title</h4>
1016 <div class="modal-body">
1017 <p>One fine body…</p>
1019 <div class="modal-footer">
1020 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1021 <button type="button" class="btn btn-primary">Save changes</button>
1023 </div><!-- /.modal-content -->
1024 </div><!-- /.modal-dialog -->
1025 </div><!-- /.modal -->
1035 * @class Roo.bootstrap.Modal
1036 * @extends Roo.bootstrap.Component
1037 * Bootstrap Modal class
1038 * @cfg {String} title Title of dialog
1039 * @cfg {Array} buttons Array of buttons or standard button set..
1042 * Create a new Modal Dialog
1043 * @param {Object} config The config object
1046 Roo.bootstrap.Modal = function(config){
1047 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1052 * The raw click event for the entire grid.
1053 * @param {Roo.EventObject} e
1059 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1061 title : 'test dialog',
1065 onRender : function(ct, position)
1067 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1069 var cfg = Roo.apply({}, this.getAutoCreate());
1072 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1074 //if (!cfg.name.length) {
1078 cfg.cls += ' ' + this.cls;
1081 cfg.style = this.style;
1083 this.el = Roo.get(document.body).createChild(cfg, position);
1085 //var type = this.el.dom.type;
1087 if(this.tabIndex !== undefined){
1088 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1093 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1094 this.maskEl.enableDisplayMode("block");
1096 //this.el.addClass("x-dlg-modal");
1100 Roo.each(this.buttons, function(bb) {
1101 b = Roo.apply({}, bb);
1102 b.xns = b.xns || Roo.bootstrap;
1103 b.xtype = b.xtype || 'Button';
1104 if (typeof(b.listeners) == 'undefined') {
1105 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1108 var btn = Roo.factory(b);
1110 btn.onRender(this.el.select('.modal-footer').first());
1118 //this.el.addClass([this.fieldClass, this.cls]);
1121 getAutoCreate : function(){
1126 html : this.html || ''
1134 cls: "modal-dialog",
1137 cls : "modal-content",
1140 cls : 'modal-header',
1149 cls : 'modal-title',
1157 cls : 'modal-footer'
1173 getChildContainer : function() {
1175 return this.el.select('.modal-body',true).first();
1178 getButtonContainer : function() {
1179 return this.el.select('.modal-footer',true).first();
1182 initEvents : function()
1184 this.el.select('.modal-header .close').on('click', this.hide, this);
1187 if (!this.rendered) {
1191 this.el.addClass('on');
1192 this.el.removeClass('fade');
1193 this.el.setStyle('display', 'block');
1194 Roo.get(document.body).addClass("x-body-masked");
1195 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1197 this.el.setStyle('zIndex', '10001');
1204 this.el.removeClass('on');
1205 this.el.addClass('fade');
1206 this.el.setStyle('display', 'none');
1208 onButtonClick: function(btn,e)
1211 this.fireEvent('btnclick', btn.name, e);
1216 Roo.apply(Roo.bootstrap.Modal, {
1218 * Button config that displays a single OK button
1227 * Button config that displays Yes and No buttons
1243 * Button config that displays OK and Cancel buttons
1258 * Button config that displays Yes, No and Cancel buttons
1286 * @class Roo.bootstrap.Navbar
1287 * @extends Roo.bootstrap.Component
1288 * Bootstrap Navbar class
1289 * @cfg {Boolean} sidebar has side bar
1290 * @cfg {Boolean} bar is a bar?
1291 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1292 * @cfg {String} brand what is brand
1293 * @cfg {Boolean} inverse is inverted color
1294 * @cfg {String} type (nav | pills | tabs)
1295 * @cfg {Boolean} arrangement stacked | justified
1296 * @cfg {String} align (left | right) alignment
1300 * Create a new Navbar
1301 * @param {Object} config The config object
1305 Roo.bootstrap.Navbar = function(config){
1306 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1309 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1321 getAutoCreate : function(){
1326 if (this.sidebar === true) {
1334 if (this.bar === true) {
1342 cls: 'navbar-header',
1347 cls: 'navbar-toggle',
1348 'data-toggle': 'collapse',
1353 html: 'Toggle navigation'
1373 cls: 'collapse navbar-collapse'
1378 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1380 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1381 cfg.cls += ' navbar-' + this.position;
1382 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1385 if (this.brand !== '') {
1389 cls: 'navbar-brand',
1398 } else if (this.bar === false) {
1401 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1411 if (['tabs','pills'].indexOf(this.type)!==-1) {
1412 cfg.cn[0].cls += ' nav-' + this.type
1414 if (this.type!=='nav') {
1415 Roo.log('nav type must be nav/tabs/pills')
1417 cfg.cn[0].cls += ' navbar-nav'
1420 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1421 cfg.cn[0].cls += ' nav-' + this.arrangement;
1424 if (this.align === 'right') {
1425 cfg.cn[0].cls += ' navbar-right';
1428 cfg.cls += ' navbar-inverse';
1436 getChildContainer : function() {
1437 if (this.bar === true) {
1438 return this.el.select('.collapse',true).first();
1456 * @class Roo.bootstrap.NavGroup
1457 * @extends Roo.bootstrap.Component
1458 * Bootstrap NavGroup class
1459 * @cfg {String} align left | right
1460 * @cfg {Boolean} inverse false | true
1463 * Create a new nav group
1464 * @param {Object} config The config object
1467 Roo.bootstrap.NavGroup = function(config){
1468 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1471 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1477 getAutoCreate : function(){
1478 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1482 cls: 'nav navbar-nav'
1485 if (this.parent().sidebar === true) {
1488 cls: 'dashboard-menu'
1494 if (this.form === true) {
1500 if (this.align === 'right') {
1501 cfg.cls += ' navbar-right';
1503 cfg.cls += ' navbar-left';
1508 if (this.align === 'right') {
1509 cfg.cls += ' navbar-right';
1513 cfg.cls += ' navbar-inverse';
1532 * @class Roo.bootstrap.Navbar.Button
1533 * @extends Roo.bootstrap.Component
1534 * Bootstrap Navbar.Button class
1535 * @cfg {String} href link to
1536 * @cfg {String} html content of button
1539 * Create a new Navbar Button
1540 * @param {Object} config The config object
1544 Roo.bootstrap.Navbar.Button = function(config){
1545 Roo.bootstrap.Navbar.Button.superclass.constructor.call(this, config);
1548 Roo.extend(Roo.bootstrap.Navbar.Button, Roo.bootstrap.Component, {
1559 getAutoCreate : function(){
1569 html : this.html || ''
1593 * @class Roo.bootstrap.Navbar.Item
1594 * @extends Roo.bootstrap.Component
1595 * Bootstrap Navbar.Button class
1596 * @cfg {String} href link to
1597 * @cfg {String} html content of button
1598 * @cfg {String} badge text inside badge
1599 * @cfg {String} glyphicon name of glyphicon
1602 * Create a new Navbar Button
1603 * @param {Object} config The config object
1605 Roo.bootstrap.Navbar.Item = function(config){
1606 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1609 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1617 getAutoCreate : function(){
1619 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1621 if (this.parent().parent().sidebar === true) {
1634 cfg.cn[0].html = this.html;
1638 this.cls += ' active';
1642 cfg.cn[0].cls += ' dropdown-toggle';
1643 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1647 cfg.cn[0].tag = 'a',
1648 cfg.cn[0].href = this.href;
1651 if (this.glyphicon) {
1652 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1668 if (this.glyphicon) {
1669 if(cfg.html){cfg.html = ' ' + this.html};
1673 cls: 'glyphicon glyphicon-' + this.glyphicon
1678 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1682 cfg.cn[0].html += " <span class='caret'></span>";
1683 //}else if (!this.href) {
1684 // cfg.cn[0].tag='p';
1685 // cfg.cn[0].cls='navbar-text';
1688 cfg.cn[0].href=this.href||'#';
1689 cfg.cn[0].html=this.html;
1692 if (this.badge !== '') {
1695 cfg.cn[0].html + ' ',
1708 initEvents: function() {
1709 // Roo.log('init events?');
1710 // Roo.log(this.el.dom);
1711 this.el.select('a',true).on('click',
1713 this.fireEvent('click', this);
1730 * @class Roo.bootstrap.Row
1731 * @extends Roo.bootstrap.Component
1732 * Bootstrap Row class (contains columns...)
1736 * @param {Object} config The config object
1739 Roo.bootstrap.Row = function(config){
1740 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1743 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1745 getAutoCreate : function(){
1764 * @class Roo.bootstrap.Element
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap Element class
1767 * @cfg {String} html contents of the element
1768 * @cfg {String} tag tag of the element
1769 * @cfg {String} cls class of the element
1772 * Create a new Element
1773 * @param {Object} config The config object
1776 Roo.bootstrap.Element = function(config){
1777 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1780 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1787 getAutoCreate : function(){
1810 * @class Roo.bootstrap.Pagination
1811 * @extends Roo.bootstrap.Component
1812 * Bootstrap Pagination class
1813 * @cfg {String} size xs | sm | md | lg
1814 * @cfg {Boolean} inverse false | true
1815 * @cfg {Number} from pagination starting number
1816 * @cfg {Number} to pagination ending number
1817 * @cfg {String} align empty or left | right
1818 * @cfg {Number} active active page number
1821 * Create a new Pagination
1822 * @param {Object} config The config object
1825 Roo.bootstrap.Pagination = function(config){
1826 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1829 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1839 getAutoCreate : function(){
1846 cfg.cls += ' inverse';
1864 var from=this.from>0?this.from:1;
1865 var to=this.to-from<=10?this.to:from+10;
1866 var active=this.active>=from&&this.active<=to?this.active:null;
1867 for (var i=from;i<=to;i++) {
1871 cls: active===i?'active':'',
1912 * @class Roo.bootstrap.Slider
1913 * @extends Roo.bootstrap.Component
1914 * Bootstrap Slider class
1917 * Create a new Slider
1918 * @param {Object} config The config object
1921 Roo.bootstrap.Slider = function(config){
1922 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1925 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
1927 getAutoCreate : function(){
1931 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1935 cls: 'ui-slider-handle ui-state-default ui-corner-all'
1953 * @class Roo.bootstrap.Table
1954 * @extends Roo.bootstrap.Component
1955 * Bootstrap Table class
1958 * Create a new Table
1959 * @param {Object} config The config object
1962 Roo.bootstrap.Table = function(config){
1963 Roo.bootstrap.Table.superclass.constructor.call(this, config);
1966 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
1971 getAutoCreate : function(){
1972 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2004 * @class Roo.bootstrap.TableCell
2005 * @extends Roo.bootstrap.Component
2006 * Bootstrap TableCell class
2009 * Create a new TableCell
2010 * @param {Object} config The config object
2013 Roo.bootstrap.TableCell = function(config){
2014 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2017 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2019 getAutoCreate : function(){
2020 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2047 * @class Roo.bootstrap.TableRow
2048 * @extends Roo.bootstrap.Component
2049 * Bootstrap TableRow class
2052 * Create a new TableRow
2053 * @param {Object} config The config object
2056 Roo.bootstrap.TableRow = function(config){
2057 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2060 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2062 getAutoCreate : function(){
2063 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2078 * Ext JS Library 1.1.1
2079 * Copyright(c) 2006-2007, Ext JS, LLC.
2081 * Originally Released Under LGPL - original licence link has changed is not relivant.
2084 * <script type="text/javascript">
2087 // as we use this in bootstrap.
2088 Roo.namespace('Roo.form');
2090 * @class Roo.form.Action
2091 * Internal Class used to handle form actions
2093 * @param {Roo.form.BasicForm} el The form element or its id
2094 * @param {Object} config Configuration options
2099 // define the action interface
2100 Roo.form.Action = function(form, options){
2102 this.options = options || {};
2105 * Client Validation Failed
2108 Roo.form.Action.CLIENT_INVALID = 'client';
2110 * Server Validation Failed
2113 Roo.form.Action.SERVER_INVALID = 'server';
2115 * Connect to Server Failed
2118 Roo.form.Action.CONNECT_FAILURE = 'connect';
2120 * Reading Data from Server Failed
2123 Roo.form.Action.LOAD_FAILURE = 'load';
2125 Roo.form.Action.prototype = {
2127 failureType : undefined,
2128 response : undefined,
2132 run : function(options){
2137 success : function(response){
2142 handleResponse : function(response){
2146 // default connection failure
2147 failure : function(response){
2149 this.response = response;
2150 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2151 this.form.afterAction(this, false);
2154 processResponse : function(response){
2155 this.response = response;
2156 if(!response.responseText){
2159 this.result = this.handleResponse(response);
2163 // utility functions used internally
2164 getUrl : function(appendParams){
2165 var url = this.options.url || this.form.url || this.form.el.dom.action;
2167 var p = this.getParams();
2169 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2175 getMethod : function(){
2176 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2179 getParams : function(){
2180 var bp = this.form.baseParams;
2181 var p = this.options.params;
2183 if(typeof p == "object"){
2184 p = Roo.urlEncode(Roo.applyIf(p, bp));
2185 }else if(typeof p == 'string' && bp){
2186 p += '&' + Roo.urlEncode(bp);
2189 p = Roo.urlEncode(bp);
2194 createCallback : function(){
2196 success: this.success,
2197 failure: this.failure,
2199 timeout: (this.form.timeout*1000),
2200 upload: this.form.fileUpload ? this.success : undefined
2205 Roo.form.Action.Submit = function(form, options){
2206 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2209 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2212 haveProgress : false,
2213 uploadComplete : false,
2215 // uploadProgress indicator.
2216 uploadProgress : function()
2218 if (!this.form.progressUrl) {
2222 if (!this.haveProgress) {
2223 Roo.MessageBox.progress("Uploading", "Uploading");
2225 if (this.uploadComplete) {
2226 Roo.MessageBox.hide();
2230 this.haveProgress = true;
2232 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2234 var c = new Roo.data.Connection();
2236 url : this.form.progressUrl,
2241 success : function(req){
2242 //console.log(data);
2246 rdata = Roo.decode(req.responseText)
2248 Roo.log("Invalid data from server..");
2252 if (!rdata || !rdata.success) {
2254 Roo.MessageBox.alert(Roo.encode(rdata));
2257 var data = rdata.data;
2259 if (this.uploadComplete) {
2260 Roo.MessageBox.hide();
2265 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2266 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2269 this.uploadProgress.defer(2000,this);
2272 failure: function(data) {
2273 Roo.log('progress url failed ');
2284 // run get Values on the form, so it syncs any secondary forms.
2285 this.form.getValues();
2287 var o = this.options;
2288 var method = this.getMethod();
2289 var isPost = method == 'POST';
2290 if(o.clientValidation === false || this.form.isValid()){
2292 if (this.form.progressUrl) {
2293 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2294 (new Date() * 1) + '' + Math.random());
2299 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2300 form:this.form.el.dom,
2301 url:this.getUrl(!isPost),
2303 params:isPost ? this.getParams() : null,
2304 isUpload: this.form.fileUpload
2307 this.uploadProgress();
2309 }else if (o.clientValidation !== false){ // client validation failed
2310 this.failureType = Roo.form.Action.CLIENT_INVALID;
2311 this.form.afterAction(this, false);
2315 success : function(response)
2317 this.uploadComplete= true;
2318 if (this.haveProgress) {
2319 Roo.MessageBox.hide();
2323 var result = this.processResponse(response);
2324 if(result === true || result.success){
2325 this.form.afterAction(this, true);
2329 this.form.markInvalid(result.errors);
2330 this.failureType = Roo.form.Action.SERVER_INVALID;
2332 this.form.afterAction(this, false);
2334 failure : function(response)
2336 this.uploadComplete= true;
2337 if (this.haveProgress) {
2338 Roo.MessageBox.hide();
2341 this.response = response;
2342 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2343 this.form.afterAction(this, false);
2346 handleResponse : function(response){
2347 if(this.form.errorReader){
2348 var rs = this.form.errorReader.read(response);
2351 for(var i = 0, len = rs.records.length; i < len; i++) {
2352 var r = rs.records[i];
2356 if(errors.length < 1){
2360 success : rs.success,
2366 ret = Roo.decode(response.responseText);
2370 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2380 Roo.form.Action.Load = function(form, options){
2381 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2382 this.reader = this.form.reader;
2385 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2390 Roo.Ajax.request(Roo.apply(
2391 this.createCallback(), {
2392 method:this.getMethod(),
2393 url:this.getUrl(false),
2394 params:this.getParams()
2398 success : function(response){
2400 var result = this.processResponse(response);
2401 if(result === true || !result.success || !result.data){
2402 this.failureType = Roo.form.Action.LOAD_FAILURE;
2403 this.form.afterAction(this, false);
2406 this.form.clearInvalid();
2407 this.form.setValues(result.data);
2408 this.form.afterAction(this, true);
2411 handleResponse : function(response){
2412 if(this.form.reader){
2413 var rs = this.form.reader.read(response);
2414 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2416 success : rs.success,
2420 return Roo.decode(response.responseText);
2424 Roo.form.Action.ACTION_TYPES = {
2425 'load' : Roo.form.Action.Load,
2426 'submit' : Roo.form.Action.Submit
2435 * @class Roo.bootstrap.Form
2436 * @extends Roo.bootstrap.Component
2437 * Bootstrap Form class
2438 * @cfg {String} method GET | POST (default POST)
2439 * @cfg {String} labelAlign top | left (default top)
2440 * @cfg {String} align left | right - for navbars
2445 * @param {Object} config The config object
2449 Roo.bootstrap.Form = function(config){
2450 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2453 * @event clientvalidation
2454 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2455 * @param {Form} this
2456 * @param {Boolean} valid true if the form has passed client-side validation
2458 clientvalidation: true,
2460 * @event beforeaction
2461 * Fires before any action is performed. Return false to cancel the action.
2462 * @param {Form} this
2463 * @param {Action} action The action to be performed
2467 * @event actionfailed
2468 * Fires when an action fails.
2469 * @param {Form} this
2470 * @param {Action} action The action that failed
2472 actionfailed : true,
2474 * @event actioncomplete
2475 * Fires when an action is completed.
2476 * @param {Form} this
2477 * @param {Action} action The action that completed
2479 actioncomplete : true
2484 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2487 * @cfg {String} method
2488 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2493 * The URL to use for form actions if one isn't supplied in the action options.
2496 * @cfg {Boolean} fileUpload
2497 * Set to true if this form is a file upload.
2501 * @cfg {Object} baseParams
2502 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2506 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2510 * @cfg {Sting} align (left|right) for navbar forms
2515 activeAction : null,
2518 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2519 * element by passing it or its id or mask the form itself by passing in true.
2522 waitMsgTarget : false,
2527 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2528 * element by passing it or its id or mask the form itself by passing in true.
2532 getAutoCreate : function(){
2536 method : this.method || 'POST',
2537 id : this.id || Roo.id(),
2540 if (this.parent().xtype.match(/^Nav/)) {
2541 cfg.cls = 'navbar-form navbar-' + this.align;
2545 if (this.labelAlign == 'left' ) {
2546 cfg.cls += ' form-horizontal';
2552 initEvents : function()
2554 this.el.on('submit', this.onSubmit, this);
2559 onSubmit : function(e){
2564 * Returns true if client-side validation on the form is successful.
2567 isValid : function(){
2568 var items = this.getItems();
2570 items.each(function(f){
2579 * Returns true if any fields in this form have changed since their original load.
2582 isDirty : function(){
2584 var items = this.getItems();
2585 items.each(function(f){
2595 * Performs a predefined action (submit or load) or custom actions you define on this form.
2596 * @param {String} actionName The name of the action type
2597 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2598 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2599 * accept other config options):
2601 Property Type Description
2602 ---------------- --------------- ----------------------------------------------------------------------------------
2603 url String The url for the action (defaults to the form's url)
2604 method String The form method to use (defaults to the form's method, or POST if not defined)
2605 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2606 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2607 validate the form on the client (defaults to false)
2609 * @return {BasicForm} this
2611 doAction : function(action, options){
2612 if(typeof action == 'string'){
2613 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2615 if(this.fireEvent('beforeaction', this, action) !== false){
2616 this.beforeAction(action);
2617 action.run.defer(100, action);
2623 beforeAction : function(action){
2624 var o = action.options;
2626 // not really supported yet.. ??
2628 //if(this.waitMsgTarget === true){
2629 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2630 //}else if(this.waitMsgTarget){
2631 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2632 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2634 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2640 afterAction : function(action, success){
2641 this.activeAction = null;
2642 var o = action.options;
2644 //if(this.waitMsgTarget === true){
2646 //}else if(this.waitMsgTarget){
2647 // this.waitMsgTarget.unmask();
2649 // Roo.MessageBox.updateProgress(1);
2650 // Roo.MessageBox.hide();
2657 Roo.callback(o.success, o.scope, [this, action]);
2658 this.fireEvent('actioncomplete', this, action);
2662 // failure condition..
2663 // we have a scenario where updates need confirming.
2664 // eg. if a locking scenario exists..
2665 // we look for { errors : { needs_confirm : true }} in the response.
2667 (typeof(action.result) != 'undefined') &&
2668 (typeof(action.result.errors) != 'undefined') &&
2669 (typeof(action.result.errors.needs_confirm) != 'undefined')
2672 Roo.log("not supported yet");
2675 Roo.MessageBox.confirm(
2676 "Change requires confirmation",
2677 action.result.errorMsg,
2682 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2692 Roo.callback(o.failure, o.scope, [this, action]);
2693 // show an error message if no failed handler is set..
2694 if (!this.hasListener('actionfailed')) {
2695 Roo.log("need to add dialog support");
2697 Roo.MessageBox.alert("Error",
2698 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2699 action.result.errorMsg :
2700 "Saving Failed, please check your entries or try again"
2705 this.fireEvent('actionfailed', this, action);
2710 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2711 * @param {String} id The value to search for
2714 findField : function(id){
2715 var items = this.getItems();
2716 var field = items.get(id);
2718 items.each(function(f){
2719 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2726 return field || null;
2729 * Mark fields in this form invalid in bulk.
2730 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2731 * @return {BasicForm} this
2733 markInvalid : function(errors){
2734 if(errors instanceof Array){
2735 for(var i = 0, len = errors.length; i < len; i++){
2736 var fieldError = errors[i];
2737 var f = this.findField(fieldError.id);
2739 f.markInvalid(fieldError.msg);
2745 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2746 field.markInvalid(errors[id]);
2750 //Roo.each(this.childForms || [], function (f) {
2751 // f.markInvalid(errors);
2758 * Set values for fields in this form in bulk.
2759 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2760 * @return {BasicForm} this
2762 setValues : function(values){
2763 if(values instanceof Array){ // array of objects
2764 for(var i = 0, len = values.length; i < len; i++){
2766 var f = this.findField(v.id);
2768 f.setValue(v.value);
2769 if(this.trackResetOnLoad){
2770 f.originalValue = f.getValue();
2774 }else{ // object hash
2777 if(typeof values[id] != 'function' && (field = this.findField(id))){
2779 if (field.setFromData &&
2781 field.displayField &&
2782 // combos' with local stores can
2783 // be queried via setValue()
2784 // to set their value..
2785 (field.store && !field.store.isLocal)
2789 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2790 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2791 field.setFromData(sd);
2794 field.setValue(values[id]);
2798 if(this.trackResetOnLoad){
2799 field.originalValue = field.getValue();
2805 //Roo.each(this.childForms || [], function (f) {
2806 // f.setValues(values);
2813 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2814 * they are returned as an array.
2815 * @param {Boolean} asString
2818 getValues : function(asString){
2819 //if (this.childForms) {
2820 // copy values from the child forms
2821 // Roo.each(this.childForms, function (f) {
2822 // this.setValues(f.getValues());
2828 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2829 if(asString === true){
2832 return Roo.urlDecode(fs);
2836 * Returns the fields in this form as an object with key/value pairs.
2837 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2840 getFieldValues : function(with_hidden)
2842 var items = this.getItems();
2844 items.each(function(f){
2848 var v = f.getValue();
2849 if (f.inputType =='radio') {
2850 if (typeof(ret[f.getName()]) == 'undefined') {
2851 ret[f.getName()] = ''; // empty..
2854 if (!f.el.dom.checked) {
2862 // not sure if this supported any more..
2863 if ((typeof(v) == 'object') && f.getRawValue) {
2864 v = f.getRawValue() ; // dates..
2866 // combo boxes where name != hiddenName...
2867 if (f.name != f.getName()) {
2868 ret[f.name] = f.getRawValue();
2870 ret[f.getName()] = v;
2877 * Clears all invalid messages in this form.
2878 * @return {BasicForm} this
2880 clearInvalid : function(){
2881 var items = this.getItems();
2883 items.each(function(f){
2894 * @return {BasicForm} this
2897 var items = this.getItems();
2898 items.each(function(f){
2902 Roo.each(this.childForms || [], function (f) {
2909 getItems : function()
2911 var r=new Roo.util.MixedCollection(false, function(o){
2912 return o.id || (o.id = Roo.id());
2914 var iter = function(el) {
2921 Roo.each(el.items,function(e) {
2940 * Ext JS Library 1.1.1
2941 * Copyright(c) 2006-2007, Ext JS, LLC.
2943 * Originally Released Under LGPL - original licence link has changed is not relivant.
2946 * <script type="text/javascript">
2949 * @class Roo.form.VTypes
2950 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2953 Roo.form.VTypes = function(){
2954 // closure these in so they are only created once.
2955 var alpha = /^[a-zA-Z_]+$/;
2956 var alphanum = /^[a-zA-Z0-9_]+$/;
2957 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2958 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2960 // All these messages and functions are configurable
2963 * The function used to validate email addresses
2964 * @param {String} value The email address
2966 'email' : function(v){
2967 return email.test(v);
2970 * The error text to display when the email validation function returns false
2973 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2975 * The keystroke filter mask to be applied on email input
2978 'emailMask' : /[a-z0-9_\.\-@]/i,
2981 * The function used to validate URLs
2982 * @param {String} value The URL
2984 'url' : function(v){
2988 * The error text to display when the url validation function returns false
2991 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
2994 * The function used to validate alpha values
2995 * @param {String} value The value
2997 'alpha' : function(v){
2998 return alpha.test(v);
3001 * The error text to display when the alpha validation function returns false
3004 'alphaText' : 'This field should only contain letters and _',
3006 * The keystroke filter mask to be applied on alpha input
3009 'alphaMask' : /[a-z_]/i,
3012 * The function used to validate alphanumeric values
3013 * @param {String} value The value
3015 'alphanum' : function(v){
3016 return alphanum.test(v);
3019 * The error text to display when the alphanumeric validation function returns false
3022 'alphanumText' : 'This field should only contain letters, numbers and _',
3024 * The keystroke filter mask to be applied on alphanumeric input
3027 'alphanumMask' : /[a-z0-9_]/i
3037 * @class Roo.bootstrap.Input
3038 * @extends Roo.bootstrap.Component
3039 * Bootstrap Input class
3040 * @cfg {Boolean} disabled is it disabled
3041 * @cfg {String} fieldLabel - the label associated
3042 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3043 * @cfg {String} name name of the input
3044 * @cfg {string} fieldLabel - the label associated
3045 * @cfg {string} inputType - input / file submit ...
3046 * @cfg {string} placeholder - placeholder to put in text.
3047 * @cfg {string} before - input group add on before
3048 * @cfg {string} after - input group add on after
3049 * @cfg {string} size - (lg|sm) or leave empty..
3050 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3051 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3052 * @cfg {Number} md colspan out of 12 for computer-sized screens
3053 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3057 * Create a new Input
3058 * @param {Object} config The config object
3061 Roo.bootstrap.Input = function(config){
3062 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3067 * Fires when this field receives input focus.
3068 * @param {Roo.form.Field} this
3073 * Fires when this field loses input focus.
3074 * @param {Roo.form.Field} this
3079 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3080 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3081 * @param {Roo.form.Field} this
3082 * @param {Roo.EventObject} e The event object
3087 * Fires just before the field blurs if the field value has changed.
3088 * @param {Roo.form.Field} this
3089 * @param {Mixed} newValue The new value
3090 * @param {Mixed} oldValue The original value
3095 * Fires after the field has been marked as invalid.
3096 * @param {Roo.form.Field} this
3097 * @param {String} msg The validation message
3102 * Fires after the field has been validated with no errors.
3103 * @param {Roo.form.Field} this
3108 * Fires after the key up
3109 * @param {Roo.form.Field} this
3110 * @param {Roo.EventObject} e The event Object
3116 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3118 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3119 automatic validation (defaults to "keyup").
3121 validationEvent : "keyup",
3123 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3125 validateOnBlur : true,
3127 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3129 validationDelay : 250,
3131 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3133 focusClass : "x-form-focus", // not needed???
3137 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3139 invalidClass : "has-error",
3142 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3144 selectOnFocus : false,
3147 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3151 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3156 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3158 disableKeyFilter : false,
3161 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3165 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3169 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3171 blankText : "This field is required",
3174 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3178 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3180 maxLength : Number.MAX_VALUE,
3182 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3184 minLengthText : "The minimum length for this field is {0}",
3186 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3188 maxLengthText : "The maximum length for this field is {0}",
3192 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3193 * If available, this function will be called only after the basic validators all return true, and will be passed the
3194 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3198 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3199 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3200 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3204 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3223 getAutoCreate : function(){
3225 var parent = this.parent();
3227 var align = parent.labelAlign;
3232 cls: 'form-group' //input-group
3238 type : this.inputType,
3239 cls : 'form-control',
3240 placeholder : this.placeholder || ''
3244 input.name = this.name;
3247 input.cls += ' input-' + this.size;
3250 ['xs','sm','md','lg'].map(function(size){
3251 if (settings[size]) {
3252 cfg.cls += ' col-' + size + '-' + settings[size];
3256 var inputblock = input;
3258 if (this.before || this.after) {
3261 cls : 'input-group',
3265 inputblock.cn.push({
3267 cls : 'input-group-addon',
3271 inputblock.cn.push(input);
3273 inputblock.cn.push({
3275 cls : 'input-group-addon',
3283 Roo.log(this.fieldLabel.length);
3285 if (align ==='left' && this.fieldLabel.length) {
3286 Roo.log("left and has label");
3292 cls : 'col-sm-2 control-label',
3293 html : this.fieldLabel
3304 } else if ( this.fieldLabel.length) {
3310 //cls : 'input-group-addon',
3311 html : this.fieldLabel
3321 Roo.log(" no label && no align");
3334 if (this.disabled) {
3335 input.disabled=true;
3341 * return the real input element.
3343 inputEl: function ()
3345 return this.el.select('input.form-control',true).first();
3347 setDisabled : function(v)
3349 var i = this.inputEl().dom;
3351 i.removeAttribute('disabled');
3355 i.setAttribute('disabled','true');
3357 initEvents : function()
3360 this.inputEl().on("keydown" , this.fireKey, this);
3361 this.inputEl().on("focus", this.onFocus, this);
3362 this.inputEl().on("blur", this.onBlur, this);
3363 this.inputEl().relayEvent('keyup', this);
3365 // reference to original value for reset
3366 this.originalValue = this.getValue();
3367 //Roo.form.TextField.superclass.initEvents.call(this);
3368 if(this.validationEvent == 'keyup'){
3369 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3370 this.inputEl().on('keyup', this.filterValidation, this);
3372 else if(this.validationEvent !== false){
3373 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3376 if(this.selectOnFocus){
3377 this.on("focus", this.preFocus, this);
3380 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3381 this.inputEl().on("keypress", this.filterKeys, this);
3384 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3385 this.el.on("click", this.autoSize, this);
3388 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3389 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3393 filterValidation : function(e){
3394 if(!e.isNavKeyPress()){
3395 this.validationTask.delay(this.validationDelay);
3399 * Validates the field value
3400 * @return {Boolean} True if the value is valid, else false
3402 validate : function(){
3403 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3404 if(this.disabled || this.validateValue(this.getRawValue())){
3405 this.clearInvalid();
3413 * Validates a value according to the field's validation rules and marks the field as invalid
3414 * if the validation fails
3415 * @param {Mixed} value The value to validate
3416 * @return {Boolean} True if the value is valid, else false
3418 validateValue : function(value){
3419 if(value.length < 1) { // if it's blank
3420 if(this.allowBlank){
3421 this.clearInvalid();
3424 this.markInvalid(this.blankText);
3428 if(value.length < this.minLength){
3429 this.markInvalid(String.format(this.minLengthText, this.minLength));
3432 if(value.length > this.maxLength){
3433 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3437 var vt = Roo.form.VTypes;
3438 if(!vt[this.vtype](value, this)){
3439 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3443 if(typeof this.validator == "function"){
3444 var msg = this.validator(value);
3446 this.markInvalid(msg);
3450 if(this.regex && !this.regex.test(value)){
3451 this.markInvalid(this.regexText);
3460 fireKey : function(e){
3461 //Roo.log('field ' + e.getKey());
3462 if(e.isNavKeyPress()){
3463 this.fireEvent("specialkey", this, e);
3466 focus : function (selectText){
3468 this.inputEl().focus();
3469 if(selectText === true){
3470 this.inputEl().dom.select();
3476 onFocus : function(){
3477 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3478 // this.el.addClass(this.focusClass);
3481 this.hasFocus = true;
3482 this.startValue = this.getValue();
3483 this.fireEvent("focus", this);
3487 beforeBlur : Roo.emptyFn,
3491 onBlur : function(){
3493 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3494 //this.el.removeClass(this.focusClass);
3496 this.hasFocus = false;
3497 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3500 var v = this.getValue();
3501 if(String(v) !== String(this.startValue)){
3502 this.fireEvent('change', this, v, this.startValue);
3504 this.fireEvent("blur", this);
3508 * Resets the current field value to the originally loaded value and clears any validation messages
3511 this.setValue(this.originalValue);
3512 this.clearInvalid();
3515 * Returns the name of the field
3516 * @return {Mixed} name The name field
3518 getName: function(){
3522 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3523 * @return {Mixed} value The field value
3525 getValue : function(){
3526 var v = this.inputEl().getValue();
3530 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3531 * @return {Mixed} value The field value
3533 getRawValue : function(){
3534 var v = this.inputEl().getValue();
3539 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3540 * @param {Mixed} value The value to set
3542 setValue : function(v){
3545 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3551 processValue : function(value){
3552 if(this.stripCharsRe){
3553 var newValue = value.replace(this.stripCharsRe, '');
3554 if(newValue !== value){
3555 this.setRawValue(newValue);
3562 preFocus : function(){
3564 if(this.selectOnFocus){
3565 this.inputEl().dom.select();
3568 filterKeys : function(e){
3570 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3573 var c = e.getCharCode(), cc = String.fromCharCode(c);
3574 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3577 if(!this.maskRe.test(cc)){
3582 * Clear any invalid styles/messages for this field
3584 clearInvalid : function(){
3586 if(!this.el || this.preventMark){ // not rendered
3589 this.el.removeClass(this.invalidClass);
3591 switch(this.msgTarget){
3593 this.el.dom.qtip = '';
3596 this.el.dom.title = '';
3600 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3605 this.errorIcon.dom.qtip = '';
3606 this.errorIcon.hide();
3607 this.un('resize', this.alignErrorIcon, this);
3611 var t = Roo.getDom(this.msgTarget);
3613 t.style.display = 'none';
3617 this.fireEvent('valid', this);
3620 * Mark this field as invalid
3621 * @param {String} msg The validation message
3623 markInvalid : function(msg){
3624 if(!this.el || this.preventMark){ // not rendered
3627 this.el.addClass(this.invalidClass);
3629 msg = msg || this.invalidText;
3630 switch(this.msgTarget){
3632 this.el.dom.qtip = msg;
3633 this.el.dom.qclass = 'x-form-invalid-tip';
3634 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3635 Roo.QuickTips.enable();
3639 this.el.dom.title = msg;
3643 var elp = this.el.findParent('.x-form-element', 5, true);
3644 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3645 this.errorEl.setWidth(elp.getWidth(true)-20);
3647 this.errorEl.update(msg);
3648 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3651 if(!this.errorIcon){
3652 var elp = this.el.findParent('.x-form-element', 5, true);
3653 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3655 this.alignErrorIcon();
3656 this.errorIcon.dom.qtip = msg;
3657 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3658 this.errorIcon.show();
3659 this.on('resize', this.alignErrorIcon, this);
3662 var t = Roo.getDom(this.msgTarget);
3664 t.style.display = this.msgDisplay;
3668 this.fireEvent('invalid', this, msg);
3671 SafariOnKeyDown : function(event)
3673 // this is a workaround for a password hang bug on chrome/ webkit.
3675 var isSelectAll = false;
3677 if(this.inputEl().dom.selectionEnd > 0){
3678 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3680 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3681 event.preventDefault();
3686 if(isSelectAll){ // backspace and delete key
3688 event.preventDefault();
3689 // this is very hacky as keydown always get's upper case.
3691 var cc = String.fromCharCode(event.getCharCode());
3692 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3704 * trigger field - base class for combo..
3709 * @class Roo.bootstrap.TriggerField
3710 * @extends Roo.bootstrap.Input
3711 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3712 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3713 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3714 * for which you can provide a custom implementation. For example:
3716 var trigger = new Roo.bootstrap.TriggerField();
3717 trigger.onTriggerClick = myTriggerFn;
3718 trigger.applyTo('my-field');
3721 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3722 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3723 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3724 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3726 * Create a new TriggerField.
3727 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3728 * to the base TextField)
3730 Roo.bootstrap.TriggerField = function(config){
3731 this.mimicing = false;
3732 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3735 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3737 * @cfg {String} triggerClass A CSS class to apply to the trigger
3740 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3744 /** @cfg {Boolean} grow @hide */
3745 /** @cfg {Number} growMin @hide */
3746 /** @cfg {Number} growMax @hide */
3752 autoSize: Roo.emptyFn,
3759 actionMode : 'wrap',
3763 getAutoCreate : function(){
3765 var parent = this.parent();
3767 var align = parent.labelAlign;
3772 cls: 'form-group' //input-group
3779 type : this.inputType,
3780 cls : 'form-control',
3781 autocomplete: 'off',
3782 placeholder : this.placeholder || ''
3786 input.name = this.name;
3789 input.cls += ' input-' + this.size;
3792 cls: 'combobox-container input-group',
3797 cls: 'form-hidden-field'
3802 cls : 'typeahead typeahead-long dropdown-menu',
3803 style : 'display:none'
3807 cls : 'input-group-addon btn dropdown-toggle',
3815 cls: 'combobox-clear',
3832 if (align ==='left' && this.fieldLabel.length) {
3836 Roo.log("left and has label");
3842 cls : 'col-sm-2 control-label',
3843 html : this.fieldLabel
3854 } else if ( this.fieldLabel.length) {
3860 //cls : 'input-group-addon',
3861 html : this.fieldLabel
3871 Roo.log(" no label && no align");
3878 ['xs','sm','md','lg'].map(function(size){
3879 if (settings[size]) {
3880 cfg.cls += ' col-' + size + '-' + settings[size];
3886 if (this.disabled) {
3887 input.disabled=true;
3896 onResize : function(w, h){
3897 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3898 if(typeof w == 'number'){
3899 var x = w - this.trigger.getWidth();
3900 this.inputEl().setWidth(this.adjustWidth('input', x));
3901 this.trigger.setStyle('left', x+'px');
3906 adjustSize : Roo.BoxComponent.prototype.adjustSize,
3909 getResizeEl : function(){
3910 return this.inputEl();
3914 getPositionEl : function(){
3915 return this.inputEl();
3919 alignErrorIcon : function(){
3920 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3924 initEvents : function(){
3926 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3928 this.trigger = this.el.select('span.dropdown-toggle',true).first();
3929 if(this.hideTrigger){
3930 this.trigger.setDisplayed(false);
3932 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3933 //this.trigger.addClassOnOver('x-form-trigger-over');
3934 //this.trigger.addClassOnClick('x-form-trigger-click');
3937 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3942 initTrigger : function(){
3947 onDestroy : function(){
3949 this.trigger.removeAllListeners();
3950 // this.trigger.remove();
3953 // this.wrap.remove();
3955 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
3959 onFocus : function(){
3960 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
3963 this.wrap.addClass('x-trigger-wrap-focus');
3964 this.mimicing = true;
3965 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
3966 if(this.monitorTab){
3967 this.el.on("keydown", this.checkTab, this);
3974 checkTab : function(e){
3975 if(e.getKey() == e.TAB){
3981 onBlur : function(){
3986 mimicBlur : function(e, t){
3988 if(!this.wrap.contains(t) && this.validateBlur()){
3995 triggerBlur : function(){
3996 this.mimicing = false;
3997 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
3998 if(this.monitorTab){
3999 this.el.un("keydown", this.checkTab, this);
4001 //this.wrap.removeClass('x-trigger-wrap-focus');
4002 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4006 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4007 validateBlur : function(e, t){
4012 onDisable : function(){
4013 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4015 // this.wrap.addClass('x-item-disabled');
4020 onEnable : function(){
4021 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4023 // this.el.removeClass('x-item-disabled');
4028 onShow : function(){
4029 var ae = this.getActionEl();
4032 ae.dom.style.display = '';
4033 ae.dom.style.visibility = 'visible';
4039 onHide : function(){
4040 var ae = this.getActionEl();
4041 ae.dom.style.display = 'none';
4045 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4046 * by an implementing function.
4048 * @param {EventObject} e
4050 onTriggerClick : Roo.emptyFn
4054 * Ext JS Library 1.1.1
4055 * Copyright(c) 2006-2007, Ext JS, LLC.
4057 * Originally Released Under LGPL - original licence link has changed is not relivant.
4060 * <script type="text/javascript">
4065 * @extends Roo.util.Observable
4066 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
4067 * This class also supports single and multi selection modes. <br>
4068 * Create a data model bound view:
4070 var store = new Roo.data.Store(...);
4072 var view = new Roo.View({
4074 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
4077 selectedClass: "ydataview-selected",
4081 // listen for node click?
4082 view.on("click", function(vw, index, node, e){
4083 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
4087 dataModel.load("foobar.xml");
4089 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
4091 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
4092 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
4094 * Note: old style constructor is still suported (container, template, config)
4098 * @param {Object} config The config object
4101 Roo.View = function(config, depreciated_tpl, depreciated_config){
4103 if (typeof(depreciated_tpl) == 'undefined') {
4104 // new way.. - universal constructor.
4105 Roo.apply(this, config);
4106 this.el = Roo.get(this.el);
4109 this.el = Roo.get(config);
4110 this.tpl = depreciated_tpl;
4111 Roo.apply(this, depreciated_config);
4113 this.wrapEl = this.el.wrap().wrap();
4114 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
4117 if(typeof(this.tpl) == "string"){
4118 this.tpl = new Roo.Template(this.tpl);
4120 // support xtype ctors..
4121 this.tpl = new Roo.factory(this.tpl, Roo);
4133 * @event beforeclick
4134 * Fires before a click is processed. Returns false to cancel the default action.
4135 * @param {Roo.View} this
4136 * @param {Number} index The index of the target node
4137 * @param {HTMLElement} node The target node
4138 * @param {Roo.EventObject} e The raw event object
4140 "beforeclick" : true,
4143 * Fires when a template node is clicked.
4144 * @param {Roo.View} this
4145 * @param {Number} index The index of the target node
4146 * @param {HTMLElement} node The target node
4147 * @param {Roo.EventObject} e The raw event object
4152 * Fires when a template node is double clicked.
4153 * @param {Roo.View} this
4154 * @param {Number} index The index of the target node
4155 * @param {HTMLElement} node The target node
4156 * @param {Roo.EventObject} e The raw event object
4160 * @event contextmenu
4161 * Fires when a template node is right clicked.
4162 * @param {Roo.View} this
4163 * @param {Number} index The index of the target node
4164 * @param {HTMLElement} node The target node
4165 * @param {Roo.EventObject} e The raw event object
4167 "contextmenu" : true,
4169 * @event selectionchange
4170 * Fires when the selected nodes change.
4171 * @param {Roo.View} this
4172 * @param {Array} selections Array of the selected nodes
4174 "selectionchange" : true,
4177 * @event beforeselect
4178 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
4179 * @param {Roo.View} this
4180 * @param {HTMLElement} node The node to be selected
4181 * @param {Array} selections Array of currently selected nodes
4183 "beforeselect" : true,
4185 * @event preparedata
4186 * Fires on every row to render, to allow you to change the data.
4187 * @param {Roo.View} this
4188 * @param {Object} data to be rendered (change this)
4190 "preparedata" : true
4198 "click": this.onClick,
4199 "dblclick": this.onDblClick,
4200 "contextmenu": this.onContextMenu,
4204 this.selections = [];
4206 this.cmp = new Roo.CompositeElementLite([]);
4208 this.store = Roo.factory(this.store, Roo.data);
4209 this.setStore(this.store, true);
4212 if ( this.footer && this.footer.xtype) {
4214 var fctr = this.wrapEl.appendChild(document.createElement("div"));
4216 this.footer.dataSource = this.store
4217 this.footer.container = fctr;
4218 this.footer = Roo.factory(this.footer, Roo);
4219 fctr.insertFirst(this.el);
4221 // this is a bit insane - as the paging toolbar seems to detach the el..
4222 // dom.parentNode.parentNode.parentNode
4223 // they get detached?
4227 Roo.View.superclass.constructor.call(this);
4232 Roo.extend(Roo.View, Roo.util.Observable, {
4235 * @cfg {Roo.data.Store} store Data store to load data from.
4240 * @cfg {String|Roo.Element} el The container element.
4245 * @cfg {String|Roo.Template} tpl The template used by this View
4249 * @cfg {String} dataName the named area of the template to use as the data area
4250 * Works with domtemplates roo-name="name"
4254 * @cfg {String} selectedClass The css class to add to selected nodes
4256 selectedClass : "x-view-selected",
4258 * @cfg {String} emptyText The empty text to show when nothing is loaded.
4263 * @cfg {String} text to display on mask (default Loading)
4267 * @cfg {Boolean} multiSelect Allow multiple selection
4269 multiSelect : false,
4271 * @cfg {Boolean} singleSelect Allow single selection
4273 singleSelect: false,
4276 * @cfg {Boolean} toggleSelect - selecting
4278 toggleSelect : false,
4281 * Returns the element this view is bound to.
4282 * @return {Roo.Element}
4291 * Refreshes the view. - called by datachanged on the store. - do not call directly.
4293 refresh : function(){
4296 // if we are using something like 'domtemplate', then
4297 // the what gets used is:
4298 // t.applySubtemplate(NAME, data, wrapping data..)
4299 // the outer template then get' applied with
4300 // the store 'extra data'
4301 // and the body get's added to the
4302 // roo-name="data" node?
4303 // <span class='roo-tpl-{name}'></span> ?????
4307 this.clearSelections();
4310 var records = this.store.getRange();
4311 if(records.length < 1) {
4313 // is this valid?? = should it render a template??
4315 this.el.update(this.emptyText);
4319 if (this.dataName) {
4320 this.el.update(t.apply(this.store.meta)); //????
4321 el = this.el.child('.roo-tpl-' + this.dataName);
4324 for(var i = 0, len = records.length; i < len; i++){
4325 var data = this.prepareData(records[i].data, i, records[i]);
4326 this.fireEvent("preparedata", this, data, i, records[i]);
4327 html[html.length] = Roo.util.Format.trim(
4329 t.applySubtemplate(this.dataName, data, this.store.meta) :
4336 el.update(html.join(""));
4337 this.nodes = el.dom.childNodes;
4338 this.updateIndexes(0);
4342 * Function to override to reformat the data that is sent to
4343 * the template for each node.
4344 * DEPRICATED - use the preparedata event handler.
4345 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
4346 * a JSON object for an UpdateManager bound view).
4348 prepareData : function(data, index, record)
4350 this.fireEvent("preparedata", this, data, index, record);
4354 onUpdate : function(ds, record){
4355 this.clearSelections();
4356 var index = this.store.indexOf(record);
4357 var n = this.nodes[index];
4358 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
4359 n.parentNode.removeChild(n);
4360 this.updateIndexes(index, index);
4366 onAdd : function(ds, records, index)
4368 this.clearSelections();
4369 if(this.nodes.length == 0){
4373 var n = this.nodes[index];
4374 for(var i = 0, len = records.length; i < len; i++){
4375 var d = this.prepareData(records[i].data, i, records[i]);
4377 this.tpl.insertBefore(n, d);
4380 this.tpl.append(this.el, d);
4383 this.updateIndexes(index);
4386 onRemove : function(ds, record, index){
4387 this.clearSelections();
4388 var el = this.dataName ?
4389 this.el.child('.roo-tpl-' + this.dataName) :
4391 el.dom.removeChild(this.nodes[index]);
4392 this.updateIndexes(index);
4396 * Refresh an individual node.
4397 * @param {Number} index
4399 refreshNode : function(index){
4400 this.onUpdate(this.store, this.store.getAt(index));
4403 updateIndexes : function(startIndex, endIndex){
4404 var ns = this.nodes;
4405 startIndex = startIndex || 0;
4406 endIndex = endIndex || ns.length - 1;
4407 for(var i = startIndex; i <= endIndex; i++){
4408 ns[i].nodeIndex = i;
4413 * Changes the data store this view uses and refresh the view.
4414 * @param {Store} store
4416 setStore : function(store, initial){
4417 if(!initial && this.store){
4418 this.store.un("datachanged", this.refresh);
4419 this.store.un("add", this.onAdd);
4420 this.store.un("remove", this.onRemove);
4421 this.store.un("update", this.onUpdate);
4422 this.store.un("clear", this.refresh);
4423 this.store.un("beforeload", this.onBeforeLoad);
4424 this.store.un("load", this.onLoad);
4425 this.store.un("loadexception", this.onLoad);
4429 store.on("datachanged", this.refresh, this);
4430 store.on("add", this.onAdd, this);
4431 store.on("remove", this.onRemove, this);
4432 store.on("update", this.onUpdate, this);
4433 store.on("clear", this.refresh, this);
4434 store.on("beforeload", this.onBeforeLoad, this);
4435 store.on("load", this.onLoad, this);
4436 store.on("loadexception", this.onLoad, this);
4444 * onbeforeLoad - masks the loading area.
4447 onBeforeLoad : function()
4450 this.el.mask(this.mask ? this.mask : "Loading" );
4452 onLoad : function ()
4459 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
4460 * @param {HTMLElement} node
4461 * @return {HTMLElement} The template node
4463 findItemFromChild : function(node){
4464 var el = this.dataName ?
4465 this.el.child('.roo-tpl-' + this.dataName,true) :
4468 if(!node || node.parentNode == el){
4471 var p = node.parentNode;
4472 while(p && p != el){
4473 if(p.parentNode == el){
4482 onClick : function(e){
4483 var item = this.findItemFromChild(e.getTarget());
4485 var index = this.indexOf(item);
4486 if(this.onItemClick(item, index, e) !== false){
4487 this.fireEvent("click", this, index, item, e);
4490 this.clearSelections();
4495 onContextMenu : function(e){
4496 var item = this.findItemFromChild(e.getTarget());
4498 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
4503 onDblClick : function(e){
4504 var item = this.findItemFromChild(e.getTarget());
4506 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
4510 onItemClick : function(item, index, e)
4512 if(this.fireEvent("beforeclick", this, index, item, e) === false){
4515 if (this.toggleSelect) {
4516 var m = this.isSelected(item) ? 'unselect' : 'select';
4519 _t[m](item, true, false);
4522 if(this.multiSelect || this.singleSelect){
4523 if(this.multiSelect && e.shiftKey && this.lastSelection){
4524 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
4526 this.select(item, this.multiSelect && e.ctrlKey);
4527 this.lastSelection = item;
4535 * Get the number of selected nodes.
4538 getSelectionCount : function(){
4539 return this.selections.length;
4543 * Get the currently selected nodes.
4544 * @return {Array} An array of HTMLElements
4546 getSelectedNodes : function(){
4547 return this.selections;
4551 * Get the indexes of the selected nodes.
4554 getSelectedIndexes : function(){
4555 var indexes = [], s = this.selections;
4556 for(var i = 0, len = s.length; i < len; i++){
4557 indexes.push(s[i].nodeIndex);
4563 * Clear all selections
4564 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
4566 clearSelections : function(suppressEvent){
4567 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
4568 this.cmp.elements = this.selections;
4569 this.cmp.removeClass(this.selectedClass);
4570 this.selections = [];
4572 this.fireEvent("selectionchange", this, this.selections);
4578 * Returns true if the passed node is selected
4579 * @param {HTMLElement/Number} node The node or node index
4582 isSelected : function(node){
4583 var s = this.selections;
4587 node = this.getNode(node);
4588 return s.indexOf(node) !== -1;
4593 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
4594 * @param {Boolean} keepExisting (optional) true to keep existing selections
4595 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
4597 select : function(nodeInfo, keepExisting, suppressEvent){
4598 if(nodeInfo instanceof Array){
4600 this.clearSelections(true);
4602 for(var i = 0, len = nodeInfo.length; i < len; i++){
4603 this.select(nodeInfo[i], true, true);
4607 var node = this.getNode(nodeInfo);
4608 if(!node || this.isSelected(node)){
4609 return; // already selected.
4612 this.clearSelections(true);
4614 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
4615 Roo.fly(node).addClass(this.selectedClass);
4616 this.selections.push(node);
4618 this.fireEvent("selectionchange", this, this.selections);
4626 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
4627 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
4628 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
4630 unselect : function(nodeInfo, keepExisting, suppressEvent)
4632 if(nodeInfo instanceof Array){
4633 Roo.each(this.selections, function(s) {
4634 this.unselect(s, nodeInfo);
4638 var node = this.getNode(nodeInfo);
4639 if(!node || !this.isSelected(node)){
4640 Roo.log("not selected");
4641 return; // not selected.
4645 Roo.each(this.selections, function(s) {
4647 Roo.fly(node).removeClass(this.selectedClass);
4654 this.selections= ns;
4655 this.fireEvent("selectionchange", this, this.selections);
4659 * Gets a template node.
4660 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
4661 * @return {HTMLElement} The node or null if it wasn't found
4663 getNode : function(nodeInfo){
4664 if(typeof nodeInfo == "string"){
4665 return document.getElementById(nodeInfo);
4666 }else if(typeof nodeInfo == "number"){
4667 return this.nodes[nodeInfo];
4673 * Gets a range template nodes.
4674 * @param {Number} startIndex
4675 * @param {Number} endIndex
4676 * @return {Array} An array of nodes
4678 getNodes : function(start, end){
4679 var ns = this.nodes;
4681 end = typeof end == "undefined" ? ns.length - 1 : end;
4684 for(var i = start; i <= end; i++){
4688 for(var i = start; i >= end; i--){
4696 * Finds the index of the passed node
4697 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
4698 * @return {Number} The index of the node or -1
4700 indexOf : function(node){
4701 node = this.getNode(node);
4702 if(typeof node.nodeIndex == "number"){
4703 return node.nodeIndex;
4705 var ns = this.nodes;
4706 for(var i = 0, len = ns.length; i < len; i++){
4720 * @class Roo.bootstrap.ComboBox
4721 * @extends Roo.bootstrap.TriggerField
4722 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
4724 * Create a new ComboBox.
4725 * @param {Object} config Configuration options
4727 Roo.bootstrap.ComboBox = function(config){
4728 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
4732 * Fires when the dropdown list is expanded
4733 * @param {Roo.bootstrap.ComboBox} combo This combo box
4738 * Fires when the dropdown list is collapsed
4739 * @param {Roo.bootstrap.ComboBox} combo This combo box
4743 * @event beforeselect
4744 * Fires before a list item is selected. Return false to cancel the selection.
4745 * @param {Roo.bootstrap.ComboBox} combo This combo box
4746 * @param {Roo.data.Record} record The data record returned from the underlying store
4747 * @param {Number} index The index of the selected item in the dropdown list
4749 'beforeselect' : true,
4752 * Fires when a list item is selected
4753 * @param {Roo.bootstrap.ComboBox} combo This combo box
4754 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
4755 * @param {Number} index The index of the selected item in the dropdown list
4759 * @event beforequery
4760 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
4761 * The event object passed has these properties:
4762 * @param {Roo.bootstrap.ComboBox} combo This combo box
4763 * @param {String} query The query
4764 * @param {Boolean} forceAll true to force "all" query
4765 * @param {Boolean} cancel true to cancel the query
4766 * @param {Object} e The query event object
4768 'beforequery': true,
4771 * Fires when the 'add' icon is pressed (add a listener to enable add button)
4772 * @param {Roo.bootstrap.ComboBox} combo This combo box
4777 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
4778 * @param {Roo.bootstrap.ComboBox} combo This combo box
4779 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
4787 this.selectedIndex = -1;
4788 if(this.mode == 'local'){
4789 if(config.queryDelay === undefined){
4790 this.queryDelay = 10;
4792 if(config.minChars === undefined){
4798 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
4801 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
4802 * rendering into an Roo.Editor, defaults to false)
4805 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
4806 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
4809 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
4812 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
4813 * the dropdown list (defaults to undefined, with no header element)
4817 * @cfg {String/Roo.Template} tpl The template to use to render the output
4821 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
4823 listWidth: undefined,
4825 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
4826 * mode = 'remote' or 'text' if mode = 'local')
4828 displayField: undefined,
4830 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
4831 * mode = 'remote' or 'value' if mode = 'local').
4832 * Note: use of a valueField requires the user make a selection
4833 * in order for a value to be mapped.
4835 valueField: undefined,
4839 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
4840 * field's data value (defaults to the underlying DOM element's name)
4842 hiddenName: undefined,
4844 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
4848 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
4850 selectedClass: 'active',
4853 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
4857 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
4858 * anchor positions (defaults to 'tl-bl')
4860 listAlign: 'tl-bl?',
4862 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
4866 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
4867 * query specified by the allQuery config option (defaults to 'query')
4869 triggerAction: 'query',
4871 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
4872 * (defaults to 4, does not apply if editable = false)
4876 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
4877 * delay (typeAheadDelay) if it matches a known value (defaults to false)
4881 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
4882 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
4886 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
4887 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
4891 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
4892 * when editable = true (defaults to false)
4894 selectOnFocus:false,
4896 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
4898 queryParam: 'query',
4900 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
4901 * when mode = 'remote' (defaults to 'Loading...')
4903 loadingText: 'Loading...',
4905 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
4909 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
4913 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
4914 * traditional select (defaults to true)
4918 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
4922 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
4926 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
4927 * listWidth has a higher value)
4931 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
4932 * allow the user to set arbitrary text into the field (defaults to false)
4934 forceSelection:false,
4936 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
4937 * if typeAhead = true (defaults to 250)
4939 typeAheadDelay : 250,
4941 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
4942 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
4944 valueNotFoundText : undefined,
4946 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
4951 * @cfg {Boolean} disableClear Disable showing of clear button.
4953 disableClear : false,
4955 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
4957 alwaysQuery : false,
4963 // element that contains real text value.. (when hidden is used..)
4966 initEvents: function(){
4969 throw "can not find store for combo";
4971 this.store = Roo.factory(this.store, Roo.data);
4975 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
4978 if(this.hiddenName){
4980 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
4982 this.hiddenField.dom.value =
4983 this.hiddenValue !== undefined ? this.hiddenValue :
4984 this.value !== undefined ? this.value : '';
4986 // prevent input submission
4987 this.el.dom.removeAttribute('name');
4988 this.hiddenField.dom.setAttribute('name', this.hiddenName);
4993 // this.el.dom.setAttribute('autocomplete', 'off');
4996 var cls = 'x-combo-list';
4997 this.list = this.el.select('ul',true).first();
4999 //this.list = new Roo.Layer({
5000 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
5003 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
5004 this.list.setWidth(lw);
5006 this.list.swallowEvent('mousewheel');
5007 this.assetHeight = 0;
5010 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
5011 this.assetHeight += this.header.getHeight();
5014 this.innerList = this.list.createChild({cls:cls+'-inner'});
5015 this.innerList.on('mouseover', this.onViewOver, this);
5016 this.innerList.on('mousemove', this.onViewMove, this);
5017 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
5019 if(this.allowBlank && !this.pageSize && !this.disableClear){
5020 this.footer = this.list.createChild({cls:cls+'-ft'});
5021 this.pageTb = new Roo.Toolbar(this.footer);
5025 this.footer = this.list.createChild({cls:cls+'-ft'});
5026 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
5027 {pageSize: this.pageSize});
5031 if (this.pageTb && this.allowBlank && !this.disableClear) {
5033 this.pageTb.add(new Roo.Toolbar.Fill(), {
5034 cls: 'x-btn-icon x-btn-clear',
5040 _this.onSelect(false, -1);
5045 this.assetHeight += this.footer.getHeight();
5050 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
5053 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
5054 singleSelect:true, store: this.store, selectedClass: this.selectedClass
5056 //this.view.wrapEl.setDisplayed(false);
5057 this.view.on('click', this.onViewClick, this);
5061 this.store.on('beforeload', this.onBeforeLoad, this);
5062 this.store.on('load', this.onLoad, this);
5063 this.store.on('loadexception', this.onLoadException, this);
5066 this.resizer = new Roo.Resizable(this.list, {
5067 pinned:true, handles:'se'
5069 this.resizer.on('resize', function(r, w, h){
5070 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
5072 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
5073 this.restrictHeight();
5075 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
5079 this.editable = true;
5080 this.setEditable(false);
5085 if (typeof(this.events.add.listeners) != 'undefined') {
5087 this.addicon = this.wrap.createChild(
5088 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
5090 this.addicon.on('click', function(e) {
5091 this.fireEvent('add', this);
5094 if (typeof(this.events.edit.listeners) != 'undefined') {
5096 this.editicon = this.wrap.createChild(
5097 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
5099 this.editicon.setStyle('margin-left', '40px');
5101 this.editicon.on('click', function(e) {
5103 // we fire even if inothing is selected..
5104 this.fireEvent('edit', this, this.lastData );
5111 this.keyNav = new Roo.KeyNav(this.inputEl(), {
5113 this.inKeyMode = true;
5117 "down" : function(e){
5118 if(!this.isExpanded()){
5119 this.onTriggerClick();
5121 this.inKeyMode = true;
5126 "enter" : function(e){
5131 "esc" : function(e){
5135 "tab" : function(e){
5136 this.onViewClick(false);
5137 this.fireEvent("specialkey", this, e);
5143 doRelay : function(foo, bar, hname){
5144 if(hname == 'down' || this.scope.isExpanded()){
5145 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
5154 this.queryDelay = Math.max(this.queryDelay || 10,
5155 this.mode == 'local' ? 10 : 250);
5158 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
5161 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
5163 if(this.editable !== false){
5164 this.inputEl().on("keyup", this.onKeyUp, this);
5166 if(this.forceSelection){
5167 this.on('blur', this.doForce, this);
5171 onDestroy : function(){
5173 this.view.setStore(null);
5174 this.view.el.removeAllListeners();
5175 this.view.el.remove();
5176 this.view.purgeListeners();
5179 this.list.dom.innerHTML = '';
5182 this.store.un('beforeload', this.onBeforeLoad, this);
5183 this.store.un('load', this.onLoad, this);
5184 this.store.un('loadexception', this.onLoadException, this);
5186 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
5190 fireKey : function(e){
5191 if(e.isNavKeyPress() && !this.list.isVisible()){
5192 this.fireEvent("specialkey", this, e);
5197 onResize: function(w, h){
5198 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
5200 if(typeof w != 'number'){
5201 // we do not handle it!?!?
5204 var tw = this.trigger.getWidth();
5205 // tw += this.addicon ? this.addicon.getWidth() : 0;
5206 // tw += this.editicon ? this.editicon.getWidth() : 0;
5208 this.inputEl().setWidth( this.adjustWidth('input', x));
5210 //this.trigger.setStyle('left', x+'px');
5212 if(this.list && this.listWidth === undefined){
5213 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
5214 this.list.setWidth(lw);
5215 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
5223 * Allow or prevent the user from directly editing the field text. If false is passed,
5224 * the user will only be able to select from the items defined in the dropdown list. This method
5225 * is the runtime equivalent of setting the 'editable' config option at config time.
5226 * @param {Boolean} value True to allow the user to directly edit the field text
5228 setEditable : function(value){
5229 if(value == this.editable){
5232 this.editable = value;
5234 this.inputEl().dom.setAttribute('readOnly', true);
5235 this.inputEl().on('mousedown', this.onTriggerClick, this);
5236 this.inputEl().addClass('x-combo-noedit');
5238 this.inputEl().dom.setAttribute('readOnly', false);
5239 this.inputEl().un('mousedown', this.onTriggerClick, this);
5240 this.inputEl().removeClass('x-combo-noedit');
5245 onBeforeLoad : function(){
5249 //this.innerList.update(this.loadingText ?
5250 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
5251 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
5253 this.restrictHeight();
5254 this.selectedIndex = -1;
5258 onLoad : function(){
5262 if(this.store.getCount() > 0){
5264 this.restrictHeight();
5265 if(this.lastQuery == this.allQuery){
5267 this.inputEl().dom.select();
5269 if(!this.selectByValue(this.value, true)){
5270 this.select(0, true);
5274 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
5275 this.taTask.delay(this.typeAheadDelay);
5279 this.onEmptyResults();
5284 onLoadException : function()
5287 Roo.log(this.store.reader.jsonData);
5288 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5290 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5296 onTypeAhead : function(){
5297 if(this.store.getCount() > 0){
5298 var r = this.store.getAt(0);
5299 var newValue = r.data[this.displayField];
5300 var len = newValue.length;
5301 var selStart = this.getRawValue().length;
5302 if(selStart != len){
5303 this.setRawValue(newValue);
5304 this.selectText(selStart, newValue.length);
5310 onSelect : function(record, index){
5311 if(this.fireEvent('beforeselect', this, record, index) !== false){
5312 this.setFromData(index > -1 ? record.data : false);
5314 this.fireEvent('select', this, record, index);
5319 * Returns the currently selected field value or empty string if no value is set.
5320 * @return {String} value The selected value
5322 getValue : function(){
5323 if(this.valueField){
5324 return typeof this.value != 'undefined' ? this.value : '';
5326 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
5331 * Clears any text/value currently set in the field
5333 clearValue : function(){
5334 if(this.hiddenField){
5335 this.hiddenField.dom.value = '';
5338 this.setRawValue('');
5339 this.lastSelectionText = '';
5344 * Sets the specified value into the field. If the value finds a match, the corresponding record text
5345 * will be displayed in the field. If the value does not match the data value of an existing item,
5346 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
5347 * Otherwise the field will be blank (although the value will still be set).
5348 * @param {String} value The value to match
5350 setValue : function(v){
5352 if(this.valueField){
5353 var r = this.findRecord(this.valueField, v);
5355 text = r.data[this.displayField];
5356 }else if(this.valueNotFoundText !== undefined){
5357 text = this.valueNotFoundText;
5360 this.lastSelectionText = text;
5361 if(this.hiddenField){
5362 this.hiddenField.dom.value = v;
5364 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
5368 * @property {Object} the last set data for the element
5373 * Sets the value of the field based on a object which is related to the record format for the store.
5374 * @param {Object} value the value to set as. or false on reset?
5376 setFromData : function(o){
5377 var dv = ''; // display value
5378 var vv = ''; // value value..
5380 if (this.displayField) {
5381 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
5383 // this is an error condition!!!
5384 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
5387 if(this.valueField){
5388 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
5390 if(this.hiddenField){
5391 this.hiddenField.dom.value = vv;
5393 this.lastSelectionText = dv;
5394 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
5398 // no hidden field.. - we store the value in 'value', but still display
5399 // display field!!!!
5400 this.lastSelectionText = dv;
5401 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
5408 // overridden so that last data is reset..
5409 this.setValue(this.originalValue);
5410 this.clearInvalid();
5411 this.lastData = false;
5413 this.view.clearSelections();
5417 findRecord : function(prop, value){
5419 if(this.store.getCount() > 0){
5420 this.store.each(function(r){
5421 if(r.data[prop] == value){
5433 // returns hidden if it's set..
5434 if (!this.rendered) {return ''};
5435 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
5439 onViewMove : function(e, t){
5440 this.inKeyMode = false;
5444 onViewOver : function(e, t){
5445 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
5448 var item = this.view.findItemFromChild(t);
5450 var index = this.view.indexOf(item);
5451 this.select(index, false);
5456 onViewClick : function(doFocus)
5458 var index = this.view.getSelectedIndexes()[0];
5459 var r = this.store.getAt(index);
5461 this.onSelect(r, index);
5463 if(doFocus !== false && !this.blockFocus){
5464 this.inputEl().focus();
5469 restrictHeight : function(){
5470 //this.innerList.dom.style.height = '';
5471 //var inner = this.innerList.dom;
5472 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
5473 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
5474 //this.list.beginUpdate();
5475 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
5476 this.list.alignTo(this.inputEl(), this.listAlign);
5477 //this.list.endUpdate();
5481 onEmptyResults : function(){
5486 * Returns true if the dropdown list is expanded, else false.
5488 isExpanded : function(){
5489 return this.list.isVisible();
5493 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
5494 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
5495 * @param {String} value The data value of the item to select
5496 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
5497 * selected item if it is not currently in view (defaults to true)
5498 * @return {Boolean} True if the value matched an item in the list, else false
5500 selectByValue : function(v, scrollIntoView){
5501 if(v !== undefined && v !== null){
5502 var r = this.findRecord(this.valueField || this.displayField, v);
5504 this.select(this.store.indexOf(r), scrollIntoView);
5512 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
5513 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
5514 * @param {Number} index The zero-based index of the list item to select
5515 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
5516 * selected item if it is not currently in view (defaults to true)
5518 select : function(index, scrollIntoView){
5519 this.selectedIndex = index;
5520 this.view.select(index);
5521 if(scrollIntoView !== false){
5522 var el = this.view.getNode(index);
5524 //this.innerList.scrollChildIntoView(el, false);
5531 selectNext : function(){
5532 var ct = this.store.getCount();
5534 if(this.selectedIndex == -1){
5536 }else if(this.selectedIndex < ct-1){
5537 this.select(this.selectedIndex+1);
5543 selectPrev : function(){
5544 var ct = this.store.getCount();
5546 if(this.selectedIndex == -1){
5548 }else if(this.selectedIndex != 0){
5549 this.select(this.selectedIndex-1);
5555 onKeyUp : function(e){
5556 if(this.editable !== false && !e.isSpecialKey()){
5557 this.lastKey = e.getKey();
5558 this.dqTask.delay(this.queryDelay);
5563 validateBlur : function(){
5564 return !this.list || !this.list.isVisible();
5568 initQuery : function(){
5569 this.doQuery(this.getRawValue());
5573 doForce : function(){
5574 if(this.el.dom.value.length > 0){
5576 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
5582 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
5583 * query allowing the query action to be canceled if needed.
5584 * @param {String} query The SQL query to execute
5585 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
5586 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
5587 * saved in the current store (defaults to false)
5589 doQuery : function(q, forceAll){
5590 if(q === undefined || q === null){
5599 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
5603 forceAll = qe.forceAll;
5604 if(forceAll === true || (q.length >= this.minChars)){
5605 if(this.lastQuery != q || this.alwaysQuery){
5607 if(this.mode == 'local'){
5608 this.selectedIndex = -1;
5610 this.store.clearFilter();
5612 this.store.filter(this.displayField, q);
5616 this.store.baseParams[this.queryParam] = q;
5618 params: this.getParams(q)
5623 this.selectedIndex = -1;
5630 getParams : function(q){
5632 //p[this.queryParam] = q;
5635 p.limit = this.pageSize;
5641 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
5643 collapse : function(){
5644 if(!this.isExpanded()){
5648 Roo.get(document).un('mousedown', this.collapseIf, this);
5649 Roo.get(document).un('mousewheel', this.collapseIf, this);
5650 if (!this.editable) {
5651 Roo.get(document).un('keydown', this.listKeyPress, this);
5653 this.fireEvent('collapse', this);
5657 collapseIf : function(e){
5658 if(!e.within(this.el) && !e.within(this.el)){
5664 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
5666 expand : function(){
5668 if(this.isExpanded() || !this.hasFocus){
5671 this.list.alignTo(this.inputEl(), this.listAlign);
5673 Roo.get(document).on('mousedown', this.collapseIf, this);
5674 Roo.get(document).on('mousewheel', this.collapseIf, this);
5675 if (!this.editable) {
5676 Roo.get(document).on('keydown', this.listKeyPress, this);
5679 this.fireEvent('expand', this);
5683 // Implements the default empty TriggerField.onTriggerClick function
5684 onTriggerClick : function()
5686 Roo.log('trigger click');
5691 if(this.isExpanded()){
5693 if (!this.blockFocus) {
5694 this.inputEl().focus();
5698 this.hasFocus = true;
5699 if(this.triggerAction == 'all') {
5700 this.doQuery(this.allQuery, true);
5702 this.doQuery(this.getRawValue());
5704 if (!this.blockFocus) {
5705 this.inputEl().focus();
5709 listKeyPress : function(e)
5711 //Roo.log('listkeypress');
5712 // scroll to first matching element based on key pres..
5713 if (e.isSpecialKey()) {
5716 var k = String.fromCharCode(e.getKey()).toUpperCase();
5719 var csel = this.view.getSelectedNodes();
5720 var cselitem = false;
5722 var ix = this.view.indexOf(csel[0]);
5723 cselitem = this.store.getAt(ix);
5724 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
5730 this.store.each(function(v) {
5732 // start at existing selection.
5733 if (cselitem.id == v.id) {
5739 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
5740 match = this.store.indexOf(v);
5746 if (match === false) {
5747 return true; // no more action?
5750 this.view.select(match);
5751 var sn = Roo.get(this.view.getSelectedNodes()[0])
5752 //sn.scrollIntoView(sn.dom.parentNode, false);
5756 * @cfg {Boolean} grow
5760 * @cfg {Number} growMin
5764 * @cfg {Number} growMax
5774 * based on jquery fullcalendar
5780 * @class Roo.bootstrap.Calendar
5781 * @extends Roo.bootstrap.Component
5782 * Bootstrap Calendar class
5785 * Create a new Container
5786 * @param {Object} config The config object
5789 Roo.bootstrap.Calendar = function(config){
5790 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
5794 * Fires when a date is selected
5795 * @param {DatePicker} this
5796 * @param {Date} date The selected date
5800 * @event monthchange
5801 * Fires when the displayed month changes
5802 * @param {DatePicker} this
5803 * @param {Date} date The selected month
5805 'monthchange': true,
5808 * Fires when mouse over an event
5809 * @param {Calendar} this
5810 * @param {event} Event
5815 * Fires when the mouse leaves an
5816 * @param {Calendar} this
5825 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
5828 * @cfg {Number} startDay
5829 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
5833 getAutoCreate : function(){
5836 fc_button = function(name, corner, style, content ) {
5837 return Roo.apply({},{
5839 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
5841 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
5844 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
5852 style : 'width:100%',
5859 cls : 'fc-header-left',
5861 fc_button('prev', 'left', 'arrow', '‹' ),
5862 fc_button('next', 'right', 'arrow', '›' ),
5863 { tag: 'span', cls: 'fc-header-space' },
5864 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
5872 cls : 'fc-header-center',
5876 cls: 'fc-header-title',
5879 html : 'month / year'
5887 cls : 'fc-header-right',
5889 /* fc_button('month', 'left', '', 'month' ),
5890 fc_button('week', '', '', 'week' ),
5891 fc_button('day', 'right', '', 'day' )
5903 var cal_heads = function() {
5905 // fixme - handle this.
5907 for (var i =0; i < Date.dayNames.length; i++) {
5908 var d = Date.dayNames[i];
5911 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
5912 html : d.substring(0,3)
5916 ret[0].cls += ' fc-first';
5917 ret[6].cls += ' fc-last';
5920 var cal_cell = function(n) {
5923 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
5928 cls: 'fc-day-number',
5932 cls: 'fc-day-content',
5936 style: 'position: relative;' // height: 17px;
5948 var cal_rows = function() {
5950 for (var r = 0; r < 6; r++) {
5957 for (var i =0; i < Date.dayNames.length; i++) {
5958 var d = Date.dayNames[i];
5959 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
5962 row.cn[0].cls+=' fc-first';
5963 row.cn[0].cn[0].style = 'min-height:90px';
5964 row.cn[6].cls+=' fc-last';
5968 ret[0].cls += ' fc-first';
5970 ret[5].cls += ' fc-last';
5976 cls: 'fc-border-separate',
5977 style : 'width:100%',
5985 cls : 'fc-first fc-last',
6004 style : "position: relative;",
6007 cls : 'fc-view fc-view-month fc-grid',
6008 style : 'position: relative',
6009 unselectable : 'on',
6012 cls : 'fc-event-container',
6013 style : 'position:absolute;z-index:8;top:0;left:0;'
6031 initEvents : function()
6034 this.cells = this.el.select('.fc-day',true);
6035 this.textNodes = this.el.query('.fc-day-number');
6036 this.update(new Date().clearTime());
6037 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
6038 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
6039 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
6040 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
6041 this.cells.addClassOnOver('fc-state-hover');
6045 this.calevents = [];
6049 end : new Date().add(Date.DAY, 2),
6053 start: new Date().add(Date.DAY, -5),
6054 end : new Date().add(Date.DAY, 2),
6059 end : new Date().add(Date.HOUR, 2),
6064 end : new Date().add(Date.HOUR, 2),
6067 this.renderEvents();
6069 resize : function() {
6070 var sz = this.el.getSize();
6072 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
6073 this.el.select('.fc-day-content div',true).setHeight(34);
6078 showPrevMonth : function(e){
6079 this.update(this.activeDate.add("mo", -1));
6081 showToday : function(e){
6082 this.update(new Date().clearTime());
6085 showNextMonth : function(e){
6086 this.update(this.activeDate.add("mo", 1));
6090 showPrevYear : function(){
6091 this.update(this.activeDate.add("y", -1));
6095 showNextYear : function(){
6096 this.update(this.activeDate.add("y", 1));
6101 update : function(date)
6104 var vd = this.activeDate;
6105 this.activeDate = date;
6107 var t = date.getTime();
6108 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
6109 Roo.log('using add remove');
6110 this.cells.removeClass("fc-state-highlight");
6111 this.cells.each(function(c){
6112 if(c.dateValue == t){
6113 c.addClass("fc-state-highlight");
6114 setTimeout(function(){
6115 try{c.dom.firstChild.focus();}catch(e){}
6125 var days = date.getDaysInMonth();
6126 var firstOfMonth = date.getFirstDateOfMonth();
6127 var startingPos = firstOfMonth.getDay()-this.startDay;
6129 if(startingPos <= this.startDay){
6133 var pm = date.add("mo", -1);
6134 var prevStart = pm.getDaysInMonth()-startingPos;
6136 var cells = this.cells.elements;
6137 var textEls = this.textNodes;
6138 days += startingPos;
6140 // convert everything to numbers so it's fast
6142 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
6143 var today = new Date().clearTime().getTime();
6144 var sel = date.clearTime().getTime();
6145 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
6146 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
6147 var ddMatch = this.disabledDatesRE;
6148 var ddText = this.disabledDatesText;
6149 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
6150 var ddaysText = this.disabledDaysText;
6151 var format = this.format;
6153 var setCellClass = function(cal, cell){
6155 var t = d.getTime();
6158 cell.className += " fc-today";
6159 cell.title = cal.todayText;
6162 cell.className += " fc-state-highlight";
6163 //setTimeout(function(){
6164 // try{cell.firstChild.focus();}catch(e){}
6169 cell.className = " fc-state-disabled";
6170 cell.title = cal.minText;
6174 cell.className = " fc-state-disabled";
6175 cell.title = cal.maxText;
6179 if(ddays.indexOf(d.getDay()) != -1){
6180 cell.title = ddaysText;
6181 cell.className = " fc-state-disabled";
6184 if(ddMatch && format){
6185 var fvalue = d.dateFormat(format);
6186 if(ddMatch.test(fvalue)){
6187 cell.title = ddText.replace("%0", fvalue);
6188 cell.className = " fc-state-disabled";
6191 if (!cell.initialClassName) {
6192 cell.initialClassName = cell.dom.className;
6194 cell.dom.className = cell.initialClassName + ' ' + cell.className;
6198 for(; i < startingPos; i++) {
6199 textEls[i].innerHTML = (++prevStart);
6200 d.setDate(d.getDate()+1);
6201 cells[i].className = "fc-past fc-other-month";
6202 setCellClass(this, cells[i]);
6204 for(; i < days; i++){
6205 intDay = i - startingPos + 1;
6206 textEls[i].innerHTML = (intDay);
6207 d.setDate(d.getDate()+1);
6208 cells[i].className = ''; // "x-date-active";
6209 setCellClass(this, cells[i]);
6212 for(; i < 42; i++) {
6213 textEls[i].innerHTML = (++extraDays);
6214 d.setDate(d.getDate()+1);
6215 cells[i].className = "fc-future fc-other-month";
6216 setCellClass(this, cells[i]);
6219 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
6220 this.fireEvent('monthchange', this, date);
6224 if(!this.internalRender){
6225 var main = this.el.dom.firstChild;
6226 var w = main.offsetWidth;
6227 this.el.setWidth(w + this.el.getBorderWidth("lr"));
6228 Roo.fly(main).setWidth(w);
6229 this.internalRender = true;
6230 // opera does not respect the auto grow header center column
6231 // then, after it gets a width opera refuses to recalculate
6232 // without a second pass
6233 if(Roo.isOpera && !this.secondPass){
6234 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
6235 this.secondPass = true;
6236 this.update.defer(10, this, [date]);
6243 findCell : function(dt) {
6244 dt = dt.clearTime().getTime();
6246 this.cells.each(function(c){
6247 //Roo.log("check " +c.dateValue + '?=' + dt);
6248 if(c.dateValue == dt){
6258 findCells : function(ev) {
6259 var s = ev.start.clone().clearTime().getTime();
6260 var e= ev.end.clone().clearTime().getTime();
6262 this.cells.each(function(c){
6263 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
6265 if(c.dateValue > e){
6268 if(c.dateValue < s){
6277 findBestRow: function(cells)
6280 for (var i =0 ; i < cells.length;i++) {
6281 ret = Math.max(cells[i].rows || 0,ret);
6284 //d.setDate(d.ev()+1);
6289 addItem : function(ev)
6292 // look for vertical location slot in
6293 var cells = this.findCells(ev);
6294 ev.row = this.findBestRow(cells);
6296 // work out the location.
6300 for(var i =0; i < cells.length; i++) {
6308 if (crow.start.getY() == cells[i].getY()) {
6310 crow.end = cells[i];
6325 for (var i = 0; i < cells.length;i++) {
6326 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
6330 this.calevents.push(ev);
6333 clearEvents: function() {
6334 Roo.each(this.calevents, function(e) {
6335 Roo.each(e.els, function(el) {
6336 el.un('mouseenter' ,this.onEventEnter, this);
6337 el.un('mouseleave' ,this.onEventLeave, this);
6344 renderEvents: function()
6347 // first make sure there is enough space..
6348 this.cells.each(function(c) {
6349 Roo.log(c.select('.fc-day-content div',true).first(), Math.max(34, c.rows * 20));
6350 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
6353 for (var e = 0; e < this.calevents.length; e++) {
6354 var ev = this.calevents[e];
6355 var cells = ev.cells;
6358 for(var i =0; i < rows.length; i++) {
6361 // how many rows should it span..
6364 cls : 'fc-event fc-event-hori fc-event-draggable ui-draggable',
6365 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
6367 unselectable : "on",
6370 cls: 'fc-event-inner',
6374 cls: 'fc-event-time',
6375 html : cells.length > 1 ? '' : '7pm'
6379 cls: 'fc-event-title',
6380 html : String.format('{0}', ev.title)
6387 cls: 'ui-resizable-handle ui-resizable-e',
6388 html : '  '
6394 cfg.cls += ' fc-event-start';
6396 if ((i+1) == rows.length) {
6397 cfg.cls += ' fc-event-end';
6400 var ctr = this.el.select('.fc-event-container',true).first();
6401 var cg = ctr.createChild(cfg);
6404 cg.on('mouseenter' ,this.onEventEnter, this);
6405 cg.on('mouseleave' ,this.onEventLeave, this);
6408 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
6409 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
6411 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
6412 cg.setWidth(ebox.right - sbox.x -2);
6419 onEventEnter: function (e, el,c,d) {
6421 this.fireEvent('evententer', this, el);
6424 onEventLeave: function (e, el,c,d) {
6426 this.fireEvent('eventleave', this, el);