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
19 * Do not use directly - it does not do anything..
20 * @param {Object} config The config object
25 Roo.bootstrap.Component = function(config){
26 Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
32 allowDomMove : false, // to stop relocations in parent onRender...
40 initEvents : function() { },
46 can_build_overlaid : true,
49 // returns the parent component..
50 return Roo.ComponentMgr.get(this.parentId)
56 onRender : function(ct, position)
58 // Roo.log("Call onRender: " + this.xtype);
60 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
63 if (this.el.attr('xtype')) {
64 this.el.attr('xtypex', this.el.attr('xtype'));
65 this.el.dom.removeAttribute('xtype');
75 var cfg = Roo.apply({}, this.getAutoCreate());
78 // fill in the extra attributes
79 if (this.xattr && typeof(this.xattr) =='object') {
80 for (var i in this.xattr) {
81 cfg[i] = this.xattr[i];
86 cfg.cls += ' ' + this.cls;
88 if (this.style) { // fixme needs to support more complex style data.
89 cfg.style = this.style;
91 this.el = ct.createChild(cfg, position);
93 if(this.tabIndex !== undefined){
94 this.el.dom.setAttribute('tabIndex', this.tabIndex);
101 getChildContainer : function()
106 addxtype : function (tree, cntr) {
108 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
110 // render the element if it's not BODY.
111 if (tree.xtype != 'Body') {
113 cn = Roo.factory(tree);
115 cn.parentType = this.xtype; //??
116 cn.parentId = this.id;
118 var is_js_build = !Roo.select('body').first().attr('xtype');
120 // does the container contain child eleemnts with 'xtype' attributes.
121 // that match this xtype..
122 // note - when we render we create these as well..
123 // so we should check to see if body has xtype set.
124 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
126 var self_cntr_el = Roo.get(this[cntr]());
127 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
130 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
131 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
137 //echild.dom.removeAttribute('xtype');
139 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
145 var has_flexy = typeof(tree['flexy:if'] != 'undefined') ||
146 typeof(tree['flexy:foreach'] != 'undefined');
148 // if object has flexy:if - then it may or may not be rendered.
149 if (!is_js_build && has_flexy && !cn.el && cn.can_build_overlaid) {
150 // skip a flexy if element.
151 Roo.log('skipping render');
154 // actually if flexy:foreach is found, we really want to create
155 // multiple copies here...
157 cn.render(this[cntr]());
159 // then add the element..
166 if (typeof (tree.menu) != 'undefined') {
167 tree.menu.parentType = cn.xtype;
168 tree.menu.triggerEl = cn.el;
169 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
173 if (!tree.items || !tree.items.length) {
177 var items = tree.items;
180 //Roo.log(items.length);
182 for(var i =0;i < items.length;i++) {
183 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
202 Roo.bootstrap.Body = function(config){
203 Roo.bootstrap.Body.superclass.constructor.call(this, config);
204 this.el = Roo.get(document.body);
207 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
212 onRender : function(ct, position){
215 //this.el.addClass([this.fieldClass, this.cls]);
233 * @class Roo.bootstrap.ButtonGroup
234 * @extends Roo.bootstrap.Component
235 * Bootstrap ButtonGroup class
236 * @cfg {String} size lg | sm | xs (default empty normal)
237 * @cfg {String} align vertical | justified (default none)
238 * @cfg {String} direction up | down (default down)
239 * @cfg {Boolean} toolbar false | true
240 * @cfg {Boolean} btn true | false
245 * @param {Object} config The config object
248 Roo.bootstrap.ButtonGroup = function(config){
249 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
252 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
260 getAutoCreate : function(){
266 cfg.html = this.html || cfg.html;
277 if (['vertical','justified'].indexOf(this.align)!==-1) {
278 cfg.cls = 'btn-group-' + this.align;
280 if (this.align == 'justified') {
281 console.log(this.items);
285 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
286 cfg.cls += ' btn-group-' + this.size;
289 if (this.direction == 'up') {
290 cfg.cls += ' dropup' ;
306 * @class Roo.bootstrap.Button
307 * @extends Roo.bootstrap.Component
308 * Bootstrap Button class
309 * @cfg {String} html The button content
310 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
311 * @cfg {String} size empty | lg | sm | xs
312 * @cfg {String} tag empty | a | input | submit
313 * @cfg {String} href empty or href
314 * @cfg {Boolean} disabled false | true
315 * @cfg {Boolean} isClose false | true
316 * @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
317 * @cfg {String} badge text for badge
318 * @cfg {String} theme default (or empty) | glow
319 * @cfg {Boolean} inverse false | true
320 * @cfg {Boolean} toggle false | true
321 * @cfg {String} ontext text for on toggle state
322 * @cfg {String} offtext text for off toggle state
323 * @cfg {Boolean} defaulton true | false
326 * Create a new button
327 * @param {Object} config The config object
331 Roo.bootstrap.Button = function(config){
332 Roo.bootstrap.Button.superclass.constructor.call(this, config);
337 * The raw click event for the entire grid.
338 * @param {Roo.EventObject} e
344 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
363 getAutoCreate : function(){
371 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
372 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
377 cfg.html = this.html || cfg.html;
379 if (this.toggle===true) {
382 cls: 'slider-frame roo-button',
387 'data-off-text':'OFF',
388 cls: 'slider-button',
394 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
395 cfg.cls += ' '+this.weight;
404 cfg["aria-hidden"] = true;
406 cfg.html = "×";
412 if (this.theme==='default') {
413 cfg.cls = 'btn roo-button';
415 if (this.parentType != 'Navbar') {
416 this.weight = this.weight.length ? this.weight : 'default';
418 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
420 cfg.cls += ' btn-' + this.weight;
422 } else if (this.theme==='glow') {
425 cfg.cls = 'btn-glow roo-button';
427 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
429 cfg.cls += ' ' + this.weight;
435 this.cls += ' inverse';
440 cfg.cls += ' active';
443 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
445 //gsRoo.log(this.parentType);
446 if (this.parentType === 'Navbar') {
454 href : this.href || '#'
457 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
458 cfg.cls += ' dropdown';
463 } else if (this.menu) {
465 cfg.cls += ' dropdown test';
471 cfg.disabled = 'disabled';
475 Roo.log('changing to ul' );
477 this.glyphicon = 'caret';
480 if (this.glyphicon) {
481 cfg.html = ' ' + cfg.html;
486 cls: 'glyphicon glyphicon-' + this.glyphicon
496 cfg.cls='btn roo-button';
512 if (cfg.tag !== 'a' && this.href !== '') {
513 throw "Tag must be a to set href.";
514 } else if (this.href.length > 0) {
515 cfg.href = this.href;
520 initEvents: function() {
521 // Roo.log('init events?');
522 // Roo.log(this.el.dom);
523 if (this.el.hasClass('roo-button')) {
524 this.el.on('click', this.onClick, this);
526 this.el.select('.roo-button').on('click', this.onClick, this);
532 onClick : function(e)
534 Roo.log('button on click ');
536 this.fireEvent('click', this, e);
550 * @class Roo.bootstrap.Column
551 * @extends Roo.bootstrap.Component
552 * Bootstrap Column class
553 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
554 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
555 * @cfg {Number} md colspan out of 12 for computer-sized screens
556 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
557 * @cfg {String} html content of column.
560 * Create a new Column
561 * @param {Object} config The config object
564 Roo.bootstrap.Column = function(config){
565 Roo.bootstrap.Column.superclass.constructor.call(this, config);
568 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
577 getAutoCreate : function(){
578 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
586 ['xs','sm','md','lg'].map(function(size){
587 if (settings[size]) {
588 cfg.cls += ' col-' + size + '-' + settings[size];
591 if (this.html.length) {
592 cfg.html = this.html;
611 * @class Roo.bootstrap.Container
612 * @extends Roo.bootstrap.Component
613 * Bootstrap Container class
614 * @cfg {Boolean} jumbotron is it a jumbotron element
615 * @cfg {String} html content of element
616 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
617 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
618 * @cfg {String} header content of header (for panel)
619 * @cfg {String} footer content of footer (for panel)
620 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
623 * Create a new Container
624 * @param {Object} config The config object
627 Roo.bootstrap.Container = function(config){
628 Roo.bootstrap.Container.superclass.constructor.call(this, config);
631 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
641 getChildContainer : function() {
642 if (this.panel.length) {
643 return this.el.select('.panel-body',true).first();
650 getAutoCreate : function(){
656 if (this.jumbotron) {
657 cfg.cls = 'jumbotron';
660 cfg.cls = this.cls + '';
663 if (this.sticky.length) {
664 var bd = Roo.get(document.body);
665 if (!bd.hasClass('bootstrap-sticky')) {
666 bd.addClass('bootstrap-sticky');
667 Roo.select('html',true).setStyle('height', '100%');
670 cfg.cls += 'bootstrap-sticky-' + this.sticky;
674 if (this.well.length) {
678 cfg.cls +=' well well-' +this.well;
688 if (this.panel.length) {
689 cfg.cls += 'panel panel-' + this.panel;
691 if (this.header.length) {
694 cls : 'panel-heading',
710 if (this.footer.length) {
712 cls : 'panel-footer',
720 body.html = this.html || cfg.html;
722 if (!cfg.cls.length) {
723 cfg.cls = 'container';
740 * @class Roo.bootstrap.Img
741 * @extends Roo.bootstrap.Component
742 * Bootstrap Img class
743 * @cfg {Boolean} imgResponsive false | true
744 * @cfg {String} border rounded | circle | thumbnail
745 * @cfg {String} src image source
746 * @cfg {String} alt image alternative text
747 * @cfg {String} href a tag href
751 * @param {Object} config The config object
754 Roo.bootstrap.Img = function(config){
755 Roo.bootstrap.Img.superclass.constructor.call(this, config);
761 * The img click event for the img.
762 * @param {Roo.EventObject} e
768 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
775 getAutoCreate : function(){
779 cls: 'img-responsive',
783 cfg.html = this.html || cfg.html;
785 cfg.src = this.src || cfg.src;
787 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
788 cfg.cls += ' img-' + this.border;
806 return (this.href) ? a : cfg;
809 initEvents: function() {
812 this.el.on('click', this.onClick, this);
816 onClick : function(e)
818 Roo.log('img onclick');
819 this.fireEvent('click', this, e);
832 * @class Roo.bootstrap.Header
833 * @extends Roo.bootstrap.Component
834 * Bootstrap Header class
835 * @cfg {String} html content of header
836 * @cfg {Number} level (1|2|3|4|5|6) default 1
839 * Create a new Header
840 * @param {Object} config The config object
844 Roo.bootstrap.Header = function(config){
845 Roo.bootstrap.Header.superclass.constructor.call(this, config);
848 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
856 getAutoCreate : function(){
859 tag: 'h' + (1 *this.level),
860 html: this.html || 'fill in html'
878 * @class Roo.bootstrap.Menu
879 * @extends Roo.bootstrap.Component
880 * Bootstrap Menu class - container for MenuItems
881 * @cfg {String} type type of menu
885 * @param {Object} config The config object
889 Roo.bootstrap.Menu = function(config){
890 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
893 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
901 getChildContainer : function() {
905 getAutoCreate : function(){
907 //if (['right'].indexOf(this.align)!==-1) {
908 // cfg.cn[1].cls += ' pull-right'
912 cls : 'dropdown-menu'
916 if (this.type==='submenu') {
917 cfg.cls='submenu active'
922 initEvents : function() {
923 // Roo.log("ADD event");
924 // Roo.log(this.triggerEl.dom);
925 this.triggerEl.on('click', this.toggle, this);
926 this.triggerEl.addClass('dropdown-toggle');
931 //Roo.log(e.getTarget());
932 // Roo.log(this.triggerEl.dom);
933 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
936 var isActive = this.triggerEl.hasClass('open');
937 // if disabled.. ingore
939 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
940 // if mobile we use a backdrop because click events don't delegate
941 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
944 //var relatedTarget = { relatedTarget: this }
945 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
947 //if (e.isDefaultPrevented()) return;
949 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
951 // .trigger('shown.bs.dropdown', relatedTarget)
953 this.triggerEl.focus();
959 clearMenus : function()
961 //$(backdrop).remove()
962 Roo.select('.dropdown-toggle',true).each(function(aa) {
963 if (!aa.hasClass('open')) {
967 aa.removeClass('open');
968 //var parent = getParent($(this))
969 //var relatedTarget = { relatedTarget: this }
971 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
972 //if (e.isDefaultPrevented()) return
973 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
991 * @class Roo.bootstrap.MenuItem
992 * @extends Roo.bootstrap.Component
993 * Bootstrap MenuItem class
994 * @cfg {String} html the menu label
995 * @cfg {String} href the link
999 * Create a new MenuItem
1000 * @param {Object} config The config object
1004 Roo.bootstrap.MenuItem = function(config){
1005 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1008 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1013 getAutoCreate : function(){
1025 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1026 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1043 * @class Roo.bootstrap.MenuSeparator
1044 * @extends Roo.bootstrap.Component
1045 * Bootstrap MenuSeparator class
1048 * Create a new MenuItem
1049 * @param {Object} config The config object
1053 Roo.bootstrap.MenuSeparator = function(config){
1054 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1057 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1059 getAutoCreate : function(){
1074 <div class="modal fade">
1075 <div class="modal-dialog">
1076 <div class="modal-content">
1077 <div class="modal-header">
1078 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1079 <h4 class="modal-title">Modal title</h4>
1081 <div class="modal-body">
1082 <p>One fine body…</p>
1084 <div class="modal-footer">
1085 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1086 <button type="button" class="btn btn-primary">Save changes</button>
1088 </div><!-- /.modal-content -->
1089 </div><!-- /.modal-dialog -->
1090 </div><!-- /.modal -->
1100 * @class Roo.bootstrap.Modal
1101 * @extends Roo.bootstrap.Component
1102 * Bootstrap Modal class
1103 * @cfg {String} title Title of dialog
1104 * @cfg {Array} buttons Array of buttons or standard button set..
1107 * Create a new Modal Dialog
1108 * @param {Object} config The config object
1111 Roo.bootstrap.Modal = function(config){
1112 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1117 * The raw btnclick event for the button
1118 * @param {Roo.EventObject} e
1124 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1126 title : 'test dialog',
1130 onRender : function(ct, position)
1132 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1134 var cfg = Roo.apply({}, this.getAutoCreate());
1137 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1139 //if (!cfg.name.length) {
1143 cfg.cls += ' ' + this.cls;
1146 cfg.style = this.style;
1148 this.el = Roo.get(document.body).createChild(cfg, position);
1150 //var type = this.el.dom.type;
1152 if(this.tabIndex !== undefined){
1153 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1158 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1159 this.maskEl.enableDisplayMode("block");
1161 //this.el.addClass("x-dlg-modal");
1165 Roo.each(this.buttons, function(bb) {
1166 var b = Roo.apply({}, bb);
1167 b.xns = b.xns || Roo.bootstrap;
1168 b.xtype = b.xtype || 'Button';
1169 if (typeof(b.listeners) == 'undefined') {
1170 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1173 var btn = Roo.factory(b);
1175 btn.onRender(this.el.select('.modal-footer').first());
1183 //this.el.addClass([this.fieldClass, this.cls]);
1186 getAutoCreate : function(){
1191 html : this.html || ''
1199 cls: "modal-dialog",
1202 cls : "modal-content",
1205 cls : 'modal-header',
1214 cls : 'modal-title',
1222 cls : 'modal-footer'
1238 getChildContainer : function() {
1240 return this.el.select('.modal-body',true).first();
1243 getButtonContainer : function() {
1244 return this.el.select('.modal-footer',true).first();
1247 initEvents : function()
1249 this.el.select('.modal-header .close').on('click', this.hide, this);
1252 if (!this.rendered) {
1256 this.el.addClass('on');
1257 this.el.removeClass('fade');
1258 this.el.setStyle('display', 'block');
1259 Roo.get(document.body).addClass("x-body-masked");
1260 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1262 this.el.setStyle('zIndex', '10001');
1269 this.el.removeClass('on');
1270 this.el.addClass('fade');
1271 this.el.setStyle('display', 'none');
1273 onButtonClick: function(btn,e)
1276 this.fireEvent('btnclick', btn.name, e);
1281 Roo.apply(Roo.bootstrap.Modal, {
1283 * Button config that displays a single OK button
1292 * Button config that displays Yes and No buttons
1308 * Button config that displays OK and Cancel buttons
1323 * Button config that displays Yes, No and Cancel buttons
1350 * @class Roo.bootstrap.Navbar
1351 * @extends Roo.bootstrap.Component
1352 * Bootstrap Navbar class
1353 * @cfg {Boolean} sidebar has side bar
1354 * @cfg {Boolean} bar is a bar?
1355 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1356 * @cfg {String} brand what is brand
1357 * @cfg {Boolean} inverse is inverted color
1358 * @cfg {String} type (nav | pills | tabs)
1359 * @cfg {Boolean} arrangement stacked | justified
1360 * @cfg {String} align (left | right) alignment
1364 * Create a new Navbar
1365 * @param {Object} config The config object
1369 Roo.bootstrap.Navbar = function(config){
1370 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1373 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1385 getAutoCreate : function(){
1390 if (this.sidebar === true) {
1398 if (this.bar === true) {
1406 cls: 'navbar-header',
1411 cls: 'navbar-toggle',
1412 'data-toggle': 'collapse',
1417 html: 'Toggle navigation'
1437 cls: 'collapse navbar-collapse'
1442 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1444 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1445 cfg.cls += ' navbar-' + this.position;
1446 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1449 if (this.brand !== '') {
1453 cls: 'navbar-brand',
1462 } else if (this.bar === false) {
1465 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1475 if (['tabs','pills'].indexOf(this.type)!==-1) {
1476 cfg.cn[0].cls += ' nav-' + this.type
1478 if (this.type!=='nav') {
1479 Roo.log('nav type must be nav/tabs/pills')
1481 cfg.cn[0].cls += ' navbar-nav'
1484 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1485 cfg.cn[0].cls += ' nav-' + this.arrangement;
1488 if (this.align === 'right') {
1489 cfg.cn[0].cls += ' navbar-right';
1492 cfg.cls += ' navbar-inverse';
1500 initEvents :function ()
1502 //Roo.log(this.el.select('.navbar-toggle',true));
1503 this.el.select('.navbar-toggle',true).on('click', function() {
1504 // Roo.log('click');
1505 this.el.select('.navbar-collapse',true).toggleClass('in');
1510 getChildContainer : function()
1512 if (this.bar === true) {
1513 return this.el.select('.collapse',true).first();
1531 * @class Roo.bootstrap.NavGroup
1532 * @extends Roo.bootstrap.Component
1533 * Bootstrap NavGroup class
1534 * @cfg {String} align left | right
1535 * @cfg {Boolean} inverse false | true
1538 * Create a new nav group
1539 * @param {Object} config The config object
1542 Roo.bootstrap.NavGroup = function(config){
1543 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1546 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1552 getAutoCreate : function(){
1553 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1557 cls: 'nav navbar-nav'
1560 if (this.parent().sidebar === true) {
1563 cls: 'dashboard-menu'
1569 if (this.form === true) {
1575 if (this.align === 'right') {
1576 cfg.cls += ' navbar-right';
1578 cfg.cls += ' navbar-left';
1583 if (this.align === 'right') {
1584 cfg.cls += ' navbar-right';
1588 cfg.cls += ' navbar-inverse';
1608 * @class Roo.bootstrap.Navbar.Item
1609 * @extends Roo.bootstrap.Component
1610 * Bootstrap Navbar.Button class
1611 * @cfg {String} href link to
1612 * @cfg {String} html content of button
1613 * @cfg {String} badge text inside badge
1614 * @cfg {String} glyphicon name of glyphicon
1617 * Create a new Navbar Button
1618 * @param {Object} config The config object
1620 Roo.bootstrap.Navbar.Item = function(config){
1621 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1624 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1632 getAutoCreate : function(){
1634 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1636 if (this.parent().parent().sidebar === true) {
1649 cfg.cn[0].html = this.html;
1653 this.cls += ' active';
1657 cfg.cn[0].cls += ' dropdown-toggle';
1658 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1662 cfg.cn[0].tag = 'a',
1663 cfg.cn[0].href = this.href;
1666 if (this.glyphicon) {
1667 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1683 if (this.glyphicon) {
1684 if(cfg.html){cfg.html = ' ' + this.html};
1688 cls: 'glyphicon glyphicon-' + this.glyphicon
1693 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1697 cfg.cn[0].html += " <span class='caret'></span>";
1698 //}else if (!this.href) {
1699 // cfg.cn[0].tag='p';
1700 // cfg.cn[0].cls='navbar-text';
1703 cfg.cn[0].href=this.href||'#';
1704 cfg.cn[0].html=this.html;
1707 if (this.badge !== '') {
1710 cfg.cn[0].html + ' ',
1723 initEvents: function() {
1724 // Roo.log('init events?');
1725 // Roo.log(this.el.dom);
1726 this.el.select('a',true).on('click',
1728 this.fireEvent('click', this);
1745 * @class Roo.bootstrap.Row
1746 * @extends Roo.bootstrap.Component
1747 * Bootstrap Row class (contains columns...)
1751 * @param {Object} config The config object
1754 Roo.bootstrap.Row = function(config){
1755 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1758 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1760 getAutoCreate : function(){
1779 * @class Roo.bootstrap.Element
1780 * @extends Roo.bootstrap.Component
1781 * Bootstrap Element class
1782 * @cfg {String} html contents of the element
1783 * @cfg {String} tag tag of the element
1784 * @cfg {String} cls class of the element
1787 * Create a new Element
1788 * @param {Object} config The config object
1791 Roo.bootstrap.Element = function(config){
1792 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1795 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1802 getAutoCreate : function(){
1825 * @class Roo.bootstrap.Pagination
1826 * @extends Roo.bootstrap.Component
1827 * Bootstrap Pagination class
1828 * @cfg {String} size xs | sm | md | lg
1829 * @cfg {Boolean} inverse false | true
1830 * @cfg {Number} from pagination starting number
1831 * @cfg {Number} to pagination ending number
1832 * @cfg {String} align empty or left | right
1833 * @cfg {Number} active active page number
1836 * Create a new Pagination
1837 * @param {Object} config The config object
1840 Roo.bootstrap.Pagination = function(config){
1841 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1844 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1854 getAutoCreate : function(){
1861 cfg.cls += ' inverse';
1879 var from=this.from>0?this.from:1;
1880 var to=this.to-from<=10?this.to:from+10;
1881 var active=this.active>=from&&this.active<=to?this.active:null;
1882 for (var i=from;i<=to;i++) {
1886 cls: active===i?'active':'',
1927 * @class Roo.bootstrap.Slider
1928 * @extends Roo.bootstrap.Component
1929 * Bootstrap Slider class
1932 * Create a new Slider
1933 * @param {Object} config The config object
1936 Roo.bootstrap.Slider = function(config){
1937 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1940 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
1942 getAutoCreate : function(){
1946 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1950 cls: 'ui-slider-handle ui-state-default ui-corner-all'
1968 * @class Roo.bootstrap.Table
1969 * @extends Roo.bootstrap.Component
1970 * Bootstrap Table class
1973 * Create a new Table
1974 * @param {Object} config The config object
1977 Roo.bootstrap.Table = function(config){
1978 Roo.bootstrap.Table.superclass.constructor.call(this, config);
1981 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
1986 getAutoCreate : function(){
1987 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2019 * @class Roo.bootstrap.TableCell
2020 * @extends Roo.bootstrap.Component
2021 * Bootstrap TableCell class
2024 * Create a new TableCell
2025 * @param {Object} config The config object
2028 Roo.bootstrap.TableCell = function(config){
2029 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2032 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2034 getAutoCreate : function(){
2035 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2062 * @class Roo.bootstrap.TableRow
2063 * @extends Roo.bootstrap.Component
2064 * Bootstrap TableRow class
2067 * Create a new TableRow
2068 * @param {Object} config The config object
2071 Roo.bootstrap.TableRow = function(config){
2072 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2075 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2077 getAutoCreate : function(){
2078 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2093 * Ext JS Library 1.1.1
2094 * Copyright(c) 2006-2007, Ext JS, LLC.
2096 * Originally Released Under LGPL - original licence link has changed is not relivant.
2099 * <script type="text/javascript">
2102 // as we use this in bootstrap.
2103 Roo.namespace('Roo.form');
2105 * @class Roo.form.Action
2106 * Internal Class used to handle form actions
2108 * @param {Roo.form.BasicForm} el The form element or its id
2109 * @param {Object} config Configuration options
2114 // define the action interface
2115 Roo.form.Action = function(form, options){
2117 this.options = options || {};
2120 * Client Validation Failed
2123 Roo.form.Action.CLIENT_INVALID = 'client';
2125 * Server Validation Failed
2128 Roo.form.Action.SERVER_INVALID = 'server';
2130 * Connect to Server Failed
2133 Roo.form.Action.CONNECT_FAILURE = 'connect';
2135 * Reading Data from Server Failed
2138 Roo.form.Action.LOAD_FAILURE = 'load';
2140 Roo.form.Action.prototype = {
2142 failureType : undefined,
2143 response : undefined,
2147 run : function(options){
2152 success : function(response){
2157 handleResponse : function(response){
2161 // default connection failure
2162 failure : function(response){
2164 this.response = response;
2165 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2166 this.form.afterAction(this, false);
2169 processResponse : function(response){
2170 this.response = response;
2171 if(!response.responseText){
2174 this.result = this.handleResponse(response);
2178 // utility functions used internally
2179 getUrl : function(appendParams){
2180 var url = this.options.url || this.form.url || this.form.el.dom.action;
2182 var p = this.getParams();
2184 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2190 getMethod : function(){
2191 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2194 getParams : function(){
2195 var bp = this.form.baseParams;
2196 var p = this.options.params;
2198 if(typeof p == "object"){
2199 p = Roo.urlEncode(Roo.applyIf(p, bp));
2200 }else if(typeof p == 'string' && bp){
2201 p += '&' + Roo.urlEncode(bp);
2204 p = Roo.urlEncode(bp);
2209 createCallback : function(){
2211 success: this.success,
2212 failure: this.failure,
2214 timeout: (this.form.timeout*1000),
2215 upload: this.form.fileUpload ? this.success : undefined
2220 Roo.form.Action.Submit = function(form, options){
2221 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2224 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2227 haveProgress : false,
2228 uploadComplete : false,
2230 // uploadProgress indicator.
2231 uploadProgress : function()
2233 if (!this.form.progressUrl) {
2237 if (!this.haveProgress) {
2238 Roo.MessageBox.progress("Uploading", "Uploading");
2240 if (this.uploadComplete) {
2241 Roo.MessageBox.hide();
2245 this.haveProgress = true;
2247 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2249 var c = new Roo.data.Connection();
2251 url : this.form.progressUrl,
2256 success : function(req){
2257 //console.log(data);
2261 rdata = Roo.decode(req.responseText)
2263 Roo.log("Invalid data from server..");
2267 if (!rdata || !rdata.success) {
2269 Roo.MessageBox.alert(Roo.encode(rdata));
2272 var data = rdata.data;
2274 if (this.uploadComplete) {
2275 Roo.MessageBox.hide();
2280 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2281 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2284 this.uploadProgress.defer(2000,this);
2287 failure: function(data) {
2288 Roo.log('progress url failed ');
2299 // run get Values on the form, so it syncs any secondary forms.
2300 this.form.getValues();
2302 var o = this.options;
2303 var method = this.getMethod();
2304 var isPost = method == 'POST';
2305 if(o.clientValidation === false || this.form.isValid()){
2307 if (this.form.progressUrl) {
2308 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2309 (new Date() * 1) + '' + Math.random());
2314 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2315 form:this.form.el.dom,
2316 url:this.getUrl(!isPost),
2318 params:isPost ? this.getParams() : null,
2319 isUpload: this.form.fileUpload
2322 this.uploadProgress();
2324 }else if (o.clientValidation !== false){ // client validation failed
2325 this.failureType = Roo.form.Action.CLIENT_INVALID;
2326 this.form.afterAction(this, false);
2330 success : function(response)
2332 this.uploadComplete= true;
2333 if (this.haveProgress) {
2334 Roo.MessageBox.hide();
2338 var result = this.processResponse(response);
2339 if(result === true || result.success){
2340 this.form.afterAction(this, true);
2344 this.form.markInvalid(result.errors);
2345 this.failureType = Roo.form.Action.SERVER_INVALID;
2347 this.form.afterAction(this, false);
2349 failure : function(response)
2351 this.uploadComplete= true;
2352 if (this.haveProgress) {
2353 Roo.MessageBox.hide();
2356 this.response = response;
2357 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2358 this.form.afterAction(this, false);
2361 handleResponse : function(response){
2362 if(this.form.errorReader){
2363 var rs = this.form.errorReader.read(response);
2366 for(var i = 0, len = rs.records.length; i < len; i++) {
2367 var r = rs.records[i];
2371 if(errors.length < 1){
2375 success : rs.success,
2381 ret = Roo.decode(response.responseText);
2385 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2395 Roo.form.Action.Load = function(form, options){
2396 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2397 this.reader = this.form.reader;
2400 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2405 Roo.Ajax.request(Roo.apply(
2406 this.createCallback(), {
2407 method:this.getMethod(),
2408 url:this.getUrl(false),
2409 params:this.getParams()
2413 success : function(response){
2415 var result = this.processResponse(response);
2416 if(result === true || !result.success || !result.data){
2417 this.failureType = Roo.form.Action.LOAD_FAILURE;
2418 this.form.afterAction(this, false);
2421 this.form.clearInvalid();
2422 this.form.setValues(result.data);
2423 this.form.afterAction(this, true);
2426 handleResponse : function(response){
2427 if(this.form.reader){
2428 var rs = this.form.reader.read(response);
2429 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2431 success : rs.success,
2435 return Roo.decode(response.responseText);
2439 Roo.form.Action.ACTION_TYPES = {
2440 'load' : Roo.form.Action.Load,
2441 'submit' : Roo.form.Action.Submit
2450 * @class Roo.bootstrap.Form
2451 * @extends Roo.bootstrap.Component
2452 * Bootstrap Form class
2453 * @cfg {String} method GET | POST (default POST)
2454 * @cfg {String} labelAlign top | left (default top)
2455 * @cfg {String} align left | right - for navbars
2460 * @param {Object} config The config object
2464 Roo.bootstrap.Form = function(config){
2465 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2468 * @event clientvalidation
2469 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2470 * @param {Form} this
2471 * @param {Boolean} valid true if the form has passed client-side validation
2473 clientvalidation: true,
2475 * @event beforeaction
2476 * Fires before any action is performed. Return false to cancel the action.
2477 * @param {Form} this
2478 * @param {Action} action The action to be performed
2482 * @event actionfailed
2483 * Fires when an action fails.
2484 * @param {Form} this
2485 * @param {Action} action The action that failed
2487 actionfailed : true,
2489 * @event actioncomplete
2490 * Fires when an action is completed.
2491 * @param {Form} this
2492 * @param {Action} action The action that completed
2494 actioncomplete : true
2499 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2502 * @cfg {String} method
2503 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2508 * The URL to use for form actions if one isn't supplied in the action options.
2511 * @cfg {Boolean} fileUpload
2512 * Set to true if this form is a file upload.
2516 * @cfg {Object} baseParams
2517 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2521 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2525 * @cfg {Sting} align (left|right) for navbar forms
2530 activeAction : null,
2533 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2534 * element by passing it or its id or mask the form itself by passing in true.
2537 waitMsgTarget : false,
2542 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2543 * element by passing it or its id or mask the form itself by passing in true.
2547 getAutoCreate : function(){
2551 method : this.method || 'POST',
2552 id : this.id || Roo.id(),
2555 if (this.parent().xtype.match(/^Nav/)) {
2556 cfg.cls = 'navbar-form navbar-' + this.align;
2560 if (this.labelAlign == 'left' ) {
2561 cfg.cls += ' form-horizontal';
2567 initEvents : function()
2569 this.el.on('submit', this.onSubmit, this);
2574 onSubmit : function(e){
2579 * Returns true if client-side validation on the form is successful.
2582 isValid : function(){
2583 var items = this.getItems();
2585 items.each(function(f){
2594 * Returns true if any fields in this form have changed since their original load.
2597 isDirty : function(){
2599 var items = this.getItems();
2600 items.each(function(f){
2610 * Performs a predefined action (submit or load) or custom actions you define on this form.
2611 * @param {String} actionName The name of the action type
2612 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2613 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2614 * accept other config options):
2616 Property Type Description
2617 ---------------- --------------- ----------------------------------------------------------------------------------
2618 url String The url for the action (defaults to the form's url)
2619 method String The form method to use (defaults to the form's method, or POST if not defined)
2620 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2621 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2622 validate the form on the client (defaults to false)
2624 * @return {BasicForm} this
2626 doAction : function(action, options){
2627 if(typeof action == 'string'){
2628 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2630 if(this.fireEvent('beforeaction', this, action) !== false){
2631 this.beforeAction(action);
2632 action.run.defer(100, action);
2638 beforeAction : function(action){
2639 var o = action.options;
2641 // not really supported yet.. ??
2643 //if(this.waitMsgTarget === true){
2644 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2645 //}else if(this.waitMsgTarget){
2646 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2647 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2649 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2655 afterAction : function(action, success){
2656 this.activeAction = null;
2657 var o = action.options;
2659 //if(this.waitMsgTarget === true){
2661 //}else if(this.waitMsgTarget){
2662 // this.waitMsgTarget.unmask();
2664 // Roo.MessageBox.updateProgress(1);
2665 // Roo.MessageBox.hide();
2672 Roo.callback(o.success, o.scope, [this, action]);
2673 this.fireEvent('actioncomplete', this, action);
2677 // failure condition..
2678 // we have a scenario where updates need confirming.
2679 // eg. if a locking scenario exists..
2680 // we look for { errors : { needs_confirm : true }} in the response.
2682 (typeof(action.result) != 'undefined') &&
2683 (typeof(action.result.errors) != 'undefined') &&
2684 (typeof(action.result.errors.needs_confirm) != 'undefined')
2687 Roo.log("not supported yet");
2690 Roo.MessageBox.confirm(
2691 "Change requires confirmation",
2692 action.result.errorMsg,
2697 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2707 Roo.callback(o.failure, o.scope, [this, action]);
2708 // show an error message if no failed handler is set..
2709 if (!this.hasListener('actionfailed')) {
2710 Roo.log("need to add dialog support");
2712 Roo.MessageBox.alert("Error",
2713 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2714 action.result.errorMsg :
2715 "Saving Failed, please check your entries or try again"
2720 this.fireEvent('actionfailed', this, action);
2725 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2726 * @param {String} id The value to search for
2729 findField : function(id){
2730 var items = this.getItems();
2731 var field = items.get(id);
2733 items.each(function(f){
2734 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2741 return field || null;
2744 * Mark fields in this form invalid in bulk.
2745 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2746 * @return {BasicForm} this
2748 markInvalid : function(errors){
2749 if(errors instanceof Array){
2750 for(var i = 0, len = errors.length; i < len; i++){
2751 var fieldError = errors[i];
2752 var f = this.findField(fieldError.id);
2754 f.markInvalid(fieldError.msg);
2760 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2761 field.markInvalid(errors[id]);
2765 //Roo.each(this.childForms || [], function (f) {
2766 // f.markInvalid(errors);
2773 * Set values for fields in this form in bulk.
2774 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2775 * @return {BasicForm} this
2777 setValues : function(values){
2778 if(values instanceof Array){ // array of objects
2779 for(var i = 0, len = values.length; i < len; i++){
2781 var f = this.findField(v.id);
2783 f.setValue(v.value);
2784 if(this.trackResetOnLoad){
2785 f.originalValue = f.getValue();
2789 }else{ // object hash
2792 if(typeof values[id] != 'function' && (field = this.findField(id))){
2794 if (field.setFromData &&
2796 field.displayField &&
2797 // combos' with local stores can
2798 // be queried via setValue()
2799 // to set their value..
2800 (field.store && !field.store.isLocal)
2804 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2805 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2806 field.setFromData(sd);
2809 field.setValue(values[id]);
2813 if(this.trackResetOnLoad){
2814 field.originalValue = field.getValue();
2820 //Roo.each(this.childForms || [], function (f) {
2821 // f.setValues(values);
2828 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2829 * they are returned as an array.
2830 * @param {Boolean} asString
2833 getValues : function(asString){
2834 //if (this.childForms) {
2835 // copy values from the child forms
2836 // Roo.each(this.childForms, function (f) {
2837 // this.setValues(f.getValues());
2843 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2844 if(asString === true){
2847 return Roo.urlDecode(fs);
2851 * Returns the fields in this form as an object with key/value pairs.
2852 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2855 getFieldValues : function(with_hidden)
2857 var items = this.getItems();
2859 items.each(function(f){
2863 var v = f.getValue();
2864 if (f.inputType =='radio') {
2865 if (typeof(ret[f.getName()]) == 'undefined') {
2866 ret[f.getName()] = ''; // empty..
2869 if (!f.el.dom.checked) {
2877 // not sure if this supported any more..
2878 if ((typeof(v) == 'object') && f.getRawValue) {
2879 v = f.getRawValue() ; // dates..
2881 // combo boxes where name != hiddenName...
2882 if (f.name != f.getName()) {
2883 ret[f.name] = f.getRawValue();
2885 ret[f.getName()] = v;
2892 * Clears all invalid messages in this form.
2893 * @return {BasicForm} this
2895 clearInvalid : function(){
2896 var items = this.getItems();
2898 items.each(function(f){
2909 * @return {BasicForm} this
2912 var items = this.getItems();
2913 items.each(function(f){
2917 Roo.each(this.childForms || [], function (f) {
2924 getItems : function()
2926 var r=new Roo.util.MixedCollection(false, function(o){
2927 return o.id || (o.id = Roo.id());
2929 var iter = function(el) {
2936 Roo.each(el.items,function(e) {
2955 * Ext JS Library 1.1.1
2956 * Copyright(c) 2006-2007, Ext JS, LLC.
2958 * Originally Released Under LGPL - original licence link has changed is not relivant.
2961 * <script type="text/javascript">
2964 * @class Roo.form.VTypes
2965 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2968 Roo.form.VTypes = function(){
2969 // closure these in so they are only created once.
2970 var alpha = /^[a-zA-Z_]+$/;
2971 var alphanum = /^[a-zA-Z0-9_]+$/;
2972 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2973 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2975 // All these messages and functions are configurable
2978 * The function used to validate email addresses
2979 * @param {String} value The email address
2981 'email' : function(v){
2982 return email.test(v);
2985 * The error text to display when the email validation function returns false
2988 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2990 * The keystroke filter mask to be applied on email input
2993 'emailMask' : /[a-z0-9_\.\-@]/i,
2996 * The function used to validate URLs
2997 * @param {String} value The URL
2999 'url' : function(v){
3003 * The error text to display when the url validation function returns false
3006 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3009 * The function used to validate alpha values
3010 * @param {String} value The value
3012 'alpha' : function(v){
3013 return alpha.test(v);
3016 * The error text to display when the alpha validation function returns false
3019 'alphaText' : 'This field should only contain letters and _',
3021 * The keystroke filter mask to be applied on alpha input
3024 'alphaMask' : /[a-z_]/i,
3027 * The function used to validate alphanumeric values
3028 * @param {String} value The value
3030 'alphanum' : function(v){
3031 return alphanum.test(v);
3034 * The error text to display when the alphanumeric validation function returns false
3037 'alphanumText' : 'This field should only contain letters, numbers and _',
3039 * The keystroke filter mask to be applied on alphanumeric input
3042 'alphanumMask' : /[a-z0-9_]/i
3052 * @class Roo.bootstrap.Input
3053 * @extends Roo.bootstrap.Component
3054 * Bootstrap Input class
3055 * @cfg {Boolean} disabled is it disabled
3056 * @cfg {String} fieldLabel - the label associated
3057 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3058 * @cfg {String} name name of the input
3059 * @cfg {string} fieldLabel - the label associated
3060 * @cfg {string} inputType - input / file submit ...
3061 * @cfg {string} placeholder - placeholder to put in text.
3062 * @cfg {string} before - input group add on before
3063 * @cfg {string} after - input group add on after
3064 * @cfg {string} size - (lg|sm) or leave empty..
3065 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3066 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3067 * @cfg {Number} md colspan out of 12 for computer-sized screens
3068 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3072 * Create a new Input
3073 * @param {Object} config The config object
3076 Roo.bootstrap.Input = function(config){
3077 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3082 * Fires when this field receives input focus.
3083 * @param {Roo.form.Field} this
3088 * Fires when this field loses input focus.
3089 * @param {Roo.form.Field} this
3094 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3095 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3096 * @param {Roo.form.Field} this
3097 * @param {Roo.EventObject} e The event object
3102 * Fires just before the field blurs if the field value has changed.
3103 * @param {Roo.form.Field} this
3104 * @param {Mixed} newValue The new value
3105 * @param {Mixed} oldValue The original value
3110 * Fires after the field has been marked as invalid.
3111 * @param {Roo.form.Field} this
3112 * @param {String} msg The validation message
3117 * Fires after the field has been validated with no errors.
3118 * @param {Roo.form.Field} this
3123 * Fires after the key up
3124 * @param {Roo.form.Field} this
3125 * @param {Roo.EventObject} e The event Object
3131 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3133 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3134 automatic validation (defaults to "keyup").
3136 validationEvent : "keyup",
3138 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3140 validateOnBlur : true,
3142 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3144 validationDelay : 250,
3146 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3148 focusClass : "x-form-focus", // not needed???
3152 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3154 invalidClass : "has-error",
3157 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3159 selectOnFocus : false,
3162 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3166 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3171 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3173 disableKeyFilter : false,
3176 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3180 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3184 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3186 blankText : "This field is required",
3189 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3193 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3195 maxLength : Number.MAX_VALUE,
3197 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3199 minLengthText : "The minimum length for this field is {0}",
3201 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3203 maxLengthText : "The maximum length for this field is {0}",
3207 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3208 * If available, this function will be called only after the basic validators all return true, and will be passed the
3209 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3213 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3214 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3215 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3219 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3238 getAutoCreate : function(){
3240 var parent = this.parent();
3242 var align = parent.labelAlign;
3247 cls: 'form-group' //input-group
3253 type : this.inputType,
3254 cls : 'form-control',
3255 placeholder : this.placeholder || ''
3259 input.name = this.name;
3262 input.cls += ' input-' + this.size;
3265 ['xs','sm','md','lg'].map(function(size){
3266 if (settings[size]) {
3267 cfg.cls += ' col-' + size + '-' + settings[size];
3271 var inputblock = input;
3273 if (this.before || this.after) {
3276 cls : 'input-group',
3280 inputblock.cn.push({
3282 cls : 'input-group-addon',
3286 inputblock.cn.push(input);
3288 inputblock.cn.push({
3290 cls : 'input-group-addon',
3298 Roo.log(this.fieldLabel.length);
3300 if (align ==='left' && this.fieldLabel.length) {
3301 Roo.log("left and has label");
3307 cls : 'col-sm-2 control-label',
3308 html : this.fieldLabel
3319 } else if ( this.fieldLabel.length) {
3325 //cls : 'input-group-addon',
3326 html : this.fieldLabel
3336 Roo.log(" no label && no align");
3349 if (this.disabled) {
3350 input.disabled=true;
3356 * return the real input element.
3358 inputEl: function ()
3360 return this.el.select('input.form-control',true).first();
3362 setDisabled : function(v)
3364 var i = this.inputEl().dom;
3366 i.removeAttribute('disabled');
3370 i.setAttribute('disabled','true');
3372 initEvents : function()
3375 this.inputEl().on("keydown" , this.fireKey, this);
3376 this.inputEl().on("focus", this.onFocus, this);
3377 this.inputEl().on("blur", this.onBlur, this);
3378 this.inputEl().relayEvent('keyup', this);
3380 // reference to original value for reset
3381 this.originalValue = this.getValue();
3382 //Roo.form.TextField.superclass.initEvents.call(this);
3383 if(this.validationEvent == 'keyup'){
3384 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3385 this.inputEl().on('keyup', this.filterValidation, this);
3387 else if(this.validationEvent !== false){
3388 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3391 if(this.selectOnFocus){
3392 this.on("focus", this.preFocus, this);
3395 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3396 this.inputEl().on("keypress", this.filterKeys, this);
3399 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3400 this.el.on("click", this.autoSize, this);
3403 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3404 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3408 filterValidation : function(e){
3409 if(!e.isNavKeyPress()){
3410 this.validationTask.delay(this.validationDelay);
3414 * Validates the field value
3415 * @return {Boolean} True if the value is valid, else false
3417 validate : function(){
3418 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3419 if(this.disabled || this.validateValue(this.getRawValue())){
3420 this.clearInvalid();
3428 * Validates a value according to the field's validation rules and marks the field as invalid
3429 * if the validation fails
3430 * @param {Mixed} value The value to validate
3431 * @return {Boolean} True if the value is valid, else false
3433 validateValue : function(value){
3434 if(value.length < 1) { // if it's blank
3435 if(this.allowBlank){
3436 this.clearInvalid();
3439 this.markInvalid(this.blankText);
3443 if(value.length < this.minLength){
3444 this.markInvalid(String.format(this.minLengthText, this.minLength));
3447 if(value.length > this.maxLength){
3448 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3452 var vt = Roo.form.VTypes;
3453 if(!vt[this.vtype](value, this)){
3454 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3458 if(typeof this.validator == "function"){
3459 var msg = this.validator(value);
3461 this.markInvalid(msg);
3465 if(this.regex && !this.regex.test(value)){
3466 this.markInvalid(this.regexText);
3475 fireKey : function(e){
3476 //Roo.log('field ' + e.getKey());
3477 if(e.isNavKeyPress()){
3478 this.fireEvent("specialkey", this, e);
3481 focus : function (selectText){
3483 this.inputEl().focus();
3484 if(selectText === true){
3485 this.inputEl().dom.select();
3491 onFocus : function(){
3492 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3493 // this.el.addClass(this.focusClass);
3496 this.hasFocus = true;
3497 this.startValue = this.getValue();
3498 this.fireEvent("focus", this);
3502 beforeBlur : Roo.emptyFn,
3506 onBlur : function(){
3508 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3509 //this.el.removeClass(this.focusClass);
3511 this.hasFocus = false;
3512 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3515 var v = this.getValue();
3516 if(String(v) !== String(this.startValue)){
3517 this.fireEvent('change', this, v, this.startValue);
3519 this.fireEvent("blur", this);
3523 * Resets the current field value to the originally loaded value and clears any validation messages
3526 this.setValue(this.originalValue);
3527 this.clearInvalid();
3530 * Returns the name of the field
3531 * @return {Mixed} name The name field
3533 getName: function(){
3537 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3538 * @return {Mixed} value The field value
3540 getValue : function(){
3541 var v = this.inputEl().getValue();
3545 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3546 * @return {Mixed} value The field value
3548 getRawValue : function(){
3549 var v = this.inputEl().getValue();
3555 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
3556 * @param {Mixed} value The value to set
3558 setRawValue : function(v){
3559 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3562 selectText : function(start, end){
3563 var v = this.getRawValue();
3565 start = start === undefined ? 0 : start;
3566 end = end === undefined ? v.length : end;
3567 var d = this.inputEl().dom;
3568 if(d.setSelectionRange){
3569 d.setSelectionRange(start, end);
3570 }else if(d.createTextRange){
3571 var range = d.createTextRange();
3572 range.moveStart("character", start);
3573 range.moveEnd("character", v.length-end);
3580 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3581 * @param {Mixed} value The value to set
3583 setValue : function(v){
3586 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3592 processValue : function(value){
3593 if(this.stripCharsRe){
3594 var newValue = value.replace(this.stripCharsRe, '');
3595 if(newValue !== value){
3596 this.setRawValue(newValue);
3603 preFocus : function(){
3605 if(this.selectOnFocus){
3606 this.inputEl().dom.select();
3609 filterKeys : function(e){
3611 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3614 var c = e.getCharCode(), cc = String.fromCharCode(c);
3615 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3618 if(!this.maskRe.test(cc)){
3623 * Clear any invalid styles/messages for this field
3625 clearInvalid : function(){
3627 if(!this.el || this.preventMark){ // not rendered
3630 this.el.removeClass(this.invalidClass);
3632 switch(this.msgTarget){
3634 this.el.dom.qtip = '';
3637 this.el.dom.title = '';
3641 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3646 this.errorIcon.dom.qtip = '';
3647 this.errorIcon.hide();
3648 this.un('resize', this.alignErrorIcon, this);
3652 var t = Roo.getDom(this.msgTarget);
3654 t.style.display = 'none';
3658 this.fireEvent('valid', this);
3661 * Mark this field as invalid
3662 * @param {String} msg The validation message
3664 markInvalid : function(msg){
3665 if(!this.el || this.preventMark){ // not rendered
3668 this.el.addClass(this.invalidClass);
3670 msg = msg || this.invalidText;
3671 switch(this.msgTarget){
3673 this.el.dom.qtip = msg;
3674 this.el.dom.qclass = 'x-form-invalid-tip';
3675 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3676 Roo.QuickTips.enable();
3680 this.el.dom.title = msg;
3684 var elp = this.el.findParent('.x-form-element', 5, true);
3685 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3686 this.errorEl.setWidth(elp.getWidth(true)-20);
3688 this.errorEl.update(msg);
3689 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3692 if(!this.errorIcon){
3693 var elp = this.el.findParent('.x-form-element', 5, true);
3694 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3696 this.alignErrorIcon();
3697 this.errorIcon.dom.qtip = msg;
3698 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3699 this.errorIcon.show();
3700 this.on('resize', this.alignErrorIcon, this);
3703 var t = Roo.getDom(this.msgTarget);
3705 t.style.display = this.msgDisplay;
3709 this.fireEvent('invalid', this, msg);
3712 SafariOnKeyDown : function(event)
3714 // this is a workaround for a password hang bug on chrome/ webkit.
3716 var isSelectAll = false;
3718 if(this.inputEl().dom.selectionEnd > 0){
3719 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3721 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3722 event.preventDefault();
3727 if(isSelectAll){ // backspace and delete key
3729 event.preventDefault();
3730 // this is very hacky as keydown always get's upper case.
3732 var cc = String.fromCharCode(event.getCharCode());
3733 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3745 * trigger field - base class for combo..
3750 * @class Roo.bootstrap.TriggerField
3751 * @extends Roo.bootstrap.Input
3752 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3753 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3754 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3755 * for which you can provide a custom implementation. For example:
3757 var trigger = new Roo.bootstrap.TriggerField();
3758 trigger.onTriggerClick = myTriggerFn;
3759 trigger.applyTo('my-field');
3762 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3763 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3764 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3765 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3767 * Create a new TriggerField.
3768 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3769 * to the base TextField)
3771 Roo.bootstrap.TriggerField = function(config){
3772 this.mimicing = false;
3773 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3776 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3778 * @cfg {String} triggerClass A CSS class to apply to the trigger
3781 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3785 /** @cfg {Boolean} grow @hide */
3786 /** @cfg {Number} growMin @hide */
3787 /** @cfg {Number} growMax @hide */
3793 autoSize: Roo.emptyFn,
3800 actionMode : 'wrap',
3804 getAutoCreate : function(){
3806 var parent = this.parent();
3808 var align = parent.labelAlign;
3813 cls: 'form-group' //input-group
3820 type : this.inputType,
3821 cls : 'form-control',
3822 autocomplete: 'off',
3823 placeholder : this.placeholder || ''
3827 input.name = this.name;
3830 input.cls += ' input-' + this.size;
3833 cls: 'combobox-container input-group',
3838 cls: 'form-hidden-field'
3843 cls : 'typeahead typeahead-long dropdown-menu',
3844 style : 'display:none'
3848 cls : 'input-group-addon btn dropdown-toggle',
3856 cls: 'combobox-clear',
3873 if (align ==='left' && this.fieldLabel.length) {
3877 Roo.log("left and has label");
3883 cls : 'col-sm-2 control-label',
3884 html : this.fieldLabel
3895 } else if ( this.fieldLabel.length) {
3901 //cls : 'input-group-addon',
3902 html : this.fieldLabel
3912 Roo.log(" no label && no align");
3919 ['xs','sm','md','lg'].map(function(size){
3920 if (settings[size]) {
3921 cfg.cls += ' col-' + size + '-' + settings[size];
3927 if (this.disabled) {
3928 input.disabled=true;
3937 onResize : function(w, h){
3938 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3939 if(typeof w == 'number'){
3940 var x = w - this.trigger.getWidth();
3941 this.inputEl().setWidth(this.adjustWidth('input', x));
3942 this.trigger.setStyle('left', x+'px');
3947 adjustSize : Roo.BoxComponent.prototype.adjustSize,
3950 getResizeEl : function(){
3951 return this.inputEl();
3955 getPositionEl : function(){
3956 return this.inputEl();
3960 alignErrorIcon : function(){
3961 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3965 initEvents : function(){
3967 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
3968 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3970 this.trigger = this.el.select('span.dropdown-toggle',true).first();
3971 if(this.hideTrigger){
3972 this.trigger.setDisplayed(false);
3974 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3975 //this.trigger.addClassOnOver('x-form-trigger-over');
3976 //this.trigger.addClassOnClick('x-form-trigger-click');
3979 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3984 initTrigger : function(){
3989 onDestroy : function(){
3991 this.trigger.removeAllListeners();
3992 // this.trigger.remove();
3995 // this.wrap.remove();
3997 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
4001 onFocus : function(){
4002 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
4005 this.wrap.addClass('x-trigger-wrap-focus');
4006 this.mimicing = true;
4007 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
4008 if(this.monitorTab){
4009 this.el.on("keydown", this.checkTab, this);
4016 checkTab : function(e){
4017 if(e.getKey() == e.TAB){
4023 onBlur : function(){
4028 mimicBlur : function(e, t){
4030 if(!this.wrap.contains(t) && this.validateBlur()){
4037 triggerBlur : function(){
4038 this.mimicing = false;
4039 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4040 if(this.monitorTab){
4041 this.el.un("keydown", this.checkTab, this);
4043 //this.wrap.removeClass('x-trigger-wrap-focus');
4044 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4048 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4049 validateBlur : function(e, t){
4054 onDisable : function(){
4055 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4057 // this.wrap.addClass('x-item-disabled');
4062 onEnable : function(){
4063 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4065 // this.el.removeClass('x-item-disabled');
4070 onShow : function(){
4071 var ae = this.getActionEl();
4074 ae.dom.style.display = '';
4075 ae.dom.style.visibility = 'visible';
4081 onHide : function(){
4082 var ae = this.getActionEl();
4083 ae.dom.style.display = 'none';
4087 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4088 * by an implementing function.
4090 * @param {EventObject} e
4092 onTriggerClick : Roo.emptyFn
4096 * Ext JS Library 1.1.1
4097 * Copyright(c) 2006-2007, Ext JS, LLC.
4099 * Originally Released Under LGPL - original licence link has changed is not relivant.
4102 * <script type="text/javascript">
4107 * @class Roo.data.SortTypes
4109 * Defines the default sorting (casting?) comparison functions used when sorting data.
4111 Roo.data.SortTypes = {
4113 * Default sort that does nothing
4114 * @param {Mixed} s The value being converted
4115 * @return {Mixed} The comparison value
4122 * The regular expression used to strip tags
4126 stripTagsRE : /<\/?[^>]+>/gi,
4129 * Strips all HTML tags to sort on text only
4130 * @param {Mixed} s The value being converted
4131 * @return {String} The comparison value
4133 asText : function(s){
4134 return String(s).replace(this.stripTagsRE, "");
4138 * Strips all HTML tags to sort on text only - Case insensitive
4139 * @param {Mixed} s The value being converted
4140 * @return {String} The comparison value
4142 asUCText : function(s){
4143 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4147 * Case insensitive string
4148 * @param {Mixed} s The value being converted
4149 * @return {String} The comparison value
4151 asUCString : function(s) {
4152 return String(s).toUpperCase();
4157 * @param {Mixed} s The value being converted
4158 * @return {Number} The comparison value
4160 asDate : function(s) {
4164 if(s instanceof Date){
4167 return Date.parse(String(s));
4172 * @param {Mixed} s The value being converted
4173 * @return {Float} The comparison value
4175 asFloat : function(s) {
4176 var val = parseFloat(String(s).replace(/,/g, ""));
4177 if(isNaN(val)) val = 0;
4183 * @param {Mixed} s The value being converted
4184 * @return {Number} The comparison value
4186 asInt : function(s) {
4187 var val = parseInt(String(s).replace(/,/g, ""));
4188 if(isNaN(val)) val = 0;
4193 * Ext JS Library 1.1.1
4194 * Copyright(c) 2006-2007, Ext JS, LLC.
4196 * Originally Released Under LGPL - original licence link has changed is not relivant.
4199 * <script type="text/javascript">
4203 * @class Roo.data.Record
4204 * Instances of this class encapsulate both record <em>definition</em> information, and record
4205 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4206 * to access Records cached in an {@link Roo.data.Store} object.<br>
4208 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4209 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4212 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4214 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4215 * {@link #create}. The parameters are the same.
4216 * @param {Array} data An associative Array of data values keyed by the field name.
4217 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4218 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4219 * not specified an integer id is generated.
4221 Roo.data.Record = function(data, id){
4222 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4227 * Generate a constructor for a specific record layout.
4228 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4229 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4230 * Each field definition object may contain the following properties: <ul>
4231 * <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,
4232 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4233 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4234 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4235 * is being used, then this is a string containing the javascript expression to reference the data relative to
4236 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4237 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4238 * this may be omitted.</p></li>
4239 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4240 * <ul><li>auto (Default, implies no conversion)</li>
4245 * <li>date</li></ul></p></li>
4246 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4247 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4248 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4249 * by the Reader into an object that will be stored in the Record. It is passed the
4250 * following parameters:<ul>
4251 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4253 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4255 * <br>usage:<br><pre><code>
4256 var TopicRecord = Roo.data.Record.create(
4257 {name: 'title', mapping: 'topic_title'},
4258 {name: 'author', mapping: 'username'},
4259 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4260 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4261 {name: 'lastPoster', mapping: 'user2'},
4262 {name: 'excerpt', mapping: 'post_text'}
4265 var myNewRecord = new TopicRecord({
4266 title: 'Do my job please',
4269 lastPost: new Date(),
4270 lastPoster: 'Animal',
4271 excerpt: 'No way dude!'
4273 myStore.add(myNewRecord);
4278 Roo.data.Record.create = function(o){
4280 f.superclass.constructor.apply(this, arguments);
4282 Roo.extend(f, Roo.data.Record);
4283 var p = f.prototype;
4284 p.fields = new Roo.util.MixedCollection(false, function(field){
4287 for(var i = 0, len = o.length; i < len; i++){
4288 p.fields.add(new Roo.data.Field(o[i]));
4290 f.getField = function(name){
4291 return p.fields.get(name);
4296 Roo.data.Record.AUTO_ID = 1000;
4297 Roo.data.Record.EDIT = 'edit';
4298 Roo.data.Record.REJECT = 'reject';
4299 Roo.data.Record.COMMIT = 'commit';
4301 Roo.data.Record.prototype = {
4303 * Readonly flag - true if this record has been modified.
4312 join : function(store){
4317 * Set the named field to the specified value.
4318 * @param {String} name The name of the field to set.
4319 * @param {Object} value The value to set the field to.
4321 set : function(name, value){
4322 if(this.data[name] == value){
4329 if(typeof this.modified[name] == 'undefined'){
4330 this.modified[name] = this.data[name];
4332 this.data[name] = value;
4333 if(!this.editing && this.store){
4334 this.store.afterEdit(this);
4339 * Get the value of the named field.
4340 * @param {String} name The name of the field to get the value of.
4341 * @return {Object} The value of the field.
4343 get : function(name){
4344 return this.data[name];
4348 beginEdit : function(){
4349 this.editing = true;
4354 cancelEdit : function(){
4355 this.editing = false;
4356 delete this.modified;
4360 endEdit : function(){
4361 this.editing = false;
4362 if(this.dirty && this.store){
4363 this.store.afterEdit(this);
4368 * Usually called by the {@link Roo.data.Store} which owns the Record.
4369 * Rejects all changes made to the Record since either creation, or the last commit operation.
4370 * Modified fields are reverted to their original values.
4372 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4373 * of reject operations.
4375 reject : function(){
4376 var m = this.modified;
4378 if(typeof m[n] != "function"){
4379 this.data[n] = m[n];
4383 delete this.modified;
4384 this.editing = false;
4386 this.store.afterReject(this);
4391 * Usually called by the {@link Roo.data.Store} which owns the Record.
4392 * Commits all changes made to the Record since either creation, or the last commit operation.
4394 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4395 * of commit operations.
4397 commit : function(){
4399 delete this.modified;
4400 this.editing = false;
4402 this.store.afterCommit(this);
4407 hasError : function(){
4408 return this.error != null;
4412 clearError : function(){
4417 * Creates a copy of this record.
4418 * @param {String} id (optional) A new record id if you don't want to use this record's id
4421 copy : function(newId) {
4422 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4426 * Ext JS Library 1.1.1
4427 * Copyright(c) 2006-2007, Ext JS, LLC.
4429 * Originally Released Under LGPL - original licence link has changed is not relivant.
4432 * <script type="text/javascript">
4438 * @class Roo.data.Store
4439 * @extends Roo.util.Observable
4440 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4441 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4443 * 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
4444 * has no knowledge of the format of the data returned by the Proxy.<br>
4446 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4447 * instances from the data object. These records are cached and made available through accessor functions.
4449 * Creates a new Store.
4450 * @param {Object} config A config object containing the objects needed for the Store to access data,
4451 * and read the data into Records.
4453 Roo.data.Store = function(config){
4454 this.data = new Roo.util.MixedCollection(false);
4455 this.data.getKey = function(o){
4458 this.baseParams = {};
4465 "multisort" : "_multisort"
4468 if(config && config.data){
4469 this.inlineData = config.data;
4473 Roo.apply(this, config);
4475 if(this.reader){ // reader passed
4476 this.reader = Roo.factory(this.reader, Roo.data);
4477 this.reader.xmodule = this.xmodule || false;
4478 if(!this.recordType){
4479 this.recordType = this.reader.recordType;
4481 if(this.reader.onMetaChange){
4482 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4486 if(this.recordType){
4487 this.fields = this.recordType.prototype.fields;
4493 * @event datachanged
4494 * Fires when the data cache has changed, and a widget which is using this Store
4495 * as a Record cache should refresh its view.
4496 * @param {Store} this
4501 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4502 * @param {Store} this
4503 * @param {Object} meta The JSON metadata
4508 * Fires when Records have been added to the Store
4509 * @param {Store} this
4510 * @param {Roo.data.Record[]} records The array of Records added
4511 * @param {Number} index The index at which the record(s) were added
4516 * Fires when a Record has been removed from the Store
4517 * @param {Store} this
4518 * @param {Roo.data.Record} record The Record that was removed
4519 * @param {Number} index The index at which the record was removed
4524 * Fires when a Record has been updated
4525 * @param {Store} this
4526 * @param {Roo.data.Record} record The Record that was updated
4527 * @param {String} operation The update operation being performed. Value may be one of:
4529 Roo.data.Record.EDIT
4530 Roo.data.Record.REJECT
4531 Roo.data.Record.COMMIT
4537 * Fires when the data cache has been cleared.
4538 * @param {Store} this
4543 * Fires before a request is made for a new data object. If the beforeload handler returns false
4544 * the load action will be canceled.
4545 * @param {Store} this
4546 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4550 * @event beforeloadadd
4551 * Fires after a new set of Records has been loaded.
4552 * @param {Store} this
4553 * @param {Roo.data.Record[]} records The Records that were loaded
4554 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4556 beforeloadadd : true,
4559 * Fires after a new set of Records has been loaded, before they are added to the store.
4560 * @param {Store} this
4561 * @param {Roo.data.Record[]} records The Records that were loaded
4562 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4563 * @params {Object} return from reader
4567 * @event loadexception
4568 * Fires if an exception occurs in the Proxy during loading.
4569 * Called with the signature of the Proxy's "loadexception" event.
4570 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4573 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4574 * @param {Object} load options
4575 * @param {Object} jsonData from your request (normally this contains the Exception)
4577 loadexception : true
4581 this.proxy = Roo.factory(this.proxy, Roo.data);
4582 this.proxy.xmodule = this.xmodule || false;
4583 this.relayEvents(this.proxy, ["loadexception"]);
4585 this.sortToggle = {};
4586 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4588 Roo.data.Store.superclass.constructor.call(this);
4590 if(this.inlineData){
4591 this.loadData(this.inlineData);
4592 delete this.inlineData;
4596 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4598 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4599 * without a remote query - used by combo/forms at present.
4603 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4606 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4609 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4610 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4613 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4614 * on any HTTP request
4617 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4620 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4624 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4625 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4630 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4631 * loaded or when a record is removed. (defaults to false).
4633 pruneModifiedRecords : false,
4639 * Add Records to the Store and fires the add event.
4640 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4642 add : function(records){
4643 records = [].concat(records);
4644 for(var i = 0, len = records.length; i < len; i++){
4645 records[i].join(this);
4647 var index = this.data.length;
4648 this.data.addAll(records);
4649 this.fireEvent("add", this, records, index);
4653 * Remove a Record from the Store and fires the remove event.
4654 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4656 remove : function(record){
4657 var index = this.data.indexOf(record);
4658 this.data.removeAt(index);
4659 if(this.pruneModifiedRecords){
4660 this.modified.remove(record);
4662 this.fireEvent("remove", this, record, index);
4666 * Remove all Records from the Store and fires the clear event.
4668 removeAll : function(){
4670 if(this.pruneModifiedRecords){
4673 this.fireEvent("clear", this);
4677 * Inserts Records to the Store at the given index and fires the add event.
4678 * @param {Number} index The start index at which to insert the passed Records.
4679 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4681 insert : function(index, records){
4682 records = [].concat(records);
4683 for(var i = 0, len = records.length; i < len; i++){
4684 this.data.insert(index, records[i]);
4685 records[i].join(this);
4687 this.fireEvent("add", this, records, index);
4691 * Get the index within the cache of the passed Record.
4692 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4693 * @return {Number} The index of the passed Record. Returns -1 if not found.
4695 indexOf : function(record){
4696 return this.data.indexOf(record);
4700 * Get the index within the cache of the Record with the passed id.
4701 * @param {String} id The id of the Record to find.
4702 * @return {Number} The index of the Record. Returns -1 if not found.
4704 indexOfId : function(id){
4705 return this.data.indexOfKey(id);
4709 * Get the Record with the specified id.
4710 * @param {String} id The id of the Record to find.
4711 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4713 getById : function(id){
4714 return this.data.key(id);
4718 * Get the Record at the specified index.
4719 * @param {Number} index The index of the Record to find.
4720 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4722 getAt : function(index){
4723 return this.data.itemAt(index);
4727 * Returns a range of Records between specified indices.
4728 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4729 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4730 * @return {Roo.data.Record[]} An array of Records
4732 getRange : function(start, end){
4733 return this.data.getRange(start, end);
4737 storeOptions : function(o){
4738 o = Roo.apply({}, o);
4741 this.lastOptions = o;
4745 * Loads the Record cache from the configured Proxy using the configured Reader.
4747 * If using remote paging, then the first load call must specify the <em>start</em>
4748 * and <em>limit</em> properties in the options.params property to establish the initial
4749 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4751 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4752 * and this call will return before the new data has been loaded. Perform any post-processing
4753 * in a callback function, or in a "load" event handler.</strong>
4755 * @param {Object} options An object containing properties which control loading options:<ul>
4756 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4757 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4758 * passed the following arguments:<ul>
4759 * <li>r : Roo.data.Record[]</li>
4760 * <li>options: Options object from the load call</li>
4761 * <li>success: Boolean success indicator</li></ul></li>
4762 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4763 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4766 load : function(options){
4767 options = options || {};
4768 if(this.fireEvent("beforeload", this, options) !== false){
4769 this.storeOptions(options);
4770 var p = Roo.apply(options.params || {}, this.baseParams);
4771 // if meta was not loaded from remote source.. try requesting it.
4772 if (!this.reader.metaFromRemote) {
4775 if(this.sortInfo && this.remoteSort){
4776 var pn = this.paramNames;
4777 p[pn["sort"]] = this.sortInfo.field;
4778 p[pn["dir"]] = this.sortInfo.direction;
4780 if (this.multiSort) {
4781 var pn = this.paramNames;
4782 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4785 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4790 * Reloads the Record cache from the configured Proxy using the configured Reader and
4791 * the options from the last load operation performed.
4792 * @param {Object} options (optional) An object containing properties which may override the options
4793 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4794 * the most recently used options are reused).
4796 reload : function(options){
4797 this.load(Roo.applyIf(options||{}, this.lastOptions));
4801 // Called as a callback by the Reader during a load operation.
4802 loadRecords : function(o, options, success){
4803 if(!o || success === false){
4804 if(success !== false){
4805 this.fireEvent("load", this, [], options, o);
4807 if(options.callback){
4808 options.callback.call(options.scope || this, [], options, false);
4812 // if data returned failure - throw an exception.
4813 if (o.success === false) {
4814 // show a message if no listener is registered.
4815 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4816 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4818 // loadmask wil be hooked into this..
4819 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4822 var r = o.records, t = o.totalRecords || r.length;
4824 this.fireEvent("beforeloadadd", this, r, options, o);
4826 if(!options || options.add !== true){
4827 if(this.pruneModifiedRecords){
4830 for(var i = 0, len = r.length; i < len; i++){
4834 this.data = this.snapshot;
4835 delete this.snapshot;
4838 this.data.addAll(r);
4839 this.totalLength = t;
4841 this.fireEvent("datachanged", this);
4843 this.totalLength = Math.max(t, this.data.length+r.length);
4846 this.fireEvent("load", this, r, options, o);
4847 if(options.callback){
4848 options.callback.call(options.scope || this, r, options, true);
4854 * Loads data from a passed data block. A Reader which understands the format of the data
4855 * must have been configured in the constructor.
4856 * @param {Object} data The data block from which to read the Records. The format of the data expected
4857 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4858 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4860 loadData : function(o, append){
4861 var r = this.reader.readRecords(o);
4862 this.loadRecords(r, {add: append}, true);
4866 * Gets the number of cached records.
4868 * <em>If using paging, this may not be the total size of the dataset. If the data object
4869 * used by the Reader contains the dataset size, then the getTotalCount() function returns
4870 * the data set size</em>
4872 getCount : function(){
4873 return this.data.length || 0;
4877 * Gets the total number of records in the dataset as returned by the server.
4879 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4880 * the dataset size</em>
4882 getTotalCount : function(){
4883 return this.totalLength || 0;
4887 * Returns the sort state of the Store as an object with two properties:
4889 field {String} The name of the field by which the Records are sorted
4890 direction {String} The sort order, "ASC" or "DESC"
4893 getSortState : function(){
4894 return this.sortInfo;
4898 applySort : function(){
4899 if(this.sortInfo && !this.remoteSort){
4900 var s = this.sortInfo, f = s.field;
4901 var st = this.fields.get(f).sortType;
4902 var fn = function(r1, r2){
4903 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4904 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
4906 this.data.sort(s.direction, fn);
4907 if(this.snapshot && this.snapshot != this.data){
4908 this.snapshot.sort(s.direction, fn);
4914 * Sets the default sort column and order to be used by the next load operation.
4915 * @param {String} fieldName The name of the field to sort by.
4916 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4918 setDefaultSort : function(field, dir){
4919 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
4924 * If remote sorting is used, the sort is performed on the server, and the cache is
4925 * reloaded. If local sorting is used, the cache is sorted internally.
4926 * @param {String} fieldName The name of the field to sort by.
4927 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4929 sort : function(fieldName, dir){
4930 var f = this.fields.get(fieldName);
4932 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
4934 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
4935 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
4940 this.sortToggle[f.name] = dir;
4941 this.sortInfo = {field: f.name, direction: dir};
4942 if(!this.remoteSort){
4944 this.fireEvent("datachanged", this);
4946 this.load(this.lastOptions);
4951 * Calls the specified function for each of the Records in the cache.
4952 * @param {Function} fn The function to call. The Record is passed as the first parameter.
4953 * Returning <em>false</em> aborts and exits the iteration.
4954 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
4956 each : function(fn, scope){
4957 this.data.each(fn, scope);
4961 * Gets all records modified since the last commit. Modified records are persisted across load operations
4962 * (e.g., during paging).
4963 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
4965 getModifiedRecords : function(){
4966 return this.modified;
4970 createFilterFn : function(property, value, anyMatch){
4971 if(!value.exec){ // not a regex
4972 value = String(value);
4973 if(value.length == 0){
4976 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
4979 return value.test(r.data[property]);
4984 * Sums the value of <i>property</i> for each record between start and end and returns the result.
4985 * @param {String} property A field on your records
4986 * @param {Number} start The record index to start at (defaults to 0)
4987 * @param {Number} end The last record index to include (defaults to length - 1)
4988 * @return {Number} The sum
4990 sum : function(property, start, end){
4991 var rs = this.data.items, v = 0;
4993 end = (end || end === 0) ? end : rs.length-1;
4995 for(var i = start; i <= end; i++){
4996 v += (rs[i].data[property] || 0);
5002 * Filter the records by a specified property.
5003 * @param {String} field A field on your records
5004 * @param {String/RegExp} value Either a string that the field
5005 * should start with or a RegExp to test against the field
5006 * @param {Boolean} anyMatch True to match any part not just the beginning
5008 filter : function(property, value, anyMatch){
5009 var fn = this.createFilterFn(property, value, anyMatch);
5010 return fn ? this.filterBy(fn) : this.clearFilter();
5014 * Filter by a function. The specified function will be called with each
5015 * record in this data source. If the function returns true the record is included,
5016 * otherwise it is filtered.
5017 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5018 * @param {Object} scope (optional) The scope of the function (defaults to this)
5020 filterBy : function(fn, scope){
5021 this.snapshot = this.snapshot || this.data;
5022 this.data = this.queryBy(fn, scope||this);
5023 this.fireEvent("datachanged", this);
5027 * Query the records by a specified property.
5028 * @param {String} field A field on your records
5029 * @param {String/RegExp} value Either a string that the field
5030 * should start with or a RegExp to test against the field
5031 * @param {Boolean} anyMatch True to match any part not just the beginning
5032 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5034 query : function(property, value, anyMatch){
5035 var fn = this.createFilterFn(property, value, anyMatch);
5036 return fn ? this.queryBy(fn) : this.data.clone();
5040 * Query by a function. The specified function will be called with each
5041 * record in this data source. If the function returns true the record is included
5043 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5044 * @param {Object} scope (optional) The scope of the function (defaults to this)
5045 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5047 queryBy : function(fn, scope){
5048 var data = this.snapshot || this.data;
5049 return data.filterBy(fn, scope||this);
5053 * Collects unique values for a particular dataIndex from this store.
5054 * @param {String} dataIndex The property to collect
5055 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5056 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5057 * @return {Array} An array of the unique values
5059 collect : function(dataIndex, allowNull, bypassFilter){
5060 var d = (bypassFilter === true && this.snapshot) ?
5061 this.snapshot.items : this.data.items;
5062 var v, sv, r = [], l = {};
5063 for(var i = 0, len = d.length; i < len; i++){
5064 v = d[i].data[dataIndex];
5066 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5075 * Revert to a view of the Record cache with no filtering applied.
5076 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5078 clearFilter : function(suppressEvent){
5079 if(this.snapshot && this.snapshot != this.data){
5080 this.data = this.snapshot;
5081 delete this.snapshot;
5082 if(suppressEvent !== true){
5083 this.fireEvent("datachanged", this);
5089 afterEdit : function(record){
5090 if(this.modified.indexOf(record) == -1){
5091 this.modified.push(record);
5093 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5097 afterReject : function(record){
5098 this.modified.remove(record);
5099 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5103 afterCommit : function(record){
5104 this.modified.remove(record);
5105 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5109 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5110 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5112 commitChanges : function(){
5113 var m = this.modified.slice(0);
5115 for(var i = 0, len = m.length; i < len; i++){
5121 * Cancel outstanding changes on all changed records.
5123 rejectChanges : function(){
5124 var m = this.modified.slice(0);
5126 for(var i = 0, len = m.length; i < len; i++){
5131 onMetaChange : function(meta, rtype, o){
5132 this.recordType = rtype;
5133 this.fields = rtype.prototype.fields;
5134 delete this.snapshot;
5135 this.sortInfo = meta.sortInfo || this.sortInfo;
5137 this.fireEvent('metachange', this, this.reader.meta);
5141 * Ext JS Library 1.1.1
5142 * Copyright(c) 2006-2007, Ext JS, LLC.
5144 * Originally Released Under LGPL - original licence link has changed is not relivant.
5147 * <script type="text/javascript">
5151 * @class Roo.data.SimpleStore
5152 * @extends Roo.data.Store
5153 * Small helper class to make creating Stores from Array data easier.
5154 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5155 * @cfg {Array} fields An array of field definition objects, or field name strings.
5156 * @cfg {Array} data The multi-dimensional array of data
5158 * @param {Object} config
5160 Roo.data.SimpleStore = function(config){
5161 Roo.data.SimpleStore.superclass.constructor.call(this, {
5163 reader: new Roo.data.ArrayReader({
5166 Roo.data.Record.create(config.fields)
5168 proxy : new Roo.data.MemoryProxy(config.data)
5172 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5174 * Ext JS Library 1.1.1
5175 * Copyright(c) 2006-2007, Ext JS, LLC.
5177 * Originally Released Under LGPL - original licence link has changed is not relivant.
5180 * <script type="text/javascript">
5185 * @extends Roo.data.Store
5186 * @class Roo.data.JsonStore
5187 * Small helper class to make creating Stores for JSON data easier. <br/>
5189 var store = new Roo.data.JsonStore({
5190 url: 'get-images.php',
5192 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5195 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5196 * JsonReader and HttpProxy (unless inline data is provided).</b>
5197 * @cfg {Array} fields An array of field definition objects, or field name strings.
5199 * @param {Object} config
5201 Roo.data.JsonStore = function(c){
5202 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5203 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5204 reader: new Roo.data.JsonReader(c, c.fields)
5207 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5209 * Ext JS Library 1.1.1
5210 * Copyright(c) 2006-2007, Ext JS, LLC.
5212 * Originally Released Under LGPL - original licence link has changed is not relivant.
5215 * <script type="text/javascript">
5219 Roo.data.Field = function(config){
5220 if(typeof config == "string"){
5221 config = {name: config};
5223 Roo.apply(this, config);
5229 var st = Roo.data.SortTypes;
5230 // named sortTypes are supported, here we look them up
5231 if(typeof this.sortType == "string"){
5232 this.sortType = st[this.sortType];
5235 // set default sortType for strings and dates
5239 this.sortType = st.asUCString;
5242 this.sortType = st.asDate;
5245 this.sortType = st.none;
5250 var stripRe = /[\$,%]/g;
5252 // prebuilt conversion function for this field, instead of
5253 // switching every time we're reading a value
5255 var cv, dateFormat = this.dateFormat;
5260 cv = function(v){ return v; };
5263 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5267 return v !== undefined && v !== null && v !== '' ?
5268 parseInt(String(v).replace(stripRe, ""), 10) : '';
5273 return v !== undefined && v !== null && v !== '' ?
5274 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5279 cv = function(v){ return v === true || v === "true" || v == 1; };
5286 if(v instanceof Date){
5290 if(dateFormat == "timestamp"){
5291 return new Date(v*1000);
5293 return Date.parseDate(v, dateFormat);
5295 var parsed = Date.parse(v);
5296 return parsed ? new Date(parsed) : null;
5305 Roo.data.Field.prototype = {
5313 * Ext JS Library 1.1.1
5314 * Copyright(c) 2006-2007, Ext JS, LLC.
5316 * Originally Released Under LGPL - original licence link has changed is not relivant.
5319 * <script type="text/javascript">
5322 // Base class for reading structured data from a data source. This class is intended to be
5323 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5326 * @class Roo.data.DataReader
5327 * Base class for reading structured data from a data source. This class is intended to be
5328 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5331 Roo.data.DataReader = function(meta, recordType){
5335 this.recordType = recordType instanceof Array ?
5336 Roo.data.Record.create(recordType) : recordType;
5339 Roo.data.DataReader.prototype = {
5341 * Create an empty record
5342 * @param {Object} data (optional) - overlay some values
5343 * @return {Roo.data.Record} record created.
5345 newRow : function(d) {
5347 this.recordType.prototype.fields.each(function(c) {
5349 case 'int' : da[c.name] = 0; break;
5350 case 'date' : da[c.name] = new Date(); break;
5351 case 'float' : da[c.name] = 0.0; break;
5352 case 'boolean' : da[c.name] = false; break;
5353 default : da[c.name] = ""; break;
5357 return new this.recordType(Roo.apply(da, d));
5362 * Ext JS Library 1.1.1
5363 * Copyright(c) 2006-2007, Ext JS, LLC.
5365 * Originally Released Under LGPL - original licence link has changed is not relivant.
5368 * <script type="text/javascript">
5372 * @class Roo.data.DataProxy
5373 * @extends Roo.data.Observable
5374 * This class is an abstract base class for implementations which provide retrieval of
5375 * unformatted data objects.<br>
5377 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5378 * (of the appropriate type which knows how to parse the data object) to provide a block of
5379 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5381 * Custom implementations must implement the load method as described in
5382 * {@link Roo.data.HttpProxy#load}.
5384 Roo.data.DataProxy = function(){
5388 * Fires before a network request is made to retrieve a data object.
5389 * @param {Object} This DataProxy object.
5390 * @param {Object} params The params parameter to the load function.
5395 * Fires before the load method's callback is called.
5396 * @param {Object} This DataProxy object.
5397 * @param {Object} o The data object.
5398 * @param {Object} arg The callback argument object passed to the load function.
5402 * @event loadexception
5403 * Fires if an Exception occurs during data retrieval.
5404 * @param {Object} This DataProxy object.
5405 * @param {Object} o The data object.
5406 * @param {Object} arg The callback argument object passed to the load function.
5407 * @param {Object} e The Exception.
5409 loadexception : true
5411 Roo.data.DataProxy.superclass.constructor.call(this);
5414 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5417 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5421 * Ext JS Library 1.1.1
5422 * Copyright(c) 2006-2007, Ext JS, LLC.
5424 * Originally Released Under LGPL - original licence link has changed is not relivant.
5427 * <script type="text/javascript">
5430 * @class Roo.data.MemoryProxy
5431 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5432 * to the Reader when its load method is called.
5434 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5436 Roo.data.MemoryProxy = function(data){
5440 Roo.data.MemoryProxy.superclass.constructor.call(this);
5444 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5446 * Load data from the requested source (in this case an in-memory
5447 * data object passed to the constructor), read the data object into
5448 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5449 * process that block using the passed callback.
5450 * @param {Object} params This parameter is not used by the MemoryProxy class.
5451 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5452 * object into a block of Roo.data.Records.
5453 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5454 * The function must be passed <ul>
5455 * <li>The Record block object</li>
5456 * <li>The "arg" argument from the load function</li>
5457 * <li>A boolean success indicator</li>
5459 * @param {Object} scope The scope in which to call the callback
5460 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5462 load : function(params, reader, callback, scope, arg){
5463 params = params || {};
5466 result = reader.readRecords(this.data);
5468 this.fireEvent("loadexception", this, arg, null, e);
5469 callback.call(scope, null, arg, false);
5472 callback.call(scope, result, arg, true);
5476 update : function(params, records){
5481 * Ext JS Library 1.1.1
5482 * Copyright(c) 2006-2007, Ext JS, LLC.
5484 * Originally Released Under LGPL - original licence link has changed is not relivant.
5487 * <script type="text/javascript">
5490 * @class Roo.data.HttpProxy
5491 * @extends Roo.data.DataProxy
5492 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5493 * configured to reference a certain URL.<br><br>
5495 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5496 * from which the running page was served.<br><br>
5498 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5500 * Be aware that to enable the browser to parse an XML document, the server must set
5501 * the Content-Type header in the HTTP response to "text/xml".
5503 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5504 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5505 * will be used to make the request.
5507 Roo.data.HttpProxy = function(conn){
5508 Roo.data.HttpProxy.superclass.constructor.call(this);
5509 // is conn a conn config or a real conn?
5511 this.useAjax = !conn || !conn.events;
5515 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5516 // thse are take from connection...
5519 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5522 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5523 * extra parameters to each request made by this object. (defaults to undefined)
5526 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5527 * to each request made by this object. (defaults to undefined)
5530 * @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)
5533 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5536 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5542 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5546 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5547 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5548 * a finer-grained basis than the DataProxy events.
5550 getConnection : function(){
5551 return this.useAjax ? Roo.Ajax : this.conn;
5555 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5556 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5557 * process that block using the passed callback.
5558 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5559 * for the request to the remote server.
5560 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5561 * object into a block of Roo.data.Records.
5562 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5563 * The function must be passed <ul>
5564 * <li>The Record block object</li>
5565 * <li>The "arg" argument from the load function</li>
5566 * <li>A boolean success indicator</li>
5568 * @param {Object} scope The scope in which to call the callback
5569 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5571 load : function(params, reader, callback, scope, arg){
5572 if(this.fireEvent("beforeload", this, params) !== false){
5574 params : params || {},
5576 callback : callback,
5581 callback : this.loadResponse,
5585 Roo.applyIf(o, this.conn);
5586 if(this.activeRequest){
5587 Roo.Ajax.abort(this.activeRequest);
5589 this.activeRequest = Roo.Ajax.request(o);
5591 this.conn.request(o);
5594 callback.call(scope||this, null, arg, false);
5599 loadResponse : function(o, success, response){
5600 delete this.activeRequest;
5602 this.fireEvent("loadexception", this, o, response);
5603 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5608 result = o.reader.read(response);
5610 this.fireEvent("loadexception", this, o, response, e);
5611 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5615 this.fireEvent("load", this, o, o.request.arg);
5616 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5620 update : function(dataSet){
5625 updateResponse : function(dataSet){
5630 * Ext JS Library 1.1.1
5631 * Copyright(c) 2006-2007, Ext JS, LLC.
5633 * Originally Released Under LGPL - original licence link has changed is not relivant.
5636 * <script type="text/javascript">
5640 * @class Roo.data.ScriptTagProxy
5641 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5642 * other than the originating domain of the running page.<br><br>
5644 * <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
5645 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5647 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5648 * source code that is used as the source inside a <script> tag.<br><br>
5650 * In order for the browser to process the returned data, the server must wrap the data object
5651 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5652 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5653 * depending on whether the callback name was passed:
5656 boolean scriptTag = false;
5657 String cb = request.getParameter("callback");
5660 response.setContentType("text/javascript");
5662 response.setContentType("application/x-json");
5664 Writer out = response.getWriter();
5666 out.write(cb + "(");
5668 out.print(dataBlock.toJsonString());
5675 * @param {Object} config A configuration object.
5677 Roo.data.ScriptTagProxy = function(config){
5678 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5679 Roo.apply(this, config);
5680 this.head = document.getElementsByTagName("head")[0];
5683 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5685 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5687 * @cfg {String} url The URL from which to request the data object.
5690 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5694 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5695 * the server the name of the callback function set up by the load call to process the returned data object.
5696 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5697 * javascript output which calls this named function passing the data object as its only parameter.
5699 callbackParam : "callback",
5701 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5702 * name to the request.
5707 * Load data from the configured URL, read the data object into
5708 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5709 * process that block using the passed callback.
5710 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5711 * for the request to the remote server.
5712 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5713 * object into a block of Roo.data.Records.
5714 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5715 * The function must be passed <ul>
5716 * <li>The Record block object</li>
5717 * <li>The "arg" argument from the load function</li>
5718 * <li>A boolean success indicator</li>
5720 * @param {Object} scope The scope in which to call the callback
5721 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5723 load : function(params, reader, callback, scope, arg){
5724 if(this.fireEvent("beforeload", this, params) !== false){
5726 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5729 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5731 url += "&_dc=" + (new Date().getTime());
5733 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5736 cb : "stcCallback"+transId,
5737 scriptId : "stcScript"+transId,
5741 callback : callback,
5747 window[trans.cb] = function(o){
5748 conn.handleResponse(o, trans);
5751 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5753 if(this.autoAbort !== false){
5757 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5759 var script = document.createElement("script");
5760 script.setAttribute("src", url);
5761 script.setAttribute("type", "text/javascript");
5762 script.setAttribute("id", trans.scriptId);
5763 this.head.appendChild(script);
5767 callback.call(scope||this, null, arg, false);
5772 isLoading : function(){
5773 return this.trans ? true : false;
5777 * Abort the current server request.
5780 if(this.isLoading()){
5781 this.destroyTrans(this.trans);
5786 destroyTrans : function(trans, isLoaded){
5787 this.head.removeChild(document.getElementById(trans.scriptId));
5788 clearTimeout(trans.timeoutId);
5790 window[trans.cb] = undefined;
5792 delete window[trans.cb];
5795 // if hasn't been loaded, wait for load to remove it to prevent script error
5796 window[trans.cb] = function(){
5797 window[trans.cb] = undefined;
5799 delete window[trans.cb];
5806 handleResponse : function(o, trans){
5808 this.destroyTrans(trans, true);
5811 result = trans.reader.readRecords(o);
5813 this.fireEvent("loadexception", this, o, trans.arg, e);
5814 trans.callback.call(trans.scope||window, null, trans.arg, false);
5817 this.fireEvent("load", this, o, trans.arg);
5818 trans.callback.call(trans.scope||window, result, trans.arg, true);
5822 handleFailure : function(trans){
5824 this.destroyTrans(trans, false);
5825 this.fireEvent("loadexception", this, null, trans.arg);
5826 trans.callback.call(trans.scope||window, null, trans.arg, false);
5830 * Ext JS Library 1.1.1
5831 * Copyright(c) 2006-2007, Ext JS, LLC.
5833 * Originally Released Under LGPL - original licence link has changed is not relivant.
5836 * <script type="text/javascript">
5840 * @class Roo.data.JsonReader
5841 * @extends Roo.data.DataReader
5842 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5843 * based on mappings in a provided Roo.data.Record constructor.
5845 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5846 * in the reply previously.
5851 var RecordDef = Roo.data.Record.create([
5852 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5853 {name: 'occupation'} // This field will use "occupation" as the mapping.
5855 var myReader = new Roo.data.JsonReader({
5856 totalProperty: "results", // The property which contains the total dataset size (optional)
5857 root: "rows", // The property which contains an Array of row objects
5858 id: "id" // The property within each row object that provides an ID for the record (optional)
5862 * This would consume a JSON file like this:
5864 { 'results': 2, 'rows': [
5865 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5866 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5869 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5870 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5871 * paged from the remote server.
5872 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5873 * @cfg {String} root name of the property which contains the Array of row objects.
5874 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5876 * Create a new JsonReader
5877 * @param {Object} meta Metadata configuration options
5878 * @param {Object} recordType Either an Array of field definition objects,
5879 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5881 Roo.data.JsonReader = function(meta, recordType){
5884 // set some defaults:
5886 totalProperty: 'total',
5887 successProperty : 'success',
5892 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5894 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5897 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
5898 * Used by Store query builder to append _requestMeta to params.
5901 metaFromRemote : false,
5903 * This method is only used by a DataProxy which has retrieved data from a remote server.
5904 * @param {Object} response The XHR object which contains the JSON data in its responseText.
5905 * @return {Object} data A data block which is used by an Roo.data.Store object as
5906 * a cache of Roo.data.Records.
5908 read : function(response){
5909 var json = response.responseText;
5911 var o = /* eval:var:o */ eval("("+json+")");
5913 throw {message: "JsonReader.read: Json object not found"};
5919 this.metaFromRemote = true;
5920 this.meta = o.metaData;
5921 this.recordType = Roo.data.Record.create(o.metaData.fields);
5922 this.onMetaChange(this.meta, this.recordType, o);
5924 return this.readRecords(o);
5927 // private function a store will implement
5928 onMetaChange : function(meta, recordType, o){
5935 simpleAccess: function(obj, subsc) {
5942 getJsonAccessor: function(){
5944 return function(expr) {
5946 return(re.test(expr))
5947 ? new Function("obj", "return obj." + expr)
5957 * Create a data block containing Roo.data.Records from an XML document.
5958 * @param {Object} o An object which contains an Array of row objects in the property specified
5959 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
5960 * which contains the total size of the dataset.
5961 * @return {Object} data A data block which is used by an Roo.data.Store object as
5962 * a cache of Roo.data.Records.
5964 readRecords : function(o){
5966 * After any data loads, the raw JSON data is available for further custom processing.
5970 var s = this.meta, Record = this.recordType,
5971 f = Record.prototype.fields, fi = f.items, fl = f.length;
5973 // Generate extraction functions for the totalProperty, the root, the id, and for each field
5975 if(s.totalProperty) {
5976 this.getTotal = this.getJsonAccessor(s.totalProperty);
5978 if(s.successProperty) {
5979 this.getSuccess = this.getJsonAccessor(s.successProperty);
5981 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
5983 var g = this.getJsonAccessor(s.id);
5984 this.getId = function(rec) {
5986 return (r === undefined || r === "") ? null : r;
5989 this.getId = function(){return null;};
5992 for(var jj = 0; jj < fl; jj++){
5994 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
5995 this.ef[jj] = this.getJsonAccessor(map);
5999 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6000 if(s.totalProperty){
6001 var vt = parseInt(this.getTotal(o), 10);
6006 if(s.successProperty){
6007 var vs = this.getSuccess(o);
6008 if(vs === false || vs === 'false'){
6013 for(var i = 0; i < c; i++){
6016 var id = this.getId(n);
6017 for(var j = 0; j < fl; j++){
6019 var v = this.ef[j](n);
6021 Roo.log('missing convert for ' + f.name);
6025 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6027 var record = new Record(values, id);
6029 records[i] = record;
6035 totalRecords : totalRecords
6040 * Ext JS Library 1.1.1
6041 * Copyright(c) 2006-2007, Ext JS, LLC.
6043 * Originally Released Under LGPL - original licence link has changed is not relivant.
6046 * <script type="text/javascript">
6050 * @class Roo.data.ArrayReader
6051 * @extends Roo.data.DataReader
6052 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6053 * Each element of that Array represents a row of data fields. The
6054 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6055 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6059 var RecordDef = Roo.data.Record.create([
6060 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6061 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6063 var myReader = new Roo.data.ArrayReader({
6064 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6068 * This would consume an Array like this:
6070 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6072 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6074 * Create a new JsonReader
6075 * @param {Object} meta Metadata configuration options.
6076 * @param {Object} recordType Either an Array of field definition objects
6077 * as specified to {@link Roo.data.Record#create},
6078 * or an {@link Roo.data.Record} object
6079 * created using {@link Roo.data.Record#create}.
6081 Roo.data.ArrayReader = function(meta, recordType){
6082 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6085 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6087 * Create a data block containing Roo.data.Records from an XML document.
6088 * @param {Object} o An Array of row objects which represents the dataset.
6089 * @return {Object} data A data block which is used by an Roo.data.Store object as
6090 * a cache of Roo.data.Records.
6092 readRecords : function(o){
6093 var sid = this.meta ? this.meta.id : null;
6094 var recordType = this.recordType, fields = recordType.prototype.fields;
6097 for(var i = 0; i < root.length; i++){
6100 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6101 for(var j = 0, jlen = fields.length; j < jlen; j++){
6102 var f = fields.items[j];
6103 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6104 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6108 var record = new recordType(values, id);
6110 records[records.length] = record;
6114 totalRecords : records.length
6123 * @class Roo.bootstrap.ComboBox
6124 * @extends Roo.bootstrap.TriggerField
6125 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6127 * Create a new ComboBox.
6128 * @param {Object} config Configuration options
6130 Roo.bootstrap.ComboBox = function(config){
6131 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6135 * Fires when the dropdown list is expanded
6136 * @param {Roo.bootstrap.ComboBox} combo This combo box
6141 * Fires when the dropdown list is collapsed
6142 * @param {Roo.bootstrap.ComboBox} combo This combo box
6146 * @event beforeselect
6147 * Fires before a list item is selected. Return false to cancel the selection.
6148 * @param {Roo.bootstrap.ComboBox} combo This combo box
6149 * @param {Roo.data.Record} record The data record returned from the underlying store
6150 * @param {Number} index The index of the selected item in the dropdown list
6152 'beforeselect' : true,
6155 * Fires when a list item is selected
6156 * @param {Roo.bootstrap.ComboBox} combo This combo box
6157 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6158 * @param {Number} index The index of the selected item in the dropdown list
6162 * @event beforequery
6163 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6164 * The event object passed has these properties:
6165 * @param {Roo.bootstrap.ComboBox} combo This combo box
6166 * @param {String} query The query
6167 * @param {Boolean} forceAll true to force "all" query
6168 * @param {Boolean} cancel true to cancel the query
6169 * @param {Object} e The query event object
6171 'beforequery': true,
6174 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6175 * @param {Roo.bootstrap.ComboBox} combo This combo box
6180 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6181 * @param {Roo.bootstrap.ComboBox} combo This combo box
6182 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6190 this.selectedIndex = -1;
6191 if(this.mode == 'local'){
6192 if(config.queryDelay === undefined){
6193 this.queryDelay = 10;
6195 if(config.minChars === undefined){
6201 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6204 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6205 * rendering into an Roo.Editor, defaults to false)
6208 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6209 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6212 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6215 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6216 * the dropdown list (defaults to undefined, with no header element)
6220 * @cfg {String/Roo.Template} tpl The template to use to render the output
6224 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6226 listWidth: undefined,
6228 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6229 * mode = 'remote' or 'text' if mode = 'local')
6231 displayField: undefined,
6233 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6234 * mode = 'remote' or 'value' if mode = 'local').
6235 * Note: use of a valueField requires the user make a selection
6236 * in order for a value to be mapped.
6238 valueField: undefined,
6242 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6243 * field's data value (defaults to the underlying DOM element's name)
6245 hiddenName: undefined,
6247 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6251 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6253 selectedClass: 'active',
6256 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6260 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6261 * anchor positions (defaults to 'tl-bl')
6263 listAlign: 'tl-bl?',
6265 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6269 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
6270 * query specified by the allQuery config option (defaults to 'query')
6272 triggerAction: 'query',
6274 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6275 * (defaults to 4, does not apply if editable = false)
6279 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6280 * delay (typeAheadDelay) if it matches a known value (defaults to false)
6284 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6285 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6289 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6290 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
6294 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
6295 * when editable = true (defaults to false)
6297 selectOnFocus:false,
6299 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6301 queryParam: 'query',
6303 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
6304 * when mode = 'remote' (defaults to 'Loading...')
6306 loadingText: 'Loading...',
6308 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6312 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6316 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6317 * traditional select (defaults to true)
6321 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6325 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6329 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6330 * listWidth has a higher value)
6334 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6335 * allow the user to set arbitrary text into the field (defaults to false)
6337 forceSelection:false,
6339 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6340 * if typeAhead = true (defaults to 250)
6342 typeAheadDelay : 250,
6344 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6345 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6347 valueNotFoundText : undefined,
6349 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6354 * @cfg {Boolean} disableClear Disable showing of clear button.
6356 disableClear : false,
6358 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
6360 alwaysQuery : false,
6366 // element that contains real text value.. (when hidden is used..)
6369 initEvents: function(){
6372 throw "can not find store for combo";
6374 this.store = Roo.factory(this.store, Roo.data);
6378 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6381 if(this.hiddenName){
6383 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6385 this.hiddenField.dom.value =
6386 this.hiddenValue !== undefined ? this.hiddenValue :
6387 this.value !== undefined ? this.value : '';
6389 // prevent input submission
6390 this.el.dom.removeAttribute('name');
6391 this.hiddenField.dom.setAttribute('name', this.hiddenName);
6396 // this.el.dom.setAttribute('autocomplete', 'off');
6399 var cls = 'x-combo-list';
6400 this.list = this.el.select('ul',true).first();
6402 //this.list = new Roo.Layer({
6403 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6406 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6407 this.list.setWidth(lw);
6409 this.list.on('mouseover', this.onViewOver, this);
6410 this.list.on('mousemove', this.onViewMove, this);
6413 this.list.swallowEvent('mousewheel');
6414 this.assetHeight = 0;
6417 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6418 this.assetHeight += this.header.getHeight();
6421 this.innerList = this.list.createChild({cls:cls+'-inner'});
6422 this.innerList.on('mouseover', this.onViewOver, this);
6423 this.innerList.on('mousemove', this.onViewMove, this);
6424 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6426 if(this.allowBlank && !this.pageSize && !this.disableClear){
6427 this.footer = this.list.createChild({cls:cls+'-ft'});
6428 this.pageTb = new Roo.Toolbar(this.footer);
6432 this.footer = this.list.createChild({cls:cls+'-ft'});
6433 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6434 {pageSize: this.pageSize});
6438 if (this.pageTb && this.allowBlank && !this.disableClear) {
6440 this.pageTb.add(new Roo.Toolbar.Fill(), {
6441 cls: 'x-btn-icon x-btn-clear',
6447 _this.onSelect(false, -1);
6452 this.assetHeight += this.footer.getHeight();
6457 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6460 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6461 singleSelect:true, store: this.store, selectedClass: this.selectedClass
6463 //this.view.wrapEl.setDisplayed(false);
6464 this.view.on('click', this.onViewClick, this);
6468 this.store.on('beforeload', this.onBeforeLoad, this);
6469 this.store.on('load', this.onLoad, this);
6470 this.store.on('loadexception', this.onLoadException, this);
6473 this.resizer = new Roo.Resizable(this.list, {
6474 pinned:true, handles:'se'
6476 this.resizer.on('resize', function(r, w, h){
6477 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6479 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6480 this.restrictHeight();
6482 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6486 this.editable = true;
6487 this.setEditable(false);
6492 if (typeof(this.events.add.listeners) != 'undefined') {
6494 this.addicon = this.wrap.createChild(
6495 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
6497 this.addicon.on('click', function(e) {
6498 this.fireEvent('add', this);
6501 if (typeof(this.events.edit.listeners) != 'undefined') {
6503 this.editicon = this.wrap.createChild(
6504 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
6506 this.editicon.setStyle('margin-left', '40px');
6508 this.editicon.on('click', function(e) {
6510 // we fire even if inothing is selected..
6511 this.fireEvent('edit', this, this.lastData );
6518 this.keyNav = new Roo.KeyNav(this.inputEl(), {
6520 this.inKeyMode = true;
6524 "down" : function(e){
6525 if(!this.isExpanded()){
6526 this.onTriggerClick();
6528 this.inKeyMode = true;
6533 "enter" : function(e){
6538 "esc" : function(e){
6542 "tab" : function(e){
6543 this.onViewClick(false);
6544 this.fireEvent("specialkey", this, e);
6550 doRelay : function(foo, bar, hname){
6551 if(hname == 'down' || this.scope.isExpanded()){
6552 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6561 this.queryDelay = Math.max(this.queryDelay || 10,
6562 this.mode == 'local' ? 10 : 250);
6565 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6568 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6570 if(this.editable !== false){
6571 this.inputEl().on("keyup", this.onKeyUp, this);
6573 if(this.forceSelection){
6574 this.on('blur', this.doForce, this);
6578 onDestroy : function(){
6580 this.view.setStore(null);
6581 this.view.el.removeAllListeners();
6582 this.view.el.remove();
6583 this.view.purgeListeners();
6586 this.list.dom.innerHTML = '';
6589 this.store.un('beforeload', this.onBeforeLoad, this);
6590 this.store.un('load', this.onLoad, this);
6591 this.store.un('loadexception', this.onLoadException, this);
6593 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6597 fireKey : function(e){
6598 if(e.isNavKeyPress() && !this.list.isVisible()){
6599 this.fireEvent("specialkey", this, e);
6604 onResize: function(w, h){
6605 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6607 if(typeof w != 'number'){
6608 // we do not handle it!?!?
6611 var tw = this.trigger.getWidth();
6612 // tw += this.addicon ? this.addicon.getWidth() : 0;
6613 // tw += this.editicon ? this.editicon.getWidth() : 0;
6615 this.inputEl().setWidth( this.adjustWidth('input', x));
6617 //this.trigger.setStyle('left', x+'px');
6619 if(this.list && this.listWidth === undefined){
6620 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6621 this.list.setWidth(lw);
6622 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6630 * Allow or prevent the user from directly editing the field text. If false is passed,
6631 * the user will only be able to select from the items defined in the dropdown list. This method
6632 * is the runtime equivalent of setting the 'editable' config option at config time.
6633 * @param {Boolean} value True to allow the user to directly edit the field text
6635 setEditable : function(value){
6636 if(value == this.editable){
6639 this.editable = value;
6641 this.inputEl().dom.setAttribute('readOnly', true);
6642 this.inputEl().on('mousedown', this.onTriggerClick, this);
6643 this.inputEl().addClass('x-combo-noedit');
6645 this.inputEl().dom.setAttribute('readOnly', false);
6646 this.inputEl().un('mousedown', this.onTriggerClick, this);
6647 this.inputEl().removeClass('x-combo-noedit');
6652 onBeforeLoad : function(){
6656 //this.innerList.update(this.loadingText ?
6657 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6658 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6660 this.restrictHeight();
6661 this.selectedIndex = -1;
6665 onLoad : function(){
6669 if(this.store.getCount() > 0){
6671 this.restrictHeight();
6672 if(this.lastQuery == this.allQuery){
6674 this.inputEl().dom.select();
6676 if(!this.selectByValue(this.value, true)){
6677 this.select(0, true);
6681 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6682 this.taTask.delay(this.typeAheadDelay);
6686 this.onEmptyResults();
6691 onLoadException : function()
6694 Roo.log(this.store.reader.jsonData);
6695 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6697 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6703 onTypeAhead : function(){
6704 if(this.store.getCount() > 0){
6705 var r = this.store.getAt(0);
6706 var newValue = r.data[this.displayField];
6707 var len = newValue.length;
6708 var selStart = this.getRawValue().length;
6710 if(selStart != len){
6711 this.setRawValue(newValue);
6712 this.selectText(selStart, newValue.length);
6718 onSelect : function(record, index){
6719 if(this.fireEvent('beforeselect', this, record, index) !== false){
6720 this.setFromData(index > -1 ? record.data : false);
6722 this.fireEvent('select', this, record, index);
6727 * Returns the currently selected field value or empty string if no value is set.
6728 * @return {String} value The selected value
6730 getValue : function(){
6731 if(this.valueField){
6732 return typeof this.value != 'undefined' ? this.value : '';
6734 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6739 * Clears any text/value currently set in the field
6741 clearValue : function(){
6742 if(this.hiddenField){
6743 this.hiddenField.dom.value = '';
6746 this.setRawValue('');
6747 this.lastSelectionText = '';
6752 * Sets the specified value into the field. If the value finds a match, the corresponding record text
6753 * will be displayed in the field. If the value does not match the data value of an existing item,
6754 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6755 * Otherwise the field will be blank (although the value will still be set).
6756 * @param {String} value The value to match
6758 setValue : function(v){
6760 if(this.valueField){
6761 var r = this.findRecord(this.valueField, v);
6763 text = r.data[this.displayField];
6764 }else if(this.valueNotFoundText !== undefined){
6765 text = this.valueNotFoundText;
6768 this.lastSelectionText = text;
6769 if(this.hiddenField){
6770 this.hiddenField.dom.value = v;
6772 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6776 * @property {Object} the last set data for the element
6781 * Sets the value of the field based on a object which is related to the record format for the store.
6782 * @param {Object} value the value to set as. or false on reset?
6784 setFromData : function(o){
6785 var dv = ''; // display value
6786 var vv = ''; // value value..
6788 if (this.displayField) {
6789 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6791 // this is an error condition!!!
6792 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
6795 if(this.valueField){
6796 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6798 if(this.hiddenField){
6799 this.hiddenField.dom.value = vv;
6801 this.lastSelectionText = dv;
6802 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6806 // no hidden field.. - we store the value in 'value', but still display
6807 // display field!!!!
6808 this.lastSelectionText = dv;
6809 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6816 // overridden so that last data is reset..
6817 this.setValue(this.originalValue);
6818 this.clearInvalid();
6819 this.lastData = false;
6821 this.view.clearSelections();
6825 findRecord : function(prop, value){
6827 if(this.store.getCount() > 0){
6828 this.store.each(function(r){
6829 if(r.data[prop] == value){
6841 // returns hidden if it's set..
6842 if (!this.rendered) {return ''};
6843 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
6847 onViewMove : function(e, t){
6848 this.inKeyMode = false;
6852 onViewOver : function(e, t){
6853 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6856 var item = this.view.findItemFromChild(t);
6858 var index = this.view.indexOf(item);
6859 this.select(index, false);
6864 onViewClick : function(doFocus)
6866 var index = this.view.getSelectedIndexes()[0];
6867 var r = this.store.getAt(index);
6869 this.onSelect(r, index);
6871 if(doFocus !== false && !this.blockFocus){
6872 this.inputEl().focus();
6877 restrictHeight : function(){
6878 //this.innerList.dom.style.height = '';
6879 //var inner = this.innerList.dom;
6880 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6881 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6882 //this.list.beginUpdate();
6883 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6884 this.list.alignTo(this.inputEl(), this.listAlign);
6885 //this.list.endUpdate();
6889 onEmptyResults : function(){
6894 * Returns true if the dropdown list is expanded, else false.
6896 isExpanded : function(){
6897 return this.list.isVisible();
6901 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6902 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6903 * @param {String} value The data value of the item to select
6904 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6905 * selected item if it is not currently in view (defaults to true)
6906 * @return {Boolean} True if the value matched an item in the list, else false
6908 selectByValue : function(v, scrollIntoView){
6909 if(v !== undefined && v !== null){
6910 var r = this.findRecord(this.valueField || this.displayField, v);
6912 this.select(this.store.indexOf(r), scrollIntoView);
6920 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
6921 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6922 * @param {Number} index The zero-based index of the list item to select
6923 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6924 * selected item if it is not currently in view (defaults to true)
6926 select : function(index, scrollIntoView){
6927 this.selectedIndex = index;
6928 this.view.select(index);
6929 if(scrollIntoView !== false){
6930 var el = this.view.getNode(index);
6932 //this.innerList.scrollChildIntoView(el, false);
6939 selectNext : function(){
6940 var ct = this.store.getCount();
6942 if(this.selectedIndex == -1){
6944 }else if(this.selectedIndex < ct-1){
6945 this.select(this.selectedIndex+1);
6951 selectPrev : function(){
6952 var ct = this.store.getCount();
6954 if(this.selectedIndex == -1){
6956 }else if(this.selectedIndex != 0){
6957 this.select(this.selectedIndex-1);
6963 onKeyUp : function(e){
6964 if(this.editable !== false && !e.isSpecialKey()){
6965 this.lastKey = e.getKey();
6966 this.dqTask.delay(this.queryDelay);
6971 validateBlur : function(){
6972 return !this.list || !this.list.isVisible();
6976 initQuery : function(){
6977 this.doQuery(this.getRawValue());
6981 doForce : function(){
6982 if(this.el.dom.value.length > 0){
6984 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
6990 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
6991 * query allowing the query action to be canceled if needed.
6992 * @param {String} query The SQL query to execute
6993 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
6994 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
6995 * saved in the current store (defaults to false)
6997 doQuery : function(q, forceAll){
6998 if(q === undefined || q === null){
7007 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
7011 forceAll = qe.forceAll;
7012 if(forceAll === true || (q.length >= this.minChars)){
7013 if(this.lastQuery != q || this.alwaysQuery){
7015 if(this.mode == 'local'){
7016 this.selectedIndex = -1;
7018 this.store.clearFilter();
7020 this.store.filter(this.displayField, q);
7024 this.store.baseParams[this.queryParam] = q;
7026 params: this.getParams(q)
7031 this.selectedIndex = -1;
7038 getParams : function(q){
7040 //p[this.queryParam] = q;
7043 p.limit = this.pageSize;
7049 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7051 collapse : function(){
7052 if(!this.isExpanded()){
7056 Roo.get(document).un('mousedown', this.collapseIf, this);
7057 Roo.get(document).un('mousewheel', this.collapseIf, this);
7058 if (!this.editable) {
7059 Roo.get(document).un('keydown', this.listKeyPress, this);
7061 this.fireEvent('collapse', this);
7065 collapseIf : function(e){
7066 if(!e.within(this.el) && !e.within(this.el)){
7072 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7074 expand : function(){
7076 if(this.isExpanded() || !this.hasFocus){
7079 this.list.alignTo(this.inputEl(), this.listAlign);
7081 Roo.get(document).on('mousedown', this.collapseIf, this);
7082 Roo.get(document).on('mousewheel', this.collapseIf, this);
7083 if (!this.editable) {
7084 Roo.get(document).on('keydown', this.listKeyPress, this);
7087 this.fireEvent('expand', this);
7091 // Implements the default empty TriggerField.onTriggerClick function
7092 onTriggerClick : function()
7094 Roo.log('trigger click');
7099 if(this.isExpanded()){
7101 if (!this.blockFocus) {
7102 this.inputEl().focus();
7106 this.hasFocus = true;
7107 if(this.triggerAction == 'all') {
7108 this.doQuery(this.allQuery, true);
7110 this.doQuery(this.getRawValue());
7112 if (!this.blockFocus) {
7113 this.inputEl().focus();
7117 listKeyPress : function(e)
7119 //Roo.log('listkeypress');
7120 // scroll to first matching element based on key pres..
7121 if (e.isSpecialKey()) {
7124 var k = String.fromCharCode(e.getKey()).toUpperCase();
7127 var csel = this.view.getSelectedNodes();
7128 var cselitem = false;
7130 var ix = this.view.indexOf(csel[0]);
7131 cselitem = this.store.getAt(ix);
7132 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7138 this.store.each(function(v) {
7140 // start at existing selection.
7141 if (cselitem.id == v.id) {
7147 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7148 match = this.store.indexOf(v);
7154 if (match === false) {
7155 return true; // no more action?
7158 this.view.select(match);
7159 var sn = Roo.get(this.view.getSelectedNodes()[0])
7160 //sn.scrollIntoView(sn.dom.parentNode, false);
7164 * @cfg {Boolean} grow
7168 * @cfg {Number} growMin
7172 * @cfg {Number} growMax
7181 * Ext JS Library 1.1.1
7182 * Copyright(c) 2006-2007, Ext JS, LLC.
7184 * Originally Released Under LGPL - original licence link has changed is not relivant.
7187 * <script type="text/javascript">
7192 * @extends Roo.util.Observable
7193 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7194 * This class also supports single and multi selection modes. <br>
7195 * Create a data model bound view:
7197 var store = new Roo.data.Store(...);
7199 var view = new Roo.View({
7201 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7204 selectedClass: "ydataview-selected",
7208 // listen for node click?
7209 view.on("click", function(vw, index, node, e){
7210 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7214 dataModel.load("foobar.xml");
7216 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7218 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7219 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7221 * Note: old style constructor is still suported (container, template, config)
7225 * @param {Object} config The config object
7228 Roo.View = function(config, depreciated_tpl, depreciated_config){
7230 if (typeof(depreciated_tpl) == 'undefined') {
7231 // new way.. - universal constructor.
7232 Roo.apply(this, config);
7233 this.el = Roo.get(this.el);
7236 this.el = Roo.get(config);
7237 this.tpl = depreciated_tpl;
7238 Roo.apply(this, depreciated_config);
7240 this.wrapEl = this.el.wrap().wrap();
7241 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7244 if(typeof(this.tpl) == "string"){
7245 this.tpl = new Roo.Template(this.tpl);
7247 // support xtype ctors..
7248 this.tpl = new Roo.factory(this.tpl, Roo);
7260 * @event beforeclick
7261 * Fires before a click is processed. Returns false to cancel the default action.
7262 * @param {Roo.View} this
7263 * @param {Number} index The index of the target node
7264 * @param {HTMLElement} node The target node
7265 * @param {Roo.EventObject} e The raw event object
7267 "beforeclick" : true,
7270 * Fires when a template node is clicked.
7271 * @param {Roo.View} this
7272 * @param {Number} index The index of the target node
7273 * @param {HTMLElement} node The target node
7274 * @param {Roo.EventObject} e The raw event object
7279 * Fires when a template node is double clicked.
7280 * @param {Roo.View} this
7281 * @param {Number} index The index of the target node
7282 * @param {HTMLElement} node The target node
7283 * @param {Roo.EventObject} e The raw event object
7287 * @event contextmenu
7288 * Fires when a template node is right clicked.
7289 * @param {Roo.View} this
7290 * @param {Number} index The index of the target node
7291 * @param {HTMLElement} node The target node
7292 * @param {Roo.EventObject} e The raw event object
7294 "contextmenu" : true,
7296 * @event selectionchange
7297 * Fires when the selected nodes change.
7298 * @param {Roo.View} this
7299 * @param {Array} selections Array of the selected nodes
7301 "selectionchange" : true,
7304 * @event beforeselect
7305 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7306 * @param {Roo.View} this
7307 * @param {HTMLElement} node The node to be selected
7308 * @param {Array} selections Array of currently selected nodes
7310 "beforeselect" : true,
7312 * @event preparedata
7313 * Fires on every row to render, to allow you to change the data.
7314 * @param {Roo.View} this
7315 * @param {Object} data to be rendered (change this)
7317 "preparedata" : true
7325 "click": this.onClick,
7326 "dblclick": this.onDblClick,
7327 "contextmenu": this.onContextMenu,
7331 this.selections = [];
7333 this.cmp = new Roo.CompositeElementLite([]);
7335 this.store = Roo.factory(this.store, Roo.data);
7336 this.setStore(this.store, true);
7339 if ( this.footer && this.footer.xtype) {
7341 var fctr = this.wrapEl.appendChild(document.createElement("div"));
7343 this.footer.dataSource = this.store
7344 this.footer.container = fctr;
7345 this.footer = Roo.factory(this.footer, Roo);
7346 fctr.insertFirst(this.el);
7348 // this is a bit insane - as the paging toolbar seems to detach the el..
7349 // dom.parentNode.parentNode.parentNode
7350 // they get detached?
7354 Roo.View.superclass.constructor.call(this);
7359 Roo.extend(Roo.View, Roo.util.Observable, {
7362 * @cfg {Roo.data.Store} store Data store to load data from.
7367 * @cfg {String|Roo.Element} el The container element.
7372 * @cfg {String|Roo.Template} tpl The template used by this View
7376 * @cfg {String} dataName the named area of the template to use as the data area
7377 * Works with domtemplates roo-name="name"
7381 * @cfg {String} selectedClass The css class to add to selected nodes
7383 selectedClass : "x-view-selected",
7385 * @cfg {String} emptyText The empty text to show when nothing is loaded.
7390 * @cfg {String} text to display on mask (default Loading)
7394 * @cfg {Boolean} multiSelect Allow multiple selection
7396 multiSelect : false,
7398 * @cfg {Boolean} singleSelect Allow single selection
7400 singleSelect: false,
7403 * @cfg {Boolean} toggleSelect - selecting
7405 toggleSelect : false,
7408 * Returns the element this view is bound to.
7409 * @return {Roo.Element}
7418 * Refreshes the view. - called by datachanged on the store. - do not call directly.
7420 refresh : function(){
7423 // if we are using something like 'domtemplate', then
7424 // the what gets used is:
7425 // t.applySubtemplate(NAME, data, wrapping data..)
7426 // the outer template then get' applied with
7427 // the store 'extra data'
7428 // and the body get's added to the
7429 // roo-name="data" node?
7430 // <span class='roo-tpl-{name}'></span> ?????
7434 this.clearSelections();
7437 var records = this.store.getRange();
7438 if(records.length < 1) {
7440 // is this valid?? = should it render a template??
7442 this.el.update(this.emptyText);
7446 if (this.dataName) {
7447 this.el.update(t.apply(this.store.meta)); //????
7448 el = this.el.child('.roo-tpl-' + this.dataName);
7451 for(var i = 0, len = records.length; i < len; i++){
7452 var data = this.prepareData(records[i].data, i, records[i]);
7453 this.fireEvent("preparedata", this, data, i, records[i]);
7454 html[html.length] = Roo.util.Format.trim(
7456 t.applySubtemplate(this.dataName, data, this.store.meta) :
7463 el.update(html.join(""));
7464 this.nodes = el.dom.childNodes;
7465 this.updateIndexes(0);
7469 * Function to override to reformat the data that is sent to
7470 * the template for each node.
7471 * DEPRICATED - use the preparedata event handler.
7472 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7473 * a JSON object for an UpdateManager bound view).
7475 prepareData : function(data, index, record)
7477 this.fireEvent("preparedata", this, data, index, record);
7481 onUpdate : function(ds, record){
7482 this.clearSelections();
7483 var index = this.store.indexOf(record);
7484 var n = this.nodes[index];
7485 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7486 n.parentNode.removeChild(n);
7487 this.updateIndexes(index, index);
7493 onAdd : function(ds, records, index)
7495 this.clearSelections();
7496 if(this.nodes.length == 0){
7500 var n = this.nodes[index];
7501 for(var i = 0, len = records.length; i < len; i++){
7502 var d = this.prepareData(records[i].data, i, records[i]);
7504 this.tpl.insertBefore(n, d);
7507 this.tpl.append(this.el, d);
7510 this.updateIndexes(index);
7513 onRemove : function(ds, record, index){
7514 this.clearSelections();
7515 var el = this.dataName ?
7516 this.el.child('.roo-tpl-' + this.dataName) :
7518 el.dom.removeChild(this.nodes[index]);
7519 this.updateIndexes(index);
7523 * Refresh an individual node.
7524 * @param {Number} index
7526 refreshNode : function(index){
7527 this.onUpdate(this.store, this.store.getAt(index));
7530 updateIndexes : function(startIndex, endIndex){
7531 var ns = this.nodes;
7532 startIndex = startIndex || 0;
7533 endIndex = endIndex || ns.length - 1;
7534 for(var i = startIndex; i <= endIndex; i++){
7535 ns[i].nodeIndex = i;
7540 * Changes the data store this view uses and refresh the view.
7541 * @param {Store} store
7543 setStore : function(store, initial){
7544 if(!initial && this.store){
7545 this.store.un("datachanged", this.refresh);
7546 this.store.un("add", this.onAdd);
7547 this.store.un("remove", this.onRemove);
7548 this.store.un("update", this.onUpdate);
7549 this.store.un("clear", this.refresh);
7550 this.store.un("beforeload", this.onBeforeLoad);
7551 this.store.un("load", this.onLoad);
7552 this.store.un("loadexception", this.onLoad);
7556 store.on("datachanged", this.refresh, this);
7557 store.on("add", this.onAdd, this);
7558 store.on("remove", this.onRemove, this);
7559 store.on("update", this.onUpdate, this);
7560 store.on("clear", this.refresh, this);
7561 store.on("beforeload", this.onBeforeLoad, this);
7562 store.on("load", this.onLoad, this);
7563 store.on("loadexception", this.onLoad, this);
7571 * onbeforeLoad - masks the loading area.
7574 onBeforeLoad : function()
7577 this.el.mask(this.mask ? this.mask : "Loading" );
7579 onLoad : function ()
7586 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7587 * @param {HTMLElement} node
7588 * @return {HTMLElement} The template node
7590 findItemFromChild : function(node){
7591 var el = this.dataName ?
7592 this.el.child('.roo-tpl-' + this.dataName,true) :
7595 if(!node || node.parentNode == el){
7598 var p = node.parentNode;
7599 while(p && p != el){
7600 if(p.parentNode == el){
7609 onClick : function(e){
7610 var item = this.findItemFromChild(e.getTarget());
7612 var index = this.indexOf(item);
7613 if(this.onItemClick(item, index, e) !== false){
7614 this.fireEvent("click", this, index, item, e);
7617 this.clearSelections();
7622 onContextMenu : function(e){
7623 var item = this.findItemFromChild(e.getTarget());
7625 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7630 onDblClick : function(e){
7631 var item = this.findItemFromChild(e.getTarget());
7633 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7637 onItemClick : function(item, index, e)
7639 if(this.fireEvent("beforeclick", this, index, item, e) === false){
7642 if (this.toggleSelect) {
7643 var m = this.isSelected(item) ? 'unselect' : 'select';
7646 _t[m](item, true, false);
7649 if(this.multiSelect || this.singleSelect){
7650 if(this.multiSelect && e.shiftKey && this.lastSelection){
7651 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7653 this.select(item, this.multiSelect && e.ctrlKey);
7654 this.lastSelection = item;
7662 * Get the number of selected nodes.
7665 getSelectionCount : function(){
7666 return this.selections.length;
7670 * Get the currently selected nodes.
7671 * @return {Array} An array of HTMLElements
7673 getSelectedNodes : function(){
7674 return this.selections;
7678 * Get the indexes of the selected nodes.
7681 getSelectedIndexes : function(){
7682 var indexes = [], s = this.selections;
7683 for(var i = 0, len = s.length; i < len; i++){
7684 indexes.push(s[i].nodeIndex);
7690 * Clear all selections
7691 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7693 clearSelections : function(suppressEvent){
7694 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7695 this.cmp.elements = this.selections;
7696 this.cmp.removeClass(this.selectedClass);
7697 this.selections = [];
7699 this.fireEvent("selectionchange", this, this.selections);
7705 * Returns true if the passed node is selected
7706 * @param {HTMLElement/Number} node The node or node index
7709 isSelected : function(node){
7710 var s = this.selections;
7714 node = this.getNode(node);
7715 return s.indexOf(node) !== -1;
7720 * @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
7721 * @param {Boolean} keepExisting (optional) true to keep existing selections
7722 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7724 select : function(nodeInfo, keepExisting, suppressEvent){
7725 if(nodeInfo instanceof Array){
7727 this.clearSelections(true);
7729 for(var i = 0, len = nodeInfo.length; i < len; i++){
7730 this.select(nodeInfo[i], true, true);
7734 var node = this.getNode(nodeInfo);
7735 if(!node || this.isSelected(node)){
7736 return; // already selected.
7739 this.clearSelections(true);
7741 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7742 Roo.fly(node).addClass(this.selectedClass);
7743 this.selections.push(node);
7745 this.fireEvent("selectionchange", this, this.selections);
7753 * @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
7754 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7755 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7757 unselect : function(nodeInfo, keepExisting, suppressEvent)
7759 if(nodeInfo instanceof Array){
7760 Roo.each(this.selections, function(s) {
7761 this.unselect(s, nodeInfo);
7765 var node = this.getNode(nodeInfo);
7766 if(!node || !this.isSelected(node)){
7767 Roo.log("not selected");
7768 return; // not selected.
7772 Roo.each(this.selections, function(s) {
7774 Roo.fly(node).removeClass(this.selectedClass);
7781 this.selections= ns;
7782 this.fireEvent("selectionchange", this, this.selections);
7786 * Gets a template node.
7787 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7788 * @return {HTMLElement} The node or null if it wasn't found
7790 getNode : function(nodeInfo){
7791 if(typeof nodeInfo == "string"){
7792 return document.getElementById(nodeInfo);
7793 }else if(typeof nodeInfo == "number"){
7794 return this.nodes[nodeInfo];
7800 * Gets a range template nodes.
7801 * @param {Number} startIndex
7802 * @param {Number} endIndex
7803 * @return {Array} An array of nodes
7805 getNodes : function(start, end){
7806 var ns = this.nodes;
7808 end = typeof end == "undefined" ? ns.length - 1 : end;
7811 for(var i = start; i <= end; i++){
7815 for(var i = start; i >= end; i--){
7823 * Finds the index of the passed node
7824 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7825 * @return {Number} The index of the node or -1
7827 indexOf : function(node){
7828 node = this.getNode(node);
7829 if(typeof node.nodeIndex == "number"){
7830 return node.nodeIndex;
7832 var ns = this.nodes;
7833 for(var i = 0, len = ns.length; i < len; i++){
7844 * based on jquery fullcalendar
7850 * @class Roo.bootstrap.Calendar
7851 * @extends Roo.bootstrap.Component
7852 * Bootstrap Calendar class
7855 * Create a new Container
7856 * @param {Object} config The config object
7859 Roo.bootstrap.Calendar = function(config){
7860 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7864 * Fires when a date is selected
7865 * @param {DatePicker} this
7866 * @param {Date} date The selected date
7870 * @event monthchange
7871 * Fires when the displayed month changes
7872 * @param {DatePicker} this
7873 * @param {Date} date The selected month
7875 'monthchange': true,
7878 * Fires when mouse over an event
7879 * @param {Calendar} this
7880 * @param {event} Event
7885 * Fires when the mouse leaves an
7886 * @param {Calendar} this
7892 * Fires when the mouse click an
7893 * @param {Calendar} this
7902 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
7905 * @cfg {Number} startDay
7906 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
7910 getAutoCreate : function(){
7913 fc_button = function(name, corner, style, content ) {
7914 return Roo.apply({},{
7916 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
7918 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
7921 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
7929 style : 'width:100%',
7936 cls : 'fc-header-left',
7938 fc_button('prev', 'left', 'arrow', '‹' ),
7939 fc_button('next', 'right', 'arrow', '›' ),
7940 { tag: 'span', cls: 'fc-header-space' },
7941 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
7949 cls : 'fc-header-center',
7953 cls: 'fc-header-title',
7956 html : 'month / year'
7964 cls : 'fc-header-right',
7966 /* fc_button('month', 'left', '', 'month' ),
7967 fc_button('week', '', '', 'week' ),
7968 fc_button('day', 'right', '', 'day' )
7980 var cal_heads = function() {
7982 // fixme - handle this.
7984 for (var i =0; i < Date.dayNames.length; i++) {
7985 var d = Date.dayNames[i];
7988 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
7989 html : d.substring(0,3)
7993 ret[0].cls += ' fc-first';
7994 ret[6].cls += ' fc-last';
7997 var cal_cell = function(n) {
8000 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
8005 cls: 'fc-day-number',
8009 cls: 'fc-day-content',
8013 style: 'position: relative;' // height: 17px;
8025 var cal_rows = function() {
8028 for (var r = 0; r < 6; r++) {
8035 for (var i =0; i < Date.dayNames.length; i++) {
8036 var d = Date.dayNames[i];
8037 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
8040 row.cn[0].cls+=' fc-first';
8041 row.cn[0].cn[0].style = 'min-height:90px';
8042 row.cn[6].cls+=' fc-last';
8046 ret[0].cls += ' fc-first';
8047 ret[4].cls += ' fc-prev-last';
8048 ret[5].cls += ' fc-last';
8055 cls: 'fc-border-separate',
8056 style : 'width:100%',
8064 cls : 'fc-first fc-last',
8083 style : "position: relative;",
8086 cls : 'fc-view fc-view-month fc-grid',
8087 style : 'position: relative',
8088 unselectable : 'on',
8091 cls : 'fc-event-container',
8092 style : 'position:absolute;z-index:8;top:0;left:0;'
8110 initEvents : function()
8113 throw "can not find store for combo";
8116 this.store = Roo.factory(this.store, Roo.data);
8117 this.store.on('load', this.onLoad, this);
8120 this.cells = this.el.select('.fc-day',true);
8122 this.textNodes = this.el.query('.fc-day-number');
8123 this.cells.addClassOnOver('fc-state-hover');
8125 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8126 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8127 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8128 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8130 this.on('monthchange', this.onMonthChange, this);
8132 this.update(new Date().clearTime());
8135 resize : function() {
8136 var sz = this.el.getSize();
8138 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8139 this.el.select('.fc-day-content div',true).setHeight(34);
8144 showPrevMonth : function(e){
8145 this.update(this.activeDate.add("mo", -1));
8147 showToday : function(e){
8148 this.update(new Date().clearTime());
8151 showNextMonth : function(e){
8152 this.update(this.activeDate.add("mo", 1));
8156 showPrevYear : function(){
8157 this.update(this.activeDate.add("y", -1));
8161 showNextYear : function(){
8162 this.update(this.activeDate.add("y", 1));
8167 update : function(date)
8169 var vd = this.activeDate;
8170 this.activeDate = date;
8172 var t = date.getTime();
8173 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8174 Roo.log('using add remove');
8176 this.fireEvent('monthchange', this, date);
8178 this.cells.removeClass("fc-state-highlight");
8179 this.cells.each(function(c){
8180 if(c.dateValue == t){
8181 c.addClass("fc-state-highlight");
8182 setTimeout(function(){
8183 try{c.dom.firstChild.focus();}catch(e){}
8193 var days = date.getDaysInMonth();
8195 var firstOfMonth = date.getFirstDateOfMonth();
8196 var startingPos = firstOfMonth.getDay()-this.startDay;
8198 if(startingPos < this.startDay){
8202 var pm = date.add("mo", -1);
8203 var prevStart = pm.getDaysInMonth()-startingPos;
8205 this.cells = this.el.select('.fc-day',true);
8206 this.textNodes = this.el.query('.fc-day-number');
8207 this.cells.addClassOnOver('fc-state-hover');
8209 var cells = this.cells.elements;
8210 var textEls = this.textNodes;
8212 Roo.each(cells, function(cell){
8213 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
8216 days += startingPos;
8218 // convert everything to numbers so it's fast
8220 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8221 var today = new Date().clearTime().getTime();
8222 var sel = date.clearTime().getTime();
8223 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8224 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8225 var ddMatch = this.disabledDatesRE;
8226 var ddText = this.disabledDatesText;
8227 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8228 var ddaysText = this.disabledDaysText;
8229 var format = this.format;
8231 var setCellClass = function(cal, cell){
8233 var t = d.getTime();
8237 cell.className += " fc-today";
8238 cell.className += " fc-state-highlight";
8239 cell.title = cal.todayText;
8242 // disable highlight in other month..
8243 //cell.className += " fc-state-highlight";
8248 cell.className = " fc-state-disabled";
8249 cell.title = cal.minText;
8253 cell.className = " fc-state-disabled";
8254 cell.title = cal.maxText;
8258 if(ddays.indexOf(d.getDay()) != -1){
8259 cell.title = ddaysText;
8260 cell.className = " fc-state-disabled";
8263 if(ddMatch && format){
8264 var fvalue = d.dateFormat(format);
8265 if(ddMatch.test(fvalue)){
8266 cell.title = ddText.replace("%0", fvalue);
8267 cell.className = " fc-state-disabled";
8271 if (!cell.initialClassName) {
8272 cell.initialClassName = cell.dom.className;
8275 cell.dom.className = cell.initialClassName + ' ' + cell.className;
8280 for(; i < startingPos; i++) {
8281 textEls[i].innerHTML = (++prevStart);
8282 d.setDate(d.getDate()+1);
8284 cells[i].className = "fc-past fc-other-month";
8285 setCellClass(this, cells[i]);
8290 for(; i < days; i++){
8291 intDay = i - startingPos + 1;
8292 textEls[i].innerHTML = (intDay);
8293 d.setDate(d.getDate()+1);
8295 cells[i].className = ''; // "x-date-active";
8296 setCellClass(this, cells[i]);
8300 for(; i < 42; i++) {
8301 textEls[i].innerHTML = (++extraDays);
8302 d.setDate(d.getDate()+1);
8304 cells[i].className = "fc-future fc-other-month";
8305 setCellClass(this, cells[i]);
8308 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8310 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
8312 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
8313 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
8316 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
8317 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
8320 this.fireEvent('monthchange', this, date);
8324 if(!this.internalRender){
8325 var main = this.el.dom.firstChild;
8326 var w = main.offsetWidth;
8327 this.el.setWidth(w + this.el.getBorderWidth("lr"));
8328 Roo.fly(main).setWidth(w);
8329 this.internalRender = true;
8330 // opera does not respect the auto grow header center column
8331 // then, after it gets a width opera refuses to recalculate
8332 // without a second pass
8333 if(Roo.isOpera && !this.secondPass){
8334 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8335 this.secondPass = true;
8336 this.update.defer(10, this, [date]);
8343 findCell : function(dt) {
8344 dt = dt.clearTime().getTime();
8346 this.cells.each(function(c){
8347 //Roo.log("check " +c.dateValue + '?=' + dt);
8348 if(c.dateValue == dt){
8358 findCells : function(ev) {
8359 var s = ev.start.clone().clearTime().getTime();
8360 var e= ev.end.clone().clearTime().getTime();
8362 this.cells.each(function(c){
8363 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8365 if(c.dateValue > e){
8368 if(c.dateValue < s){
8377 findBestRow: function(cells)
8381 for (var i =0 ; i < cells.length;i++) {
8382 ret = Math.max(cells[i].rows || 0,ret);
8389 addItem : function(ev)
8391 // look for vertical location slot in
8392 var cells = this.findCells(ev);
8394 ev.row = this.findBestRow(cells);
8396 // work out the location.
8400 for(var i =0; i < cells.length; i++) {
8408 if (crow.start.getY() == cells[i].getY()) {
8410 crow.end = cells[i];
8426 for (var i = 0; i < cells.length;i++) {
8427 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8431 this.calevents.push(ev);
8434 clearEvents: function() {
8436 if(!this.calevents){
8440 Roo.each(this.cells.elements, function(c){
8444 Roo.each(this.calevents, function(e) {
8445 Roo.each(e.els, function(el) {
8446 el.un('mouseenter' ,this.onEventEnter, this);
8447 el.un('mouseleave' ,this.onEventLeave, this);
8454 renderEvents: function()
8456 // first make sure there is enough space..
8458 this.cells.each(function(c) {
8460 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8463 for (var e = 0; e < this.calevents.length; e++) {
8464 var ev = this.calevents[e];
8465 var cells = ev.cells;
8468 for(var i =0; i < rows.length; i++) {
8471 // how many rows should it span..
8474 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8475 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8477 unselectable : "on",
8480 cls: 'fc-event-inner',
8484 cls: 'fc-event-time',
8485 html : cells.length > 1 ? '' : ev.time
8489 cls: 'fc-event-title',
8490 html : String.format('{0}', ev.title)
8497 cls: 'ui-resizable-handle ui-resizable-e',
8498 html : '  '
8504 cfg.cls += ' fc-event-start';
8506 if ((i+1) == rows.length) {
8507 cfg.cls += ' fc-event-end';
8510 var ctr = this.el.select('.fc-event-container',true).first();
8511 var cg = ctr.createChild(cfg);
8513 cg.on('mouseenter' ,this.onEventEnter, this, ev);
8514 cg.on('mouseleave' ,this.onEventLeave, this, ev);
8515 cg.on('click', this.onEventClick, this, ev);
8519 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8520 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8522 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
8523 cg.setWidth(ebox.right - sbox.x -2);
8531 onEventEnter: function (e, el,event,d) {
8532 this.fireEvent('evententer', this, el, event);
8535 onEventLeave: function (e, el,event,d) {
8536 this.fireEvent('eventleave', this, el, event);
8539 onEventClick: function (e, el,event,d) {
8540 this.fireEvent('eventclick', this, el, event);
8543 onMonthChange: function () {
8547 onLoad: function () {
8550 Roo.log('calendar onload');
8552 this.calevents = [];
8554 if(this.store.getCount() > 0){
8555 this.store.data.each(function(d){
8558 start: new Date(d.data.start_dt),
8559 end : new Date(d.data.end_dt),
8560 time : d.data.start_time,
8561 title : d.data.title,
8562 description : d.data.description
8567 this.renderEvents();
8580 * @class Roo.bootstrap.Popover
8581 * @extends Roo.bootstrap.Component
8582 * Bootstrap Popover class
8583 * @cfg {String} html contents of the popover (or false to use children..)
8584 * @cfg {String} title of popover (or false to hide)
8585 * @cfg {String} placement how it is placed
8586 * @cfg {String} trigger click || hover (or false to trigger manually)
8587 * @cfg {String} over what (parent or false to trigger manually.)
8590 * Create a new Popover
8591 * @param {Object} config The config object
8594 Roo.bootstrap.Popover = function(config){
8595 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8598 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
8600 title: 'Fill in a title',
8603 placement : 'right',
8604 trigger : 'hover', // hover
8608 can_build_overlaid : false,
8610 getChildContainer : function()
8612 return this.el.select('.popover-content',true).first();
8615 getAutoCreate : function(){
8616 Roo.log('make popover?');
8618 cls : 'popover roo-dynamic',
8619 style: 'display:block',
8625 cls : 'popover-inner',
8629 cls: 'popover-title',
8633 cls : 'popover-content',
8644 setTitle: function(str)
8646 this.el.select('.popover-title',true).first().dom.innerHTML = str;
8648 setContent: function(str)
8650 this.el.select('.popover-content',true).first().dom.innerHTML = str;
8652 // as it get's added to the bottom of the page.
8653 onRender : function(ct, position)
8655 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8657 var cfg = Roo.apply({}, this.getAutoCreate());
8661 cfg.cls += ' ' + this.cls;
8664 cfg.style = this.style;
8666 Roo.log("adding to ")
8667 this.el = Roo.get(document.body).createChild(cfg, position);
8673 initEvents : function()
8675 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8676 this.el.enableDisplayMode('block');
8678 if (this.over === false) {
8681 if (this.triggers === false) {
8684 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8685 var triggers = this.trigger ? this.trigger.split(' ') : [];
8686 Roo.each(triggers, function(trigger) {
8688 if (trigger == 'click') {
8689 on_el.on('click', this.toggle, this);
8690 } else if (trigger != 'manual') {
8691 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
8692 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8694 on_el.on(eventIn ,this.enter, this);
8695 on_el.on(eventOut, this.leave, this);
8706 toggle : function () {
8707 this.hoverState == 'in' ? this.leave() : this.enter();
8710 enter : function () {
8713 clearTimeout(this.timeout);
8715 this.hoverState = 'in'
8717 if (!this.delay || !this.delay.show) {
8722 this.timeout = setTimeout(function () {
8723 if (_t.hoverState == 'in') {
8728 leave : function() {
8729 clearTimeout(this.timeout);
8731 this.hoverState = 'out'
8733 if (!this.delay || !this.delay.hide) {
8738 this.timeout = setTimeout(function () {
8739 if (_t.hoverState == 'out') {
8745 show : function (on_el)
8748 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8751 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8752 if (this.html !== false) {
8753 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8755 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8756 if (!this.title.length) {
8757 this.el.select('.popover-title',true).hide();
8760 var placement = typeof this.placement == 'function' ?
8761 this.placement.call(this, this.el, on_el) :
8764 var autoToken = /\s?auto?\s?/i;
8765 var autoPlace = autoToken.test(placement);
8767 placement = placement.replace(autoToken, '') || 'top';
8771 //this.el.setXY([0,0]);
8773 this.el.dom.style.display='block';
8774 this.el.addClass(placement);
8776 //this.el.appendTo(on_el);
8778 var p = this.getPosition();
8779 var box = this.el.getBox();
8784 var align = Roo.bootstrap.Popover.alignment[placement]
8785 this.el.alignTo(on_el, align[0],align[1]);
8786 //var arrow = this.el.select('.arrow',true).first();
8787 //arrow.set(align[2],
8789 this.el.addClass('in');
8790 this.hoverState = null;
8792 if (this.el.hasClass('fade')) {
8799 this.el.setXY([0,0]);
8800 this.el.removeClass('in');
8807 Roo.bootstrap.Popover.alignment = {
8808 'left' : ['r-l', [-10,0], 'right'],
8809 'right' : ['l-r', [10,0], 'left'],
8810 'bottom' : ['t-b', [0,10], 'top'],
8811 'top' : [ 'b-t', [0,-10], 'bottom']