4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
19 * Do not use directly - it does not do anything..
20 * @param {Object} config The config object
25 Roo.bootstrap.Component = function(config){
26 Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
32 allowDomMove : false, // to stop relocations in parent onRender...
40 initEvents : function() { },
47 // returns the parent component..
48 return Roo.ComponentMgr.get(this.parentId)
54 onRender : function(ct, position)
56 // Roo.log("Call onRender: " + this.xtype);
58 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
61 if (this.el.attr('xtype')) {
62 this.el.attr('xtypex', this.el.attr('xtype'));
63 this.el.dom.removeAttribute('xtype');
73 var cfg = Roo.apply({}, this.getAutoCreate());
76 // fill in the extra attributes
77 if (this.xattr && typeof(this.xattr) =='object') {
78 for (var i in this.xattr) {
79 cfg[i] = this.xattr[i];
84 cfg.cls += ' ' + this.cls;
86 if (this.style) { // fixme needs to support more complex style data.
87 cfg.style = this.style;
89 this.el = ct.createChild(cfg, position);
90 if(this.tabIndex !== undefined){
91 this.el.dom.setAttribute('tabIndex', this.tabIndex);
98 getChildContainer : function()
103 addxtype : function (tree, cntr) {
105 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
107 // render the element if it's not BODY.
108 if (tree.xtype != 'Body') {
110 cn = Roo.factory(tree);
112 cn.parentType = this.xtype; //??
113 cn.parentId = this.id;
115 // does the container contain child eleemnts with 'xtype' attributes.
116 // that match this xtype..
117 // note - when we render we create these as well..
118 // so we should check to see if body has xtype set.
119 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
121 var echild = Roo.get(this[cntr]()).child('*[xtype]');
124 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
125 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
127 //echild.dom.removeAttribute('xtype');
129 Roo.log("looking for " + cn.xtype);
130 Roo.log("missing child for " + this.xtype);
138 cn.render(this[cntr]());
139 // then add the element..
146 if (typeof (tree.menu) != 'undefined') {
147 tree.menu.parentType = cn.xtype;
148 tree.menu.triggerEl = cn.el;
149 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
153 if (!tree.items || !tree.items.length) {
157 var items = tree.items;
160 //Roo.log(items.length);
162 for(var i =0;i < items.length;i++) {
163 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
183 Roo.bootstrap.Body = function(config){
184 Roo.bootstrap.Body.superclass.constructor.call(this, config);
185 this.el = Roo.get(document.body);
188 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
193 onRender : function(ct, position){
196 //this.el.addClass([this.fieldClass, this.cls]);
214 * @class Roo.bootstrap.ButtonGroup
215 * @extends Roo.bootstrap.Component
216 * Bootstrap ButtonGroup class
217 * @cfg {String} size lg | sm | xs (default empty normal)
218 * @cfg {String} align vertical | justified (default none)
219 * @cfg {String} direction up | down (default down)
220 * @cfg {Boolean} toolbar false | true
221 * @cfg {Boolean} btn true | false
226 * @param {Object} config The config object
229 Roo.bootstrap.ButtonGroup = function(config){
230 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
233 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
241 getAutoCreate : function(){
247 cfg.html = this.html || cfg.html;
258 if (['vertical','justified'].indexOf(this.align)!==-1) {
259 cfg.cls = 'btn-group-' + this.align;
261 if (this.align == 'justified') {
262 console.log(this.items);
266 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
267 cfg.cls += ' btn-group-' + this.size;
270 if (this.direction == 'up') {
271 cfg.cls += ' dropup' ;
287 * @class Roo.bootstrap.Button
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Button class
290 * @cfg {String} html The button content
291 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
292 * @cfg {String} size empty | lg | sm | xs
293 * @cfg {String} tag empty | a | input | submit
294 * @cfg {String} href empty or href
295 * @cfg {Boolean} disabled false | true
296 * @cfg {Boolean} isClose false | true
297 * @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
298 * @cfg {String} badge text for badge
299 * @cfg {String} theme default (or empty) | glow
300 * @cfg {Boolean} inverse false | true
301 * @cfg {Boolean} toggle false | true
302 * @cfg {String} ontext text for on toggle state
303 * @cfg {String} offtext text for off toggle state
304 * @cfg {Boolean} defaulton true | false
307 * Create a new button
308 * @param {Object} config The config object
312 Roo.bootstrap.Button = function(config){
313 Roo.bootstrap.Button.superclass.constructor.call(this, config);
318 * The raw click event for the entire grid.
319 * @param {Roo.EventObject} e
325 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
344 getAutoCreate : function(){
352 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
353 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
358 cfg.html = this.html || cfg.html;
360 if (this.toggle===true) {
363 cls: 'slider-frame roo-button',
368 'data-off-text':'OFF',
369 cls: 'slider-button',
375 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
376 cfg.cls += ' '+this.weight;
385 cfg["aria-hidden"] = true;
387 cfg.html = "×";
393 if (this.theme==='default') {
394 cfg.cls = 'btn roo-button';
396 if (this.parentType != 'Navbar') {
397 this.weight = this.weight.length ? this.weight : 'default';
399 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
401 cfg.cls += ' btn-' + this.weight;
403 } else if (this.theme==='glow') {
406 cfg.cls = 'btn-glow roo-button';
408 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
410 cfg.cls += ' ' + this.weight;
416 this.cls += ' inverse';
421 cfg.cls += ' active';
424 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
426 //gsRoo.log(this.parentType);
427 if (this.parentType === 'Navbar') {
435 href : this.href || '#'
438 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
439 cfg.cls += ' dropdown';
444 } else if (this.menu) {
446 cfg.cls += ' dropdown test';
452 cfg.disabled = 'disabled';
456 Roo.log('changing to ul' );
458 this.glyphicon = 'caret';
461 if (this.glyphicon) {
462 cfg.html = ' ' + cfg.html;
467 cls: 'glyphicon glyphicon-' + this.glyphicon
477 cfg.cls='btn roo-button';
493 if (cfg.tag !== 'a' && this.href !== '') {
494 throw "Tag must be a to set href.";
495 } else if (this.href.length > 0) {
496 cfg.href = this.href;
501 initEvents: function() {
502 // Roo.log('init events?');
503 // Roo.log(this.el.dom);
504 if (this.el.hasClass('roo-button')) {
505 this.el.on('click', this.onClick, this);
507 this.el.select('.roo-button').on('click', this.onClick, this);
513 onClick : function(e)
515 Roo.log('button on click ');
517 this.fireEvent('click', this, e);
531 * @class Roo.bootstrap.Column
532 * @extends Roo.bootstrap.Component
533 * Bootstrap Column class
534 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
535 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
536 * @cfg {Number} md colspan out of 12 for computer-sized screens
537 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
538 * @cfg {String} html content of column.
541 * Create a new Column
542 * @param {Object} config The config object
545 Roo.bootstrap.Column = function(config){
546 Roo.bootstrap.Column.superclass.constructor.call(this, config);
549 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
558 getAutoCreate : function(){
559 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
567 ['xs','sm','md','lg'].map(function(size){
568 if (settings[size]) {
569 cfg.cls += ' col-' + size + '-' + settings[size];
572 if (this.html.length) {
573 cfg.html = this.html;
592 * @class Roo.bootstrap.Container
593 * @extends Roo.bootstrap.Component
594 * Bootstrap Container class
595 * @cfg {Boolean} jumbotron is it a jumbotron element
596 * @cfg {String} html content of element
597 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
598 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
599 * @cfg {String} header content of header (for panel)
600 * @cfg {String} footer content of footer (for panel)
601 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
604 * Create a new Container
605 * @param {Object} config The config object
608 Roo.bootstrap.Container = function(config){
609 Roo.bootstrap.Container.superclass.constructor.call(this, config);
612 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
622 getChildContainer : function() {
623 if (this.panel.length) {
624 return this.el.select('.panel-body',true).first();
631 getAutoCreate : function(){
637 if (this.jumbotron) {
638 cfg.cls = 'jumbotron';
641 cfg.cls = this.cls + '';
644 if (this.sticky.length) {
645 var bd = Roo.get(document.body);
646 if (!bd.hasClass('bootstrap-sticky')) {
647 bd.addClass('bootstrap-sticky');
648 Roo.select('html',true).setStyle('height', '100%');
651 cfg.cls += 'bootstrap-sticky-' + this.sticky;
655 if (this.well.length) {
659 cfg.cls +=' well well-' +this.well;
669 if (this.panel.length) {
670 cfg.cls += 'panel panel-' + this.panel;
672 if (this.header.length) {
675 cls : 'panel-heading',
691 if (this.footer.length) {
693 cls : 'panel-footer',
701 body.html = this.html || cfg.html;
703 if (!cfg.cls.length) {
704 cfg.cls = 'container';
721 * @class Roo.bootstrap.Img
722 * @extends Roo.bootstrap.Component
723 * Bootstrap Img class
724 * @cfg {Boolean} imgResponsive false | true
725 * @cfg {String} border rounded | circle | thumbnail
726 * @cfg {String} src image source
727 * @cfg {String} alt image alternative text
731 * @param {Object} config The config object
734 Roo.bootstrap.Img = function(config){
735 Roo.bootstrap.Img.superclass.constructor.call(this, config);
738 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
744 getAutoCreate : function(){
748 cls: 'img-responsive',
752 cfg.html = this.html || cfg.html;
754 cfg.src = this.src || cfg.src;
756 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
757 cfg.cls += ' img-' + this.border;
777 * @class Roo.bootstrap.Header
778 * @extends Roo.bootstrap.Component
779 * Bootstrap Header class
780 * @cfg {String} html content of header
781 * @cfg {Number} level (1|2|3|4|5|6) default 1
784 * Create a new Header
785 * @param {Object} config The config object
789 Roo.bootstrap.Header = function(config){
790 Roo.bootstrap.Header.superclass.constructor.call(this, config);
793 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
801 getAutoCreate : function(){
804 tag: 'h' + (1 *this.level),
805 html: this.html || 'fill in html'
823 * @class Roo.bootstrap.Menu
824 * @extends Roo.bootstrap.Component
825 * Bootstrap Menu class - container for MenuItems
826 * @cfg {String} type type of menu
830 * @param {Object} config The config object
834 Roo.bootstrap.Menu = function(config){
835 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
838 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
846 getChildContainer : function() {
850 getAutoCreate : function(){
852 //if (['right'].indexOf(this.align)!==-1) {
853 // cfg.cn[1].cls += ' pull-right'
857 cls : 'dropdown-menu'
861 if (this.type==='submenu') {
862 cfg.cls='submenu active'
867 initEvents : function() {
868 // Roo.log("ADD event");
869 // Roo.log(this.triggerEl.dom);
870 this.triggerEl.on('click', this.toggle, this);
871 this.triggerEl.addClass('dropdown-toggle');
876 //Roo.log(e.getTarget());
877 // Roo.log(this.triggerEl.dom);
878 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
881 var isActive = this.triggerEl.hasClass('open');
882 // if disabled.. ingore
884 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
885 // if mobile we use a backdrop because click events don't delegate
886 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
889 //var relatedTarget = { relatedTarget: this }
890 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
892 //if (e.isDefaultPrevented()) return;
894 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
896 // .trigger('shown.bs.dropdown', relatedTarget)
898 this.triggerEl.focus();
904 clearMenus : function()
906 //$(backdrop).remove()
907 Roo.select('.dropdown-toggle',true).each(function(aa) {
908 if (!aa.hasClass('open')) {
912 aa.removeClass('open');
913 //var parent = getParent($(this))
914 //var relatedTarget = { relatedTarget: this }
916 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
917 //if (e.isDefaultPrevented()) return
918 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
936 * @class Roo.bootstrap.MenuItem
937 * @extends Roo.bootstrap.Component
938 * Bootstrap MenuItem class
939 * @cfg {String} html the menu label
940 * @cfg {String} href the link
944 * Create a new MenuItem
945 * @param {Object} config The config object
949 Roo.bootstrap.MenuItem = function(config){
950 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
953 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
958 getAutoCreate : function(){
970 cfg.cn[0].href = this.href || cfg.cn[0].href ;
971 cfg.cn[0].html = this.html || cfg.cn[0].html ;
988 * @class Roo.bootstrap.MenuSeparator
989 * @extends Roo.bootstrap.Component
990 * Bootstrap MenuSeparator class
993 * Create a new MenuItem
994 * @param {Object} config The config object
998 Roo.bootstrap.MenuSeparator = function(config){
999 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1002 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1004 getAutoCreate : function(){
1019 <div class="modal fade">
1020 <div class="modal-dialog">
1021 <div class="modal-content">
1022 <div class="modal-header">
1023 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1024 <h4 class="modal-title">Modal title</h4>
1026 <div class="modal-body">
1027 <p>One fine body…</p>
1029 <div class="modal-footer">
1030 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1031 <button type="button" class="btn btn-primary">Save changes</button>
1033 </div><!-- /.modal-content -->
1034 </div><!-- /.modal-dialog -->
1035 </div><!-- /.modal -->
1045 * @class Roo.bootstrap.Modal
1046 * @extends Roo.bootstrap.Component
1047 * Bootstrap Modal class
1048 * @cfg {String} title Title of dialog
1049 * @cfg {Array} buttons Array of buttons or standard button set..
1052 * Create a new Modal Dialog
1053 * @param {Object} config The config object
1056 Roo.bootstrap.Modal = function(config){
1057 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1062 * The raw click event for the entire grid.
1063 * @param {Roo.EventObject} e
1069 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1071 title : 'test dialog',
1075 onRender : function(ct, position)
1077 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1079 var cfg = Roo.apply({}, this.getAutoCreate());
1082 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1084 //if (!cfg.name.length) {
1088 cfg.cls += ' ' + this.cls;
1091 cfg.style = this.style;
1093 this.el = Roo.get(document.body).createChild(cfg, position);
1095 //var type = this.el.dom.type;
1097 if(this.tabIndex !== undefined){
1098 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1103 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1104 this.maskEl.enableDisplayMode("block");
1106 //this.el.addClass("x-dlg-modal");
1110 Roo.each(this.buttons, function(bb) {
1111 b = Roo.apply({}, bb);
1112 b.xns = b.xns || Roo.bootstrap;
1113 b.xtype = b.xtype || 'Button';
1114 if (typeof(b.listeners) == 'undefined') {
1115 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1118 var btn = Roo.factory(b);
1120 btn.onRender(this.el.select('.modal-footer').first());
1128 //this.el.addClass([this.fieldClass, this.cls]);
1131 getAutoCreate : function(){
1136 html : this.html || ''
1144 cls: "modal-dialog",
1147 cls : "modal-content",
1150 cls : 'modal-header',
1159 cls : 'modal-title',
1167 cls : 'modal-footer'
1183 getChildContainer : function() {
1185 return this.el.select('.modal-body',true).first();
1188 getButtonContainer : function() {
1189 return this.el.select('.modal-footer',true).first();
1192 initEvents : function()
1194 this.el.select('.modal-header .close').on('click', this.hide, this);
1197 if (!this.rendered) {
1201 this.el.addClass('on');
1202 this.el.removeClass('fade');
1203 this.el.setStyle('display', 'block');
1204 Roo.get(document.body).addClass("x-body-masked");
1205 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1207 this.el.setStyle('zIndex', '10001');
1214 this.el.removeClass('on');
1215 this.el.addClass('fade');
1216 this.el.setStyle('display', 'none');
1218 onButtonClick: function(btn,e)
1221 this.fireEvent('btnclick', btn.name, e);
1226 Roo.apply(Roo.bootstrap.Modal, {
1228 * Button config that displays a single OK button
1237 * Button config that displays Yes and No buttons
1253 * Button config that displays OK and Cancel buttons
1268 * Button config that displays Yes, No and Cancel buttons
1295 * @class Roo.bootstrap.Navbar
1296 * @extends Roo.bootstrap.Component
1297 * Bootstrap Navbar class
1298 * @cfg {Boolean} sidebar has side bar
1299 * @cfg {Boolean} bar is a bar?
1300 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1301 * @cfg {String} brand what is brand
1302 * @cfg {Boolean} inverse is inverted color
1303 * @cfg {String} type (nav | pills | tabs)
1304 * @cfg {Boolean} arrangement stacked | justified
1305 * @cfg {String} align (left | right) alignment
1309 * Create a new Navbar
1310 * @param {Object} config The config object
1314 Roo.bootstrap.Navbar = function(config){
1315 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1318 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1330 getAutoCreate : function(){
1335 if (this.sidebar === true) {
1343 if (this.bar === true) {
1351 cls: 'navbar-header',
1356 cls: 'navbar-toggle',
1357 'data-toggle': 'collapse',
1362 html: 'Toggle navigation'
1382 cls: 'collapse navbar-collapse'
1387 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1389 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1390 cfg.cls += ' navbar-' + this.position;
1391 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1394 if (this.brand !== '') {
1398 cls: 'navbar-brand',
1407 } else if (this.bar === false) {
1410 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1420 if (['tabs','pills'].indexOf(this.type)!==-1) {
1421 cfg.cn[0].cls += ' nav-' + this.type
1423 if (this.type!=='nav') {
1424 Roo.log('nav type must be nav/tabs/pills')
1426 cfg.cn[0].cls += ' navbar-nav'
1429 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1430 cfg.cn[0].cls += ' nav-' + this.arrangement;
1433 if (this.align === 'right') {
1434 cfg.cn[0].cls += ' navbar-right';
1437 cfg.cls += ' navbar-inverse';
1445 initEvents :function ()
1447 //Roo.log(this.el.select('.navbar-toggle',true));
1448 this.el.select('.navbar-toggle',true).on('click', function() {
1449 // Roo.log('click');
1450 this.el.select('.navbar-collapse',true).toggleClass('in');
1455 getChildContainer : function()
1457 if (this.bar === true) {
1458 return this.el.select('.collapse',true).first();
1476 * @class Roo.bootstrap.NavGroup
1477 * @extends Roo.bootstrap.Component
1478 * Bootstrap NavGroup class
1479 * @cfg {String} align left | right
1480 * @cfg {Boolean} inverse false | true
1483 * Create a new nav group
1484 * @param {Object} config The config object
1487 Roo.bootstrap.NavGroup = function(config){
1488 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1491 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1497 getAutoCreate : function(){
1498 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1502 cls: 'nav navbar-nav'
1505 if (this.parent().sidebar === true) {
1508 cls: 'dashboard-menu'
1514 if (this.form === true) {
1520 if (this.align === 'right') {
1521 cfg.cls += ' navbar-right';
1523 cfg.cls += ' navbar-left';
1528 if (this.align === 'right') {
1529 cfg.cls += ' navbar-right';
1533 cfg.cls += ' navbar-inverse';
1553 * @class Roo.bootstrap.Navbar.Item
1554 * @extends Roo.bootstrap.Component
1555 * Bootstrap Navbar.Button class
1556 * @cfg {String} href link to
1557 * @cfg {String} html content of button
1558 * @cfg {String} badge text inside badge
1559 * @cfg {String} glyphicon name of glyphicon
1562 * Create a new Navbar Button
1563 * @param {Object} config The config object
1565 Roo.bootstrap.Navbar.Item = function(config){
1566 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1569 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1577 getAutoCreate : function(){
1579 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1581 if (this.parent().parent().sidebar === true) {
1594 cfg.cn[0].html = this.html;
1598 this.cls += ' active';
1602 cfg.cn[0].cls += ' dropdown-toggle';
1603 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1607 cfg.cn[0].tag = 'a',
1608 cfg.cn[0].href = this.href;
1611 if (this.glyphicon) {
1612 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1628 if (this.glyphicon) {
1629 if(cfg.html){cfg.html = ' ' + this.html};
1633 cls: 'glyphicon glyphicon-' + this.glyphicon
1638 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1642 cfg.cn[0].html += " <span class='caret'></span>";
1643 //}else if (!this.href) {
1644 // cfg.cn[0].tag='p';
1645 // cfg.cn[0].cls='navbar-text';
1648 cfg.cn[0].href=this.href||'#';
1649 cfg.cn[0].html=this.html;
1652 if (this.badge !== '') {
1655 cfg.cn[0].html + ' ',
1668 initEvents: function() {
1669 // Roo.log('init events?');
1670 // Roo.log(this.el.dom);
1671 this.el.select('a',true).on('click',
1673 this.fireEvent('click', this);
1690 * @class Roo.bootstrap.Row
1691 * @extends Roo.bootstrap.Component
1692 * Bootstrap Row class (contains columns...)
1696 * @param {Object} config The config object
1699 Roo.bootstrap.Row = function(config){
1700 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1703 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1705 getAutoCreate : function(){
1724 * @class Roo.bootstrap.Element
1725 * @extends Roo.bootstrap.Component
1726 * Bootstrap Element class
1727 * @cfg {String} html contents of the element
1728 * @cfg {String} tag tag of the element
1729 * @cfg {String} cls class of the element
1732 * Create a new Element
1733 * @param {Object} config The config object
1736 Roo.bootstrap.Element = function(config){
1737 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1740 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1747 getAutoCreate : function(){
1770 * @class Roo.bootstrap.Pagination
1771 * @extends Roo.bootstrap.Component
1772 * Bootstrap Pagination class
1773 * @cfg {String} size xs | sm | md | lg
1774 * @cfg {Boolean} inverse false | true
1775 * @cfg {Number} from pagination starting number
1776 * @cfg {Number} to pagination ending number
1777 * @cfg {String} align empty or left | right
1778 * @cfg {Number} active active page number
1781 * Create a new Pagination
1782 * @param {Object} config The config object
1785 Roo.bootstrap.Pagination = function(config){
1786 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1789 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1799 getAutoCreate : function(){
1806 cfg.cls += ' inverse';
1824 var from=this.from>0?this.from:1;
1825 var to=this.to-from<=10?this.to:from+10;
1826 var active=this.active>=from&&this.active<=to?this.active:null;
1827 for (var i=from;i<=to;i++) {
1831 cls: active===i?'active':'',
1872 * @class Roo.bootstrap.Slider
1873 * @extends Roo.bootstrap.Component
1874 * Bootstrap Slider class
1877 * Create a new Slider
1878 * @param {Object} config The config object
1881 Roo.bootstrap.Slider = function(config){
1882 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1885 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
1887 getAutoCreate : function(){
1891 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1895 cls: 'ui-slider-handle ui-state-default ui-corner-all'
1913 * @class Roo.bootstrap.Table
1914 * @extends Roo.bootstrap.Component
1915 * Bootstrap Table class
1918 * Create a new Table
1919 * @param {Object} config The config object
1922 Roo.bootstrap.Table = function(config){
1923 Roo.bootstrap.Table.superclass.constructor.call(this, config);
1926 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
1931 getAutoCreate : function(){
1932 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
1964 * @class Roo.bootstrap.TableCell
1965 * @extends Roo.bootstrap.Component
1966 * Bootstrap TableCell class
1969 * Create a new TableCell
1970 * @param {Object} config The config object
1973 Roo.bootstrap.TableCell = function(config){
1974 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
1977 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
1979 getAutoCreate : function(){
1980 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2007 * @class Roo.bootstrap.TableRow
2008 * @extends Roo.bootstrap.Component
2009 * Bootstrap TableRow class
2012 * Create a new TableRow
2013 * @param {Object} config The config object
2016 Roo.bootstrap.TableRow = function(config){
2017 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2020 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2022 getAutoCreate : function(){
2023 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2038 * Ext JS Library 1.1.1
2039 * Copyright(c) 2006-2007, Ext JS, LLC.
2041 * Originally Released Under LGPL - original licence link has changed is not relivant.
2044 * <script type="text/javascript">
2047 // as we use this in bootstrap.
2048 Roo.namespace('Roo.form');
2050 * @class Roo.form.Action
2051 * Internal Class used to handle form actions
2053 * @param {Roo.form.BasicForm} el The form element or its id
2054 * @param {Object} config Configuration options
2059 // define the action interface
2060 Roo.form.Action = function(form, options){
2062 this.options = options || {};
2065 * Client Validation Failed
2068 Roo.form.Action.CLIENT_INVALID = 'client';
2070 * Server Validation Failed
2073 Roo.form.Action.SERVER_INVALID = 'server';
2075 * Connect to Server Failed
2078 Roo.form.Action.CONNECT_FAILURE = 'connect';
2080 * Reading Data from Server Failed
2083 Roo.form.Action.LOAD_FAILURE = 'load';
2085 Roo.form.Action.prototype = {
2087 failureType : undefined,
2088 response : undefined,
2092 run : function(options){
2097 success : function(response){
2102 handleResponse : function(response){
2106 // default connection failure
2107 failure : function(response){
2109 this.response = response;
2110 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2111 this.form.afterAction(this, false);
2114 processResponse : function(response){
2115 this.response = response;
2116 if(!response.responseText){
2119 this.result = this.handleResponse(response);
2123 // utility functions used internally
2124 getUrl : function(appendParams){
2125 var url = this.options.url || this.form.url || this.form.el.dom.action;
2127 var p = this.getParams();
2129 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2135 getMethod : function(){
2136 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2139 getParams : function(){
2140 var bp = this.form.baseParams;
2141 var p = this.options.params;
2143 if(typeof p == "object"){
2144 p = Roo.urlEncode(Roo.applyIf(p, bp));
2145 }else if(typeof p == 'string' && bp){
2146 p += '&' + Roo.urlEncode(bp);
2149 p = Roo.urlEncode(bp);
2154 createCallback : function(){
2156 success: this.success,
2157 failure: this.failure,
2159 timeout: (this.form.timeout*1000),
2160 upload: this.form.fileUpload ? this.success : undefined
2165 Roo.form.Action.Submit = function(form, options){
2166 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2169 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2172 haveProgress : false,
2173 uploadComplete : false,
2175 // uploadProgress indicator.
2176 uploadProgress : function()
2178 if (!this.form.progressUrl) {
2182 if (!this.haveProgress) {
2183 Roo.MessageBox.progress("Uploading", "Uploading");
2185 if (this.uploadComplete) {
2186 Roo.MessageBox.hide();
2190 this.haveProgress = true;
2192 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2194 var c = new Roo.data.Connection();
2196 url : this.form.progressUrl,
2201 success : function(req){
2202 //console.log(data);
2206 rdata = Roo.decode(req.responseText)
2208 Roo.log("Invalid data from server..");
2212 if (!rdata || !rdata.success) {
2214 Roo.MessageBox.alert(Roo.encode(rdata));
2217 var data = rdata.data;
2219 if (this.uploadComplete) {
2220 Roo.MessageBox.hide();
2225 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2226 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2229 this.uploadProgress.defer(2000,this);
2232 failure: function(data) {
2233 Roo.log('progress url failed ');
2244 // run get Values on the form, so it syncs any secondary forms.
2245 this.form.getValues();
2247 var o = this.options;
2248 var method = this.getMethod();
2249 var isPost = method == 'POST';
2250 if(o.clientValidation === false || this.form.isValid()){
2252 if (this.form.progressUrl) {
2253 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2254 (new Date() * 1) + '' + Math.random());
2259 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2260 form:this.form.el.dom,
2261 url:this.getUrl(!isPost),
2263 params:isPost ? this.getParams() : null,
2264 isUpload: this.form.fileUpload
2267 this.uploadProgress();
2269 }else if (o.clientValidation !== false){ // client validation failed
2270 this.failureType = Roo.form.Action.CLIENT_INVALID;
2271 this.form.afterAction(this, false);
2275 success : function(response)
2277 this.uploadComplete= true;
2278 if (this.haveProgress) {
2279 Roo.MessageBox.hide();
2283 var result = this.processResponse(response);
2284 if(result === true || result.success){
2285 this.form.afterAction(this, true);
2289 this.form.markInvalid(result.errors);
2290 this.failureType = Roo.form.Action.SERVER_INVALID;
2292 this.form.afterAction(this, false);
2294 failure : function(response)
2296 this.uploadComplete= true;
2297 if (this.haveProgress) {
2298 Roo.MessageBox.hide();
2301 this.response = response;
2302 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2303 this.form.afterAction(this, false);
2306 handleResponse : function(response){
2307 if(this.form.errorReader){
2308 var rs = this.form.errorReader.read(response);
2311 for(var i = 0, len = rs.records.length; i < len; i++) {
2312 var r = rs.records[i];
2316 if(errors.length < 1){
2320 success : rs.success,
2326 ret = Roo.decode(response.responseText);
2330 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2340 Roo.form.Action.Load = function(form, options){
2341 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2342 this.reader = this.form.reader;
2345 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2350 Roo.Ajax.request(Roo.apply(
2351 this.createCallback(), {
2352 method:this.getMethod(),
2353 url:this.getUrl(false),
2354 params:this.getParams()
2358 success : function(response){
2360 var result = this.processResponse(response);
2361 if(result === true || !result.success || !result.data){
2362 this.failureType = Roo.form.Action.LOAD_FAILURE;
2363 this.form.afterAction(this, false);
2366 this.form.clearInvalid();
2367 this.form.setValues(result.data);
2368 this.form.afterAction(this, true);
2371 handleResponse : function(response){
2372 if(this.form.reader){
2373 var rs = this.form.reader.read(response);
2374 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2376 success : rs.success,
2380 return Roo.decode(response.responseText);
2384 Roo.form.Action.ACTION_TYPES = {
2385 'load' : Roo.form.Action.Load,
2386 'submit' : Roo.form.Action.Submit
2395 * @class Roo.bootstrap.Form
2396 * @extends Roo.bootstrap.Component
2397 * Bootstrap Form class
2398 * @cfg {String} method GET | POST (default POST)
2399 * @cfg {String} labelAlign top | left (default top)
2400 * @cfg {String} align left | right - for navbars
2405 * @param {Object} config The config object
2409 Roo.bootstrap.Form = function(config){
2410 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2413 * @event clientvalidation
2414 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2415 * @param {Form} this
2416 * @param {Boolean} valid true if the form has passed client-side validation
2418 clientvalidation: true,
2420 * @event beforeaction
2421 * Fires before any action is performed. Return false to cancel the action.
2422 * @param {Form} this
2423 * @param {Action} action The action to be performed
2427 * @event actionfailed
2428 * Fires when an action fails.
2429 * @param {Form} this
2430 * @param {Action} action The action that failed
2432 actionfailed : true,
2434 * @event actioncomplete
2435 * Fires when an action is completed.
2436 * @param {Form} this
2437 * @param {Action} action The action that completed
2439 actioncomplete : true
2444 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2447 * @cfg {String} method
2448 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2453 * The URL to use for form actions if one isn't supplied in the action options.
2456 * @cfg {Boolean} fileUpload
2457 * Set to true if this form is a file upload.
2461 * @cfg {Object} baseParams
2462 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2466 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2470 * @cfg {Sting} align (left|right) for navbar forms
2475 activeAction : null,
2478 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2479 * element by passing it or its id or mask the form itself by passing in true.
2482 waitMsgTarget : false,
2487 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2488 * element by passing it or its id or mask the form itself by passing in true.
2492 getAutoCreate : function(){
2496 method : this.method || 'POST',
2497 id : this.id || Roo.id(),
2500 if (this.parent().xtype.match(/^Nav/)) {
2501 cfg.cls = 'navbar-form navbar-' + this.align;
2505 if (this.labelAlign == 'left' ) {
2506 cfg.cls += ' form-horizontal';
2512 initEvents : function()
2514 this.el.on('submit', this.onSubmit, this);
2519 onSubmit : function(e){
2524 * Returns true if client-side validation on the form is successful.
2527 isValid : function(){
2528 var items = this.getItems();
2530 items.each(function(f){
2539 * Returns true if any fields in this form have changed since their original load.
2542 isDirty : function(){
2544 var items = this.getItems();
2545 items.each(function(f){
2555 * Performs a predefined action (submit or load) or custom actions you define on this form.
2556 * @param {String} actionName The name of the action type
2557 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2558 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2559 * accept other config options):
2561 Property Type Description
2562 ---------------- --------------- ----------------------------------------------------------------------------------
2563 url String The url for the action (defaults to the form's url)
2564 method String The form method to use (defaults to the form's method, or POST if not defined)
2565 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2566 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2567 validate the form on the client (defaults to false)
2569 * @return {BasicForm} this
2571 doAction : function(action, options){
2572 if(typeof action == 'string'){
2573 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2575 if(this.fireEvent('beforeaction', this, action) !== false){
2576 this.beforeAction(action);
2577 action.run.defer(100, action);
2583 beforeAction : function(action){
2584 var o = action.options;
2586 // not really supported yet.. ??
2588 //if(this.waitMsgTarget === true){
2589 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2590 //}else if(this.waitMsgTarget){
2591 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2592 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2594 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2600 afterAction : function(action, success){
2601 this.activeAction = null;
2602 var o = action.options;
2604 //if(this.waitMsgTarget === true){
2606 //}else if(this.waitMsgTarget){
2607 // this.waitMsgTarget.unmask();
2609 // Roo.MessageBox.updateProgress(1);
2610 // Roo.MessageBox.hide();
2617 Roo.callback(o.success, o.scope, [this, action]);
2618 this.fireEvent('actioncomplete', this, action);
2622 // failure condition..
2623 // we have a scenario where updates need confirming.
2624 // eg. if a locking scenario exists..
2625 // we look for { errors : { needs_confirm : true }} in the response.
2627 (typeof(action.result) != 'undefined') &&
2628 (typeof(action.result.errors) != 'undefined') &&
2629 (typeof(action.result.errors.needs_confirm) != 'undefined')
2632 Roo.log("not supported yet");
2635 Roo.MessageBox.confirm(
2636 "Change requires confirmation",
2637 action.result.errorMsg,
2642 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2652 Roo.callback(o.failure, o.scope, [this, action]);
2653 // show an error message if no failed handler is set..
2654 if (!this.hasListener('actionfailed')) {
2655 Roo.log("need to add dialog support");
2657 Roo.MessageBox.alert("Error",
2658 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2659 action.result.errorMsg :
2660 "Saving Failed, please check your entries or try again"
2665 this.fireEvent('actionfailed', this, action);
2670 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2671 * @param {String} id The value to search for
2674 findField : function(id){
2675 var items = this.getItems();
2676 var field = items.get(id);
2678 items.each(function(f){
2679 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2686 return field || null;
2689 * Mark fields in this form invalid in bulk.
2690 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2691 * @return {BasicForm} this
2693 markInvalid : function(errors){
2694 if(errors instanceof Array){
2695 for(var i = 0, len = errors.length; i < len; i++){
2696 var fieldError = errors[i];
2697 var f = this.findField(fieldError.id);
2699 f.markInvalid(fieldError.msg);
2705 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2706 field.markInvalid(errors[id]);
2710 //Roo.each(this.childForms || [], function (f) {
2711 // f.markInvalid(errors);
2718 * Set values for fields in this form in bulk.
2719 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2720 * @return {BasicForm} this
2722 setValues : function(values){
2723 if(values instanceof Array){ // array of objects
2724 for(var i = 0, len = values.length; i < len; i++){
2726 var f = this.findField(v.id);
2728 f.setValue(v.value);
2729 if(this.trackResetOnLoad){
2730 f.originalValue = f.getValue();
2734 }else{ // object hash
2737 if(typeof values[id] != 'function' && (field = this.findField(id))){
2739 if (field.setFromData &&
2741 field.displayField &&
2742 // combos' with local stores can
2743 // be queried via setValue()
2744 // to set their value..
2745 (field.store && !field.store.isLocal)
2749 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2750 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2751 field.setFromData(sd);
2754 field.setValue(values[id]);
2758 if(this.trackResetOnLoad){
2759 field.originalValue = field.getValue();
2765 //Roo.each(this.childForms || [], function (f) {
2766 // f.setValues(values);
2773 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2774 * they are returned as an array.
2775 * @param {Boolean} asString
2778 getValues : function(asString){
2779 //if (this.childForms) {
2780 // copy values from the child forms
2781 // Roo.each(this.childForms, function (f) {
2782 // this.setValues(f.getValues());
2788 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2789 if(asString === true){
2792 return Roo.urlDecode(fs);
2796 * Returns the fields in this form as an object with key/value pairs.
2797 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2800 getFieldValues : function(with_hidden)
2802 var items = this.getItems();
2804 items.each(function(f){
2808 var v = f.getValue();
2809 if (f.inputType =='radio') {
2810 if (typeof(ret[f.getName()]) == 'undefined') {
2811 ret[f.getName()] = ''; // empty..
2814 if (!f.el.dom.checked) {
2822 // not sure if this supported any more..
2823 if ((typeof(v) == 'object') && f.getRawValue) {
2824 v = f.getRawValue() ; // dates..
2826 // combo boxes where name != hiddenName...
2827 if (f.name != f.getName()) {
2828 ret[f.name] = f.getRawValue();
2830 ret[f.getName()] = v;
2837 * Clears all invalid messages in this form.
2838 * @return {BasicForm} this
2840 clearInvalid : function(){
2841 var items = this.getItems();
2843 items.each(function(f){
2854 * @return {BasicForm} this
2857 var items = this.getItems();
2858 items.each(function(f){
2862 Roo.each(this.childForms || [], function (f) {
2869 getItems : function()
2871 var r=new Roo.util.MixedCollection(false, function(o){
2872 return o.id || (o.id = Roo.id());
2874 var iter = function(el) {
2881 Roo.each(el.items,function(e) {
2900 * Ext JS Library 1.1.1
2901 * Copyright(c) 2006-2007, Ext JS, LLC.
2903 * Originally Released Under LGPL - original licence link has changed is not relivant.
2906 * <script type="text/javascript">
2909 * @class Roo.form.VTypes
2910 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2913 Roo.form.VTypes = function(){
2914 // closure these in so they are only created once.
2915 var alpha = /^[a-zA-Z_]+$/;
2916 var alphanum = /^[a-zA-Z0-9_]+$/;
2917 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2918 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2920 // All these messages and functions are configurable
2923 * The function used to validate email addresses
2924 * @param {String} value The email address
2926 'email' : function(v){
2927 return email.test(v);
2930 * The error text to display when the email validation function returns false
2933 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2935 * The keystroke filter mask to be applied on email input
2938 'emailMask' : /[a-z0-9_\.\-@]/i,
2941 * The function used to validate URLs
2942 * @param {String} value The URL
2944 'url' : function(v){
2948 * The error text to display when the url validation function returns false
2951 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
2954 * The function used to validate alpha values
2955 * @param {String} value The value
2957 'alpha' : function(v){
2958 return alpha.test(v);
2961 * The error text to display when the alpha validation function returns false
2964 'alphaText' : 'This field should only contain letters and _',
2966 * The keystroke filter mask to be applied on alpha input
2969 'alphaMask' : /[a-z_]/i,
2972 * The function used to validate alphanumeric values
2973 * @param {String} value The value
2975 'alphanum' : function(v){
2976 return alphanum.test(v);
2979 * The error text to display when the alphanumeric validation function returns false
2982 'alphanumText' : 'This field should only contain letters, numbers and _',
2984 * The keystroke filter mask to be applied on alphanumeric input
2987 'alphanumMask' : /[a-z0-9_]/i
2997 * @class Roo.bootstrap.Input
2998 * @extends Roo.bootstrap.Component
2999 * Bootstrap Input class
3000 * @cfg {Boolean} disabled is it disabled
3001 * @cfg {String} fieldLabel - the label associated
3002 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3003 * @cfg {String} name name of the input
3004 * @cfg {string} fieldLabel - the label associated
3005 * @cfg {string} inputType - input / file submit ...
3006 * @cfg {string} placeholder - placeholder to put in text.
3007 * @cfg {string} before - input group add on before
3008 * @cfg {string} after - input group add on after
3009 * @cfg {string} size - (lg|sm) or leave empty..
3010 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3011 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3012 * @cfg {Number} md colspan out of 12 for computer-sized screens
3013 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3017 * Create a new Input
3018 * @param {Object} config The config object
3021 Roo.bootstrap.Input = function(config){
3022 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3027 * Fires when this field receives input focus.
3028 * @param {Roo.form.Field} this
3033 * Fires when this field loses input focus.
3034 * @param {Roo.form.Field} this
3039 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3040 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3041 * @param {Roo.form.Field} this
3042 * @param {Roo.EventObject} e The event object
3047 * Fires just before the field blurs if the field value has changed.
3048 * @param {Roo.form.Field} this
3049 * @param {Mixed} newValue The new value
3050 * @param {Mixed} oldValue The original value
3055 * Fires after the field has been marked as invalid.
3056 * @param {Roo.form.Field} this
3057 * @param {String} msg The validation message
3062 * Fires after the field has been validated with no errors.
3063 * @param {Roo.form.Field} this
3068 * Fires after the key up
3069 * @param {Roo.form.Field} this
3070 * @param {Roo.EventObject} e The event Object
3076 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3078 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3079 automatic validation (defaults to "keyup").
3081 validationEvent : "keyup",
3083 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3085 validateOnBlur : true,
3087 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3089 validationDelay : 250,
3091 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3093 focusClass : "x-form-focus", // not needed???
3097 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3099 invalidClass : "has-error",
3102 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3104 selectOnFocus : false,
3107 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3111 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3116 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3118 disableKeyFilter : false,
3121 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3125 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3129 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3131 blankText : "This field is required",
3134 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3138 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3140 maxLength : Number.MAX_VALUE,
3142 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3144 minLengthText : "The minimum length for this field is {0}",
3146 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3148 maxLengthText : "The maximum length for this field is {0}",
3152 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3153 * If available, this function will be called only after the basic validators all return true, and will be passed the
3154 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3158 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3159 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3160 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3164 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3183 getAutoCreate : function(){
3185 var parent = this.parent();
3187 var align = parent.labelAlign;
3192 cls: 'form-group' //input-group
3198 type : this.inputType,
3199 cls : 'form-control',
3200 placeholder : this.placeholder || ''
3204 input.name = this.name;
3207 input.cls += ' input-' + this.size;
3210 ['xs','sm','md','lg'].map(function(size){
3211 if (settings[size]) {
3212 cfg.cls += ' col-' + size + '-' + settings[size];
3216 var inputblock = input;
3218 if (this.before || this.after) {
3221 cls : 'input-group',
3225 inputblock.cn.push({
3227 cls : 'input-group-addon',
3231 inputblock.cn.push(input);
3233 inputblock.cn.push({
3235 cls : 'input-group-addon',
3243 Roo.log(this.fieldLabel.length);
3245 if (align ==='left' && this.fieldLabel.length) {
3246 Roo.log("left and has label");
3252 cls : 'col-sm-2 control-label',
3253 html : this.fieldLabel
3264 } else if ( this.fieldLabel.length) {
3270 //cls : 'input-group-addon',
3271 html : this.fieldLabel
3281 Roo.log(" no label && no align");
3294 if (this.disabled) {
3295 input.disabled=true;
3301 * return the real input element.
3303 inputEl: function ()
3305 return this.el.select('input.form-control',true).first();
3307 setDisabled : function(v)
3309 var i = this.inputEl().dom;
3311 i.removeAttribute('disabled');
3315 i.setAttribute('disabled','true');
3317 initEvents : function()
3320 this.inputEl().on("keydown" , this.fireKey, this);
3321 this.inputEl().on("focus", this.onFocus, this);
3322 this.inputEl().on("blur", this.onBlur, this);
3323 this.inputEl().relayEvent('keyup', this);
3325 // reference to original value for reset
3326 this.originalValue = this.getValue();
3327 //Roo.form.TextField.superclass.initEvents.call(this);
3328 if(this.validationEvent == 'keyup'){
3329 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3330 this.inputEl().on('keyup', this.filterValidation, this);
3332 else if(this.validationEvent !== false){
3333 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3336 if(this.selectOnFocus){
3337 this.on("focus", this.preFocus, this);
3340 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3341 this.inputEl().on("keypress", this.filterKeys, this);
3344 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3345 this.el.on("click", this.autoSize, this);
3348 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3349 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3353 filterValidation : function(e){
3354 if(!e.isNavKeyPress()){
3355 this.validationTask.delay(this.validationDelay);
3359 * Validates the field value
3360 * @return {Boolean} True if the value is valid, else false
3362 validate : function(){
3363 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3364 if(this.disabled || this.validateValue(this.getRawValue())){
3365 this.clearInvalid();
3373 * Validates a value according to the field's validation rules and marks the field as invalid
3374 * if the validation fails
3375 * @param {Mixed} value The value to validate
3376 * @return {Boolean} True if the value is valid, else false
3378 validateValue : function(value){
3379 if(value.length < 1) { // if it's blank
3380 if(this.allowBlank){
3381 this.clearInvalid();
3384 this.markInvalid(this.blankText);
3388 if(value.length < this.minLength){
3389 this.markInvalid(String.format(this.minLengthText, this.minLength));
3392 if(value.length > this.maxLength){
3393 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3397 var vt = Roo.form.VTypes;
3398 if(!vt[this.vtype](value, this)){
3399 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3403 if(typeof this.validator == "function"){
3404 var msg = this.validator(value);
3406 this.markInvalid(msg);
3410 if(this.regex && !this.regex.test(value)){
3411 this.markInvalid(this.regexText);
3420 fireKey : function(e){
3421 //Roo.log('field ' + e.getKey());
3422 if(e.isNavKeyPress()){
3423 this.fireEvent("specialkey", this, e);
3426 focus : function (selectText){
3428 this.inputEl().focus();
3429 if(selectText === true){
3430 this.inputEl().dom.select();
3436 onFocus : function(){
3437 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3438 // this.el.addClass(this.focusClass);
3441 this.hasFocus = true;
3442 this.startValue = this.getValue();
3443 this.fireEvent("focus", this);
3447 beforeBlur : Roo.emptyFn,
3451 onBlur : function(){
3453 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3454 //this.el.removeClass(this.focusClass);
3456 this.hasFocus = false;
3457 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3460 var v = this.getValue();
3461 if(String(v) !== String(this.startValue)){
3462 this.fireEvent('change', this, v, this.startValue);
3464 this.fireEvent("blur", this);
3468 * Resets the current field value to the originally loaded value and clears any validation messages
3471 this.setValue(this.originalValue);
3472 this.clearInvalid();
3475 * Returns the name of the field
3476 * @return {Mixed} name The name field
3478 getName: function(){
3482 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3483 * @return {Mixed} value The field value
3485 getValue : function(){
3486 var v = this.inputEl().getValue();
3490 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3491 * @return {Mixed} value The field value
3493 getRawValue : function(){
3494 var v = this.inputEl().getValue();
3499 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3500 * @param {Mixed} value The value to set
3502 setValue : function(v){
3505 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3511 processValue : function(value){
3512 if(this.stripCharsRe){
3513 var newValue = value.replace(this.stripCharsRe, '');
3514 if(newValue !== value){
3515 this.setRawValue(newValue);
3522 preFocus : function(){
3524 if(this.selectOnFocus){
3525 this.inputEl().dom.select();
3528 filterKeys : function(e){
3530 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3533 var c = e.getCharCode(), cc = String.fromCharCode(c);
3534 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3537 if(!this.maskRe.test(cc)){
3542 * Clear any invalid styles/messages for this field
3544 clearInvalid : function(){
3546 if(!this.el || this.preventMark){ // not rendered
3549 this.el.removeClass(this.invalidClass);
3551 switch(this.msgTarget){
3553 this.el.dom.qtip = '';
3556 this.el.dom.title = '';
3560 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3565 this.errorIcon.dom.qtip = '';
3566 this.errorIcon.hide();
3567 this.un('resize', this.alignErrorIcon, this);
3571 var t = Roo.getDom(this.msgTarget);
3573 t.style.display = 'none';
3577 this.fireEvent('valid', this);
3580 * Mark this field as invalid
3581 * @param {String} msg The validation message
3583 markInvalid : function(msg){
3584 if(!this.el || this.preventMark){ // not rendered
3587 this.el.addClass(this.invalidClass);
3589 msg = msg || this.invalidText;
3590 switch(this.msgTarget){
3592 this.el.dom.qtip = msg;
3593 this.el.dom.qclass = 'x-form-invalid-tip';
3594 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3595 Roo.QuickTips.enable();
3599 this.el.dom.title = msg;
3603 var elp = this.el.findParent('.x-form-element', 5, true);
3604 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3605 this.errorEl.setWidth(elp.getWidth(true)-20);
3607 this.errorEl.update(msg);
3608 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3611 if(!this.errorIcon){
3612 var elp = this.el.findParent('.x-form-element', 5, true);
3613 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3615 this.alignErrorIcon();
3616 this.errorIcon.dom.qtip = msg;
3617 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3618 this.errorIcon.show();
3619 this.on('resize', this.alignErrorIcon, this);
3622 var t = Roo.getDom(this.msgTarget);
3624 t.style.display = this.msgDisplay;
3628 this.fireEvent('invalid', this, msg);
3631 SafariOnKeyDown : function(event)
3633 // this is a workaround for a password hang bug on chrome/ webkit.
3635 var isSelectAll = false;
3637 if(this.inputEl().dom.selectionEnd > 0){
3638 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3640 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3641 event.preventDefault();
3646 if(isSelectAll){ // backspace and delete key
3648 event.preventDefault();
3649 // this is very hacky as keydown always get's upper case.
3651 var cc = String.fromCharCode(event.getCharCode());
3652 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3664 * trigger field - base class for combo..
3669 * @class Roo.bootstrap.TriggerField
3670 * @extends Roo.bootstrap.Input
3671 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3672 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3673 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3674 * for which you can provide a custom implementation. For example:
3676 var trigger = new Roo.bootstrap.TriggerField();
3677 trigger.onTriggerClick = myTriggerFn;
3678 trigger.applyTo('my-field');
3681 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3682 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3683 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3684 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3686 * Create a new TriggerField.
3687 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3688 * to the base TextField)
3690 Roo.bootstrap.TriggerField = function(config){
3691 this.mimicing = false;
3692 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3695 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3697 * @cfg {String} triggerClass A CSS class to apply to the trigger
3700 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3704 /** @cfg {Boolean} grow @hide */
3705 /** @cfg {Number} growMin @hide */
3706 /** @cfg {Number} growMax @hide */
3712 autoSize: Roo.emptyFn,
3719 actionMode : 'wrap',
3723 getAutoCreate : function(){
3725 var parent = this.parent();
3727 var align = parent.labelAlign;
3732 cls: 'form-group' //input-group
3739 type : this.inputType,
3740 cls : 'form-control',
3741 autocomplete: 'off',
3742 placeholder : this.placeholder || ''
3746 input.name = this.name;
3749 input.cls += ' input-' + this.size;
3752 cls: 'combobox-container input-group',
3757 cls: 'form-hidden-field'
3762 cls : 'typeahead typeahead-long dropdown-menu',
3763 style : 'display:none'
3767 cls : 'input-group-addon btn dropdown-toggle',
3775 cls: 'combobox-clear',
3792 if (align ==='left' && this.fieldLabel.length) {
3796 Roo.log("left and has label");
3802 cls : 'col-sm-2 control-label',
3803 html : this.fieldLabel
3814 } else if ( this.fieldLabel.length) {
3820 //cls : 'input-group-addon',
3821 html : this.fieldLabel
3831 Roo.log(" no label && no align");
3838 ['xs','sm','md','lg'].map(function(size){
3839 if (settings[size]) {
3840 cfg.cls += ' col-' + size + '-' + settings[size];
3846 if (this.disabled) {
3847 input.disabled=true;
3856 onResize : function(w, h){
3857 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3858 if(typeof w == 'number'){
3859 var x = w - this.trigger.getWidth();
3860 this.inputEl().setWidth(this.adjustWidth('input', x));
3861 this.trigger.setStyle('left', x+'px');
3866 adjustSize : Roo.BoxComponent.prototype.adjustSize,
3869 getResizeEl : function(){
3870 return this.inputEl();
3874 getPositionEl : function(){
3875 return this.inputEl();
3879 alignErrorIcon : function(){
3880 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3884 initEvents : function(){
3886 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3888 this.trigger = this.el.select('span.dropdown-toggle',true).first();
3889 if(this.hideTrigger){
3890 this.trigger.setDisplayed(false);
3892 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3893 //this.trigger.addClassOnOver('x-form-trigger-over');
3894 //this.trigger.addClassOnClick('x-form-trigger-click');
3897 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3902 initTrigger : function(){
3907 onDestroy : function(){
3909 this.trigger.removeAllListeners();
3910 // this.trigger.remove();
3913 // this.wrap.remove();
3915 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
3919 onFocus : function(){
3920 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
3923 this.wrap.addClass('x-trigger-wrap-focus');
3924 this.mimicing = true;
3925 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
3926 if(this.monitorTab){
3927 this.el.on("keydown", this.checkTab, this);
3934 checkTab : function(e){
3935 if(e.getKey() == e.TAB){
3941 onBlur : function(){
3946 mimicBlur : function(e, t){
3948 if(!this.wrap.contains(t) && this.validateBlur()){
3955 triggerBlur : function(){
3956 this.mimicing = false;
3957 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
3958 if(this.monitorTab){
3959 this.el.un("keydown", this.checkTab, this);
3961 //this.wrap.removeClass('x-trigger-wrap-focus');
3962 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
3966 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
3967 validateBlur : function(e, t){
3972 onDisable : function(){
3973 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
3975 // this.wrap.addClass('x-item-disabled');
3980 onEnable : function(){
3981 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
3983 // this.el.removeClass('x-item-disabled');
3988 onShow : function(){
3989 var ae = this.getActionEl();
3992 ae.dom.style.display = '';
3993 ae.dom.style.visibility = 'visible';
3999 onHide : function(){
4000 var ae = this.getActionEl();
4001 ae.dom.style.display = 'none';
4005 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4006 * by an implementing function.
4008 * @param {EventObject} e
4010 onTriggerClick : Roo.emptyFn
4014 * Ext JS Library 1.1.1
4015 * Copyright(c) 2006-2007, Ext JS, LLC.
4017 * Originally Released Under LGPL - original licence link has changed is not relivant.
4020 * <script type="text/javascript">
4025 * @class Roo.data.SortTypes
4027 * Defines the default sorting (casting?) comparison functions used when sorting data.
4029 Roo.data.SortTypes = {
4031 * Default sort that does nothing
4032 * @param {Mixed} s The value being converted
4033 * @return {Mixed} The comparison value
4040 * The regular expression used to strip tags
4044 stripTagsRE : /<\/?[^>]+>/gi,
4047 * Strips all HTML tags to sort on text only
4048 * @param {Mixed} s The value being converted
4049 * @return {String} The comparison value
4051 asText : function(s){
4052 return String(s).replace(this.stripTagsRE, "");
4056 * Strips all HTML tags to sort on text only - Case insensitive
4057 * @param {Mixed} s The value being converted
4058 * @return {String} The comparison value
4060 asUCText : function(s){
4061 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4065 * Case insensitive string
4066 * @param {Mixed} s The value being converted
4067 * @return {String} The comparison value
4069 asUCString : function(s) {
4070 return String(s).toUpperCase();
4075 * @param {Mixed} s The value being converted
4076 * @return {Number} The comparison value
4078 asDate : function(s) {
4082 if(s instanceof Date){
4085 return Date.parse(String(s));
4090 * @param {Mixed} s The value being converted
4091 * @return {Float} The comparison value
4093 asFloat : function(s) {
4094 var val = parseFloat(String(s).replace(/,/g, ""));
4095 if(isNaN(val)) val = 0;
4101 * @param {Mixed} s The value being converted
4102 * @return {Number} The comparison value
4104 asInt : function(s) {
4105 var val = parseInt(String(s).replace(/,/g, ""));
4106 if(isNaN(val)) val = 0;
4111 * Ext JS Library 1.1.1
4112 * Copyright(c) 2006-2007, Ext JS, LLC.
4114 * Originally Released Under LGPL - original licence link has changed is not relivant.
4117 * <script type="text/javascript">
4121 * @class Roo.data.Record
4122 * Instances of this class encapsulate both record <em>definition</em> information, and record
4123 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4124 * to access Records cached in an {@link Roo.data.Store} object.<br>
4126 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4127 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4130 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4132 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4133 * {@link #create}. The parameters are the same.
4134 * @param {Array} data An associative Array of data values keyed by the field name.
4135 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4136 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4137 * not specified an integer id is generated.
4139 Roo.data.Record = function(data, id){
4140 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4145 * Generate a constructor for a specific record layout.
4146 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4147 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4148 * Each field definition object may contain the following properties: <ul>
4149 * <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,
4150 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4151 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4152 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4153 * is being used, then this is a string containing the javascript expression to reference the data relative to
4154 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4155 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4156 * this may be omitted.</p></li>
4157 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4158 * <ul><li>auto (Default, implies no conversion)</li>
4163 * <li>date</li></ul></p></li>
4164 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4165 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4166 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4167 * by the Reader into an object that will be stored in the Record. It is passed the
4168 * following parameters:<ul>
4169 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4171 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4173 * <br>usage:<br><pre><code>
4174 var TopicRecord = Roo.data.Record.create(
4175 {name: 'title', mapping: 'topic_title'},
4176 {name: 'author', mapping: 'username'},
4177 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4178 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4179 {name: 'lastPoster', mapping: 'user2'},
4180 {name: 'excerpt', mapping: 'post_text'}
4183 var myNewRecord = new TopicRecord({
4184 title: 'Do my job please',
4187 lastPost: new Date(),
4188 lastPoster: 'Animal',
4189 excerpt: 'No way dude!'
4191 myStore.add(myNewRecord);
4196 Roo.data.Record.create = function(o){
4198 f.superclass.constructor.apply(this, arguments);
4200 Roo.extend(f, Roo.data.Record);
4201 var p = f.prototype;
4202 p.fields = new Roo.util.MixedCollection(false, function(field){
4205 for(var i = 0, len = o.length; i < len; i++){
4206 p.fields.add(new Roo.data.Field(o[i]));
4208 f.getField = function(name){
4209 return p.fields.get(name);
4214 Roo.data.Record.AUTO_ID = 1000;
4215 Roo.data.Record.EDIT = 'edit';
4216 Roo.data.Record.REJECT = 'reject';
4217 Roo.data.Record.COMMIT = 'commit';
4219 Roo.data.Record.prototype = {
4221 * Readonly flag - true if this record has been modified.
4230 join : function(store){
4235 * Set the named field to the specified value.
4236 * @param {String} name The name of the field to set.
4237 * @param {Object} value The value to set the field to.
4239 set : function(name, value){
4240 if(this.data[name] == value){
4247 if(typeof this.modified[name] == 'undefined'){
4248 this.modified[name] = this.data[name];
4250 this.data[name] = value;
4251 if(!this.editing && this.store){
4252 this.store.afterEdit(this);
4257 * Get the value of the named field.
4258 * @param {String} name The name of the field to get the value of.
4259 * @return {Object} The value of the field.
4261 get : function(name){
4262 return this.data[name];
4266 beginEdit : function(){
4267 this.editing = true;
4272 cancelEdit : function(){
4273 this.editing = false;
4274 delete this.modified;
4278 endEdit : function(){
4279 this.editing = false;
4280 if(this.dirty && this.store){
4281 this.store.afterEdit(this);
4286 * Usually called by the {@link Roo.data.Store} which owns the Record.
4287 * Rejects all changes made to the Record since either creation, or the last commit operation.
4288 * Modified fields are reverted to their original values.
4290 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4291 * of reject operations.
4293 reject : function(){
4294 var m = this.modified;
4296 if(typeof m[n] != "function"){
4297 this.data[n] = m[n];
4301 delete this.modified;
4302 this.editing = false;
4304 this.store.afterReject(this);
4309 * Usually called by the {@link Roo.data.Store} which owns the Record.
4310 * Commits all changes made to the Record since either creation, or the last commit operation.
4312 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4313 * of commit operations.
4315 commit : function(){
4317 delete this.modified;
4318 this.editing = false;
4320 this.store.afterCommit(this);
4325 hasError : function(){
4326 return this.error != null;
4330 clearError : function(){
4335 * Creates a copy of this record.
4336 * @param {String} id (optional) A new record id if you don't want to use this record's id
4339 copy : function(newId) {
4340 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4344 * Ext JS Library 1.1.1
4345 * Copyright(c) 2006-2007, Ext JS, LLC.
4347 * Originally Released Under LGPL - original licence link has changed is not relivant.
4350 * <script type="text/javascript">
4356 * @class Roo.data.Store
4357 * @extends Roo.util.Observable
4358 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4359 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4361 * 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
4362 * has no knowledge of the format of the data returned by the Proxy.<br>
4364 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4365 * instances from the data object. These records are cached and made available through accessor functions.
4367 * Creates a new Store.
4368 * @param {Object} config A config object containing the objects needed for the Store to access data,
4369 * and read the data into Records.
4371 Roo.data.Store = function(config){
4372 this.data = new Roo.util.MixedCollection(false);
4373 this.data.getKey = function(o){
4376 this.baseParams = {};
4383 "multisort" : "_multisort"
4386 if(config && config.data){
4387 this.inlineData = config.data;
4391 Roo.apply(this, config);
4393 if(this.reader){ // reader passed
4394 this.reader = Roo.factory(this.reader, Roo.data);
4395 this.reader.xmodule = this.xmodule || false;
4396 if(!this.recordType){
4397 this.recordType = this.reader.recordType;
4399 if(this.reader.onMetaChange){
4400 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4404 if(this.recordType){
4405 this.fields = this.recordType.prototype.fields;
4411 * @event datachanged
4412 * Fires when the data cache has changed, and a widget which is using this Store
4413 * as a Record cache should refresh its view.
4414 * @param {Store} this
4419 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4420 * @param {Store} this
4421 * @param {Object} meta The JSON metadata
4426 * Fires when Records have been added to the Store
4427 * @param {Store} this
4428 * @param {Roo.data.Record[]} records The array of Records added
4429 * @param {Number} index The index at which the record(s) were added
4434 * Fires when a Record has been removed from the Store
4435 * @param {Store} this
4436 * @param {Roo.data.Record} record The Record that was removed
4437 * @param {Number} index The index at which the record was removed
4442 * Fires when a Record has been updated
4443 * @param {Store} this
4444 * @param {Roo.data.Record} record The Record that was updated
4445 * @param {String} operation The update operation being performed. Value may be one of:
4447 Roo.data.Record.EDIT
4448 Roo.data.Record.REJECT
4449 Roo.data.Record.COMMIT
4455 * Fires when the data cache has been cleared.
4456 * @param {Store} this
4461 * Fires before a request is made for a new data object. If the beforeload handler returns false
4462 * the load action will be canceled.
4463 * @param {Store} this
4464 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4468 * @event beforeloadadd
4469 * Fires after a new set of Records has been loaded.
4470 * @param {Store} this
4471 * @param {Roo.data.Record[]} records The Records that were loaded
4472 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4474 beforeloadadd : true,
4477 * Fires after a new set of Records has been loaded, before they are added to the store.
4478 * @param {Store} this
4479 * @param {Roo.data.Record[]} records The Records that were loaded
4480 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4481 * @params {Object} return from reader
4485 * @event loadexception
4486 * Fires if an exception occurs in the Proxy during loading.
4487 * Called with the signature of the Proxy's "loadexception" event.
4488 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4491 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4492 * @param {Object} load options
4493 * @param {Object} jsonData from your request (normally this contains the Exception)
4495 loadexception : true
4499 this.proxy = Roo.factory(this.proxy, Roo.data);
4500 this.proxy.xmodule = this.xmodule || false;
4501 this.relayEvents(this.proxy, ["loadexception"]);
4503 this.sortToggle = {};
4504 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4506 Roo.data.Store.superclass.constructor.call(this);
4508 if(this.inlineData){
4509 this.loadData(this.inlineData);
4510 delete this.inlineData;
4514 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4516 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4517 * without a remote query - used by combo/forms at present.
4521 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4524 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4527 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4528 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4531 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4532 * on any HTTP request
4535 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4538 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4542 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4543 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4548 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4549 * loaded or when a record is removed. (defaults to false).
4551 pruneModifiedRecords : false,
4557 * Add Records to the Store and fires the add event.
4558 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4560 add : function(records){
4561 records = [].concat(records);
4562 for(var i = 0, len = records.length; i < len; i++){
4563 records[i].join(this);
4565 var index = this.data.length;
4566 this.data.addAll(records);
4567 this.fireEvent("add", this, records, index);
4571 * Remove a Record from the Store and fires the remove event.
4572 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4574 remove : function(record){
4575 var index = this.data.indexOf(record);
4576 this.data.removeAt(index);
4577 if(this.pruneModifiedRecords){
4578 this.modified.remove(record);
4580 this.fireEvent("remove", this, record, index);
4584 * Remove all Records from the Store and fires the clear event.
4586 removeAll : function(){
4588 if(this.pruneModifiedRecords){
4591 this.fireEvent("clear", this);
4595 * Inserts Records to the Store at the given index and fires the add event.
4596 * @param {Number} index The start index at which to insert the passed Records.
4597 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4599 insert : function(index, records){
4600 records = [].concat(records);
4601 for(var i = 0, len = records.length; i < len; i++){
4602 this.data.insert(index, records[i]);
4603 records[i].join(this);
4605 this.fireEvent("add", this, records, index);
4609 * Get the index within the cache of the passed Record.
4610 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4611 * @return {Number} The index of the passed Record. Returns -1 if not found.
4613 indexOf : function(record){
4614 return this.data.indexOf(record);
4618 * Get the index within the cache of the Record with the passed id.
4619 * @param {String} id The id of the Record to find.
4620 * @return {Number} The index of the Record. Returns -1 if not found.
4622 indexOfId : function(id){
4623 return this.data.indexOfKey(id);
4627 * Get the Record with the specified id.
4628 * @param {String} id The id of the Record to find.
4629 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4631 getById : function(id){
4632 return this.data.key(id);
4636 * Get the Record at the specified index.
4637 * @param {Number} index The index of the Record to find.
4638 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4640 getAt : function(index){
4641 return this.data.itemAt(index);
4645 * Returns a range of Records between specified indices.
4646 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4647 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4648 * @return {Roo.data.Record[]} An array of Records
4650 getRange : function(start, end){
4651 return this.data.getRange(start, end);
4655 storeOptions : function(o){
4656 o = Roo.apply({}, o);
4659 this.lastOptions = o;
4663 * Loads the Record cache from the configured Proxy using the configured Reader.
4665 * If using remote paging, then the first load call must specify the <em>start</em>
4666 * and <em>limit</em> properties in the options.params property to establish the initial
4667 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4669 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4670 * and this call will return before the new data has been loaded. Perform any post-processing
4671 * in a callback function, or in a "load" event handler.</strong>
4673 * @param {Object} options An object containing properties which control loading options:<ul>
4674 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4675 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4676 * passed the following arguments:<ul>
4677 * <li>r : Roo.data.Record[]</li>
4678 * <li>options: Options object from the load call</li>
4679 * <li>success: Boolean success indicator</li></ul></li>
4680 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4681 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4684 load : function(options){
4685 options = options || {};
4686 if(this.fireEvent("beforeload", this, options) !== false){
4687 this.storeOptions(options);
4688 var p = Roo.apply(options.params || {}, this.baseParams);
4689 // if meta was not loaded from remote source.. try requesting it.
4690 if (!this.reader.metaFromRemote) {
4693 if(this.sortInfo && this.remoteSort){
4694 var pn = this.paramNames;
4695 p[pn["sort"]] = this.sortInfo.field;
4696 p[pn["dir"]] = this.sortInfo.direction;
4698 if (this.multiSort) {
4699 var pn = this.paramNames;
4700 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4703 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4708 * Reloads the Record cache from the configured Proxy using the configured Reader and
4709 * the options from the last load operation performed.
4710 * @param {Object} options (optional) An object containing properties which may override the options
4711 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4712 * the most recently used options are reused).
4714 reload : function(options){
4715 this.load(Roo.applyIf(options||{}, this.lastOptions));
4719 // Called as a callback by the Reader during a load operation.
4720 loadRecords : function(o, options, success){
4721 if(!o || success === false){
4722 if(success !== false){
4723 this.fireEvent("load", this, [], options, o);
4725 if(options.callback){
4726 options.callback.call(options.scope || this, [], options, false);
4730 // if data returned failure - throw an exception.
4731 if (o.success === false) {
4732 // show a message if no listener is registered.
4733 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4734 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4736 // loadmask wil be hooked into this..
4737 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4740 var r = o.records, t = o.totalRecords || r.length;
4742 this.fireEvent("beforeloadadd", this, r, options, o);
4744 if(!options || options.add !== true){
4745 if(this.pruneModifiedRecords){
4748 for(var i = 0, len = r.length; i < len; i++){
4752 this.data = this.snapshot;
4753 delete this.snapshot;
4756 this.data.addAll(r);
4757 this.totalLength = t;
4759 this.fireEvent("datachanged", this);
4761 this.totalLength = Math.max(t, this.data.length+r.length);
4764 this.fireEvent("load", this, r, options, o);
4765 if(options.callback){
4766 options.callback.call(options.scope || this, r, options, true);
4772 * Loads data from a passed data block. A Reader which understands the format of the data
4773 * must have been configured in the constructor.
4774 * @param {Object} data The data block from which to read the Records. The format of the data expected
4775 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4776 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4778 loadData : function(o, append){
4779 var r = this.reader.readRecords(o);
4780 this.loadRecords(r, {add: append}, true);
4784 * Gets the number of cached records.
4786 * <em>If using paging, this may not be the total size of the dataset. If the data object
4787 * used by the Reader contains the dataset size, then the getTotalCount() function returns
4788 * the data set size</em>
4790 getCount : function(){
4791 return this.data.length || 0;
4795 * Gets the total number of records in the dataset as returned by the server.
4797 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4798 * the dataset size</em>
4800 getTotalCount : function(){
4801 return this.totalLength || 0;
4805 * Returns the sort state of the Store as an object with two properties:
4807 field {String} The name of the field by which the Records are sorted
4808 direction {String} The sort order, "ASC" or "DESC"
4811 getSortState : function(){
4812 return this.sortInfo;
4816 applySort : function(){
4817 if(this.sortInfo && !this.remoteSort){
4818 var s = this.sortInfo, f = s.field;
4819 var st = this.fields.get(f).sortType;
4820 var fn = function(r1, r2){
4821 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4822 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
4824 this.data.sort(s.direction, fn);
4825 if(this.snapshot && this.snapshot != this.data){
4826 this.snapshot.sort(s.direction, fn);
4832 * Sets the default sort column and order to be used by the next load operation.
4833 * @param {String} fieldName The name of the field to sort by.
4834 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4836 setDefaultSort : function(field, dir){
4837 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
4842 * If remote sorting is used, the sort is performed on the server, and the cache is
4843 * reloaded. If local sorting is used, the cache is sorted internally.
4844 * @param {String} fieldName The name of the field to sort by.
4845 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4847 sort : function(fieldName, dir){
4848 var f = this.fields.get(fieldName);
4850 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
4852 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
4853 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
4858 this.sortToggle[f.name] = dir;
4859 this.sortInfo = {field: f.name, direction: dir};
4860 if(!this.remoteSort){
4862 this.fireEvent("datachanged", this);
4864 this.load(this.lastOptions);
4869 * Calls the specified function for each of the Records in the cache.
4870 * @param {Function} fn The function to call. The Record is passed as the first parameter.
4871 * Returning <em>false</em> aborts and exits the iteration.
4872 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
4874 each : function(fn, scope){
4875 this.data.each(fn, scope);
4879 * Gets all records modified since the last commit. Modified records are persisted across load operations
4880 * (e.g., during paging).
4881 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
4883 getModifiedRecords : function(){
4884 return this.modified;
4888 createFilterFn : function(property, value, anyMatch){
4889 if(!value.exec){ // not a regex
4890 value = String(value);
4891 if(value.length == 0){
4894 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
4897 return value.test(r.data[property]);
4902 * Sums the value of <i>property</i> for each record between start and end and returns the result.
4903 * @param {String} property A field on your records
4904 * @param {Number} start The record index to start at (defaults to 0)
4905 * @param {Number} end The last record index to include (defaults to length - 1)
4906 * @return {Number} The sum
4908 sum : function(property, start, end){
4909 var rs = this.data.items, v = 0;
4911 end = (end || end === 0) ? end : rs.length-1;
4913 for(var i = start; i <= end; i++){
4914 v += (rs[i].data[property] || 0);
4920 * Filter the records by a specified property.
4921 * @param {String} field A field on your records
4922 * @param {String/RegExp} value Either a string that the field
4923 * should start with or a RegExp to test against the field
4924 * @param {Boolean} anyMatch True to match any part not just the beginning
4926 filter : function(property, value, anyMatch){
4927 var fn = this.createFilterFn(property, value, anyMatch);
4928 return fn ? this.filterBy(fn) : this.clearFilter();
4932 * Filter by a function. The specified function will be called with each
4933 * record in this data source. If the function returns true the record is included,
4934 * otherwise it is filtered.
4935 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4936 * @param {Object} scope (optional) The scope of the function (defaults to this)
4938 filterBy : function(fn, scope){
4939 this.snapshot = this.snapshot || this.data;
4940 this.data = this.queryBy(fn, scope||this);
4941 this.fireEvent("datachanged", this);
4945 * Query the records by a specified property.
4946 * @param {String} field A field on your records
4947 * @param {String/RegExp} value Either a string that the field
4948 * should start with or a RegExp to test against the field
4949 * @param {Boolean} anyMatch True to match any part not just the beginning
4950 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
4952 query : function(property, value, anyMatch){
4953 var fn = this.createFilterFn(property, value, anyMatch);
4954 return fn ? this.queryBy(fn) : this.data.clone();
4958 * Query by a function. The specified function will be called with each
4959 * record in this data source. If the function returns true the record is included
4961 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4962 * @param {Object} scope (optional) The scope of the function (defaults to this)
4963 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
4965 queryBy : function(fn, scope){
4966 var data = this.snapshot || this.data;
4967 return data.filterBy(fn, scope||this);
4971 * Collects unique values for a particular dataIndex from this store.
4972 * @param {String} dataIndex The property to collect
4973 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
4974 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
4975 * @return {Array} An array of the unique values
4977 collect : function(dataIndex, allowNull, bypassFilter){
4978 var d = (bypassFilter === true && this.snapshot) ?
4979 this.snapshot.items : this.data.items;
4980 var v, sv, r = [], l = {};
4981 for(var i = 0, len = d.length; i < len; i++){
4982 v = d[i].data[dataIndex];
4984 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
4993 * Revert to a view of the Record cache with no filtering applied.
4994 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
4996 clearFilter : function(suppressEvent){
4997 if(this.snapshot && this.snapshot != this.data){
4998 this.data = this.snapshot;
4999 delete this.snapshot;
5000 if(suppressEvent !== true){
5001 this.fireEvent("datachanged", this);
5007 afterEdit : function(record){
5008 if(this.modified.indexOf(record) == -1){
5009 this.modified.push(record);
5011 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5015 afterReject : function(record){
5016 this.modified.remove(record);
5017 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5021 afterCommit : function(record){
5022 this.modified.remove(record);
5023 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5027 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5028 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5030 commitChanges : function(){
5031 var m = this.modified.slice(0);
5033 for(var i = 0, len = m.length; i < len; i++){
5039 * Cancel outstanding changes on all changed records.
5041 rejectChanges : function(){
5042 var m = this.modified.slice(0);
5044 for(var i = 0, len = m.length; i < len; i++){
5049 onMetaChange : function(meta, rtype, o){
5050 this.recordType = rtype;
5051 this.fields = rtype.prototype.fields;
5052 delete this.snapshot;
5053 this.sortInfo = meta.sortInfo || this.sortInfo;
5055 this.fireEvent('metachange', this, this.reader.meta);
5059 * Ext JS Library 1.1.1
5060 * Copyright(c) 2006-2007, Ext JS, LLC.
5062 * Originally Released Under LGPL - original licence link has changed is not relivant.
5065 * <script type="text/javascript">
5069 * @class Roo.data.SimpleStore
5070 * @extends Roo.data.Store
5071 * Small helper class to make creating Stores from Array data easier.
5072 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5073 * @cfg {Array} fields An array of field definition objects, or field name strings.
5074 * @cfg {Array} data The multi-dimensional array of data
5076 * @param {Object} config
5078 Roo.data.SimpleStore = function(config){
5079 Roo.data.SimpleStore.superclass.constructor.call(this, {
5081 reader: new Roo.data.ArrayReader({
5084 Roo.data.Record.create(config.fields)
5086 proxy : new Roo.data.MemoryProxy(config.data)
5090 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5092 * Ext JS Library 1.1.1
5093 * Copyright(c) 2006-2007, Ext JS, LLC.
5095 * Originally Released Under LGPL - original licence link has changed is not relivant.
5098 * <script type="text/javascript">
5103 * @extends Roo.data.Store
5104 * @class Roo.data.JsonStore
5105 * Small helper class to make creating Stores for JSON data easier. <br/>
5107 var store = new Roo.data.JsonStore({
5108 url: 'get-images.php',
5110 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5113 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5114 * JsonReader and HttpProxy (unless inline data is provided).</b>
5115 * @cfg {Array} fields An array of field definition objects, or field name strings.
5117 * @param {Object} config
5119 Roo.data.JsonStore = function(c){
5120 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5121 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5122 reader: new Roo.data.JsonReader(c, c.fields)
5125 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5127 * Ext JS Library 1.1.1
5128 * Copyright(c) 2006-2007, Ext JS, LLC.
5130 * Originally Released Under LGPL - original licence link has changed is not relivant.
5133 * <script type="text/javascript">
5137 Roo.data.Field = function(config){
5138 if(typeof config == "string"){
5139 config = {name: config};
5141 Roo.apply(this, config);
5147 var st = Roo.data.SortTypes;
5148 // named sortTypes are supported, here we look them up
5149 if(typeof this.sortType == "string"){
5150 this.sortType = st[this.sortType];
5153 // set default sortType for strings and dates
5157 this.sortType = st.asUCString;
5160 this.sortType = st.asDate;
5163 this.sortType = st.none;
5168 var stripRe = /[\$,%]/g;
5170 // prebuilt conversion function for this field, instead of
5171 // switching every time we're reading a value
5173 var cv, dateFormat = this.dateFormat;
5178 cv = function(v){ return v; };
5181 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5185 return v !== undefined && v !== null && v !== '' ?
5186 parseInt(String(v).replace(stripRe, ""), 10) : '';
5191 return v !== undefined && v !== null && v !== '' ?
5192 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5197 cv = function(v){ return v === true || v === "true" || v == 1; };
5204 if(v instanceof Date){
5208 if(dateFormat == "timestamp"){
5209 return new Date(v*1000);
5211 return Date.parseDate(v, dateFormat);
5213 var parsed = Date.parse(v);
5214 return parsed ? new Date(parsed) : null;
5223 Roo.data.Field.prototype = {
5231 * Ext JS Library 1.1.1
5232 * Copyright(c) 2006-2007, Ext JS, LLC.
5234 * Originally Released Under LGPL - original licence link has changed is not relivant.
5237 * <script type="text/javascript">
5240 // Base class for reading structured data from a data source. This class is intended to be
5241 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5244 * @class Roo.data.DataReader
5245 * Base class for reading structured data from a data source. This class is intended to be
5246 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5249 Roo.data.DataReader = function(meta, recordType){
5253 this.recordType = recordType instanceof Array ?
5254 Roo.data.Record.create(recordType) : recordType;
5257 Roo.data.DataReader.prototype = {
5259 * Create an empty record
5260 * @param {Object} data (optional) - overlay some values
5261 * @return {Roo.data.Record} record created.
5263 newRow : function(d) {
5265 this.recordType.prototype.fields.each(function(c) {
5267 case 'int' : da[c.name] = 0; break;
5268 case 'date' : da[c.name] = new Date(); break;
5269 case 'float' : da[c.name] = 0.0; break;
5270 case 'boolean' : da[c.name] = false; break;
5271 default : da[c.name] = ""; break;
5275 return new this.recordType(Roo.apply(da, d));
5280 * Ext JS Library 1.1.1
5281 * Copyright(c) 2006-2007, Ext JS, LLC.
5283 * Originally Released Under LGPL - original licence link has changed is not relivant.
5286 * <script type="text/javascript">
5290 * @class Roo.data.DataProxy
5291 * @extends Roo.data.Observable
5292 * This class is an abstract base class for implementations which provide retrieval of
5293 * unformatted data objects.<br>
5295 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5296 * (of the appropriate type which knows how to parse the data object) to provide a block of
5297 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5299 * Custom implementations must implement the load method as described in
5300 * {@link Roo.data.HttpProxy#load}.
5302 Roo.data.DataProxy = function(){
5306 * Fires before a network request is made to retrieve a data object.
5307 * @param {Object} This DataProxy object.
5308 * @param {Object} params The params parameter to the load function.
5313 * Fires before the load method's callback is called.
5314 * @param {Object} This DataProxy object.
5315 * @param {Object} o The data object.
5316 * @param {Object} arg The callback argument object passed to the load function.
5320 * @event loadexception
5321 * Fires if an Exception occurs during data retrieval.
5322 * @param {Object} This DataProxy object.
5323 * @param {Object} o The data object.
5324 * @param {Object} arg The callback argument object passed to the load function.
5325 * @param {Object} e The Exception.
5327 loadexception : true
5329 Roo.data.DataProxy.superclass.constructor.call(this);
5332 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5335 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5339 * Ext JS Library 1.1.1
5340 * Copyright(c) 2006-2007, Ext JS, LLC.
5342 * Originally Released Under LGPL - original licence link has changed is not relivant.
5345 * <script type="text/javascript">
5348 * @class Roo.data.MemoryProxy
5349 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5350 * to the Reader when its load method is called.
5352 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5354 Roo.data.MemoryProxy = function(data){
5358 Roo.data.MemoryProxy.superclass.constructor.call(this);
5362 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5364 * Load data from the requested source (in this case an in-memory
5365 * data object passed to the constructor), read the data object into
5366 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5367 * process that block using the passed callback.
5368 * @param {Object} params This parameter is not used by the MemoryProxy class.
5369 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5370 * object into a block of Roo.data.Records.
5371 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5372 * The function must be passed <ul>
5373 * <li>The Record block object</li>
5374 * <li>The "arg" argument from the load function</li>
5375 * <li>A boolean success indicator</li>
5377 * @param {Object} scope The scope in which to call the callback
5378 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5380 load : function(params, reader, callback, scope, arg){
5381 params = params || {};
5384 result = reader.readRecords(this.data);
5386 this.fireEvent("loadexception", this, arg, null, e);
5387 callback.call(scope, null, arg, false);
5390 callback.call(scope, result, arg, true);
5394 update : function(params, records){
5399 * Ext JS Library 1.1.1
5400 * Copyright(c) 2006-2007, Ext JS, LLC.
5402 * Originally Released Under LGPL - original licence link has changed is not relivant.
5405 * <script type="text/javascript">
5408 * @class Roo.data.HttpProxy
5409 * @extends Roo.data.DataProxy
5410 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5411 * configured to reference a certain URL.<br><br>
5413 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5414 * from which the running page was served.<br><br>
5416 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5418 * Be aware that to enable the browser to parse an XML document, the server must set
5419 * the Content-Type header in the HTTP response to "text/xml".
5421 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5422 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5423 * will be used to make the request.
5425 Roo.data.HttpProxy = function(conn){
5426 Roo.data.HttpProxy.superclass.constructor.call(this);
5427 // is conn a conn config or a real conn?
5429 this.useAjax = !conn || !conn.events;
5433 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5434 // thse are take from connection...
5437 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5440 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5441 * extra parameters to each request made by this object. (defaults to undefined)
5444 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5445 * to each request made by this object. (defaults to undefined)
5448 * @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)
5451 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5454 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5460 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5464 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5465 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5466 * a finer-grained basis than the DataProxy events.
5468 getConnection : function(){
5469 return this.useAjax ? Roo.Ajax : this.conn;
5473 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5474 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5475 * process that block using the passed callback.
5476 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5477 * for the request to the remote server.
5478 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5479 * object into a block of Roo.data.Records.
5480 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5481 * The function must be passed <ul>
5482 * <li>The Record block object</li>
5483 * <li>The "arg" argument from the load function</li>
5484 * <li>A boolean success indicator</li>
5486 * @param {Object} scope The scope in which to call the callback
5487 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5489 load : function(params, reader, callback, scope, arg){
5490 if(this.fireEvent("beforeload", this, params) !== false){
5492 params : params || {},
5494 callback : callback,
5499 callback : this.loadResponse,
5503 Roo.applyIf(o, this.conn);
5504 if(this.activeRequest){
5505 Roo.Ajax.abort(this.activeRequest);
5507 this.activeRequest = Roo.Ajax.request(o);
5509 this.conn.request(o);
5512 callback.call(scope||this, null, arg, false);
5517 loadResponse : function(o, success, response){
5518 delete this.activeRequest;
5520 this.fireEvent("loadexception", this, o, response);
5521 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5526 result = o.reader.read(response);
5528 this.fireEvent("loadexception", this, o, response, e);
5529 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5533 this.fireEvent("load", this, o, o.request.arg);
5534 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5538 update : function(dataSet){
5543 updateResponse : function(dataSet){
5548 * Ext JS Library 1.1.1
5549 * Copyright(c) 2006-2007, Ext JS, LLC.
5551 * Originally Released Under LGPL - original licence link has changed is not relivant.
5554 * <script type="text/javascript">
5558 * @class Roo.data.ScriptTagProxy
5559 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5560 * other than the originating domain of the running page.<br><br>
5562 * <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
5563 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5565 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5566 * source code that is used as the source inside a <script> tag.<br><br>
5568 * In order for the browser to process the returned data, the server must wrap the data object
5569 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5570 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5571 * depending on whether the callback name was passed:
5574 boolean scriptTag = false;
5575 String cb = request.getParameter("callback");
5578 response.setContentType("text/javascript");
5580 response.setContentType("application/x-json");
5582 Writer out = response.getWriter();
5584 out.write(cb + "(");
5586 out.print(dataBlock.toJsonString());
5593 * @param {Object} config A configuration object.
5595 Roo.data.ScriptTagProxy = function(config){
5596 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5597 Roo.apply(this, config);
5598 this.head = document.getElementsByTagName("head")[0];
5601 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5603 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5605 * @cfg {String} url The URL from which to request the data object.
5608 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5612 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5613 * the server the name of the callback function set up by the load call to process the returned data object.
5614 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5615 * javascript output which calls this named function passing the data object as its only parameter.
5617 callbackParam : "callback",
5619 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5620 * name to the request.
5625 * Load data from the configured URL, read the data object into
5626 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5627 * process that block using the passed callback.
5628 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5629 * for the request to the remote server.
5630 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5631 * object into a block of Roo.data.Records.
5632 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5633 * The function must be passed <ul>
5634 * <li>The Record block object</li>
5635 * <li>The "arg" argument from the load function</li>
5636 * <li>A boolean success indicator</li>
5638 * @param {Object} scope The scope in which to call the callback
5639 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5641 load : function(params, reader, callback, scope, arg){
5642 if(this.fireEvent("beforeload", this, params) !== false){
5644 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5647 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5649 url += "&_dc=" + (new Date().getTime());
5651 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5654 cb : "stcCallback"+transId,
5655 scriptId : "stcScript"+transId,
5659 callback : callback,
5665 window[trans.cb] = function(o){
5666 conn.handleResponse(o, trans);
5669 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5671 if(this.autoAbort !== false){
5675 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5677 var script = document.createElement("script");
5678 script.setAttribute("src", url);
5679 script.setAttribute("type", "text/javascript");
5680 script.setAttribute("id", trans.scriptId);
5681 this.head.appendChild(script);
5685 callback.call(scope||this, null, arg, false);
5690 isLoading : function(){
5691 return this.trans ? true : false;
5695 * Abort the current server request.
5698 if(this.isLoading()){
5699 this.destroyTrans(this.trans);
5704 destroyTrans : function(trans, isLoaded){
5705 this.head.removeChild(document.getElementById(trans.scriptId));
5706 clearTimeout(trans.timeoutId);
5708 window[trans.cb] = undefined;
5710 delete window[trans.cb];
5713 // if hasn't been loaded, wait for load to remove it to prevent script error
5714 window[trans.cb] = function(){
5715 window[trans.cb] = undefined;
5717 delete window[trans.cb];
5724 handleResponse : function(o, trans){
5726 this.destroyTrans(trans, true);
5729 result = trans.reader.readRecords(o);
5731 this.fireEvent("loadexception", this, o, trans.arg, e);
5732 trans.callback.call(trans.scope||window, null, trans.arg, false);
5735 this.fireEvent("load", this, o, trans.arg);
5736 trans.callback.call(trans.scope||window, result, trans.arg, true);
5740 handleFailure : function(trans){
5742 this.destroyTrans(trans, false);
5743 this.fireEvent("loadexception", this, null, trans.arg);
5744 trans.callback.call(trans.scope||window, null, trans.arg, false);
5748 * Ext JS Library 1.1.1
5749 * Copyright(c) 2006-2007, Ext JS, LLC.
5751 * Originally Released Under LGPL - original licence link has changed is not relivant.
5754 * <script type="text/javascript">
5758 * @class Roo.data.JsonReader
5759 * @extends Roo.data.DataReader
5760 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5761 * based on mappings in a provided Roo.data.Record constructor.
5763 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5764 * in the reply previously.
5769 var RecordDef = Roo.data.Record.create([
5770 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5771 {name: 'occupation'} // This field will use "occupation" as the mapping.
5773 var myReader = new Roo.data.JsonReader({
5774 totalProperty: "results", // The property which contains the total dataset size (optional)
5775 root: "rows", // The property which contains an Array of row objects
5776 id: "id" // The property within each row object that provides an ID for the record (optional)
5780 * This would consume a JSON file like this:
5782 { 'results': 2, 'rows': [
5783 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5784 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5787 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5788 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5789 * paged from the remote server.
5790 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5791 * @cfg {String} root name of the property which contains the Array of row objects.
5792 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5794 * Create a new JsonReader
5795 * @param {Object} meta Metadata configuration options
5796 * @param {Object} recordType Either an Array of field definition objects,
5797 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5799 Roo.data.JsonReader = function(meta, recordType){
5802 // set some defaults:
5804 totalProperty: 'total',
5805 successProperty : 'success',
5810 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5812 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5815 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
5816 * Used by Store query builder to append _requestMeta to params.
5819 metaFromRemote : false,
5821 * This method is only used by a DataProxy which has retrieved data from a remote server.
5822 * @param {Object} response The XHR object which contains the JSON data in its responseText.
5823 * @return {Object} data A data block which is used by an Roo.data.Store object as
5824 * a cache of Roo.data.Records.
5826 read : function(response){
5827 var json = response.responseText;
5829 var o = /* eval:var:o */ eval("("+json+")");
5831 throw {message: "JsonReader.read: Json object not found"};
5837 this.metaFromRemote = true;
5838 this.meta = o.metaData;
5839 this.recordType = Roo.data.Record.create(o.metaData.fields);
5840 this.onMetaChange(this.meta, this.recordType, o);
5842 return this.readRecords(o);
5845 // private function a store will implement
5846 onMetaChange : function(meta, recordType, o){
5853 simpleAccess: function(obj, subsc) {
5860 getJsonAccessor: function(){
5862 return function(expr) {
5864 return(re.test(expr))
5865 ? new Function("obj", "return obj." + expr)
5875 * Create a data block containing Roo.data.Records from an XML document.
5876 * @param {Object} o An object which contains an Array of row objects in the property specified
5877 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
5878 * which contains the total size of the dataset.
5879 * @return {Object} data A data block which is used by an Roo.data.Store object as
5880 * a cache of Roo.data.Records.
5882 readRecords : function(o){
5884 * After any data loads, the raw JSON data is available for further custom processing.
5888 var s = this.meta, Record = this.recordType,
5889 f = Record.prototype.fields, fi = f.items, fl = f.length;
5891 // Generate extraction functions for the totalProperty, the root, the id, and for each field
5893 if(s.totalProperty) {
5894 this.getTotal = this.getJsonAccessor(s.totalProperty);
5896 if(s.successProperty) {
5897 this.getSuccess = this.getJsonAccessor(s.successProperty);
5899 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
5901 var g = this.getJsonAccessor(s.id);
5902 this.getId = function(rec) {
5904 return (r === undefined || r === "") ? null : r;
5907 this.getId = function(){return null;};
5910 for(var jj = 0; jj < fl; jj++){
5912 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
5913 this.ef[jj] = this.getJsonAccessor(map);
5917 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
5918 if(s.totalProperty){
5919 var vt = parseInt(this.getTotal(o), 10);
5924 if(s.successProperty){
5925 var vs = this.getSuccess(o);
5926 if(vs === false || vs === 'false'){
5931 for(var i = 0; i < c; i++){
5934 var id = this.getId(n);
5935 for(var j = 0; j < fl; j++){
5937 var v = this.ef[j](n);
5939 Roo.log('missing convert for ' + f.name);
5943 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
5945 var record = new Record(values, id);
5947 records[i] = record;
5953 totalRecords : totalRecords
5958 * Ext JS Library 1.1.1
5959 * Copyright(c) 2006-2007, Ext JS, LLC.
5961 * Originally Released Under LGPL - original licence link has changed is not relivant.
5964 * <script type="text/javascript">
5968 * @class Roo.data.ArrayReader
5969 * @extends Roo.data.DataReader
5970 * Data reader class to create an Array of Roo.data.Record objects from an Array.
5971 * Each element of that Array represents a row of data fields. The
5972 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
5973 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
5977 var RecordDef = Roo.data.Record.create([
5978 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
5979 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
5981 var myReader = new Roo.data.ArrayReader({
5982 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
5986 * This would consume an Array like this:
5988 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
5990 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
5992 * Create a new JsonReader
5993 * @param {Object} meta Metadata configuration options.
5994 * @param {Object} recordType Either an Array of field definition objects
5995 * as specified to {@link Roo.data.Record#create},
5996 * or an {@link Roo.data.Record} object
5997 * created using {@link Roo.data.Record#create}.
5999 Roo.data.ArrayReader = function(meta, recordType){
6000 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6003 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6005 * Create a data block containing Roo.data.Records from an XML document.
6006 * @param {Object} o An Array of row objects which represents the dataset.
6007 * @return {Object} data A data block which is used by an Roo.data.Store object as
6008 * a cache of Roo.data.Records.
6010 readRecords : function(o){
6011 var sid = this.meta ? this.meta.id : null;
6012 var recordType = this.recordType, fields = recordType.prototype.fields;
6015 for(var i = 0; i < root.length; i++){
6018 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6019 for(var j = 0, jlen = fields.length; j < jlen; j++){
6020 var f = fields.items[j];
6021 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6022 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6026 var record = new recordType(values, id);
6028 records[records.length] = record;
6032 totalRecords : records.length
6041 * @class Roo.bootstrap.ComboBox
6042 * @extends Roo.bootstrap.TriggerField
6043 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6045 * Create a new ComboBox.
6046 * @param {Object} config Configuration options
6048 Roo.bootstrap.ComboBox = function(config){
6049 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6053 * Fires when the dropdown list is expanded
6054 * @param {Roo.bootstrap.ComboBox} combo This combo box
6059 * Fires when the dropdown list is collapsed
6060 * @param {Roo.bootstrap.ComboBox} combo This combo box
6064 * @event beforeselect
6065 * Fires before a list item is selected. Return false to cancel the selection.
6066 * @param {Roo.bootstrap.ComboBox} combo This combo box
6067 * @param {Roo.data.Record} record The data record returned from the underlying store
6068 * @param {Number} index The index of the selected item in the dropdown list
6070 'beforeselect' : true,
6073 * Fires when a list item is selected
6074 * @param {Roo.bootstrap.ComboBox} combo This combo box
6075 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6076 * @param {Number} index The index of the selected item in the dropdown list
6080 * @event beforequery
6081 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6082 * The event object passed has these properties:
6083 * @param {Roo.bootstrap.ComboBox} combo This combo box
6084 * @param {String} query The query
6085 * @param {Boolean} forceAll true to force "all" query
6086 * @param {Boolean} cancel true to cancel the query
6087 * @param {Object} e The query event object
6089 'beforequery': true,
6092 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6093 * @param {Roo.bootstrap.ComboBox} combo This combo box
6098 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6099 * @param {Roo.bootstrap.ComboBox} combo This combo box
6100 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6108 this.selectedIndex = -1;
6109 if(this.mode == 'local'){
6110 if(config.queryDelay === undefined){
6111 this.queryDelay = 10;
6113 if(config.minChars === undefined){
6119 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6122 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6123 * rendering into an Roo.Editor, defaults to false)
6126 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6127 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6130 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6133 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6134 * the dropdown list (defaults to undefined, with no header element)
6138 * @cfg {String/Roo.Template} tpl The template to use to render the output
6142 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6144 listWidth: undefined,
6146 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6147 * mode = 'remote' or 'text' if mode = 'local')
6149 displayField: undefined,
6151 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6152 * mode = 'remote' or 'value' if mode = 'local').
6153 * Note: use of a valueField requires the user make a selection
6154 * in order for a value to be mapped.
6156 valueField: undefined,
6160 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6161 * field's data value (defaults to the underlying DOM element's name)
6163 hiddenName: undefined,
6165 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6169 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6171 selectedClass: 'active',
6174 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6178 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6179 * anchor positions (defaults to 'tl-bl')
6181 listAlign: 'tl-bl?',
6183 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6187 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
6188 * query specified by the allQuery config option (defaults to 'query')
6190 triggerAction: 'query',
6192 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6193 * (defaults to 4, does not apply if editable = false)
6197 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6198 * delay (typeAheadDelay) if it matches a known value (defaults to false)
6202 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6203 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6207 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6208 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
6212 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
6213 * when editable = true (defaults to false)
6215 selectOnFocus:false,
6217 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6219 queryParam: 'query',
6221 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
6222 * when mode = 'remote' (defaults to 'Loading...')
6224 loadingText: 'Loading...',
6226 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6230 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6234 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6235 * traditional select (defaults to true)
6239 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6243 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6247 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6248 * listWidth has a higher value)
6252 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6253 * allow the user to set arbitrary text into the field (defaults to false)
6255 forceSelection:false,
6257 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6258 * if typeAhead = true (defaults to 250)
6260 typeAheadDelay : 250,
6262 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6263 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6265 valueNotFoundText : undefined,
6267 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6272 * @cfg {Boolean} disableClear Disable showing of clear button.
6274 disableClear : false,
6276 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
6278 alwaysQuery : false,
6284 // element that contains real text value.. (when hidden is used..)
6287 initEvents: function(){
6290 throw "can not find store for combo";
6292 this.store = Roo.factory(this.store, Roo.data);
6296 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6299 if(this.hiddenName){
6301 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6303 this.hiddenField.dom.value =
6304 this.hiddenValue !== undefined ? this.hiddenValue :
6305 this.value !== undefined ? this.value : '';
6307 // prevent input submission
6308 this.el.dom.removeAttribute('name');
6309 this.hiddenField.dom.setAttribute('name', this.hiddenName);
6314 // this.el.dom.setAttribute('autocomplete', 'off');
6317 var cls = 'x-combo-list';
6318 this.list = this.el.select('ul',true).first();
6320 //this.list = new Roo.Layer({
6321 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6324 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6325 this.list.setWidth(lw);
6327 this.list.swallowEvent('mousewheel');
6328 this.assetHeight = 0;
6331 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6332 this.assetHeight += this.header.getHeight();
6335 this.innerList = this.list.createChild({cls:cls+'-inner'});
6336 this.innerList.on('mouseover', this.onViewOver, this);
6337 this.innerList.on('mousemove', this.onViewMove, this);
6338 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6340 if(this.allowBlank && !this.pageSize && !this.disableClear){
6341 this.footer = this.list.createChild({cls:cls+'-ft'});
6342 this.pageTb = new Roo.Toolbar(this.footer);
6346 this.footer = this.list.createChild({cls:cls+'-ft'});
6347 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6348 {pageSize: this.pageSize});
6352 if (this.pageTb && this.allowBlank && !this.disableClear) {
6354 this.pageTb.add(new Roo.Toolbar.Fill(), {
6355 cls: 'x-btn-icon x-btn-clear',
6361 _this.onSelect(false, -1);
6366 this.assetHeight += this.footer.getHeight();
6371 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6374 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6375 singleSelect:true, store: this.store, selectedClass: this.selectedClass
6377 //this.view.wrapEl.setDisplayed(false);
6378 this.view.on('click', this.onViewClick, this);
6382 this.store.on('beforeload', this.onBeforeLoad, this);
6383 this.store.on('load', this.onLoad, this);
6384 this.store.on('loadexception', this.onLoadException, this);
6387 this.resizer = new Roo.Resizable(this.list, {
6388 pinned:true, handles:'se'
6390 this.resizer.on('resize', function(r, w, h){
6391 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6393 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6394 this.restrictHeight();
6396 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6400 this.editable = true;
6401 this.setEditable(false);
6406 if (typeof(this.events.add.listeners) != 'undefined') {
6408 this.addicon = this.wrap.createChild(
6409 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
6411 this.addicon.on('click', function(e) {
6412 this.fireEvent('add', this);
6415 if (typeof(this.events.edit.listeners) != 'undefined') {
6417 this.editicon = this.wrap.createChild(
6418 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
6420 this.editicon.setStyle('margin-left', '40px');
6422 this.editicon.on('click', function(e) {
6424 // we fire even if inothing is selected..
6425 this.fireEvent('edit', this, this.lastData );
6432 this.keyNav = new Roo.KeyNav(this.inputEl(), {
6434 this.inKeyMode = true;
6438 "down" : function(e){
6439 if(!this.isExpanded()){
6440 this.onTriggerClick();
6442 this.inKeyMode = true;
6447 "enter" : function(e){
6452 "esc" : function(e){
6456 "tab" : function(e){
6457 this.onViewClick(false);
6458 this.fireEvent("specialkey", this, e);
6464 doRelay : function(foo, bar, hname){
6465 if(hname == 'down' || this.scope.isExpanded()){
6466 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6475 this.queryDelay = Math.max(this.queryDelay || 10,
6476 this.mode == 'local' ? 10 : 250);
6479 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6482 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6484 if(this.editable !== false){
6485 this.inputEl().on("keyup", this.onKeyUp, this);
6487 if(this.forceSelection){
6488 this.on('blur', this.doForce, this);
6492 onDestroy : function(){
6494 this.view.setStore(null);
6495 this.view.el.removeAllListeners();
6496 this.view.el.remove();
6497 this.view.purgeListeners();
6500 this.list.dom.innerHTML = '';
6503 this.store.un('beforeload', this.onBeforeLoad, this);
6504 this.store.un('load', this.onLoad, this);
6505 this.store.un('loadexception', this.onLoadException, this);
6507 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6511 fireKey : function(e){
6512 if(e.isNavKeyPress() && !this.list.isVisible()){
6513 this.fireEvent("specialkey", this, e);
6518 onResize: function(w, h){
6519 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6521 if(typeof w != 'number'){
6522 // we do not handle it!?!?
6525 var tw = this.trigger.getWidth();
6526 // tw += this.addicon ? this.addicon.getWidth() : 0;
6527 // tw += this.editicon ? this.editicon.getWidth() : 0;
6529 this.inputEl().setWidth( this.adjustWidth('input', x));
6531 //this.trigger.setStyle('left', x+'px');
6533 if(this.list && this.listWidth === undefined){
6534 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6535 this.list.setWidth(lw);
6536 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6544 * Allow or prevent the user from directly editing the field text. If false is passed,
6545 * the user will only be able to select from the items defined in the dropdown list. This method
6546 * is the runtime equivalent of setting the 'editable' config option at config time.
6547 * @param {Boolean} value True to allow the user to directly edit the field text
6549 setEditable : function(value){
6550 if(value == this.editable){
6553 this.editable = value;
6555 this.inputEl().dom.setAttribute('readOnly', true);
6556 this.inputEl().on('mousedown', this.onTriggerClick, this);
6557 this.inputEl().addClass('x-combo-noedit');
6559 this.inputEl().dom.setAttribute('readOnly', false);
6560 this.inputEl().un('mousedown', this.onTriggerClick, this);
6561 this.inputEl().removeClass('x-combo-noedit');
6566 onBeforeLoad : function(){
6570 //this.innerList.update(this.loadingText ?
6571 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6572 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6574 this.restrictHeight();
6575 this.selectedIndex = -1;
6579 onLoad : function(){
6583 if(this.store.getCount() > 0){
6585 this.restrictHeight();
6586 if(this.lastQuery == this.allQuery){
6588 this.inputEl().dom.select();
6590 if(!this.selectByValue(this.value, true)){
6591 this.select(0, true);
6595 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6596 this.taTask.delay(this.typeAheadDelay);
6600 this.onEmptyResults();
6605 onLoadException : function()
6608 Roo.log(this.store.reader.jsonData);
6609 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6611 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6617 onTypeAhead : function(){
6618 if(this.store.getCount() > 0){
6619 var r = this.store.getAt(0);
6620 var newValue = r.data[this.displayField];
6621 var len = newValue.length;
6622 var selStart = this.getRawValue().length;
6623 if(selStart != len){
6624 this.setRawValue(newValue);
6625 this.selectText(selStart, newValue.length);
6631 onSelect : function(record, index){
6632 if(this.fireEvent('beforeselect', this, record, index) !== false){
6633 this.setFromData(index > -1 ? record.data : false);
6635 this.fireEvent('select', this, record, index);
6640 * Returns the currently selected field value or empty string if no value is set.
6641 * @return {String} value The selected value
6643 getValue : function(){
6644 if(this.valueField){
6645 return typeof this.value != 'undefined' ? this.value : '';
6647 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6652 * Clears any text/value currently set in the field
6654 clearValue : function(){
6655 if(this.hiddenField){
6656 this.hiddenField.dom.value = '';
6659 this.setRawValue('');
6660 this.lastSelectionText = '';
6665 * Sets the specified value into the field. If the value finds a match, the corresponding record text
6666 * will be displayed in the field. If the value does not match the data value of an existing item,
6667 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6668 * Otherwise the field will be blank (although the value will still be set).
6669 * @param {String} value The value to match
6671 setValue : function(v){
6673 if(this.valueField){
6674 var r = this.findRecord(this.valueField, v);
6676 text = r.data[this.displayField];
6677 }else if(this.valueNotFoundText !== undefined){
6678 text = this.valueNotFoundText;
6681 this.lastSelectionText = text;
6682 if(this.hiddenField){
6683 this.hiddenField.dom.value = v;
6685 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6689 * @property {Object} the last set data for the element
6694 * Sets the value of the field based on a object which is related to the record format for the store.
6695 * @param {Object} value the value to set as. or false on reset?
6697 setFromData : function(o){
6698 var dv = ''; // display value
6699 var vv = ''; // value value..
6701 if (this.displayField) {
6702 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6704 // this is an error condition!!!
6705 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
6708 if(this.valueField){
6709 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6711 if(this.hiddenField){
6712 this.hiddenField.dom.value = vv;
6714 this.lastSelectionText = dv;
6715 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6719 // no hidden field.. - we store the value in 'value', but still display
6720 // display field!!!!
6721 this.lastSelectionText = dv;
6722 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6729 // overridden so that last data is reset..
6730 this.setValue(this.originalValue);
6731 this.clearInvalid();
6732 this.lastData = false;
6734 this.view.clearSelections();
6738 findRecord : function(prop, value){
6740 if(this.store.getCount() > 0){
6741 this.store.each(function(r){
6742 if(r.data[prop] == value){
6754 // returns hidden if it's set..
6755 if (!this.rendered) {return ''};
6756 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
6760 onViewMove : function(e, t){
6761 this.inKeyMode = false;
6765 onViewOver : function(e, t){
6766 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6769 var item = this.view.findItemFromChild(t);
6771 var index = this.view.indexOf(item);
6772 this.select(index, false);
6777 onViewClick : function(doFocus)
6779 var index = this.view.getSelectedIndexes()[0];
6780 var r = this.store.getAt(index);
6782 this.onSelect(r, index);
6784 if(doFocus !== false && !this.blockFocus){
6785 this.inputEl().focus();
6790 restrictHeight : function(){
6791 //this.innerList.dom.style.height = '';
6792 //var inner = this.innerList.dom;
6793 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6794 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6795 //this.list.beginUpdate();
6796 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6797 this.list.alignTo(this.inputEl(), this.listAlign);
6798 //this.list.endUpdate();
6802 onEmptyResults : function(){
6807 * Returns true if the dropdown list is expanded, else false.
6809 isExpanded : function(){
6810 return this.list.isVisible();
6814 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6815 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6816 * @param {String} value The data value of the item to select
6817 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6818 * selected item if it is not currently in view (defaults to true)
6819 * @return {Boolean} True if the value matched an item in the list, else false
6821 selectByValue : function(v, scrollIntoView){
6822 if(v !== undefined && v !== null){
6823 var r = this.findRecord(this.valueField || this.displayField, v);
6825 this.select(this.store.indexOf(r), scrollIntoView);
6833 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
6834 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6835 * @param {Number} index The zero-based index of the list item to select
6836 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6837 * selected item if it is not currently in view (defaults to true)
6839 select : function(index, scrollIntoView){
6840 this.selectedIndex = index;
6841 this.view.select(index);
6842 if(scrollIntoView !== false){
6843 var el = this.view.getNode(index);
6845 //this.innerList.scrollChildIntoView(el, false);
6852 selectNext : function(){
6853 var ct = this.store.getCount();
6855 if(this.selectedIndex == -1){
6857 }else if(this.selectedIndex < ct-1){
6858 this.select(this.selectedIndex+1);
6864 selectPrev : function(){
6865 var ct = this.store.getCount();
6867 if(this.selectedIndex == -1){
6869 }else if(this.selectedIndex != 0){
6870 this.select(this.selectedIndex-1);
6876 onKeyUp : function(e){
6877 if(this.editable !== false && !e.isSpecialKey()){
6878 this.lastKey = e.getKey();
6879 this.dqTask.delay(this.queryDelay);
6884 validateBlur : function(){
6885 return !this.list || !this.list.isVisible();
6889 initQuery : function(){
6890 this.doQuery(this.getRawValue());
6894 doForce : function(){
6895 if(this.el.dom.value.length > 0){
6897 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
6903 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
6904 * query allowing the query action to be canceled if needed.
6905 * @param {String} query The SQL query to execute
6906 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
6907 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
6908 * saved in the current store (defaults to false)
6910 doQuery : function(q, forceAll){
6911 if(q === undefined || q === null){
6920 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
6924 forceAll = qe.forceAll;
6925 if(forceAll === true || (q.length >= this.minChars)){
6926 if(this.lastQuery != q || this.alwaysQuery){
6928 if(this.mode == 'local'){
6929 this.selectedIndex = -1;
6931 this.store.clearFilter();
6933 this.store.filter(this.displayField, q);
6937 this.store.baseParams[this.queryParam] = q;
6939 params: this.getParams(q)
6944 this.selectedIndex = -1;
6951 getParams : function(q){
6953 //p[this.queryParam] = q;
6956 p.limit = this.pageSize;
6962 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
6964 collapse : function(){
6965 if(!this.isExpanded()){
6969 Roo.get(document).un('mousedown', this.collapseIf, this);
6970 Roo.get(document).un('mousewheel', this.collapseIf, this);
6971 if (!this.editable) {
6972 Roo.get(document).un('keydown', this.listKeyPress, this);
6974 this.fireEvent('collapse', this);
6978 collapseIf : function(e){
6979 if(!e.within(this.el) && !e.within(this.el)){
6985 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
6987 expand : function(){
6989 if(this.isExpanded() || !this.hasFocus){
6992 this.list.alignTo(this.inputEl(), this.listAlign);
6994 Roo.get(document).on('mousedown', this.collapseIf, this);
6995 Roo.get(document).on('mousewheel', this.collapseIf, this);
6996 if (!this.editable) {
6997 Roo.get(document).on('keydown', this.listKeyPress, this);
7000 this.fireEvent('expand', this);
7004 // Implements the default empty TriggerField.onTriggerClick function
7005 onTriggerClick : function()
7007 Roo.log('trigger click');
7012 if(this.isExpanded()){
7014 if (!this.blockFocus) {
7015 this.inputEl().focus();
7019 this.hasFocus = true;
7020 if(this.triggerAction == 'all') {
7021 this.doQuery(this.allQuery, true);
7023 this.doQuery(this.getRawValue());
7025 if (!this.blockFocus) {
7026 this.inputEl().focus();
7030 listKeyPress : function(e)
7032 //Roo.log('listkeypress');
7033 // scroll to first matching element based on key pres..
7034 if (e.isSpecialKey()) {
7037 var k = String.fromCharCode(e.getKey()).toUpperCase();
7040 var csel = this.view.getSelectedNodes();
7041 var cselitem = false;
7043 var ix = this.view.indexOf(csel[0]);
7044 cselitem = this.store.getAt(ix);
7045 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7051 this.store.each(function(v) {
7053 // start at existing selection.
7054 if (cselitem.id == v.id) {
7060 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7061 match = this.store.indexOf(v);
7067 if (match === false) {
7068 return true; // no more action?
7071 this.view.select(match);
7072 var sn = Roo.get(this.view.getSelectedNodes()[0])
7073 //sn.scrollIntoView(sn.dom.parentNode, false);
7077 * @cfg {Boolean} grow
7081 * @cfg {Number} growMin
7085 * @cfg {Number} growMax
7094 * Ext JS Library 1.1.1
7095 * Copyright(c) 2006-2007, Ext JS, LLC.
7097 * Originally Released Under LGPL - original licence link has changed is not relivant.
7100 * <script type="text/javascript">
7105 * @extends Roo.util.Observable
7106 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7107 * This class also supports single and multi selection modes. <br>
7108 * Create a data model bound view:
7110 var store = new Roo.data.Store(...);
7112 var view = new Roo.View({
7114 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7117 selectedClass: "ydataview-selected",
7121 // listen for node click?
7122 view.on("click", function(vw, index, node, e){
7123 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7127 dataModel.load("foobar.xml");
7129 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7131 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7132 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7134 * Note: old style constructor is still suported (container, template, config)
7138 * @param {Object} config The config object
7141 Roo.View = function(config, depreciated_tpl, depreciated_config){
7143 if (typeof(depreciated_tpl) == 'undefined') {
7144 // new way.. - universal constructor.
7145 Roo.apply(this, config);
7146 this.el = Roo.get(this.el);
7149 this.el = Roo.get(config);
7150 this.tpl = depreciated_tpl;
7151 Roo.apply(this, depreciated_config);
7153 this.wrapEl = this.el.wrap().wrap();
7154 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7157 if(typeof(this.tpl) == "string"){
7158 this.tpl = new Roo.Template(this.tpl);
7160 // support xtype ctors..
7161 this.tpl = new Roo.factory(this.tpl, Roo);
7173 * @event beforeclick
7174 * Fires before a click is processed. Returns false to cancel the default action.
7175 * @param {Roo.View} this
7176 * @param {Number} index The index of the target node
7177 * @param {HTMLElement} node The target node
7178 * @param {Roo.EventObject} e The raw event object
7180 "beforeclick" : true,
7183 * Fires when a template node is clicked.
7184 * @param {Roo.View} this
7185 * @param {Number} index The index of the target node
7186 * @param {HTMLElement} node The target node
7187 * @param {Roo.EventObject} e The raw event object
7192 * Fires when a template node is double clicked.
7193 * @param {Roo.View} this
7194 * @param {Number} index The index of the target node
7195 * @param {HTMLElement} node The target node
7196 * @param {Roo.EventObject} e The raw event object
7200 * @event contextmenu
7201 * Fires when a template node is right clicked.
7202 * @param {Roo.View} this
7203 * @param {Number} index The index of the target node
7204 * @param {HTMLElement} node The target node
7205 * @param {Roo.EventObject} e The raw event object
7207 "contextmenu" : true,
7209 * @event selectionchange
7210 * Fires when the selected nodes change.
7211 * @param {Roo.View} this
7212 * @param {Array} selections Array of the selected nodes
7214 "selectionchange" : true,
7217 * @event beforeselect
7218 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7219 * @param {Roo.View} this
7220 * @param {HTMLElement} node The node to be selected
7221 * @param {Array} selections Array of currently selected nodes
7223 "beforeselect" : true,
7225 * @event preparedata
7226 * Fires on every row to render, to allow you to change the data.
7227 * @param {Roo.View} this
7228 * @param {Object} data to be rendered (change this)
7230 "preparedata" : true
7238 "click": this.onClick,
7239 "dblclick": this.onDblClick,
7240 "contextmenu": this.onContextMenu,
7244 this.selections = [];
7246 this.cmp = new Roo.CompositeElementLite([]);
7248 this.store = Roo.factory(this.store, Roo.data);
7249 this.setStore(this.store, true);
7252 if ( this.footer && this.footer.xtype) {
7254 var fctr = this.wrapEl.appendChild(document.createElement("div"));
7256 this.footer.dataSource = this.store
7257 this.footer.container = fctr;
7258 this.footer = Roo.factory(this.footer, Roo);
7259 fctr.insertFirst(this.el);
7261 // this is a bit insane - as the paging toolbar seems to detach the el..
7262 // dom.parentNode.parentNode.parentNode
7263 // they get detached?
7267 Roo.View.superclass.constructor.call(this);
7272 Roo.extend(Roo.View, Roo.util.Observable, {
7275 * @cfg {Roo.data.Store} store Data store to load data from.
7280 * @cfg {String|Roo.Element} el The container element.
7285 * @cfg {String|Roo.Template} tpl The template used by this View
7289 * @cfg {String} dataName the named area of the template to use as the data area
7290 * Works with domtemplates roo-name="name"
7294 * @cfg {String} selectedClass The css class to add to selected nodes
7296 selectedClass : "x-view-selected",
7298 * @cfg {String} emptyText The empty text to show when nothing is loaded.
7303 * @cfg {String} text to display on mask (default Loading)
7307 * @cfg {Boolean} multiSelect Allow multiple selection
7309 multiSelect : false,
7311 * @cfg {Boolean} singleSelect Allow single selection
7313 singleSelect: false,
7316 * @cfg {Boolean} toggleSelect - selecting
7318 toggleSelect : false,
7321 * Returns the element this view is bound to.
7322 * @return {Roo.Element}
7331 * Refreshes the view. - called by datachanged on the store. - do not call directly.
7333 refresh : function(){
7336 // if we are using something like 'domtemplate', then
7337 // the what gets used is:
7338 // t.applySubtemplate(NAME, data, wrapping data..)
7339 // the outer template then get' applied with
7340 // the store 'extra data'
7341 // and the body get's added to the
7342 // roo-name="data" node?
7343 // <span class='roo-tpl-{name}'></span> ?????
7347 this.clearSelections();
7350 var records = this.store.getRange();
7351 if(records.length < 1) {
7353 // is this valid?? = should it render a template??
7355 this.el.update(this.emptyText);
7359 if (this.dataName) {
7360 this.el.update(t.apply(this.store.meta)); //????
7361 el = this.el.child('.roo-tpl-' + this.dataName);
7364 for(var i = 0, len = records.length; i < len; i++){
7365 var data = this.prepareData(records[i].data, i, records[i]);
7366 this.fireEvent("preparedata", this, data, i, records[i]);
7367 html[html.length] = Roo.util.Format.trim(
7369 t.applySubtemplate(this.dataName, data, this.store.meta) :
7376 el.update(html.join(""));
7377 this.nodes = el.dom.childNodes;
7378 this.updateIndexes(0);
7382 * Function to override to reformat the data that is sent to
7383 * the template for each node.
7384 * DEPRICATED - use the preparedata event handler.
7385 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7386 * a JSON object for an UpdateManager bound view).
7388 prepareData : function(data, index, record)
7390 this.fireEvent("preparedata", this, data, index, record);
7394 onUpdate : function(ds, record){
7395 this.clearSelections();
7396 var index = this.store.indexOf(record);
7397 var n = this.nodes[index];
7398 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7399 n.parentNode.removeChild(n);
7400 this.updateIndexes(index, index);
7406 onAdd : function(ds, records, index)
7408 this.clearSelections();
7409 if(this.nodes.length == 0){
7413 var n = this.nodes[index];
7414 for(var i = 0, len = records.length; i < len; i++){
7415 var d = this.prepareData(records[i].data, i, records[i]);
7417 this.tpl.insertBefore(n, d);
7420 this.tpl.append(this.el, d);
7423 this.updateIndexes(index);
7426 onRemove : function(ds, record, index){
7427 this.clearSelections();
7428 var el = this.dataName ?
7429 this.el.child('.roo-tpl-' + this.dataName) :
7431 el.dom.removeChild(this.nodes[index]);
7432 this.updateIndexes(index);
7436 * Refresh an individual node.
7437 * @param {Number} index
7439 refreshNode : function(index){
7440 this.onUpdate(this.store, this.store.getAt(index));
7443 updateIndexes : function(startIndex, endIndex){
7444 var ns = this.nodes;
7445 startIndex = startIndex || 0;
7446 endIndex = endIndex || ns.length - 1;
7447 for(var i = startIndex; i <= endIndex; i++){
7448 ns[i].nodeIndex = i;
7453 * Changes the data store this view uses and refresh the view.
7454 * @param {Store} store
7456 setStore : function(store, initial){
7457 if(!initial && this.store){
7458 this.store.un("datachanged", this.refresh);
7459 this.store.un("add", this.onAdd);
7460 this.store.un("remove", this.onRemove);
7461 this.store.un("update", this.onUpdate);
7462 this.store.un("clear", this.refresh);
7463 this.store.un("beforeload", this.onBeforeLoad);
7464 this.store.un("load", this.onLoad);
7465 this.store.un("loadexception", this.onLoad);
7469 store.on("datachanged", this.refresh, this);
7470 store.on("add", this.onAdd, this);
7471 store.on("remove", this.onRemove, this);
7472 store.on("update", this.onUpdate, this);
7473 store.on("clear", this.refresh, this);
7474 store.on("beforeload", this.onBeforeLoad, this);
7475 store.on("load", this.onLoad, this);
7476 store.on("loadexception", this.onLoad, this);
7484 * onbeforeLoad - masks the loading area.
7487 onBeforeLoad : function()
7490 this.el.mask(this.mask ? this.mask : "Loading" );
7492 onLoad : function ()
7499 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7500 * @param {HTMLElement} node
7501 * @return {HTMLElement} The template node
7503 findItemFromChild : function(node){
7504 var el = this.dataName ?
7505 this.el.child('.roo-tpl-' + this.dataName,true) :
7508 if(!node || node.parentNode == el){
7511 var p = node.parentNode;
7512 while(p && p != el){
7513 if(p.parentNode == el){
7522 onClick : function(e){
7523 var item = this.findItemFromChild(e.getTarget());
7525 var index = this.indexOf(item);
7526 if(this.onItemClick(item, index, e) !== false){
7527 this.fireEvent("click", this, index, item, e);
7530 this.clearSelections();
7535 onContextMenu : function(e){
7536 var item = this.findItemFromChild(e.getTarget());
7538 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7543 onDblClick : function(e){
7544 var item = this.findItemFromChild(e.getTarget());
7546 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7550 onItemClick : function(item, index, e)
7552 if(this.fireEvent("beforeclick", this, index, item, e) === false){
7555 if (this.toggleSelect) {
7556 var m = this.isSelected(item) ? 'unselect' : 'select';
7559 _t[m](item, true, false);
7562 if(this.multiSelect || this.singleSelect){
7563 if(this.multiSelect && e.shiftKey && this.lastSelection){
7564 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7566 this.select(item, this.multiSelect && e.ctrlKey);
7567 this.lastSelection = item;
7575 * Get the number of selected nodes.
7578 getSelectionCount : function(){
7579 return this.selections.length;
7583 * Get the currently selected nodes.
7584 * @return {Array} An array of HTMLElements
7586 getSelectedNodes : function(){
7587 return this.selections;
7591 * Get the indexes of the selected nodes.
7594 getSelectedIndexes : function(){
7595 var indexes = [], s = this.selections;
7596 for(var i = 0, len = s.length; i < len; i++){
7597 indexes.push(s[i].nodeIndex);
7603 * Clear all selections
7604 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7606 clearSelections : function(suppressEvent){
7607 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7608 this.cmp.elements = this.selections;
7609 this.cmp.removeClass(this.selectedClass);
7610 this.selections = [];
7612 this.fireEvent("selectionchange", this, this.selections);
7618 * Returns true if the passed node is selected
7619 * @param {HTMLElement/Number} node The node or node index
7622 isSelected : function(node){
7623 var s = this.selections;
7627 node = this.getNode(node);
7628 return s.indexOf(node) !== -1;
7633 * @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
7634 * @param {Boolean} keepExisting (optional) true to keep existing selections
7635 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7637 select : function(nodeInfo, keepExisting, suppressEvent){
7638 if(nodeInfo instanceof Array){
7640 this.clearSelections(true);
7642 for(var i = 0, len = nodeInfo.length; i < len; i++){
7643 this.select(nodeInfo[i], true, true);
7647 var node = this.getNode(nodeInfo);
7648 if(!node || this.isSelected(node)){
7649 return; // already selected.
7652 this.clearSelections(true);
7654 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7655 Roo.fly(node).addClass(this.selectedClass);
7656 this.selections.push(node);
7658 this.fireEvent("selectionchange", this, this.selections);
7666 * @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
7667 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7668 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7670 unselect : function(nodeInfo, keepExisting, suppressEvent)
7672 if(nodeInfo instanceof Array){
7673 Roo.each(this.selections, function(s) {
7674 this.unselect(s, nodeInfo);
7678 var node = this.getNode(nodeInfo);
7679 if(!node || !this.isSelected(node)){
7680 Roo.log("not selected");
7681 return; // not selected.
7685 Roo.each(this.selections, function(s) {
7687 Roo.fly(node).removeClass(this.selectedClass);
7694 this.selections= ns;
7695 this.fireEvent("selectionchange", this, this.selections);
7699 * Gets a template node.
7700 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7701 * @return {HTMLElement} The node or null if it wasn't found
7703 getNode : function(nodeInfo){
7704 if(typeof nodeInfo == "string"){
7705 return document.getElementById(nodeInfo);
7706 }else if(typeof nodeInfo == "number"){
7707 return this.nodes[nodeInfo];
7713 * Gets a range template nodes.
7714 * @param {Number} startIndex
7715 * @param {Number} endIndex
7716 * @return {Array} An array of nodes
7718 getNodes : function(start, end){
7719 var ns = this.nodes;
7721 end = typeof end == "undefined" ? ns.length - 1 : end;
7724 for(var i = start; i <= end; i++){
7728 for(var i = start; i >= end; i--){
7736 * Finds the index of the passed node
7737 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7738 * @return {Number} The index of the node or -1
7740 indexOf : function(node){
7741 node = this.getNode(node);
7742 if(typeof node.nodeIndex == "number"){
7743 return node.nodeIndex;
7745 var ns = this.nodes;
7746 for(var i = 0, len = ns.length; i < len; i++){
7757 * based on jquery fullcalendar
7763 * @class Roo.bootstrap.Calendar
7764 * @extends Roo.bootstrap.Component
7765 * Bootstrap Calendar class
7768 * Create a new Container
7769 * @param {Object} config The config object
7772 Roo.bootstrap.Calendar = function(config){
7773 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7777 * Fires when a date is selected
7778 * @param {DatePicker} this
7779 * @param {Date} date The selected date
7783 * @event monthchange
7784 * Fires when the displayed month changes
7785 * @param {DatePicker} this
7786 * @param {Date} date The selected month
7788 'monthchange': true,
7791 * Fires when mouse over an event
7792 * @param {Calendar} this
7793 * @param {event} Event
7798 * Fires when the mouse leaves an
7799 * @param {Calendar} this
7808 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
7811 * @cfg {Number} startDay
7812 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
7816 getAutoCreate : function(){
7819 fc_button = function(name, corner, style, content ) {
7820 return Roo.apply({},{
7822 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
7824 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
7827 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
7835 style : 'width:100%',
7842 cls : 'fc-header-left',
7844 fc_button('prev', 'left', 'arrow', '‹' ),
7845 fc_button('next', 'right', 'arrow', '›' ),
7846 { tag: 'span', cls: 'fc-header-space' },
7847 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
7855 cls : 'fc-header-center',
7859 cls: 'fc-header-title',
7862 html : 'month / year'
7870 cls : 'fc-header-right',
7872 /* fc_button('month', 'left', '', 'month' ),
7873 fc_button('week', '', '', 'week' ),
7874 fc_button('day', 'right', '', 'day' )
7886 var cal_heads = function() {
7888 // fixme - handle this.
7890 for (var i =0; i < Date.dayNames.length; i++) {
7891 var d = Date.dayNames[i];
7894 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
7895 html : d.substring(0,3)
7899 ret[0].cls += ' fc-first';
7900 ret[6].cls += ' fc-last';
7903 var cal_cell = function(n) {
7906 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
7911 cls: 'fc-day-number',
7915 cls: 'fc-day-content',
7919 style: 'position: relative;' // height: 17px;
7931 var cal_rows = function() {
7934 for (var r = 0; r < 6; r++) {
7941 for (var i =0; i < Date.dayNames.length; i++) {
7942 var d = Date.dayNames[i];
7943 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
7946 row.cn[0].cls+=' fc-first';
7947 row.cn[0].cn[0].style = 'min-height:90px';
7948 row.cn[6].cls+=' fc-last';
7952 ret[0].cls += ' fc-first';
7953 ret[4].cls += ' fc-prev-last';
7954 ret[5].cls += ' fc-last';
7961 cls: 'fc-border-separate',
7962 style : 'width:100%',
7970 cls : 'fc-first fc-last',
7989 style : "position: relative;",
7992 cls : 'fc-view fc-view-month fc-grid',
7993 style : 'position: relative',
7994 unselectable : 'on',
7997 cls : 'fc-event-container',
7998 style : 'position:absolute;z-index:8;top:0;left:0;'
8016 initEvents : function()
8019 throw "can not find store for combo";
8022 this.store = Roo.factory(this.store, Roo.data);
8023 this.store.on('load', this.onLoad, this);
8026 this.cells = this.el.select('.fc-day',true);
8028 this.textNodes = this.el.query('.fc-day-number');
8029 this.cells.addClassOnOver('fc-state-hover');
8031 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8032 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8033 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8034 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8036 this.on('monthchange', this.onMonthChange, this);
8038 this.update(new Date().clearTime());
8041 resize : function() {
8042 var sz = this.el.getSize();
8044 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8045 this.el.select('.fc-day-content div',true).setHeight(34);
8050 showPrevMonth : function(e){
8051 this.update(this.activeDate.add("mo", -1));
8053 showToday : function(e){
8054 this.update(new Date().clearTime());
8057 showNextMonth : function(e){
8058 this.update(this.activeDate.add("mo", 1));
8062 showPrevYear : function(){
8063 this.update(this.activeDate.add("y", -1));
8067 showNextYear : function(){
8068 this.update(this.activeDate.add("y", 1));
8073 update : function(date)
8075 var vd = this.activeDate;
8076 this.activeDate = date;
8078 var t = date.getTime();
8079 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8080 Roo.log('using add remove');
8081 this.cells.removeClass("fc-state-highlight");
8082 this.cells.each(function(c){
8083 if(c.dateValue == t){
8084 c.addClass("fc-state-highlight");
8085 setTimeout(function(){
8086 try{c.dom.firstChild.focus();}catch(e){}
8096 var days = date.getDaysInMonth();
8098 var firstOfMonth = date.getFirstDateOfMonth();
8099 var startingPos = firstOfMonth.getDay()-this.startDay;
8101 if(startingPos < this.startDay){
8105 var pm = date.add("mo", -1);
8106 var prevStart = pm.getDaysInMonth()-startingPos;
8108 this.cells = this.el.select('.fc-day',true);
8109 this.textNodes = this.el.query('.fc-day-number');
8110 this.cells.addClassOnOver('fc-state-hover');
8112 var cells = this.cells.elements;
8113 var textEls = this.textNodes;
8115 Roo.each(cells, function(cell){
8116 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
8119 days += startingPos;
8121 // convert everything to numbers so it's fast
8123 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8124 var today = new Date().clearTime().getTime();
8125 var sel = date.clearTime().getTime();
8126 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8127 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8128 var ddMatch = this.disabledDatesRE;
8129 var ddText = this.disabledDatesText;
8130 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8131 var ddaysText = this.disabledDaysText;
8132 var format = this.format;
8134 var setCellClass = function(cal, cell){
8136 var t = d.getTime();
8140 cell.className += " fc-today";
8141 cell.title = cal.todayText;
8144 cell.className += " fc-state-highlight";
8145 //setTimeout(function(){
8146 // try{cell.firstChild.focus();}catch(e){}
8151 cell.className = " fc-state-disabled";
8152 cell.title = cal.minText;
8156 cell.className = " fc-state-disabled";
8157 cell.title = cal.maxText;
8161 if(ddays.indexOf(d.getDay()) != -1){
8162 cell.title = ddaysText;
8163 cell.className = " fc-state-disabled";
8166 if(ddMatch && format){
8167 var fvalue = d.dateFormat(format);
8168 if(ddMatch.test(fvalue)){
8169 cell.title = ddText.replace("%0", fvalue);
8170 cell.className = " fc-state-disabled";
8174 if (!cell.initialClassName) {
8175 cell.initialClassName = cell.dom.className;
8178 cell.dom.className = cell.initialClassName + ' ' + cell.className;
8183 for(; i < startingPos; i++) {
8184 textEls[i].innerHTML = (++prevStart);
8185 d.setDate(d.getDate()+1);
8187 cells[i].className = "fc-past fc-other-month";
8188 setCellClass(this, cells[i]);
8193 for(; i < days; i++){
8194 intDay = i - startingPos + 1;
8195 textEls[i].innerHTML = (intDay);
8196 d.setDate(d.getDate()+1);
8198 cells[i].className = ''; // "x-date-active";
8199 setCellClass(this, cells[i]);
8203 for(; i < 42; i++) {
8204 textEls[i].innerHTML = (++extraDays);
8205 d.setDate(d.getDate()+1);
8207 cells[i].className = "fc-future fc-other-month";
8208 setCellClass(this, cells[i]);
8211 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8213 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
8215 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
8216 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
8219 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
8220 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
8223 this.fireEvent('monthchange', this, date);
8227 if(!this.internalRender){
8228 var main = this.el.dom.firstChild;
8229 var w = main.offsetWidth;
8230 this.el.setWidth(w + this.el.getBorderWidth("lr"));
8231 Roo.fly(main).setWidth(w);
8232 this.internalRender = true;
8233 // opera does not respect the auto grow header center column
8234 // then, after it gets a width opera refuses to recalculate
8235 // without a second pass
8236 if(Roo.isOpera && !this.secondPass){
8237 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8238 this.secondPass = true;
8239 this.update.defer(10, this, [date]);
8246 findCell : function(dt) {
8247 dt = dt.clearTime().getTime();
8249 this.cells.each(function(c){
8250 //Roo.log("check " +c.dateValue + '?=' + dt);
8251 if(c.dateValue == dt){
8261 findCells : function(ev) {
8262 var s = ev.start.clone().clearTime().getTime();
8263 var e= ev.end.clone().clearTime().getTime();
8265 this.cells.each(function(c){
8266 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8268 if(c.dateValue > e){
8271 if(c.dateValue < s){
8280 findBestRow: function(cells)
8284 for (var i =0 ; i < cells.length;i++) {
8285 ret = Math.max(cells[i].rows || 0,ret);
8292 addItem : function(ev)
8294 // look for vertical location slot in
8295 var cells = this.findCells(ev);
8297 ev.row = this.findBestRow(cells);
8299 // work out the location.
8303 for(var i =0; i < cells.length; i++) {
8311 if (crow.start.getY() == cells[i].getY()) {
8313 crow.end = cells[i];
8329 for (var i = 0; i < cells.length;i++) {
8330 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8334 this.calevents.push(ev);
8337 clearEvents: function() {
8339 if(!this.calevents){
8343 Roo.each(this.cells.elements, function(c){
8347 Roo.each(this.calevents, function(e) {
8348 Roo.each(e.els, function(el) {
8349 el.un('mouseenter' ,this.onEventEnter, this);
8350 el.un('mouseleave' ,this.onEventLeave, this);
8357 renderEvents: function()
8359 // first make sure there is enough space..
8361 this.cells.each(function(c) {
8363 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8366 for (var e = 0; e < this.calevents.length; e++) {
8367 var ev = this.calevents[e];
8368 var cells = ev.cells;
8371 for(var i =0; i < rows.length; i++) {
8374 // how many rows should it span..
8377 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8378 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8380 unselectable : "on",
8383 cls: 'fc-event-inner',
8387 cls: 'fc-event-time',
8388 html : cells.length > 1 ? '' : ev.time
8392 cls: 'fc-event-title',
8393 html : String.format('{0}', ev.title)
8400 cls: 'ui-resizable-handle ui-resizable-e',
8401 html : '  '
8407 cfg.cls += ' fc-event-start';
8409 if ((i+1) == rows.length) {
8410 cfg.cls += ' fc-event-end';
8413 var ctr = this.el.select('.fc-event-container',true).first();
8414 var cg = ctr.createChild(cfg);
8416 cg.on('mouseenter' ,this.onEventEnter, this, ev);
8417 cg.on('mouseleave' ,this.onEventLeave, this, ev);
8421 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8422 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8424 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
8425 cg.setWidth(ebox.right - sbox.x -2);
8433 onEventEnter: function (e, el,event,d) {
8434 this.fireEvent('evententer', this, el, event);
8437 onEventLeave: function (e, el,event,d) {
8438 this.fireEvent('eventleave', this, event);
8441 onMonthChange: function () {
8445 onLoad: function () {
8449 this.calevents = [];
8451 if(this.store.getCount() > 0){
8452 this.store.data.each(function(d){
8454 start: new Date(d.data.start_dt),
8455 end : new Date(d.data.end_dt),
8456 time : d.data.start_time,
8457 title : d.data.title,
8458 description : d.data.description
8463 this.renderEvents();
8476 * @class Roo.bootstrap.Popover
8477 * @extends Roo.bootstrap.Component
8478 * Bootstrap Popover class
8479 * @cfg {String} html contents of the popover (or false to use children..)
8480 * @cfg {String} title of popover (or false to hide)
8481 * @cfg {String} placement how it is placed
8482 * @cfg {String} trigger click || hover (or false to trigger manually)
8483 * @cfg {String} over what (parent or false to trigger manually.)
8486 * Create a new Popover
8487 * @param {Object} config The config object
8490 Roo.bootstrap.Popover = function(config){
8491 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8494 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
8496 title: 'Fill in a title',
8499 placement : 'right',
8500 trigger : 'hover', // hover
8504 getChildContainer : function()
8506 return this.el.select('.popover-content',true).first();
8509 getAutoCreate : function(){
8510 Roo.log('make popover?');
8512 cls : 'popover roo-dynamic',
8513 style: 'display:block',
8519 cls : 'popover-inner',
8523 cls: 'popover-title',
8527 cls : 'popover-content',
8538 setTitle: function(str)
8540 this.el.select('.popover-title',true).first().dom.innerHTML = str;
8542 setContent: function(str)
8544 this.el.select('.popover-content',true).first().dom.innerHTML = str;
8546 // as it get's added to the bottom of the page.
8547 onRender : function(ct, position)
8549 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8551 var cfg = Roo.apply({}, this.getAutoCreate());
8555 cfg.cls += ' ' + this.cls;
8558 cfg.style = this.style;
8560 Roo.log("adding to ")
8561 this.el = Roo.get(document.body).createChild(cfg, position);
8567 initEvents : function()
8569 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8570 this.el.enableDisplayMode('block');
8572 if (this.over === false) {
8575 if (this.triggers === false) {
8578 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8579 var triggers = this.trigger ? this.trigger.split(' ') : [];
8580 Roo.each(triggers, function(trigger) {
8582 if (trigger == 'click') {
8583 on_el.on('click', this.toggle, this);
8584 } else if (trigger != 'manual') {
8585 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
8586 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8588 on_el.on(eventIn ,this.enter, this);
8589 on_el.on(eventOut, this.leave, this);
8600 toggle : function () {
8601 this.hoverState == 'in' ? this.leave() : this.enter();
8604 enter : function () {
8607 clearTimeout(this.timeout);
8609 this.hoverState = 'in'
8611 if (!this.delay || !this.delay.show) {
8616 this.timeout = setTimeout(function () {
8617 if (_t.hoverState == 'in') {
8622 leave : function() {
8623 clearTimeout(this.timeout);
8625 this.hoverState = 'out'
8627 if (!this.delay || !this.delay.hide) {
8632 this.timeout = setTimeout(function () {
8633 if (_t.hoverState == 'out') {
8639 show : function (on_el)
8642 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8645 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8646 if (this.html !== false) {
8647 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8649 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8650 if (!this.title.length) {
8651 this.el.select('.popover-title',true).hide();
8654 var placement = typeof this.placement == 'function' ?
8655 this.placement.call(this, this.el, on_el) :
8658 var autoToken = /\s?auto?\s?/i;
8659 var autoPlace = autoToken.test(placement);
8661 placement = placement.replace(autoToken, '') || 'top';
8665 //this.el.setXY([0,0]);
8667 this.el.dom.style.display='block';
8668 this.el.addClass(placement);
8670 //this.el.appendTo(on_el);
8672 var p = this.getPosition();
8673 var box = this.el.getBox();
8678 var align = Roo.bootstrap.Popover.alignment[placement]
8679 this.el.alignTo(on_el, align[0],align[1]);
8680 //var arrow = this.el.select('.arrow',true).first();
8681 //arrow.set(align[2],
8683 this.el.addClass('in');
8684 this.hoverState = null;
8686 if (this.el.hasClass('fade')) {
8693 this.el.setXY([0,0]);
8694 this.el.removeClass('in');
8701 Roo.bootstrap.Popover.alignment = {
8702 'left' : ['r-l', [-10,0], 'right'],
8703 'right' : ['l-r', [10,0], 'left'],
8704 'bottom' : ['t-b', [0,10], 'top'],
8705 'top' : [ 'b-t', [0,-10], 'bottom']