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.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
20 * Do not use directly - it does not do anything..
21 * @param {Object} config The config object
26 Roo.bootstrap.Component = function(config){
27 Roo.bootstrap.Component.superclass.constructor.call(this, config);
30 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
33 allowDomMove : false, // to stop relocations in parent onRender...
41 initEvents : function() { },
47 can_build_overlaid : true,
52 // returns the parent component..
53 return Roo.ComponentMgr.get(this.parentId)
59 onRender : function(ct, position)
61 // Roo.log("Call onRender: " + this.xtype);
63 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
66 if (this.el.attr('xtype')) {
67 this.el.attr('xtypex', this.el.attr('xtype'));
68 this.el.dom.removeAttribute('xtype');
78 var cfg = Roo.apply({}, this.getAutoCreate());
81 // fill in the extra attributes
82 if (this.xattr && typeof(this.xattr) =='object') {
83 for (var i in this.xattr) {
84 cfg[i] = this.xattr[i];
89 cfg.dataId = this.dataId;
93 cfg.cls += ' ' + this.cls;
95 if (this.style) { // fixme needs to support more complex style data.
96 cfg.style = this.style;
98 this.el = ct.createChild(cfg, position);
100 if(this.tabIndex !== undefined){
101 this.el.dom.setAttribute('tabIndex', this.tabIndex);
108 getChildContainer : function()
114 addxtype : function(tree,cntr)
116 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
117 (typeof(tree['flexy:foreach']) != 'undefined');
119 var build_from_html = Roo.XComponent.build_from_html;
121 var is_body = (tree.xtype == 'Body') ;
123 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
125 if (!has_flexy || !build_from_html || is_body || !page_has_body ) {
127 return this.addxtypeChild(tree,cntr);
132 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
134 cn = Roo.factory(tree);
136 cn.parentType = this.xtype; //??
137 cn.parentId = this.id;
139 var self_cntr_el = Roo.get(this[cntr]());
143 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
149 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
153 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
158 addxtypeChild : function (tree, cntr)
161 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
164 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
165 (typeof(tree['flexy:foreach']) != 'undefined');
170 // render the element if it's not BODY.
171 if (tree.xtype != 'Body') {
173 cn = Roo.factory(tree);
175 cn.parentType = this.xtype; //??
176 cn.parentId = this.id;
178 var build_from_html = Roo.XComponent.build_from_html;
181 // does the container contain child eleemnts with 'xtype' attributes.
182 // that match this xtype..
183 // note - when we render we create these as well..
184 // so we should check to see if body has xtype set.
185 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
187 var self_cntr_el = Roo.get(this[cntr]());
188 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
191 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
192 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
198 //echild.dom.removeAttribute('xtype');
200 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
207 // if object has flexy:if - then it may or may not be rendered.
208 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
209 // skip a flexy if element.
210 Roo.log('skipping render');
215 // actually if flexy:foreach is found, we really want to create
216 // multiple copies here...
217 cn.render(this[cntr]());
219 // then add the element..
226 if (typeof (tree.menu) != 'undefined') {
227 tree.menu.parentType = cn.xtype;
228 tree.menu.triggerEl = cn.el;
229 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
233 if (!tree.items || !tree.items.length) {
237 var items = tree.items;
240 //Roo.log(items.length);
242 for(var i =0;i < items.length;i++) {
243 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
262 Roo.bootstrap.Body = function(config){
263 Roo.bootstrap.Body.superclass.constructor.call(this, config);
264 this.el = Roo.get(document.body);
267 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
272 onRender : function(ct, position){
275 //this.el.addClass([this.fieldClass, this.cls]);
293 * @class Roo.bootstrap.ButtonGroup
294 * @extends Roo.bootstrap.Component
295 * Bootstrap ButtonGroup class
296 * @cfg {String} size lg | sm | xs (default empty normal)
297 * @cfg {String} align vertical | justified (default none)
298 * @cfg {String} direction up | down (default down)
299 * @cfg {Boolean} toolbar false | true
300 * @cfg {Boolean} btn true | false
305 * @param {Object} config The config object
308 Roo.bootstrap.ButtonGroup = function(config){
309 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
312 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
320 getAutoCreate : function(){
326 cfg.html = this.html || cfg.html;
337 if (['vertical','justified'].indexOf(this.align)!==-1) {
338 cfg.cls = 'btn-group-' + this.align;
340 if (this.align == 'justified') {
341 console.log(this.items);
345 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
346 cfg.cls += ' btn-group-' + this.size;
349 if (this.direction == 'up') {
350 cfg.cls += ' dropup' ;
366 * @class Roo.bootstrap.Button
367 * @extends Roo.bootstrap.Component
368 * Bootstrap Button class
369 * @cfg {String} html The button content
370 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
371 * @cfg {String} size empty | lg | sm | xs
372 * @cfg {String} tag empty | a | input | submit
373 * @cfg {String} href empty or href
374 * @cfg {Boolean} disabled false | true
375 * @cfg {Boolean} isClose false | true
376 * @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
377 * @cfg {String} badge text for badge
378 * @cfg {String} theme default (or empty) | glow
379 * @cfg {Boolean} inverse false | true
380 * @cfg {Boolean} toggle false | true
381 * @cfg {String} ontext text for on toggle state
382 * @cfg {String} offtext text for off toggle state
383 * @cfg {Boolean} defaulton true | false
384 * @cfg {Boolean} preventDefault true | false
387 * Create a new button
388 * @param {Object} config The config object
392 Roo.bootstrap.Button = function(config){
393 Roo.bootstrap.Button.superclass.constructor.call(this, config);
398 * The raw click event for the entire grid.
399 * @param {Roo.EventObject} e
405 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
423 preventDefault : true,
425 getAutoCreate : function(){
433 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
434 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
439 cfg.html = this.html || cfg.html;
441 if (this.toggle===true) {
444 cls: 'slider-frame roo-button',
449 'data-off-text':'OFF',
450 cls: 'slider-button',
456 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
457 cfg.cls += ' '+this.weight;
466 cfg["aria-hidden"] = true;
468 cfg.html = "×";
474 if (this.theme==='default') {
475 cfg.cls = 'btn roo-button';
477 if (this.parentType != 'Navbar') {
478 this.weight = this.weight.length ? this.weight : 'default';
480 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
482 cfg.cls += ' btn-' + this.weight;
484 } else if (this.theme==='glow') {
487 cfg.cls = 'btn-glow roo-button';
489 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
491 cfg.cls += ' ' + this.weight;
497 this.cls += ' inverse';
502 cfg.cls += ' active';
505 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
507 //gsRoo.log(this.parentType);
508 if (this.parentType === 'Navbar') {
516 href : this.href || '#'
519 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
520 cfg.cls += ' dropdown';
525 } else if (this.menu) {
527 cfg.cls += ' dropdown test';
531 cfg.disabled = 'disabled';
535 Roo.log('changing to ul' );
537 this.glyphicon = 'caret';
540 if (this.glyphicon) {
541 cfg.html = ' ' + cfg.html;
546 cls: 'glyphicon glyphicon-' + this.glyphicon
556 cfg.cls='btn roo-button';
572 if (cfg.tag !== 'a' && this.href !== '') {
573 throw "Tag must be a to set href.";
574 } else if (this.href.length > 0) {
575 cfg.href = this.href;
580 initEvents: function() {
581 // Roo.log('init events?');
582 // Roo.log(this.el.dom);
583 if (this.el.hasClass('roo-button')) {
584 this.el.on('click', this.onClick, this);
586 this.el.select('.roo-button').on('click', this.onClick, this);
592 onClick : function(e)
594 Roo.log('button on click ');
595 if(this.preventDefault){
599 this.fireEvent('click', this, e);
613 * @class Roo.bootstrap.Column
614 * @extends Roo.bootstrap.Component
615 * Bootstrap Column class
616 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
617 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
618 * @cfg {Number} md colspan out of 12 for computer-sized screens
619 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
620 * @cfg {String} html content of column.
623 * Create a new Column
624 * @param {Object} config The config object
627 Roo.bootstrap.Column = function(config){
628 Roo.bootstrap.Column.superclass.constructor.call(this, config);
631 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
640 getAutoCreate : function(){
641 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
649 ['xs','sm','md','lg'].map(function(size){
650 if (settings[size]) {
651 cfg.cls += ' col-' + size + '-' + settings[size];
654 if (this.html.length) {
655 cfg.html = this.html;
674 * @class Roo.bootstrap.Container
675 * @extends Roo.bootstrap.Component
676 * Bootstrap Container class
677 * @cfg {Boolean} jumbotron is it a jumbotron element
678 * @cfg {String} html content of element
679 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
680 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
681 * @cfg {String} header content of header (for panel)
682 * @cfg {String} footer content of footer (for panel)
683 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
686 * Create a new Container
687 * @param {Object} config The config object
690 Roo.bootstrap.Container = function(config){
691 Roo.bootstrap.Container.superclass.constructor.call(this, config);
694 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
704 getChildContainer : function() {
710 if (this.panel.length) {
711 return this.el.select('.panel-body',true).first();
718 getAutoCreate : function(){
724 if (this.jumbotron) {
725 cfg.cls = 'jumbotron';
728 cfg.cls = this.cls + '';
731 if (this.sticky.length) {
732 var bd = Roo.get(document.body);
733 if (!bd.hasClass('bootstrap-sticky')) {
734 bd.addClass('bootstrap-sticky');
735 Roo.select('html',true).setStyle('height', '100%');
738 cfg.cls += 'bootstrap-sticky-' + this.sticky;
742 if (this.well.length) {
746 cfg.cls +=' well well-' +this.well;
756 if (this.panel.length) {
757 cfg.cls += 'panel panel-' + this.panel;
759 if (this.header.length) {
762 cls : 'panel-heading',
778 if (this.footer.length) {
780 cls : 'panel-footer',
788 body.html = this.html || cfg.html;
790 if (!cfg.cls.length) {
791 cfg.cls = 'container';
808 * @class Roo.bootstrap.Img
809 * @extends Roo.bootstrap.Component
810 * Bootstrap Img class
811 * @cfg {Boolean} imgResponsive false | true
812 * @cfg {String} border rounded | circle | thumbnail
813 * @cfg {String} src image source
814 * @cfg {String} alt image alternative text
815 * @cfg {String} href a tag href
819 * @param {Object} config The config object
822 Roo.bootstrap.Img = function(config){
823 Roo.bootstrap.Img.superclass.constructor.call(this, config);
829 * The img click event for the img.
830 * @param {Roo.EventObject} e
836 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
843 getAutoCreate : function(){
847 cls: 'img-responsive',
851 cfg.html = this.html || cfg.html;
853 cfg.src = this.src || cfg.src;
855 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
856 cfg.cls += ' img-' + this.border;
874 return (this.href) ? a : cfg;
877 initEvents: function() {
880 this.el.on('click', this.onClick, this);
884 onClick : function(e)
886 Roo.log('img onclick');
887 this.fireEvent('click', this, e);
900 * @class Roo.bootstrap.Header
901 * @extends Roo.bootstrap.Component
902 * Bootstrap Header class
903 * @cfg {String} html content of header
904 * @cfg {Number} level (1|2|3|4|5|6) default 1
907 * Create a new Header
908 * @param {Object} config The config object
912 Roo.bootstrap.Header = function(config){
913 Roo.bootstrap.Header.superclass.constructor.call(this, config);
916 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
924 getAutoCreate : function(){
927 tag: 'h' + (1 *this.level),
928 html: this.html || 'fill in html'
946 * @class Roo.bootstrap.Menu
947 * @extends Roo.bootstrap.Component
948 * Bootstrap Menu class - container for MenuItems
949 * @cfg {String} type type of menu
953 * @param {Object} config The config object
957 Roo.bootstrap.Menu = function(config){
958 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
961 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
969 getChildContainer : function() {
973 getAutoCreate : function(){
975 //if (['right'].indexOf(this.align)!==-1) {
976 // cfg.cn[1].cls += ' pull-right'
980 cls : 'dropdown-menu'
984 if (this.type==='submenu') {
985 cfg.cls='submenu active'
990 initEvents : function() {
991 // Roo.log("ADD event");
992 // Roo.log(this.triggerEl.dom);
993 this.triggerEl.on('click', this.toggle, this);
994 this.triggerEl.addClass('dropdown-toggle');
999 //Roo.log(e.getTarget());
1000 // Roo.log(this.triggerEl.dom);
1001 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1004 var isActive = this.triggerEl.hasClass('open');
1005 // if disabled.. ingore
1007 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
1008 // if mobile we use a backdrop because click events don't delegate
1009 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
1012 //var relatedTarget = { relatedTarget: this }
1013 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
1015 //if (e.isDefaultPrevented()) return;
1017 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
1019 // .trigger('shown.bs.dropdown', relatedTarget)
1021 this.triggerEl.focus();
1027 clearMenus : function()
1029 //$(backdrop).remove()
1030 Roo.select('.dropdown-toggle',true).each(function(aa) {
1031 if (!aa.hasClass('open')) {
1035 aa.removeClass('open');
1036 //var parent = getParent($(this))
1037 //var relatedTarget = { relatedTarget: this }
1039 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1040 //if (e.isDefaultPrevented()) return
1041 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1059 * @class Roo.bootstrap.MenuItem
1060 * @extends Roo.bootstrap.Component
1061 * Bootstrap MenuItem class
1062 * @cfg {String} html the menu label
1063 * @cfg {String} href the link
1067 * Create a new MenuItem
1068 * @param {Object} config The config object
1072 Roo.bootstrap.MenuItem = function(config){
1073 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1076 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1081 getAutoCreate : function(){
1093 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1094 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1111 * @class Roo.bootstrap.MenuSeparator
1112 * @extends Roo.bootstrap.Component
1113 * Bootstrap MenuSeparator class
1116 * Create a new MenuItem
1117 * @param {Object} config The config object
1121 Roo.bootstrap.MenuSeparator = function(config){
1122 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1125 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1127 getAutoCreate : function(){
1142 <div class="modal fade">
1143 <div class="modal-dialog">
1144 <div class="modal-content">
1145 <div class="modal-header">
1146 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1147 <h4 class="modal-title">Modal title</h4>
1149 <div class="modal-body">
1150 <p>One fine body…</p>
1152 <div class="modal-footer">
1153 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1154 <button type="button" class="btn btn-primary">Save changes</button>
1156 </div><!-- /.modal-content -->
1157 </div><!-- /.modal-dialog -->
1158 </div><!-- /.modal -->
1168 * @class Roo.bootstrap.Modal
1169 * @extends Roo.bootstrap.Component
1170 * Bootstrap Modal class
1171 * @cfg {String} title Title of dialog
1172 * @cfg {Array} buttons Array of buttons or standard button set..
1175 * Create a new Modal Dialog
1176 * @param {Object} config The config object
1179 Roo.bootstrap.Modal = function(config){
1180 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1185 * The raw btnclick event for the button
1186 * @param {Roo.EventObject} e
1192 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1194 title : 'test dialog',
1198 onRender : function(ct, position)
1200 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1203 var cfg = Roo.apply({}, this.getAutoCreate());
1206 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1208 //if (!cfg.name.length) {
1212 cfg.cls += ' ' + this.cls;
1215 cfg.style = this.style;
1217 this.el = Roo.get(document.body).createChild(cfg, position);
1219 //var type = this.el.dom.type;
1221 if(this.tabIndex !== undefined){
1222 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1227 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1228 this.maskEl.enableDisplayMode("block");
1230 //this.el.addClass("x-dlg-modal");
1234 Roo.each(this.buttons, function(bb) {
1235 b = Roo.apply({}, bb);
1236 b.xns = b.xns || Roo.bootstrap;
1237 b.xtype = b.xtype || 'Button';
1238 if (typeof(b.listeners) == 'undefined') {
1239 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1242 var btn = Roo.factory(b);
1244 btn.onRender(this.el.select('.modal-footer').first());
1248 // render the children.
1250 var items = this.items;
1253 for(var i =0;i < items.length;i++) {
1254 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1256 this.items = nitems;
1258 //this.el.addClass([this.fieldClass, this.cls]);
1261 getAutoCreate : function(){
1266 html : this.html || ''
1274 cls: "modal-dialog",
1277 cls : "modal-content",
1280 cls : 'modal-header',
1289 cls : 'modal-title',
1297 cls : 'modal-footer'
1313 getChildContainer : function() {
1315 return this.el.select('.modal-body',true).first();
1318 getButtonContainer : function() {
1319 return this.el.select('.modal-footer',true).first();
1322 initEvents : function()
1324 this.el.select('.modal-header .close').on('click', this.hide, this);
1326 // this.addxtype(this);
1330 if (!this.rendered) {
1334 this.el.addClass('on');
1335 this.el.removeClass('fade');
1336 this.el.setStyle('display', 'block');
1337 Roo.get(document.body).addClass("x-body-masked");
1338 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1340 this.el.setStyle('zIndex', '10001');
1346 Roo.log('Modal hide?!');
1348 this.el.removeClass('on');
1349 this.el.addClass('fade');
1350 this.el.setStyle('display', 'none');
1352 onButtonClick: function(btn,e)
1355 this.fireEvent('btnclick', btn.name, e);
1360 Roo.apply(Roo.bootstrap.Modal, {
1362 * Button config that displays a single OK button
1371 * Button config that displays Yes and No buttons
1387 * Button config that displays OK and Cancel buttons
1402 * Button config that displays Yes, No and Cancel buttons
1429 * @class Roo.bootstrap.Navbar
1430 * @extends Roo.bootstrap.Component
1431 * Bootstrap Navbar class
1432 * @cfg {Boolean} sidebar has side bar
1433 * @cfg {Boolean} bar is a bar?
1434 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1435 * @cfg {String} brand what is brand
1436 * @cfg {Boolean} inverse is inverted color
1437 * @cfg {String} type (nav | pills | tabs)
1438 * @cfg {Boolean} arrangement stacked | justified
1439 * @cfg {String} align (left | right) alignment
1443 * Create a new Navbar
1444 * @param {Object} config The config object
1448 Roo.bootstrap.Navbar = function(config){
1449 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1452 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1464 getAutoCreate : function(){
1469 if (this.sidebar === true) {
1477 if (this.bar === true) {
1485 cls: 'navbar-header',
1490 cls: 'navbar-toggle',
1491 'data-toggle': 'collapse',
1496 html: 'Toggle navigation'
1516 cls: 'collapse navbar-collapse'
1521 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1523 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1524 cfg.cls += ' navbar-' + this.position;
1525 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1528 if (this.brand !== '') {
1532 cls: 'navbar-brand',
1541 } else if (this.bar === false) {
1544 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1554 if (['tabs','pills'].indexOf(this.type)!==-1) {
1555 cfg.cn[0].cls += ' nav-' + this.type
1557 if (this.type!=='nav') {
1558 Roo.log('nav type must be nav/tabs/pills')
1560 cfg.cn[0].cls += ' navbar-nav'
1563 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1564 cfg.cn[0].cls += ' nav-' + this.arrangement;
1567 if (this.align === 'right') {
1568 cfg.cn[0].cls += ' navbar-right';
1571 cfg.cls += ' navbar-inverse';
1579 initEvents :function ()
1581 //Roo.log(this.el.select('.navbar-toggle',true));
1582 this.el.select('.navbar-toggle',true).on('click', function() {
1583 // Roo.log('click');
1584 this.el.select('.navbar-collapse',true).toggleClass('in');
1589 getChildContainer : function()
1591 if (this.bar === true) {
1592 return this.el.select('.collapse',true).first();
1610 * @class Roo.bootstrap.NavGroup
1611 * @extends Roo.bootstrap.Component
1612 * Bootstrap NavGroup class
1613 * @cfg {String} align left | right
1614 * @cfg {Boolean} inverse false | true
1617 * Create a new nav group
1618 * @param {Object} config The config object
1621 Roo.bootstrap.NavGroup = function(config){
1622 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1625 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1631 getAutoCreate : function(){
1632 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1636 cls: 'nav navbar-nav'
1639 if (this.parent().sidebar === true) {
1642 cls: 'dashboard-menu'
1648 if (this.form === true) {
1654 if (this.align === 'right') {
1655 cfg.cls += ' navbar-right';
1657 cfg.cls += ' navbar-left';
1662 if (this.align === 'right') {
1663 cfg.cls += ' navbar-right';
1667 cfg.cls += ' navbar-inverse';
1687 * @class Roo.bootstrap.Navbar.Item
1688 * @extends Roo.bootstrap.Component
1689 * Bootstrap Navbar.Button class
1690 * @cfg {String} href link to
1691 * @cfg {String} html content of button
1692 * @cfg {String} badge text inside badge
1693 * @cfg {String} glyphicon name of glyphicon
1696 * Create a new Navbar Button
1697 * @param {Object} config The config object
1699 Roo.bootstrap.Navbar.Item = function(config){
1700 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1703 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1711 getAutoCreate : function(){
1713 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1715 if (this.parent().parent().sidebar === true) {
1728 cfg.cn[0].html = this.html;
1732 this.cls += ' active';
1736 cfg.cn[0].cls += ' dropdown-toggle';
1737 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1741 cfg.cn[0].tag = 'a',
1742 cfg.cn[0].href = this.href;
1745 if (this.glyphicon) {
1746 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1762 if (this.glyphicon) {
1763 if(cfg.html){cfg.html = ' ' + this.html};
1767 cls: 'glyphicon glyphicon-' + this.glyphicon
1772 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1776 cfg.cn[0].html += " <span class='caret'></span>";
1777 //}else if (!this.href) {
1778 // cfg.cn[0].tag='p';
1779 // cfg.cn[0].cls='navbar-text';
1782 cfg.cn[0].href=this.href||'#';
1783 cfg.cn[0].html=this.html;
1786 if (this.badge !== '') {
1789 cfg.cn[0].html + ' ',
1802 initEvents: function() {
1803 // Roo.log('init events?');
1804 // Roo.log(this.el.dom);
1805 this.el.select('a',true).on('click',
1807 this.fireEvent('click', this);
1824 * @class Roo.bootstrap.Row
1825 * @extends Roo.bootstrap.Component
1826 * Bootstrap Row class (contains columns...)
1830 * @param {Object} config The config object
1833 Roo.bootstrap.Row = function(config){
1834 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1837 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1839 getAutoCreate : function(){
1858 * @class Roo.bootstrap.Element
1859 * @extends Roo.bootstrap.Component
1860 * Bootstrap Element class
1861 * @cfg {String} html contents of the element
1862 * @cfg {String} tag tag of the element
1863 * @cfg {String} cls class of the element
1866 * Create a new Element
1867 * @param {Object} config The config object
1870 Roo.bootstrap.Element = function(config){
1871 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1874 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1881 getAutoCreate : function(){
1904 * @class Roo.bootstrap.Pagination
1905 * @extends Roo.bootstrap.Component
1906 * Bootstrap Pagination class
1907 * @cfg {String} size xs | sm | md | lg
1908 * @cfg {Boolean} inverse false | true
1909 * @cfg {Number} from pagination starting number
1910 * @cfg {Number} to pagination ending number
1911 * @cfg {String} align empty or left | right
1912 * @cfg {Number} active active page number
1915 * Create a new Pagination
1916 * @param {Object} config The config object
1919 Roo.bootstrap.Pagination = function(config){
1920 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1923 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1933 getAutoCreate : function(){
1940 cfg.cls += ' inverse';
1958 var from=this.from>0?this.from:1;
1959 var to=this.to-from<=10?this.to:from+10;
1960 var active=this.active>=from&&this.active<=to?this.active:null;
1961 for (var i=from;i<=to;i++) {
1965 cls: active===i?'active':'',
2006 * @class Roo.bootstrap.Slider
2007 * @extends Roo.bootstrap.Component
2008 * Bootstrap Slider class
2011 * Create a new Slider
2012 * @param {Object} config The config object
2015 Roo.bootstrap.Slider = function(config){
2016 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2019 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2021 getAutoCreate : function(){
2025 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2029 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2047 * @class Roo.bootstrap.Table
2048 * @extends Roo.bootstrap.Component
2049 * Bootstrap Table class
2052 * Create a new Table
2053 * @param {Object} config The config object
2056 Roo.bootstrap.Table = function(config){
2057 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2060 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2065 getAutoCreate : function(){
2066 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2098 * @class Roo.bootstrap.TableCell
2099 * @extends Roo.bootstrap.Component
2100 * Bootstrap TableCell class
2103 * Create a new TableCell
2104 * @param {Object} config The config object
2107 Roo.bootstrap.TableCell = function(config){
2108 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2111 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2113 getAutoCreate : function(){
2114 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2141 * @class Roo.bootstrap.TableRow
2142 * @extends Roo.bootstrap.Component
2143 * Bootstrap TableRow class
2146 * Create a new TableRow
2147 * @param {Object} config The config object
2150 Roo.bootstrap.TableRow = function(config){
2151 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2154 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2156 getAutoCreate : function(){
2157 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2172 * Ext JS Library 1.1.1
2173 * Copyright(c) 2006-2007, Ext JS, LLC.
2175 * Originally Released Under LGPL - original licence link has changed is not relivant.
2178 * <script type="text/javascript">
2181 // as we use this in bootstrap.
2182 Roo.namespace('Roo.form');
2184 * @class Roo.form.Action
2185 * Internal Class used to handle form actions
2187 * @param {Roo.form.BasicForm} el The form element or its id
2188 * @param {Object} config Configuration options
2193 // define the action interface
2194 Roo.form.Action = function(form, options){
2196 this.options = options || {};
2199 * Client Validation Failed
2202 Roo.form.Action.CLIENT_INVALID = 'client';
2204 * Server Validation Failed
2207 Roo.form.Action.SERVER_INVALID = 'server';
2209 * Connect to Server Failed
2212 Roo.form.Action.CONNECT_FAILURE = 'connect';
2214 * Reading Data from Server Failed
2217 Roo.form.Action.LOAD_FAILURE = 'load';
2219 Roo.form.Action.prototype = {
2221 failureType : undefined,
2222 response : undefined,
2226 run : function(options){
2231 success : function(response){
2236 handleResponse : function(response){
2240 // default connection failure
2241 failure : function(response){
2243 this.response = response;
2244 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2245 this.form.afterAction(this, false);
2248 processResponse : function(response){
2249 this.response = response;
2250 if(!response.responseText){
2253 this.result = this.handleResponse(response);
2257 // utility functions used internally
2258 getUrl : function(appendParams){
2259 var url = this.options.url || this.form.url || this.form.el.dom.action;
2261 var p = this.getParams();
2263 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2269 getMethod : function(){
2270 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2273 getParams : function(){
2274 var bp = this.form.baseParams;
2275 var p = this.options.params;
2277 if(typeof p == "object"){
2278 p = Roo.urlEncode(Roo.applyIf(p, bp));
2279 }else if(typeof p == 'string' && bp){
2280 p += '&' + Roo.urlEncode(bp);
2283 p = Roo.urlEncode(bp);
2288 createCallback : function(){
2290 success: this.success,
2291 failure: this.failure,
2293 timeout: (this.form.timeout*1000),
2294 upload: this.form.fileUpload ? this.success : undefined
2299 Roo.form.Action.Submit = function(form, options){
2300 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2303 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2306 haveProgress : false,
2307 uploadComplete : false,
2309 // uploadProgress indicator.
2310 uploadProgress : function()
2312 if (!this.form.progressUrl) {
2316 if (!this.haveProgress) {
2317 Roo.MessageBox.progress("Uploading", "Uploading");
2319 if (this.uploadComplete) {
2320 Roo.MessageBox.hide();
2324 this.haveProgress = true;
2326 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2328 var c = new Roo.data.Connection();
2330 url : this.form.progressUrl,
2335 success : function(req){
2336 //console.log(data);
2340 rdata = Roo.decode(req.responseText)
2342 Roo.log("Invalid data from server..");
2346 if (!rdata || !rdata.success) {
2348 Roo.MessageBox.alert(Roo.encode(rdata));
2351 var data = rdata.data;
2353 if (this.uploadComplete) {
2354 Roo.MessageBox.hide();
2359 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2360 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2363 this.uploadProgress.defer(2000,this);
2366 failure: function(data) {
2367 Roo.log('progress url failed ');
2378 // run get Values on the form, so it syncs any secondary forms.
2379 this.form.getValues();
2381 var o = this.options;
2382 var method = this.getMethod();
2383 var isPost = method == 'POST';
2384 if(o.clientValidation === false || this.form.isValid()){
2386 if (this.form.progressUrl) {
2387 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2388 (new Date() * 1) + '' + Math.random());
2393 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2394 form:this.form.el.dom,
2395 url:this.getUrl(!isPost),
2397 params:isPost ? this.getParams() : null,
2398 isUpload: this.form.fileUpload
2401 this.uploadProgress();
2403 }else if (o.clientValidation !== false){ // client validation failed
2404 this.failureType = Roo.form.Action.CLIENT_INVALID;
2405 this.form.afterAction(this, false);
2409 success : function(response)
2411 this.uploadComplete= true;
2412 if (this.haveProgress) {
2413 Roo.MessageBox.hide();
2417 var result = this.processResponse(response);
2418 if(result === true || result.success){
2419 this.form.afterAction(this, true);
2423 this.form.markInvalid(result.errors);
2424 this.failureType = Roo.form.Action.SERVER_INVALID;
2426 this.form.afterAction(this, false);
2428 failure : function(response)
2430 this.uploadComplete= true;
2431 if (this.haveProgress) {
2432 Roo.MessageBox.hide();
2435 this.response = response;
2436 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2437 this.form.afterAction(this, false);
2440 handleResponse : function(response){
2441 if(this.form.errorReader){
2442 var rs = this.form.errorReader.read(response);
2445 for(var i = 0, len = rs.records.length; i < len; i++) {
2446 var r = rs.records[i];
2450 if(errors.length < 1){
2454 success : rs.success,
2460 ret = Roo.decode(response.responseText);
2464 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2474 Roo.form.Action.Load = function(form, options){
2475 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2476 this.reader = this.form.reader;
2479 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2484 Roo.Ajax.request(Roo.apply(
2485 this.createCallback(), {
2486 method:this.getMethod(),
2487 url:this.getUrl(false),
2488 params:this.getParams()
2492 success : function(response){
2494 var result = this.processResponse(response);
2495 if(result === true || !result.success || !result.data){
2496 this.failureType = Roo.form.Action.LOAD_FAILURE;
2497 this.form.afterAction(this, false);
2500 this.form.clearInvalid();
2501 this.form.setValues(result.data);
2502 this.form.afterAction(this, true);
2505 handleResponse : function(response){
2506 if(this.form.reader){
2507 var rs = this.form.reader.read(response);
2508 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2510 success : rs.success,
2514 return Roo.decode(response.responseText);
2518 Roo.form.Action.ACTION_TYPES = {
2519 'load' : Roo.form.Action.Load,
2520 'submit' : Roo.form.Action.Submit
2529 * @class Roo.bootstrap.Form
2530 * @extends Roo.bootstrap.Component
2531 * Bootstrap Form class
2532 * @cfg {String} method GET | POST (default POST)
2533 * @cfg {String} labelAlign top | left (default top)
2534 * @cfg {String} align left | right - for navbars
2539 * @param {Object} config The config object
2543 Roo.bootstrap.Form = function(config){
2544 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2547 * @event clientvalidation
2548 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2549 * @param {Form} this
2550 * @param {Boolean} valid true if the form has passed client-side validation
2552 clientvalidation: true,
2554 * @event beforeaction
2555 * Fires before any action is performed. Return false to cancel the action.
2556 * @param {Form} this
2557 * @param {Action} action The action to be performed
2561 * @event actionfailed
2562 * Fires when an action fails.
2563 * @param {Form} this
2564 * @param {Action} action The action that failed
2566 actionfailed : true,
2568 * @event actioncomplete
2569 * Fires when an action is completed.
2570 * @param {Form} this
2571 * @param {Action} action The action that completed
2573 actioncomplete : true
2578 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2581 * @cfg {String} method
2582 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2587 * The URL to use for form actions if one isn't supplied in the action options.
2590 * @cfg {Boolean} fileUpload
2591 * Set to true if this form is a file upload.
2595 * @cfg {Object} baseParams
2596 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2600 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2604 * @cfg {Sting} align (left|right) for navbar forms
2609 activeAction : null,
2612 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2613 * element by passing it or its id or mask the form itself by passing in true.
2616 waitMsgTarget : false,
2621 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2622 * element by passing it or its id or mask the form itself by passing in true.
2626 getAutoCreate : function(){
2630 method : this.method || 'POST',
2631 id : this.id || Roo.id(),
2634 if (this.parent().xtype.match(/^Nav/)) {
2635 cfg.cls = 'navbar-form navbar-' + this.align;
2639 if (this.labelAlign == 'left' ) {
2640 cfg.cls += ' form-horizontal';
2646 initEvents : function()
2648 this.el.on('submit', this.onSubmit, this);
2653 onSubmit : function(e){
2658 * Returns true if client-side validation on the form is successful.
2661 isValid : function(){
2662 var items = this.getItems();
2664 items.each(function(f){
2673 * Returns true if any fields in this form have changed since their original load.
2676 isDirty : function(){
2678 var items = this.getItems();
2679 items.each(function(f){
2689 * Performs a predefined action (submit or load) or custom actions you define on this form.
2690 * @param {String} actionName The name of the action type
2691 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2692 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2693 * accept other config options):
2695 Property Type Description
2696 ---------------- --------------- ----------------------------------------------------------------------------------
2697 url String The url for the action (defaults to the form's url)
2698 method String The form method to use (defaults to the form's method, or POST if not defined)
2699 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2700 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2701 validate the form on the client (defaults to false)
2703 * @return {BasicForm} this
2705 doAction : function(action, options){
2706 if(typeof action == 'string'){
2707 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2709 if(this.fireEvent('beforeaction', this, action) !== false){
2710 this.beforeAction(action);
2711 action.run.defer(100, action);
2717 beforeAction : function(action){
2718 var o = action.options;
2720 // not really supported yet.. ??
2722 //if(this.waitMsgTarget === true){
2723 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2724 //}else if(this.waitMsgTarget){
2725 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2726 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2728 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2734 afterAction : function(action, success){
2735 this.activeAction = null;
2736 var o = action.options;
2738 //if(this.waitMsgTarget === true){
2740 //}else if(this.waitMsgTarget){
2741 // this.waitMsgTarget.unmask();
2743 // Roo.MessageBox.updateProgress(1);
2744 // Roo.MessageBox.hide();
2751 Roo.callback(o.success, o.scope, [this, action]);
2752 this.fireEvent('actioncomplete', this, action);
2756 // failure condition..
2757 // we have a scenario where updates need confirming.
2758 // eg. if a locking scenario exists..
2759 // we look for { errors : { needs_confirm : true }} in the response.
2761 (typeof(action.result) != 'undefined') &&
2762 (typeof(action.result.errors) != 'undefined') &&
2763 (typeof(action.result.errors.needs_confirm) != 'undefined')
2766 Roo.log("not supported yet");
2769 Roo.MessageBox.confirm(
2770 "Change requires confirmation",
2771 action.result.errorMsg,
2776 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2786 Roo.callback(o.failure, o.scope, [this, action]);
2787 // show an error message if no failed handler is set..
2788 if (!this.hasListener('actionfailed')) {
2789 Roo.log("need to add dialog support");
2791 Roo.MessageBox.alert("Error",
2792 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2793 action.result.errorMsg :
2794 "Saving Failed, please check your entries or try again"
2799 this.fireEvent('actionfailed', this, action);
2804 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2805 * @param {String} id The value to search for
2808 findField : function(id){
2809 var items = this.getItems();
2810 var field = items.get(id);
2812 items.each(function(f){
2813 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2820 return field || null;
2823 * Mark fields in this form invalid in bulk.
2824 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2825 * @return {BasicForm} this
2827 markInvalid : function(errors){
2828 if(errors instanceof Array){
2829 for(var i = 0, len = errors.length; i < len; i++){
2830 var fieldError = errors[i];
2831 var f = this.findField(fieldError.id);
2833 f.markInvalid(fieldError.msg);
2839 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2840 field.markInvalid(errors[id]);
2844 //Roo.each(this.childForms || [], function (f) {
2845 // f.markInvalid(errors);
2852 * Set values for fields in this form in bulk.
2853 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2854 * @return {BasicForm} this
2856 setValues : function(values){
2857 if(values instanceof Array){ // array of objects
2858 for(var i = 0, len = values.length; i < len; i++){
2860 var f = this.findField(v.id);
2862 f.setValue(v.value);
2863 if(this.trackResetOnLoad){
2864 f.originalValue = f.getValue();
2868 }else{ // object hash
2871 if(typeof values[id] != 'function' && (field = this.findField(id))){
2873 if (field.setFromData &&
2875 field.displayField &&
2876 // combos' with local stores can
2877 // be queried via setValue()
2878 // to set their value..
2879 (field.store && !field.store.isLocal)
2883 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2884 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2885 field.setFromData(sd);
2888 field.setValue(values[id]);
2892 if(this.trackResetOnLoad){
2893 field.originalValue = field.getValue();
2899 //Roo.each(this.childForms || [], function (f) {
2900 // f.setValues(values);
2907 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2908 * they are returned as an array.
2909 * @param {Boolean} asString
2912 getValues : function(asString){
2913 //if (this.childForms) {
2914 // copy values from the child forms
2915 // Roo.each(this.childForms, function (f) {
2916 // this.setValues(f.getValues());
2922 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2923 if(asString === true){
2926 return Roo.urlDecode(fs);
2930 * Returns the fields in this form as an object with key/value pairs.
2931 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2934 getFieldValues : function(with_hidden)
2936 var items = this.getItems();
2938 items.each(function(f){
2942 var v = f.getValue();
2943 if (f.inputType =='radio') {
2944 if (typeof(ret[f.getName()]) == 'undefined') {
2945 ret[f.getName()] = ''; // empty..
2948 if (!f.el.dom.checked) {
2956 // not sure if this supported any more..
2957 if ((typeof(v) == 'object') && f.getRawValue) {
2958 v = f.getRawValue() ; // dates..
2960 // combo boxes where name != hiddenName...
2961 if (f.name != f.getName()) {
2962 ret[f.name] = f.getRawValue();
2964 ret[f.getName()] = v;
2971 * Clears all invalid messages in this form.
2972 * @return {BasicForm} this
2974 clearInvalid : function(){
2975 var items = this.getItems();
2977 items.each(function(f){
2988 * @return {BasicForm} this
2991 var items = this.getItems();
2992 items.each(function(f){
2996 Roo.each(this.childForms || [], function (f) {
3003 getItems : function()
3005 var r=new Roo.util.MixedCollection(false, function(o){
3006 return o.id || (o.id = Roo.id());
3008 var iter = function(el) {
3015 Roo.each(el.items,function(e) {
3034 * Ext JS Library 1.1.1
3035 * Copyright(c) 2006-2007, Ext JS, LLC.
3037 * Originally Released Under LGPL - original licence link has changed is not relivant.
3040 * <script type="text/javascript">
3043 * @class Roo.form.VTypes
3044 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3047 Roo.form.VTypes = function(){
3048 // closure these in so they are only created once.
3049 var alpha = /^[a-zA-Z_]+$/;
3050 var alphanum = /^[a-zA-Z0-9_]+$/;
3051 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3052 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3054 // All these messages and functions are configurable
3057 * The function used to validate email addresses
3058 * @param {String} value The email address
3060 'email' : function(v){
3061 return email.test(v);
3064 * The error text to display when the email validation function returns false
3067 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3069 * The keystroke filter mask to be applied on email input
3072 'emailMask' : /[a-z0-9_\.\-@]/i,
3075 * The function used to validate URLs
3076 * @param {String} value The URL
3078 'url' : function(v){
3082 * The error text to display when the url validation function returns false
3085 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3088 * The function used to validate alpha values
3089 * @param {String} value The value
3091 'alpha' : function(v){
3092 return alpha.test(v);
3095 * The error text to display when the alpha validation function returns false
3098 'alphaText' : 'This field should only contain letters and _',
3100 * The keystroke filter mask to be applied on alpha input
3103 'alphaMask' : /[a-z_]/i,
3106 * The function used to validate alphanumeric values
3107 * @param {String} value The value
3109 'alphanum' : function(v){
3110 return alphanum.test(v);
3113 * The error text to display when the alphanumeric validation function returns false
3116 'alphanumText' : 'This field should only contain letters, numbers and _',
3118 * The keystroke filter mask to be applied on alphanumeric input
3121 'alphanumMask' : /[a-z0-9_]/i
3131 * @class Roo.bootstrap.Input
3132 * @extends Roo.bootstrap.Component
3133 * Bootstrap Input class
3134 * @cfg {Boolean} disabled is it disabled
3135 * @cfg {String} fieldLabel - the label associated
3136 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3137 * @cfg {String} name name of the input
3138 * @cfg {string} fieldLabel - the label associated
3139 * @cfg {string} inputType - input / file submit ...
3140 * @cfg {string} placeholder - placeholder to put in text.
3141 * @cfg {string} before - input group add on before
3142 * @cfg {string} after - input group add on after
3143 * @cfg {string} size - (lg|sm) or leave empty..
3144 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3145 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3146 * @cfg {Number} md colspan out of 12 for computer-sized screens
3147 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3148 * @cfg {string} value default value of the input
3149 * @cfg {Number} labelWidth set the width of label (0-12)
3153 * Create a new Input
3154 * @param {Object} config The config object
3157 Roo.bootstrap.Input = function(config){
3158 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3163 * Fires when this field receives input focus.
3164 * @param {Roo.form.Field} this
3169 * Fires when this field loses input focus.
3170 * @param {Roo.form.Field} this
3175 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3176 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3177 * @param {Roo.form.Field} this
3178 * @param {Roo.EventObject} e The event object
3183 * Fires just before the field blurs if the field value has changed.
3184 * @param {Roo.form.Field} this
3185 * @param {Mixed} newValue The new value
3186 * @param {Mixed} oldValue The original value
3191 * Fires after the field has been marked as invalid.
3192 * @param {Roo.form.Field} this
3193 * @param {String} msg The validation message
3198 * Fires after the field has been validated with no errors.
3199 * @param {Roo.form.Field} this
3204 * Fires after the key up
3205 * @param {Roo.form.Field} this
3206 * @param {Roo.EventObject} e The event Object
3212 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3214 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3215 automatic validation (defaults to "keyup").
3217 validationEvent : "keyup",
3219 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3221 validateOnBlur : true,
3223 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3225 validationDelay : 250,
3227 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3229 focusClass : "x-form-focus", // not needed???
3233 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3235 invalidClass : "has-error",
3238 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3240 selectOnFocus : false,
3243 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3247 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3252 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3254 disableKeyFilter : false,
3257 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3261 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3265 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3267 blankText : "This field is required",
3270 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3274 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3276 maxLength : Number.MAX_VALUE,
3278 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3280 minLengthText : "The minimum length for this field is {0}",
3282 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3284 maxLengthText : "The maximum length for this field is {0}",
3288 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3289 * If available, this function will be called only after the basic validators all return true, and will be passed the
3290 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3294 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3295 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3296 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3300 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3322 getAutoCreate : function(){
3324 var parent = this.parent();
3326 var align = parent.labelAlign;
3332 if(this.inputType != 'hidden'){
3333 cfg.cls = 'form-group' //input-group
3337 // cls: 'form-group' //input-group
3343 type : this.inputType,
3345 cls : 'form-control',
3346 placeholder : this.placeholder || ''
3350 input.name = this.name;
3353 input.cls += ' input-' + this.size;
3356 ['xs','sm','md','lg'].map(function(size){
3357 if (settings[size]) {
3358 cfg.cls += ' col-' + size + '-' + settings[size];
3362 var inputblock = input;
3364 if (this.before || this.after) {
3367 cls : 'input-group',
3371 inputblock.cn.push({
3373 cls : 'input-group-addon',
3377 inputblock.cn.push(input);
3379 inputblock.cn.push({
3381 cls : 'input-group-addon',
3389 Roo.log(this.fieldLabel.length);
3391 if (align ==='left' && this.fieldLabel.length) {
3392 Roo.log("left and has label");
3398 cls : 'control-label col-sm-' + this.labelWidth,
3399 html : this.fieldLabel
3403 cls : "col-sm-" + (12 - this.labelWidth),
3410 } else if ( this.fieldLabel.length) {
3416 //cls : 'input-group-addon',
3417 html : this.fieldLabel
3427 Roo.log(" no label && no align");
3440 if (this.disabled) {
3441 input.disabled=true;
3447 * return the real input element.
3449 inputEl: function ()
3451 return this.el.select('input.form-control',true).first();
3453 setDisabled : function(v)
3455 var i = this.inputEl().dom;
3457 i.removeAttribute('disabled');
3461 i.setAttribute('disabled','true');
3463 initEvents : function()
3466 this.inputEl().on("keydown" , this.fireKey, this);
3467 this.inputEl().on("focus", this.onFocus, this);
3468 this.inputEl().on("blur", this.onBlur, this);
3469 this.inputEl().relayEvent('keyup', this);
3471 // reference to original value for reset
3472 this.originalValue = this.getValue();
3473 //Roo.form.TextField.superclass.initEvents.call(this);
3474 if(this.validationEvent == 'keyup'){
3475 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3476 this.inputEl().on('keyup', this.filterValidation, this);
3478 else if(this.validationEvent !== false){
3479 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3482 if(this.selectOnFocus){
3483 this.on("focus", this.preFocus, this);
3486 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3487 this.inputEl().on("keypress", this.filterKeys, this);
3490 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3491 this.el.on("click", this.autoSize, this);
3494 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3495 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3499 filterValidation : function(e){
3500 if(!e.isNavKeyPress()){
3501 this.validationTask.delay(this.validationDelay);
3505 * Validates the field value
3506 * @return {Boolean} True if the value is valid, else false
3508 validate : function(){
3509 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3510 if(this.disabled || this.validateValue(this.getRawValue())){
3511 this.clearInvalid();
3519 * Validates a value according to the field's validation rules and marks the field as invalid
3520 * if the validation fails
3521 * @param {Mixed} value The value to validate
3522 * @return {Boolean} True if the value is valid, else false
3524 validateValue : function(value){
3525 if(value.length < 1) { // if it's blank
3526 if(this.allowBlank){
3527 this.clearInvalid();
3530 this.markInvalid(this.blankText);
3534 if(value.length < this.minLength){
3535 this.markInvalid(String.format(this.minLengthText, this.minLength));
3538 if(value.length > this.maxLength){
3539 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3543 var vt = Roo.form.VTypes;
3544 if(!vt[this.vtype](value, this)){
3545 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3549 if(typeof this.validator == "function"){
3550 var msg = this.validator(value);
3552 this.markInvalid(msg);
3556 if(this.regex && !this.regex.test(value)){
3557 this.markInvalid(this.regexText);
3566 fireKey : function(e){
3567 //Roo.log('field ' + e.getKey());
3568 if(e.isNavKeyPress()){
3569 this.fireEvent("specialkey", this, e);
3572 focus : function (selectText){
3574 this.inputEl().focus();
3575 if(selectText === true){
3576 this.inputEl().dom.select();
3582 onFocus : function(){
3583 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3584 // this.el.addClass(this.focusClass);
3587 this.hasFocus = true;
3588 this.startValue = this.getValue();
3589 this.fireEvent("focus", this);
3593 beforeBlur : Roo.emptyFn,
3597 onBlur : function(){
3599 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3600 //this.el.removeClass(this.focusClass);
3602 this.hasFocus = false;
3603 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3606 var v = this.getValue();
3607 if(String(v) !== String(this.startValue)){
3608 this.fireEvent('change', this, v, this.startValue);
3610 this.fireEvent("blur", this);
3614 * Resets the current field value to the originally loaded value and clears any validation messages
3617 this.setValue(this.originalValue);
3618 this.clearInvalid();
3621 * Returns the name of the field
3622 * @return {Mixed} name The name field
3624 getName: function(){
3628 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3629 * @return {Mixed} value The field value
3631 getValue : function(){
3632 var v = this.inputEl().getValue();
3636 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3637 * @return {Mixed} value The field value
3639 getRawValue : function(){
3640 var v = this.inputEl().getValue();
3646 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
3647 * @param {Mixed} value The value to set
3649 setRawValue : function(v){
3650 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3653 selectText : function(start, end){
3654 var v = this.getRawValue();
3656 start = start === undefined ? 0 : start;
3657 end = end === undefined ? v.length : end;
3658 var d = this.inputEl().dom;
3659 if(d.setSelectionRange){
3660 d.setSelectionRange(start, end);
3661 }else if(d.createTextRange){
3662 var range = d.createTextRange();
3663 range.moveStart("character", start);
3664 range.moveEnd("character", v.length-end);
3671 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3672 * @param {Mixed} value The value to set
3674 setValue : function(v){
3677 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3683 processValue : function(value){
3684 if(this.stripCharsRe){
3685 var newValue = value.replace(this.stripCharsRe, '');
3686 if(newValue !== value){
3687 this.setRawValue(newValue);
3694 preFocus : function(){
3696 if(this.selectOnFocus){
3697 this.inputEl().dom.select();
3700 filterKeys : function(e){
3702 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3705 var c = e.getCharCode(), cc = String.fromCharCode(c);
3706 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3709 if(!this.maskRe.test(cc)){
3714 * Clear any invalid styles/messages for this field
3716 clearInvalid : function(){
3718 if(!this.el || this.preventMark){ // not rendered
3721 this.el.removeClass(this.invalidClass);
3723 switch(this.msgTarget){
3725 this.el.dom.qtip = '';
3728 this.el.dom.title = '';
3732 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3737 this.errorIcon.dom.qtip = '';
3738 this.errorIcon.hide();
3739 this.un('resize', this.alignErrorIcon, this);
3743 var t = Roo.getDom(this.msgTarget);
3745 t.style.display = 'none';
3749 this.fireEvent('valid', this);
3752 * Mark this field as invalid
3753 * @param {String} msg The validation message
3755 markInvalid : function(msg){
3756 if(!this.el || this.preventMark){ // not rendered
3759 this.el.addClass(this.invalidClass);
3761 msg = msg || this.invalidText;
3762 switch(this.msgTarget){
3764 this.el.dom.qtip = msg;
3765 this.el.dom.qclass = 'x-form-invalid-tip';
3766 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3767 Roo.QuickTips.enable();
3771 this.el.dom.title = msg;
3775 var elp = this.el.findParent('.x-form-element', 5, true);
3776 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3777 this.errorEl.setWidth(elp.getWidth(true)-20);
3779 this.errorEl.update(msg);
3780 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3783 if(!this.errorIcon){
3784 var elp = this.el.findParent('.x-form-element', 5, true);
3785 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3787 this.alignErrorIcon();
3788 this.errorIcon.dom.qtip = msg;
3789 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3790 this.errorIcon.show();
3791 this.on('resize', this.alignErrorIcon, this);
3794 var t = Roo.getDom(this.msgTarget);
3796 t.style.display = this.msgDisplay;
3800 this.fireEvent('invalid', this, msg);
3803 SafariOnKeyDown : function(event)
3805 // this is a workaround for a password hang bug on chrome/ webkit.
3807 var isSelectAll = false;
3809 if(this.inputEl().dom.selectionEnd > 0){
3810 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3812 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3813 event.preventDefault();
3818 if(isSelectAll){ // backspace and delete key
3820 event.preventDefault();
3821 // this is very hacky as keydown always get's upper case.
3823 var cc = String.fromCharCode(event.getCharCode());
3824 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3836 * trigger field - base class for combo..
3841 * @class Roo.bootstrap.TriggerField
3842 * @extends Roo.bootstrap.Input
3843 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3844 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3845 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3846 * for which you can provide a custom implementation. For example:
3848 var trigger = new Roo.bootstrap.TriggerField();
3849 trigger.onTriggerClick = myTriggerFn;
3850 trigger.applyTo('my-field');
3853 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3854 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3855 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3856 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3858 * Create a new TriggerField.
3859 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3860 * to the base TextField)
3862 Roo.bootstrap.TriggerField = function(config){
3863 this.mimicing = false;
3864 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3867 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3869 * @cfg {String} triggerClass A CSS class to apply to the trigger
3872 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3876 /** @cfg {Boolean} grow @hide */
3877 /** @cfg {Number} growMin @hide */
3878 /** @cfg {Number} growMax @hide */
3884 autoSize: Roo.emptyFn,
3891 actionMode : 'wrap',
3895 getAutoCreate : function(){
3897 var parent = this.parent();
3899 var align = parent.labelAlign;
3904 cls: 'form-group' //input-group
3911 type : this.inputType,
3912 cls : 'form-control',
3913 autocomplete: 'off',
3914 placeholder : this.placeholder || ''
3918 input.name = this.name;
3921 input.cls += ' input-' + this.size;
3924 cls: 'combobox-container input-group',
3929 cls: 'form-hidden-field'
3934 cls : 'typeahead typeahead-long dropdown-menu',
3935 style : 'display:none'
3939 cls : 'input-group-addon btn dropdown-toggle',
3947 cls: 'combobox-clear',
3964 if (align ==='left' && this.fieldLabel.length) {
3968 Roo.log("left and has label");
3974 cls : 'col-sm-2 control-label',
3975 html : this.fieldLabel
3986 } else if ( this.fieldLabel.length) {
3992 //cls : 'input-group-addon',
3993 html : this.fieldLabel
4003 Roo.log(" no label && no align");
4010 ['xs','sm','md','lg'].map(function(size){
4011 if (settings[size]) {
4012 cfg.cls += ' col-' + size + '-' + settings[size];
4018 if (this.disabled) {
4019 input.disabled=true;
4028 onResize : function(w, h){
4029 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
4030 if(typeof w == 'number'){
4031 var x = w - this.trigger.getWidth();
4032 this.inputEl().setWidth(this.adjustWidth('input', x));
4033 this.trigger.setStyle('left', x+'px');
4038 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4041 getResizeEl : function(){
4042 return this.inputEl();
4046 getPositionEl : function(){
4047 return this.inputEl();
4051 alignErrorIcon : function(){
4052 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4056 initEvents : function(){
4058 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4059 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4061 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4062 if(this.hideTrigger){
4063 this.trigger.setDisplayed(false);
4065 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4066 //this.trigger.addClassOnOver('x-form-trigger-over');
4067 //this.trigger.addClassOnClick('x-form-trigger-click');
4070 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4075 initTrigger : function(){
4080 onDestroy : function(){
4082 this.trigger.removeAllListeners();
4083 // this.trigger.remove();
4086 // this.wrap.remove();
4088 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4092 onFocus : function(){
4093 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4096 this.wrap.addClass('x-trigger-wrap-focus');
4097 this.mimicing = true;
4098 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4099 if(this.monitorTab){
4100 this.el.on("keydown", this.checkTab, this);
4107 checkTab : function(e){
4108 if(e.getKey() == e.TAB){
4114 onBlur : function(){
4119 mimicBlur : function(e, t){
4121 if(!this.wrap.contains(t) && this.validateBlur()){
4128 triggerBlur : function(){
4129 this.mimicing = false;
4130 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4131 if(this.monitorTab){
4132 this.el.un("keydown", this.checkTab, this);
4134 //this.wrap.removeClass('x-trigger-wrap-focus');
4135 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4139 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4140 validateBlur : function(e, t){
4145 onDisable : function(){
4146 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4148 // this.wrap.addClass('x-item-disabled');
4153 onEnable : function(){
4154 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4156 // this.el.removeClass('x-item-disabled');
4161 onShow : function(){
4162 var ae = this.getActionEl();
4165 ae.dom.style.display = '';
4166 ae.dom.style.visibility = 'visible';
4172 onHide : function(){
4173 var ae = this.getActionEl();
4174 ae.dom.style.display = 'none';
4178 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4179 * by an implementing function.
4181 * @param {EventObject} e
4183 onTriggerClick : Roo.emptyFn
4187 * Ext JS Library 1.1.1
4188 * Copyright(c) 2006-2007, Ext JS, LLC.
4190 * Originally Released Under LGPL - original licence link has changed is not relivant.
4193 * <script type="text/javascript">
4198 * @class Roo.data.SortTypes
4200 * Defines the default sorting (casting?) comparison functions used when sorting data.
4202 Roo.data.SortTypes = {
4204 * Default sort that does nothing
4205 * @param {Mixed} s The value being converted
4206 * @return {Mixed} The comparison value
4213 * The regular expression used to strip tags
4217 stripTagsRE : /<\/?[^>]+>/gi,
4220 * Strips all HTML tags to sort on text only
4221 * @param {Mixed} s The value being converted
4222 * @return {String} The comparison value
4224 asText : function(s){
4225 return String(s).replace(this.stripTagsRE, "");
4229 * Strips all HTML tags to sort on text only - Case insensitive
4230 * @param {Mixed} s The value being converted
4231 * @return {String} The comparison value
4233 asUCText : function(s){
4234 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4238 * Case insensitive string
4239 * @param {Mixed} s The value being converted
4240 * @return {String} The comparison value
4242 asUCString : function(s) {
4243 return String(s).toUpperCase();
4248 * @param {Mixed} s The value being converted
4249 * @return {Number} The comparison value
4251 asDate : function(s) {
4255 if(s instanceof Date){
4258 return Date.parse(String(s));
4263 * @param {Mixed} s The value being converted
4264 * @return {Float} The comparison value
4266 asFloat : function(s) {
4267 var val = parseFloat(String(s).replace(/,/g, ""));
4268 if(isNaN(val)) val = 0;
4274 * @param {Mixed} s The value being converted
4275 * @return {Number} The comparison value
4277 asInt : function(s) {
4278 var val = parseInt(String(s).replace(/,/g, ""));
4279 if(isNaN(val)) val = 0;
4284 * Ext JS Library 1.1.1
4285 * Copyright(c) 2006-2007, Ext JS, LLC.
4287 * Originally Released Under LGPL - original licence link has changed is not relivant.
4290 * <script type="text/javascript">
4294 * @class Roo.data.Record
4295 * Instances of this class encapsulate both record <em>definition</em> information, and record
4296 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4297 * to access Records cached in an {@link Roo.data.Store} object.<br>
4299 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4300 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4303 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4305 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4306 * {@link #create}. The parameters are the same.
4307 * @param {Array} data An associative Array of data values keyed by the field name.
4308 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4309 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4310 * not specified an integer id is generated.
4312 Roo.data.Record = function(data, id){
4313 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4318 * Generate a constructor for a specific record layout.
4319 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4320 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4321 * Each field definition object may contain the following properties: <ul>
4322 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4323 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4324 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4325 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4326 * is being used, then this is a string containing the javascript expression to reference the data relative to
4327 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4328 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4329 * this may be omitted.</p></li>
4330 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4331 * <ul><li>auto (Default, implies no conversion)</li>
4336 * <li>date</li></ul></p></li>
4337 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4338 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4339 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4340 * by the Reader into an object that will be stored in the Record. It is passed the
4341 * following parameters:<ul>
4342 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4344 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4346 * <br>usage:<br><pre><code>
4347 var TopicRecord = Roo.data.Record.create(
4348 {name: 'title', mapping: 'topic_title'},
4349 {name: 'author', mapping: 'username'},
4350 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4351 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4352 {name: 'lastPoster', mapping: 'user2'},
4353 {name: 'excerpt', mapping: 'post_text'}
4356 var myNewRecord = new TopicRecord({
4357 title: 'Do my job please',
4360 lastPost: new Date(),
4361 lastPoster: 'Animal',
4362 excerpt: 'No way dude!'
4364 myStore.add(myNewRecord);
4369 Roo.data.Record.create = function(o){
4371 f.superclass.constructor.apply(this, arguments);
4373 Roo.extend(f, Roo.data.Record);
4374 var p = f.prototype;
4375 p.fields = new Roo.util.MixedCollection(false, function(field){
4378 for(var i = 0, len = o.length; i < len; i++){
4379 p.fields.add(new Roo.data.Field(o[i]));
4381 f.getField = function(name){
4382 return p.fields.get(name);
4387 Roo.data.Record.AUTO_ID = 1000;
4388 Roo.data.Record.EDIT = 'edit';
4389 Roo.data.Record.REJECT = 'reject';
4390 Roo.data.Record.COMMIT = 'commit';
4392 Roo.data.Record.prototype = {
4394 * Readonly flag - true if this record has been modified.
4403 join : function(store){
4408 * Set the named field to the specified value.
4409 * @param {String} name The name of the field to set.
4410 * @param {Object} value The value to set the field to.
4412 set : function(name, value){
4413 if(this.data[name] == value){
4420 if(typeof this.modified[name] == 'undefined'){
4421 this.modified[name] = this.data[name];
4423 this.data[name] = value;
4424 if(!this.editing && this.store){
4425 this.store.afterEdit(this);
4430 * Get the value of the named field.
4431 * @param {String} name The name of the field to get the value of.
4432 * @return {Object} The value of the field.
4434 get : function(name){
4435 return this.data[name];
4439 beginEdit : function(){
4440 this.editing = true;
4445 cancelEdit : function(){
4446 this.editing = false;
4447 delete this.modified;
4451 endEdit : function(){
4452 this.editing = false;
4453 if(this.dirty && this.store){
4454 this.store.afterEdit(this);
4459 * Usually called by the {@link Roo.data.Store} which owns the Record.
4460 * Rejects all changes made to the Record since either creation, or the last commit operation.
4461 * Modified fields are reverted to their original values.
4463 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4464 * of reject operations.
4466 reject : function(){
4467 var m = this.modified;
4469 if(typeof m[n] != "function"){
4470 this.data[n] = m[n];
4474 delete this.modified;
4475 this.editing = false;
4477 this.store.afterReject(this);
4482 * Usually called by the {@link Roo.data.Store} which owns the Record.
4483 * Commits all changes made to the Record since either creation, or the last commit operation.
4485 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4486 * of commit operations.
4488 commit : function(){
4490 delete this.modified;
4491 this.editing = false;
4493 this.store.afterCommit(this);
4498 hasError : function(){
4499 return this.error != null;
4503 clearError : function(){
4508 * Creates a copy of this record.
4509 * @param {String} id (optional) A new record id if you don't want to use this record's id
4512 copy : function(newId) {
4513 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4517 * Ext JS Library 1.1.1
4518 * Copyright(c) 2006-2007, Ext JS, LLC.
4520 * Originally Released Under LGPL - original licence link has changed is not relivant.
4523 * <script type="text/javascript">
4529 * @class Roo.data.Store
4530 * @extends Roo.util.Observable
4531 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4532 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4534 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4535 * has no knowledge of the format of the data returned by the Proxy.<br>
4537 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4538 * instances from the data object. These records are cached and made available through accessor functions.
4540 * Creates a new Store.
4541 * @param {Object} config A config object containing the objects needed for the Store to access data,
4542 * and read the data into Records.
4544 Roo.data.Store = function(config){
4545 this.data = new Roo.util.MixedCollection(false);
4546 this.data.getKey = function(o){
4549 this.baseParams = {};
4556 "multisort" : "_multisort"
4559 if(config && config.data){
4560 this.inlineData = config.data;
4564 Roo.apply(this, config);
4566 if(this.reader){ // reader passed
4567 this.reader = Roo.factory(this.reader, Roo.data);
4568 this.reader.xmodule = this.xmodule || false;
4569 if(!this.recordType){
4570 this.recordType = this.reader.recordType;
4572 if(this.reader.onMetaChange){
4573 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4577 if(this.recordType){
4578 this.fields = this.recordType.prototype.fields;
4584 * @event datachanged
4585 * Fires when the data cache has changed, and a widget which is using this Store
4586 * as a Record cache should refresh its view.
4587 * @param {Store} this
4592 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4593 * @param {Store} this
4594 * @param {Object} meta The JSON metadata
4599 * Fires when Records have been added to the Store
4600 * @param {Store} this
4601 * @param {Roo.data.Record[]} records The array of Records added
4602 * @param {Number} index The index at which the record(s) were added
4607 * Fires when a Record has been removed from the Store
4608 * @param {Store} this
4609 * @param {Roo.data.Record} record The Record that was removed
4610 * @param {Number} index The index at which the record was removed
4615 * Fires when a Record has been updated
4616 * @param {Store} this
4617 * @param {Roo.data.Record} record The Record that was updated
4618 * @param {String} operation The update operation being performed. Value may be one of:
4620 Roo.data.Record.EDIT
4621 Roo.data.Record.REJECT
4622 Roo.data.Record.COMMIT
4628 * Fires when the data cache has been cleared.
4629 * @param {Store} this
4634 * Fires before a request is made for a new data object. If the beforeload handler returns false
4635 * the load action will be canceled.
4636 * @param {Store} this
4637 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4641 * @event beforeloadadd
4642 * Fires after a new set of Records has been loaded.
4643 * @param {Store} this
4644 * @param {Roo.data.Record[]} records The Records that were loaded
4645 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4647 beforeloadadd : true,
4650 * Fires after a new set of Records has been loaded, before they are added to the store.
4651 * @param {Store} this
4652 * @param {Roo.data.Record[]} records The Records that were loaded
4653 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4654 * @params {Object} return from reader
4658 * @event loadexception
4659 * Fires if an exception occurs in the Proxy during loading.
4660 * Called with the signature of the Proxy's "loadexception" event.
4661 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4664 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4665 * @param {Object} load options
4666 * @param {Object} jsonData from your request (normally this contains the Exception)
4668 loadexception : true
4672 this.proxy = Roo.factory(this.proxy, Roo.data);
4673 this.proxy.xmodule = this.xmodule || false;
4674 this.relayEvents(this.proxy, ["loadexception"]);
4676 this.sortToggle = {};
4677 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4679 Roo.data.Store.superclass.constructor.call(this);
4681 if(this.inlineData){
4682 this.loadData(this.inlineData);
4683 delete this.inlineData;
4687 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4689 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4690 * without a remote query - used by combo/forms at present.
4694 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4697 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4700 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4701 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4704 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4705 * on any HTTP request
4708 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4711 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4715 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4716 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4721 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4722 * loaded or when a record is removed. (defaults to false).
4724 pruneModifiedRecords : false,
4730 * Add Records to the Store and fires the add event.
4731 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4733 add : function(records){
4734 records = [].concat(records);
4735 for(var i = 0, len = records.length; i < len; i++){
4736 records[i].join(this);
4738 var index = this.data.length;
4739 this.data.addAll(records);
4740 this.fireEvent("add", this, records, index);
4744 * Remove a Record from the Store and fires the remove event.
4745 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4747 remove : function(record){
4748 var index = this.data.indexOf(record);
4749 this.data.removeAt(index);
4750 if(this.pruneModifiedRecords){
4751 this.modified.remove(record);
4753 this.fireEvent("remove", this, record, index);
4757 * Remove all Records from the Store and fires the clear event.
4759 removeAll : function(){
4761 if(this.pruneModifiedRecords){
4764 this.fireEvent("clear", this);
4768 * Inserts Records to the Store at the given index and fires the add event.
4769 * @param {Number} index The start index at which to insert the passed Records.
4770 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4772 insert : function(index, records){
4773 records = [].concat(records);
4774 for(var i = 0, len = records.length; i < len; i++){
4775 this.data.insert(index, records[i]);
4776 records[i].join(this);
4778 this.fireEvent("add", this, records, index);
4782 * Get the index within the cache of the passed Record.
4783 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4784 * @return {Number} The index of the passed Record. Returns -1 if not found.
4786 indexOf : function(record){
4787 return this.data.indexOf(record);
4791 * Get the index within the cache of the Record with the passed id.
4792 * @param {String} id The id of the Record to find.
4793 * @return {Number} The index of the Record. Returns -1 if not found.
4795 indexOfId : function(id){
4796 return this.data.indexOfKey(id);
4800 * Get the Record with the specified id.
4801 * @param {String} id The id of the Record to find.
4802 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4804 getById : function(id){
4805 return this.data.key(id);
4809 * Get the Record at the specified index.
4810 * @param {Number} index The index of the Record to find.
4811 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4813 getAt : function(index){
4814 return this.data.itemAt(index);
4818 * Returns a range of Records between specified indices.
4819 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4820 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4821 * @return {Roo.data.Record[]} An array of Records
4823 getRange : function(start, end){
4824 return this.data.getRange(start, end);
4828 storeOptions : function(o){
4829 o = Roo.apply({}, o);
4832 this.lastOptions = o;
4836 * Loads the Record cache from the configured Proxy using the configured Reader.
4838 * If using remote paging, then the first load call must specify the <em>start</em>
4839 * and <em>limit</em> properties in the options.params property to establish the initial
4840 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4842 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4843 * and this call will return before the new data has been loaded. Perform any post-processing
4844 * in a callback function, or in a "load" event handler.</strong>
4846 * @param {Object} options An object containing properties which control loading options:<ul>
4847 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4848 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4849 * passed the following arguments:<ul>
4850 * <li>r : Roo.data.Record[]</li>
4851 * <li>options: Options object from the load call</li>
4852 * <li>success: Boolean success indicator</li></ul></li>
4853 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4854 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4857 load : function(options){
4858 options = options || {};
4859 if(this.fireEvent("beforeload", this, options) !== false){
4860 this.storeOptions(options);
4861 var p = Roo.apply(options.params || {}, this.baseParams);
4862 // if meta was not loaded from remote source.. try requesting it.
4863 if (!this.reader.metaFromRemote) {
4866 if(this.sortInfo && this.remoteSort){
4867 var pn = this.paramNames;
4868 p[pn["sort"]] = this.sortInfo.field;
4869 p[pn["dir"]] = this.sortInfo.direction;
4871 if (this.multiSort) {
4872 var pn = this.paramNames;
4873 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4876 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4881 * Reloads the Record cache from the configured Proxy using the configured Reader and
4882 * the options from the last load operation performed.
4883 * @param {Object} options (optional) An object containing properties which may override the options
4884 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4885 * the most recently used options are reused).
4887 reload : function(options){
4888 this.load(Roo.applyIf(options||{}, this.lastOptions));
4892 // Called as a callback by the Reader during a load operation.
4893 loadRecords : function(o, options, success){
4894 if(!o || success === false){
4895 if(success !== false){
4896 this.fireEvent("load", this, [], options, o);
4898 if(options.callback){
4899 options.callback.call(options.scope || this, [], options, false);
4903 // if data returned failure - throw an exception.
4904 if (o.success === false) {
4905 // show a message if no listener is registered.
4906 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4907 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4909 // loadmask wil be hooked into this..
4910 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4913 var r = o.records, t = o.totalRecords || r.length;
4915 this.fireEvent("beforeloadadd", this, r, options, o);
4917 if(!options || options.add !== true){
4918 if(this.pruneModifiedRecords){
4921 for(var i = 0, len = r.length; i < len; i++){
4925 this.data = this.snapshot;
4926 delete this.snapshot;
4929 this.data.addAll(r);
4930 this.totalLength = t;
4932 this.fireEvent("datachanged", this);
4934 this.totalLength = Math.max(t, this.data.length+r.length);
4937 this.fireEvent("load", this, r, options, o);
4938 if(options.callback){
4939 options.callback.call(options.scope || this, r, options, true);
4945 * Loads data from a passed data block. A Reader which understands the format of the data
4946 * must have been configured in the constructor.
4947 * @param {Object} data The data block from which to read the Records. The format of the data expected
4948 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4949 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4951 loadData : function(o, append){
4952 var r = this.reader.readRecords(o);
4953 this.loadRecords(r, {add: append}, true);
4957 * Gets the number of cached records.
4959 * <em>If using paging, this may not be the total size of the dataset. If the data object
4960 * used by the Reader contains the dataset size, then the getTotalCount() function returns
4961 * the data set size</em>
4963 getCount : function(){
4964 return this.data.length || 0;
4968 * Gets the total number of records in the dataset as returned by the server.
4970 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4971 * the dataset size</em>
4973 getTotalCount : function(){
4974 return this.totalLength || 0;
4978 * Returns the sort state of the Store as an object with two properties:
4980 field {String} The name of the field by which the Records are sorted
4981 direction {String} The sort order, "ASC" or "DESC"
4984 getSortState : function(){
4985 return this.sortInfo;
4989 applySort : function(){
4990 if(this.sortInfo && !this.remoteSort){
4991 var s = this.sortInfo, f = s.field;
4992 var st = this.fields.get(f).sortType;
4993 var fn = function(r1, r2){
4994 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4995 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
4997 this.data.sort(s.direction, fn);
4998 if(this.snapshot && this.snapshot != this.data){
4999 this.snapshot.sort(s.direction, fn);
5005 * Sets the default sort column and order to be used by the next load operation.
5006 * @param {String} fieldName The name of the field to sort by.
5007 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5009 setDefaultSort : function(field, dir){
5010 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5015 * If remote sorting is used, the sort is performed on the server, and the cache is
5016 * reloaded. If local sorting is used, the cache is sorted internally.
5017 * @param {String} fieldName The name of the field to sort by.
5018 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5020 sort : function(fieldName, dir){
5021 var f = this.fields.get(fieldName);
5023 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5025 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5026 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5031 this.sortToggle[f.name] = dir;
5032 this.sortInfo = {field: f.name, direction: dir};
5033 if(!this.remoteSort){
5035 this.fireEvent("datachanged", this);
5037 this.load(this.lastOptions);
5042 * Calls the specified function for each of the Records in the cache.
5043 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5044 * Returning <em>false</em> aborts and exits the iteration.
5045 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5047 each : function(fn, scope){
5048 this.data.each(fn, scope);
5052 * Gets all records modified since the last commit. Modified records are persisted across load operations
5053 * (e.g., during paging).
5054 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5056 getModifiedRecords : function(){
5057 return this.modified;
5061 createFilterFn : function(property, value, anyMatch){
5062 if(!value.exec){ // not a regex
5063 value = String(value);
5064 if(value.length == 0){
5067 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5070 return value.test(r.data[property]);
5075 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5076 * @param {String} property A field on your records
5077 * @param {Number} start The record index to start at (defaults to 0)
5078 * @param {Number} end The last record index to include (defaults to length - 1)
5079 * @return {Number} The sum
5081 sum : function(property, start, end){
5082 var rs = this.data.items, v = 0;
5084 end = (end || end === 0) ? end : rs.length-1;
5086 for(var i = start; i <= end; i++){
5087 v += (rs[i].data[property] || 0);
5093 * Filter the records by a specified property.
5094 * @param {String} field A field on your records
5095 * @param {String/RegExp} value Either a string that the field
5096 * should start with or a RegExp to test against the field
5097 * @param {Boolean} anyMatch True to match any part not just the beginning
5099 filter : function(property, value, anyMatch){
5100 var fn = this.createFilterFn(property, value, anyMatch);
5101 return fn ? this.filterBy(fn) : this.clearFilter();
5105 * Filter by a function. The specified function will be called with each
5106 * record in this data source. If the function returns true the record is included,
5107 * otherwise it is filtered.
5108 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5109 * @param {Object} scope (optional) The scope of the function (defaults to this)
5111 filterBy : function(fn, scope){
5112 this.snapshot = this.snapshot || this.data;
5113 this.data = this.queryBy(fn, scope||this);
5114 this.fireEvent("datachanged", this);
5118 * Query the records by a specified property.
5119 * @param {String} field A field on your records
5120 * @param {String/RegExp} value Either a string that the field
5121 * should start with or a RegExp to test against the field
5122 * @param {Boolean} anyMatch True to match any part not just the beginning
5123 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5125 query : function(property, value, anyMatch){
5126 var fn = this.createFilterFn(property, value, anyMatch);
5127 return fn ? this.queryBy(fn) : this.data.clone();
5131 * Query by a function. The specified function will be called with each
5132 * record in this data source. If the function returns true the record is included
5134 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5135 * @param {Object} scope (optional) The scope of the function (defaults to this)
5136 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5138 queryBy : function(fn, scope){
5139 var data = this.snapshot || this.data;
5140 return data.filterBy(fn, scope||this);
5144 * Collects unique values for a particular dataIndex from this store.
5145 * @param {String} dataIndex The property to collect
5146 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5147 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5148 * @return {Array} An array of the unique values
5150 collect : function(dataIndex, allowNull, bypassFilter){
5151 var d = (bypassFilter === true && this.snapshot) ?
5152 this.snapshot.items : this.data.items;
5153 var v, sv, r = [], l = {};
5154 for(var i = 0, len = d.length; i < len; i++){
5155 v = d[i].data[dataIndex];
5157 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5166 * Revert to a view of the Record cache with no filtering applied.
5167 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5169 clearFilter : function(suppressEvent){
5170 if(this.snapshot && this.snapshot != this.data){
5171 this.data = this.snapshot;
5172 delete this.snapshot;
5173 if(suppressEvent !== true){
5174 this.fireEvent("datachanged", this);
5180 afterEdit : function(record){
5181 if(this.modified.indexOf(record) == -1){
5182 this.modified.push(record);
5184 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5188 afterReject : function(record){
5189 this.modified.remove(record);
5190 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5194 afterCommit : function(record){
5195 this.modified.remove(record);
5196 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5200 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5201 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5203 commitChanges : function(){
5204 var m = this.modified.slice(0);
5206 for(var i = 0, len = m.length; i < len; i++){
5212 * Cancel outstanding changes on all changed records.
5214 rejectChanges : function(){
5215 var m = this.modified.slice(0);
5217 for(var i = 0, len = m.length; i < len; i++){
5222 onMetaChange : function(meta, rtype, o){
5223 this.recordType = rtype;
5224 this.fields = rtype.prototype.fields;
5225 delete this.snapshot;
5226 this.sortInfo = meta.sortInfo || this.sortInfo;
5228 this.fireEvent('metachange', this, this.reader.meta);
5232 * Ext JS Library 1.1.1
5233 * Copyright(c) 2006-2007, Ext JS, LLC.
5235 * Originally Released Under LGPL - original licence link has changed is not relivant.
5238 * <script type="text/javascript">
5242 * @class Roo.data.SimpleStore
5243 * @extends Roo.data.Store
5244 * Small helper class to make creating Stores from Array data easier.
5245 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5246 * @cfg {Array} fields An array of field definition objects, or field name strings.
5247 * @cfg {Array} data The multi-dimensional array of data
5249 * @param {Object} config
5251 Roo.data.SimpleStore = function(config){
5252 Roo.data.SimpleStore.superclass.constructor.call(this, {
5254 reader: new Roo.data.ArrayReader({
5257 Roo.data.Record.create(config.fields)
5259 proxy : new Roo.data.MemoryProxy(config.data)
5263 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5265 * Ext JS Library 1.1.1
5266 * Copyright(c) 2006-2007, Ext JS, LLC.
5268 * Originally Released Under LGPL - original licence link has changed is not relivant.
5271 * <script type="text/javascript">
5276 * @extends Roo.data.Store
5277 * @class Roo.data.JsonStore
5278 * Small helper class to make creating Stores for JSON data easier. <br/>
5280 var store = new Roo.data.JsonStore({
5281 url: 'get-images.php',
5283 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5286 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5287 * JsonReader and HttpProxy (unless inline data is provided).</b>
5288 * @cfg {Array} fields An array of field definition objects, or field name strings.
5290 * @param {Object} config
5292 Roo.data.JsonStore = function(c){
5293 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5294 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5295 reader: new Roo.data.JsonReader(c, c.fields)
5298 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5300 * Ext JS Library 1.1.1
5301 * Copyright(c) 2006-2007, Ext JS, LLC.
5303 * Originally Released Under LGPL - original licence link has changed is not relivant.
5306 * <script type="text/javascript">
5310 Roo.data.Field = function(config){
5311 if(typeof config == "string"){
5312 config = {name: config};
5314 Roo.apply(this, config);
5320 var st = Roo.data.SortTypes;
5321 // named sortTypes are supported, here we look them up
5322 if(typeof this.sortType == "string"){
5323 this.sortType = st[this.sortType];
5326 // set default sortType for strings and dates
5330 this.sortType = st.asUCString;
5333 this.sortType = st.asDate;
5336 this.sortType = st.none;
5341 var stripRe = /[\$,%]/g;
5343 // prebuilt conversion function for this field, instead of
5344 // switching every time we're reading a value
5346 var cv, dateFormat = this.dateFormat;
5351 cv = function(v){ return v; };
5354 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5358 return v !== undefined && v !== null && v !== '' ?
5359 parseInt(String(v).replace(stripRe, ""), 10) : '';
5364 return v !== undefined && v !== null && v !== '' ?
5365 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5370 cv = function(v){ return v === true || v === "true" || v == 1; };
5377 if(v instanceof Date){
5381 if(dateFormat == "timestamp"){
5382 return new Date(v*1000);
5384 return Date.parseDate(v, dateFormat);
5386 var parsed = Date.parse(v);
5387 return parsed ? new Date(parsed) : null;
5396 Roo.data.Field.prototype = {
5404 * Ext JS Library 1.1.1
5405 * Copyright(c) 2006-2007, Ext JS, LLC.
5407 * Originally Released Under LGPL - original licence link has changed is not relivant.
5410 * <script type="text/javascript">
5413 // Base class for reading structured data from a data source. This class is intended to be
5414 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5417 * @class Roo.data.DataReader
5418 * Base class for reading structured data from a data source. This class is intended to be
5419 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5422 Roo.data.DataReader = function(meta, recordType){
5426 this.recordType = recordType instanceof Array ?
5427 Roo.data.Record.create(recordType) : recordType;
5430 Roo.data.DataReader.prototype = {
5432 * Create an empty record
5433 * @param {Object} data (optional) - overlay some values
5434 * @return {Roo.data.Record} record created.
5436 newRow : function(d) {
5438 this.recordType.prototype.fields.each(function(c) {
5440 case 'int' : da[c.name] = 0; break;
5441 case 'date' : da[c.name] = new Date(); break;
5442 case 'float' : da[c.name] = 0.0; break;
5443 case 'boolean' : da[c.name] = false; break;
5444 default : da[c.name] = ""; break;
5448 return new this.recordType(Roo.apply(da, d));
5453 * Ext JS Library 1.1.1
5454 * Copyright(c) 2006-2007, Ext JS, LLC.
5456 * Originally Released Under LGPL - original licence link has changed is not relivant.
5459 * <script type="text/javascript">
5463 * @class Roo.data.DataProxy
5464 * @extends Roo.data.Observable
5465 * This class is an abstract base class for implementations which provide retrieval of
5466 * unformatted data objects.<br>
5468 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5469 * (of the appropriate type which knows how to parse the data object) to provide a block of
5470 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5472 * Custom implementations must implement the load method as described in
5473 * {@link Roo.data.HttpProxy#load}.
5475 Roo.data.DataProxy = function(){
5479 * Fires before a network request is made to retrieve a data object.
5480 * @param {Object} This DataProxy object.
5481 * @param {Object} params The params parameter to the load function.
5486 * Fires before the load method's callback is called.
5487 * @param {Object} This DataProxy object.
5488 * @param {Object} o The data object.
5489 * @param {Object} arg The callback argument object passed to the load function.
5493 * @event loadexception
5494 * Fires if an Exception occurs during data retrieval.
5495 * @param {Object} This DataProxy object.
5496 * @param {Object} o The data object.
5497 * @param {Object} arg The callback argument object passed to the load function.
5498 * @param {Object} e The Exception.
5500 loadexception : true
5502 Roo.data.DataProxy.superclass.constructor.call(this);
5505 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5508 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5512 * Ext JS Library 1.1.1
5513 * Copyright(c) 2006-2007, Ext JS, LLC.
5515 * Originally Released Under LGPL - original licence link has changed is not relivant.
5518 * <script type="text/javascript">
5521 * @class Roo.data.MemoryProxy
5522 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5523 * to the Reader when its load method is called.
5525 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5527 Roo.data.MemoryProxy = function(data){
5531 Roo.data.MemoryProxy.superclass.constructor.call(this);
5535 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5537 * Load data from the requested source (in this case an in-memory
5538 * data object passed to the constructor), read the data object into
5539 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5540 * process that block using the passed callback.
5541 * @param {Object} params This parameter is not used by the MemoryProxy class.
5542 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5543 * object into a block of Roo.data.Records.
5544 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5545 * The function must be passed <ul>
5546 * <li>The Record block object</li>
5547 * <li>The "arg" argument from the load function</li>
5548 * <li>A boolean success indicator</li>
5550 * @param {Object} scope The scope in which to call the callback
5551 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5553 load : function(params, reader, callback, scope, arg){
5554 params = params || {};
5557 result = reader.readRecords(this.data);
5559 this.fireEvent("loadexception", this, arg, null, e);
5560 callback.call(scope, null, arg, false);
5563 callback.call(scope, result, arg, true);
5567 update : function(params, records){
5572 * Ext JS Library 1.1.1
5573 * Copyright(c) 2006-2007, Ext JS, LLC.
5575 * Originally Released Under LGPL - original licence link has changed is not relivant.
5578 * <script type="text/javascript">
5581 * @class Roo.data.HttpProxy
5582 * @extends Roo.data.DataProxy
5583 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5584 * configured to reference a certain URL.<br><br>
5586 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5587 * from which the running page was served.<br><br>
5589 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5591 * Be aware that to enable the browser to parse an XML document, the server must set
5592 * the Content-Type header in the HTTP response to "text/xml".
5594 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5595 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5596 * will be used to make the request.
5598 Roo.data.HttpProxy = function(conn){
5599 Roo.data.HttpProxy.superclass.constructor.call(this);
5600 // is conn a conn config or a real conn?
5602 this.useAjax = !conn || !conn.events;
5606 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5607 // thse are take from connection...
5610 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5613 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5614 * extra parameters to each request made by this object. (defaults to undefined)
5617 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5618 * to each request made by this object. (defaults to undefined)
5621 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5624 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5627 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5633 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5637 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5638 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5639 * a finer-grained basis than the DataProxy events.
5641 getConnection : function(){
5642 return this.useAjax ? Roo.Ajax : this.conn;
5646 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5647 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5648 * process that block using the passed callback.
5649 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5650 * for the request to the remote server.
5651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5652 * object into a block of Roo.data.Records.
5653 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5654 * The function must be passed <ul>
5655 * <li>The Record block object</li>
5656 * <li>The "arg" argument from the load function</li>
5657 * <li>A boolean success indicator</li>
5659 * @param {Object} scope The scope in which to call the callback
5660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5662 load : function(params, reader, callback, scope, arg){
5663 if(this.fireEvent("beforeload", this, params) !== false){
5665 params : params || {},
5667 callback : callback,
5672 callback : this.loadResponse,
5676 Roo.applyIf(o, this.conn);
5677 if(this.activeRequest){
5678 Roo.Ajax.abort(this.activeRequest);
5680 this.activeRequest = Roo.Ajax.request(o);
5682 this.conn.request(o);
5685 callback.call(scope||this, null, arg, false);
5690 loadResponse : function(o, success, response){
5691 delete this.activeRequest;
5693 this.fireEvent("loadexception", this, o, response);
5694 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5699 result = o.reader.read(response);
5701 this.fireEvent("loadexception", this, o, response, e);
5702 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5706 this.fireEvent("load", this, o, o.request.arg);
5707 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5711 update : function(dataSet){
5716 updateResponse : function(dataSet){
5721 * Ext JS Library 1.1.1
5722 * Copyright(c) 2006-2007, Ext JS, LLC.
5724 * Originally Released Under LGPL - original licence link has changed is not relivant.
5727 * <script type="text/javascript">
5731 * @class Roo.data.ScriptTagProxy
5732 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5733 * other than the originating domain of the running page.<br><br>
5735 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5736 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5738 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5739 * source code that is used as the source inside a <script> tag.<br><br>
5741 * In order for the browser to process the returned data, the server must wrap the data object
5742 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5743 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5744 * depending on whether the callback name was passed:
5747 boolean scriptTag = false;
5748 String cb = request.getParameter("callback");
5751 response.setContentType("text/javascript");
5753 response.setContentType("application/x-json");
5755 Writer out = response.getWriter();
5757 out.write(cb + "(");
5759 out.print(dataBlock.toJsonString());
5766 * @param {Object} config A configuration object.
5768 Roo.data.ScriptTagProxy = function(config){
5769 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5770 Roo.apply(this, config);
5771 this.head = document.getElementsByTagName("head")[0];
5774 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5776 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5778 * @cfg {String} url The URL from which to request the data object.
5781 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5785 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5786 * the server the name of the callback function set up by the load call to process the returned data object.
5787 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5788 * javascript output which calls this named function passing the data object as its only parameter.
5790 callbackParam : "callback",
5792 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5793 * name to the request.
5798 * Load data from the configured URL, read the data object into
5799 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5800 * process that block using the passed callback.
5801 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5802 * for the request to the remote server.
5803 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5804 * object into a block of Roo.data.Records.
5805 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5806 * The function must be passed <ul>
5807 * <li>The Record block object</li>
5808 * <li>The "arg" argument from the load function</li>
5809 * <li>A boolean success indicator</li>
5811 * @param {Object} scope The scope in which to call the callback
5812 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5814 load : function(params, reader, callback, scope, arg){
5815 if(this.fireEvent("beforeload", this, params) !== false){
5817 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5820 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5822 url += "&_dc=" + (new Date().getTime());
5824 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5827 cb : "stcCallback"+transId,
5828 scriptId : "stcScript"+transId,
5832 callback : callback,
5838 window[trans.cb] = function(o){
5839 conn.handleResponse(o, trans);
5842 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5844 if(this.autoAbort !== false){
5848 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5850 var script = document.createElement("script");
5851 script.setAttribute("src", url);
5852 script.setAttribute("type", "text/javascript");
5853 script.setAttribute("id", trans.scriptId);
5854 this.head.appendChild(script);
5858 callback.call(scope||this, null, arg, false);
5863 isLoading : function(){
5864 return this.trans ? true : false;
5868 * Abort the current server request.
5871 if(this.isLoading()){
5872 this.destroyTrans(this.trans);
5877 destroyTrans : function(trans, isLoaded){
5878 this.head.removeChild(document.getElementById(trans.scriptId));
5879 clearTimeout(trans.timeoutId);
5881 window[trans.cb] = undefined;
5883 delete window[trans.cb];
5886 // if hasn't been loaded, wait for load to remove it to prevent script error
5887 window[trans.cb] = function(){
5888 window[trans.cb] = undefined;
5890 delete window[trans.cb];
5897 handleResponse : function(o, trans){
5899 this.destroyTrans(trans, true);
5902 result = trans.reader.readRecords(o);
5904 this.fireEvent("loadexception", this, o, trans.arg, e);
5905 trans.callback.call(trans.scope||window, null, trans.arg, false);
5908 this.fireEvent("load", this, o, trans.arg);
5909 trans.callback.call(trans.scope||window, result, trans.arg, true);
5913 handleFailure : function(trans){
5915 this.destroyTrans(trans, false);
5916 this.fireEvent("loadexception", this, null, trans.arg);
5917 trans.callback.call(trans.scope||window, null, trans.arg, false);
5921 * Ext JS Library 1.1.1
5922 * Copyright(c) 2006-2007, Ext JS, LLC.
5924 * Originally Released Under LGPL - original licence link has changed is not relivant.
5927 * <script type="text/javascript">
5931 * @class Roo.data.JsonReader
5932 * @extends Roo.data.DataReader
5933 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5934 * based on mappings in a provided Roo.data.Record constructor.
5936 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5937 * in the reply previously.
5942 var RecordDef = Roo.data.Record.create([
5943 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5944 {name: 'occupation'} // This field will use "occupation" as the mapping.
5946 var myReader = new Roo.data.JsonReader({
5947 totalProperty: "results", // The property which contains the total dataset size (optional)
5948 root: "rows", // The property which contains an Array of row objects
5949 id: "id" // The property within each row object that provides an ID for the record (optional)
5953 * This would consume a JSON file like this:
5955 { 'results': 2, 'rows': [
5956 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5957 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5960 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5961 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5962 * paged from the remote server.
5963 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5964 * @cfg {String} root name of the property which contains the Array of row objects.
5965 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5967 * Create a new JsonReader
5968 * @param {Object} meta Metadata configuration options
5969 * @param {Object} recordType Either an Array of field definition objects,
5970 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5972 Roo.data.JsonReader = function(meta, recordType){
5975 // set some defaults:
5977 totalProperty: 'total',
5978 successProperty : 'success',
5983 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5985 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5988 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
5989 * Used by Store query builder to append _requestMeta to params.
5992 metaFromRemote : false,
5994 * This method is only used by a DataProxy which has retrieved data from a remote server.
5995 * @param {Object} response The XHR object which contains the JSON data in its responseText.
5996 * @return {Object} data A data block which is used by an Roo.data.Store object as
5997 * a cache of Roo.data.Records.
5999 read : function(response){
6000 var json = response.responseText;
6002 var o = /* eval:var:o */ eval("("+json+")");
6004 throw {message: "JsonReader.read: Json object not found"};
6010 this.metaFromRemote = true;
6011 this.meta = o.metaData;
6012 this.recordType = Roo.data.Record.create(o.metaData.fields);
6013 this.onMetaChange(this.meta, this.recordType, o);
6015 return this.readRecords(o);
6018 // private function a store will implement
6019 onMetaChange : function(meta, recordType, o){
6026 simpleAccess: function(obj, subsc) {
6033 getJsonAccessor: function(){
6035 return function(expr) {
6037 return(re.test(expr))
6038 ? new Function("obj", "return obj." + expr)
6048 * Create a data block containing Roo.data.Records from an XML document.
6049 * @param {Object} o An object which contains an Array of row objects in the property specified
6050 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6051 * which contains the total size of the dataset.
6052 * @return {Object} data A data block which is used by an Roo.data.Store object as
6053 * a cache of Roo.data.Records.
6055 readRecords : function(o){
6057 * After any data loads, the raw JSON data is available for further custom processing.
6061 var s = this.meta, Record = this.recordType,
6062 f = Record.prototype.fields, fi = f.items, fl = f.length;
6064 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6066 if(s.totalProperty) {
6067 this.getTotal = this.getJsonAccessor(s.totalProperty);
6069 if(s.successProperty) {
6070 this.getSuccess = this.getJsonAccessor(s.successProperty);
6072 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6074 var g = this.getJsonAccessor(s.id);
6075 this.getId = function(rec) {
6077 return (r === undefined || r === "") ? null : r;
6080 this.getId = function(){return null;};
6083 for(var jj = 0; jj < fl; jj++){
6085 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6086 this.ef[jj] = this.getJsonAccessor(map);
6090 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6091 if(s.totalProperty){
6092 var vt = parseInt(this.getTotal(o), 10);
6097 if(s.successProperty){
6098 var vs = this.getSuccess(o);
6099 if(vs === false || vs === 'false'){
6104 for(var i = 0; i < c; i++){
6107 var id = this.getId(n);
6108 for(var j = 0; j < fl; j++){
6110 var v = this.ef[j](n);
6112 Roo.log('missing convert for ' + f.name);
6116 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6118 var record = new Record(values, id);
6120 records[i] = record;
6126 totalRecords : totalRecords
6131 * Ext JS Library 1.1.1
6132 * Copyright(c) 2006-2007, Ext JS, LLC.
6134 * Originally Released Under LGPL - original licence link has changed is not relivant.
6137 * <script type="text/javascript">
6141 * @class Roo.data.ArrayReader
6142 * @extends Roo.data.DataReader
6143 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6144 * Each element of that Array represents a row of data fields. The
6145 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6146 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6150 var RecordDef = Roo.data.Record.create([
6151 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6152 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6154 var myReader = new Roo.data.ArrayReader({
6155 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6159 * This would consume an Array like this:
6161 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6163 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6165 * Create a new JsonReader
6166 * @param {Object} meta Metadata configuration options.
6167 * @param {Object} recordType Either an Array of field definition objects
6168 * as specified to {@link Roo.data.Record#create},
6169 * or an {@link Roo.data.Record} object
6170 * created using {@link Roo.data.Record#create}.
6172 Roo.data.ArrayReader = function(meta, recordType){
6173 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6176 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6178 * Create a data block containing Roo.data.Records from an XML document.
6179 * @param {Object} o An Array of row objects which represents the dataset.
6180 * @return {Object} data A data block which is used by an Roo.data.Store object as
6181 * a cache of Roo.data.Records.
6183 readRecords : function(o){
6184 var sid = this.meta ? this.meta.id : null;
6185 var recordType = this.recordType, fields = recordType.prototype.fields;
6188 for(var i = 0; i < root.length; i++){
6191 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6192 for(var j = 0, jlen = fields.length; j < jlen; j++){
6193 var f = fields.items[j];
6194 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6195 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6199 var record = new recordType(values, id);
6201 records[records.length] = record;
6205 totalRecords : records.length
6214 * @class Roo.bootstrap.ComboBox
6215 * @extends Roo.bootstrap.TriggerField
6216 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6218 * Create a new ComboBox.
6219 * @param {Object} config Configuration options
6221 Roo.bootstrap.ComboBox = function(config){
6222 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6226 * Fires when the dropdown list is expanded
6227 * @param {Roo.bootstrap.ComboBox} combo This combo box
6232 * Fires when the dropdown list is collapsed
6233 * @param {Roo.bootstrap.ComboBox} combo This combo box
6237 * @event beforeselect
6238 * Fires before a list item is selected. Return false to cancel the selection.
6239 * @param {Roo.bootstrap.ComboBox} combo This combo box
6240 * @param {Roo.data.Record} record The data record returned from the underlying store
6241 * @param {Number} index The index of the selected item in the dropdown list
6243 'beforeselect' : true,
6246 * Fires when a list item is selected
6247 * @param {Roo.bootstrap.ComboBox} combo This combo box
6248 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6249 * @param {Number} index The index of the selected item in the dropdown list
6253 * @event beforequery
6254 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6255 * The event object passed has these properties:
6256 * @param {Roo.bootstrap.ComboBox} combo This combo box
6257 * @param {String} query The query
6258 * @param {Boolean} forceAll true to force "all" query
6259 * @param {Boolean} cancel true to cancel the query
6260 * @param {Object} e The query event object
6262 'beforequery': true,
6265 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6266 * @param {Roo.bootstrap.ComboBox} combo This combo box
6271 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6272 * @param {Roo.bootstrap.ComboBox} combo This combo box
6273 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6281 this.selectedIndex = -1;
6282 if(this.mode == 'local'){
6283 if(config.queryDelay === undefined){
6284 this.queryDelay = 10;
6286 if(config.minChars === undefined){
6292 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6295 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6296 * rendering into an Roo.Editor, defaults to false)
6299 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6300 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6303 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6306 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6307 * the dropdown list (defaults to undefined, with no header element)
6311 * @cfg {String/Roo.Template} tpl The template to use to render the output
6315 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6317 listWidth: undefined,
6319 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6320 * mode = 'remote' or 'text' if mode = 'local')
6322 displayField: undefined,
6324 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6325 * mode = 'remote' or 'value' if mode = 'local').
6326 * Note: use of a valueField requires the user make a selection
6327 * in order for a value to be mapped.
6329 valueField: undefined,
6333 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6334 * field's data value (defaults to the underlying DOM element's name)
6336 hiddenName: undefined,
6338 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6342 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6344 selectedClass: 'active',
6347 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6351 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6352 * anchor positions (defaults to 'tl-bl')
6354 listAlign: 'tl-bl?',
6356 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6360 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
6361 * query specified by the allQuery config option (defaults to 'query')
6363 triggerAction: 'query',
6365 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6366 * (defaults to 4, does not apply if editable = false)
6370 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6371 * delay (typeAheadDelay) if it matches a known value (defaults to false)
6375 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6376 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6380 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6381 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
6385 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
6386 * when editable = true (defaults to false)
6388 selectOnFocus:false,
6390 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6392 queryParam: 'query',
6394 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
6395 * when mode = 'remote' (defaults to 'Loading...')
6397 loadingText: 'Loading...',
6399 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6403 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6407 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6408 * traditional select (defaults to true)
6412 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6416 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6420 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6421 * listWidth has a higher value)
6425 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6426 * allow the user to set arbitrary text into the field (defaults to false)
6428 forceSelection:false,
6430 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6431 * if typeAhead = true (defaults to 250)
6433 typeAheadDelay : 250,
6435 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6436 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6438 valueNotFoundText : undefined,
6440 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6445 * @cfg {Boolean} disableClear Disable showing of clear button.
6447 disableClear : false,
6449 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
6451 alwaysQuery : false,
6457 // element that contains real text value.. (when hidden is used..)
6460 initEvents: function(){
6463 throw "can not find store for combo";
6465 this.store = Roo.factory(this.store, Roo.data);
6469 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6472 if(this.hiddenName){
6474 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6476 this.hiddenField.dom.value =
6477 this.hiddenValue !== undefined ? this.hiddenValue :
6478 this.value !== undefined ? this.value : '';
6480 // prevent input submission
6481 this.el.dom.removeAttribute('name');
6482 this.hiddenField.dom.setAttribute('name', this.hiddenName);
6487 // this.el.dom.setAttribute('autocomplete', 'off');
6490 var cls = 'x-combo-list';
6491 this.list = this.el.select('ul',true).first();
6493 //this.list = new Roo.Layer({
6494 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6497 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6498 this.list.setWidth(lw);
6500 this.list.on('mouseover', this.onViewOver, this);
6501 this.list.on('mousemove', this.onViewMove, this);
6504 this.list.swallowEvent('mousewheel');
6505 this.assetHeight = 0;
6508 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6509 this.assetHeight += this.header.getHeight();
6512 this.innerList = this.list.createChild({cls:cls+'-inner'});
6513 this.innerList.on('mouseover', this.onViewOver, this);
6514 this.innerList.on('mousemove', this.onViewMove, this);
6515 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6517 if(this.allowBlank && !this.pageSize && !this.disableClear){
6518 this.footer = this.list.createChild({cls:cls+'-ft'});
6519 this.pageTb = new Roo.Toolbar(this.footer);
6523 this.footer = this.list.createChild({cls:cls+'-ft'});
6524 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6525 {pageSize: this.pageSize});
6529 if (this.pageTb && this.allowBlank && !this.disableClear) {
6531 this.pageTb.add(new Roo.Toolbar.Fill(), {
6532 cls: 'x-btn-icon x-btn-clear',
6538 _this.onSelect(false, -1);
6543 this.assetHeight += this.footer.getHeight();
6548 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6551 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6552 singleSelect:true, store: this.store, selectedClass: this.selectedClass
6554 //this.view.wrapEl.setDisplayed(false);
6555 this.view.on('click', this.onViewClick, this);
6559 this.store.on('beforeload', this.onBeforeLoad, this);
6560 this.store.on('load', this.onLoad, this);
6561 this.store.on('loadexception', this.onLoadException, this);
6564 this.resizer = new Roo.Resizable(this.list, {
6565 pinned:true, handles:'se'
6567 this.resizer.on('resize', function(r, w, h){
6568 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6570 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6571 this.restrictHeight();
6573 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6577 this.editable = true;
6578 this.setEditable(false);
6583 if (typeof(this.events.add.listeners) != 'undefined') {
6585 this.addicon = this.wrap.createChild(
6586 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
6588 this.addicon.on('click', function(e) {
6589 this.fireEvent('add', this);
6592 if (typeof(this.events.edit.listeners) != 'undefined') {
6594 this.editicon = this.wrap.createChild(
6595 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
6597 this.editicon.setStyle('margin-left', '40px');
6599 this.editicon.on('click', function(e) {
6601 // we fire even if inothing is selected..
6602 this.fireEvent('edit', this, this.lastData );
6609 this.keyNav = new Roo.KeyNav(this.inputEl(), {
6611 this.inKeyMode = true;
6615 "down" : function(e){
6616 if(!this.isExpanded()){
6617 this.onTriggerClick();
6619 this.inKeyMode = true;
6624 "enter" : function(e){
6629 "esc" : function(e){
6633 "tab" : function(e){
6634 this.onViewClick(false);
6635 this.fireEvent("specialkey", this, e);
6641 doRelay : function(foo, bar, hname){
6642 if(hname == 'down' || this.scope.isExpanded()){
6643 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6652 this.queryDelay = Math.max(this.queryDelay || 10,
6653 this.mode == 'local' ? 10 : 250);
6656 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6659 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6661 if(this.editable !== false){
6662 this.inputEl().on("keyup", this.onKeyUp, this);
6664 if(this.forceSelection){
6665 this.on('blur', this.doForce, this);
6669 onDestroy : function(){
6671 this.view.setStore(null);
6672 this.view.el.removeAllListeners();
6673 this.view.el.remove();
6674 this.view.purgeListeners();
6677 this.list.dom.innerHTML = '';
6680 this.store.un('beforeload', this.onBeforeLoad, this);
6681 this.store.un('load', this.onLoad, this);
6682 this.store.un('loadexception', this.onLoadException, this);
6684 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6688 fireKey : function(e){
6689 if(e.isNavKeyPress() && !this.list.isVisible()){
6690 this.fireEvent("specialkey", this, e);
6695 onResize: function(w, h){
6696 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6698 if(typeof w != 'number'){
6699 // we do not handle it!?!?
6702 var tw = this.trigger.getWidth();
6703 // tw += this.addicon ? this.addicon.getWidth() : 0;
6704 // tw += this.editicon ? this.editicon.getWidth() : 0;
6706 this.inputEl().setWidth( this.adjustWidth('input', x));
6708 //this.trigger.setStyle('left', x+'px');
6710 if(this.list && this.listWidth === undefined){
6711 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6712 this.list.setWidth(lw);
6713 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6721 * Allow or prevent the user from directly editing the field text. If false is passed,
6722 * the user will only be able to select from the items defined in the dropdown list. This method
6723 * is the runtime equivalent of setting the 'editable' config option at config time.
6724 * @param {Boolean} value True to allow the user to directly edit the field text
6726 setEditable : function(value){
6727 if(value == this.editable){
6730 this.editable = value;
6732 this.inputEl().dom.setAttribute('readOnly', true);
6733 this.inputEl().on('mousedown', this.onTriggerClick, this);
6734 this.inputEl().addClass('x-combo-noedit');
6736 this.inputEl().dom.setAttribute('readOnly', false);
6737 this.inputEl().un('mousedown', this.onTriggerClick, this);
6738 this.inputEl().removeClass('x-combo-noedit');
6743 onBeforeLoad : function(){
6747 //this.innerList.update(this.loadingText ?
6748 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6749 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6751 this.restrictHeight();
6752 this.selectedIndex = -1;
6756 onLoad : function(){
6760 if(this.store.getCount() > 0){
6762 this.restrictHeight();
6763 if(this.lastQuery == this.allQuery){
6765 this.inputEl().dom.select();
6767 if(!this.selectByValue(this.value, true)){
6768 this.select(0, true);
6772 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6773 this.taTask.delay(this.typeAheadDelay);
6777 this.onEmptyResults();
6782 onLoadException : function()
6785 Roo.log(this.store.reader.jsonData);
6786 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6788 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6794 onTypeAhead : function(){
6795 if(this.store.getCount() > 0){
6796 var r = this.store.getAt(0);
6797 var newValue = r.data[this.displayField];
6798 var len = newValue.length;
6799 var selStart = this.getRawValue().length;
6801 if(selStart != len){
6802 this.setRawValue(newValue);
6803 this.selectText(selStart, newValue.length);
6809 onSelect : function(record, index){
6810 if(this.fireEvent('beforeselect', this, record, index) !== false){
6811 this.setFromData(index > -1 ? record.data : false);
6813 this.fireEvent('select', this, record, index);
6818 * Returns the currently selected field value or empty string if no value is set.
6819 * @return {String} value The selected value
6821 getValue : function(){
6822 if(this.valueField){
6823 return typeof this.value != 'undefined' ? this.value : '';
6825 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6830 * Clears any text/value currently set in the field
6832 clearValue : function(){
6833 if(this.hiddenField){
6834 this.hiddenField.dom.value = '';
6837 this.setRawValue('');
6838 this.lastSelectionText = '';
6843 * Sets the specified value into the field. If the value finds a match, the corresponding record text
6844 * will be displayed in the field. If the value does not match the data value of an existing item,
6845 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6846 * Otherwise the field will be blank (although the value will still be set).
6847 * @param {String} value The value to match
6849 setValue : function(v){
6851 if(this.valueField){
6852 var r = this.findRecord(this.valueField, v);
6854 text = r.data[this.displayField];
6855 }else if(this.valueNotFoundText !== undefined){
6856 text = this.valueNotFoundText;
6859 this.lastSelectionText = text;
6860 if(this.hiddenField){
6861 this.hiddenField.dom.value = v;
6863 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6867 * @property {Object} the last set data for the element
6872 * Sets the value of the field based on a object which is related to the record format for the store.
6873 * @param {Object} value the value to set as. or false on reset?
6875 setFromData : function(o){
6876 var dv = ''; // display value
6877 var vv = ''; // value value..
6879 if (this.displayField) {
6880 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6882 // this is an error condition!!!
6883 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
6886 if(this.valueField){
6887 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6889 if(this.hiddenField){
6890 this.hiddenField.dom.value = vv;
6892 this.lastSelectionText = dv;
6893 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6897 // no hidden field.. - we store the value in 'value', but still display
6898 // display field!!!!
6899 this.lastSelectionText = dv;
6900 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6907 // overridden so that last data is reset..
6908 this.setValue(this.originalValue);
6909 this.clearInvalid();
6910 this.lastData = false;
6912 this.view.clearSelections();
6916 findRecord : function(prop, value){
6918 if(this.store.getCount() > 0){
6919 this.store.each(function(r){
6920 if(r.data[prop] == value){
6932 // returns hidden if it's set..
6933 if (!this.rendered) {return ''};
6934 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
6938 onViewMove : function(e, t){
6939 this.inKeyMode = false;
6943 onViewOver : function(e, t){
6944 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6947 var item = this.view.findItemFromChild(t);
6949 var index = this.view.indexOf(item);
6950 this.select(index, false);
6955 onViewClick : function(doFocus)
6957 var index = this.view.getSelectedIndexes()[0];
6958 var r = this.store.getAt(index);
6960 this.onSelect(r, index);
6962 if(doFocus !== false && !this.blockFocus){
6963 this.inputEl().focus();
6968 restrictHeight : function(){
6969 //this.innerList.dom.style.height = '';
6970 //var inner = this.innerList.dom;
6971 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6972 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6973 //this.list.beginUpdate();
6974 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6975 this.list.alignTo(this.inputEl(), this.listAlign);
6976 //this.list.endUpdate();
6980 onEmptyResults : function(){
6985 * Returns true if the dropdown list is expanded, else false.
6987 isExpanded : function(){
6988 return this.list.isVisible();
6992 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6993 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6994 * @param {String} value The data value of the item to select
6995 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6996 * selected item if it is not currently in view (defaults to true)
6997 * @return {Boolean} True if the value matched an item in the list, else false
6999 selectByValue : function(v, scrollIntoView){
7000 if(v !== undefined && v !== null){
7001 var r = this.findRecord(this.valueField || this.displayField, v);
7003 this.select(this.store.indexOf(r), scrollIntoView);
7011 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7012 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7013 * @param {Number} index The zero-based index of the list item to select
7014 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7015 * selected item if it is not currently in view (defaults to true)
7017 select : function(index, scrollIntoView){
7018 this.selectedIndex = index;
7019 this.view.select(index);
7020 if(scrollIntoView !== false){
7021 var el = this.view.getNode(index);
7023 //this.innerList.scrollChildIntoView(el, false);
7030 selectNext : function(){
7031 var ct = this.store.getCount();
7033 if(this.selectedIndex == -1){
7035 }else if(this.selectedIndex < ct-1){
7036 this.select(this.selectedIndex+1);
7042 selectPrev : function(){
7043 var ct = this.store.getCount();
7045 if(this.selectedIndex == -1){
7047 }else if(this.selectedIndex != 0){
7048 this.select(this.selectedIndex-1);
7054 onKeyUp : function(e){
7055 if(this.editable !== false && !e.isSpecialKey()){
7056 this.lastKey = e.getKey();
7057 this.dqTask.delay(this.queryDelay);
7062 validateBlur : function(){
7063 return !this.list || !this.list.isVisible();
7067 initQuery : function(){
7068 this.doQuery(this.getRawValue());
7072 doForce : function(){
7073 if(this.el.dom.value.length > 0){
7075 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7081 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7082 * query allowing the query action to be canceled if needed.
7083 * @param {String} query The SQL query to execute
7084 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7085 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7086 * saved in the current store (defaults to false)
7088 doQuery : function(q, forceAll){
7089 if(q === undefined || q === null){
7098 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7102 forceAll = qe.forceAll;
7103 if(forceAll === true || (q.length >= this.minChars)){
7104 if(this.lastQuery != q || this.alwaysQuery){
7106 if(this.mode == 'local'){
7107 this.selectedIndex = -1;
7109 this.store.clearFilter();
7111 this.store.filter(this.displayField, q);
7115 this.store.baseParams[this.queryParam] = q;
7117 params: this.getParams(q)
7122 this.selectedIndex = -1;
7129 getParams : function(q){
7131 //p[this.queryParam] = q;
7134 p.limit = this.pageSize;
7140 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7142 collapse : function(){
7143 if(!this.isExpanded()){
7147 Roo.get(document).un('mousedown', this.collapseIf, this);
7148 Roo.get(document).un('mousewheel', this.collapseIf, this);
7149 if (!this.editable) {
7150 Roo.get(document).un('keydown', this.listKeyPress, this);
7152 this.fireEvent('collapse', this);
7156 collapseIf : function(e){
7157 if(!e.within(this.el) && !e.within(this.el)){
7163 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7165 expand : function(){
7167 if(this.isExpanded() || !this.hasFocus){
7170 this.list.alignTo(this.inputEl(), this.listAlign);
7172 Roo.get(document).on('mousedown', this.collapseIf, this);
7173 Roo.get(document).on('mousewheel', this.collapseIf, this);
7174 if (!this.editable) {
7175 Roo.get(document).on('keydown', this.listKeyPress, this);
7178 this.fireEvent('expand', this);
7182 // Implements the default empty TriggerField.onTriggerClick function
7183 onTriggerClick : function()
7185 Roo.log('trigger click');
7190 if(this.isExpanded()){
7192 if (!this.blockFocus) {
7193 this.inputEl().focus();
7197 this.hasFocus = true;
7198 if(this.triggerAction == 'all') {
7199 this.doQuery(this.allQuery, true);
7201 this.doQuery(this.getRawValue());
7203 if (!this.blockFocus) {
7204 this.inputEl().focus();
7208 listKeyPress : function(e)
7210 //Roo.log('listkeypress');
7211 // scroll to first matching element based on key pres..
7212 if (e.isSpecialKey()) {
7215 var k = String.fromCharCode(e.getKey()).toUpperCase();
7218 var csel = this.view.getSelectedNodes();
7219 var cselitem = false;
7221 var ix = this.view.indexOf(csel[0]);
7222 cselitem = this.store.getAt(ix);
7223 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7229 this.store.each(function(v) {
7231 // start at existing selection.
7232 if (cselitem.id == v.id) {
7238 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7239 match = this.store.indexOf(v);
7245 if (match === false) {
7246 return true; // no more action?
7249 this.view.select(match);
7250 var sn = Roo.get(this.view.getSelectedNodes()[0])
7251 //sn.scrollIntoView(sn.dom.parentNode, false);
7255 * @cfg {Boolean} grow
7259 * @cfg {Number} growMin
7263 * @cfg {Number} growMax
7272 * Ext JS Library 1.1.1
7273 * Copyright(c) 2006-2007, Ext JS, LLC.
7275 * Originally Released Under LGPL - original licence link has changed is not relivant.
7278 * <script type="text/javascript">
7283 * @extends Roo.util.Observable
7284 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7285 * This class also supports single and multi selection modes. <br>
7286 * Create a data model bound view:
7288 var store = new Roo.data.Store(...);
7290 var view = new Roo.View({
7292 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7295 selectedClass: "ydataview-selected",
7299 // listen for node click?
7300 view.on("click", function(vw, index, node, e){
7301 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7305 dataModel.load("foobar.xml");
7307 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7309 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7310 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7312 * Note: old style constructor is still suported (container, template, config)
7316 * @param {Object} config The config object
7319 Roo.View = function(config, depreciated_tpl, depreciated_config){
7321 if (typeof(depreciated_tpl) == 'undefined') {
7322 // new way.. - universal constructor.
7323 Roo.apply(this, config);
7324 this.el = Roo.get(this.el);
7327 this.el = Roo.get(config);
7328 this.tpl = depreciated_tpl;
7329 Roo.apply(this, depreciated_config);
7331 this.wrapEl = this.el.wrap().wrap();
7332 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7335 if(typeof(this.tpl) == "string"){
7336 this.tpl = new Roo.Template(this.tpl);
7338 // support xtype ctors..
7339 this.tpl = new Roo.factory(this.tpl, Roo);
7351 * @event beforeclick
7352 * Fires before a click is processed. Returns false to cancel the default action.
7353 * @param {Roo.View} this
7354 * @param {Number} index The index of the target node
7355 * @param {HTMLElement} node The target node
7356 * @param {Roo.EventObject} e The raw event object
7358 "beforeclick" : true,
7361 * Fires when a template node is clicked.
7362 * @param {Roo.View} this
7363 * @param {Number} index The index of the target node
7364 * @param {HTMLElement} node The target node
7365 * @param {Roo.EventObject} e The raw event object
7370 * Fires when a template node is double clicked.
7371 * @param {Roo.View} this
7372 * @param {Number} index The index of the target node
7373 * @param {HTMLElement} node The target node
7374 * @param {Roo.EventObject} e The raw event object
7378 * @event contextmenu
7379 * Fires when a template node is right clicked.
7380 * @param {Roo.View} this
7381 * @param {Number} index The index of the target node
7382 * @param {HTMLElement} node The target node
7383 * @param {Roo.EventObject} e The raw event object
7385 "contextmenu" : true,
7387 * @event selectionchange
7388 * Fires when the selected nodes change.
7389 * @param {Roo.View} this
7390 * @param {Array} selections Array of the selected nodes
7392 "selectionchange" : true,
7395 * @event beforeselect
7396 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7397 * @param {Roo.View} this
7398 * @param {HTMLElement} node The node to be selected
7399 * @param {Array} selections Array of currently selected nodes
7401 "beforeselect" : true,
7403 * @event preparedata
7404 * Fires on every row to render, to allow you to change the data.
7405 * @param {Roo.View} this
7406 * @param {Object} data to be rendered (change this)
7408 "preparedata" : true
7416 "click": this.onClick,
7417 "dblclick": this.onDblClick,
7418 "contextmenu": this.onContextMenu,
7422 this.selections = [];
7424 this.cmp = new Roo.CompositeElementLite([]);
7426 this.store = Roo.factory(this.store, Roo.data);
7427 this.setStore(this.store, true);
7430 if ( this.footer && this.footer.xtype) {
7432 var fctr = this.wrapEl.appendChild(document.createElement("div"));
7434 this.footer.dataSource = this.store
7435 this.footer.container = fctr;
7436 this.footer = Roo.factory(this.footer, Roo);
7437 fctr.insertFirst(this.el);
7439 // this is a bit insane - as the paging toolbar seems to detach the el..
7440 // dom.parentNode.parentNode.parentNode
7441 // they get detached?
7445 Roo.View.superclass.constructor.call(this);
7450 Roo.extend(Roo.View, Roo.util.Observable, {
7453 * @cfg {Roo.data.Store} store Data store to load data from.
7458 * @cfg {String|Roo.Element} el The container element.
7463 * @cfg {String|Roo.Template} tpl The template used by this View
7467 * @cfg {String} dataName the named area of the template to use as the data area
7468 * Works with domtemplates roo-name="name"
7472 * @cfg {String} selectedClass The css class to add to selected nodes
7474 selectedClass : "x-view-selected",
7476 * @cfg {String} emptyText The empty text to show when nothing is loaded.
7481 * @cfg {String} text to display on mask (default Loading)
7485 * @cfg {Boolean} multiSelect Allow multiple selection
7487 multiSelect : false,
7489 * @cfg {Boolean} singleSelect Allow single selection
7491 singleSelect: false,
7494 * @cfg {Boolean} toggleSelect - selecting
7496 toggleSelect : false,
7499 * Returns the element this view is bound to.
7500 * @return {Roo.Element}
7509 * Refreshes the view. - called by datachanged on the store. - do not call directly.
7511 refresh : function(){
7514 // if we are using something like 'domtemplate', then
7515 // the what gets used is:
7516 // t.applySubtemplate(NAME, data, wrapping data..)
7517 // the outer template then get' applied with
7518 // the store 'extra data'
7519 // and the body get's added to the
7520 // roo-name="data" node?
7521 // <span class='roo-tpl-{name}'></span> ?????
7525 this.clearSelections();
7528 var records = this.store.getRange();
7529 if(records.length < 1) {
7531 // is this valid?? = should it render a template??
7533 this.el.update(this.emptyText);
7537 if (this.dataName) {
7538 this.el.update(t.apply(this.store.meta)); //????
7539 el = this.el.child('.roo-tpl-' + this.dataName);
7542 for(var i = 0, len = records.length; i < len; i++){
7543 var data = this.prepareData(records[i].data, i, records[i]);
7544 this.fireEvent("preparedata", this, data, i, records[i]);
7545 html[html.length] = Roo.util.Format.trim(
7547 t.applySubtemplate(this.dataName, data, this.store.meta) :
7554 el.update(html.join(""));
7555 this.nodes = el.dom.childNodes;
7556 this.updateIndexes(0);
7560 * Function to override to reformat the data that is sent to
7561 * the template for each node.
7562 * DEPRICATED - use the preparedata event handler.
7563 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7564 * a JSON object for an UpdateManager bound view).
7566 prepareData : function(data, index, record)
7568 this.fireEvent("preparedata", this, data, index, record);
7572 onUpdate : function(ds, record){
7573 this.clearSelections();
7574 var index = this.store.indexOf(record);
7575 var n = this.nodes[index];
7576 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7577 n.parentNode.removeChild(n);
7578 this.updateIndexes(index, index);
7584 onAdd : function(ds, records, index)
7586 this.clearSelections();
7587 if(this.nodes.length == 0){
7591 var n = this.nodes[index];
7592 for(var i = 0, len = records.length; i < len; i++){
7593 var d = this.prepareData(records[i].data, i, records[i]);
7595 this.tpl.insertBefore(n, d);
7598 this.tpl.append(this.el, d);
7601 this.updateIndexes(index);
7604 onRemove : function(ds, record, index){
7605 this.clearSelections();
7606 var el = this.dataName ?
7607 this.el.child('.roo-tpl-' + this.dataName) :
7609 el.dom.removeChild(this.nodes[index]);
7610 this.updateIndexes(index);
7614 * Refresh an individual node.
7615 * @param {Number} index
7617 refreshNode : function(index){
7618 this.onUpdate(this.store, this.store.getAt(index));
7621 updateIndexes : function(startIndex, endIndex){
7622 var ns = this.nodes;
7623 startIndex = startIndex || 0;
7624 endIndex = endIndex || ns.length - 1;
7625 for(var i = startIndex; i <= endIndex; i++){
7626 ns[i].nodeIndex = i;
7631 * Changes the data store this view uses and refresh the view.
7632 * @param {Store} store
7634 setStore : function(store, initial){
7635 if(!initial && this.store){
7636 this.store.un("datachanged", this.refresh);
7637 this.store.un("add", this.onAdd);
7638 this.store.un("remove", this.onRemove);
7639 this.store.un("update", this.onUpdate);
7640 this.store.un("clear", this.refresh);
7641 this.store.un("beforeload", this.onBeforeLoad);
7642 this.store.un("load", this.onLoad);
7643 this.store.un("loadexception", this.onLoad);
7647 store.on("datachanged", this.refresh, this);
7648 store.on("add", this.onAdd, this);
7649 store.on("remove", this.onRemove, this);
7650 store.on("update", this.onUpdate, this);
7651 store.on("clear", this.refresh, this);
7652 store.on("beforeload", this.onBeforeLoad, this);
7653 store.on("load", this.onLoad, this);
7654 store.on("loadexception", this.onLoad, this);
7662 * onbeforeLoad - masks the loading area.
7665 onBeforeLoad : function()
7668 this.el.mask(this.mask ? this.mask : "Loading" );
7670 onLoad : function ()
7677 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7678 * @param {HTMLElement} node
7679 * @return {HTMLElement} The template node
7681 findItemFromChild : function(node){
7682 var el = this.dataName ?
7683 this.el.child('.roo-tpl-' + this.dataName,true) :
7686 if(!node || node.parentNode == el){
7689 var p = node.parentNode;
7690 while(p && p != el){
7691 if(p.parentNode == el){
7700 onClick : function(e){
7701 var item = this.findItemFromChild(e.getTarget());
7703 var index = this.indexOf(item);
7704 if(this.onItemClick(item, index, e) !== false){
7705 this.fireEvent("click", this, index, item, e);
7708 this.clearSelections();
7713 onContextMenu : function(e){
7714 var item = this.findItemFromChild(e.getTarget());
7716 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7721 onDblClick : function(e){
7722 var item = this.findItemFromChild(e.getTarget());
7724 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7728 onItemClick : function(item, index, e)
7730 if(this.fireEvent("beforeclick", this, index, item, e) === false){
7733 if (this.toggleSelect) {
7734 var m = this.isSelected(item) ? 'unselect' : 'select';
7737 _t[m](item, true, false);
7740 if(this.multiSelect || this.singleSelect){
7741 if(this.multiSelect && e.shiftKey && this.lastSelection){
7742 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7744 this.select(item, this.multiSelect && e.ctrlKey);
7745 this.lastSelection = item;
7753 * Get the number of selected nodes.
7756 getSelectionCount : function(){
7757 return this.selections.length;
7761 * Get the currently selected nodes.
7762 * @return {Array} An array of HTMLElements
7764 getSelectedNodes : function(){
7765 return this.selections;
7769 * Get the indexes of the selected nodes.
7772 getSelectedIndexes : function(){
7773 var indexes = [], s = this.selections;
7774 for(var i = 0, len = s.length; i < len; i++){
7775 indexes.push(s[i].nodeIndex);
7781 * Clear all selections
7782 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7784 clearSelections : function(suppressEvent){
7785 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7786 this.cmp.elements = this.selections;
7787 this.cmp.removeClass(this.selectedClass);
7788 this.selections = [];
7790 this.fireEvent("selectionchange", this, this.selections);
7796 * Returns true if the passed node is selected
7797 * @param {HTMLElement/Number} node The node or node index
7800 isSelected : function(node){
7801 var s = this.selections;
7805 node = this.getNode(node);
7806 return s.indexOf(node) !== -1;
7811 * @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
7812 * @param {Boolean} keepExisting (optional) true to keep existing selections
7813 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7815 select : function(nodeInfo, keepExisting, suppressEvent){
7816 if(nodeInfo instanceof Array){
7818 this.clearSelections(true);
7820 for(var i = 0, len = nodeInfo.length; i < len; i++){
7821 this.select(nodeInfo[i], true, true);
7825 var node = this.getNode(nodeInfo);
7826 if(!node || this.isSelected(node)){
7827 return; // already selected.
7830 this.clearSelections(true);
7832 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7833 Roo.fly(node).addClass(this.selectedClass);
7834 this.selections.push(node);
7836 this.fireEvent("selectionchange", this, this.selections);
7844 * @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
7845 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7846 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7848 unselect : function(nodeInfo, keepExisting, suppressEvent)
7850 if(nodeInfo instanceof Array){
7851 Roo.each(this.selections, function(s) {
7852 this.unselect(s, nodeInfo);
7856 var node = this.getNode(nodeInfo);
7857 if(!node || !this.isSelected(node)){
7858 Roo.log("not selected");
7859 return; // not selected.
7863 Roo.each(this.selections, function(s) {
7865 Roo.fly(node).removeClass(this.selectedClass);
7872 this.selections= ns;
7873 this.fireEvent("selectionchange", this, this.selections);
7877 * Gets a template node.
7878 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7879 * @return {HTMLElement} The node or null if it wasn't found
7881 getNode : function(nodeInfo){
7882 if(typeof nodeInfo == "string"){
7883 return document.getElementById(nodeInfo);
7884 }else if(typeof nodeInfo == "number"){
7885 return this.nodes[nodeInfo];
7891 * Gets a range template nodes.
7892 * @param {Number} startIndex
7893 * @param {Number} endIndex
7894 * @return {Array} An array of nodes
7896 getNodes : function(start, end){
7897 var ns = this.nodes;
7899 end = typeof end == "undefined" ? ns.length - 1 : end;
7902 for(var i = start; i <= end; i++){
7906 for(var i = start; i >= end; i--){
7914 * Finds the index of the passed node
7915 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7916 * @return {Number} The index of the node or -1
7918 indexOf : function(node){
7919 node = this.getNode(node);
7920 if(typeof node.nodeIndex == "number"){
7921 return node.nodeIndex;
7923 var ns = this.nodes;
7924 for(var i = 0, len = ns.length; i < len; i++){
7935 * based on jquery fullcalendar
7941 * @class Roo.bootstrap.Calendar
7942 * @extends Roo.bootstrap.Component
7943 * Bootstrap Calendar class
7946 * Create a new Container
7947 * @param {Object} config The config object
7950 Roo.bootstrap.Calendar = function(config){
7951 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7955 * Fires when a date is selected
7956 * @param {DatePicker} this
7957 * @param {Date} date The selected date
7961 * @event monthchange
7962 * Fires when the displayed month changes
7963 * @param {DatePicker} this
7964 * @param {Date} date The selected month
7966 'monthchange': true,
7969 * Fires when mouse over an event
7970 * @param {Calendar} this
7971 * @param {event} Event
7976 * Fires when the mouse leaves an
7977 * @param {Calendar} this
7983 * Fires when the mouse click an
7984 * @param {Calendar} this
7993 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
7996 * @cfg {Number} startDay
7997 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8001 getAutoCreate : function(){
8004 fc_button = function(name, corner, style, content ) {
8005 return Roo.apply({},{
8007 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8009 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8012 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8020 style : 'width:100%',
8027 cls : 'fc-header-left',
8029 fc_button('prev', 'left', 'arrow', '‹' ),
8030 fc_button('next', 'right', 'arrow', '›' ),
8031 { tag: 'span', cls: 'fc-header-space' },
8032 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8040 cls : 'fc-header-center',
8044 cls: 'fc-header-title',
8047 html : 'month / year'
8055 cls : 'fc-header-right',
8057 /* fc_button('month', 'left', '', 'month' ),
8058 fc_button('week', '', '', 'week' ),
8059 fc_button('day', 'right', '', 'day' )
8071 var cal_heads = function() {
8073 // fixme - handle this.
8075 for (var i =0; i < Date.dayNames.length; i++) {
8076 var d = Date.dayNames[i];
8079 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8080 html : d.substring(0,3)
8084 ret[0].cls += ' fc-first';
8085 ret[6].cls += ' fc-last';
8088 var cal_cell = function(n) {
8091 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8096 cls: 'fc-day-number',
8100 cls: 'fc-day-content',
8104 style: 'position: relative;' // height: 17px;
8116 var cal_rows = function() {
8119 for (var r = 0; r < 6; r++) {
8126 for (var i =0; i < Date.dayNames.length; i++) {
8127 var d = Date.dayNames[i];
8128 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8131 row.cn[0].cls+=' fc-first';
8132 row.cn[0].cn[0].style = 'min-height:90px';
8133 row.cn[6].cls+=' fc-last';
8137 ret[0].cls += ' fc-first';
8138 ret[4].cls += ' fc-prev-last';
8139 ret[5].cls += ' fc-last';
8146 cls: 'fc-border-separate',
8147 style : 'width:100%',
8155 cls : 'fc-first fc-last',
8174 style : "position: relative;",
8177 cls : 'fc-view fc-view-month fc-grid',
8178 style : 'position: relative',
8179 unselectable : 'on',
8182 cls : 'fc-event-container',
8183 style : 'position:absolute;z-index:8;top:0;left:0;'
8201 initEvents : function()
8204 throw "can not find store for combo";
8207 this.store = Roo.factory(this.store, Roo.data);
8208 this.store.on('load', this.onLoad, this);
8211 this.cells = this.el.select('.fc-day',true);
8213 this.textNodes = this.el.query('.fc-day-number');
8214 this.cells.addClassOnOver('fc-state-hover');
8216 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8217 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8218 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8219 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8221 this.on('monthchange', this.onMonthChange, this);
8223 this.update(new Date().clearTime());
8226 resize : function() {
8227 var sz = this.el.getSize();
8229 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8230 this.el.select('.fc-day-content div',true).setHeight(34);
8235 showPrevMonth : function(e){
8236 this.update(this.activeDate.add("mo", -1));
8238 showToday : function(e){
8239 this.update(new Date().clearTime());
8242 showNextMonth : function(e){
8243 this.update(this.activeDate.add("mo", 1));
8247 showPrevYear : function(){
8248 this.update(this.activeDate.add("y", -1));
8252 showNextYear : function(){
8253 this.update(this.activeDate.add("y", 1));
8258 update : function(date)
8260 var vd = this.activeDate;
8261 this.activeDate = date;
8262 // if(vd && this.el){
8263 // var t = date.getTime();
8264 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8265 // Roo.log('using add remove');
8267 // this.fireEvent('monthchange', this, date);
8269 // this.cells.removeClass("fc-state-highlight");
8270 // this.cells.each(function(c){
8271 // if(c.dateValue == t){
8272 // c.addClass("fc-state-highlight");
8273 // setTimeout(function(){
8274 // try{c.dom.firstChild.focus();}catch(e){}
8284 var days = date.getDaysInMonth();
8286 var firstOfMonth = date.getFirstDateOfMonth();
8287 var startingPos = firstOfMonth.getDay()-this.startDay;
8289 if(startingPos < this.startDay){
8293 var pm = date.add("mo", -1);
8294 var prevStart = pm.getDaysInMonth()-startingPos;
8296 this.cells = this.el.select('.fc-day',true);
8297 this.textNodes = this.el.query('.fc-day-number');
8298 this.cells.addClassOnOver('fc-state-hover');
8300 var cells = this.cells.elements;
8301 var textEls = this.textNodes;
8303 Roo.each(cells, function(cell){
8304 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
8307 days += startingPos;
8309 // convert everything to numbers so it's fast
8311 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8312 var today = new Date().clearTime().getTime();
8313 var sel = date.clearTime().getTime();
8314 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8315 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8316 var ddMatch = this.disabledDatesRE;
8317 var ddText = this.disabledDatesText;
8318 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8319 var ddaysText = this.disabledDaysText;
8320 var format = this.format;
8322 var setCellClass = function(cal, cell){
8324 var t = d.getTime();
8328 cell.className += " fc-today";
8329 cell.className += " fc-state-highlight";
8330 cell.title = cal.todayText;
8333 // disable highlight in other month..
8334 //cell.className += " fc-state-highlight";
8339 cell.className = " fc-state-disabled";
8340 cell.title = cal.minText;
8344 cell.className = " fc-state-disabled";
8345 cell.title = cal.maxText;
8349 if(ddays.indexOf(d.getDay()) != -1){
8350 cell.title = ddaysText;
8351 cell.className = " fc-state-disabled";
8354 if(ddMatch && format){
8355 var fvalue = d.dateFormat(format);
8356 if(ddMatch.test(fvalue)){
8357 cell.title = ddText.replace("%0", fvalue);
8358 cell.className = " fc-state-disabled";
8362 if (!cell.initialClassName) {
8363 cell.initialClassName = cell.dom.className;
8366 cell.dom.className = cell.initialClassName + ' ' + cell.className;
8371 for(; i < startingPos; i++) {
8372 textEls[i].innerHTML = (++prevStart);
8373 d.setDate(d.getDate()+1);
8375 cells[i].className = "fc-past fc-other-month";
8376 setCellClass(this, cells[i]);
8381 for(; i < days; i++){
8382 intDay = i - startingPos + 1;
8383 textEls[i].innerHTML = (intDay);
8384 d.setDate(d.getDate()+1);
8386 cells[i].className = ''; // "x-date-active";
8387 setCellClass(this, cells[i]);
8391 for(; i < 42; i++) {
8392 textEls[i].innerHTML = (++extraDays);
8393 d.setDate(d.getDate()+1);
8395 cells[i].className = "fc-future fc-other-month";
8396 setCellClass(this, cells[i]);
8399 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8401 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
8403 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
8404 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
8407 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
8408 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
8411 this.fireEvent('monthchange', this, date);
8415 if(!this.internalRender){
8416 var main = this.el.dom.firstChild;
8417 var w = main.offsetWidth;
8418 this.el.setWidth(w + this.el.getBorderWidth("lr"));
8419 Roo.fly(main).setWidth(w);
8420 this.internalRender = true;
8421 // opera does not respect the auto grow header center column
8422 // then, after it gets a width opera refuses to recalculate
8423 // without a second pass
8424 if(Roo.isOpera && !this.secondPass){
8425 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8426 this.secondPass = true;
8427 this.update.defer(10, this, [date]);
8434 findCell : function(dt) {
8435 dt = dt.clearTime().getTime();
8437 this.cells.each(function(c){
8438 //Roo.log("check " +c.dateValue + '?=' + dt);
8439 if(c.dateValue == dt){
8449 findCells : function(ev) {
8450 var s = ev.start.clone().clearTime().getTime();
8451 var e= ev.end.clone().clearTime().getTime();
8453 this.cells.each(function(c){
8454 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8456 if(c.dateValue > e){
8459 if(c.dateValue < s){
8468 findBestRow: function(cells)
8472 for (var i =0 ; i < cells.length;i++) {
8473 ret = Math.max(cells[i].rows || 0,ret);
8480 addItem : function(ev)
8482 // look for vertical location slot in
8483 var cells = this.findCells(ev);
8485 ev.row = this.findBestRow(cells);
8487 // work out the location.
8491 for(var i =0; i < cells.length; i++) {
8499 if (crow.start.getY() == cells[i].getY()) {
8501 crow.end = cells[i];
8517 for (var i = 0; i < cells.length;i++) {
8518 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8522 this.calevents.push(ev);
8525 clearEvents: function() {
8527 if(!this.calevents){
8531 Roo.each(this.cells.elements, function(c){
8535 Roo.each(this.calevents, function(e) {
8536 Roo.each(e.els, function(el) {
8537 el.un('mouseenter' ,this.onEventEnter, this);
8538 el.un('mouseleave' ,this.onEventLeave, this);
8545 renderEvents: function()
8547 // first make sure there is enough space..
8549 this.cells.each(function(c) {
8551 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8554 for (var e = 0; e < this.calevents.length; e++) {
8555 var ev = this.calevents[e];
8556 var cells = ev.cells;
8559 for(var i =0; i < rows.length; i++) {
8562 // how many rows should it span..
8565 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8566 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8568 unselectable : "on",
8571 cls: 'fc-event-inner',
8575 cls: 'fc-event-time',
8576 html : cells.length > 1 ? '' : ev.time
8580 cls: 'fc-event-title',
8581 html : String.format('{0}', ev.title)
8588 cls: 'ui-resizable-handle ui-resizable-e',
8589 html : '  '
8595 cfg.cls += ' fc-event-start';
8597 if ((i+1) == rows.length) {
8598 cfg.cls += ' fc-event-end';
8601 var ctr = this.el.select('.fc-event-container',true).first();
8602 var cg = ctr.createChild(cfg);
8604 cg.on('mouseenter' ,this.onEventEnter, this, ev);
8605 cg.on('mouseleave' ,this.onEventLeave, this, ev);
8606 cg.on('click', this.onEventClick, this, ev);
8610 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8611 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8613 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
8614 cg.setWidth(ebox.right - sbox.x -2);
8622 onEventEnter: function (e, el,event,d) {
8623 this.fireEvent('evententer', this, el, event);
8626 onEventLeave: function (e, el,event,d) {
8627 this.fireEvent('eventleave', this, el, event);
8630 onEventClick: function (e, el,event,d) {
8631 this.fireEvent('eventclick', this, el, event);
8634 onMonthChange: function () {
8638 onLoad: function () {
8641 Roo.log('calendar onload');
8643 this.calevents = [];
8645 if(this.store.getCount() > 0){
8646 this.store.data.each(function(d){
8649 start: new Date(d.data.start_dt),
8650 end : new Date(d.data.end_dt),
8651 time : d.data.start_time,
8652 title : d.data.title,
8653 description : d.data.description,
8654 venue : d.data.venue
8659 this.renderEvents();
8672 * @class Roo.bootstrap.Popover
8673 * @extends Roo.bootstrap.Component
8674 * Bootstrap Popover class
8675 * @cfg {String} html contents of the popover (or false to use children..)
8676 * @cfg {String} title of popover (or false to hide)
8677 * @cfg {String} placement how it is placed
8678 * @cfg {String} trigger click || hover (or false to trigger manually)
8679 * @cfg {String} over what (parent or false to trigger manually.)
8682 * Create a new Popover
8683 * @param {Object} config The config object
8686 Roo.bootstrap.Popover = function(config){
8687 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8690 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
8692 title: 'Fill in a title',
8695 placement : 'right',
8696 trigger : 'hover', // hover
8700 can_build_overlaid : false,
8702 getChildContainer : function()
8704 return this.el.select('.popover-content',true).first();
8707 getAutoCreate : function(){
8708 Roo.log('make popover?');
8710 cls : 'popover roo-dynamic',
8711 style: 'display:block',
8717 cls : 'popover-inner',
8721 cls: 'popover-title',
8725 cls : 'popover-content',
8736 setTitle: function(str)
8738 this.el.select('.popover-title',true).first().dom.innerHTML = str;
8740 setContent: function(str)
8742 this.el.select('.popover-content',true).first().dom.innerHTML = str;
8744 // as it get's added to the bottom of the page.
8745 onRender : function(ct, position)
8747 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8749 var cfg = Roo.apply({}, this.getAutoCreate());
8753 cfg.cls += ' ' + this.cls;
8756 cfg.style = this.style;
8758 Roo.log("adding to ")
8759 this.el = Roo.get(document.body).createChild(cfg, position);
8765 initEvents : function()
8767 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8768 this.el.enableDisplayMode('block');
8770 if (this.over === false) {
8773 if (this.triggers === false) {
8776 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8777 var triggers = this.trigger ? this.trigger.split(' ') : [];
8778 Roo.each(triggers, function(trigger) {
8780 if (trigger == 'click') {
8781 on_el.on('click', this.toggle, this);
8782 } else if (trigger != 'manual') {
8783 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
8784 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8786 on_el.on(eventIn ,this.enter, this);
8787 on_el.on(eventOut, this.leave, this);
8798 toggle : function () {
8799 this.hoverState == 'in' ? this.leave() : this.enter();
8802 enter : function () {
8805 clearTimeout(this.timeout);
8807 this.hoverState = 'in'
8809 if (!this.delay || !this.delay.show) {
8814 this.timeout = setTimeout(function () {
8815 if (_t.hoverState == 'in') {
8820 leave : function() {
8821 clearTimeout(this.timeout);
8823 this.hoverState = 'out'
8825 if (!this.delay || !this.delay.hide) {
8830 this.timeout = setTimeout(function () {
8831 if (_t.hoverState == 'out') {
8837 show : function (on_el)
8840 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8843 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8844 if (this.html !== false) {
8845 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8847 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8848 if (!this.title.length) {
8849 this.el.select('.popover-title',true).hide();
8852 var placement = typeof this.placement == 'function' ?
8853 this.placement.call(this, this.el, on_el) :
8856 var autoToken = /\s?auto?\s?/i;
8857 var autoPlace = autoToken.test(placement);
8859 placement = placement.replace(autoToken, '') || 'top';
8863 //this.el.setXY([0,0]);
8865 this.el.dom.style.display='block';
8866 this.el.addClass(placement);
8868 //this.el.appendTo(on_el);
8870 var p = this.getPosition();
8871 var box = this.el.getBox();
8876 var align = Roo.bootstrap.Popover.alignment[placement]
8877 this.el.alignTo(on_el, align[0],align[1]);
8878 //var arrow = this.el.select('.arrow',true).first();
8879 //arrow.set(align[2],
8881 this.el.addClass('in');
8882 this.hoverState = null;
8884 if (this.el.hasClass('fade')) {
8891 this.el.setXY([0,0]);
8892 this.el.removeClass('in');
8899 Roo.bootstrap.Popover.alignment = {
8900 'left' : ['r-l', [-10,0], 'right'],
8901 'right' : ['l-r', [10,0], 'left'],
8902 'bottom' : ['t-b', [0,10], 'top'],
8903 'top' : [ 'b-t', [0,-10], 'bottom']