4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
19 * Do not use directly - it does not do anything..
20 * @param {Object} config The config object
25 Roo.bootstrap.Component = function(config){
26 Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
32 allowDomMove : false, // to stop relocations in parent onRender...
40 initEvents : function() { },
47 // returns the parent component..
48 return Roo.ComponentMgr.get(this.parentId)
54 onRender : function(ct, position)
56 // Roo.log("Call onRender: " + this.xtype);
58 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
61 if (this.el.attr('xtype')) {
62 this.el.dom.removeAttribute('xtype');
71 var cfg = Roo.apply({}, this.getAutoCreate());
74 // fill in the extra attributes
75 if (this.xattr && typeof(this.xattr) =='object') {
76 for (var i in this.xattr) {
77 cfg[i] = this.xattr[i];
82 cfg.cls += ' ' + this.cls;
84 if (this.style) { // fixme needs to support more complex style data.
85 cfg.style = this.style;
87 this.el = ct.createChild(cfg, position);
88 if(this.tabIndex !== undefined){
89 this.el.dom.setAttribute('tabIndex', this.tabIndex);
96 getChildContainer : function()
101 addxtype : function (tree, cntr) {
103 cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
105 // render the element if it's not BODY.
106 if (tree.xtype != 'Body') {
108 cn = Roo.factory(tree);
110 cn.parentType = this.xtype; //??
111 cn.parentId = this.id;
113 // does the container contain child eleemnts with 'xtype' attributes.
114 // that match this xtype..
115 // note - when we render we create these as well..
116 // so we should check to see if body has xtype set.
117 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
119 var echild = Roo.get(this[cntr]()).child('*[xtype]');
121 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
123 //echild.dom.removeAttribute('xtype');
125 Roo.log("missing child for " + this.xtype);
128 cn.render(this[cntr]());
129 // then add the element..
136 if (typeof (tree.menu) != 'undefined') {
137 tree.menu.parentType = cn.xtype;
138 tree.menu.triggerEl = cn.el;
139 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
143 if (!tree.items || !tree.items.length) {
147 var items = tree.items;
150 //Roo.log(items.length);
152 for(var i =0;i < items.length;i++) {
153 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
173 Roo.bootstrap.Body = function(config){
174 Roo.bootstrap.Body.superclass.constructor.call(this, config);
175 this.el = Roo.get(document.body);
178 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
183 onRender : function(ct, position){
186 //this.el.addClass([this.fieldClass, this.cls]);
204 * @class Roo.bootstrap.ButtonGroup
205 * @extends Roo.bootstrap.Component
206 * Bootstrap ButtonGroup class
207 * @cfg {String} size lg | sm | xs (default empty normal)
208 * @cfg {String} align vertical | justified (default none)
209 * @cfg {String} direction up | down (default down)
210 * @cfg {Boolean} toolbar false | true
211 * @cfg {Boolean} btn true | false
216 * @param {Object} config The config object
219 Roo.bootstrap.ButtonGroup = function(config){
220 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
223 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
231 getAutoCreate : function(){
237 cfg.html = this.html || cfg.html;
248 if (['vertical','justified'].indexOf(this.align)!==-1) {
249 cfg.cls = 'btn-group-' + this.align;
251 if (this.align == 'justified') {
252 console.log(this.items);
256 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
257 cfg.cls += ' btn-group-' + this.size;
260 if (this.direction == 'up') {
261 cfg.cls += ' dropup' ;
277 * @class Roo.bootstrap.Button
278 * @extends Roo.bootstrap.Component
279 * Bootstrap Button class
280 * @cfg {String} html The button content
281 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
282 * @cfg {String} size empty | lg | sm | xs
283 * @cfg {String} tag empty | a | input | submit
284 * @cfg {String} href empty or href
285 * @cfg {Boolean} disabled false | true
286 * @cfg {Boolean} isClose false | true
287 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
288 * @cfg {String} badge text for badge
289 * @cfg {String} theme default (or empty) | glow
290 * @cfg {Boolean} inverse false | true
291 * @cfg {Boolean} toggle false | true
292 * @cfg {String} ontext text for on toggle state
293 * @cfg {String} offtext text for off toggle state
294 * @cfg {Boolean} defaulton true | false
297 * Create a new button
298 * @param {Object} config The config object
302 Roo.bootstrap.Button = function(config){
303 Roo.bootstrap.Button.superclass.constructor.call(this, config);
308 * The raw click event for the entire grid.
309 * @param {Roo.EventObject} e
315 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
334 getAutoCreate : function(){
342 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
343 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
348 cfg.html = this.html || cfg.html;
350 if (this.toggle===true) {
353 cls: 'slider-frame roo-button',
358 'data-off-text':'OFF',
359 cls: 'slider-button',
365 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
366 cfg.cls += ' '+this.weight;
375 cfg["aria-hidden"] = true;
377 cfg.html = "×";
383 if (this.theme==='default') {
384 cfg.cls = 'btn roo-button';
386 if (this.parentType != 'Navbar') {
387 this.weight = this.weight.length ? this.weight : 'default';
389 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
391 cfg.cls += ' btn-' + this.weight;
393 } else if (this.theme==='glow') {
396 cfg.cls = 'btn-glow roo-button';
398 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
400 cfg.cls += ' ' + this.weight;
406 this.cls += ' inverse';
411 cfg.cls += ' active';
414 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
416 //gsRoo.log(this.parentType);
417 if (this.parentType === 'Navbar') {
425 href : this.href || '#'
428 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
429 cfg.cls += ' dropdown';
434 } else if (this.menu) {
436 cfg.cls += ' dropdown test';
442 cfg.disabled = 'disabled';
446 Roo.log('changing to ul' );
448 this.glyphicon = 'caret';
451 if (this.glyphicon) {
452 cfg.html = ' ' + cfg.html;
457 cls: 'glyphicon glyphicon-' + this.glyphicon
467 cfg.cls='btn roo-button';
483 if (cfg.tag !== 'a' && this.href !== '') {
484 throw "Tag must be a to set href.";
485 } else if (this.href.length > 0) {
486 cfg.href = this.href;
491 initEvents: function() {
492 // Roo.log('init events?');
493 // Roo.log(this.el.dom);
494 if (this.el.hasClass('roo-button')) {
495 this.el.on('click', this.onClick, this);
497 this.el.select('.roo-button').on('click', this.onClick, this);
503 onClick : function(e)
505 Roo.log('button on click ');
507 this.fireEvent('click', this, e);
521 * @class Roo.bootstrap.Column
522 * @extends Roo.bootstrap.Component
523 * Bootstrap Column class
524 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
525 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
526 * @cfg {Number} md colspan out of 12 for computer-sized screens
527 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
528 * @cfg {String} html content of column.
531 * Create a new Column
532 * @param {Object} config The config object
535 Roo.bootstrap.Column = function(config){
536 Roo.bootstrap.Column.superclass.constructor.call(this, config);
539 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
548 getAutoCreate : function(){
549 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
557 ['xs','sm','md','lg'].map(function(size){
558 if (settings[size]) {
559 cfg.cls += ' col-' + size + '-' + settings[size];
562 if (this.html.length) {
563 cfg.html = this.html;
582 * @class Roo.bootstrap.Container
583 * @extends Roo.bootstrap.Component
584 * Bootstrap Container class
585 * @cfg {Boolean} jumbotron is it a jumbotron element
586 * @cfg {String} html content of element
587 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
588 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
589 * @cfg {String} header content of header (for panel)
590 * @cfg {String} footer content of footer (for panel)
591 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
594 * Create a new Container
595 * @param {Object} config The config object
598 Roo.bootstrap.Container = function(config){
599 Roo.bootstrap.Container.superclass.constructor.call(this, config);
602 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
612 getChildContainer : function() {
613 if (this.panel.length) {
614 return this.el.select('.panel-body',true).first();
621 getAutoCreate : function(){
627 if (this.jumbotron) {
628 cfg.cls = 'jumbotron';
631 cfg.cls = this.cls + '';
634 if (this.sticky.length) {
635 var bd = Roo.get(document.body);
636 if (!bd.hasClass('bootstrap-sticky')) {
637 bd.addClass('bootstrap-sticky');
638 Roo.select('html',true).setStyle('height', '100%');
641 cfg.cls += 'bootstrap-sticky-' + this.sticky;
645 if (this.well.length) {
649 cfg.cls +=' well well-' +this.well;
659 if (this.panel.length) {
660 cfg.cls += 'panel panel-' + this.panel;
662 if (this.header.length) {
665 cls : 'panel-heading',
681 if (this.footer.length) {
683 cls : 'panel-footer',
691 body.html = this.html || cfg.html;
693 if (!cfg.cls.length) {
694 cfg.cls = 'container';
711 * @class Roo.bootstrap.Img
712 * @extends Roo.bootstrap.Component
713 * Bootstrap Img class
714 * @cfg {Boolean} imgResponsive false | true
715 * @cfg {String} border rounded | circle | thumbnail
716 * @cfg {String} src image source
717 * @cfg {String} alt image alternative text
721 * @param {Object} config The config object
724 Roo.bootstrap.Img = function(config){
725 Roo.bootstrap.Img.superclass.constructor.call(this, config);
728 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
734 getAutoCreate : function(){
738 cls: 'img-responsive',
742 cfg.html = this.html || cfg.html;
744 cfg.src = this.src || cfg.src;
746 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
747 cfg.cls += ' img-' + this.border;
767 * @class Roo.bootstrap.Header
768 * @extends Roo.bootstrap.Component
769 * Bootstrap Header class
770 * @cfg {String} html content of header
771 * @cfg {Number} level (1|2|3|4|5|6) default 1
774 * Create a new Header
775 * @param {Object} config The config object
779 Roo.bootstrap.Header = function(config){
780 Roo.bootstrap.Header.superclass.constructor.call(this, config);
783 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
791 getAutoCreate : function(){
794 tag: 'h' + (1 *this.level),
795 html: this.html || 'fill in html'
813 * @class Roo.bootstrap.Menu
814 * @extends Roo.bootstrap.Component
815 * Bootstrap Menu class - container for MenuItems
816 * @cfg {String} type type of menu
820 * @param {Object} config The config object
824 Roo.bootstrap.Menu = function(config){
825 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
828 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
836 getChildContainer : function() {
840 getAutoCreate : function(){
842 //if (['right'].indexOf(this.align)!==-1) {
843 // cfg.cn[1].cls += ' pull-right'
847 cls : 'dropdown-menu'
851 if (this.type==='submenu') {
852 cfg.cls='submenu active'
857 initEvents : function() {
858 // Roo.log("ADD event");
859 // Roo.log(this.triggerEl.dom);
860 this.triggerEl.on('click', this.toggle, this);
861 this.triggerEl.addClass('dropdown-toggle');
866 //Roo.log(e.getTarget());
867 // Roo.log(this.triggerEl.dom);
868 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
871 var isActive = this.triggerEl.hasClass('open');
872 // if disabled.. ingore
874 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
875 // if mobile we use a backdrop because click events don't delegate
876 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
879 //var relatedTarget = { relatedTarget: this }
880 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
882 //if (e.isDefaultPrevented()) return;
884 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
886 // .trigger('shown.bs.dropdown', relatedTarget)
888 this.triggerEl.focus();
894 clearMenus : function()
896 //$(backdrop).remove()
897 Roo.select('.dropdown-toggle',true).each(function(aa) {
898 if (!aa.hasClass('open')) {
902 aa.removeClass('open');
903 //var parent = getParent($(this))
904 //var relatedTarget = { relatedTarget: this }
906 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
907 //if (e.isDefaultPrevented()) return
908 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
926 * @class Roo.bootstrap.MenuItem
927 * @extends Roo.bootstrap.Component
928 * Bootstrap MenuItem class
929 * @cfg {String} html the menu label
930 * @cfg {String} href the link
934 * Create a new MenuItem
935 * @param {Object} config The config object
939 Roo.bootstrap.MenuItem = function(config){
940 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
943 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
948 getAutoCreate : function(){
960 cfg.cn[0].href = this.href || cfg.cn[0].href ;
961 cfg.cn[0].html = this.html || cfg.cn[0].html ;
978 * @class Roo.bootstrap.MenuSeparator
979 * @extends Roo.bootstrap.Component
980 * Bootstrap MenuSeparator class
983 * Create a new MenuItem
984 * @param {Object} config The config object
988 Roo.bootstrap.MenuSeparator = function(config){
989 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
992 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
994 getAutoCreate : function(){
1009 <div class="modal fade">
1010 <div class="modal-dialog">
1011 <div class="modal-content">
1012 <div class="modal-header">
1013 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1014 <h4 class="modal-title">Modal title</h4>
1016 <div class="modal-body">
1017 <p>One fine body…</p>
1019 <div class="modal-footer">
1020 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1021 <button type="button" class="btn btn-primary">Save changes</button>
1023 </div><!-- /.modal-content -->
1024 </div><!-- /.modal-dialog -->
1025 </div><!-- /.modal -->
1035 * @class Roo.bootstrap.Modal
1036 * @extends Roo.bootstrap.Component
1037 * Bootstrap Modal class
1038 * @cfg {String} title Title of dialog
1039 * @cfg {Array} buttons Array of buttons or standard button set..
1042 * Create a new Modal Dialog
1043 * @param {Object} config The config object
1046 Roo.bootstrap.Modal = function(config){
1047 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1052 * The raw click event for the entire grid.
1053 * @param {Roo.EventObject} e
1059 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1061 title : 'test dialog',
1065 onRender : function(ct, position)
1067 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1069 var cfg = Roo.apply({}, this.getAutoCreate());
1072 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1074 //if (!cfg.name.length) {
1078 cfg.cls += ' ' + this.cls;
1081 cfg.style = this.style;
1083 this.el = Roo.get(document.body).createChild(cfg, position);
1085 //var type = this.el.dom.type;
1087 if(this.tabIndex !== undefined){
1088 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1093 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1094 this.maskEl.enableDisplayMode("block");
1096 //this.el.addClass("x-dlg-modal");
1100 Roo.each(this.buttons, function(bb) {
1101 b = Roo.apply({}, bb);
1102 b.xns = b.xns || Roo.bootstrap;
1103 b.xtype = b.xtype || 'Button';
1104 if (typeof(b.listeners) == 'undefined') {
1105 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1108 var btn = Roo.factory(b);
1110 btn.onRender(this.el.select('.modal-footer').first());
1118 //this.el.addClass([this.fieldClass, this.cls]);
1121 getAutoCreate : function(){
1126 html : this.html || ''
1134 cls: "modal-dialog",
1137 cls : "modal-content",
1140 cls : 'modal-header',
1149 cls : 'modal-title',
1157 cls : 'modal-footer'
1173 getChildContainer : function() {
1175 return this.el.select('.modal-body',true).first();
1178 getButtonContainer : function() {
1179 return this.el.select('.modal-footer',true).first();
1182 initEvents : function()
1184 this.el.select('.modal-header .close').on('click', this.hide, this);
1187 if (!this.rendered) {
1191 this.el.addClass('on');
1192 this.el.removeClass('fade');
1193 this.el.setStyle('display', 'block');
1194 Roo.get(document.body).addClass("x-body-masked");
1195 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1197 this.el.setStyle('zIndex', '10001');
1204 this.el.removeClass('on');
1205 this.el.addClass('fade');
1206 this.el.setStyle('display', 'none');
1208 onButtonClick: function(btn,e)
1211 this.fireEvent('btnclick', btn.name, e);
1216 Roo.apply(Roo.bootstrap.Modal, {
1218 * Button config that displays a single OK button
1227 * Button config that displays Yes and No buttons
1243 * Button config that displays OK and Cancel buttons
1258 * Button config that displays Yes, No and Cancel buttons
1286 * @class Roo.bootstrap.Navbar
1287 * @extends Roo.bootstrap.Component
1288 * Bootstrap Navbar class
1289 * @cfg {Boolean} sidebar has side bar
1290 * @cfg {Boolean} bar is a bar?
1291 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1292 * @cfg {String} brand what is brand
1293 * @cfg {Boolean} inverse is inverted color
1294 * @cfg {String} type (nav | pills | tabs)
1295 * @cfg {Boolean} arrangement stacked | justified
1296 * @cfg {String} align (left | right) alignment
1300 * Create a new Navbar
1301 * @param {Object} config The config object
1305 Roo.bootstrap.Navbar = function(config){
1306 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1309 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1321 getAutoCreate : function(){
1326 if (this.sidebar === true) {
1334 if (this.bar === true) {
1342 cls: 'navbar-header',
1347 cls: 'navbar-toggle',
1348 'data-toggle': 'collapse',
1353 html: 'Toggle navigation'
1373 cls: 'collapse navbar-collapse'
1378 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1380 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1381 cfg.cls += ' navbar-' + this.position;
1382 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1385 if (this.brand !== '') {
1389 cls: 'navbar-brand',
1398 } else if (this.bar === false) {
1401 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1411 if (['tabs','pills'].indexOf(this.type)!==-1) {
1412 cfg.cn[0].cls += ' nav-' + this.type
1414 if (this.type!=='nav') {
1415 Roo.log('nav type must be nav/tabs/pills')
1417 cfg.cn[0].cls += ' navbar-nav'
1420 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1421 cfg.cn[0].cls += ' nav-' + this.arrangement;
1424 if (this.align === 'right') {
1425 cfg.cn[0].cls += ' navbar-right';
1428 cfg.cls += ' navbar-inverse';
1436 initEvents :function ()
1438 //Roo.log(this.el.select('.navbar-toggle',true));
1439 this.el.select('.navbar-toggle',true).on('click', function() {
1440 // Roo.log('click');
1441 this.el.select('.navbar-collapse',true).toggleClass('in');
1446 getChildContainer : function()
1448 if (this.bar === true) {
1449 return this.el.select('.collapse',true).first();
1467 * @class Roo.bootstrap.NavGroup
1468 * @extends Roo.bootstrap.Component
1469 * Bootstrap NavGroup class
1470 * @cfg {String} align left | right
1471 * @cfg {Boolean} inverse false | true
1474 * Create a new nav group
1475 * @param {Object} config The config object
1478 Roo.bootstrap.NavGroup = function(config){
1479 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1482 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1488 getAutoCreate : function(){
1489 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1493 cls: 'nav navbar-nav'
1496 if (this.parent().sidebar === true) {
1499 cls: 'dashboard-menu'
1505 if (this.form === true) {
1511 if (this.align === 'right') {
1512 cfg.cls += ' navbar-right';
1514 cfg.cls += ' navbar-left';
1519 if (this.align === 'right') {
1520 cfg.cls += ' navbar-right';
1524 cfg.cls += ' navbar-inverse';
1544 * @class Roo.bootstrap.Navbar.Item
1545 * @extends Roo.bootstrap.Component
1546 * Bootstrap Navbar.Button class
1547 * @cfg {String} href link to
1548 * @cfg {String} html content of button
1549 * @cfg {String} badge text inside badge
1550 * @cfg {String} glyphicon name of glyphicon
1553 * Create a new Navbar Button
1554 * @param {Object} config The config object
1556 Roo.bootstrap.Navbar.Item = function(config){
1557 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1560 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1568 getAutoCreate : function(){
1570 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1572 if (this.parent().parent().sidebar === true) {
1585 cfg.cn[0].html = this.html;
1589 this.cls += ' active';
1593 cfg.cn[0].cls += ' dropdown-toggle';
1594 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1598 cfg.cn[0].tag = 'a',
1599 cfg.cn[0].href = this.href;
1602 if (this.glyphicon) {
1603 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1619 if (this.glyphicon) {
1620 if(cfg.html){cfg.html = ' ' + this.html};
1624 cls: 'glyphicon glyphicon-' + this.glyphicon
1629 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1633 cfg.cn[0].html += " <span class='caret'></span>";
1634 //}else if (!this.href) {
1635 // cfg.cn[0].tag='p';
1636 // cfg.cn[0].cls='navbar-text';
1639 cfg.cn[0].href=this.href||'#';
1640 cfg.cn[0].html=this.html;
1643 if (this.badge !== '') {
1646 cfg.cn[0].html + ' ',
1659 initEvents: function() {
1660 // Roo.log('init events?');
1661 // Roo.log(this.el.dom);
1662 this.el.select('a',true).on('click',
1664 this.fireEvent('click', this);
1681 * @class Roo.bootstrap.Row
1682 * @extends Roo.bootstrap.Component
1683 * Bootstrap Row class (contains columns...)
1687 * @param {Object} config The config object
1690 Roo.bootstrap.Row = function(config){
1691 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1694 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1696 getAutoCreate : function(){
1715 * @class Roo.bootstrap.Element
1716 * @extends Roo.bootstrap.Component
1717 * Bootstrap Element class
1718 * @cfg {String} html contents of the element
1719 * @cfg {String} tag tag of the element
1720 * @cfg {String} cls class of the element
1723 * Create a new Element
1724 * @param {Object} config The config object
1727 Roo.bootstrap.Element = function(config){
1728 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1731 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1738 getAutoCreate : function(){
1761 * @class Roo.bootstrap.Pagination
1762 * @extends Roo.bootstrap.Component
1763 * Bootstrap Pagination class
1764 * @cfg {String} size xs | sm | md | lg
1765 * @cfg {Boolean} inverse false | true
1766 * @cfg {Number} from pagination starting number
1767 * @cfg {Number} to pagination ending number
1768 * @cfg {String} align empty or left | right
1769 * @cfg {Number} active active page number
1772 * Create a new Pagination
1773 * @param {Object} config The config object
1776 Roo.bootstrap.Pagination = function(config){
1777 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1780 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1790 getAutoCreate : function(){
1797 cfg.cls += ' inverse';
1815 var from=this.from>0?this.from:1;
1816 var to=this.to-from<=10?this.to:from+10;
1817 var active=this.active>=from&&this.active<=to?this.active:null;
1818 for (var i=from;i<=to;i++) {
1822 cls: active===i?'active':'',
1863 * @class Roo.bootstrap.Slider
1864 * @extends Roo.bootstrap.Component
1865 * Bootstrap Slider class
1868 * Create a new Slider
1869 * @param {Object} config The config object
1872 Roo.bootstrap.Slider = function(config){
1873 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1876 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
1878 getAutoCreate : function(){
1882 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1886 cls: 'ui-slider-handle ui-state-default ui-corner-all'
1904 * @class Roo.bootstrap.Table
1905 * @extends Roo.bootstrap.Component
1906 * Bootstrap Table class
1909 * Create a new Table
1910 * @param {Object} config The config object
1913 Roo.bootstrap.Table = function(config){
1914 Roo.bootstrap.Table.superclass.constructor.call(this, config);
1917 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
1922 getAutoCreate : function(){
1923 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
1955 * @class Roo.bootstrap.TableCell
1956 * @extends Roo.bootstrap.Component
1957 * Bootstrap TableCell class
1960 * Create a new TableCell
1961 * @param {Object} config The config object
1964 Roo.bootstrap.TableCell = function(config){
1965 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
1968 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
1970 getAutoCreate : function(){
1971 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
1998 * @class Roo.bootstrap.TableRow
1999 * @extends Roo.bootstrap.Component
2000 * Bootstrap TableRow class
2003 * Create a new TableRow
2004 * @param {Object} config The config object
2007 Roo.bootstrap.TableRow = function(config){
2008 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2011 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2013 getAutoCreate : function(){
2014 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2029 * Ext JS Library 1.1.1
2030 * Copyright(c) 2006-2007, Ext JS, LLC.
2032 * Originally Released Under LGPL - original licence link has changed is not relivant.
2035 * <script type="text/javascript">
2038 // as we use this in bootstrap.
2039 Roo.namespace('Roo.form');
2041 * @class Roo.form.Action
2042 * Internal Class used to handle form actions
2044 * @param {Roo.form.BasicForm} el The form element or its id
2045 * @param {Object} config Configuration options
2050 // define the action interface
2051 Roo.form.Action = function(form, options){
2053 this.options = options || {};
2056 * Client Validation Failed
2059 Roo.form.Action.CLIENT_INVALID = 'client';
2061 * Server Validation Failed
2064 Roo.form.Action.SERVER_INVALID = 'server';
2066 * Connect to Server Failed
2069 Roo.form.Action.CONNECT_FAILURE = 'connect';
2071 * Reading Data from Server Failed
2074 Roo.form.Action.LOAD_FAILURE = 'load';
2076 Roo.form.Action.prototype = {
2078 failureType : undefined,
2079 response : undefined,
2083 run : function(options){
2088 success : function(response){
2093 handleResponse : function(response){
2097 // default connection failure
2098 failure : function(response){
2100 this.response = response;
2101 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2102 this.form.afterAction(this, false);
2105 processResponse : function(response){
2106 this.response = response;
2107 if(!response.responseText){
2110 this.result = this.handleResponse(response);
2114 // utility functions used internally
2115 getUrl : function(appendParams){
2116 var url = this.options.url || this.form.url || this.form.el.dom.action;
2118 var p = this.getParams();
2120 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2126 getMethod : function(){
2127 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2130 getParams : function(){
2131 var bp = this.form.baseParams;
2132 var p = this.options.params;
2134 if(typeof p == "object"){
2135 p = Roo.urlEncode(Roo.applyIf(p, bp));
2136 }else if(typeof p == 'string' && bp){
2137 p += '&' + Roo.urlEncode(bp);
2140 p = Roo.urlEncode(bp);
2145 createCallback : function(){
2147 success: this.success,
2148 failure: this.failure,
2150 timeout: (this.form.timeout*1000),
2151 upload: this.form.fileUpload ? this.success : undefined
2156 Roo.form.Action.Submit = function(form, options){
2157 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2160 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2163 haveProgress : false,
2164 uploadComplete : false,
2166 // uploadProgress indicator.
2167 uploadProgress : function()
2169 if (!this.form.progressUrl) {
2173 if (!this.haveProgress) {
2174 Roo.MessageBox.progress("Uploading", "Uploading");
2176 if (this.uploadComplete) {
2177 Roo.MessageBox.hide();
2181 this.haveProgress = true;
2183 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2185 var c = new Roo.data.Connection();
2187 url : this.form.progressUrl,
2192 success : function(req){
2193 //console.log(data);
2197 rdata = Roo.decode(req.responseText)
2199 Roo.log("Invalid data from server..");
2203 if (!rdata || !rdata.success) {
2205 Roo.MessageBox.alert(Roo.encode(rdata));
2208 var data = rdata.data;
2210 if (this.uploadComplete) {
2211 Roo.MessageBox.hide();
2216 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2217 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2220 this.uploadProgress.defer(2000,this);
2223 failure: function(data) {
2224 Roo.log('progress url failed ');
2235 // run get Values on the form, so it syncs any secondary forms.
2236 this.form.getValues();
2238 var o = this.options;
2239 var method = this.getMethod();
2240 var isPost = method == 'POST';
2241 if(o.clientValidation === false || this.form.isValid()){
2243 if (this.form.progressUrl) {
2244 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2245 (new Date() * 1) + '' + Math.random());
2250 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2251 form:this.form.el.dom,
2252 url:this.getUrl(!isPost),
2254 params:isPost ? this.getParams() : null,
2255 isUpload: this.form.fileUpload
2258 this.uploadProgress();
2260 }else if (o.clientValidation !== false){ // client validation failed
2261 this.failureType = Roo.form.Action.CLIENT_INVALID;
2262 this.form.afterAction(this, false);
2266 success : function(response)
2268 this.uploadComplete= true;
2269 if (this.haveProgress) {
2270 Roo.MessageBox.hide();
2274 var result = this.processResponse(response);
2275 if(result === true || result.success){
2276 this.form.afterAction(this, true);
2280 this.form.markInvalid(result.errors);
2281 this.failureType = Roo.form.Action.SERVER_INVALID;
2283 this.form.afterAction(this, false);
2285 failure : function(response)
2287 this.uploadComplete= true;
2288 if (this.haveProgress) {
2289 Roo.MessageBox.hide();
2292 this.response = response;
2293 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2294 this.form.afterAction(this, false);
2297 handleResponse : function(response){
2298 if(this.form.errorReader){
2299 var rs = this.form.errorReader.read(response);
2302 for(var i = 0, len = rs.records.length; i < len; i++) {
2303 var r = rs.records[i];
2307 if(errors.length < 1){
2311 success : rs.success,
2317 ret = Roo.decode(response.responseText);
2321 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2331 Roo.form.Action.Load = function(form, options){
2332 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2333 this.reader = this.form.reader;
2336 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2341 Roo.Ajax.request(Roo.apply(
2342 this.createCallback(), {
2343 method:this.getMethod(),
2344 url:this.getUrl(false),
2345 params:this.getParams()
2349 success : function(response){
2351 var result = this.processResponse(response);
2352 if(result === true || !result.success || !result.data){
2353 this.failureType = Roo.form.Action.LOAD_FAILURE;
2354 this.form.afterAction(this, false);
2357 this.form.clearInvalid();
2358 this.form.setValues(result.data);
2359 this.form.afterAction(this, true);
2362 handleResponse : function(response){
2363 if(this.form.reader){
2364 var rs = this.form.reader.read(response);
2365 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2367 success : rs.success,
2371 return Roo.decode(response.responseText);
2375 Roo.form.Action.ACTION_TYPES = {
2376 'load' : Roo.form.Action.Load,
2377 'submit' : Roo.form.Action.Submit
2386 * @class Roo.bootstrap.Form
2387 * @extends Roo.bootstrap.Component
2388 * Bootstrap Form class
2389 * @cfg {String} method GET | POST (default POST)
2390 * @cfg {String} labelAlign top | left (default top)
2391 * @cfg {String} align left | right - for navbars
2396 * @param {Object} config The config object
2400 Roo.bootstrap.Form = function(config){
2401 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2404 * @event clientvalidation
2405 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2406 * @param {Form} this
2407 * @param {Boolean} valid true if the form has passed client-side validation
2409 clientvalidation: true,
2411 * @event beforeaction
2412 * Fires before any action is performed. Return false to cancel the action.
2413 * @param {Form} this
2414 * @param {Action} action The action to be performed
2418 * @event actionfailed
2419 * Fires when an action fails.
2420 * @param {Form} this
2421 * @param {Action} action The action that failed
2423 actionfailed : true,
2425 * @event actioncomplete
2426 * Fires when an action is completed.
2427 * @param {Form} this
2428 * @param {Action} action The action that completed
2430 actioncomplete : true
2435 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2438 * @cfg {String} method
2439 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2444 * The URL to use for form actions if one isn't supplied in the action options.
2447 * @cfg {Boolean} fileUpload
2448 * Set to true if this form is a file upload.
2452 * @cfg {Object} baseParams
2453 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2457 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2461 * @cfg {Sting} align (left|right) for navbar forms
2466 activeAction : null,
2469 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2470 * element by passing it or its id or mask the form itself by passing in true.
2473 waitMsgTarget : false,
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.
2483 getAutoCreate : function(){
2487 method : this.method || 'POST',
2488 id : this.id || Roo.id(),
2491 if (this.parent().xtype.match(/^Nav/)) {
2492 cfg.cls = 'navbar-form navbar-' + this.align;
2496 if (this.labelAlign == 'left' ) {
2497 cfg.cls += ' form-horizontal';
2503 initEvents : function()
2505 this.el.on('submit', this.onSubmit, this);
2510 onSubmit : function(e){
2515 * Returns true if client-side validation on the form is successful.
2518 isValid : function(){
2519 var items = this.getItems();
2521 items.each(function(f){
2530 * Returns true if any fields in this form have changed since their original load.
2533 isDirty : function(){
2535 var items = this.getItems();
2536 items.each(function(f){
2546 * Performs a predefined action (submit or load) or custom actions you define on this form.
2547 * @param {String} actionName The name of the action type
2548 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2549 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2550 * accept other config options):
2552 Property Type Description
2553 ---------------- --------------- ----------------------------------------------------------------------------------
2554 url String The url for the action (defaults to the form's url)
2555 method String The form method to use (defaults to the form's method, or POST if not defined)
2556 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2557 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2558 validate the form on the client (defaults to false)
2560 * @return {BasicForm} this
2562 doAction : function(action, options){
2563 if(typeof action == 'string'){
2564 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2566 if(this.fireEvent('beforeaction', this, action) !== false){
2567 this.beforeAction(action);
2568 action.run.defer(100, action);
2574 beforeAction : function(action){
2575 var o = action.options;
2577 // not really supported yet.. ??
2579 //if(this.waitMsgTarget === true){
2580 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2581 //}else if(this.waitMsgTarget){
2582 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2583 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2585 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2591 afterAction : function(action, success){
2592 this.activeAction = null;
2593 var o = action.options;
2595 //if(this.waitMsgTarget === true){
2597 //}else if(this.waitMsgTarget){
2598 // this.waitMsgTarget.unmask();
2600 // Roo.MessageBox.updateProgress(1);
2601 // Roo.MessageBox.hide();
2608 Roo.callback(o.success, o.scope, [this, action]);
2609 this.fireEvent('actioncomplete', this, action);
2613 // failure condition..
2614 // we have a scenario where updates need confirming.
2615 // eg. if a locking scenario exists..
2616 // we look for { errors : { needs_confirm : true }} in the response.
2618 (typeof(action.result) != 'undefined') &&
2619 (typeof(action.result.errors) != 'undefined') &&
2620 (typeof(action.result.errors.needs_confirm) != 'undefined')
2623 Roo.log("not supported yet");
2626 Roo.MessageBox.confirm(
2627 "Change requires confirmation",
2628 action.result.errorMsg,
2633 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2643 Roo.callback(o.failure, o.scope, [this, action]);
2644 // show an error message if no failed handler is set..
2645 if (!this.hasListener('actionfailed')) {
2646 Roo.log("need to add dialog support");
2648 Roo.MessageBox.alert("Error",
2649 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2650 action.result.errorMsg :
2651 "Saving Failed, please check your entries or try again"
2656 this.fireEvent('actionfailed', this, action);
2661 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2662 * @param {String} id The value to search for
2665 findField : function(id){
2666 var items = this.getItems();
2667 var field = items.get(id);
2669 items.each(function(f){
2670 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2677 return field || null;
2680 * Mark fields in this form invalid in bulk.
2681 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2682 * @return {BasicForm} this
2684 markInvalid : function(errors){
2685 if(errors instanceof Array){
2686 for(var i = 0, len = errors.length; i < len; i++){
2687 var fieldError = errors[i];
2688 var f = this.findField(fieldError.id);
2690 f.markInvalid(fieldError.msg);
2696 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2697 field.markInvalid(errors[id]);
2701 //Roo.each(this.childForms || [], function (f) {
2702 // f.markInvalid(errors);
2709 * Set values for fields in this form in bulk.
2710 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2711 * @return {BasicForm} this
2713 setValues : function(values){
2714 if(values instanceof Array){ // array of objects
2715 for(var i = 0, len = values.length; i < len; i++){
2717 var f = this.findField(v.id);
2719 f.setValue(v.value);
2720 if(this.trackResetOnLoad){
2721 f.originalValue = f.getValue();
2725 }else{ // object hash
2728 if(typeof values[id] != 'function' && (field = this.findField(id))){
2730 if (field.setFromData &&
2732 field.displayField &&
2733 // combos' with local stores can
2734 // be queried via setValue()
2735 // to set their value..
2736 (field.store && !field.store.isLocal)
2740 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2741 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2742 field.setFromData(sd);
2745 field.setValue(values[id]);
2749 if(this.trackResetOnLoad){
2750 field.originalValue = field.getValue();
2756 //Roo.each(this.childForms || [], function (f) {
2757 // f.setValues(values);
2764 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2765 * they are returned as an array.
2766 * @param {Boolean} asString
2769 getValues : function(asString){
2770 //if (this.childForms) {
2771 // copy values from the child forms
2772 // Roo.each(this.childForms, function (f) {
2773 // this.setValues(f.getValues());
2779 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2780 if(asString === true){
2783 return Roo.urlDecode(fs);
2787 * Returns the fields in this form as an object with key/value pairs.
2788 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2791 getFieldValues : function(with_hidden)
2793 var items = this.getItems();
2795 items.each(function(f){
2799 var v = f.getValue();
2800 if (f.inputType =='radio') {
2801 if (typeof(ret[f.getName()]) == 'undefined') {
2802 ret[f.getName()] = ''; // empty..
2805 if (!f.el.dom.checked) {
2813 // not sure if this supported any more..
2814 if ((typeof(v) == 'object') && f.getRawValue) {
2815 v = f.getRawValue() ; // dates..
2817 // combo boxes where name != hiddenName...
2818 if (f.name != f.getName()) {
2819 ret[f.name] = f.getRawValue();
2821 ret[f.getName()] = v;
2828 * Clears all invalid messages in this form.
2829 * @return {BasicForm} this
2831 clearInvalid : function(){
2832 var items = this.getItems();
2834 items.each(function(f){
2845 * @return {BasicForm} this
2848 var items = this.getItems();
2849 items.each(function(f){
2853 Roo.each(this.childForms || [], function (f) {
2860 getItems : function()
2862 var r=new Roo.util.MixedCollection(false, function(o){
2863 return o.id || (o.id = Roo.id());
2865 var iter = function(el) {
2872 Roo.each(el.items,function(e) {
2891 * Ext JS Library 1.1.1
2892 * Copyright(c) 2006-2007, Ext JS, LLC.
2894 * Originally Released Under LGPL - original licence link has changed is not relivant.
2897 * <script type="text/javascript">
2900 * @class Roo.form.VTypes
2901 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2904 Roo.form.VTypes = function(){
2905 // closure these in so they are only created once.
2906 var alpha = /^[a-zA-Z_]+$/;
2907 var alphanum = /^[a-zA-Z0-9_]+$/;
2908 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2909 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2911 // All these messages and functions are configurable
2914 * The function used to validate email addresses
2915 * @param {String} value The email address
2917 'email' : function(v){
2918 return email.test(v);
2921 * The error text to display when the email validation function returns false
2924 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2926 * The keystroke filter mask to be applied on email input
2929 'emailMask' : /[a-z0-9_\.\-@]/i,
2932 * The function used to validate URLs
2933 * @param {String} value The URL
2935 'url' : function(v){
2939 * The error text to display when the url validation function returns false
2942 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
2945 * The function used to validate alpha values
2946 * @param {String} value The value
2948 'alpha' : function(v){
2949 return alpha.test(v);
2952 * The error text to display when the alpha validation function returns false
2955 'alphaText' : 'This field should only contain letters and _',
2957 * The keystroke filter mask to be applied on alpha input
2960 'alphaMask' : /[a-z_]/i,
2963 * The function used to validate alphanumeric values
2964 * @param {String} value The value
2966 'alphanum' : function(v){
2967 return alphanum.test(v);
2970 * The error text to display when the alphanumeric validation function returns false
2973 'alphanumText' : 'This field should only contain letters, numbers and _',
2975 * The keystroke filter mask to be applied on alphanumeric input
2978 'alphanumMask' : /[a-z0-9_]/i
2988 * @class Roo.bootstrap.Input
2989 * @extends Roo.bootstrap.Component
2990 * Bootstrap Input class
2991 * @cfg {Boolean} disabled is it disabled
2992 * @cfg {String} fieldLabel - the label associated
2993 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
2994 * @cfg {String} name name of the input
2995 * @cfg {string} fieldLabel - the label associated
2996 * @cfg {string} inputType - input / file submit ...
2997 * @cfg {string} placeholder - placeholder to put in text.
2998 * @cfg {string} before - input group add on before
2999 * @cfg {string} after - input group add on after
3000 * @cfg {string} size - (lg|sm) or leave empty..
3001 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3002 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3003 * @cfg {Number} md colspan out of 12 for computer-sized screens
3004 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3008 * Create a new Input
3009 * @param {Object} config The config object
3012 Roo.bootstrap.Input = function(config){
3013 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3018 * Fires when this field receives input focus.
3019 * @param {Roo.form.Field} this
3024 * Fires when this field loses input focus.
3025 * @param {Roo.form.Field} this
3030 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3031 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3032 * @param {Roo.form.Field} this
3033 * @param {Roo.EventObject} e The event object
3038 * Fires just before the field blurs if the field value has changed.
3039 * @param {Roo.form.Field} this
3040 * @param {Mixed} newValue The new value
3041 * @param {Mixed} oldValue The original value
3046 * Fires after the field has been marked as invalid.
3047 * @param {Roo.form.Field} this
3048 * @param {String} msg The validation message
3053 * Fires after the field has been validated with no errors.
3054 * @param {Roo.form.Field} this
3059 * Fires after the key up
3060 * @param {Roo.form.Field} this
3061 * @param {Roo.EventObject} e The event Object
3067 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3069 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3070 automatic validation (defaults to "keyup").
3072 validationEvent : "keyup",
3074 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3076 validateOnBlur : true,
3078 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3080 validationDelay : 250,
3082 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3084 focusClass : "x-form-focus", // not needed???
3088 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3090 invalidClass : "has-error",
3093 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3095 selectOnFocus : false,
3098 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3102 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3107 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3109 disableKeyFilter : false,
3112 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3116 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3120 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3122 blankText : "This field is required",
3125 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3129 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3131 maxLength : Number.MAX_VALUE,
3133 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3135 minLengthText : "The minimum length for this field is {0}",
3137 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3139 maxLengthText : "The maximum length for this field is {0}",
3143 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3144 * If available, this function will be called only after the basic validators all return true, and will be passed the
3145 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3149 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3150 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3151 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3155 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3174 getAutoCreate : function(){
3176 var parent = this.parent();
3178 var align = parent.labelAlign;
3183 cls: 'form-group' //input-group
3189 type : this.inputType,
3190 cls : 'form-control',
3191 placeholder : this.placeholder || ''
3195 input.name = this.name;
3198 input.cls += ' input-' + this.size;
3201 ['xs','sm','md','lg'].map(function(size){
3202 if (settings[size]) {
3203 cfg.cls += ' col-' + size + '-' + settings[size];
3207 var inputblock = input;
3209 if (this.before || this.after) {
3212 cls : 'input-group',
3216 inputblock.cn.push({
3218 cls : 'input-group-addon',
3222 inputblock.cn.push(input);
3224 inputblock.cn.push({
3226 cls : 'input-group-addon',
3234 Roo.log(this.fieldLabel.length);
3236 if (align ==='left' && this.fieldLabel.length) {
3237 Roo.log("left and has label");
3243 cls : 'col-sm-2 control-label',
3244 html : this.fieldLabel
3255 } else if ( this.fieldLabel.length) {
3261 //cls : 'input-group-addon',
3262 html : this.fieldLabel
3272 Roo.log(" no label && no align");
3285 if (this.disabled) {
3286 input.disabled=true;
3292 * return the real input element.
3294 inputEl: function ()
3296 return this.el.select('input.form-control',true).first();
3298 setDisabled : function(v)
3300 var i = this.inputEl().dom;
3302 i.removeAttribute('disabled');
3306 i.setAttribute('disabled','true');
3308 initEvents : function()
3311 this.inputEl().on("keydown" , this.fireKey, this);
3312 this.inputEl().on("focus", this.onFocus, this);
3313 this.inputEl().on("blur", this.onBlur, this);
3314 this.inputEl().relayEvent('keyup', this);
3316 // reference to original value for reset
3317 this.originalValue = this.getValue();
3318 //Roo.form.TextField.superclass.initEvents.call(this);
3319 if(this.validationEvent == 'keyup'){
3320 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3321 this.inputEl().on('keyup', this.filterValidation, this);
3323 else if(this.validationEvent !== false){
3324 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3327 if(this.selectOnFocus){
3328 this.on("focus", this.preFocus, this);
3331 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3332 this.inputEl().on("keypress", this.filterKeys, this);
3335 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3336 this.el.on("click", this.autoSize, this);
3339 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3340 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3344 filterValidation : function(e){
3345 if(!e.isNavKeyPress()){
3346 this.validationTask.delay(this.validationDelay);
3350 * Validates the field value
3351 * @return {Boolean} True if the value is valid, else false
3353 validate : function(){
3354 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3355 if(this.disabled || this.validateValue(this.getRawValue())){
3356 this.clearInvalid();
3364 * Validates a value according to the field's validation rules and marks the field as invalid
3365 * if the validation fails
3366 * @param {Mixed} value The value to validate
3367 * @return {Boolean} True if the value is valid, else false
3369 validateValue : function(value){
3370 if(value.length < 1) { // if it's blank
3371 if(this.allowBlank){
3372 this.clearInvalid();
3375 this.markInvalid(this.blankText);
3379 if(value.length < this.minLength){
3380 this.markInvalid(String.format(this.minLengthText, this.minLength));
3383 if(value.length > this.maxLength){
3384 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3388 var vt = Roo.form.VTypes;
3389 if(!vt[this.vtype](value, this)){
3390 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3394 if(typeof this.validator == "function"){
3395 var msg = this.validator(value);
3397 this.markInvalid(msg);
3401 if(this.regex && !this.regex.test(value)){
3402 this.markInvalid(this.regexText);
3411 fireKey : function(e){
3412 //Roo.log('field ' + e.getKey());
3413 if(e.isNavKeyPress()){
3414 this.fireEvent("specialkey", this, e);
3417 focus : function (selectText){
3419 this.inputEl().focus();
3420 if(selectText === true){
3421 this.inputEl().dom.select();
3427 onFocus : function(){
3428 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3429 // this.el.addClass(this.focusClass);
3432 this.hasFocus = true;
3433 this.startValue = this.getValue();
3434 this.fireEvent("focus", this);
3438 beforeBlur : Roo.emptyFn,
3442 onBlur : function(){
3444 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3445 //this.el.removeClass(this.focusClass);
3447 this.hasFocus = false;
3448 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3451 var v = this.getValue();
3452 if(String(v) !== String(this.startValue)){
3453 this.fireEvent('change', this, v, this.startValue);
3455 this.fireEvent("blur", this);
3459 * Resets the current field value to the originally loaded value and clears any validation messages
3462 this.setValue(this.originalValue);
3463 this.clearInvalid();
3466 * Returns the name of the field
3467 * @return {Mixed} name The name field
3469 getName: function(){
3473 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3474 * @return {Mixed} value The field value
3476 getValue : function(){
3477 var v = this.inputEl().getValue();
3481 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3482 * @return {Mixed} value The field value
3484 getRawValue : function(){
3485 var v = this.inputEl().getValue();
3490 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3491 * @param {Mixed} value The value to set
3493 setValue : function(v){
3496 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3502 processValue : function(value){
3503 if(this.stripCharsRe){
3504 var newValue = value.replace(this.stripCharsRe, '');
3505 if(newValue !== value){
3506 this.setRawValue(newValue);
3513 preFocus : function(){
3515 if(this.selectOnFocus){
3516 this.inputEl().dom.select();
3519 filterKeys : function(e){
3521 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3524 var c = e.getCharCode(), cc = String.fromCharCode(c);
3525 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3528 if(!this.maskRe.test(cc)){
3533 * Clear any invalid styles/messages for this field
3535 clearInvalid : function(){
3537 if(!this.el || this.preventMark){ // not rendered
3540 this.el.removeClass(this.invalidClass);
3542 switch(this.msgTarget){
3544 this.el.dom.qtip = '';
3547 this.el.dom.title = '';
3551 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3556 this.errorIcon.dom.qtip = '';
3557 this.errorIcon.hide();
3558 this.un('resize', this.alignErrorIcon, this);
3562 var t = Roo.getDom(this.msgTarget);
3564 t.style.display = 'none';
3568 this.fireEvent('valid', this);
3571 * Mark this field as invalid
3572 * @param {String} msg The validation message
3574 markInvalid : function(msg){
3575 if(!this.el || this.preventMark){ // not rendered
3578 this.el.addClass(this.invalidClass);
3580 msg = msg || this.invalidText;
3581 switch(this.msgTarget){
3583 this.el.dom.qtip = msg;
3584 this.el.dom.qclass = 'x-form-invalid-tip';
3585 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3586 Roo.QuickTips.enable();
3590 this.el.dom.title = msg;
3594 var elp = this.el.findParent('.x-form-element', 5, true);
3595 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3596 this.errorEl.setWidth(elp.getWidth(true)-20);
3598 this.errorEl.update(msg);
3599 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3602 if(!this.errorIcon){
3603 var elp = this.el.findParent('.x-form-element', 5, true);
3604 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3606 this.alignErrorIcon();
3607 this.errorIcon.dom.qtip = msg;
3608 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3609 this.errorIcon.show();
3610 this.on('resize', this.alignErrorIcon, this);
3613 var t = Roo.getDom(this.msgTarget);
3615 t.style.display = this.msgDisplay;
3619 this.fireEvent('invalid', this, msg);
3622 SafariOnKeyDown : function(event)
3624 // this is a workaround for a password hang bug on chrome/ webkit.
3626 var isSelectAll = false;
3628 if(this.inputEl().dom.selectionEnd > 0){
3629 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3631 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3632 event.preventDefault();
3637 if(isSelectAll){ // backspace and delete key
3639 event.preventDefault();
3640 // this is very hacky as keydown always get's upper case.
3642 var cc = String.fromCharCode(event.getCharCode());
3643 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3655 * trigger field - base class for combo..
3660 * @class Roo.bootstrap.TriggerField
3661 * @extends Roo.bootstrap.Input
3662 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3663 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3664 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3665 * for which you can provide a custom implementation. For example:
3667 var trigger = new Roo.bootstrap.TriggerField();
3668 trigger.onTriggerClick = myTriggerFn;
3669 trigger.applyTo('my-field');
3672 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3673 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3674 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3675 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3677 * Create a new TriggerField.
3678 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3679 * to the base TextField)
3681 Roo.bootstrap.TriggerField = function(config){
3682 this.mimicing = false;
3683 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3686 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3688 * @cfg {String} triggerClass A CSS class to apply to the trigger
3691 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3695 /** @cfg {Boolean} grow @hide */
3696 /** @cfg {Number} growMin @hide */
3697 /** @cfg {Number} growMax @hide */
3703 autoSize: Roo.emptyFn,
3710 actionMode : 'wrap',
3714 getAutoCreate : function(){
3716 var parent = this.parent();
3718 var align = parent.labelAlign;
3723 cls: 'form-group' //input-group
3730 type : this.inputType,
3731 cls : 'form-control',
3732 autocomplete: 'off',
3733 placeholder : this.placeholder || ''
3737 input.name = this.name;
3740 input.cls += ' input-' + this.size;
3743 cls: 'combobox-container input-group',
3748 cls: 'form-hidden-field'
3753 cls : 'typeahead typeahead-long dropdown-menu',
3754 style : 'display:none'
3758 cls : 'input-group-addon btn dropdown-toggle',
3766 cls: 'combobox-clear',
3783 if (align ==='left' && this.fieldLabel.length) {
3787 Roo.log("left and has label");
3793 cls : 'col-sm-2 control-label',
3794 html : this.fieldLabel
3805 } else if ( this.fieldLabel.length) {
3811 //cls : 'input-group-addon',
3812 html : this.fieldLabel
3822 Roo.log(" no label && no align");
3829 ['xs','sm','md','lg'].map(function(size){
3830 if (settings[size]) {
3831 cfg.cls += ' col-' + size + '-' + settings[size];
3837 if (this.disabled) {
3838 input.disabled=true;
3847 onResize : function(w, h){
3848 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3849 if(typeof w == 'number'){
3850 var x = w - this.trigger.getWidth();
3851 this.inputEl().setWidth(this.adjustWidth('input', x));
3852 this.trigger.setStyle('left', x+'px');
3857 adjustSize : Roo.BoxComponent.prototype.adjustSize,
3860 getResizeEl : function(){
3861 return this.inputEl();
3865 getPositionEl : function(){
3866 return this.inputEl();
3870 alignErrorIcon : function(){
3871 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3875 initEvents : function(){
3877 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3879 this.trigger = this.el.select('span.dropdown-toggle',true).first();
3880 if(this.hideTrigger){
3881 this.trigger.setDisplayed(false);
3883 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3884 //this.trigger.addClassOnOver('x-form-trigger-over');
3885 //this.trigger.addClassOnClick('x-form-trigger-click');
3888 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3893 initTrigger : function(){
3898 onDestroy : function(){
3900 this.trigger.removeAllListeners();
3901 // this.trigger.remove();
3904 // this.wrap.remove();
3906 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
3910 onFocus : function(){
3911 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
3914 this.wrap.addClass('x-trigger-wrap-focus');
3915 this.mimicing = true;
3916 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
3917 if(this.monitorTab){
3918 this.el.on("keydown", this.checkTab, this);
3925 checkTab : function(e){
3926 if(e.getKey() == e.TAB){
3932 onBlur : function(){
3937 mimicBlur : function(e, t){
3939 if(!this.wrap.contains(t) && this.validateBlur()){
3946 triggerBlur : function(){
3947 this.mimicing = false;
3948 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
3949 if(this.monitorTab){
3950 this.el.un("keydown", this.checkTab, this);
3952 //this.wrap.removeClass('x-trigger-wrap-focus');
3953 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
3957 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
3958 validateBlur : function(e, t){
3963 onDisable : function(){
3964 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
3966 // this.wrap.addClass('x-item-disabled');
3971 onEnable : function(){
3972 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
3974 // this.el.removeClass('x-item-disabled');
3979 onShow : function(){
3980 var ae = this.getActionEl();
3983 ae.dom.style.display = '';
3984 ae.dom.style.visibility = 'visible';
3990 onHide : function(){
3991 var ae = this.getActionEl();
3992 ae.dom.style.display = 'none';
3996 * The function that should handle the trigger's click event. This method does nothing by default until overridden
3997 * by an implementing function.
3999 * @param {EventObject} e
4001 onTriggerClick : Roo.emptyFn
4005 * Ext JS Library 1.1.1
4006 * Copyright(c) 2006-2007, Ext JS, LLC.
4008 * Originally Released Under LGPL - original licence link has changed is not relivant.
4011 * <script type="text/javascript">
4016 * @class Roo.data.SortTypes
4018 * Defines the default sorting (casting?) comparison functions used when sorting data.
4020 Roo.data.SortTypes = {
4022 * Default sort that does nothing
4023 * @param {Mixed} s The value being converted
4024 * @return {Mixed} The comparison value
4031 * The regular expression used to strip tags
4035 stripTagsRE : /<\/?[^>]+>/gi,
4038 * Strips all HTML tags to sort on text only
4039 * @param {Mixed} s The value being converted
4040 * @return {String} The comparison value
4042 asText : function(s){
4043 return String(s).replace(this.stripTagsRE, "");
4047 * Strips all HTML tags to sort on text only - Case insensitive
4048 * @param {Mixed} s The value being converted
4049 * @return {String} The comparison value
4051 asUCText : function(s){
4052 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4056 * Case insensitive string
4057 * @param {Mixed} s The value being converted
4058 * @return {String} The comparison value
4060 asUCString : function(s) {
4061 return String(s).toUpperCase();
4066 * @param {Mixed} s The value being converted
4067 * @return {Number} The comparison value
4069 asDate : function(s) {
4073 if(s instanceof Date){
4076 return Date.parse(String(s));
4081 * @param {Mixed} s The value being converted
4082 * @return {Float} The comparison value
4084 asFloat : function(s) {
4085 var val = parseFloat(String(s).replace(/,/g, ""));
4086 if(isNaN(val)) val = 0;
4092 * @param {Mixed} s The value being converted
4093 * @return {Number} The comparison value
4095 asInt : function(s) {
4096 var val = parseInt(String(s).replace(/,/g, ""));
4097 if(isNaN(val)) val = 0;
4102 * Ext JS Library 1.1.1
4103 * Copyright(c) 2006-2007, Ext JS, LLC.
4105 * Originally Released Under LGPL - original licence link has changed is not relivant.
4108 * <script type="text/javascript">
4112 * @class Roo.data.Record
4113 * Instances of this class encapsulate both record <em>definition</em> information, and record
4114 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4115 * to access Records cached in an {@link Roo.data.Store} object.<br>
4117 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4118 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4121 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4123 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4124 * {@link #create}. The parameters are the same.
4125 * @param {Array} data An associative Array of data values keyed by the field name.
4126 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4127 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4128 * not specified an integer id is generated.
4130 Roo.data.Record = function(data, id){
4131 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4136 * Generate a constructor for a specific record layout.
4137 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4138 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4139 * Each field definition object may contain the following properties: <ul>
4140 * <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,
4141 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4142 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4143 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4144 * is being used, then this is a string containing the javascript expression to reference the data relative to
4145 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4146 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4147 * this may be omitted.</p></li>
4148 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4149 * <ul><li>auto (Default, implies no conversion)</li>
4154 * <li>date</li></ul></p></li>
4155 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4156 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4157 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4158 * by the Reader into an object that will be stored in the Record. It is passed the
4159 * following parameters:<ul>
4160 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4162 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4164 * <br>usage:<br><pre><code>
4165 var TopicRecord = Roo.data.Record.create(
4166 {name: 'title', mapping: 'topic_title'},
4167 {name: 'author', mapping: 'username'},
4168 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4169 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4170 {name: 'lastPoster', mapping: 'user2'},
4171 {name: 'excerpt', mapping: 'post_text'}
4174 var myNewRecord = new TopicRecord({
4175 title: 'Do my job please',
4178 lastPost: new Date(),
4179 lastPoster: 'Animal',
4180 excerpt: 'No way dude!'
4182 myStore.add(myNewRecord);
4187 Roo.data.Record.create = function(o){
4189 f.superclass.constructor.apply(this, arguments);
4191 Roo.extend(f, Roo.data.Record);
4192 var p = f.prototype;
4193 p.fields = new Roo.util.MixedCollection(false, function(field){
4196 for(var i = 0, len = o.length; i < len; i++){
4197 p.fields.add(new Roo.data.Field(o[i]));
4199 f.getField = function(name){
4200 return p.fields.get(name);
4205 Roo.data.Record.AUTO_ID = 1000;
4206 Roo.data.Record.EDIT = 'edit';
4207 Roo.data.Record.REJECT = 'reject';
4208 Roo.data.Record.COMMIT = 'commit';
4210 Roo.data.Record.prototype = {
4212 * Readonly flag - true if this record has been modified.
4221 join : function(store){
4226 * Set the named field to the specified value.
4227 * @param {String} name The name of the field to set.
4228 * @param {Object} value The value to set the field to.
4230 set : function(name, value){
4231 if(this.data[name] == value){
4238 if(typeof this.modified[name] == 'undefined'){
4239 this.modified[name] = this.data[name];
4241 this.data[name] = value;
4242 if(!this.editing && this.store){
4243 this.store.afterEdit(this);
4248 * Get the value of the named field.
4249 * @param {String} name The name of the field to get the value of.
4250 * @return {Object} The value of the field.
4252 get : function(name){
4253 return this.data[name];
4257 beginEdit : function(){
4258 this.editing = true;
4263 cancelEdit : function(){
4264 this.editing = false;
4265 delete this.modified;
4269 endEdit : function(){
4270 this.editing = false;
4271 if(this.dirty && this.store){
4272 this.store.afterEdit(this);
4277 * Usually called by the {@link Roo.data.Store} which owns the Record.
4278 * Rejects all changes made to the Record since either creation, or the last commit operation.
4279 * Modified fields are reverted to their original values.
4281 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4282 * of reject operations.
4284 reject : function(){
4285 var m = this.modified;
4287 if(typeof m[n] != "function"){
4288 this.data[n] = m[n];
4292 delete this.modified;
4293 this.editing = false;
4295 this.store.afterReject(this);
4300 * Usually called by the {@link Roo.data.Store} which owns the Record.
4301 * Commits all changes made to the Record since either creation, or the last commit operation.
4303 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4304 * of commit operations.
4306 commit : function(){
4308 delete this.modified;
4309 this.editing = false;
4311 this.store.afterCommit(this);
4316 hasError : function(){
4317 return this.error != null;
4321 clearError : function(){
4326 * Creates a copy of this record.
4327 * @param {String} id (optional) A new record id if you don't want to use this record's id
4330 copy : function(newId) {
4331 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4335 * Ext JS Library 1.1.1
4336 * Copyright(c) 2006-2007, Ext JS, LLC.
4338 * Originally Released Under LGPL - original licence link has changed is not relivant.
4341 * <script type="text/javascript">
4347 * @class Roo.data.Store
4348 * @extends Roo.util.Observable
4349 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4350 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4352 * 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
4353 * has no knowledge of the format of the data returned by the Proxy.<br>
4355 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4356 * instances from the data object. These records are cached and made available through accessor functions.
4358 * Creates a new Store.
4359 * @param {Object} config A config object containing the objects needed for the Store to access data,
4360 * and read the data into Records.
4362 Roo.data.Store = function(config){
4363 this.data = new Roo.util.MixedCollection(false);
4364 this.data.getKey = function(o){
4367 this.baseParams = {};
4374 "multisort" : "_multisort"
4377 if(config && config.data){
4378 this.inlineData = config.data;
4382 Roo.apply(this, config);
4384 if(this.reader){ // reader passed
4385 this.reader = Roo.factory(this.reader, Roo.data);
4386 this.reader.xmodule = this.xmodule || false;
4387 if(!this.recordType){
4388 this.recordType = this.reader.recordType;
4390 if(this.reader.onMetaChange){
4391 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4395 if(this.recordType){
4396 this.fields = this.recordType.prototype.fields;
4402 * @event datachanged
4403 * Fires when the data cache has changed, and a widget which is using this Store
4404 * as a Record cache should refresh its view.
4405 * @param {Store} this
4410 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4411 * @param {Store} this
4412 * @param {Object} meta The JSON metadata
4417 * Fires when Records have been added to the Store
4418 * @param {Store} this
4419 * @param {Roo.data.Record[]} records The array of Records added
4420 * @param {Number} index The index at which the record(s) were added
4425 * Fires when a Record has been removed from the Store
4426 * @param {Store} this
4427 * @param {Roo.data.Record} record The Record that was removed
4428 * @param {Number} index The index at which the record was removed
4433 * Fires when a Record has been updated
4434 * @param {Store} this
4435 * @param {Roo.data.Record} record The Record that was updated
4436 * @param {String} operation The update operation being performed. Value may be one of:
4438 Roo.data.Record.EDIT
4439 Roo.data.Record.REJECT
4440 Roo.data.Record.COMMIT
4446 * Fires when the data cache has been cleared.
4447 * @param {Store} this
4452 * Fires before a request is made for a new data object. If the beforeload handler returns false
4453 * the load action will be canceled.
4454 * @param {Store} this
4455 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4459 * @event beforeloadadd
4460 * Fires after a new set of Records has been loaded.
4461 * @param {Store} this
4462 * @param {Roo.data.Record[]} records The Records that were loaded
4463 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4465 beforeloadadd : true,
4468 * Fires after a new set of Records has been loaded, before they are added to the store.
4469 * @param {Store} this
4470 * @param {Roo.data.Record[]} records The Records that were loaded
4471 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4472 * @params {Object} return from reader
4476 * @event loadexception
4477 * Fires if an exception occurs in the Proxy during loading.
4478 * Called with the signature of the Proxy's "loadexception" event.
4479 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4482 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4483 * @param {Object} load options
4484 * @param {Object} jsonData from your request (normally this contains the Exception)
4486 loadexception : true
4490 this.proxy = Roo.factory(this.proxy, Roo.data);
4491 this.proxy.xmodule = this.xmodule || false;
4492 this.relayEvents(this.proxy, ["loadexception"]);
4494 this.sortToggle = {};
4495 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4497 Roo.data.Store.superclass.constructor.call(this);
4499 if(this.inlineData){
4500 this.loadData(this.inlineData);
4501 delete this.inlineData;
4505 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4507 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4508 * without a remote query - used by combo/forms at present.
4512 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4515 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4518 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4519 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4522 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4523 * on any HTTP request
4526 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4529 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4533 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4534 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4539 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4540 * loaded or when a record is removed. (defaults to false).
4542 pruneModifiedRecords : false,
4548 * Add Records to the Store and fires the add event.
4549 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4551 add : function(records){
4552 records = [].concat(records);
4553 for(var i = 0, len = records.length; i < len; i++){
4554 records[i].join(this);
4556 var index = this.data.length;
4557 this.data.addAll(records);
4558 this.fireEvent("add", this, records, index);
4562 * Remove a Record from the Store and fires the remove event.
4563 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4565 remove : function(record){
4566 var index = this.data.indexOf(record);
4567 this.data.removeAt(index);
4568 if(this.pruneModifiedRecords){
4569 this.modified.remove(record);
4571 this.fireEvent("remove", this, record, index);
4575 * Remove all Records from the Store and fires the clear event.
4577 removeAll : function(){
4579 if(this.pruneModifiedRecords){
4582 this.fireEvent("clear", this);
4586 * Inserts Records to the Store at the given index and fires the add event.
4587 * @param {Number} index The start index at which to insert the passed Records.
4588 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4590 insert : function(index, records){
4591 records = [].concat(records);
4592 for(var i = 0, len = records.length; i < len; i++){
4593 this.data.insert(index, records[i]);
4594 records[i].join(this);
4596 this.fireEvent("add", this, records, index);
4600 * Get the index within the cache of the passed Record.
4601 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4602 * @return {Number} The index of the passed Record. Returns -1 if not found.
4604 indexOf : function(record){
4605 return this.data.indexOf(record);
4609 * Get the index within the cache of the Record with the passed id.
4610 * @param {String} id The id of the Record to find.
4611 * @return {Number} The index of the Record. Returns -1 if not found.
4613 indexOfId : function(id){
4614 return this.data.indexOfKey(id);
4618 * Get the Record with the specified id.
4619 * @param {String} id The id of the Record to find.
4620 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4622 getById : function(id){
4623 return this.data.key(id);
4627 * Get the Record at the specified index.
4628 * @param {Number} index The index of the Record to find.
4629 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4631 getAt : function(index){
4632 return this.data.itemAt(index);
4636 * Returns a range of Records between specified indices.
4637 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4638 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4639 * @return {Roo.data.Record[]} An array of Records
4641 getRange : function(start, end){
4642 return this.data.getRange(start, end);
4646 storeOptions : function(o){
4647 o = Roo.apply({}, o);
4650 this.lastOptions = o;
4654 * Loads the Record cache from the configured Proxy using the configured Reader.
4656 * If using remote paging, then the first load call must specify the <em>start</em>
4657 * and <em>limit</em> properties in the options.params property to establish the initial
4658 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4660 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4661 * and this call will return before the new data has been loaded. Perform any post-processing
4662 * in a callback function, or in a "load" event handler.</strong>
4664 * @param {Object} options An object containing properties which control loading options:<ul>
4665 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4666 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4667 * passed the following arguments:<ul>
4668 * <li>r : Roo.data.Record[]</li>
4669 * <li>options: Options object from the load call</li>
4670 * <li>success: Boolean success indicator</li></ul></li>
4671 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4672 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4675 load : function(options){
4676 options = options || {};
4677 if(this.fireEvent("beforeload", this, options) !== false){
4678 this.storeOptions(options);
4679 var p = Roo.apply(options.params || {}, this.baseParams);
4680 // if meta was not loaded from remote source.. try requesting it.
4681 if (!this.reader.metaFromRemote) {
4684 if(this.sortInfo && this.remoteSort){
4685 var pn = this.paramNames;
4686 p[pn["sort"]] = this.sortInfo.field;
4687 p[pn["dir"]] = this.sortInfo.direction;
4689 if (this.multiSort) {
4690 var pn = this.paramNames;
4691 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4694 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4699 * Reloads the Record cache from the configured Proxy using the configured Reader and
4700 * the options from the last load operation performed.
4701 * @param {Object} options (optional) An object containing properties which may override the options
4702 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4703 * the most recently used options are reused).
4705 reload : function(options){
4706 this.load(Roo.applyIf(options||{}, this.lastOptions));
4710 // Called as a callback by the Reader during a load operation.
4711 loadRecords : function(o, options, success){
4712 if(!o || success === false){
4713 if(success !== false){
4714 this.fireEvent("load", this, [], options, o);
4716 if(options.callback){
4717 options.callback.call(options.scope || this, [], options, false);
4721 // if data returned failure - throw an exception.
4722 if (o.success === false) {
4723 // show a message if no listener is registered.
4724 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4725 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4727 // loadmask wil be hooked into this..
4728 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4731 var r = o.records, t = o.totalRecords || r.length;
4733 this.fireEvent("beforeloadadd", this, r, options, o);
4735 if(!options || options.add !== true){
4736 if(this.pruneModifiedRecords){
4739 for(var i = 0, len = r.length; i < len; i++){
4743 this.data = this.snapshot;
4744 delete this.snapshot;
4747 this.data.addAll(r);
4748 this.totalLength = t;
4750 this.fireEvent("datachanged", this);
4752 this.totalLength = Math.max(t, this.data.length+r.length);
4755 this.fireEvent("load", this, r, options, o);
4756 if(options.callback){
4757 options.callback.call(options.scope || this, r, options, true);
4763 * Loads data from a passed data block. A Reader which understands the format of the data
4764 * must have been configured in the constructor.
4765 * @param {Object} data The data block from which to read the Records. The format of the data expected
4766 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4767 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4769 loadData : function(o, append){
4770 var r = this.reader.readRecords(o);
4771 this.loadRecords(r, {add: append}, true);
4775 * Gets the number of cached records.
4777 * <em>If using paging, this may not be the total size of the dataset. If the data object
4778 * used by the Reader contains the dataset size, then the getTotalCount() function returns
4779 * the data set size</em>
4781 getCount : function(){
4782 return this.data.length || 0;
4786 * Gets the total number of records in the dataset as returned by the server.
4788 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4789 * the dataset size</em>
4791 getTotalCount : function(){
4792 return this.totalLength || 0;
4796 * Returns the sort state of the Store as an object with two properties:
4798 field {String} The name of the field by which the Records are sorted
4799 direction {String} The sort order, "ASC" or "DESC"
4802 getSortState : function(){
4803 return this.sortInfo;
4807 applySort : function(){
4808 if(this.sortInfo && !this.remoteSort){
4809 var s = this.sortInfo, f = s.field;
4810 var st = this.fields.get(f).sortType;
4811 var fn = function(r1, r2){
4812 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4813 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
4815 this.data.sort(s.direction, fn);
4816 if(this.snapshot && this.snapshot != this.data){
4817 this.snapshot.sort(s.direction, fn);
4823 * Sets the default sort column and order to be used by the next load operation.
4824 * @param {String} fieldName The name of the field to sort by.
4825 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4827 setDefaultSort : function(field, dir){
4828 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
4833 * If remote sorting is used, the sort is performed on the server, and the cache is
4834 * reloaded. If local sorting is used, the cache is sorted internally.
4835 * @param {String} fieldName The name of the field to sort by.
4836 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4838 sort : function(fieldName, dir){
4839 var f = this.fields.get(fieldName);
4841 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
4843 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
4844 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
4849 this.sortToggle[f.name] = dir;
4850 this.sortInfo = {field: f.name, direction: dir};
4851 if(!this.remoteSort){
4853 this.fireEvent("datachanged", this);
4855 this.load(this.lastOptions);
4860 * Calls the specified function for each of the Records in the cache.
4861 * @param {Function} fn The function to call. The Record is passed as the first parameter.
4862 * Returning <em>false</em> aborts and exits the iteration.
4863 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
4865 each : function(fn, scope){
4866 this.data.each(fn, scope);
4870 * Gets all records modified since the last commit. Modified records are persisted across load operations
4871 * (e.g., during paging).
4872 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
4874 getModifiedRecords : function(){
4875 return this.modified;
4879 createFilterFn : function(property, value, anyMatch){
4880 if(!value.exec){ // not a regex
4881 value = String(value);
4882 if(value.length == 0){
4885 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
4888 return value.test(r.data[property]);
4893 * Sums the value of <i>property</i> for each record between start and end and returns the result.
4894 * @param {String} property A field on your records
4895 * @param {Number} start The record index to start at (defaults to 0)
4896 * @param {Number} end The last record index to include (defaults to length - 1)
4897 * @return {Number} The sum
4899 sum : function(property, start, end){
4900 var rs = this.data.items, v = 0;
4902 end = (end || end === 0) ? end : rs.length-1;
4904 for(var i = start; i <= end; i++){
4905 v += (rs[i].data[property] || 0);
4911 * Filter the records by a specified property.
4912 * @param {String} field A field on your records
4913 * @param {String/RegExp} value Either a string that the field
4914 * should start with or a RegExp to test against the field
4915 * @param {Boolean} anyMatch True to match any part not just the beginning
4917 filter : function(property, value, anyMatch){
4918 var fn = this.createFilterFn(property, value, anyMatch);
4919 return fn ? this.filterBy(fn) : this.clearFilter();
4923 * Filter by a function. The specified function will be called with each
4924 * record in this data source. If the function returns true the record is included,
4925 * otherwise it is filtered.
4926 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4927 * @param {Object} scope (optional) The scope of the function (defaults to this)
4929 filterBy : function(fn, scope){
4930 this.snapshot = this.snapshot || this.data;
4931 this.data = this.queryBy(fn, scope||this);
4932 this.fireEvent("datachanged", this);
4936 * Query the records by a specified property.
4937 * @param {String} field A field on your records
4938 * @param {String/RegExp} value Either a string that the field
4939 * should start with or a RegExp to test against the field
4940 * @param {Boolean} anyMatch True to match any part not just the beginning
4941 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
4943 query : function(property, value, anyMatch){
4944 var fn = this.createFilterFn(property, value, anyMatch);
4945 return fn ? this.queryBy(fn) : this.data.clone();
4949 * Query by a function. The specified function will be called with each
4950 * record in this data source. If the function returns true the record is included
4952 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4953 * @param {Object} scope (optional) The scope of the function (defaults to this)
4954 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
4956 queryBy : function(fn, scope){
4957 var data = this.snapshot || this.data;
4958 return data.filterBy(fn, scope||this);
4962 * Collects unique values for a particular dataIndex from this store.
4963 * @param {String} dataIndex The property to collect
4964 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
4965 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
4966 * @return {Array} An array of the unique values
4968 collect : function(dataIndex, allowNull, bypassFilter){
4969 var d = (bypassFilter === true && this.snapshot) ?
4970 this.snapshot.items : this.data.items;
4971 var v, sv, r = [], l = {};
4972 for(var i = 0, len = d.length; i < len; i++){
4973 v = d[i].data[dataIndex];
4975 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
4984 * Revert to a view of the Record cache with no filtering applied.
4985 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
4987 clearFilter : function(suppressEvent){
4988 if(this.snapshot && this.snapshot != this.data){
4989 this.data = this.snapshot;
4990 delete this.snapshot;
4991 if(suppressEvent !== true){
4992 this.fireEvent("datachanged", this);
4998 afterEdit : function(record){
4999 if(this.modified.indexOf(record) == -1){
5000 this.modified.push(record);
5002 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5006 afterReject : function(record){
5007 this.modified.remove(record);
5008 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5012 afterCommit : function(record){
5013 this.modified.remove(record);
5014 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5018 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5019 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5021 commitChanges : function(){
5022 var m = this.modified.slice(0);
5024 for(var i = 0, len = m.length; i < len; i++){
5030 * Cancel outstanding changes on all changed records.
5032 rejectChanges : function(){
5033 var m = this.modified.slice(0);
5035 for(var i = 0, len = m.length; i < len; i++){
5040 onMetaChange : function(meta, rtype, o){
5041 this.recordType = rtype;
5042 this.fields = rtype.prototype.fields;
5043 delete this.snapshot;
5044 this.sortInfo = meta.sortInfo || this.sortInfo;
5046 this.fireEvent('metachange', this, this.reader.meta);
5050 * Ext JS Library 1.1.1
5051 * Copyright(c) 2006-2007, Ext JS, LLC.
5053 * Originally Released Under LGPL - original licence link has changed is not relivant.
5056 * <script type="text/javascript">
5060 * @class Roo.data.SimpleStore
5061 * @extends Roo.data.Store
5062 * Small helper class to make creating Stores from Array data easier.
5063 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5064 * @cfg {Array} fields An array of field definition objects, or field name strings.
5065 * @cfg {Array} data The multi-dimensional array of data
5067 * @param {Object} config
5069 Roo.data.SimpleStore = function(config){
5070 Roo.data.SimpleStore.superclass.constructor.call(this, {
5072 reader: new Roo.data.ArrayReader({
5075 Roo.data.Record.create(config.fields)
5077 proxy : new Roo.data.MemoryProxy(config.data)
5081 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5083 * Ext JS Library 1.1.1
5084 * Copyright(c) 2006-2007, Ext JS, LLC.
5086 * Originally Released Under LGPL - original licence link has changed is not relivant.
5089 * <script type="text/javascript">
5094 * @extends Roo.data.Store
5095 * @class Roo.data.JsonStore
5096 * Small helper class to make creating Stores for JSON data easier. <br/>
5098 var store = new Roo.data.JsonStore({
5099 url: 'get-images.php',
5101 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5104 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5105 * JsonReader and HttpProxy (unless inline data is provided).</b>
5106 * @cfg {Array} fields An array of field definition objects, or field name strings.
5108 * @param {Object} config
5110 Roo.data.JsonStore = function(c){
5111 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5112 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5113 reader: new Roo.data.JsonReader(c, c.fields)
5116 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5118 * Ext JS Library 1.1.1
5119 * Copyright(c) 2006-2007, Ext JS, LLC.
5121 * Originally Released Under LGPL - original licence link has changed is not relivant.
5124 * <script type="text/javascript">
5128 Roo.data.Field = function(config){
5129 if(typeof config == "string"){
5130 config = {name: config};
5132 Roo.apply(this, config);
5138 var st = Roo.data.SortTypes;
5139 // named sortTypes are supported, here we look them up
5140 if(typeof this.sortType == "string"){
5141 this.sortType = st[this.sortType];
5144 // set default sortType for strings and dates
5148 this.sortType = st.asUCString;
5151 this.sortType = st.asDate;
5154 this.sortType = st.none;
5159 var stripRe = /[\$,%]/g;
5161 // prebuilt conversion function for this field, instead of
5162 // switching every time we're reading a value
5164 var cv, dateFormat = this.dateFormat;
5169 cv = function(v){ return v; };
5172 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5176 return v !== undefined && v !== null && v !== '' ?
5177 parseInt(String(v).replace(stripRe, ""), 10) : '';
5182 return v !== undefined && v !== null && v !== '' ?
5183 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5188 cv = function(v){ return v === true || v === "true" || v == 1; };
5195 if(v instanceof Date){
5199 if(dateFormat == "timestamp"){
5200 return new Date(v*1000);
5202 return Date.parseDate(v, dateFormat);
5204 var parsed = Date.parse(v);
5205 return parsed ? new Date(parsed) : null;
5214 Roo.data.Field.prototype = {
5222 * Ext JS Library 1.1.1
5223 * Copyright(c) 2006-2007, Ext JS, LLC.
5225 * Originally Released Under LGPL - original licence link has changed is not relivant.
5228 * <script type="text/javascript">
5231 // Base class for reading structured data from a data source. This class is intended to be
5232 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5235 * @class Roo.data.DataReader
5236 * Base class for reading structured data from a data source. This class is intended to be
5237 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5240 Roo.data.DataReader = function(meta, recordType){
5244 this.recordType = recordType instanceof Array ?
5245 Roo.data.Record.create(recordType) : recordType;
5248 Roo.data.DataReader.prototype = {
5250 * Create an empty record
5251 * @param {Object} data (optional) - overlay some values
5252 * @return {Roo.data.Record} record created.
5254 newRow : function(d) {
5256 this.recordType.prototype.fields.each(function(c) {
5258 case 'int' : da[c.name] = 0; break;
5259 case 'date' : da[c.name] = new Date(); break;
5260 case 'float' : da[c.name] = 0.0; break;
5261 case 'boolean' : da[c.name] = false; break;
5262 default : da[c.name] = ""; break;
5266 return new this.recordType(Roo.apply(da, d));
5271 * Ext JS Library 1.1.1
5272 * Copyright(c) 2006-2007, Ext JS, LLC.
5274 * Originally Released Under LGPL - original licence link has changed is not relivant.
5277 * <script type="text/javascript">
5281 * @class Roo.data.DataProxy
5282 * @extends Roo.data.Observable
5283 * This class is an abstract base class for implementations which provide retrieval of
5284 * unformatted data objects.<br>
5286 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5287 * (of the appropriate type which knows how to parse the data object) to provide a block of
5288 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5290 * Custom implementations must implement the load method as described in
5291 * {@link Roo.data.HttpProxy#load}.
5293 Roo.data.DataProxy = function(){
5297 * Fires before a network request is made to retrieve a data object.
5298 * @param {Object} This DataProxy object.
5299 * @param {Object} params The params parameter to the load function.
5304 * Fires before the load method's callback is called.
5305 * @param {Object} This DataProxy object.
5306 * @param {Object} o The data object.
5307 * @param {Object} arg The callback argument object passed to the load function.
5311 * @event loadexception
5312 * Fires if an Exception occurs during data retrieval.
5313 * @param {Object} This DataProxy object.
5314 * @param {Object} o The data object.
5315 * @param {Object} arg The callback argument object passed to the load function.
5316 * @param {Object} e The Exception.
5318 loadexception : true
5320 Roo.data.DataProxy.superclass.constructor.call(this);
5323 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5326 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5330 * Ext JS Library 1.1.1
5331 * Copyright(c) 2006-2007, Ext JS, LLC.
5333 * Originally Released Under LGPL - original licence link has changed is not relivant.
5336 * <script type="text/javascript">
5339 * @class Roo.data.MemoryProxy
5340 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5341 * to the Reader when its load method is called.
5343 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5345 Roo.data.MemoryProxy = function(data){
5349 Roo.data.MemoryProxy.superclass.constructor.call(this);
5353 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5355 * Load data from the requested source (in this case an in-memory
5356 * data object passed to the constructor), read the data object into
5357 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5358 * process that block using the passed callback.
5359 * @param {Object} params This parameter is not used by the MemoryProxy class.
5360 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5361 * object into a block of Roo.data.Records.
5362 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5363 * The function must be passed <ul>
5364 * <li>The Record block object</li>
5365 * <li>The "arg" argument from the load function</li>
5366 * <li>A boolean success indicator</li>
5368 * @param {Object} scope The scope in which to call the callback
5369 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5371 load : function(params, reader, callback, scope, arg){
5372 params = params || {};
5375 result = reader.readRecords(this.data);
5377 this.fireEvent("loadexception", this, arg, null, e);
5378 callback.call(scope, null, arg, false);
5381 callback.call(scope, result, arg, true);
5385 update : function(params, records){
5390 * Ext JS Library 1.1.1
5391 * Copyright(c) 2006-2007, Ext JS, LLC.
5393 * Originally Released Under LGPL - original licence link has changed is not relivant.
5396 * <script type="text/javascript">
5399 * @class Roo.data.HttpProxy
5400 * @extends Roo.data.DataProxy
5401 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5402 * configured to reference a certain URL.<br><br>
5404 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5405 * from which the running page was served.<br><br>
5407 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5409 * Be aware that to enable the browser to parse an XML document, the server must set
5410 * the Content-Type header in the HTTP response to "text/xml".
5412 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5413 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5414 * will be used to make the request.
5416 Roo.data.HttpProxy = function(conn){
5417 Roo.data.HttpProxy.superclass.constructor.call(this);
5418 // is conn a conn config or a real conn?
5420 this.useAjax = !conn || !conn.events;
5424 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5425 // thse are take from connection...
5428 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5431 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5432 * extra parameters to each request made by this object. (defaults to undefined)
5435 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5436 * to each request made by this object. (defaults to undefined)
5439 * @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)
5442 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5445 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5451 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5455 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5456 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5457 * a finer-grained basis than the DataProxy events.
5459 getConnection : function(){
5460 return this.useAjax ? Roo.Ajax : this.conn;
5464 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5465 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5466 * process that block using the passed callback.
5467 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5468 * for the request to the remote server.
5469 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5470 * object into a block of Roo.data.Records.
5471 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5472 * The function must be passed <ul>
5473 * <li>The Record block object</li>
5474 * <li>The "arg" argument from the load function</li>
5475 * <li>A boolean success indicator</li>
5477 * @param {Object} scope The scope in which to call the callback
5478 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5480 load : function(params, reader, callback, scope, arg){
5481 if(this.fireEvent("beforeload", this, params) !== false){
5483 params : params || {},
5485 callback : callback,
5490 callback : this.loadResponse,
5494 Roo.applyIf(o, this.conn);
5495 if(this.activeRequest){
5496 Roo.Ajax.abort(this.activeRequest);
5498 this.activeRequest = Roo.Ajax.request(o);
5500 this.conn.request(o);
5503 callback.call(scope||this, null, arg, false);
5508 loadResponse : function(o, success, response){
5509 delete this.activeRequest;
5511 this.fireEvent("loadexception", this, o, response);
5512 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5517 result = o.reader.read(response);
5519 this.fireEvent("loadexception", this, o, response, e);
5520 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5524 this.fireEvent("load", this, o, o.request.arg);
5525 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5529 update : function(dataSet){
5534 updateResponse : function(dataSet){
5539 * Ext JS Library 1.1.1
5540 * Copyright(c) 2006-2007, Ext JS, LLC.
5542 * Originally Released Under LGPL - original licence link has changed is not relivant.
5545 * <script type="text/javascript">
5549 * @class Roo.data.ScriptTagProxy
5550 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5551 * other than the originating domain of the running page.<br><br>
5553 * <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
5554 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5556 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5557 * source code that is used as the source inside a <script> tag.<br><br>
5559 * In order for the browser to process the returned data, the server must wrap the data object
5560 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5561 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5562 * depending on whether the callback name was passed:
5565 boolean scriptTag = false;
5566 String cb = request.getParameter("callback");
5569 response.setContentType("text/javascript");
5571 response.setContentType("application/x-json");
5573 Writer out = response.getWriter();
5575 out.write(cb + "(");
5577 out.print(dataBlock.toJsonString());
5584 * @param {Object} config A configuration object.
5586 Roo.data.ScriptTagProxy = function(config){
5587 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5588 Roo.apply(this, config);
5589 this.head = document.getElementsByTagName("head")[0];
5592 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5594 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5596 * @cfg {String} url The URL from which to request the data object.
5599 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5603 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5604 * the server the name of the callback function set up by the load call to process the returned data object.
5605 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5606 * javascript output which calls this named function passing the data object as its only parameter.
5608 callbackParam : "callback",
5610 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5611 * name to the request.
5616 * Load data from the configured URL, read the data object into
5617 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5618 * process that block using the passed callback.
5619 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5620 * for the request to the remote server.
5621 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5622 * object into a block of Roo.data.Records.
5623 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5624 * The function must be passed <ul>
5625 * <li>The Record block object</li>
5626 * <li>The "arg" argument from the load function</li>
5627 * <li>A boolean success indicator</li>
5629 * @param {Object} scope The scope in which to call the callback
5630 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5632 load : function(params, reader, callback, scope, arg){
5633 if(this.fireEvent("beforeload", this, params) !== false){
5635 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5638 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5640 url += "&_dc=" + (new Date().getTime());
5642 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5645 cb : "stcCallback"+transId,
5646 scriptId : "stcScript"+transId,
5650 callback : callback,
5656 window[trans.cb] = function(o){
5657 conn.handleResponse(o, trans);
5660 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5662 if(this.autoAbort !== false){
5666 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5668 var script = document.createElement("script");
5669 script.setAttribute("src", url);
5670 script.setAttribute("type", "text/javascript");
5671 script.setAttribute("id", trans.scriptId);
5672 this.head.appendChild(script);
5676 callback.call(scope||this, null, arg, false);
5681 isLoading : function(){
5682 return this.trans ? true : false;
5686 * Abort the current server request.
5689 if(this.isLoading()){
5690 this.destroyTrans(this.trans);
5695 destroyTrans : function(trans, isLoaded){
5696 this.head.removeChild(document.getElementById(trans.scriptId));
5697 clearTimeout(trans.timeoutId);
5699 window[trans.cb] = undefined;
5701 delete window[trans.cb];
5704 // if hasn't been loaded, wait for load to remove it to prevent script error
5705 window[trans.cb] = function(){
5706 window[trans.cb] = undefined;
5708 delete window[trans.cb];
5715 handleResponse : function(o, trans){
5717 this.destroyTrans(trans, true);
5720 result = trans.reader.readRecords(o);
5722 this.fireEvent("loadexception", this, o, trans.arg, e);
5723 trans.callback.call(trans.scope||window, null, trans.arg, false);
5726 this.fireEvent("load", this, o, trans.arg);
5727 trans.callback.call(trans.scope||window, result, trans.arg, true);
5731 handleFailure : function(trans){
5733 this.destroyTrans(trans, false);
5734 this.fireEvent("loadexception", this, null, trans.arg);
5735 trans.callback.call(trans.scope||window, null, trans.arg, false);
5739 * Ext JS Library 1.1.1
5740 * Copyright(c) 2006-2007, Ext JS, LLC.
5742 * Originally Released Under LGPL - original licence link has changed is not relivant.
5745 * <script type="text/javascript">
5749 * @class Roo.data.JsonReader
5750 * @extends Roo.data.DataReader
5751 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5752 * based on mappings in a provided Roo.data.Record constructor.
5754 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5755 * in the reply previously.
5760 var RecordDef = Roo.data.Record.create([
5761 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5762 {name: 'occupation'} // This field will use "occupation" as the mapping.
5764 var myReader = new Roo.data.JsonReader({
5765 totalProperty: "results", // The property which contains the total dataset size (optional)
5766 root: "rows", // The property which contains an Array of row objects
5767 id: "id" // The property within each row object that provides an ID for the record (optional)
5771 * This would consume a JSON file like this:
5773 { 'results': 2, 'rows': [
5774 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5775 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5778 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5779 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5780 * paged from the remote server.
5781 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5782 * @cfg {String} root name of the property which contains the Array of row objects.
5783 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5785 * Create a new JsonReader
5786 * @param {Object} meta Metadata configuration options
5787 * @param {Object} recordType Either an Array of field definition objects,
5788 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5790 Roo.data.JsonReader = function(meta, recordType){
5793 // set some defaults:
5795 totalProperty: 'total',
5796 successProperty : 'success',
5801 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5803 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5806 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
5807 * Used by Store query builder to append _requestMeta to params.
5810 metaFromRemote : false,
5812 * This method is only used by a DataProxy which has retrieved data from a remote server.
5813 * @param {Object} response The XHR object which contains the JSON data in its responseText.
5814 * @return {Object} data A data block which is used by an Roo.data.Store object as
5815 * a cache of Roo.data.Records.
5817 read : function(response){
5818 var json = response.responseText;
5820 var o = /* eval:var:o */ eval("("+json+")");
5822 throw {message: "JsonReader.read: Json object not found"};
5828 this.metaFromRemote = true;
5829 this.meta = o.metaData;
5830 this.recordType = Roo.data.Record.create(o.metaData.fields);
5831 this.onMetaChange(this.meta, this.recordType, o);
5833 return this.readRecords(o);
5836 // private function a store will implement
5837 onMetaChange : function(meta, recordType, o){
5844 simpleAccess: function(obj, subsc) {
5851 getJsonAccessor: function(){
5853 return function(expr) {
5855 return(re.test(expr))
5856 ? new Function("obj", "return obj." + expr)
5866 * Create a data block containing Roo.data.Records from an XML document.
5867 * @param {Object} o An object which contains an Array of row objects in the property specified
5868 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
5869 * which contains the total size of the dataset.
5870 * @return {Object} data A data block which is used by an Roo.data.Store object as
5871 * a cache of Roo.data.Records.
5873 readRecords : function(o){
5875 * After any data loads, the raw JSON data is available for further custom processing.
5879 var s = this.meta, Record = this.recordType,
5880 f = Record.prototype.fields, fi = f.items, fl = f.length;
5882 // Generate extraction functions for the totalProperty, the root, the id, and for each field
5884 if(s.totalProperty) {
5885 this.getTotal = this.getJsonAccessor(s.totalProperty);
5887 if(s.successProperty) {
5888 this.getSuccess = this.getJsonAccessor(s.successProperty);
5890 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
5892 var g = this.getJsonAccessor(s.id);
5893 this.getId = function(rec) {
5895 return (r === undefined || r === "") ? null : r;
5898 this.getId = function(){return null;};
5901 for(var jj = 0; jj < fl; jj++){
5903 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
5904 this.ef[jj] = this.getJsonAccessor(map);
5908 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
5909 if(s.totalProperty){
5910 var vt = parseInt(this.getTotal(o), 10);
5915 if(s.successProperty){
5916 var vs = this.getSuccess(o);
5917 if(vs === false || vs === 'false'){
5922 for(var i = 0; i < c; i++){
5925 var id = this.getId(n);
5926 for(var j = 0; j < fl; j++){
5928 var v = this.ef[j](n);
5930 Roo.log('missing convert for ' + f.name);
5934 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
5936 var record = new Record(values, id);
5938 records[i] = record;
5944 totalRecords : totalRecords
5949 * Ext JS Library 1.1.1
5950 * Copyright(c) 2006-2007, Ext JS, LLC.
5952 * Originally Released Under LGPL - original licence link has changed is not relivant.
5955 * <script type="text/javascript">
5959 * @class Roo.data.ArrayReader
5960 * @extends Roo.data.DataReader
5961 * Data reader class to create an Array of Roo.data.Record objects from an Array.
5962 * Each element of that Array represents a row of data fields. The
5963 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
5964 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
5968 var RecordDef = Roo.data.Record.create([
5969 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
5970 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
5972 var myReader = new Roo.data.ArrayReader({
5973 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
5977 * This would consume an Array like this:
5979 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
5981 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
5983 * Create a new JsonReader
5984 * @param {Object} meta Metadata configuration options.
5985 * @param {Object} recordType Either an Array of field definition objects
5986 * as specified to {@link Roo.data.Record#create},
5987 * or an {@link Roo.data.Record} object
5988 * created using {@link Roo.data.Record#create}.
5990 Roo.data.ArrayReader = function(meta, recordType){
5991 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
5994 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
5996 * Create a data block containing Roo.data.Records from an XML document.
5997 * @param {Object} o An Array of row objects which represents the dataset.
5998 * @return {Object} data A data block which is used by an Roo.data.Store object as
5999 * a cache of Roo.data.Records.
6001 readRecords : function(o){
6002 var sid = this.meta ? this.meta.id : null;
6003 var recordType = this.recordType, fields = recordType.prototype.fields;
6006 for(var i = 0; i < root.length; i++){
6009 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6010 for(var j = 0, jlen = fields.length; j < jlen; j++){
6011 var f = fields.items[j];
6012 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6013 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6017 var record = new recordType(values, id);
6019 records[records.length] = record;
6023 totalRecords : records.length
6032 * @class Roo.bootstrap.ComboBox
6033 * @extends Roo.bootstrap.TriggerField
6034 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6036 * Create a new ComboBox.
6037 * @param {Object} config Configuration options
6039 Roo.bootstrap.ComboBox = function(config){
6040 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6044 * Fires when the dropdown list is expanded
6045 * @param {Roo.bootstrap.ComboBox} combo This combo box
6050 * Fires when the dropdown list is collapsed
6051 * @param {Roo.bootstrap.ComboBox} combo This combo box
6055 * @event beforeselect
6056 * Fires before a list item is selected. Return false to cancel the selection.
6057 * @param {Roo.bootstrap.ComboBox} combo This combo box
6058 * @param {Roo.data.Record} record The data record returned from the underlying store
6059 * @param {Number} index The index of the selected item in the dropdown list
6061 'beforeselect' : true,
6064 * Fires when a list item is selected
6065 * @param {Roo.bootstrap.ComboBox} combo This combo box
6066 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6067 * @param {Number} index The index of the selected item in the dropdown list
6071 * @event beforequery
6072 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6073 * The event object passed has these properties:
6074 * @param {Roo.bootstrap.ComboBox} combo This combo box
6075 * @param {String} query The query
6076 * @param {Boolean} forceAll true to force "all" query
6077 * @param {Boolean} cancel true to cancel the query
6078 * @param {Object} e The query event object
6080 'beforequery': true,
6083 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6084 * @param {Roo.bootstrap.ComboBox} combo This combo box
6089 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6090 * @param {Roo.bootstrap.ComboBox} combo This combo box
6091 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6099 this.selectedIndex = -1;
6100 if(this.mode == 'local'){
6101 if(config.queryDelay === undefined){
6102 this.queryDelay = 10;
6104 if(config.minChars === undefined){
6110 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6113 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6114 * rendering into an Roo.Editor, defaults to false)
6117 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6118 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6121 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6124 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6125 * the dropdown list (defaults to undefined, with no header element)
6129 * @cfg {String/Roo.Template} tpl The template to use to render the output
6133 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6135 listWidth: undefined,
6137 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6138 * mode = 'remote' or 'text' if mode = 'local')
6140 displayField: undefined,
6142 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6143 * mode = 'remote' or 'value' if mode = 'local').
6144 * Note: use of a valueField requires the user make a selection
6145 * in order for a value to be mapped.
6147 valueField: undefined,
6151 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6152 * field's data value (defaults to the underlying DOM element's name)
6154 hiddenName: undefined,
6156 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6160 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6162 selectedClass: 'active',
6165 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6169 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6170 * anchor positions (defaults to 'tl-bl')
6172 listAlign: 'tl-bl?',
6174 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6178 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
6179 * query specified by the allQuery config option (defaults to 'query')
6181 triggerAction: 'query',
6183 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6184 * (defaults to 4, does not apply if editable = false)
6188 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6189 * delay (typeAheadDelay) if it matches a known value (defaults to false)
6193 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6194 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6198 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6199 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
6203 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
6204 * when editable = true (defaults to false)
6206 selectOnFocus:false,
6208 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6210 queryParam: 'query',
6212 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
6213 * when mode = 'remote' (defaults to 'Loading...')
6215 loadingText: 'Loading...',
6217 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6221 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6225 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6226 * traditional select (defaults to true)
6230 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6234 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6238 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6239 * listWidth has a higher value)
6243 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6244 * allow the user to set arbitrary text into the field (defaults to false)
6246 forceSelection:false,
6248 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6249 * if typeAhead = true (defaults to 250)
6251 typeAheadDelay : 250,
6253 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6254 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6256 valueNotFoundText : undefined,
6258 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6263 * @cfg {Boolean} disableClear Disable showing of clear button.
6265 disableClear : false,
6267 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
6269 alwaysQuery : false,
6275 // element that contains real text value.. (when hidden is used..)
6278 initEvents: function(){
6281 throw "can not find store for combo";
6283 this.store = Roo.factory(this.store, Roo.data);
6287 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6290 if(this.hiddenName){
6292 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6294 this.hiddenField.dom.value =
6295 this.hiddenValue !== undefined ? this.hiddenValue :
6296 this.value !== undefined ? this.value : '';
6298 // prevent input submission
6299 this.el.dom.removeAttribute('name');
6300 this.hiddenField.dom.setAttribute('name', this.hiddenName);
6305 // this.el.dom.setAttribute('autocomplete', 'off');
6308 var cls = 'x-combo-list';
6309 this.list = this.el.select('ul',true).first();
6311 //this.list = new Roo.Layer({
6312 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6315 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6316 this.list.setWidth(lw);
6318 this.list.swallowEvent('mousewheel');
6319 this.assetHeight = 0;
6322 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6323 this.assetHeight += this.header.getHeight();
6326 this.innerList = this.list.createChild({cls:cls+'-inner'});
6327 this.innerList.on('mouseover', this.onViewOver, this);
6328 this.innerList.on('mousemove', this.onViewMove, this);
6329 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6331 if(this.allowBlank && !this.pageSize && !this.disableClear){
6332 this.footer = this.list.createChild({cls:cls+'-ft'});
6333 this.pageTb = new Roo.Toolbar(this.footer);
6337 this.footer = this.list.createChild({cls:cls+'-ft'});
6338 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6339 {pageSize: this.pageSize});
6343 if (this.pageTb && this.allowBlank && !this.disableClear) {
6345 this.pageTb.add(new Roo.Toolbar.Fill(), {
6346 cls: 'x-btn-icon x-btn-clear',
6352 _this.onSelect(false, -1);
6357 this.assetHeight += this.footer.getHeight();
6362 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6365 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6366 singleSelect:true, store: this.store, selectedClass: this.selectedClass
6368 //this.view.wrapEl.setDisplayed(false);
6369 this.view.on('click', this.onViewClick, this);
6373 this.store.on('beforeload', this.onBeforeLoad, this);
6374 this.store.on('load', this.onLoad, this);
6375 this.store.on('loadexception', this.onLoadException, this);
6378 this.resizer = new Roo.Resizable(this.list, {
6379 pinned:true, handles:'se'
6381 this.resizer.on('resize', function(r, w, h){
6382 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6384 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6385 this.restrictHeight();
6387 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6391 this.editable = true;
6392 this.setEditable(false);
6397 if (typeof(this.events.add.listeners) != 'undefined') {
6399 this.addicon = this.wrap.createChild(
6400 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
6402 this.addicon.on('click', function(e) {
6403 this.fireEvent('add', this);
6406 if (typeof(this.events.edit.listeners) != 'undefined') {
6408 this.editicon = this.wrap.createChild(
6409 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
6411 this.editicon.setStyle('margin-left', '40px');
6413 this.editicon.on('click', function(e) {
6415 // we fire even if inothing is selected..
6416 this.fireEvent('edit', this, this.lastData );
6423 this.keyNav = new Roo.KeyNav(this.inputEl(), {
6425 this.inKeyMode = true;
6429 "down" : function(e){
6430 if(!this.isExpanded()){
6431 this.onTriggerClick();
6433 this.inKeyMode = true;
6438 "enter" : function(e){
6443 "esc" : function(e){
6447 "tab" : function(e){
6448 this.onViewClick(false);
6449 this.fireEvent("specialkey", this, e);
6455 doRelay : function(foo, bar, hname){
6456 if(hname == 'down' || this.scope.isExpanded()){
6457 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6466 this.queryDelay = Math.max(this.queryDelay || 10,
6467 this.mode == 'local' ? 10 : 250);
6470 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6473 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6475 if(this.editable !== false){
6476 this.inputEl().on("keyup", this.onKeyUp, this);
6478 if(this.forceSelection){
6479 this.on('blur', this.doForce, this);
6483 onDestroy : function(){
6485 this.view.setStore(null);
6486 this.view.el.removeAllListeners();
6487 this.view.el.remove();
6488 this.view.purgeListeners();
6491 this.list.dom.innerHTML = '';
6494 this.store.un('beforeload', this.onBeforeLoad, this);
6495 this.store.un('load', this.onLoad, this);
6496 this.store.un('loadexception', this.onLoadException, this);
6498 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6502 fireKey : function(e){
6503 if(e.isNavKeyPress() && !this.list.isVisible()){
6504 this.fireEvent("specialkey", this, e);
6509 onResize: function(w, h){
6510 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6512 if(typeof w != 'number'){
6513 // we do not handle it!?!?
6516 var tw = this.trigger.getWidth();
6517 // tw += this.addicon ? this.addicon.getWidth() : 0;
6518 // tw += this.editicon ? this.editicon.getWidth() : 0;
6520 this.inputEl().setWidth( this.adjustWidth('input', x));
6522 //this.trigger.setStyle('left', x+'px');
6524 if(this.list && this.listWidth === undefined){
6525 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6526 this.list.setWidth(lw);
6527 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6535 * Allow or prevent the user from directly editing the field text. If false is passed,
6536 * the user will only be able to select from the items defined in the dropdown list. This method
6537 * is the runtime equivalent of setting the 'editable' config option at config time.
6538 * @param {Boolean} value True to allow the user to directly edit the field text
6540 setEditable : function(value){
6541 if(value == this.editable){
6544 this.editable = value;
6546 this.inputEl().dom.setAttribute('readOnly', true);
6547 this.inputEl().on('mousedown', this.onTriggerClick, this);
6548 this.inputEl().addClass('x-combo-noedit');
6550 this.inputEl().dom.setAttribute('readOnly', false);
6551 this.inputEl().un('mousedown', this.onTriggerClick, this);
6552 this.inputEl().removeClass('x-combo-noedit');
6557 onBeforeLoad : function(){
6561 //this.innerList.update(this.loadingText ?
6562 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6563 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6565 this.restrictHeight();
6566 this.selectedIndex = -1;
6570 onLoad : function(){
6574 if(this.store.getCount() > 0){
6576 this.restrictHeight();
6577 if(this.lastQuery == this.allQuery){
6579 this.inputEl().dom.select();
6581 if(!this.selectByValue(this.value, true)){
6582 this.select(0, true);
6586 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6587 this.taTask.delay(this.typeAheadDelay);
6591 this.onEmptyResults();
6596 onLoadException : function()
6599 Roo.log(this.store.reader.jsonData);
6600 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6602 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6608 onTypeAhead : function(){
6609 if(this.store.getCount() > 0){
6610 var r = this.store.getAt(0);
6611 var newValue = r.data[this.displayField];
6612 var len = newValue.length;
6613 var selStart = this.getRawValue().length;
6614 if(selStart != len){
6615 this.setRawValue(newValue);
6616 this.selectText(selStart, newValue.length);
6622 onSelect : function(record, index){
6623 if(this.fireEvent('beforeselect', this, record, index) !== false){
6624 this.setFromData(index > -1 ? record.data : false);
6626 this.fireEvent('select', this, record, index);
6631 * Returns the currently selected field value or empty string if no value is set.
6632 * @return {String} value The selected value
6634 getValue : function(){
6635 if(this.valueField){
6636 return typeof this.value != 'undefined' ? this.value : '';
6638 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6643 * Clears any text/value currently set in the field
6645 clearValue : function(){
6646 if(this.hiddenField){
6647 this.hiddenField.dom.value = '';
6650 this.setRawValue('');
6651 this.lastSelectionText = '';
6656 * Sets the specified value into the field. If the value finds a match, the corresponding record text
6657 * will be displayed in the field. If the value does not match the data value of an existing item,
6658 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6659 * Otherwise the field will be blank (although the value will still be set).
6660 * @param {String} value The value to match
6662 setValue : function(v){
6664 if(this.valueField){
6665 var r = this.findRecord(this.valueField, v);
6667 text = r.data[this.displayField];
6668 }else if(this.valueNotFoundText !== undefined){
6669 text = this.valueNotFoundText;
6672 this.lastSelectionText = text;
6673 if(this.hiddenField){
6674 this.hiddenField.dom.value = v;
6676 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6680 * @property {Object} the last set data for the element
6685 * Sets the value of the field based on a object which is related to the record format for the store.
6686 * @param {Object} value the value to set as. or false on reset?
6688 setFromData : function(o){
6689 var dv = ''; // display value
6690 var vv = ''; // value value..
6692 if (this.displayField) {
6693 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6695 // this is an error condition!!!
6696 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
6699 if(this.valueField){
6700 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6702 if(this.hiddenField){
6703 this.hiddenField.dom.value = vv;
6705 this.lastSelectionText = dv;
6706 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6710 // no hidden field.. - we store the value in 'value', but still display
6711 // display field!!!!
6712 this.lastSelectionText = dv;
6713 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6720 // overridden so that last data is reset..
6721 this.setValue(this.originalValue);
6722 this.clearInvalid();
6723 this.lastData = false;
6725 this.view.clearSelections();
6729 findRecord : function(prop, value){
6731 if(this.store.getCount() > 0){
6732 this.store.each(function(r){
6733 if(r.data[prop] == value){
6745 // returns hidden if it's set..
6746 if (!this.rendered) {return ''};
6747 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
6751 onViewMove : function(e, t){
6752 this.inKeyMode = false;
6756 onViewOver : function(e, t){
6757 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6760 var item = this.view.findItemFromChild(t);
6762 var index = this.view.indexOf(item);
6763 this.select(index, false);
6768 onViewClick : function(doFocus)
6770 var index = this.view.getSelectedIndexes()[0];
6771 var r = this.store.getAt(index);
6773 this.onSelect(r, index);
6775 if(doFocus !== false && !this.blockFocus){
6776 this.inputEl().focus();
6781 restrictHeight : function(){
6782 //this.innerList.dom.style.height = '';
6783 //var inner = this.innerList.dom;
6784 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6785 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6786 //this.list.beginUpdate();
6787 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6788 this.list.alignTo(this.inputEl(), this.listAlign);
6789 //this.list.endUpdate();
6793 onEmptyResults : function(){
6798 * Returns true if the dropdown list is expanded, else false.
6800 isExpanded : function(){
6801 return this.list.isVisible();
6805 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6806 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6807 * @param {String} value The data value of the item to select
6808 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6809 * selected item if it is not currently in view (defaults to true)
6810 * @return {Boolean} True if the value matched an item in the list, else false
6812 selectByValue : function(v, scrollIntoView){
6813 if(v !== undefined && v !== null){
6814 var r = this.findRecord(this.valueField || this.displayField, v);
6816 this.select(this.store.indexOf(r), scrollIntoView);
6824 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
6825 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6826 * @param {Number} index The zero-based index of the list item to select
6827 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6828 * selected item if it is not currently in view (defaults to true)
6830 select : function(index, scrollIntoView){
6831 this.selectedIndex = index;
6832 this.view.select(index);
6833 if(scrollIntoView !== false){
6834 var el = this.view.getNode(index);
6836 //this.innerList.scrollChildIntoView(el, false);
6843 selectNext : function(){
6844 var ct = this.store.getCount();
6846 if(this.selectedIndex == -1){
6848 }else if(this.selectedIndex < ct-1){
6849 this.select(this.selectedIndex+1);
6855 selectPrev : function(){
6856 var ct = this.store.getCount();
6858 if(this.selectedIndex == -1){
6860 }else if(this.selectedIndex != 0){
6861 this.select(this.selectedIndex-1);
6867 onKeyUp : function(e){
6868 if(this.editable !== false && !e.isSpecialKey()){
6869 this.lastKey = e.getKey();
6870 this.dqTask.delay(this.queryDelay);
6875 validateBlur : function(){
6876 return !this.list || !this.list.isVisible();
6880 initQuery : function(){
6881 this.doQuery(this.getRawValue());
6885 doForce : function(){
6886 if(this.el.dom.value.length > 0){
6888 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
6894 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
6895 * query allowing the query action to be canceled if needed.
6896 * @param {String} query The SQL query to execute
6897 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
6898 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
6899 * saved in the current store (defaults to false)
6901 doQuery : function(q, forceAll){
6902 if(q === undefined || q === null){
6911 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
6915 forceAll = qe.forceAll;
6916 if(forceAll === true || (q.length >= this.minChars)){
6917 if(this.lastQuery != q || this.alwaysQuery){
6919 if(this.mode == 'local'){
6920 this.selectedIndex = -1;
6922 this.store.clearFilter();
6924 this.store.filter(this.displayField, q);
6928 this.store.baseParams[this.queryParam] = q;
6930 params: this.getParams(q)
6935 this.selectedIndex = -1;
6942 getParams : function(q){
6944 //p[this.queryParam] = q;
6947 p.limit = this.pageSize;
6953 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
6955 collapse : function(){
6956 if(!this.isExpanded()){
6960 Roo.get(document).un('mousedown', this.collapseIf, this);
6961 Roo.get(document).un('mousewheel', this.collapseIf, this);
6962 if (!this.editable) {
6963 Roo.get(document).un('keydown', this.listKeyPress, this);
6965 this.fireEvent('collapse', this);
6969 collapseIf : function(e){
6970 if(!e.within(this.el) && !e.within(this.el)){
6976 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
6978 expand : function(){
6980 if(this.isExpanded() || !this.hasFocus){
6983 this.list.alignTo(this.inputEl(), this.listAlign);
6985 Roo.get(document).on('mousedown', this.collapseIf, this);
6986 Roo.get(document).on('mousewheel', this.collapseIf, this);
6987 if (!this.editable) {
6988 Roo.get(document).on('keydown', this.listKeyPress, this);
6991 this.fireEvent('expand', this);
6995 // Implements the default empty TriggerField.onTriggerClick function
6996 onTriggerClick : function()
6998 Roo.log('trigger click');
7003 if(this.isExpanded()){
7005 if (!this.blockFocus) {
7006 this.inputEl().focus();
7010 this.hasFocus = true;
7011 if(this.triggerAction == 'all') {
7012 this.doQuery(this.allQuery, true);
7014 this.doQuery(this.getRawValue());
7016 if (!this.blockFocus) {
7017 this.inputEl().focus();
7021 listKeyPress : function(e)
7023 //Roo.log('listkeypress');
7024 // scroll to first matching element based on key pres..
7025 if (e.isSpecialKey()) {
7028 var k = String.fromCharCode(e.getKey()).toUpperCase();
7031 var csel = this.view.getSelectedNodes();
7032 var cselitem = false;
7034 var ix = this.view.indexOf(csel[0]);
7035 cselitem = this.store.getAt(ix);
7036 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7042 this.store.each(function(v) {
7044 // start at existing selection.
7045 if (cselitem.id == v.id) {
7051 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7052 match = this.store.indexOf(v);
7058 if (match === false) {
7059 return true; // no more action?
7062 this.view.select(match);
7063 var sn = Roo.get(this.view.getSelectedNodes()[0])
7064 //sn.scrollIntoView(sn.dom.parentNode, false);
7068 * @cfg {Boolean} grow
7072 * @cfg {Number} growMin
7076 * @cfg {Number} growMax
7085 * Ext JS Library 1.1.1
7086 * Copyright(c) 2006-2007, Ext JS, LLC.
7088 * Originally Released Under LGPL - original licence link has changed is not relivant.
7091 * <script type="text/javascript">
7096 * @extends Roo.util.Observable
7097 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7098 * This class also supports single and multi selection modes. <br>
7099 * Create a data model bound view:
7101 var store = new Roo.data.Store(...);
7103 var view = new Roo.View({
7105 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7108 selectedClass: "ydataview-selected",
7112 // listen for node click?
7113 view.on("click", function(vw, index, node, e){
7114 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7118 dataModel.load("foobar.xml");
7120 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7122 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7123 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7125 * Note: old style constructor is still suported (container, template, config)
7129 * @param {Object} config The config object
7132 Roo.View = function(config, depreciated_tpl, depreciated_config){
7134 if (typeof(depreciated_tpl) == 'undefined') {
7135 // new way.. - universal constructor.
7136 Roo.apply(this, config);
7137 this.el = Roo.get(this.el);
7140 this.el = Roo.get(config);
7141 this.tpl = depreciated_tpl;
7142 Roo.apply(this, depreciated_config);
7144 this.wrapEl = this.el.wrap().wrap();
7145 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7148 if(typeof(this.tpl) == "string"){
7149 this.tpl = new Roo.Template(this.tpl);
7151 // support xtype ctors..
7152 this.tpl = new Roo.factory(this.tpl, Roo);
7164 * @event beforeclick
7165 * Fires before a click is processed. Returns false to cancel the default action.
7166 * @param {Roo.View} this
7167 * @param {Number} index The index of the target node
7168 * @param {HTMLElement} node The target node
7169 * @param {Roo.EventObject} e The raw event object
7171 "beforeclick" : true,
7174 * Fires when a template node is clicked.
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
7183 * Fires when a template node is double 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
7191 * @event contextmenu
7192 * Fires when a template node is right 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
7198 "contextmenu" : true,
7200 * @event selectionchange
7201 * Fires when the selected nodes change.
7202 * @param {Roo.View} this
7203 * @param {Array} selections Array of the selected nodes
7205 "selectionchange" : true,
7208 * @event beforeselect
7209 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7210 * @param {Roo.View} this
7211 * @param {HTMLElement} node The node to be selected
7212 * @param {Array} selections Array of currently selected nodes
7214 "beforeselect" : true,
7216 * @event preparedata
7217 * Fires on every row to render, to allow you to change the data.
7218 * @param {Roo.View} this
7219 * @param {Object} data to be rendered (change this)
7221 "preparedata" : true
7229 "click": this.onClick,
7230 "dblclick": this.onDblClick,
7231 "contextmenu": this.onContextMenu,
7235 this.selections = [];
7237 this.cmp = new Roo.CompositeElementLite([]);
7239 this.store = Roo.factory(this.store, Roo.data);
7240 this.setStore(this.store, true);
7243 if ( this.footer && this.footer.xtype) {
7245 var fctr = this.wrapEl.appendChild(document.createElement("div"));
7247 this.footer.dataSource = this.store
7248 this.footer.container = fctr;
7249 this.footer = Roo.factory(this.footer, Roo);
7250 fctr.insertFirst(this.el);
7252 // this is a bit insane - as the paging toolbar seems to detach the el..
7253 // dom.parentNode.parentNode.parentNode
7254 // they get detached?
7258 Roo.View.superclass.constructor.call(this);
7263 Roo.extend(Roo.View, Roo.util.Observable, {
7266 * @cfg {Roo.data.Store} store Data store to load data from.
7271 * @cfg {String|Roo.Element} el The container element.
7276 * @cfg {String|Roo.Template} tpl The template used by this View
7280 * @cfg {String} dataName the named area of the template to use as the data area
7281 * Works with domtemplates roo-name="name"
7285 * @cfg {String} selectedClass The css class to add to selected nodes
7287 selectedClass : "x-view-selected",
7289 * @cfg {String} emptyText The empty text to show when nothing is loaded.
7294 * @cfg {String} text to display on mask (default Loading)
7298 * @cfg {Boolean} multiSelect Allow multiple selection
7300 multiSelect : false,
7302 * @cfg {Boolean} singleSelect Allow single selection
7304 singleSelect: false,
7307 * @cfg {Boolean} toggleSelect - selecting
7309 toggleSelect : false,
7312 * Returns the element this view is bound to.
7313 * @return {Roo.Element}
7322 * Refreshes the view. - called by datachanged on the store. - do not call directly.
7324 refresh : function(){
7327 // if we are using something like 'domtemplate', then
7328 // the what gets used is:
7329 // t.applySubtemplate(NAME, data, wrapping data..)
7330 // the outer template then get' applied with
7331 // the store 'extra data'
7332 // and the body get's added to the
7333 // roo-name="data" node?
7334 // <span class='roo-tpl-{name}'></span> ?????
7338 this.clearSelections();
7341 var records = this.store.getRange();
7342 if(records.length < 1) {
7344 // is this valid?? = should it render a template??
7346 this.el.update(this.emptyText);
7350 if (this.dataName) {
7351 this.el.update(t.apply(this.store.meta)); //????
7352 el = this.el.child('.roo-tpl-' + this.dataName);
7355 for(var i = 0, len = records.length; i < len; i++){
7356 var data = this.prepareData(records[i].data, i, records[i]);
7357 this.fireEvent("preparedata", this, data, i, records[i]);
7358 html[html.length] = Roo.util.Format.trim(
7360 t.applySubtemplate(this.dataName, data, this.store.meta) :
7367 el.update(html.join(""));
7368 this.nodes = el.dom.childNodes;
7369 this.updateIndexes(0);
7373 * Function to override to reformat the data that is sent to
7374 * the template for each node.
7375 * DEPRICATED - use the preparedata event handler.
7376 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7377 * a JSON object for an UpdateManager bound view).
7379 prepareData : function(data, index, record)
7381 this.fireEvent("preparedata", this, data, index, record);
7385 onUpdate : function(ds, record){
7386 this.clearSelections();
7387 var index = this.store.indexOf(record);
7388 var n = this.nodes[index];
7389 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7390 n.parentNode.removeChild(n);
7391 this.updateIndexes(index, index);
7397 onAdd : function(ds, records, index)
7399 this.clearSelections();
7400 if(this.nodes.length == 0){
7404 var n = this.nodes[index];
7405 for(var i = 0, len = records.length; i < len; i++){
7406 var d = this.prepareData(records[i].data, i, records[i]);
7408 this.tpl.insertBefore(n, d);
7411 this.tpl.append(this.el, d);
7414 this.updateIndexes(index);
7417 onRemove : function(ds, record, index){
7418 this.clearSelections();
7419 var el = this.dataName ?
7420 this.el.child('.roo-tpl-' + this.dataName) :
7422 el.dom.removeChild(this.nodes[index]);
7423 this.updateIndexes(index);
7427 * Refresh an individual node.
7428 * @param {Number} index
7430 refreshNode : function(index){
7431 this.onUpdate(this.store, this.store.getAt(index));
7434 updateIndexes : function(startIndex, endIndex){
7435 var ns = this.nodes;
7436 startIndex = startIndex || 0;
7437 endIndex = endIndex || ns.length - 1;
7438 for(var i = startIndex; i <= endIndex; i++){
7439 ns[i].nodeIndex = i;
7444 * Changes the data store this view uses and refresh the view.
7445 * @param {Store} store
7447 setStore : function(store, initial){
7448 if(!initial && this.store){
7449 this.store.un("datachanged", this.refresh);
7450 this.store.un("add", this.onAdd);
7451 this.store.un("remove", this.onRemove);
7452 this.store.un("update", this.onUpdate);
7453 this.store.un("clear", this.refresh);
7454 this.store.un("beforeload", this.onBeforeLoad);
7455 this.store.un("load", this.onLoad);
7456 this.store.un("loadexception", this.onLoad);
7460 store.on("datachanged", this.refresh, this);
7461 store.on("add", this.onAdd, this);
7462 store.on("remove", this.onRemove, this);
7463 store.on("update", this.onUpdate, this);
7464 store.on("clear", this.refresh, this);
7465 store.on("beforeload", this.onBeforeLoad, this);
7466 store.on("load", this.onLoad, this);
7467 store.on("loadexception", this.onLoad, this);
7475 * onbeforeLoad - masks the loading area.
7478 onBeforeLoad : function()
7481 this.el.mask(this.mask ? this.mask : "Loading" );
7483 onLoad : function ()
7490 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7491 * @param {HTMLElement} node
7492 * @return {HTMLElement} The template node
7494 findItemFromChild : function(node){
7495 var el = this.dataName ?
7496 this.el.child('.roo-tpl-' + this.dataName,true) :
7499 if(!node || node.parentNode == el){
7502 var p = node.parentNode;
7503 while(p && p != el){
7504 if(p.parentNode == el){
7513 onClick : function(e){
7514 var item = this.findItemFromChild(e.getTarget());
7516 var index = this.indexOf(item);
7517 if(this.onItemClick(item, index, e) !== false){
7518 this.fireEvent("click", this, index, item, e);
7521 this.clearSelections();
7526 onContextMenu : function(e){
7527 var item = this.findItemFromChild(e.getTarget());
7529 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7534 onDblClick : function(e){
7535 var item = this.findItemFromChild(e.getTarget());
7537 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7541 onItemClick : function(item, index, e)
7543 if(this.fireEvent("beforeclick", this, index, item, e) === false){
7546 if (this.toggleSelect) {
7547 var m = this.isSelected(item) ? 'unselect' : 'select';
7550 _t[m](item, true, false);
7553 if(this.multiSelect || this.singleSelect){
7554 if(this.multiSelect && e.shiftKey && this.lastSelection){
7555 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7557 this.select(item, this.multiSelect && e.ctrlKey);
7558 this.lastSelection = item;
7566 * Get the number of selected nodes.
7569 getSelectionCount : function(){
7570 return this.selections.length;
7574 * Get the currently selected nodes.
7575 * @return {Array} An array of HTMLElements
7577 getSelectedNodes : function(){
7578 return this.selections;
7582 * Get the indexes of the selected nodes.
7585 getSelectedIndexes : function(){
7586 var indexes = [], s = this.selections;
7587 for(var i = 0, len = s.length; i < len; i++){
7588 indexes.push(s[i].nodeIndex);
7594 * Clear all selections
7595 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7597 clearSelections : function(suppressEvent){
7598 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7599 this.cmp.elements = this.selections;
7600 this.cmp.removeClass(this.selectedClass);
7601 this.selections = [];
7603 this.fireEvent("selectionchange", this, this.selections);
7609 * Returns true if the passed node is selected
7610 * @param {HTMLElement/Number} node The node or node index
7613 isSelected : function(node){
7614 var s = this.selections;
7618 node = this.getNode(node);
7619 return s.indexOf(node) !== -1;
7624 * @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
7625 * @param {Boolean} keepExisting (optional) true to keep existing selections
7626 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7628 select : function(nodeInfo, keepExisting, suppressEvent){
7629 if(nodeInfo instanceof Array){
7631 this.clearSelections(true);
7633 for(var i = 0, len = nodeInfo.length; i < len; i++){
7634 this.select(nodeInfo[i], true, true);
7638 var node = this.getNode(nodeInfo);
7639 if(!node || this.isSelected(node)){
7640 return; // already selected.
7643 this.clearSelections(true);
7645 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7646 Roo.fly(node).addClass(this.selectedClass);
7647 this.selections.push(node);
7649 this.fireEvent("selectionchange", this, this.selections);
7657 * @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
7658 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7659 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7661 unselect : function(nodeInfo, keepExisting, suppressEvent)
7663 if(nodeInfo instanceof Array){
7664 Roo.each(this.selections, function(s) {
7665 this.unselect(s, nodeInfo);
7669 var node = this.getNode(nodeInfo);
7670 if(!node || !this.isSelected(node)){
7671 Roo.log("not selected");
7672 return; // not selected.
7676 Roo.each(this.selections, function(s) {
7678 Roo.fly(node).removeClass(this.selectedClass);
7685 this.selections= ns;
7686 this.fireEvent("selectionchange", this, this.selections);
7690 * Gets a template node.
7691 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7692 * @return {HTMLElement} The node or null if it wasn't found
7694 getNode : function(nodeInfo){
7695 if(typeof nodeInfo == "string"){
7696 return document.getElementById(nodeInfo);
7697 }else if(typeof nodeInfo == "number"){
7698 return this.nodes[nodeInfo];
7704 * Gets a range template nodes.
7705 * @param {Number} startIndex
7706 * @param {Number} endIndex
7707 * @return {Array} An array of nodes
7709 getNodes : function(start, end){
7710 var ns = this.nodes;
7712 end = typeof end == "undefined" ? ns.length - 1 : end;
7715 for(var i = start; i <= end; i++){
7719 for(var i = start; i >= end; i--){
7727 * Finds the index of the passed node
7728 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7729 * @return {Number} The index of the node or -1
7731 indexOf : function(node){
7732 node = this.getNode(node);
7733 if(typeof node.nodeIndex == "number"){
7734 return node.nodeIndex;
7736 var ns = this.nodes;
7737 for(var i = 0, len = ns.length; i < len; i++){
7748 * based on jquery fullcalendar
7754 * @class Roo.bootstrap.Calendar
7755 * @extends Roo.bootstrap.Component
7756 * Bootstrap Calendar class
7759 * Create a new Container
7760 * @param {Object} config The config object
7763 Roo.bootstrap.Calendar = function(config){
7764 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7768 * Fires when a date is selected
7769 * @param {DatePicker} this
7770 * @param {Date} date The selected date
7774 * @event monthchange
7775 * Fires when the displayed month changes
7776 * @param {DatePicker} this
7777 * @param {Date} date The selected month
7779 'monthchange': true,
7782 * Fires when mouse over an event
7783 * @param {Calendar} this
7784 * @param {event} Event
7789 * Fires when the mouse leaves an
7790 * @param {Calendar} this
7799 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
7802 * @cfg {Number} startDay
7803 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
7807 getAutoCreate : function(){
7810 fc_button = function(name, corner, style, content ) {
7811 return Roo.apply({},{
7813 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
7815 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
7818 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
7826 style : 'width:100%',
7833 cls : 'fc-header-left',
7835 fc_button('prev', 'left', 'arrow', '‹' ),
7836 fc_button('next', 'right', 'arrow', '›' ),
7837 { tag: 'span', cls: 'fc-header-space' },
7838 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
7846 cls : 'fc-header-center',
7850 cls: 'fc-header-title',
7853 html : 'month / year'
7861 cls : 'fc-header-right',
7863 /* fc_button('month', 'left', '', 'month' ),
7864 fc_button('week', '', '', 'week' ),
7865 fc_button('day', 'right', '', 'day' )
7877 var cal_heads = function() {
7879 // fixme - handle this.
7881 for (var i =0; i < Date.dayNames.length; i++) {
7882 var d = Date.dayNames[i];
7885 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
7886 html : d.substring(0,3)
7890 ret[0].cls += ' fc-first';
7891 ret[6].cls += ' fc-last';
7894 var cal_cell = function(n) {
7897 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
7902 cls: 'fc-day-number',
7906 cls: 'fc-day-content',
7910 style: 'position: relative;' // height: 17px;
7922 var cal_rows = function() {
7925 for (var r = 0; r < 6; r++) {
7932 for (var i =0; i < Date.dayNames.length; i++) {
7933 var d = Date.dayNames[i];
7934 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
7937 row.cn[0].cls+=' fc-first';
7938 row.cn[0].cn[0].style = 'min-height:90px';
7939 row.cn[6].cls+=' fc-last';
7943 ret[0].cls += ' fc-first';
7944 ret[4].cls += ' fc-prev-last';
7945 ret[5].cls += ' fc-last';
7952 cls: 'fc-border-separate',
7953 style : 'width:100%',
7961 cls : 'fc-first fc-last',
7980 style : "position: relative;",
7983 cls : 'fc-view fc-view-month fc-grid',
7984 style : 'position: relative',
7985 unselectable : 'on',
7988 cls : 'fc-event-container',
7989 style : 'position:absolute;z-index:8;top:0;left:0;'
8007 initEvents : function()
8010 throw "can not find store for combo";
8013 this.store = Roo.factory(this.store, Roo.data);
8014 this.store.on('load', this.onLoad, this);
8017 this.cells = this.el.select('.fc-day',true);
8018 this.textNodes = this.el.query('.fc-day-number');
8019 this.cells.addClassOnOver('fc-state-hover');
8021 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8022 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8023 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8024 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8026 this.on('monthchange', this.onMonthChange, this);
8028 this.update(new Date().clearTime());
8031 resize : function() {
8032 var sz = this.el.getSize();
8034 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8035 this.el.select('.fc-day-content div',true).setHeight(34);
8040 showPrevMonth : function(e){
8041 this.update(this.activeDate.add("mo", -1));
8043 showToday : function(e){
8044 this.update(new Date().clearTime());
8047 showNextMonth : function(e){
8048 this.update(this.activeDate.add("mo", 1));
8052 showPrevYear : function(){
8053 this.update(this.activeDate.add("y", -1));
8057 showNextYear : function(){
8058 this.update(this.activeDate.add("y", 1));
8063 update : function(date)
8065 var vd = this.activeDate;
8066 this.activeDate = date;
8068 var t = date.getTime();
8069 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8070 Roo.log('using add remove');
8071 this.cells.removeClass("fc-state-highlight");
8072 this.cells.each(function(c){
8073 if(c.dateValue == t){
8074 c.addClass("fc-state-highlight");
8075 setTimeout(function(){
8076 try{c.dom.firstChild.focus();}catch(e){}
8086 var days = date.getDaysInMonth();
8088 var firstOfMonth = date.getFirstDateOfMonth();
8089 var startingPos = firstOfMonth.getDay()-this.startDay;
8091 if(startingPos < this.startDay){
8095 var pm = date.add("mo", -1);
8096 var prevStart = pm.getDaysInMonth()-startingPos;
8098 var cells = this.cells.elements;
8099 var textEls = this.textNodes;
8100 days += startingPos;
8102 // convert everything to numbers so it's fast
8104 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8105 var today = new Date().clearTime().getTime();
8106 var sel = date.clearTime().getTime();
8107 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8108 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8109 var ddMatch = this.disabledDatesRE;
8110 var ddText = this.disabledDatesText;
8111 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8112 var ddaysText = this.disabledDaysText;
8113 var format = this.format;
8115 var setCellClass = function(cal, cell){
8117 var t = d.getTime();
8121 cell.className += " fc-today";
8122 cell.title = cal.todayText;
8125 cell.className += " fc-state-highlight";
8126 //setTimeout(function(){
8127 // try{cell.firstChild.focus();}catch(e){}
8132 cell.className = " fc-state-disabled";
8133 cell.title = cal.minText;
8137 cell.className = " fc-state-disabled";
8138 cell.title = cal.maxText;
8142 if(ddays.indexOf(d.getDay()) != -1){
8143 cell.title = ddaysText;
8144 cell.className = " fc-state-disabled";
8147 if(ddMatch && format){
8148 var fvalue = d.dateFormat(format);
8149 if(ddMatch.test(fvalue)){
8150 cell.title = ddText.replace("%0", fvalue);
8151 cell.className = " fc-state-disabled";
8154 if (!cell.initialClassName) {
8155 cell.initialClassName = cell.dom.className;
8157 cell.dom.className = cell.initialClassName + ' ' + cell.className;
8161 for(; i < startingPos; i++) {
8162 textEls[i].innerHTML = (++prevStart);
8163 d.setDate(d.getDate()+1);
8164 cells[i].className = "fc-past fc-other-month";
8165 setCellClass(this, cells[i]);
8167 for(; i < days; i++){
8168 intDay = i - startingPos + 1;
8169 textEls[i].innerHTML = (intDay);
8170 d.setDate(d.getDate()+1);
8171 cells[i].className = ''; // "x-date-active";
8172 setCellClass(this, cells[i]);
8176 for(; i < 42; i++) {
8177 textEls[i].innerHTML = (++extraDays);
8178 d.setDate(d.getDate()+1);
8179 cells[i].className = "fc-future fc-other-month";
8180 setCellClass(this, cells[i]);
8183 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8185 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
8187 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
8188 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
8191 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
8192 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
8195 this.fireEvent('monthchange', this, date);
8199 if(!this.internalRender){
8200 var main = this.el.dom.firstChild;
8201 var w = main.offsetWidth;
8202 this.el.setWidth(w + this.el.getBorderWidth("lr"));
8203 Roo.fly(main).setWidth(w);
8204 this.internalRender = true;
8205 // opera does not respect the auto grow header center column
8206 // then, after it gets a width opera refuses to recalculate
8207 // without a second pass
8208 if(Roo.isOpera && !this.secondPass){
8209 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8210 this.secondPass = true;
8211 this.update.defer(10, this, [date]);
8218 findCell : function(dt) {
8219 dt = dt.clearTime().getTime();
8221 this.cells.each(function(c){
8222 //Roo.log("check " +c.dateValue + '?=' + dt);
8223 if(c.dateValue == dt){
8233 findCells : function(ev) {
8234 var s = ev.start.clone().clearTime().getTime();
8235 var e= ev.end.clone().clearTime().getTime();
8237 this.cells.each(function(c){
8238 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8240 if(c.dateValue > e){
8243 if(c.dateValue < s){
8252 findBestRow: function(cells)
8256 for (var i =0 ; i < cells.length;i++) {
8257 ret = Math.max(cells[i].rows || 0,ret);
8264 addItem : function(ev)
8266 // look for vertical location slot in
8267 var cells = this.findCells(ev);
8269 ev.row = this.findBestRow(cells);
8271 // work out the location.
8275 for(var i =0; i < cells.length; i++) {
8283 if (crow.start.getY() == cells[i].getY()) {
8285 crow.end = cells[i];
8301 for (var i = 0; i < cells.length;i++) {
8302 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8306 this.calevents.push(ev);
8309 clearEvents: function() {
8311 if(!this.calevents){
8315 Roo.each(this.cells.elements, function(c){
8319 Roo.each(this.calevents, function(e) {
8320 Roo.each(e.els, function(el) {
8321 el.un('mouseenter' ,this.onEventEnter, this);
8322 el.un('mouseleave' ,this.onEventLeave, this);
8329 renderEvents: function()
8331 // first make sure there is enough space..
8333 this.cells.each(function(c) {
8334 // Roo.log(c.select('.fc-day-content div',true).first(), Math.max(34, c.rows * 20));
8335 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8338 for (var e = 0; e < this.calevents.length; e++) {
8339 var ev = this.calevents[e];
8340 var cells = ev.cells;
8343 for(var i =0; i < rows.length; i++) {
8346 // how many rows should it span..
8349 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8350 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8352 unselectable : "on",
8355 cls: 'fc-event-inner',
8359 cls: 'fc-event-time',
8360 html : cells.length > 1 ? '' : ev.time
8364 cls: 'fc-event-title',
8365 html : String.format('{0}', ev.title)
8372 cls: 'ui-resizable-handle ui-resizable-e',
8373 html : '  '
8379 cfg.cls += ' fc-event-start';
8381 if ((i+1) == rows.length) {
8382 cfg.cls += ' fc-event-end';
8385 var ctr = this.el.select('.fc-event-container',true).first();
8386 var cg = ctr.createChild(cfg);
8388 cg.on('mouseenter' ,this.onEventEnter, this);
8389 cg.on('mouseleave' ,this.onEventLeave, this);
8393 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8394 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8396 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
8397 cg.setWidth(ebox.right - sbox.x -2);
8405 onEventEnter: function (e, el,c,d) {
8406 this.fireEvent('evententer', this, el);
8409 onEventLeave: function (e, el,c,d) {
8410 this.fireEvent('eventleave', this, el);
8413 onMonthChange: function () {
8417 onLoad: function () {
8421 this.calevents = [];
8423 if(this.store.getCount() > 0){
8424 this.store.data.each(function(d){
8426 start: new Date(d.data.start_dt),
8427 end : new Date(d.data.end_dt),
8428 time : d.data.start_time,
8429 title : d.data.title
8434 this.renderEvents();
8447 * @class Roo.bootstrap.Popover
8448 * @extends Roo.bootstrap.Component
8449 * Bootstrap Popover class
8450 * @cfg {String} html contents of the popover (or false to use children..)
8451 * @cfg {String} title of popover (or false to hide)
8452 * @cfg {String} placement how it is placed
8453 * @cfg {String} trigger click || hover (or false to trigger manually)
8454 * @cfg {String} over what (parent or false to trigger manually.)
8457 * Create a new Popover
8458 * @param {Object} config The config object
8461 Roo.bootstrap.Popover = function(config){
8462 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8465 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
8467 title: 'Fill in a title',
8470 placement : 'right',
8471 trigger : 'hover', // hover
8475 getChildContainer : function()
8477 return this.el.select('.popover-content',true).first();
8480 getAutoCreate : function(){
8481 Roo.log('make popover?');
8484 style: 'display:block',
8490 cls : 'popover-inner',
8494 cls: 'popover-title',
8498 cls : 'popover-content',
8509 // as it get's added to the bottom of the page.
8510 onRender : function(ct, position)
8512 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8514 var cfg = Roo.apply({}, this.getAutoCreate());
8518 cfg.cls += ' ' + this.cls;
8521 cfg.style = this.style;
8523 Roo.log("adding to ")
8524 this.el = Roo.get(document.body).createChild(cfg, position);
8530 initEvents : function()
8532 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8533 this.el.enableDisplayMode('block');
8535 if (this.over === false) {
8538 if (this.triggers === false) {
8541 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8542 var triggers = this.trigger ? this.trigger.split(' ') : [];
8543 Roo.each(triggers, function(trigger) {
8545 if (trigger == 'click') {
8546 on_el.on('click', this.toggle, this);
8547 } else if (trigger != 'manual') {
8548 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
8549 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8551 on_el.on(eventIn ,this.enter, this);
8552 on_el.on(eventOut, this.leave, this);
8563 toggle : function () {
8564 this.hoverState == 'in' ? this.leave() : this.enter();
8567 enter : function () {
8570 clearTimeout(this.timeout);
8572 this.hoverState = 'in'
8574 if (!this.delay || !this.delay.show) {
8579 this.timeout = setTimeout(function () {
8580 if (_t.hoverState == 'in') {
8585 leave : function() {
8586 clearTimeout(this.timeout);
8588 this.hoverState = 'out'
8590 if (!this.delay || !this.delay.hide) {
8595 this.timeout = setTimeout(function () {
8596 if (_t.hoverState == 'out') {
8602 show : function (on_el)
8605 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8608 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8609 if (this.html !== false) {
8610 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8612 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8613 if (!this.title.length) {
8614 this.el.select('.popover-title',true).hide();
8617 var placement = typeof this.placement == 'function' ?
8618 this.placement.call(this, this.el, on_el) :
8621 var autoToken = /\s?auto?\s?/i;
8622 var autoPlace = autoToken.test(placement);
8624 placement = placement.replace(autoToken, '') || 'top';
8628 //this.el.setXY([0,0]);
8630 this.el.dom.style.display='block';
8631 this.el.addClass(placement);
8633 //this.el.appendTo(on_el);
8635 var p = this.getPosition();
8636 var box = this.el.getBox();
8641 var align = Roo.bootstrap.Popover.alignment[placement]
8642 this.el.alignTo(on_el, align[0],align[1]);
8643 //var arrow = this.el.select('.arrow',true).first();
8644 //arrow.set(align[2],
8646 this.el.addClass('in');
8647 this.hoverState = null;
8649 if (this.el.hasClass('fade')) {
8656 this.el.setXY([0,0]);
8657 this.el.removeClass('in');
8664 Roo.bootstrap.Popover.alignment = {
8665 'left' : ['r-l', [-10,0], 'right'],
8666 'right' : ['l-r', [10,0], 'left'],
8667 'bottom' : ['t-b', [0,10], 'top'],
8668 'top' : [ 'b-t', [0,-10], 'bottom']