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';
563 cls: 'glyphicon glyphicon-' + this.glyphicon
576 if (cfg.tag !== 'a' && this.href !== '') {
577 throw "Tag must be a to set href.";
578 } else if (this.href.length > 0) {
579 cfg.href = this.href;
584 initEvents: function() {
585 // Roo.log('init events?');
586 // Roo.log(this.el.dom);
587 if (this.el.hasClass('roo-button')) {
588 this.el.on('click', this.onClick, this);
590 this.el.select('.roo-button').on('click', this.onClick, this);
596 onClick : function(e)
598 Roo.log('button on click ');
599 if(this.preventDefault){
603 this.fireEvent('click', this, e);
617 * @class Roo.bootstrap.Column
618 * @extends Roo.bootstrap.Component
619 * Bootstrap Column class
620 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
621 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
622 * @cfg {Number} md colspan out of 12 for computer-sized screens
623 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
624 * @cfg {String} html content of column.
627 * Create a new Column
628 * @param {Object} config The config object
631 Roo.bootstrap.Column = function(config){
632 Roo.bootstrap.Column.superclass.constructor.call(this, config);
635 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
644 getAutoCreate : function(){
645 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
653 ['xs','sm','md','lg'].map(function(size){
654 if (settings[size]) {
655 cfg.cls += ' col-' + size + '-' + settings[size];
658 if (this.html.length) {
659 cfg.html = this.html;
678 * @class Roo.bootstrap.Container
679 * @extends Roo.bootstrap.Component
680 * Bootstrap Container class
681 * @cfg {Boolean} jumbotron is it a jumbotron element
682 * @cfg {String} html content of element
683 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
684 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
685 * @cfg {String} header content of header (for panel)
686 * @cfg {String} footer content of footer (for panel)
687 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
690 * Create a new Container
691 * @param {Object} config The config object
694 Roo.bootstrap.Container = function(config){
695 Roo.bootstrap.Container.superclass.constructor.call(this, config);
698 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
708 getChildContainer : function() {
714 if (this.panel.length) {
715 return this.el.select('.panel-body',true).first();
722 getAutoCreate : function(){
728 if (this.jumbotron) {
729 cfg.cls = 'jumbotron';
732 cfg.cls = this.cls + '';
735 if (this.sticky.length) {
736 var bd = Roo.get(document.body);
737 if (!bd.hasClass('bootstrap-sticky')) {
738 bd.addClass('bootstrap-sticky');
739 Roo.select('html',true).setStyle('height', '100%');
742 cfg.cls += 'bootstrap-sticky-' + this.sticky;
746 if (this.well.length) {
750 cfg.cls +=' well well-' +this.well;
760 if (this.panel.length) {
761 cfg.cls += 'panel panel-' + this.panel;
763 if (this.header.length) {
766 cls : 'panel-heading',
782 if (this.footer.length) {
784 cls : 'panel-footer',
792 body.html = this.html || cfg.html;
794 if (!cfg.cls.length) {
795 cfg.cls = 'container';
812 * @class Roo.bootstrap.Img
813 * @extends Roo.bootstrap.Component
814 * Bootstrap Img class
815 * @cfg {Boolean} imgResponsive false | true
816 * @cfg {String} border rounded | circle | thumbnail
817 * @cfg {String} src image source
818 * @cfg {String} alt image alternative text
819 * @cfg {String} href a tag href
823 * @param {Object} config The config object
826 Roo.bootstrap.Img = function(config){
827 Roo.bootstrap.Img.superclass.constructor.call(this, config);
833 * The img click event for the img.
834 * @param {Roo.EventObject} e
840 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
847 getAutoCreate : function(){
851 cls: 'img-responsive',
855 cfg.html = this.html || cfg.html;
857 cfg.src = this.src || cfg.src;
859 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
860 cfg.cls += ' img-' + this.border;
878 return (this.href) ? a : cfg;
881 initEvents: function() {
884 this.el.on('click', this.onClick, this);
888 onClick : function(e)
890 Roo.log('img onclick');
891 this.fireEvent('click', this, e);
904 * @class Roo.bootstrap.Header
905 * @extends Roo.bootstrap.Component
906 * Bootstrap Header class
907 * @cfg {String} html content of header
908 * @cfg {Number} level (1|2|3|4|5|6) default 1
911 * Create a new Header
912 * @param {Object} config The config object
916 Roo.bootstrap.Header = function(config){
917 Roo.bootstrap.Header.superclass.constructor.call(this, config);
920 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
928 getAutoCreate : function(){
931 tag: 'h' + (1 *this.level),
932 html: this.html || 'fill in html'
950 * @class Roo.bootstrap.Menu
951 * @extends Roo.bootstrap.Component
952 * Bootstrap Menu class - container for MenuItems
953 * @cfg {String} type type of menu
957 * @param {Object} config The config object
961 Roo.bootstrap.Menu = function(config){
962 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
965 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
973 getChildContainer : function() {
977 getAutoCreate : function(){
979 //if (['right'].indexOf(this.align)!==-1) {
980 // cfg.cn[1].cls += ' pull-right'
984 cls : 'dropdown-menu'
988 if (this.type==='submenu') {
989 cfg.cls='submenu active'
994 initEvents : function() {
995 // Roo.log("ADD event");
996 // Roo.log(this.triggerEl.dom);
997 this.triggerEl.on('click', this.toggle, this);
998 this.triggerEl.addClass('dropdown-toggle');
1001 toggle : function(e)
1003 //Roo.log(e.getTarget());
1004 // Roo.log(this.triggerEl.dom);
1005 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1008 var isActive = this.triggerEl.hasClass('open');
1009 // if disabled.. ingore
1011 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
1012 // if mobile we use a backdrop because click events don't delegate
1013 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
1016 //var relatedTarget = { relatedTarget: this }
1017 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
1019 //if (e.isDefaultPrevented()) return;
1021 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
1023 // .trigger('shown.bs.dropdown', relatedTarget)
1025 this.triggerEl.focus();
1031 clearMenus : function()
1033 //$(backdrop).remove()
1034 Roo.select('.dropdown-toggle',true).each(function(aa) {
1035 if (!aa.hasClass('open')) {
1039 aa.removeClass('open');
1040 //var parent = getParent($(this))
1041 //var relatedTarget = { relatedTarget: this }
1043 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1044 //if (e.isDefaultPrevented()) return
1045 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1063 * @class Roo.bootstrap.MenuItem
1064 * @extends Roo.bootstrap.Component
1065 * Bootstrap MenuItem class
1066 * @cfg {String} html the menu label
1067 * @cfg {String} href the link
1071 * Create a new MenuItem
1072 * @param {Object} config The config object
1076 Roo.bootstrap.MenuItem = function(config){
1077 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1080 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1085 getAutoCreate : function(){
1097 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1098 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1115 * @class Roo.bootstrap.MenuSeparator
1116 * @extends Roo.bootstrap.Component
1117 * Bootstrap MenuSeparator class
1120 * Create a new MenuItem
1121 * @param {Object} config The config object
1125 Roo.bootstrap.MenuSeparator = function(config){
1126 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1129 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1131 getAutoCreate : function(){
1146 <div class="modal fade">
1147 <div class="modal-dialog">
1148 <div class="modal-content">
1149 <div class="modal-header">
1150 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1151 <h4 class="modal-title">Modal title</h4>
1153 <div class="modal-body">
1154 <p>One fine body…</p>
1156 <div class="modal-footer">
1157 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1158 <button type="button" class="btn btn-primary">Save changes</button>
1160 </div><!-- /.modal-content -->
1161 </div><!-- /.modal-dialog -->
1162 </div><!-- /.modal -->
1172 * @class Roo.bootstrap.Modal
1173 * @extends Roo.bootstrap.Component
1174 * Bootstrap Modal class
1175 * @cfg {String} title Title of dialog
1176 * @cfg {Array} buttons Array of buttons or standard button set..
1179 * Create a new Modal Dialog
1180 * @param {Object} config The config object
1183 Roo.bootstrap.Modal = function(config){
1184 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1189 * The raw btnclick event for the button
1190 * @param {Roo.EventObject} e
1196 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1198 title : 'test dialog',
1202 onRender : function(ct, position)
1204 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1207 var cfg = Roo.apply({}, this.getAutoCreate());
1210 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1212 //if (!cfg.name.length) {
1216 cfg.cls += ' ' + this.cls;
1219 cfg.style = this.style;
1221 this.el = Roo.get(document.body).createChild(cfg, position);
1223 //var type = this.el.dom.type;
1225 if(this.tabIndex !== undefined){
1226 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1231 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1232 this.maskEl.enableDisplayMode("block");
1234 //this.el.addClass("x-dlg-modal");
1238 Roo.each(this.buttons, function(bb) {
1239 b = Roo.apply({}, bb);
1240 b.xns = b.xns || Roo.bootstrap;
1241 b.xtype = b.xtype || 'Button';
1242 if (typeof(b.listeners) == 'undefined') {
1243 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1246 var btn = Roo.factory(b);
1248 btn.onRender(this.el.select('.modal-footer').first());
1252 // render the children.
1254 var items = this.items;
1257 for(var i =0;i < items.length;i++) {
1258 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1260 this.items = nitems;
1262 //this.el.addClass([this.fieldClass, this.cls]);
1265 getAutoCreate : function(){
1270 html : this.html || ''
1278 cls: "modal-dialog",
1281 cls : "modal-content",
1284 cls : 'modal-header',
1293 cls : 'modal-title',
1301 cls : 'modal-footer'
1317 getChildContainer : function() {
1319 return this.el.select('.modal-body',true).first();
1322 getButtonContainer : function() {
1323 return this.el.select('.modal-footer',true).first();
1326 initEvents : function()
1328 this.el.select('.modal-header .close').on('click', this.hide, this);
1330 // this.addxtype(this);
1334 if (!this.rendered) {
1338 this.el.addClass('on');
1339 this.el.removeClass('fade');
1340 this.el.setStyle('display', 'block');
1341 Roo.get(document.body).addClass("x-body-masked");
1342 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1344 this.el.setStyle('zIndex', '10001');
1350 Roo.log('Modal hide?!');
1352 this.el.removeClass('on');
1353 this.el.addClass('fade');
1354 this.el.setStyle('display', 'none');
1356 onButtonClick: function(btn,e)
1359 this.fireEvent('btnclick', btn.name, e);
1364 Roo.apply(Roo.bootstrap.Modal, {
1366 * Button config that displays a single OK button
1375 * Button config that displays Yes and No buttons
1391 * Button config that displays OK and Cancel buttons
1406 * Button config that displays Yes, No and Cancel buttons
1433 * @class Roo.bootstrap.Navbar
1434 * @extends Roo.bootstrap.Component
1435 * Bootstrap Navbar class
1436 * @cfg {Boolean} sidebar has side bar
1437 * @cfg {Boolean} bar is a bar?
1438 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1439 * @cfg {String} brand what is brand
1440 * @cfg {Boolean} inverse is inverted color
1441 * @cfg {String} type (nav | pills | tabs)
1442 * @cfg {Boolean} arrangement stacked | justified
1443 * @cfg {String} align (left | right) alignment
1447 * Create a new Navbar
1448 * @param {Object} config The config object
1452 Roo.bootstrap.Navbar = function(config){
1453 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1456 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1468 getAutoCreate : function(){
1473 if (this.sidebar === true) {
1481 if (this.bar === true) {
1489 cls: 'navbar-header',
1494 cls: 'navbar-toggle',
1495 'data-toggle': 'collapse',
1500 html: 'Toggle navigation'
1520 cls: 'collapse navbar-collapse'
1525 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1527 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1528 cfg.cls += ' navbar-' + this.position;
1529 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1532 if (this.brand !== '') {
1536 cls: 'navbar-brand',
1545 } else if (this.bar === false) {
1548 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1558 if (['tabs','pills'].indexOf(this.type)!==-1) {
1559 cfg.cn[0].cls += ' nav-' + this.type
1561 if (this.type!=='nav') {
1562 Roo.log('nav type must be nav/tabs/pills')
1564 cfg.cn[0].cls += ' navbar-nav'
1567 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1568 cfg.cn[0].cls += ' nav-' + this.arrangement;
1571 if (this.align === 'right') {
1572 cfg.cn[0].cls += ' navbar-right';
1575 cfg.cls += ' navbar-inverse';
1583 initEvents :function ()
1585 //Roo.log(this.el.select('.navbar-toggle',true));
1586 this.el.select('.navbar-toggle',true).on('click', function() {
1587 // Roo.log('click');
1588 this.el.select('.navbar-collapse',true).toggleClass('in');
1593 getChildContainer : function()
1595 if (this.bar === true) {
1596 return this.el.select('.collapse',true).first();
1614 * @class Roo.bootstrap.NavGroup
1615 * @extends Roo.bootstrap.Component
1616 * Bootstrap NavGroup class
1617 * @cfg {String} align left | right
1618 * @cfg {Boolean} inverse false | true
1621 * Create a new nav group
1622 * @param {Object} config The config object
1625 Roo.bootstrap.NavGroup = function(config){
1626 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1629 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1635 getAutoCreate : function(){
1636 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1640 cls: 'nav navbar-nav'
1643 if (this.parent().sidebar === true) {
1646 cls: 'dashboard-menu'
1652 if (this.form === true) {
1658 if (this.align === 'right') {
1659 cfg.cls += ' navbar-right';
1661 cfg.cls += ' navbar-left';
1666 if (this.align === 'right') {
1667 cfg.cls += ' navbar-right';
1671 cfg.cls += ' navbar-inverse';
1691 * @class Roo.bootstrap.Navbar.Item
1692 * @extends Roo.bootstrap.Component
1693 * Bootstrap Navbar.Button class
1694 * @cfg {String} href link to
1695 * @cfg {String} html content of button
1696 * @cfg {String} badge text inside badge
1697 * @cfg {String} glyphicon name of glyphicon
1700 * Create a new Navbar Button
1701 * @param {Object} config The config object
1703 Roo.bootstrap.Navbar.Item = function(config){
1704 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1707 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1715 getAutoCreate : function(){
1717 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1719 if (this.parent().parent().sidebar === true) {
1732 cfg.cn[0].html = this.html;
1736 this.cls += ' active';
1740 cfg.cn[0].cls += ' dropdown-toggle';
1741 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1745 cfg.cn[0].tag = 'a',
1746 cfg.cn[0].href = this.href;
1749 if (this.glyphicon) {
1750 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1766 if (this.glyphicon) {
1767 if(cfg.html){cfg.html = ' ' + this.html};
1771 cls: 'glyphicon glyphicon-' + this.glyphicon
1776 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1780 cfg.cn[0].html += " <span class='caret'></span>";
1781 //}else if (!this.href) {
1782 // cfg.cn[0].tag='p';
1783 // cfg.cn[0].cls='navbar-text';
1786 cfg.cn[0].href=this.href||'#';
1787 cfg.cn[0].html=this.html;
1790 if (this.badge !== '') {
1793 cfg.cn[0].html + ' ',
1806 initEvents: function() {
1807 // Roo.log('init events?');
1808 // Roo.log(this.el.dom);
1809 this.el.select('a',true).on('click',
1811 this.fireEvent('click', this);
1828 * @class Roo.bootstrap.Row
1829 * @extends Roo.bootstrap.Component
1830 * Bootstrap Row class (contains columns...)
1834 * @param {Object} config The config object
1837 Roo.bootstrap.Row = function(config){
1838 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1841 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1843 getAutoCreate : function(){
1862 * @class Roo.bootstrap.Element
1863 * @extends Roo.bootstrap.Component
1864 * Bootstrap Element class
1865 * @cfg {String} html contents of the element
1866 * @cfg {String} tag tag of the element
1867 * @cfg {String} cls class of the element
1870 * Create a new Element
1871 * @param {Object} config The config object
1874 Roo.bootstrap.Element = function(config){
1875 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1878 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1885 getAutoCreate : function(){
1908 * @class Roo.bootstrap.Pagination
1909 * @extends Roo.bootstrap.Component
1910 * Bootstrap Pagination class
1911 * @cfg {String} size xs | sm | md | lg
1912 * @cfg {Boolean} inverse false | true
1913 * @cfg {Number} from pagination starting number
1914 * @cfg {Number} to pagination ending number
1915 * @cfg {String} align empty or left | right
1916 * @cfg {Number} active active page number
1919 * Create a new Pagination
1920 * @param {Object} config The config object
1923 Roo.bootstrap.Pagination = function(config){
1924 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1927 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1937 getAutoCreate : function(){
1944 cfg.cls += ' inverse';
1962 var from=this.from>0?this.from:1;
1963 var to=this.to-from<=10?this.to:from+10;
1964 var active=this.active>=from&&this.active<=to?this.active:null;
1965 for (var i=from;i<=to;i++) {
1969 cls: active===i?'active':'',
2010 * @class Roo.bootstrap.Slider
2011 * @extends Roo.bootstrap.Component
2012 * Bootstrap Slider class
2015 * Create a new Slider
2016 * @param {Object} config The config object
2019 Roo.bootstrap.Slider = function(config){
2020 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2023 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2025 getAutoCreate : function(){
2029 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2033 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2051 * @class Roo.bootstrap.Table
2052 * @extends Roo.bootstrap.Component
2053 * Bootstrap Table class
2056 * Create a new Table
2057 * @param {Object} config The config object
2060 Roo.bootstrap.Table = function(config){
2061 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2064 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2069 getAutoCreate : function(){
2070 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2102 * @class Roo.bootstrap.TableCell
2103 * @extends Roo.bootstrap.Component
2104 * Bootstrap TableCell class
2107 * Create a new TableCell
2108 * @param {Object} config The config object
2111 Roo.bootstrap.TableCell = function(config){
2112 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2115 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2117 getAutoCreate : function(){
2118 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2145 * @class Roo.bootstrap.TableRow
2146 * @extends Roo.bootstrap.Component
2147 * Bootstrap TableRow class
2150 * Create a new TableRow
2151 * @param {Object} config The config object
2154 Roo.bootstrap.TableRow = function(config){
2155 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2158 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2160 getAutoCreate : function(){
2161 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2176 * Ext JS Library 1.1.1
2177 * Copyright(c) 2006-2007, Ext JS, LLC.
2179 * Originally Released Under LGPL - original licence link has changed is not relivant.
2182 * <script type="text/javascript">
2185 // as we use this in bootstrap.
2186 Roo.namespace('Roo.form');
2188 * @class Roo.form.Action
2189 * Internal Class used to handle form actions
2191 * @param {Roo.form.BasicForm} el The form element or its id
2192 * @param {Object} config Configuration options
2197 // define the action interface
2198 Roo.form.Action = function(form, options){
2200 this.options = options || {};
2203 * Client Validation Failed
2206 Roo.form.Action.CLIENT_INVALID = 'client';
2208 * Server Validation Failed
2211 Roo.form.Action.SERVER_INVALID = 'server';
2213 * Connect to Server Failed
2216 Roo.form.Action.CONNECT_FAILURE = 'connect';
2218 * Reading Data from Server Failed
2221 Roo.form.Action.LOAD_FAILURE = 'load';
2223 Roo.form.Action.prototype = {
2225 failureType : undefined,
2226 response : undefined,
2230 run : function(options){
2235 success : function(response){
2240 handleResponse : function(response){
2244 // default connection failure
2245 failure : function(response){
2247 this.response = response;
2248 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2249 this.form.afterAction(this, false);
2252 processResponse : function(response){
2253 this.response = response;
2254 if(!response.responseText){
2257 this.result = this.handleResponse(response);
2261 // utility functions used internally
2262 getUrl : function(appendParams){
2263 var url = this.options.url || this.form.url || this.form.el.dom.action;
2265 var p = this.getParams();
2267 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2273 getMethod : function(){
2274 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2277 getParams : function(){
2278 var bp = this.form.baseParams;
2279 var p = this.options.params;
2281 if(typeof p == "object"){
2282 p = Roo.urlEncode(Roo.applyIf(p, bp));
2283 }else if(typeof p == 'string' && bp){
2284 p += '&' + Roo.urlEncode(bp);
2287 p = Roo.urlEncode(bp);
2292 createCallback : function(){
2294 success: this.success,
2295 failure: this.failure,
2297 timeout: (this.form.timeout*1000),
2298 upload: this.form.fileUpload ? this.success : undefined
2303 Roo.form.Action.Submit = function(form, options){
2304 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2307 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2310 haveProgress : false,
2311 uploadComplete : false,
2313 // uploadProgress indicator.
2314 uploadProgress : function()
2316 if (!this.form.progressUrl) {
2320 if (!this.haveProgress) {
2321 Roo.MessageBox.progress("Uploading", "Uploading");
2323 if (this.uploadComplete) {
2324 Roo.MessageBox.hide();
2328 this.haveProgress = true;
2330 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2332 var c = new Roo.data.Connection();
2334 url : this.form.progressUrl,
2339 success : function(req){
2340 //console.log(data);
2344 rdata = Roo.decode(req.responseText)
2346 Roo.log("Invalid data from server..");
2350 if (!rdata || !rdata.success) {
2352 Roo.MessageBox.alert(Roo.encode(rdata));
2355 var data = rdata.data;
2357 if (this.uploadComplete) {
2358 Roo.MessageBox.hide();
2363 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2364 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2367 this.uploadProgress.defer(2000,this);
2370 failure: function(data) {
2371 Roo.log('progress url failed ');
2382 // run get Values on the form, so it syncs any secondary forms.
2383 this.form.getValues();
2385 var o = this.options;
2386 var method = this.getMethod();
2387 var isPost = method == 'POST';
2388 if(o.clientValidation === false || this.form.isValid()){
2390 if (this.form.progressUrl) {
2391 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2392 (new Date() * 1) + '' + Math.random());
2397 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2398 form:this.form.el.dom,
2399 url:this.getUrl(!isPost),
2401 params:isPost ? this.getParams() : null,
2402 isUpload: this.form.fileUpload
2405 this.uploadProgress();
2407 }else if (o.clientValidation !== false){ // client validation failed
2408 this.failureType = Roo.form.Action.CLIENT_INVALID;
2409 this.form.afterAction(this, false);
2413 success : function(response)
2415 this.uploadComplete= true;
2416 if (this.haveProgress) {
2417 Roo.MessageBox.hide();
2421 var result = this.processResponse(response);
2422 if(result === true || result.success){
2423 this.form.afterAction(this, true);
2427 this.form.markInvalid(result.errors);
2428 this.failureType = Roo.form.Action.SERVER_INVALID;
2430 this.form.afterAction(this, false);
2432 failure : function(response)
2434 this.uploadComplete= true;
2435 if (this.haveProgress) {
2436 Roo.MessageBox.hide();
2439 this.response = response;
2440 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2441 this.form.afterAction(this, false);
2444 handleResponse : function(response){
2445 if(this.form.errorReader){
2446 var rs = this.form.errorReader.read(response);
2449 for(var i = 0, len = rs.records.length; i < len; i++) {
2450 var r = rs.records[i];
2454 if(errors.length < 1){
2458 success : rs.success,
2464 ret = Roo.decode(response.responseText);
2468 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2478 Roo.form.Action.Load = function(form, options){
2479 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2480 this.reader = this.form.reader;
2483 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2488 Roo.Ajax.request(Roo.apply(
2489 this.createCallback(), {
2490 method:this.getMethod(),
2491 url:this.getUrl(false),
2492 params:this.getParams()
2496 success : function(response){
2498 var result = this.processResponse(response);
2499 if(result === true || !result.success || !result.data){
2500 this.failureType = Roo.form.Action.LOAD_FAILURE;
2501 this.form.afterAction(this, false);
2504 this.form.clearInvalid();
2505 this.form.setValues(result.data);
2506 this.form.afterAction(this, true);
2509 handleResponse : function(response){
2510 if(this.form.reader){
2511 var rs = this.form.reader.read(response);
2512 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2514 success : rs.success,
2518 return Roo.decode(response.responseText);
2522 Roo.form.Action.ACTION_TYPES = {
2523 'load' : Roo.form.Action.Load,
2524 'submit' : Roo.form.Action.Submit
2533 * @class Roo.bootstrap.Form
2534 * @extends Roo.bootstrap.Component
2535 * Bootstrap Form class
2536 * @cfg {String} method GET | POST (default POST)
2537 * @cfg {String} labelAlign top | left (default top)
2538 * @cfg {String} align left | right - for navbars
2543 * @param {Object} config The config object
2547 Roo.bootstrap.Form = function(config){
2548 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2551 * @event clientvalidation
2552 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2553 * @param {Form} this
2554 * @param {Boolean} valid true if the form has passed client-side validation
2556 clientvalidation: true,
2558 * @event beforeaction
2559 * Fires before any action is performed. Return false to cancel the action.
2560 * @param {Form} this
2561 * @param {Action} action The action to be performed
2565 * @event actionfailed
2566 * Fires when an action fails.
2567 * @param {Form} this
2568 * @param {Action} action The action that failed
2570 actionfailed : true,
2572 * @event actioncomplete
2573 * Fires when an action is completed.
2574 * @param {Form} this
2575 * @param {Action} action The action that completed
2577 actioncomplete : true
2582 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2585 * @cfg {String} method
2586 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2591 * The URL to use for form actions if one isn't supplied in the action options.
2594 * @cfg {Boolean} fileUpload
2595 * Set to true if this form is a file upload.
2599 * @cfg {Object} baseParams
2600 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2604 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2608 * @cfg {Sting} align (left|right) for navbar forms
2613 activeAction : null,
2616 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2617 * element by passing it or its id or mask the form itself by passing in true.
2620 waitMsgTarget : false,
2625 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2626 * element by passing it or its id or mask the form itself by passing in true.
2630 getAutoCreate : function(){
2634 method : this.method || 'POST',
2635 id : this.id || Roo.id(),
2638 if (this.parent().xtype.match(/^Nav/)) {
2639 cfg.cls = 'navbar-form navbar-' + this.align;
2643 if (this.labelAlign == 'left' ) {
2644 cfg.cls += ' form-horizontal';
2650 initEvents : function()
2652 this.el.on('submit', this.onSubmit, this);
2657 onSubmit : function(e){
2662 * Returns true if client-side validation on the form is successful.
2665 isValid : function(){
2666 var items = this.getItems();
2668 items.each(function(f){
2677 * Returns true if any fields in this form have changed since their original load.
2680 isDirty : function(){
2682 var items = this.getItems();
2683 items.each(function(f){
2693 * Performs a predefined action (submit or load) or custom actions you define on this form.
2694 * @param {String} actionName The name of the action type
2695 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2696 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2697 * accept other config options):
2699 Property Type Description
2700 ---------------- --------------- ----------------------------------------------------------------------------------
2701 url String The url for the action (defaults to the form's url)
2702 method String The form method to use (defaults to the form's method, or POST if not defined)
2703 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2704 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2705 validate the form on the client (defaults to false)
2707 * @return {BasicForm} this
2709 doAction : function(action, options){
2710 if(typeof action == 'string'){
2711 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2713 if(this.fireEvent('beforeaction', this, action) !== false){
2714 this.beforeAction(action);
2715 action.run.defer(100, action);
2721 beforeAction : function(action){
2722 var o = action.options;
2724 // not really supported yet.. ??
2726 //if(this.waitMsgTarget === true){
2727 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2728 //}else if(this.waitMsgTarget){
2729 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2730 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2732 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2738 afterAction : function(action, success){
2739 this.activeAction = null;
2740 var o = action.options;
2742 //if(this.waitMsgTarget === true){
2744 //}else if(this.waitMsgTarget){
2745 // this.waitMsgTarget.unmask();
2747 // Roo.MessageBox.updateProgress(1);
2748 // Roo.MessageBox.hide();
2755 Roo.callback(o.success, o.scope, [this, action]);
2756 this.fireEvent('actioncomplete', this, action);
2760 // failure condition..
2761 // we have a scenario where updates need confirming.
2762 // eg. if a locking scenario exists..
2763 // we look for { errors : { needs_confirm : true }} in the response.
2765 (typeof(action.result) != 'undefined') &&
2766 (typeof(action.result.errors) != 'undefined') &&
2767 (typeof(action.result.errors.needs_confirm) != 'undefined')
2770 Roo.log("not supported yet");
2773 Roo.MessageBox.confirm(
2774 "Change requires confirmation",
2775 action.result.errorMsg,
2780 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2790 Roo.callback(o.failure, o.scope, [this, action]);
2791 // show an error message if no failed handler is set..
2792 if (!this.hasListener('actionfailed')) {
2793 Roo.log("need to add dialog support");
2795 Roo.MessageBox.alert("Error",
2796 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2797 action.result.errorMsg :
2798 "Saving Failed, please check your entries or try again"
2803 this.fireEvent('actionfailed', this, action);
2808 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2809 * @param {String} id The value to search for
2812 findField : function(id){
2813 var items = this.getItems();
2814 var field = items.get(id);
2816 items.each(function(f){
2817 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2824 return field || null;
2827 * Mark fields in this form invalid in bulk.
2828 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2829 * @return {BasicForm} this
2831 markInvalid : function(errors){
2832 if(errors instanceof Array){
2833 for(var i = 0, len = errors.length; i < len; i++){
2834 var fieldError = errors[i];
2835 var f = this.findField(fieldError.id);
2837 f.markInvalid(fieldError.msg);
2843 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2844 field.markInvalid(errors[id]);
2848 //Roo.each(this.childForms || [], function (f) {
2849 // f.markInvalid(errors);
2856 * Set values for fields in this form in bulk.
2857 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2858 * @return {BasicForm} this
2860 setValues : function(values){
2861 if(values instanceof Array){ // array of objects
2862 for(var i = 0, len = values.length; i < len; i++){
2864 var f = this.findField(v.id);
2866 f.setValue(v.value);
2867 if(this.trackResetOnLoad){
2868 f.originalValue = f.getValue();
2872 }else{ // object hash
2875 if(typeof values[id] != 'function' && (field = this.findField(id))){
2877 if (field.setFromData &&
2879 field.displayField &&
2880 // combos' with local stores can
2881 // be queried via setValue()
2882 // to set their value..
2883 (field.store && !field.store.isLocal)
2887 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2888 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2889 field.setFromData(sd);
2892 field.setValue(values[id]);
2896 if(this.trackResetOnLoad){
2897 field.originalValue = field.getValue();
2903 //Roo.each(this.childForms || [], function (f) {
2904 // f.setValues(values);
2911 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2912 * they are returned as an array.
2913 * @param {Boolean} asString
2916 getValues : function(asString){
2917 //if (this.childForms) {
2918 // copy values from the child forms
2919 // Roo.each(this.childForms, function (f) {
2920 // this.setValues(f.getValues());
2926 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2927 if(asString === true){
2930 return Roo.urlDecode(fs);
2934 * Returns the fields in this form as an object with key/value pairs.
2935 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2938 getFieldValues : function(with_hidden)
2940 var items = this.getItems();
2942 items.each(function(f){
2946 var v = f.getValue();
2947 if (f.inputType =='radio') {
2948 if (typeof(ret[f.getName()]) == 'undefined') {
2949 ret[f.getName()] = ''; // empty..
2952 if (!f.el.dom.checked) {
2960 // not sure if this supported any more..
2961 if ((typeof(v) == 'object') && f.getRawValue) {
2962 v = f.getRawValue() ; // dates..
2964 // combo boxes where name != hiddenName...
2965 if (f.name != f.getName()) {
2966 ret[f.name] = f.getRawValue();
2968 ret[f.getName()] = v;
2975 * Clears all invalid messages in this form.
2976 * @return {BasicForm} this
2978 clearInvalid : function(){
2979 var items = this.getItems();
2981 items.each(function(f){
2992 * @return {BasicForm} this
2995 var items = this.getItems();
2996 items.each(function(f){
3000 Roo.each(this.childForms || [], function (f) {
3007 getItems : function()
3009 var r=new Roo.util.MixedCollection(false, function(o){
3010 return o.id || (o.id = Roo.id());
3012 var iter = function(el) {
3019 Roo.each(el.items,function(e) {
3038 * Ext JS Library 1.1.1
3039 * Copyright(c) 2006-2007, Ext JS, LLC.
3041 * Originally Released Under LGPL - original licence link has changed is not relivant.
3044 * <script type="text/javascript">
3047 * @class Roo.form.VTypes
3048 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3051 Roo.form.VTypes = function(){
3052 // closure these in so they are only created once.
3053 var alpha = /^[a-zA-Z_]+$/;
3054 var alphanum = /^[a-zA-Z0-9_]+$/;
3055 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3056 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3058 // All these messages and functions are configurable
3061 * The function used to validate email addresses
3062 * @param {String} value The email address
3064 'email' : function(v){
3065 return email.test(v);
3068 * The error text to display when the email validation function returns false
3071 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3073 * The keystroke filter mask to be applied on email input
3076 'emailMask' : /[a-z0-9_\.\-@]/i,
3079 * The function used to validate URLs
3080 * @param {String} value The URL
3082 'url' : function(v){
3086 * The error text to display when the url validation function returns false
3089 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3092 * The function used to validate alpha values
3093 * @param {String} value The value
3095 'alpha' : function(v){
3096 return alpha.test(v);
3099 * The error text to display when the alpha validation function returns false
3102 'alphaText' : 'This field should only contain letters and _',
3104 * The keystroke filter mask to be applied on alpha input
3107 'alphaMask' : /[a-z_]/i,
3110 * The function used to validate alphanumeric values
3111 * @param {String} value The value
3113 'alphanum' : function(v){
3114 return alphanum.test(v);
3117 * The error text to display when the alphanumeric validation function returns false
3120 'alphanumText' : 'This field should only contain letters, numbers and _',
3122 * The keystroke filter mask to be applied on alphanumeric input
3125 'alphanumMask' : /[a-z0-9_]/i
3135 * @class Roo.bootstrap.Input
3136 * @extends Roo.bootstrap.Component
3137 * Bootstrap Input class
3138 * @cfg {Boolean} disabled is it disabled
3139 * @cfg {String} fieldLabel - the label associated
3140 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3141 * @cfg {String} name name of the input
3142 * @cfg {string} fieldLabel - the label associated
3143 * @cfg {string} inputType - input / file submit ...
3144 * @cfg {string} placeholder - placeholder to put in text.
3145 * @cfg {string} before - input group add on before
3146 * @cfg {string} after - input group add on after
3147 * @cfg {string} size - (lg|sm) or leave empty..
3148 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3149 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3150 * @cfg {Number} md colspan out of 12 for computer-sized screens
3151 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3152 * @cfg {string} value default value of the input
3153 * @cfg {Number} labelWidth set the width of label (0-12)
3157 * Create a new Input
3158 * @param {Object} config The config object
3161 Roo.bootstrap.Input = function(config){
3162 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3167 * Fires when this field receives input focus.
3168 * @param {Roo.form.Field} this
3173 * Fires when this field loses input focus.
3174 * @param {Roo.form.Field} this
3179 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3180 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3181 * @param {Roo.form.Field} this
3182 * @param {Roo.EventObject} e The event object
3187 * Fires just before the field blurs if the field value has changed.
3188 * @param {Roo.form.Field} this
3189 * @param {Mixed} newValue The new value
3190 * @param {Mixed} oldValue The original value
3195 * Fires after the field has been marked as invalid.
3196 * @param {Roo.form.Field} this
3197 * @param {String} msg The validation message
3202 * Fires after the field has been validated with no errors.
3203 * @param {Roo.form.Field} this
3208 * Fires after the key up
3209 * @param {Roo.form.Field} this
3210 * @param {Roo.EventObject} e The event Object
3216 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3218 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3219 automatic validation (defaults to "keyup").
3221 validationEvent : "keyup",
3223 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3225 validateOnBlur : true,
3227 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3229 validationDelay : 250,
3231 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3233 focusClass : "x-form-focus", // not needed???
3237 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3239 invalidClass : "has-error",
3242 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3244 selectOnFocus : false,
3247 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3251 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3256 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3258 disableKeyFilter : false,
3261 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3265 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3269 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3271 blankText : "This field is required",
3274 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3278 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3280 maxLength : Number.MAX_VALUE,
3282 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3284 minLengthText : "The minimum length for this field is {0}",
3286 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3288 maxLengthText : "The maximum length for this field is {0}",
3292 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3293 * If available, this function will be called only after the basic validators all return true, and will be passed the
3294 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3298 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3299 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3300 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3304 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3326 getAutoCreate : function(){
3328 var parent = this.parent();
3330 var align = parent.labelAlign;
3336 if(this.inputType != 'hidden'){
3337 cfg.cls = 'form-group' //input-group
3341 // cls: 'form-group' //input-group
3347 type : this.inputType,
3349 cls : 'form-control',
3350 placeholder : this.placeholder || ''
3354 input.name = this.name;
3357 input.cls += ' input-' + this.size;
3360 ['xs','sm','md','lg'].map(function(size){
3361 if (settings[size]) {
3362 cfg.cls += ' col-' + size + '-' + settings[size];
3366 var inputblock = input;
3368 if (this.before || this.after) {
3371 cls : 'input-group',
3375 inputblock.cn.push({
3377 cls : 'input-group-addon',
3381 inputblock.cn.push(input);
3383 inputblock.cn.push({
3385 cls : 'input-group-addon',
3393 Roo.log(this.fieldLabel.length);
3395 if (align ==='left' && this.fieldLabel.length) {
3396 Roo.log("left and has label");
3402 cls : 'control-label col-sm-' + this.labelWidth,
3403 html : this.fieldLabel
3407 cls : "col-sm-" + (12 - this.labelWidth),
3414 } else if ( this.fieldLabel.length) {
3420 //cls : 'input-group-addon',
3421 html : this.fieldLabel
3431 Roo.log(" no label && no align");
3444 if (this.disabled) {
3445 input.disabled=true;
3451 * return the real input element.
3453 inputEl: function ()
3455 return this.el.select('input.form-control',true).first();
3457 setDisabled : function(v)
3459 var i = this.inputEl().dom;
3461 i.removeAttribute('disabled');
3465 i.setAttribute('disabled','true');
3467 initEvents : function()
3470 this.inputEl().on("keydown" , this.fireKey, this);
3471 this.inputEl().on("focus", this.onFocus, this);
3472 this.inputEl().on("blur", this.onBlur, this);
3473 this.inputEl().relayEvent('keyup', this);
3475 // reference to original value for reset
3476 this.originalValue = this.getValue();
3477 //Roo.form.TextField.superclass.initEvents.call(this);
3478 if(this.validationEvent == 'keyup'){
3479 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3480 this.inputEl().on('keyup', this.filterValidation, this);
3482 else if(this.validationEvent !== false){
3483 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3486 if(this.selectOnFocus){
3487 this.on("focus", this.preFocus, this);
3490 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3491 this.inputEl().on("keypress", this.filterKeys, this);
3494 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3495 this.el.on("click", this.autoSize, this);
3498 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3499 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3503 filterValidation : function(e){
3504 if(!e.isNavKeyPress()){
3505 this.validationTask.delay(this.validationDelay);
3509 * Validates the field value
3510 * @return {Boolean} True if the value is valid, else false
3512 validate : function(){
3513 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3514 if(this.disabled || this.validateValue(this.getRawValue())){
3515 this.clearInvalid();
3523 * Validates a value according to the field's validation rules and marks the field as invalid
3524 * if the validation fails
3525 * @param {Mixed} value The value to validate
3526 * @return {Boolean} True if the value is valid, else false
3528 validateValue : function(value){
3529 if(value.length < 1) { // if it's blank
3530 if(this.allowBlank){
3531 this.clearInvalid();
3534 this.markInvalid(this.blankText);
3538 if(value.length < this.minLength){
3539 this.markInvalid(String.format(this.minLengthText, this.minLength));
3542 if(value.length > this.maxLength){
3543 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3547 var vt = Roo.form.VTypes;
3548 if(!vt[this.vtype](value, this)){
3549 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3553 if(typeof this.validator == "function"){
3554 var msg = this.validator(value);
3556 this.markInvalid(msg);
3560 if(this.regex && !this.regex.test(value)){
3561 this.markInvalid(this.regexText);
3570 fireKey : function(e){
3571 //Roo.log('field ' + e.getKey());
3572 if(e.isNavKeyPress()){
3573 this.fireEvent("specialkey", this, e);
3576 focus : function (selectText){
3578 this.inputEl().focus();
3579 if(selectText === true){
3580 this.inputEl().dom.select();
3586 onFocus : function(){
3587 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3588 // this.el.addClass(this.focusClass);
3591 this.hasFocus = true;
3592 this.startValue = this.getValue();
3593 this.fireEvent("focus", this);
3597 beforeBlur : Roo.emptyFn,
3601 onBlur : function(){
3603 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3604 //this.el.removeClass(this.focusClass);
3606 this.hasFocus = false;
3607 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3610 var v = this.getValue();
3611 if(String(v) !== String(this.startValue)){
3612 this.fireEvent('change', this, v, this.startValue);
3614 this.fireEvent("blur", this);
3618 * Resets the current field value to the originally loaded value and clears any validation messages
3621 this.setValue(this.originalValue);
3622 this.clearInvalid();
3625 * Returns the name of the field
3626 * @return {Mixed} name The name field
3628 getName: function(){
3632 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3633 * @return {Mixed} value The field value
3635 getValue : function(){
3636 var v = this.inputEl().getValue();
3640 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3641 * @return {Mixed} value The field value
3643 getRawValue : function(){
3644 var v = this.inputEl().getValue();
3650 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
3651 * @param {Mixed} value The value to set
3653 setRawValue : function(v){
3654 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3657 selectText : function(start, end){
3658 var v = this.getRawValue();
3660 start = start === undefined ? 0 : start;
3661 end = end === undefined ? v.length : end;
3662 var d = this.inputEl().dom;
3663 if(d.setSelectionRange){
3664 d.setSelectionRange(start, end);
3665 }else if(d.createTextRange){
3666 var range = d.createTextRange();
3667 range.moveStart("character", start);
3668 range.moveEnd("character", v.length-end);
3675 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3676 * @param {Mixed} value The value to set
3678 setValue : function(v){
3681 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3687 processValue : function(value){
3688 if(this.stripCharsRe){
3689 var newValue = value.replace(this.stripCharsRe, '');
3690 if(newValue !== value){
3691 this.setRawValue(newValue);
3698 preFocus : function(){
3700 if(this.selectOnFocus){
3701 this.inputEl().dom.select();
3704 filterKeys : function(e){
3706 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3709 var c = e.getCharCode(), cc = String.fromCharCode(c);
3710 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3713 if(!this.maskRe.test(cc)){
3718 * Clear any invalid styles/messages for this field
3720 clearInvalid : function(){
3722 if(!this.el || this.preventMark){ // not rendered
3725 this.el.removeClass(this.invalidClass);
3727 switch(this.msgTarget){
3729 this.el.dom.qtip = '';
3732 this.el.dom.title = '';
3736 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3741 this.errorIcon.dom.qtip = '';
3742 this.errorIcon.hide();
3743 this.un('resize', this.alignErrorIcon, this);
3747 var t = Roo.getDom(this.msgTarget);
3749 t.style.display = 'none';
3753 this.fireEvent('valid', this);
3756 * Mark this field as invalid
3757 * @param {String} msg The validation message
3759 markInvalid : function(msg){
3760 if(!this.el || this.preventMark){ // not rendered
3763 this.el.addClass(this.invalidClass);
3765 msg = msg || this.invalidText;
3766 switch(this.msgTarget){
3768 this.el.dom.qtip = msg;
3769 this.el.dom.qclass = 'x-form-invalid-tip';
3770 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3771 Roo.QuickTips.enable();
3775 this.el.dom.title = msg;
3779 var elp = this.el.findParent('.x-form-element', 5, true);
3780 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3781 this.errorEl.setWidth(elp.getWidth(true)-20);
3783 this.errorEl.update(msg);
3784 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3787 if(!this.errorIcon){
3788 var elp = this.el.findParent('.x-form-element', 5, true);
3789 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3791 this.alignErrorIcon();
3792 this.errorIcon.dom.qtip = msg;
3793 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3794 this.errorIcon.show();
3795 this.on('resize', this.alignErrorIcon, this);
3798 var t = Roo.getDom(this.msgTarget);
3800 t.style.display = this.msgDisplay;
3804 this.fireEvent('invalid', this, msg);
3807 SafariOnKeyDown : function(event)
3809 // this is a workaround for a password hang bug on chrome/ webkit.
3811 var isSelectAll = false;
3813 if(this.inputEl().dom.selectionEnd > 0){
3814 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3816 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3817 event.preventDefault();
3822 if(isSelectAll){ // backspace and delete key
3824 event.preventDefault();
3825 // this is very hacky as keydown always get's upper case.
3827 var cc = String.fromCharCode(event.getCharCode());
3828 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3840 * trigger field - base class for combo..
3845 * @class Roo.bootstrap.TriggerField
3846 * @extends Roo.bootstrap.Input
3847 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3848 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3849 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3850 * for which you can provide a custom implementation. For example:
3852 var trigger = new Roo.bootstrap.TriggerField();
3853 trigger.onTriggerClick = myTriggerFn;
3854 trigger.applyTo('my-field');
3857 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3858 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3859 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3860 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3862 * Create a new TriggerField.
3863 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3864 * to the base TextField)
3866 Roo.bootstrap.TriggerField = function(config){
3867 this.mimicing = false;
3868 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3871 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3873 * @cfg {String} triggerClass A CSS class to apply to the trigger
3876 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3880 /** @cfg {Boolean} grow @hide */
3881 /** @cfg {Number} growMin @hide */
3882 /** @cfg {Number} growMax @hide */
3888 autoSize: Roo.emptyFn,
3895 actionMode : 'wrap',
3899 getAutoCreate : function(){
3901 var parent = this.parent();
3903 var align = parent.labelAlign;
3908 cls: 'form-group' //input-group
3915 type : this.inputType,
3916 cls : 'form-control',
3917 autocomplete: 'off',
3918 placeholder : this.placeholder || ''
3922 input.name = this.name;
3925 input.cls += ' input-' + this.size;
3928 cls: 'combobox-container input-group',
3933 cls: 'form-hidden-field'
3938 cls : 'typeahead typeahead-long dropdown-menu',
3939 style : 'display:none'
3943 cls : 'input-group-addon btn dropdown-toggle',
3951 cls: 'combobox-clear',
3968 if (align ==='left' && this.fieldLabel.length) {
3972 Roo.log("left and has label");
3978 cls : 'col-sm-2 control-label',
3979 html : this.fieldLabel
3990 } else if ( this.fieldLabel.length) {
3996 //cls : 'input-group-addon',
3997 html : this.fieldLabel
4007 Roo.log(" no label && no align");
4014 ['xs','sm','md','lg'].map(function(size){
4015 if (settings[size]) {
4016 cfg.cls += ' col-' + size + '-' + settings[size];
4022 if (this.disabled) {
4023 input.disabled=true;
4032 onResize : function(w, h){
4033 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
4034 if(typeof w == 'number'){
4035 var x = w - this.trigger.getWidth();
4036 this.inputEl().setWidth(this.adjustWidth('input', x));
4037 this.trigger.setStyle('left', x+'px');
4042 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4045 getResizeEl : function(){
4046 return this.inputEl();
4050 getPositionEl : function(){
4051 return this.inputEl();
4055 alignErrorIcon : function(){
4056 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4060 initEvents : function(){
4062 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4063 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4065 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4066 if(this.hideTrigger){
4067 this.trigger.setDisplayed(false);
4069 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
4070 //this.trigger.addClassOnOver('x-form-trigger-over');
4071 //this.trigger.addClassOnClick('x-form-trigger-click');
4074 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
4079 initTrigger : function(){
4084 onDestroy : function(){
4086 this.trigger.removeAllListeners();
4087 // this.trigger.remove();
4090 // this.wrap.remove();
4092 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4096 onFocus : function(){
4097 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4100 this.wrap.addClass('x-trigger-wrap-focus');
4101 this.mimicing = true;
4102 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4103 if(this.monitorTab){
4104 this.el.on("keydown", this.checkTab, this);
4111 checkTab : function(e){
4112 if(e.getKey() == e.TAB){
4118 onBlur : function(){
4123 mimicBlur : function(e, t){
4125 if(!this.wrap.contains(t) && this.validateBlur()){
4132 triggerBlur : function(){
4133 this.mimicing = false;
4134 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4135 if(this.monitorTab){
4136 this.el.un("keydown", this.checkTab, this);
4138 //this.wrap.removeClass('x-trigger-wrap-focus');
4139 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4143 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4144 validateBlur : function(e, t){
4149 onDisable : function(){
4150 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4152 // this.wrap.addClass('x-item-disabled');
4157 onEnable : function(){
4158 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4160 // this.el.removeClass('x-item-disabled');
4165 onShow : function(){
4166 var ae = this.getActionEl();
4169 ae.dom.style.display = '';
4170 ae.dom.style.visibility = 'visible';
4176 onHide : function(){
4177 var ae = this.getActionEl();
4178 ae.dom.style.display = 'none';
4182 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4183 * by an implementing function.
4185 * @param {EventObject} e
4187 onTriggerClick : Roo.emptyFn
4191 * Ext JS Library 1.1.1
4192 * Copyright(c) 2006-2007, Ext JS, LLC.
4194 * Originally Released Under LGPL - original licence link has changed is not relivant.
4197 * <script type="text/javascript">
4202 * @class Roo.data.SortTypes
4204 * Defines the default sorting (casting?) comparison functions used when sorting data.
4206 Roo.data.SortTypes = {
4208 * Default sort that does nothing
4209 * @param {Mixed} s The value being converted
4210 * @return {Mixed} The comparison value
4217 * The regular expression used to strip tags
4221 stripTagsRE : /<\/?[^>]+>/gi,
4224 * Strips all HTML tags to sort on text only
4225 * @param {Mixed} s The value being converted
4226 * @return {String} The comparison value
4228 asText : function(s){
4229 return String(s).replace(this.stripTagsRE, "");
4233 * Strips all HTML tags to sort on text only - Case insensitive
4234 * @param {Mixed} s The value being converted
4235 * @return {String} The comparison value
4237 asUCText : function(s){
4238 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4242 * Case insensitive string
4243 * @param {Mixed} s The value being converted
4244 * @return {String} The comparison value
4246 asUCString : function(s) {
4247 return String(s).toUpperCase();
4252 * @param {Mixed} s The value being converted
4253 * @return {Number} The comparison value
4255 asDate : function(s) {
4259 if(s instanceof Date){
4262 return Date.parse(String(s));
4267 * @param {Mixed} s The value being converted
4268 * @return {Float} The comparison value
4270 asFloat : function(s) {
4271 var val = parseFloat(String(s).replace(/,/g, ""));
4272 if(isNaN(val)) val = 0;
4278 * @param {Mixed} s The value being converted
4279 * @return {Number} The comparison value
4281 asInt : function(s) {
4282 var val = parseInt(String(s).replace(/,/g, ""));
4283 if(isNaN(val)) val = 0;
4288 * Ext JS Library 1.1.1
4289 * Copyright(c) 2006-2007, Ext JS, LLC.
4291 * Originally Released Under LGPL - original licence link has changed is not relivant.
4294 * <script type="text/javascript">
4298 * @class Roo.data.Record
4299 * Instances of this class encapsulate both record <em>definition</em> information, and record
4300 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4301 * to access Records cached in an {@link Roo.data.Store} object.<br>
4303 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4304 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4307 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4309 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4310 * {@link #create}. The parameters are the same.
4311 * @param {Array} data An associative Array of data values keyed by the field name.
4312 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4313 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4314 * not specified an integer id is generated.
4316 Roo.data.Record = function(data, id){
4317 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4322 * Generate a constructor for a specific record layout.
4323 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4324 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4325 * Each field definition object may contain the following properties: <ul>
4326 * <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,
4327 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4328 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4329 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4330 * is being used, then this is a string containing the javascript expression to reference the data relative to
4331 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4332 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4333 * this may be omitted.</p></li>
4334 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4335 * <ul><li>auto (Default, implies no conversion)</li>
4340 * <li>date</li></ul></p></li>
4341 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4342 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4343 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4344 * by the Reader into an object that will be stored in the Record. It is passed the
4345 * following parameters:<ul>
4346 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4348 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4350 * <br>usage:<br><pre><code>
4351 var TopicRecord = Roo.data.Record.create(
4352 {name: 'title', mapping: 'topic_title'},
4353 {name: 'author', mapping: 'username'},
4354 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4355 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4356 {name: 'lastPoster', mapping: 'user2'},
4357 {name: 'excerpt', mapping: 'post_text'}
4360 var myNewRecord = new TopicRecord({
4361 title: 'Do my job please',
4364 lastPost: new Date(),
4365 lastPoster: 'Animal',
4366 excerpt: 'No way dude!'
4368 myStore.add(myNewRecord);
4373 Roo.data.Record.create = function(o){
4375 f.superclass.constructor.apply(this, arguments);
4377 Roo.extend(f, Roo.data.Record);
4378 var p = f.prototype;
4379 p.fields = new Roo.util.MixedCollection(false, function(field){
4382 for(var i = 0, len = o.length; i < len; i++){
4383 p.fields.add(new Roo.data.Field(o[i]));
4385 f.getField = function(name){
4386 return p.fields.get(name);
4391 Roo.data.Record.AUTO_ID = 1000;
4392 Roo.data.Record.EDIT = 'edit';
4393 Roo.data.Record.REJECT = 'reject';
4394 Roo.data.Record.COMMIT = 'commit';
4396 Roo.data.Record.prototype = {
4398 * Readonly flag - true if this record has been modified.
4407 join : function(store){
4412 * Set the named field to the specified value.
4413 * @param {String} name The name of the field to set.
4414 * @param {Object} value The value to set the field to.
4416 set : function(name, value){
4417 if(this.data[name] == value){
4424 if(typeof this.modified[name] == 'undefined'){
4425 this.modified[name] = this.data[name];
4427 this.data[name] = value;
4428 if(!this.editing && this.store){
4429 this.store.afterEdit(this);
4434 * Get the value of the named field.
4435 * @param {String} name The name of the field to get the value of.
4436 * @return {Object} The value of the field.
4438 get : function(name){
4439 return this.data[name];
4443 beginEdit : function(){
4444 this.editing = true;
4449 cancelEdit : function(){
4450 this.editing = false;
4451 delete this.modified;
4455 endEdit : function(){
4456 this.editing = false;
4457 if(this.dirty && this.store){
4458 this.store.afterEdit(this);
4463 * Usually called by the {@link Roo.data.Store} which owns the Record.
4464 * Rejects all changes made to the Record since either creation, or the last commit operation.
4465 * Modified fields are reverted to their original values.
4467 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4468 * of reject operations.
4470 reject : function(){
4471 var m = this.modified;
4473 if(typeof m[n] != "function"){
4474 this.data[n] = m[n];
4478 delete this.modified;
4479 this.editing = false;
4481 this.store.afterReject(this);
4486 * Usually called by the {@link Roo.data.Store} which owns the Record.
4487 * Commits all changes made to the Record since either creation, or the last commit operation.
4489 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4490 * of commit operations.
4492 commit : function(){
4494 delete this.modified;
4495 this.editing = false;
4497 this.store.afterCommit(this);
4502 hasError : function(){
4503 return this.error != null;
4507 clearError : function(){
4512 * Creates a copy of this record.
4513 * @param {String} id (optional) A new record id if you don't want to use this record's id
4516 copy : function(newId) {
4517 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4521 * Ext JS Library 1.1.1
4522 * Copyright(c) 2006-2007, Ext JS, LLC.
4524 * Originally Released Under LGPL - original licence link has changed is not relivant.
4527 * <script type="text/javascript">
4533 * @class Roo.data.Store
4534 * @extends Roo.util.Observable
4535 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4536 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4538 * 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
4539 * has no knowledge of the format of the data returned by the Proxy.<br>
4541 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4542 * instances from the data object. These records are cached and made available through accessor functions.
4544 * Creates a new Store.
4545 * @param {Object} config A config object containing the objects needed for the Store to access data,
4546 * and read the data into Records.
4548 Roo.data.Store = function(config){
4549 this.data = new Roo.util.MixedCollection(false);
4550 this.data.getKey = function(o){
4553 this.baseParams = {};
4560 "multisort" : "_multisort"
4563 if(config && config.data){
4564 this.inlineData = config.data;
4568 Roo.apply(this, config);
4570 if(this.reader){ // reader passed
4571 this.reader = Roo.factory(this.reader, Roo.data);
4572 this.reader.xmodule = this.xmodule || false;
4573 if(!this.recordType){
4574 this.recordType = this.reader.recordType;
4576 if(this.reader.onMetaChange){
4577 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4581 if(this.recordType){
4582 this.fields = this.recordType.prototype.fields;
4588 * @event datachanged
4589 * Fires when the data cache has changed, and a widget which is using this Store
4590 * as a Record cache should refresh its view.
4591 * @param {Store} this
4596 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4597 * @param {Store} this
4598 * @param {Object} meta The JSON metadata
4603 * Fires when Records have been added to the Store
4604 * @param {Store} this
4605 * @param {Roo.data.Record[]} records The array of Records added
4606 * @param {Number} index The index at which the record(s) were added
4611 * Fires when a Record has been removed from the Store
4612 * @param {Store} this
4613 * @param {Roo.data.Record} record The Record that was removed
4614 * @param {Number} index The index at which the record was removed
4619 * Fires when a Record has been updated
4620 * @param {Store} this
4621 * @param {Roo.data.Record} record The Record that was updated
4622 * @param {String} operation The update operation being performed. Value may be one of:
4624 Roo.data.Record.EDIT
4625 Roo.data.Record.REJECT
4626 Roo.data.Record.COMMIT
4632 * Fires when the data cache has been cleared.
4633 * @param {Store} this
4638 * Fires before a request is made for a new data object. If the beforeload handler returns false
4639 * the load action will be canceled.
4640 * @param {Store} this
4641 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4645 * @event beforeloadadd
4646 * Fires after a new set of Records has been loaded.
4647 * @param {Store} this
4648 * @param {Roo.data.Record[]} records The Records that were loaded
4649 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4651 beforeloadadd : true,
4654 * Fires after a new set of Records has been loaded, before they are added to the store.
4655 * @param {Store} this
4656 * @param {Roo.data.Record[]} records The Records that were loaded
4657 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4658 * @params {Object} return from reader
4662 * @event loadexception
4663 * Fires if an exception occurs in the Proxy during loading.
4664 * Called with the signature of the Proxy's "loadexception" event.
4665 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4668 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4669 * @param {Object} load options
4670 * @param {Object} jsonData from your request (normally this contains the Exception)
4672 loadexception : true
4676 this.proxy = Roo.factory(this.proxy, Roo.data);
4677 this.proxy.xmodule = this.xmodule || false;
4678 this.relayEvents(this.proxy, ["loadexception"]);
4680 this.sortToggle = {};
4681 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4683 Roo.data.Store.superclass.constructor.call(this);
4685 if(this.inlineData){
4686 this.loadData(this.inlineData);
4687 delete this.inlineData;
4691 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4693 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4694 * without a remote query - used by combo/forms at present.
4698 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4701 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4704 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4705 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4708 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4709 * on any HTTP request
4712 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4715 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4719 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4720 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4725 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4726 * loaded or when a record is removed. (defaults to false).
4728 pruneModifiedRecords : false,
4734 * Add Records to the Store and fires the add event.
4735 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4737 add : function(records){
4738 records = [].concat(records);
4739 for(var i = 0, len = records.length; i < len; i++){
4740 records[i].join(this);
4742 var index = this.data.length;
4743 this.data.addAll(records);
4744 this.fireEvent("add", this, records, index);
4748 * Remove a Record from the Store and fires the remove event.
4749 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4751 remove : function(record){
4752 var index = this.data.indexOf(record);
4753 this.data.removeAt(index);
4754 if(this.pruneModifiedRecords){
4755 this.modified.remove(record);
4757 this.fireEvent("remove", this, record, index);
4761 * Remove all Records from the Store and fires the clear event.
4763 removeAll : function(){
4765 if(this.pruneModifiedRecords){
4768 this.fireEvent("clear", this);
4772 * Inserts Records to the Store at the given index and fires the add event.
4773 * @param {Number} index The start index at which to insert the passed Records.
4774 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4776 insert : function(index, records){
4777 records = [].concat(records);
4778 for(var i = 0, len = records.length; i < len; i++){
4779 this.data.insert(index, records[i]);
4780 records[i].join(this);
4782 this.fireEvent("add", this, records, index);
4786 * Get the index within the cache of the passed Record.
4787 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4788 * @return {Number} The index of the passed Record. Returns -1 if not found.
4790 indexOf : function(record){
4791 return this.data.indexOf(record);
4795 * Get the index within the cache of the Record with the passed id.
4796 * @param {String} id The id of the Record to find.
4797 * @return {Number} The index of the Record. Returns -1 if not found.
4799 indexOfId : function(id){
4800 return this.data.indexOfKey(id);
4804 * Get the Record with the specified id.
4805 * @param {String} id The id of the Record to find.
4806 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4808 getById : function(id){
4809 return this.data.key(id);
4813 * Get the Record at the specified index.
4814 * @param {Number} index The index of the Record to find.
4815 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4817 getAt : function(index){
4818 return this.data.itemAt(index);
4822 * Returns a range of Records between specified indices.
4823 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4824 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4825 * @return {Roo.data.Record[]} An array of Records
4827 getRange : function(start, end){
4828 return this.data.getRange(start, end);
4832 storeOptions : function(o){
4833 o = Roo.apply({}, o);
4836 this.lastOptions = o;
4840 * Loads the Record cache from the configured Proxy using the configured Reader.
4842 * If using remote paging, then the first load call must specify the <em>start</em>
4843 * and <em>limit</em> properties in the options.params property to establish the initial
4844 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4846 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4847 * and this call will return before the new data has been loaded. Perform any post-processing
4848 * in a callback function, or in a "load" event handler.</strong>
4850 * @param {Object} options An object containing properties which control loading options:<ul>
4851 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4852 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4853 * passed the following arguments:<ul>
4854 * <li>r : Roo.data.Record[]</li>
4855 * <li>options: Options object from the load call</li>
4856 * <li>success: Boolean success indicator</li></ul></li>
4857 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4858 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4861 load : function(options){
4862 options = options || {};
4863 if(this.fireEvent("beforeload", this, options) !== false){
4864 this.storeOptions(options);
4865 var p = Roo.apply(options.params || {}, this.baseParams);
4866 // if meta was not loaded from remote source.. try requesting it.
4867 if (!this.reader.metaFromRemote) {
4870 if(this.sortInfo && this.remoteSort){
4871 var pn = this.paramNames;
4872 p[pn["sort"]] = this.sortInfo.field;
4873 p[pn["dir"]] = this.sortInfo.direction;
4875 if (this.multiSort) {
4876 var pn = this.paramNames;
4877 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4880 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4885 * Reloads the Record cache from the configured Proxy using the configured Reader and
4886 * the options from the last load operation performed.
4887 * @param {Object} options (optional) An object containing properties which may override the options
4888 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4889 * the most recently used options are reused).
4891 reload : function(options){
4892 this.load(Roo.applyIf(options||{}, this.lastOptions));
4896 // Called as a callback by the Reader during a load operation.
4897 loadRecords : function(o, options, success){
4898 if(!o || success === false){
4899 if(success !== false){
4900 this.fireEvent("load", this, [], options, o);
4902 if(options.callback){
4903 options.callback.call(options.scope || this, [], options, false);
4907 // if data returned failure - throw an exception.
4908 if (o.success === false) {
4909 // show a message if no listener is registered.
4910 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4911 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4913 // loadmask wil be hooked into this..
4914 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4917 var r = o.records, t = o.totalRecords || r.length;
4919 this.fireEvent("beforeloadadd", this, r, options, o);
4921 if(!options || options.add !== true){
4922 if(this.pruneModifiedRecords){
4925 for(var i = 0, len = r.length; i < len; i++){
4929 this.data = this.snapshot;
4930 delete this.snapshot;
4933 this.data.addAll(r);
4934 this.totalLength = t;
4936 this.fireEvent("datachanged", this);
4938 this.totalLength = Math.max(t, this.data.length+r.length);
4941 this.fireEvent("load", this, r, options, o);
4942 if(options.callback){
4943 options.callback.call(options.scope || this, r, options, true);
4949 * Loads data from a passed data block. A Reader which understands the format of the data
4950 * must have been configured in the constructor.
4951 * @param {Object} data The data block from which to read the Records. The format of the data expected
4952 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4953 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4955 loadData : function(o, append){
4956 var r = this.reader.readRecords(o);
4957 this.loadRecords(r, {add: append}, true);
4961 * Gets the number of cached records.
4963 * <em>If using paging, this may not be the total size of the dataset. If the data object
4964 * used by the Reader contains the dataset size, then the getTotalCount() function returns
4965 * the data set size</em>
4967 getCount : function(){
4968 return this.data.length || 0;
4972 * Gets the total number of records in the dataset as returned by the server.
4974 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4975 * the dataset size</em>
4977 getTotalCount : function(){
4978 return this.totalLength || 0;
4982 * Returns the sort state of the Store as an object with two properties:
4984 field {String} The name of the field by which the Records are sorted
4985 direction {String} The sort order, "ASC" or "DESC"
4988 getSortState : function(){
4989 return this.sortInfo;
4993 applySort : function(){
4994 if(this.sortInfo && !this.remoteSort){
4995 var s = this.sortInfo, f = s.field;
4996 var st = this.fields.get(f).sortType;
4997 var fn = function(r1, r2){
4998 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4999 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5001 this.data.sort(s.direction, fn);
5002 if(this.snapshot && this.snapshot != this.data){
5003 this.snapshot.sort(s.direction, fn);
5009 * Sets the default sort column and order to be used by the next load operation.
5010 * @param {String} fieldName The name of the field to sort by.
5011 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5013 setDefaultSort : function(field, dir){
5014 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5019 * If remote sorting is used, the sort is performed on the server, and the cache is
5020 * reloaded. If local sorting is used, the cache is sorted internally.
5021 * @param {String} fieldName The name of the field to sort by.
5022 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5024 sort : function(fieldName, dir){
5025 var f = this.fields.get(fieldName);
5027 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5029 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5030 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5035 this.sortToggle[f.name] = dir;
5036 this.sortInfo = {field: f.name, direction: dir};
5037 if(!this.remoteSort){
5039 this.fireEvent("datachanged", this);
5041 this.load(this.lastOptions);
5046 * Calls the specified function for each of the Records in the cache.
5047 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5048 * Returning <em>false</em> aborts and exits the iteration.
5049 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5051 each : function(fn, scope){
5052 this.data.each(fn, scope);
5056 * Gets all records modified since the last commit. Modified records are persisted across load operations
5057 * (e.g., during paging).
5058 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5060 getModifiedRecords : function(){
5061 return this.modified;
5065 createFilterFn : function(property, value, anyMatch){
5066 if(!value.exec){ // not a regex
5067 value = String(value);
5068 if(value.length == 0){
5071 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5074 return value.test(r.data[property]);
5079 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5080 * @param {String} property A field on your records
5081 * @param {Number} start The record index to start at (defaults to 0)
5082 * @param {Number} end The last record index to include (defaults to length - 1)
5083 * @return {Number} The sum
5085 sum : function(property, start, end){
5086 var rs = this.data.items, v = 0;
5088 end = (end || end === 0) ? end : rs.length-1;
5090 for(var i = start; i <= end; i++){
5091 v += (rs[i].data[property] || 0);
5097 * Filter the records by a specified property.
5098 * @param {String} field A field on your records
5099 * @param {String/RegExp} value Either a string that the field
5100 * should start with or a RegExp to test against the field
5101 * @param {Boolean} anyMatch True to match any part not just the beginning
5103 filter : function(property, value, anyMatch){
5104 var fn = this.createFilterFn(property, value, anyMatch);
5105 return fn ? this.filterBy(fn) : this.clearFilter();
5109 * Filter by a function. The specified function will be called with each
5110 * record in this data source. If the function returns true the record is included,
5111 * otherwise it is filtered.
5112 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5113 * @param {Object} scope (optional) The scope of the function (defaults to this)
5115 filterBy : function(fn, scope){
5116 this.snapshot = this.snapshot || this.data;
5117 this.data = this.queryBy(fn, scope||this);
5118 this.fireEvent("datachanged", this);
5122 * Query the records by a specified property.
5123 * @param {String} field A field on your records
5124 * @param {String/RegExp} value Either a string that the field
5125 * should start with or a RegExp to test against the field
5126 * @param {Boolean} anyMatch True to match any part not just the beginning
5127 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5129 query : function(property, value, anyMatch){
5130 var fn = this.createFilterFn(property, value, anyMatch);
5131 return fn ? this.queryBy(fn) : this.data.clone();
5135 * Query by a function. The specified function will be called with each
5136 * record in this data source. If the function returns true the record is included
5138 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5139 * @param {Object} scope (optional) The scope of the function (defaults to this)
5140 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5142 queryBy : function(fn, scope){
5143 var data = this.snapshot || this.data;
5144 return data.filterBy(fn, scope||this);
5148 * Collects unique values for a particular dataIndex from this store.
5149 * @param {String} dataIndex The property to collect
5150 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5151 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5152 * @return {Array} An array of the unique values
5154 collect : function(dataIndex, allowNull, bypassFilter){
5155 var d = (bypassFilter === true && this.snapshot) ?
5156 this.snapshot.items : this.data.items;
5157 var v, sv, r = [], l = {};
5158 for(var i = 0, len = d.length; i < len; i++){
5159 v = d[i].data[dataIndex];
5161 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5170 * Revert to a view of the Record cache with no filtering applied.
5171 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5173 clearFilter : function(suppressEvent){
5174 if(this.snapshot && this.snapshot != this.data){
5175 this.data = this.snapshot;
5176 delete this.snapshot;
5177 if(suppressEvent !== true){
5178 this.fireEvent("datachanged", this);
5184 afterEdit : function(record){
5185 if(this.modified.indexOf(record) == -1){
5186 this.modified.push(record);
5188 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5192 afterReject : function(record){
5193 this.modified.remove(record);
5194 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5198 afterCommit : function(record){
5199 this.modified.remove(record);
5200 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5204 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5205 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5207 commitChanges : function(){
5208 var m = this.modified.slice(0);
5210 for(var i = 0, len = m.length; i < len; i++){
5216 * Cancel outstanding changes on all changed records.
5218 rejectChanges : function(){
5219 var m = this.modified.slice(0);
5221 for(var i = 0, len = m.length; i < len; i++){
5226 onMetaChange : function(meta, rtype, o){
5227 this.recordType = rtype;
5228 this.fields = rtype.prototype.fields;
5229 delete this.snapshot;
5230 this.sortInfo = meta.sortInfo || this.sortInfo;
5232 this.fireEvent('metachange', this, this.reader.meta);
5236 * Ext JS Library 1.1.1
5237 * Copyright(c) 2006-2007, Ext JS, LLC.
5239 * Originally Released Under LGPL - original licence link has changed is not relivant.
5242 * <script type="text/javascript">
5246 * @class Roo.data.SimpleStore
5247 * @extends Roo.data.Store
5248 * Small helper class to make creating Stores from Array data easier.
5249 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5250 * @cfg {Array} fields An array of field definition objects, or field name strings.
5251 * @cfg {Array} data The multi-dimensional array of data
5253 * @param {Object} config
5255 Roo.data.SimpleStore = function(config){
5256 Roo.data.SimpleStore.superclass.constructor.call(this, {
5258 reader: new Roo.data.ArrayReader({
5261 Roo.data.Record.create(config.fields)
5263 proxy : new Roo.data.MemoryProxy(config.data)
5267 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5269 * Ext JS Library 1.1.1
5270 * Copyright(c) 2006-2007, Ext JS, LLC.
5272 * Originally Released Under LGPL - original licence link has changed is not relivant.
5275 * <script type="text/javascript">
5280 * @extends Roo.data.Store
5281 * @class Roo.data.JsonStore
5282 * Small helper class to make creating Stores for JSON data easier. <br/>
5284 var store = new Roo.data.JsonStore({
5285 url: 'get-images.php',
5287 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5290 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5291 * JsonReader and HttpProxy (unless inline data is provided).</b>
5292 * @cfg {Array} fields An array of field definition objects, or field name strings.
5294 * @param {Object} config
5296 Roo.data.JsonStore = function(c){
5297 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5298 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5299 reader: new Roo.data.JsonReader(c, c.fields)
5302 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5304 * Ext JS Library 1.1.1
5305 * Copyright(c) 2006-2007, Ext JS, LLC.
5307 * Originally Released Under LGPL - original licence link has changed is not relivant.
5310 * <script type="text/javascript">
5314 Roo.data.Field = function(config){
5315 if(typeof config == "string"){
5316 config = {name: config};
5318 Roo.apply(this, config);
5324 var st = Roo.data.SortTypes;
5325 // named sortTypes are supported, here we look them up
5326 if(typeof this.sortType == "string"){
5327 this.sortType = st[this.sortType];
5330 // set default sortType for strings and dates
5334 this.sortType = st.asUCString;
5337 this.sortType = st.asDate;
5340 this.sortType = st.none;
5345 var stripRe = /[\$,%]/g;
5347 // prebuilt conversion function for this field, instead of
5348 // switching every time we're reading a value
5350 var cv, dateFormat = this.dateFormat;
5355 cv = function(v){ return v; };
5358 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5362 return v !== undefined && v !== null && v !== '' ?
5363 parseInt(String(v).replace(stripRe, ""), 10) : '';
5368 return v !== undefined && v !== null && v !== '' ?
5369 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5374 cv = function(v){ return v === true || v === "true" || v == 1; };
5381 if(v instanceof Date){
5385 if(dateFormat == "timestamp"){
5386 return new Date(v*1000);
5388 return Date.parseDate(v, dateFormat);
5390 var parsed = Date.parse(v);
5391 return parsed ? new Date(parsed) : null;
5400 Roo.data.Field.prototype = {
5408 * Ext JS Library 1.1.1
5409 * Copyright(c) 2006-2007, Ext JS, LLC.
5411 * Originally Released Under LGPL - original licence link has changed is not relivant.
5414 * <script type="text/javascript">
5417 // Base class for reading structured data from a data source. This class is intended to be
5418 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5421 * @class Roo.data.DataReader
5422 * Base class for reading structured data from a data source. This class is intended to be
5423 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5426 Roo.data.DataReader = function(meta, recordType){
5430 this.recordType = recordType instanceof Array ?
5431 Roo.data.Record.create(recordType) : recordType;
5434 Roo.data.DataReader.prototype = {
5436 * Create an empty record
5437 * @param {Object} data (optional) - overlay some values
5438 * @return {Roo.data.Record} record created.
5440 newRow : function(d) {
5442 this.recordType.prototype.fields.each(function(c) {
5444 case 'int' : da[c.name] = 0; break;
5445 case 'date' : da[c.name] = new Date(); break;
5446 case 'float' : da[c.name] = 0.0; break;
5447 case 'boolean' : da[c.name] = false; break;
5448 default : da[c.name] = ""; break;
5452 return new this.recordType(Roo.apply(da, d));
5457 * Ext JS Library 1.1.1
5458 * Copyright(c) 2006-2007, Ext JS, LLC.
5460 * Originally Released Under LGPL - original licence link has changed is not relivant.
5463 * <script type="text/javascript">
5467 * @class Roo.data.DataProxy
5468 * @extends Roo.data.Observable
5469 * This class is an abstract base class for implementations which provide retrieval of
5470 * unformatted data objects.<br>
5472 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5473 * (of the appropriate type which knows how to parse the data object) to provide a block of
5474 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5476 * Custom implementations must implement the load method as described in
5477 * {@link Roo.data.HttpProxy#load}.
5479 Roo.data.DataProxy = function(){
5483 * Fires before a network request is made to retrieve a data object.
5484 * @param {Object} This DataProxy object.
5485 * @param {Object} params The params parameter to the load function.
5490 * Fires before the load method's callback is called.
5491 * @param {Object} This DataProxy object.
5492 * @param {Object} o The data object.
5493 * @param {Object} arg The callback argument object passed to the load function.
5497 * @event loadexception
5498 * Fires if an Exception occurs during data retrieval.
5499 * @param {Object} This DataProxy object.
5500 * @param {Object} o The data object.
5501 * @param {Object} arg The callback argument object passed to the load function.
5502 * @param {Object} e The Exception.
5504 loadexception : true
5506 Roo.data.DataProxy.superclass.constructor.call(this);
5509 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5512 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5516 * Ext JS Library 1.1.1
5517 * Copyright(c) 2006-2007, Ext JS, LLC.
5519 * Originally Released Under LGPL - original licence link has changed is not relivant.
5522 * <script type="text/javascript">
5525 * @class Roo.data.MemoryProxy
5526 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5527 * to the Reader when its load method is called.
5529 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5531 Roo.data.MemoryProxy = function(data){
5535 Roo.data.MemoryProxy.superclass.constructor.call(this);
5539 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5541 * Load data from the requested source (in this case an in-memory
5542 * data object passed to the constructor), read the data object into
5543 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5544 * process that block using the passed callback.
5545 * @param {Object} params This parameter is not used by the MemoryProxy class.
5546 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5547 * object into a block of Roo.data.Records.
5548 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5549 * The function must be passed <ul>
5550 * <li>The Record block object</li>
5551 * <li>The "arg" argument from the load function</li>
5552 * <li>A boolean success indicator</li>
5554 * @param {Object} scope The scope in which to call the callback
5555 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5557 load : function(params, reader, callback, scope, arg){
5558 params = params || {};
5561 result = reader.readRecords(this.data);
5563 this.fireEvent("loadexception", this, arg, null, e);
5564 callback.call(scope, null, arg, false);
5567 callback.call(scope, result, arg, true);
5571 update : function(params, records){
5576 * Ext JS Library 1.1.1
5577 * Copyright(c) 2006-2007, Ext JS, LLC.
5579 * Originally Released Under LGPL - original licence link has changed is not relivant.
5582 * <script type="text/javascript">
5585 * @class Roo.data.HttpProxy
5586 * @extends Roo.data.DataProxy
5587 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5588 * configured to reference a certain URL.<br><br>
5590 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5591 * from which the running page was served.<br><br>
5593 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5595 * Be aware that to enable the browser to parse an XML document, the server must set
5596 * the Content-Type header in the HTTP response to "text/xml".
5598 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5599 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5600 * will be used to make the request.
5602 Roo.data.HttpProxy = function(conn){
5603 Roo.data.HttpProxy.superclass.constructor.call(this);
5604 // is conn a conn config or a real conn?
5606 this.useAjax = !conn || !conn.events;
5610 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5611 // thse are take from connection...
5614 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5617 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5618 * extra parameters to each request made by this object. (defaults to undefined)
5621 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5622 * to each request made by this object. (defaults to undefined)
5625 * @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)
5628 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5631 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5637 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5641 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5642 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5643 * a finer-grained basis than the DataProxy events.
5645 getConnection : function(){
5646 return this.useAjax ? Roo.Ajax : this.conn;
5650 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5651 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5652 * process that block using the passed callback.
5653 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5654 * for the request to the remote server.
5655 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5656 * object into a block of Roo.data.Records.
5657 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5658 * The function must be passed <ul>
5659 * <li>The Record block object</li>
5660 * <li>The "arg" argument from the load function</li>
5661 * <li>A boolean success indicator</li>
5663 * @param {Object} scope The scope in which to call the callback
5664 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5666 load : function(params, reader, callback, scope, arg){
5667 if(this.fireEvent("beforeload", this, params) !== false){
5669 params : params || {},
5671 callback : callback,
5676 callback : this.loadResponse,
5680 Roo.applyIf(o, this.conn);
5681 if(this.activeRequest){
5682 Roo.Ajax.abort(this.activeRequest);
5684 this.activeRequest = Roo.Ajax.request(o);
5686 this.conn.request(o);
5689 callback.call(scope||this, null, arg, false);
5694 loadResponse : function(o, success, response){
5695 delete this.activeRequest;
5697 this.fireEvent("loadexception", this, o, response);
5698 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5703 result = o.reader.read(response);
5705 this.fireEvent("loadexception", this, o, response, e);
5706 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5710 this.fireEvent("load", this, o, o.request.arg);
5711 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5715 update : function(dataSet){
5720 updateResponse : function(dataSet){
5725 * Ext JS Library 1.1.1
5726 * Copyright(c) 2006-2007, Ext JS, LLC.
5728 * Originally Released Under LGPL - original licence link has changed is not relivant.
5731 * <script type="text/javascript">
5735 * @class Roo.data.ScriptTagProxy
5736 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5737 * other than the originating domain of the running page.<br><br>
5739 * <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
5740 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5742 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5743 * source code that is used as the source inside a <script> tag.<br><br>
5745 * In order for the browser to process the returned data, the server must wrap the data object
5746 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5747 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5748 * depending on whether the callback name was passed:
5751 boolean scriptTag = false;
5752 String cb = request.getParameter("callback");
5755 response.setContentType("text/javascript");
5757 response.setContentType("application/x-json");
5759 Writer out = response.getWriter();
5761 out.write(cb + "(");
5763 out.print(dataBlock.toJsonString());
5770 * @param {Object} config A configuration object.
5772 Roo.data.ScriptTagProxy = function(config){
5773 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5774 Roo.apply(this, config);
5775 this.head = document.getElementsByTagName("head")[0];
5778 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5780 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5782 * @cfg {String} url The URL from which to request the data object.
5785 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5789 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5790 * the server the name of the callback function set up by the load call to process the returned data object.
5791 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5792 * javascript output which calls this named function passing the data object as its only parameter.
5794 callbackParam : "callback",
5796 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5797 * name to the request.
5802 * Load data from the configured URL, read the data object into
5803 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5804 * process that block using the passed callback.
5805 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5806 * for the request to the remote server.
5807 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5808 * object into a block of Roo.data.Records.
5809 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5810 * The function must be passed <ul>
5811 * <li>The Record block object</li>
5812 * <li>The "arg" argument from the load function</li>
5813 * <li>A boolean success indicator</li>
5815 * @param {Object} scope The scope in which to call the callback
5816 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5818 load : function(params, reader, callback, scope, arg){
5819 if(this.fireEvent("beforeload", this, params) !== false){
5821 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5824 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5826 url += "&_dc=" + (new Date().getTime());
5828 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5831 cb : "stcCallback"+transId,
5832 scriptId : "stcScript"+transId,
5836 callback : callback,
5842 window[trans.cb] = function(o){
5843 conn.handleResponse(o, trans);
5846 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5848 if(this.autoAbort !== false){
5852 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5854 var script = document.createElement("script");
5855 script.setAttribute("src", url);
5856 script.setAttribute("type", "text/javascript");
5857 script.setAttribute("id", trans.scriptId);
5858 this.head.appendChild(script);
5862 callback.call(scope||this, null, arg, false);
5867 isLoading : function(){
5868 return this.trans ? true : false;
5872 * Abort the current server request.
5875 if(this.isLoading()){
5876 this.destroyTrans(this.trans);
5881 destroyTrans : function(trans, isLoaded){
5882 this.head.removeChild(document.getElementById(trans.scriptId));
5883 clearTimeout(trans.timeoutId);
5885 window[trans.cb] = undefined;
5887 delete window[trans.cb];
5890 // if hasn't been loaded, wait for load to remove it to prevent script error
5891 window[trans.cb] = function(){
5892 window[trans.cb] = undefined;
5894 delete window[trans.cb];
5901 handleResponse : function(o, trans){
5903 this.destroyTrans(trans, true);
5906 result = trans.reader.readRecords(o);
5908 this.fireEvent("loadexception", this, o, trans.arg, e);
5909 trans.callback.call(trans.scope||window, null, trans.arg, false);
5912 this.fireEvent("load", this, o, trans.arg);
5913 trans.callback.call(trans.scope||window, result, trans.arg, true);
5917 handleFailure : function(trans){
5919 this.destroyTrans(trans, false);
5920 this.fireEvent("loadexception", this, null, trans.arg);
5921 trans.callback.call(trans.scope||window, null, trans.arg, false);
5925 * Ext JS Library 1.1.1
5926 * Copyright(c) 2006-2007, Ext JS, LLC.
5928 * Originally Released Under LGPL - original licence link has changed is not relivant.
5931 * <script type="text/javascript">
5935 * @class Roo.data.JsonReader
5936 * @extends Roo.data.DataReader
5937 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5938 * based on mappings in a provided Roo.data.Record constructor.
5940 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5941 * in the reply previously.
5946 var RecordDef = Roo.data.Record.create([
5947 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5948 {name: 'occupation'} // This field will use "occupation" as the mapping.
5950 var myReader = new Roo.data.JsonReader({
5951 totalProperty: "results", // The property which contains the total dataset size (optional)
5952 root: "rows", // The property which contains an Array of row objects
5953 id: "id" // The property within each row object that provides an ID for the record (optional)
5957 * This would consume a JSON file like this:
5959 { 'results': 2, 'rows': [
5960 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5961 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5964 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5965 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5966 * paged from the remote server.
5967 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5968 * @cfg {String} root name of the property which contains the Array of row objects.
5969 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5971 * Create a new JsonReader
5972 * @param {Object} meta Metadata configuration options
5973 * @param {Object} recordType Either an Array of field definition objects,
5974 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5976 Roo.data.JsonReader = function(meta, recordType){
5979 // set some defaults:
5981 totalProperty: 'total',
5982 successProperty : 'success',
5987 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5989 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5992 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
5993 * Used by Store query builder to append _requestMeta to params.
5996 metaFromRemote : false,
5998 * This method is only used by a DataProxy which has retrieved data from a remote server.
5999 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6000 * @return {Object} data A data block which is used by an Roo.data.Store object as
6001 * a cache of Roo.data.Records.
6003 read : function(response){
6004 var json = response.responseText;
6006 var o = /* eval:var:o */ eval("("+json+")");
6008 throw {message: "JsonReader.read: Json object not found"};
6014 this.metaFromRemote = true;
6015 this.meta = o.metaData;
6016 this.recordType = Roo.data.Record.create(o.metaData.fields);
6017 this.onMetaChange(this.meta, this.recordType, o);
6019 return this.readRecords(o);
6022 // private function a store will implement
6023 onMetaChange : function(meta, recordType, o){
6030 simpleAccess: function(obj, subsc) {
6037 getJsonAccessor: function(){
6039 return function(expr) {
6041 return(re.test(expr))
6042 ? new Function("obj", "return obj." + expr)
6052 * Create a data block containing Roo.data.Records from an XML document.
6053 * @param {Object} o An object which contains an Array of row objects in the property specified
6054 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6055 * which contains the total size of the dataset.
6056 * @return {Object} data A data block which is used by an Roo.data.Store object as
6057 * a cache of Roo.data.Records.
6059 readRecords : function(o){
6061 * After any data loads, the raw JSON data is available for further custom processing.
6065 var s = this.meta, Record = this.recordType,
6066 f = Record.prototype.fields, fi = f.items, fl = f.length;
6068 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6070 if(s.totalProperty) {
6071 this.getTotal = this.getJsonAccessor(s.totalProperty);
6073 if(s.successProperty) {
6074 this.getSuccess = this.getJsonAccessor(s.successProperty);
6076 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6078 var g = this.getJsonAccessor(s.id);
6079 this.getId = function(rec) {
6081 return (r === undefined || r === "") ? null : r;
6084 this.getId = function(){return null;};
6087 for(var jj = 0; jj < fl; jj++){
6089 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6090 this.ef[jj] = this.getJsonAccessor(map);
6094 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6095 if(s.totalProperty){
6096 var vt = parseInt(this.getTotal(o), 10);
6101 if(s.successProperty){
6102 var vs = this.getSuccess(o);
6103 if(vs === false || vs === 'false'){
6108 for(var i = 0; i < c; i++){
6111 var id = this.getId(n);
6112 for(var j = 0; j < fl; j++){
6114 var v = this.ef[j](n);
6116 Roo.log('missing convert for ' + f.name);
6120 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6122 var record = new Record(values, id);
6124 records[i] = record;
6130 totalRecords : totalRecords
6135 * Ext JS Library 1.1.1
6136 * Copyright(c) 2006-2007, Ext JS, LLC.
6138 * Originally Released Under LGPL - original licence link has changed is not relivant.
6141 * <script type="text/javascript">
6145 * @class Roo.data.ArrayReader
6146 * @extends Roo.data.DataReader
6147 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6148 * Each element of that Array represents a row of data fields. The
6149 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6150 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6154 var RecordDef = Roo.data.Record.create([
6155 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6156 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6158 var myReader = new Roo.data.ArrayReader({
6159 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6163 * This would consume an Array like this:
6165 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6167 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6169 * Create a new JsonReader
6170 * @param {Object} meta Metadata configuration options.
6171 * @param {Object} recordType Either an Array of field definition objects
6172 * as specified to {@link Roo.data.Record#create},
6173 * or an {@link Roo.data.Record} object
6174 * created using {@link Roo.data.Record#create}.
6176 Roo.data.ArrayReader = function(meta, recordType){
6177 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6180 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6182 * Create a data block containing Roo.data.Records from an XML document.
6183 * @param {Object} o An Array of row objects which represents the dataset.
6184 * @return {Object} data A data block which is used by an Roo.data.Store object as
6185 * a cache of Roo.data.Records.
6187 readRecords : function(o){
6188 var sid = this.meta ? this.meta.id : null;
6189 var recordType = this.recordType, fields = recordType.prototype.fields;
6192 for(var i = 0; i < root.length; i++){
6195 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6196 for(var j = 0, jlen = fields.length; j < jlen; j++){
6197 var f = fields.items[j];
6198 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6199 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6203 var record = new recordType(values, id);
6205 records[records.length] = record;
6209 totalRecords : records.length
6218 * @class Roo.bootstrap.ComboBox
6219 * @extends Roo.bootstrap.TriggerField
6220 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6222 * Create a new ComboBox.
6223 * @param {Object} config Configuration options
6225 Roo.bootstrap.ComboBox = function(config){
6226 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6230 * Fires when the dropdown list is expanded
6231 * @param {Roo.bootstrap.ComboBox} combo This combo box
6236 * Fires when the dropdown list is collapsed
6237 * @param {Roo.bootstrap.ComboBox} combo This combo box
6241 * @event beforeselect
6242 * Fires before a list item is selected. Return false to cancel the selection.
6243 * @param {Roo.bootstrap.ComboBox} combo This combo box
6244 * @param {Roo.data.Record} record The data record returned from the underlying store
6245 * @param {Number} index The index of the selected item in the dropdown list
6247 'beforeselect' : true,
6250 * Fires when a list item is selected
6251 * @param {Roo.bootstrap.ComboBox} combo This combo box
6252 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6253 * @param {Number} index The index of the selected item in the dropdown list
6257 * @event beforequery
6258 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6259 * The event object passed has these properties:
6260 * @param {Roo.bootstrap.ComboBox} combo This combo box
6261 * @param {String} query The query
6262 * @param {Boolean} forceAll true to force "all" query
6263 * @param {Boolean} cancel true to cancel the query
6264 * @param {Object} e The query event object
6266 'beforequery': true,
6269 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6270 * @param {Roo.bootstrap.ComboBox} combo This combo box
6275 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6276 * @param {Roo.bootstrap.ComboBox} combo This combo box
6277 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6285 this.selectedIndex = -1;
6286 if(this.mode == 'local'){
6287 if(config.queryDelay === undefined){
6288 this.queryDelay = 10;
6290 if(config.minChars === undefined){
6296 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6299 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6300 * rendering into an Roo.Editor, defaults to false)
6303 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6304 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6307 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6310 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6311 * the dropdown list (defaults to undefined, with no header element)
6315 * @cfg {String/Roo.Template} tpl The template to use to render the output
6319 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6321 listWidth: undefined,
6323 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6324 * mode = 'remote' or 'text' if mode = 'local')
6326 displayField: undefined,
6328 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6329 * mode = 'remote' or 'value' if mode = 'local').
6330 * Note: use of a valueField requires the user make a selection
6331 * in order for a value to be mapped.
6333 valueField: undefined,
6337 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6338 * field's data value (defaults to the underlying DOM element's name)
6340 hiddenName: undefined,
6342 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6346 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6348 selectedClass: 'active',
6351 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6355 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6356 * anchor positions (defaults to 'tl-bl')
6358 listAlign: 'tl-bl?',
6360 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6364 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
6365 * query specified by the allQuery config option (defaults to 'query')
6367 triggerAction: 'query',
6369 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6370 * (defaults to 4, does not apply if editable = false)
6374 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6375 * delay (typeAheadDelay) if it matches a known value (defaults to false)
6379 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6380 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6384 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6385 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
6389 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
6390 * when editable = true (defaults to false)
6392 selectOnFocus:false,
6394 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6396 queryParam: 'query',
6398 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
6399 * when mode = 'remote' (defaults to 'Loading...')
6401 loadingText: 'Loading...',
6403 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6407 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6411 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6412 * traditional select (defaults to true)
6416 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6420 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6424 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6425 * listWidth has a higher value)
6429 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6430 * allow the user to set arbitrary text into the field (defaults to false)
6432 forceSelection:false,
6434 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6435 * if typeAhead = true (defaults to 250)
6437 typeAheadDelay : 250,
6439 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6440 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6442 valueNotFoundText : undefined,
6444 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6449 * @cfg {Boolean} disableClear Disable showing of clear button.
6451 disableClear : false,
6453 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
6455 alwaysQuery : false,
6461 // element that contains real text value.. (when hidden is used..)
6464 initEvents: function(){
6467 throw "can not find store for combo";
6469 this.store = Roo.factory(this.store, Roo.data);
6473 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6476 if(this.hiddenName){
6478 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6480 this.hiddenField.dom.value =
6481 this.hiddenValue !== undefined ? this.hiddenValue :
6482 this.value !== undefined ? this.value : '';
6484 // prevent input submission
6485 this.el.dom.removeAttribute('name');
6486 this.hiddenField.dom.setAttribute('name', this.hiddenName);
6491 // this.el.dom.setAttribute('autocomplete', 'off');
6494 var cls = 'x-combo-list';
6495 this.list = this.el.select('ul',true).first();
6497 //this.list = new Roo.Layer({
6498 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6501 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6502 this.list.setWidth(lw);
6504 this.list.on('mouseover', this.onViewOver, this);
6505 this.list.on('mousemove', this.onViewMove, this);
6508 this.list.swallowEvent('mousewheel');
6509 this.assetHeight = 0;
6512 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6513 this.assetHeight += this.header.getHeight();
6516 this.innerList = this.list.createChild({cls:cls+'-inner'});
6517 this.innerList.on('mouseover', this.onViewOver, this);
6518 this.innerList.on('mousemove', this.onViewMove, this);
6519 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6521 if(this.allowBlank && !this.pageSize && !this.disableClear){
6522 this.footer = this.list.createChild({cls:cls+'-ft'});
6523 this.pageTb = new Roo.Toolbar(this.footer);
6527 this.footer = this.list.createChild({cls:cls+'-ft'});
6528 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6529 {pageSize: this.pageSize});
6533 if (this.pageTb && this.allowBlank && !this.disableClear) {
6535 this.pageTb.add(new Roo.Toolbar.Fill(), {
6536 cls: 'x-btn-icon x-btn-clear',
6542 _this.onSelect(false, -1);
6547 this.assetHeight += this.footer.getHeight();
6552 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6555 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6556 singleSelect:true, store: this.store, selectedClass: this.selectedClass
6558 //this.view.wrapEl.setDisplayed(false);
6559 this.view.on('click', this.onViewClick, this);
6563 this.store.on('beforeload', this.onBeforeLoad, this);
6564 this.store.on('load', this.onLoad, this);
6565 this.store.on('loadexception', this.onLoadException, this);
6568 this.resizer = new Roo.Resizable(this.list, {
6569 pinned:true, handles:'se'
6571 this.resizer.on('resize', function(r, w, h){
6572 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6574 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6575 this.restrictHeight();
6577 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6581 this.editable = true;
6582 this.setEditable(false);
6587 if (typeof(this.events.add.listeners) != 'undefined') {
6589 this.addicon = this.wrap.createChild(
6590 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
6592 this.addicon.on('click', function(e) {
6593 this.fireEvent('add', this);
6596 if (typeof(this.events.edit.listeners) != 'undefined') {
6598 this.editicon = this.wrap.createChild(
6599 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
6601 this.editicon.setStyle('margin-left', '40px');
6603 this.editicon.on('click', function(e) {
6605 // we fire even if inothing is selected..
6606 this.fireEvent('edit', this, this.lastData );
6613 this.keyNav = new Roo.KeyNav(this.inputEl(), {
6615 this.inKeyMode = true;
6619 "down" : function(e){
6620 if(!this.isExpanded()){
6621 this.onTriggerClick();
6623 this.inKeyMode = true;
6628 "enter" : function(e){
6633 "esc" : function(e){
6637 "tab" : function(e){
6638 this.onViewClick(false);
6639 this.fireEvent("specialkey", this, e);
6645 doRelay : function(foo, bar, hname){
6646 if(hname == 'down' || this.scope.isExpanded()){
6647 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6656 this.queryDelay = Math.max(this.queryDelay || 10,
6657 this.mode == 'local' ? 10 : 250);
6660 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6663 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6665 if(this.editable !== false){
6666 this.inputEl().on("keyup", this.onKeyUp, this);
6668 if(this.forceSelection){
6669 this.on('blur', this.doForce, this);
6673 onDestroy : function(){
6675 this.view.setStore(null);
6676 this.view.el.removeAllListeners();
6677 this.view.el.remove();
6678 this.view.purgeListeners();
6681 this.list.dom.innerHTML = '';
6684 this.store.un('beforeload', this.onBeforeLoad, this);
6685 this.store.un('load', this.onLoad, this);
6686 this.store.un('loadexception', this.onLoadException, this);
6688 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6692 fireKey : function(e){
6693 if(e.isNavKeyPress() && !this.list.isVisible()){
6694 this.fireEvent("specialkey", this, e);
6699 onResize: function(w, h){
6700 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6702 if(typeof w != 'number'){
6703 // we do not handle it!?!?
6706 var tw = this.trigger.getWidth();
6707 // tw += this.addicon ? this.addicon.getWidth() : 0;
6708 // tw += this.editicon ? this.editicon.getWidth() : 0;
6710 this.inputEl().setWidth( this.adjustWidth('input', x));
6712 //this.trigger.setStyle('left', x+'px');
6714 if(this.list && this.listWidth === undefined){
6715 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6716 this.list.setWidth(lw);
6717 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6725 * Allow or prevent the user from directly editing the field text. If false is passed,
6726 * the user will only be able to select from the items defined in the dropdown list. This method
6727 * is the runtime equivalent of setting the 'editable' config option at config time.
6728 * @param {Boolean} value True to allow the user to directly edit the field text
6730 setEditable : function(value){
6731 if(value == this.editable){
6734 this.editable = value;
6736 this.inputEl().dom.setAttribute('readOnly', true);
6737 this.inputEl().on('mousedown', this.onTriggerClick, this);
6738 this.inputEl().addClass('x-combo-noedit');
6740 this.inputEl().dom.setAttribute('readOnly', false);
6741 this.inputEl().un('mousedown', this.onTriggerClick, this);
6742 this.inputEl().removeClass('x-combo-noedit');
6747 onBeforeLoad : function(){
6751 //this.innerList.update(this.loadingText ?
6752 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6753 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6755 this.restrictHeight();
6756 this.selectedIndex = -1;
6760 onLoad : function(){
6764 if(this.store.getCount() > 0){
6766 this.restrictHeight();
6767 if(this.lastQuery == this.allQuery){
6769 this.inputEl().dom.select();
6771 if(!this.selectByValue(this.value, true)){
6772 this.select(0, true);
6776 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6777 this.taTask.delay(this.typeAheadDelay);
6781 this.onEmptyResults();
6786 onLoadException : function()
6789 Roo.log(this.store.reader.jsonData);
6790 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6792 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6798 onTypeAhead : function(){
6799 if(this.store.getCount() > 0){
6800 var r = this.store.getAt(0);
6801 var newValue = r.data[this.displayField];
6802 var len = newValue.length;
6803 var selStart = this.getRawValue().length;
6805 if(selStart != len){
6806 this.setRawValue(newValue);
6807 this.selectText(selStart, newValue.length);
6813 onSelect : function(record, index){
6814 if(this.fireEvent('beforeselect', this, record, index) !== false){
6815 this.setFromData(index > -1 ? record.data : false);
6817 this.fireEvent('select', this, record, index);
6822 * Returns the currently selected field value or empty string if no value is set.
6823 * @return {String} value The selected value
6825 getValue : function(){
6826 if(this.valueField){
6827 return typeof this.value != 'undefined' ? this.value : '';
6829 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6834 * Clears any text/value currently set in the field
6836 clearValue : function(){
6837 if(this.hiddenField){
6838 this.hiddenField.dom.value = '';
6841 this.setRawValue('');
6842 this.lastSelectionText = '';
6847 * Sets the specified value into the field. If the value finds a match, the corresponding record text
6848 * will be displayed in the field. If the value does not match the data value of an existing item,
6849 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6850 * Otherwise the field will be blank (although the value will still be set).
6851 * @param {String} value The value to match
6853 setValue : function(v){
6855 if(this.valueField){
6856 var r = this.findRecord(this.valueField, v);
6858 text = r.data[this.displayField];
6859 }else if(this.valueNotFoundText !== undefined){
6860 text = this.valueNotFoundText;
6863 this.lastSelectionText = text;
6864 if(this.hiddenField){
6865 this.hiddenField.dom.value = v;
6867 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6871 * @property {Object} the last set data for the element
6876 * Sets the value of the field based on a object which is related to the record format for the store.
6877 * @param {Object} value the value to set as. or false on reset?
6879 setFromData : function(o){
6880 var dv = ''; // display value
6881 var vv = ''; // value value..
6883 if (this.displayField) {
6884 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6886 // this is an error condition!!!
6887 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
6890 if(this.valueField){
6891 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6893 if(this.hiddenField){
6894 this.hiddenField.dom.value = vv;
6896 this.lastSelectionText = dv;
6897 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6901 // no hidden field.. - we store the value in 'value', but still display
6902 // display field!!!!
6903 this.lastSelectionText = dv;
6904 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6911 // overridden so that last data is reset..
6912 this.setValue(this.originalValue);
6913 this.clearInvalid();
6914 this.lastData = false;
6916 this.view.clearSelections();
6920 findRecord : function(prop, value){
6922 if(this.store.getCount() > 0){
6923 this.store.each(function(r){
6924 if(r.data[prop] == value){
6936 // returns hidden if it's set..
6937 if (!this.rendered) {return ''};
6938 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
6942 onViewMove : function(e, t){
6943 this.inKeyMode = false;
6947 onViewOver : function(e, t){
6948 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6951 var item = this.view.findItemFromChild(t);
6953 var index = this.view.indexOf(item);
6954 this.select(index, false);
6959 onViewClick : function(doFocus)
6961 var index = this.view.getSelectedIndexes()[0];
6962 var r = this.store.getAt(index);
6964 this.onSelect(r, index);
6966 if(doFocus !== false && !this.blockFocus){
6967 this.inputEl().focus();
6972 restrictHeight : function(){
6973 //this.innerList.dom.style.height = '';
6974 //var inner = this.innerList.dom;
6975 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6976 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6977 //this.list.beginUpdate();
6978 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6979 this.list.alignTo(this.inputEl(), this.listAlign);
6980 //this.list.endUpdate();
6984 onEmptyResults : function(){
6989 * Returns true if the dropdown list is expanded, else false.
6991 isExpanded : function(){
6992 return this.list.isVisible();
6996 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6997 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6998 * @param {String} value The data value of the item to select
6999 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7000 * selected item if it is not currently in view (defaults to true)
7001 * @return {Boolean} True if the value matched an item in the list, else false
7003 selectByValue : function(v, scrollIntoView){
7004 if(v !== undefined && v !== null){
7005 var r = this.findRecord(this.valueField || this.displayField, v);
7007 this.select(this.store.indexOf(r), scrollIntoView);
7015 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7016 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7017 * @param {Number} index The zero-based index of the list item to select
7018 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7019 * selected item if it is not currently in view (defaults to true)
7021 select : function(index, scrollIntoView){
7022 this.selectedIndex = index;
7023 this.view.select(index);
7024 if(scrollIntoView !== false){
7025 var el = this.view.getNode(index);
7027 //this.innerList.scrollChildIntoView(el, false);
7034 selectNext : function(){
7035 var ct = this.store.getCount();
7037 if(this.selectedIndex == -1){
7039 }else if(this.selectedIndex < ct-1){
7040 this.select(this.selectedIndex+1);
7046 selectPrev : function(){
7047 var ct = this.store.getCount();
7049 if(this.selectedIndex == -1){
7051 }else if(this.selectedIndex != 0){
7052 this.select(this.selectedIndex-1);
7058 onKeyUp : function(e){
7059 if(this.editable !== false && !e.isSpecialKey()){
7060 this.lastKey = e.getKey();
7061 this.dqTask.delay(this.queryDelay);
7066 validateBlur : function(){
7067 return !this.list || !this.list.isVisible();
7071 initQuery : function(){
7072 this.doQuery(this.getRawValue());
7076 doForce : function(){
7077 if(this.el.dom.value.length > 0){
7079 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
7085 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
7086 * query allowing the query action to be canceled if needed.
7087 * @param {String} query The SQL query to execute
7088 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
7089 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
7090 * saved in the current store (defaults to false)
7092 doQuery : function(q, forceAll){
7093 if(q === undefined || q === null){
7102 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7106 forceAll = qe.forceAll;
7107 if(forceAll === true || (q.length >= this.minChars)){
7108 if(this.lastQuery != q || this.alwaysQuery){
7110 if(this.mode == 'local'){
7111 this.selectedIndex = -1;
7113 this.store.clearFilter();
7115 this.store.filter(this.displayField, q);
7119 this.store.baseParams[this.queryParam] = q;
7121 params: this.getParams(q)
7126 this.selectedIndex = -1;
7133 getParams : function(q){
7135 //p[this.queryParam] = q;
7138 p.limit = this.pageSize;
7144 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7146 collapse : function(){
7147 if(!this.isExpanded()){
7151 Roo.get(document).un('mousedown', this.collapseIf, this);
7152 Roo.get(document).un('mousewheel', this.collapseIf, this);
7153 if (!this.editable) {
7154 Roo.get(document).un('keydown', this.listKeyPress, this);
7156 this.fireEvent('collapse', this);
7160 collapseIf : function(e){
7161 if(!e.within(this.el) && !e.within(this.el)){
7167 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7169 expand : function(){
7171 if(this.isExpanded() || !this.hasFocus){
7174 this.list.alignTo(this.inputEl(), this.listAlign);
7176 Roo.get(document).on('mousedown', this.collapseIf, this);
7177 Roo.get(document).on('mousewheel', this.collapseIf, this);
7178 if (!this.editable) {
7179 Roo.get(document).on('keydown', this.listKeyPress, this);
7182 this.fireEvent('expand', this);
7186 // Implements the default empty TriggerField.onTriggerClick function
7187 onTriggerClick : function()
7189 Roo.log('trigger click');
7194 if(this.isExpanded()){
7196 if (!this.blockFocus) {
7197 this.inputEl().focus();
7201 this.hasFocus = true;
7202 if(this.triggerAction == 'all') {
7203 this.doQuery(this.allQuery, true);
7205 this.doQuery(this.getRawValue());
7207 if (!this.blockFocus) {
7208 this.inputEl().focus();
7212 listKeyPress : function(e)
7214 //Roo.log('listkeypress');
7215 // scroll to first matching element based on key pres..
7216 if (e.isSpecialKey()) {
7219 var k = String.fromCharCode(e.getKey()).toUpperCase();
7222 var csel = this.view.getSelectedNodes();
7223 var cselitem = false;
7225 var ix = this.view.indexOf(csel[0]);
7226 cselitem = this.store.getAt(ix);
7227 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7233 this.store.each(function(v) {
7235 // start at existing selection.
7236 if (cselitem.id == v.id) {
7242 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7243 match = this.store.indexOf(v);
7249 if (match === false) {
7250 return true; // no more action?
7253 this.view.select(match);
7254 var sn = Roo.get(this.view.getSelectedNodes()[0])
7255 //sn.scrollIntoView(sn.dom.parentNode, false);
7259 * @cfg {Boolean} grow
7263 * @cfg {Number} growMin
7267 * @cfg {Number} growMax
7276 * Ext JS Library 1.1.1
7277 * Copyright(c) 2006-2007, Ext JS, LLC.
7279 * Originally Released Under LGPL - original licence link has changed is not relivant.
7282 * <script type="text/javascript">
7287 * @extends Roo.util.Observable
7288 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7289 * This class also supports single and multi selection modes. <br>
7290 * Create a data model bound view:
7292 var store = new Roo.data.Store(...);
7294 var view = new Roo.View({
7296 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7299 selectedClass: "ydataview-selected",
7303 // listen for node click?
7304 view.on("click", function(vw, index, node, e){
7305 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7309 dataModel.load("foobar.xml");
7311 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7313 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7314 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7316 * Note: old style constructor is still suported (container, template, config)
7320 * @param {Object} config The config object
7323 Roo.View = function(config, depreciated_tpl, depreciated_config){
7325 if (typeof(depreciated_tpl) == 'undefined') {
7326 // new way.. - universal constructor.
7327 Roo.apply(this, config);
7328 this.el = Roo.get(this.el);
7331 this.el = Roo.get(config);
7332 this.tpl = depreciated_tpl;
7333 Roo.apply(this, depreciated_config);
7335 this.wrapEl = this.el.wrap().wrap();
7336 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7339 if(typeof(this.tpl) == "string"){
7340 this.tpl = new Roo.Template(this.tpl);
7342 // support xtype ctors..
7343 this.tpl = new Roo.factory(this.tpl, Roo);
7355 * @event beforeclick
7356 * Fires before a click is processed. Returns false to cancel the default action.
7357 * @param {Roo.View} this
7358 * @param {Number} index The index of the target node
7359 * @param {HTMLElement} node The target node
7360 * @param {Roo.EventObject} e The raw event object
7362 "beforeclick" : true,
7365 * Fires when a template node is clicked.
7366 * @param {Roo.View} this
7367 * @param {Number} index The index of the target node
7368 * @param {HTMLElement} node The target node
7369 * @param {Roo.EventObject} e The raw event object
7374 * Fires when a template node is double clicked.
7375 * @param {Roo.View} this
7376 * @param {Number} index The index of the target node
7377 * @param {HTMLElement} node The target node
7378 * @param {Roo.EventObject} e The raw event object
7382 * @event contextmenu
7383 * Fires when a template node is right clicked.
7384 * @param {Roo.View} this
7385 * @param {Number} index The index of the target node
7386 * @param {HTMLElement} node The target node
7387 * @param {Roo.EventObject} e The raw event object
7389 "contextmenu" : true,
7391 * @event selectionchange
7392 * Fires when the selected nodes change.
7393 * @param {Roo.View} this
7394 * @param {Array} selections Array of the selected nodes
7396 "selectionchange" : true,
7399 * @event beforeselect
7400 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7401 * @param {Roo.View} this
7402 * @param {HTMLElement} node The node to be selected
7403 * @param {Array} selections Array of currently selected nodes
7405 "beforeselect" : true,
7407 * @event preparedata
7408 * Fires on every row to render, to allow you to change the data.
7409 * @param {Roo.View} this
7410 * @param {Object} data to be rendered (change this)
7412 "preparedata" : true
7420 "click": this.onClick,
7421 "dblclick": this.onDblClick,
7422 "contextmenu": this.onContextMenu,
7426 this.selections = [];
7428 this.cmp = new Roo.CompositeElementLite([]);
7430 this.store = Roo.factory(this.store, Roo.data);
7431 this.setStore(this.store, true);
7434 if ( this.footer && this.footer.xtype) {
7436 var fctr = this.wrapEl.appendChild(document.createElement("div"));
7438 this.footer.dataSource = this.store
7439 this.footer.container = fctr;
7440 this.footer = Roo.factory(this.footer, Roo);
7441 fctr.insertFirst(this.el);
7443 // this is a bit insane - as the paging toolbar seems to detach the el..
7444 // dom.parentNode.parentNode.parentNode
7445 // they get detached?
7449 Roo.View.superclass.constructor.call(this);
7454 Roo.extend(Roo.View, Roo.util.Observable, {
7457 * @cfg {Roo.data.Store} store Data store to load data from.
7462 * @cfg {String|Roo.Element} el The container element.
7467 * @cfg {String|Roo.Template} tpl The template used by this View
7471 * @cfg {String} dataName the named area of the template to use as the data area
7472 * Works with domtemplates roo-name="name"
7476 * @cfg {String} selectedClass The css class to add to selected nodes
7478 selectedClass : "x-view-selected",
7480 * @cfg {String} emptyText The empty text to show when nothing is loaded.
7485 * @cfg {String} text to display on mask (default Loading)
7489 * @cfg {Boolean} multiSelect Allow multiple selection
7491 multiSelect : false,
7493 * @cfg {Boolean} singleSelect Allow single selection
7495 singleSelect: false,
7498 * @cfg {Boolean} toggleSelect - selecting
7500 toggleSelect : false,
7503 * Returns the element this view is bound to.
7504 * @return {Roo.Element}
7513 * Refreshes the view. - called by datachanged on the store. - do not call directly.
7515 refresh : function(){
7518 // if we are using something like 'domtemplate', then
7519 // the what gets used is:
7520 // t.applySubtemplate(NAME, data, wrapping data..)
7521 // the outer template then get' applied with
7522 // the store 'extra data'
7523 // and the body get's added to the
7524 // roo-name="data" node?
7525 // <span class='roo-tpl-{name}'></span> ?????
7529 this.clearSelections();
7532 var records = this.store.getRange();
7533 if(records.length < 1) {
7535 // is this valid?? = should it render a template??
7537 this.el.update(this.emptyText);
7541 if (this.dataName) {
7542 this.el.update(t.apply(this.store.meta)); //????
7543 el = this.el.child('.roo-tpl-' + this.dataName);
7546 for(var i = 0, len = records.length; i < len; i++){
7547 var data = this.prepareData(records[i].data, i, records[i]);
7548 this.fireEvent("preparedata", this, data, i, records[i]);
7549 html[html.length] = Roo.util.Format.trim(
7551 t.applySubtemplate(this.dataName, data, this.store.meta) :
7558 el.update(html.join(""));
7559 this.nodes = el.dom.childNodes;
7560 this.updateIndexes(0);
7564 * Function to override to reformat the data that is sent to
7565 * the template for each node.
7566 * DEPRICATED - use the preparedata event handler.
7567 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7568 * a JSON object for an UpdateManager bound view).
7570 prepareData : function(data, index, record)
7572 this.fireEvent("preparedata", this, data, index, record);
7576 onUpdate : function(ds, record){
7577 this.clearSelections();
7578 var index = this.store.indexOf(record);
7579 var n = this.nodes[index];
7580 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7581 n.parentNode.removeChild(n);
7582 this.updateIndexes(index, index);
7588 onAdd : function(ds, records, index)
7590 this.clearSelections();
7591 if(this.nodes.length == 0){
7595 var n = this.nodes[index];
7596 for(var i = 0, len = records.length; i < len; i++){
7597 var d = this.prepareData(records[i].data, i, records[i]);
7599 this.tpl.insertBefore(n, d);
7602 this.tpl.append(this.el, d);
7605 this.updateIndexes(index);
7608 onRemove : function(ds, record, index){
7609 this.clearSelections();
7610 var el = this.dataName ?
7611 this.el.child('.roo-tpl-' + this.dataName) :
7613 el.dom.removeChild(this.nodes[index]);
7614 this.updateIndexes(index);
7618 * Refresh an individual node.
7619 * @param {Number} index
7621 refreshNode : function(index){
7622 this.onUpdate(this.store, this.store.getAt(index));
7625 updateIndexes : function(startIndex, endIndex){
7626 var ns = this.nodes;
7627 startIndex = startIndex || 0;
7628 endIndex = endIndex || ns.length - 1;
7629 for(var i = startIndex; i <= endIndex; i++){
7630 ns[i].nodeIndex = i;
7635 * Changes the data store this view uses and refresh the view.
7636 * @param {Store} store
7638 setStore : function(store, initial){
7639 if(!initial && this.store){
7640 this.store.un("datachanged", this.refresh);
7641 this.store.un("add", this.onAdd);
7642 this.store.un("remove", this.onRemove);
7643 this.store.un("update", this.onUpdate);
7644 this.store.un("clear", this.refresh);
7645 this.store.un("beforeload", this.onBeforeLoad);
7646 this.store.un("load", this.onLoad);
7647 this.store.un("loadexception", this.onLoad);
7651 store.on("datachanged", this.refresh, this);
7652 store.on("add", this.onAdd, this);
7653 store.on("remove", this.onRemove, this);
7654 store.on("update", this.onUpdate, this);
7655 store.on("clear", this.refresh, this);
7656 store.on("beforeload", this.onBeforeLoad, this);
7657 store.on("load", this.onLoad, this);
7658 store.on("loadexception", this.onLoad, this);
7666 * onbeforeLoad - masks the loading area.
7669 onBeforeLoad : function()
7672 this.el.mask(this.mask ? this.mask : "Loading" );
7674 onLoad : function ()
7681 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7682 * @param {HTMLElement} node
7683 * @return {HTMLElement} The template node
7685 findItemFromChild : function(node){
7686 var el = this.dataName ?
7687 this.el.child('.roo-tpl-' + this.dataName,true) :
7690 if(!node || node.parentNode == el){
7693 var p = node.parentNode;
7694 while(p && p != el){
7695 if(p.parentNode == el){
7704 onClick : function(e){
7705 var item = this.findItemFromChild(e.getTarget());
7707 var index = this.indexOf(item);
7708 if(this.onItemClick(item, index, e) !== false){
7709 this.fireEvent("click", this, index, item, e);
7712 this.clearSelections();
7717 onContextMenu : function(e){
7718 var item = this.findItemFromChild(e.getTarget());
7720 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7725 onDblClick : function(e){
7726 var item = this.findItemFromChild(e.getTarget());
7728 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7732 onItemClick : function(item, index, e)
7734 if(this.fireEvent("beforeclick", this, index, item, e) === false){
7737 if (this.toggleSelect) {
7738 var m = this.isSelected(item) ? 'unselect' : 'select';
7741 _t[m](item, true, false);
7744 if(this.multiSelect || this.singleSelect){
7745 if(this.multiSelect && e.shiftKey && this.lastSelection){
7746 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7748 this.select(item, this.multiSelect && e.ctrlKey);
7749 this.lastSelection = item;
7757 * Get the number of selected nodes.
7760 getSelectionCount : function(){
7761 return this.selections.length;
7765 * Get the currently selected nodes.
7766 * @return {Array} An array of HTMLElements
7768 getSelectedNodes : function(){
7769 return this.selections;
7773 * Get the indexes of the selected nodes.
7776 getSelectedIndexes : function(){
7777 var indexes = [], s = this.selections;
7778 for(var i = 0, len = s.length; i < len; i++){
7779 indexes.push(s[i].nodeIndex);
7785 * Clear all selections
7786 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7788 clearSelections : function(suppressEvent){
7789 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7790 this.cmp.elements = this.selections;
7791 this.cmp.removeClass(this.selectedClass);
7792 this.selections = [];
7794 this.fireEvent("selectionchange", this, this.selections);
7800 * Returns true if the passed node is selected
7801 * @param {HTMLElement/Number} node The node or node index
7804 isSelected : function(node){
7805 var s = this.selections;
7809 node = this.getNode(node);
7810 return s.indexOf(node) !== -1;
7815 * @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
7816 * @param {Boolean} keepExisting (optional) true to keep existing selections
7817 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7819 select : function(nodeInfo, keepExisting, suppressEvent){
7820 if(nodeInfo instanceof Array){
7822 this.clearSelections(true);
7824 for(var i = 0, len = nodeInfo.length; i < len; i++){
7825 this.select(nodeInfo[i], true, true);
7829 var node = this.getNode(nodeInfo);
7830 if(!node || this.isSelected(node)){
7831 return; // already selected.
7834 this.clearSelections(true);
7836 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7837 Roo.fly(node).addClass(this.selectedClass);
7838 this.selections.push(node);
7840 this.fireEvent("selectionchange", this, this.selections);
7848 * @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
7849 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7850 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7852 unselect : function(nodeInfo, keepExisting, suppressEvent)
7854 if(nodeInfo instanceof Array){
7855 Roo.each(this.selections, function(s) {
7856 this.unselect(s, nodeInfo);
7860 var node = this.getNode(nodeInfo);
7861 if(!node || !this.isSelected(node)){
7862 Roo.log("not selected");
7863 return; // not selected.
7867 Roo.each(this.selections, function(s) {
7869 Roo.fly(node).removeClass(this.selectedClass);
7876 this.selections= ns;
7877 this.fireEvent("selectionchange", this, this.selections);
7881 * Gets a template node.
7882 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7883 * @return {HTMLElement} The node or null if it wasn't found
7885 getNode : function(nodeInfo){
7886 if(typeof nodeInfo == "string"){
7887 return document.getElementById(nodeInfo);
7888 }else if(typeof nodeInfo == "number"){
7889 return this.nodes[nodeInfo];
7895 * Gets a range template nodes.
7896 * @param {Number} startIndex
7897 * @param {Number} endIndex
7898 * @return {Array} An array of nodes
7900 getNodes : function(start, end){
7901 var ns = this.nodes;
7903 end = typeof end == "undefined" ? ns.length - 1 : end;
7906 for(var i = start; i <= end; i++){
7910 for(var i = start; i >= end; i--){
7918 * Finds the index of the passed node
7919 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7920 * @return {Number} The index of the node or -1
7922 indexOf : function(node){
7923 node = this.getNode(node);
7924 if(typeof node.nodeIndex == "number"){
7925 return node.nodeIndex;
7927 var ns = this.nodes;
7928 for(var i = 0, len = ns.length; i < len; i++){
7939 * based on jquery fullcalendar
7945 * @class Roo.bootstrap.Calendar
7946 * @extends Roo.bootstrap.Component
7947 * Bootstrap Calendar class
7950 * Create a new Container
7951 * @param {Object} config The config object
7954 Roo.bootstrap.Calendar = function(config){
7955 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7959 * Fires when a date is selected
7960 * @param {DatePicker} this
7961 * @param {Date} date The selected date
7965 * @event monthchange
7966 * Fires when the displayed month changes
7967 * @param {DatePicker} this
7968 * @param {Date} date The selected month
7970 'monthchange': true,
7973 * Fires when mouse over an event
7974 * @param {Calendar} this
7975 * @param {event} Event
7980 * Fires when the mouse leaves an
7981 * @param {Calendar} this
7987 * Fires when the mouse click an
7988 * @param {Calendar} this
7997 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8000 * @cfg {Number} startDay
8001 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8005 getAutoCreate : function(){
8008 fc_button = function(name, corner, style, content ) {
8009 return Roo.apply({},{
8011 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8013 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8016 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8024 style : 'width:100%',
8031 cls : 'fc-header-left',
8033 fc_button('prev', 'left', 'arrow', '‹' ),
8034 fc_button('next', 'right', 'arrow', '›' ),
8035 { tag: 'span', cls: 'fc-header-space' },
8036 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8044 cls : 'fc-header-center',
8048 cls: 'fc-header-title',
8051 html : 'month / year'
8059 cls : 'fc-header-right',
8061 /* fc_button('month', 'left', '', 'month' ),
8062 fc_button('week', '', '', 'week' ),
8063 fc_button('day', 'right', '', 'day' )
8075 var cal_heads = function() {
8077 // fixme - handle this.
8079 for (var i =0; i < Date.dayNames.length; i++) {
8080 var d = Date.dayNames[i];
8083 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
8084 html : d.substring(0,3)
8088 ret[0].cls += ' fc-first';
8089 ret[6].cls += ' fc-last';
8092 var cal_cell = function(n) {
8095 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8100 cls: 'fc-day-number',
8104 cls: 'fc-day-content',
8108 style: 'position: relative;' // height: 17px;
8120 var cal_rows = function() {
8123 for (var r = 0; r < 6; r++) {
8130 for (var i =0; i < Date.dayNames.length; i++) {
8131 var d = Date.dayNames[i];
8132 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8135 row.cn[0].cls+=' fc-first';
8136 row.cn[0].cn[0].style = 'min-height:90px';
8137 row.cn[6].cls+=' fc-last';
8141 ret[0].cls += ' fc-first';
8142 ret[4].cls += ' fc-prev-last';
8143 ret[5].cls += ' fc-last';
8150 cls: 'fc-border-separate',
8151 style : 'width:100%',
8159 cls : 'fc-first fc-last',
8178 style : "position: relative;",
8181 cls : 'fc-view fc-view-month fc-grid',
8182 style : 'position: relative',
8183 unselectable : 'on',
8186 cls : 'fc-event-container',
8187 style : 'position:absolute;z-index:8;top:0;left:0;'
8205 initEvents : function()
8208 throw "can not find store for combo";
8211 this.store = Roo.factory(this.store, Roo.data);
8212 this.store.on('load', this.onLoad, this);
8215 this.cells = this.el.select('.fc-day',true);
8217 this.textNodes = this.el.query('.fc-day-number');
8218 this.cells.addClassOnOver('fc-state-hover');
8220 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8221 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8222 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8223 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8225 this.on('monthchange', this.onMonthChange, this);
8227 this.update(new Date().clearTime());
8230 resize : function() {
8231 var sz = this.el.getSize();
8233 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8234 this.el.select('.fc-day-content div',true).setHeight(34);
8239 showPrevMonth : function(e){
8240 this.update(this.activeDate.add("mo", -1));
8242 showToday : function(e){
8243 this.update(new Date().clearTime());
8246 showNextMonth : function(e){
8247 this.update(this.activeDate.add("mo", 1));
8251 showPrevYear : function(){
8252 this.update(this.activeDate.add("y", -1));
8256 showNextYear : function(){
8257 this.update(this.activeDate.add("y", 1));
8262 update : function(date)
8264 var vd = this.activeDate;
8265 this.activeDate = date;
8266 // if(vd && this.el){
8267 // var t = date.getTime();
8268 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8269 // Roo.log('using add remove');
8271 // this.fireEvent('monthchange', this, date);
8273 // this.cells.removeClass("fc-state-highlight");
8274 // this.cells.each(function(c){
8275 // if(c.dateValue == t){
8276 // c.addClass("fc-state-highlight");
8277 // setTimeout(function(){
8278 // try{c.dom.firstChild.focus();}catch(e){}
8288 var days = date.getDaysInMonth();
8290 var firstOfMonth = date.getFirstDateOfMonth();
8291 var startingPos = firstOfMonth.getDay()-this.startDay;
8293 if(startingPos < this.startDay){
8297 var pm = date.add("mo", -1);
8298 var prevStart = pm.getDaysInMonth()-startingPos;
8300 this.cells = this.el.select('.fc-day',true);
8301 this.textNodes = this.el.query('.fc-day-number');
8302 this.cells.addClassOnOver('fc-state-hover');
8304 var cells = this.cells.elements;
8305 var textEls = this.textNodes;
8307 Roo.each(cells, function(cell){
8308 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
8311 days += startingPos;
8313 // convert everything to numbers so it's fast
8315 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8316 var today = new Date().clearTime().getTime();
8317 var sel = date.clearTime().getTime();
8318 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8319 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8320 var ddMatch = this.disabledDatesRE;
8321 var ddText = this.disabledDatesText;
8322 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8323 var ddaysText = this.disabledDaysText;
8324 var format = this.format;
8326 var setCellClass = function(cal, cell){
8328 var t = d.getTime();
8332 cell.className += " fc-today";
8333 cell.className += " fc-state-highlight";
8334 cell.title = cal.todayText;
8337 // disable highlight in other month..
8338 //cell.className += " fc-state-highlight";
8343 cell.className = " fc-state-disabled";
8344 cell.title = cal.minText;
8348 cell.className = " fc-state-disabled";
8349 cell.title = cal.maxText;
8353 if(ddays.indexOf(d.getDay()) != -1){
8354 cell.title = ddaysText;
8355 cell.className = " fc-state-disabled";
8358 if(ddMatch && format){
8359 var fvalue = d.dateFormat(format);
8360 if(ddMatch.test(fvalue)){
8361 cell.title = ddText.replace("%0", fvalue);
8362 cell.className = " fc-state-disabled";
8366 if (!cell.initialClassName) {
8367 cell.initialClassName = cell.dom.className;
8370 cell.dom.className = cell.initialClassName + ' ' + cell.className;
8375 for(; i < startingPos; i++) {
8376 textEls[i].innerHTML = (++prevStart);
8377 d.setDate(d.getDate()+1);
8379 cells[i].className = "fc-past fc-other-month";
8380 setCellClass(this, cells[i]);
8385 for(; i < days; i++){
8386 intDay = i - startingPos + 1;
8387 textEls[i].innerHTML = (intDay);
8388 d.setDate(d.getDate()+1);
8390 cells[i].className = ''; // "x-date-active";
8391 setCellClass(this, cells[i]);
8395 for(; i < 42; i++) {
8396 textEls[i].innerHTML = (++extraDays);
8397 d.setDate(d.getDate()+1);
8399 cells[i].className = "fc-future fc-other-month";
8400 setCellClass(this, cells[i]);
8403 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8405 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
8407 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
8408 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
8411 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
8412 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
8415 this.fireEvent('monthchange', this, date);
8419 if(!this.internalRender){
8420 var main = this.el.dom.firstChild;
8421 var w = main.offsetWidth;
8422 this.el.setWidth(w + this.el.getBorderWidth("lr"));
8423 Roo.fly(main).setWidth(w);
8424 this.internalRender = true;
8425 // opera does not respect the auto grow header center column
8426 // then, after it gets a width opera refuses to recalculate
8427 // without a second pass
8428 if(Roo.isOpera && !this.secondPass){
8429 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8430 this.secondPass = true;
8431 this.update.defer(10, this, [date]);
8438 findCell : function(dt) {
8439 dt = dt.clearTime().getTime();
8441 this.cells.each(function(c){
8442 //Roo.log("check " +c.dateValue + '?=' + dt);
8443 if(c.dateValue == dt){
8453 findCells : function(ev) {
8454 var s = ev.start.clone().clearTime().getTime();
8455 var e= ev.end.clone().clearTime().getTime();
8457 this.cells.each(function(c){
8458 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8460 if(c.dateValue > e){
8463 if(c.dateValue < s){
8472 findBestRow: function(cells)
8476 for (var i =0 ; i < cells.length;i++) {
8477 ret = Math.max(cells[i].rows || 0,ret);
8484 addItem : function(ev)
8486 // look for vertical location slot in
8487 var cells = this.findCells(ev);
8489 ev.row = this.findBestRow(cells);
8491 // work out the location.
8495 for(var i =0; i < cells.length; i++) {
8503 if (crow.start.getY() == cells[i].getY()) {
8505 crow.end = cells[i];
8521 for (var i = 0; i < cells.length;i++) {
8522 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8526 this.calevents.push(ev);
8529 clearEvents: function() {
8531 if(!this.calevents){
8535 Roo.each(this.cells.elements, function(c){
8539 Roo.each(this.calevents, function(e) {
8540 Roo.each(e.els, function(el) {
8541 el.un('mouseenter' ,this.onEventEnter, this);
8542 el.un('mouseleave' ,this.onEventLeave, this);
8549 renderEvents: function()
8551 // first make sure there is enough space..
8553 this.cells.each(function(c) {
8555 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8558 for (var e = 0; e < this.calevents.length; e++) {
8559 var ev = this.calevents[e];
8560 var cells = ev.cells;
8563 for(var i =0; i < rows.length; i++) {
8566 // how many rows should it span..
8569 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8570 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8572 unselectable : "on",
8575 cls: 'fc-event-inner',
8579 cls: 'fc-event-time',
8580 html : cells.length > 1 ? '' : ev.time
8584 cls: 'fc-event-title',
8585 html : String.format('{0}', ev.title)
8592 cls: 'ui-resizable-handle ui-resizable-e',
8593 html : '  '
8599 cfg.cls += ' fc-event-start';
8601 if ((i+1) == rows.length) {
8602 cfg.cls += ' fc-event-end';
8605 var ctr = this.el.select('.fc-event-container',true).first();
8606 var cg = ctr.createChild(cfg);
8608 cg.on('mouseenter' ,this.onEventEnter, this, ev);
8609 cg.on('mouseleave' ,this.onEventLeave, this, ev);
8610 cg.on('click', this.onEventClick, this, ev);
8614 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8615 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8617 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
8618 cg.setWidth(ebox.right - sbox.x -2);
8626 onEventEnter: function (e, el,event,d) {
8627 this.fireEvent('evententer', this, el, event);
8630 onEventLeave: function (e, el,event,d) {
8631 this.fireEvent('eventleave', this, el, event);
8634 onEventClick: function (e, el,event,d) {
8635 this.fireEvent('eventclick', this, el, event);
8638 onMonthChange: function () {
8642 onLoad: function () {
8645 Roo.log('calendar onload');
8647 this.calevents = [];
8649 if(this.store.getCount() > 0){
8650 this.store.data.each(function(d){
8653 start: new Date(d.data.start_dt),
8654 end : new Date(d.data.end_dt),
8655 time : d.data.start_time,
8656 title : d.data.title,
8657 description : d.data.description,
8658 venue : d.data.venue
8663 this.renderEvents();
8676 * @class Roo.bootstrap.Popover
8677 * @extends Roo.bootstrap.Component
8678 * Bootstrap Popover class
8679 * @cfg {String} html contents of the popover (or false to use children..)
8680 * @cfg {String} title of popover (or false to hide)
8681 * @cfg {String} placement how it is placed
8682 * @cfg {String} trigger click || hover (or false to trigger manually)
8683 * @cfg {String} over what (parent or false to trigger manually.)
8686 * Create a new Popover
8687 * @param {Object} config The config object
8690 Roo.bootstrap.Popover = function(config){
8691 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8694 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
8696 title: 'Fill in a title',
8699 placement : 'right',
8700 trigger : 'hover', // hover
8704 can_build_overlaid : false,
8706 getChildContainer : function()
8708 return this.el.select('.popover-content',true).first();
8711 getAutoCreate : function(){
8712 Roo.log('make popover?');
8714 cls : 'popover roo-dynamic',
8715 style: 'display:block',
8721 cls : 'popover-inner',
8725 cls: 'popover-title',
8729 cls : 'popover-content',
8740 setTitle: function(str)
8742 this.el.select('.popover-title',true).first().dom.innerHTML = str;
8744 setContent: function(str)
8746 this.el.select('.popover-content',true).first().dom.innerHTML = str;
8748 // as it get's added to the bottom of the page.
8749 onRender : function(ct, position)
8751 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8753 var cfg = Roo.apply({}, this.getAutoCreate());
8757 cfg.cls += ' ' + this.cls;
8760 cfg.style = this.style;
8762 Roo.log("adding to ")
8763 this.el = Roo.get(document.body).createChild(cfg, position);
8769 initEvents : function()
8771 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8772 this.el.enableDisplayMode('block');
8774 if (this.over === false) {
8777 if (this.triggers === false) {
8780 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8781 var triggers = this.trigger ? this.trigger.split(' ') : [];
8782 Roo.each(triggers, function(trigger) {
8784 if (trigger == 'click') {
8785 on_el.on('click', this.toggle, this);
8786 } else if (trigger != 'manual') {
8787 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
8788 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8790 on_el.on(eventIn ,this.enter, this);
8791 on_el.on(eventOut, this.leave, this);
8802 toggle : function () {
8803 this.hoverState == 'in' ? this.leave() : this.enter();
8806 enter : function () {
8809 clearTimeout(this.timeout);
8811 this.hoverState = 'in'
8813 if (!this.delay || !this.delay.show) {
8818 this.timeout = setTimeout(function () {
8819 if (_t.hoverState == 'in') {
8824 leave : function() {
8825 clearTimeout(this.timeout);
8827 this.hoverState = 'out'
8829 if (!this.delay || !this.delay.hide) {
8834 this.timeout = setTimeout(function () {
8835 if (_t.hoverState == 'out') {
8841 show : function (on_el)
8844 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8847 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8848 if (this.html !== false) {
8849 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8851 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8852 if (!this.title.length) {
8853 this.el.select('.popover-title',true).hide();
8856 var placement = typeof this.placement == 'function' ?
8857 this.placement.call(this, this.el, on_el) :
8860 var autoToken = /\s?auto?\s?/i;
8861 var autoPlace = autoToken.test(placement);
8863 placement = placement.replace(autoToken, '') || 'top';
8867 //this.el.setXY([0,0]);
8869 this.el.dom.style.display='block';
8870 this.el.addClass(placement);
8872 //this.el.appendTo(on_el);
8874 var p = this.getPosition();
8875 var box = this.el.getBox();
8880 var align = Roo.bootstrap.Popover.alignment[placement]
8881 this.el.alignTo(on_el, align[0],align[1]);
8882 //var arrow = this.el.select('.arrow',true).first();
8883 //arrow.set(align[2],
8885 this.el.addClass('in');
8886 this.hoverState = null;
8888 if (this.el.hasClass('fade')) {
8895 this.el.setXY([0,0]);
8896 this.el.removeClass('in');
8903 Roo.bootstrap.Popover.alignment = {
8904 'left' : ['r-l', [-10,0], 'right'],
8905 'right' : ['l-r', [10,0], 'left'],
8906 'bottom' : ['t-b', [0,10], 'top'],
8907 'top' : [ 'b-t', [0,-10], 'bottom']