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';
1543 * @class Roo.bootstrap.Navbar.Button
1544 * @extends Roo.bootstrap.Component
1545 * Bootstrap Navbar.Button class
1546 * @cfg {String} href link to
1547 * @cfg {String} html content of button
1550 * Create a new Navbar Button
1551 * @param {Object} config The config object
1555 Roo.bootstrap.Navbar.Button = function(config){
1556 Roo.bootstrap.Navbar.Button.superclass.constructor.call(this, config);
1559 Roo.extend(Roo.bootstrap.Navbar.Button, Roo.bootstrap.Component, {
1570 getAutoCreate : function(){
1580 html : this.html || ''
1604 * @class Roo.bootstrap.Navbar.Item
1605 * @extends Roo.bootstrap.Component
1606 * Bootstrap Navbar.Button class
1607 * @cfg {String} href link to
1608 * @cfg {String} html content of button
1609 * @cfg {String} badge text inside badge
1610 * @cfg {String} glyphicon name of glyphicon
1613 * Create a new Navbar Button
1614 * @param {Object} config The config object
1616 Roo.bootstrap.Navbar.Item = function(config){
1617 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1620 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1628 getAutoCreate : function(){
1630 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1632 if (this.parent().parent().sidebar === true) {
1645 cfg.cn[0].html = this.html;
1649 this.cls += ' active';
1653 cfg.cn[0].cls += ' dropdown-toggle';
1654 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1658 cfg.cn[0].tag = 'a',
1659 cfg.cn[0].href = this.href;
1662 if (this.glyphicon) {
1663 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1679 if (this.glyphicon) {
1680 if(cfg.html){cfg.html = ' ' + this.html};
1684 cls: 'glyphicon glyphicon-' + this.glyphicon
1689 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1693 cfg.cn[0].html += " <span class='caret'></span>";
1694 //}else if (!this.href) {
1695 // cfg.cn[0].tag='p';
1696 // cfg.cn[0].cls='navbar-text';
1699 cfg.cn[0].href=this.href||'#';
1700 cfg.cn[0].html=this.html;
1703 if (this.badge !== '') {
1706 cfg.cn[0].html + ' ',
1719 initEvents: function() {
1720 // Roo.log('init events?');
1721 // Roo.log(this.el.dom);
1722 this.el.select('a',true).on('click',
1724 this.fireEvent('click', this);
1741 * @class Roo.bootstrap.Row
1742 * @extends Roo.bootstrap.Component
1743 * Bootstrap Row class (contains columns...)
1747 * @param {Object} config The config object
1750 Roo.bootstrap.Row = function(config){
1751 Roo.bootstrap.Row.superclass.constructor.call(this, config);
1754 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
1756 getAutoCreate : function(){
1775 * @class Roo.bootstrap.Element
1776 * @extends Roo.bootstrap.Component
1777 * Bootstrap Element class
1778 * @cfg {String} html contents of the element
1779 * @cfg {String} tag tag of the element
1780 * @cfg {String} cls class of the element
1783 * Create a new Element
1784 * @param {Object} config The config object
1787 Roo.bootstrap.Element = function(config){
1788 Roo.bootstrap.Element.superclass.constructor.call(this, config);
1791 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
1798 getAutoCreate : function(){
1821 * @class Roo.bootstrap.Pagination
1822 * @extends Roo.bootstrap.Component
1823 * Bootstrap Pagination class
1824 * @cfg {String} size xs | sm | md | lg
1825 * @cfg {Boolean} inverse false | true
1826 * @cfg {Number} from pagination starting number
1827 * @cfg {Number} to pagination ending number
1828 * @cfg {String} align empty or left | right
1829 * @cfg {Number} active active page number
1832 * Create a new Pagination
1833 * @param {Object} config The config object
1836 Roo.bootstrap.Pagination = function(config){
1837 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1840 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
1850 getAutoCreate : function(){
1857 cfg.cls += ' inverse';
1875 var from=this.from>0?this.from:1;
1876 var to=this.to-from<=10?this.to:from+10;
1877 var active=this.active>=from&&this.active<=to?this.active:null;
1878 for (var i=from;i<=to;i++) {
1882 cls: active===i?'active':'',
1923 * @class Roo.bootstrap.Slider
1924 * @extends Roo.bootstrap.Component
1925 * Bootstrap Slider class
1928 * Create a new Slider
1929 * @param {Object} config The config object
1932 Roo.bootstrap.Slider = function(config){
1933 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1936 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
1938 getAutoCreate : function(){
1942 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1946 cls: 'ui-slider-handle ui-state-default ui-corner-all'
1964 * @class Roo.bootstrap.Table
1965 * @extends Roo.bootstrap.Component
1966 * Bootstrap Table class
1969 * Create a new Table
1970 * @param {Object} config The config object
1973 Roo.bootstrap.Table = function(config){
1974 Roo.bootstrap.Table.superclass.constructor.call(this, config);
1977 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
1982 getAutoCreate : function(){
1983 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2015 * @class Roo.bootstrap.TableCell
2016 * @extends Roo.bootstrap.Component
2017 * Bootstrap TableCell class
2020 * Create a new TableCell
2021 * @param {Object} config The config object
2024 Roo.bootstrap.TableCell = function(config){
2025 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2028 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2030 getAutoCreate : function(){
2031 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2058 * @class Roo.bootstrap.TableRow
2059 * @extends Roo.bootstrap.Component
2060 * Bootstrap TableRow class
2063 * Create a new TableRow
2064 * @param {Object} config The config object
2067 Roo.bootstrap.TableRow = function(config){
2068 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2071 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2073 getAutoCreate : function(){
2074 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2089 * Ext JS Library 1.1.1
2090 * Copyright(c) 2006-2007, Ext JS, LLC.
2092 * Originally Released Under LGPL - original licence link has changed is not relivant.
2095 * <script type="text/javascript">
2098 // as we use this in bootstrap.
2099 Roo.namespace('Roo.form');
2101 * @class Roo.form.Action
2102 * Internal Class used to handle form actions
2104 * @param {Roo.form.BasicForm} el The form element or its id
2105 * @param {Object} config Configuration options
2110 // define the action interface
2111 Roo.form.Action = function(form, options){
2113 this.options = options || {};
2116 * Client Validation Failed
2119 Roo.form.Action.CLIENT_INVALID = 'client';
2121 * Server Validation Failed
2124 Roo.form.Action.SERVER_INVALID = 'server';
2126 * Connect to Server Failed
2129 Roo.form.Action.CONNECT_FAILURE = 'connect';
2131 * Reading Data from Server Failed
2134 Roo.form.Action.LOAD_FAILURE = 'load';
2136 Roo.form.Action.prototype = {
2138 failureType : undefined,
2139 response : undefined,
2143 run : function(options){
2148 success : function(response){
2153 handleResponse : function(response){
2157 // default connection failure
2158 failure : function(response){
2160 this.response = response;
2161 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2162 this.form.afterAction(this, false);
2165 processResponse : function(response){
2166 this.response = response;
2167 if(!response.responseText){
2170 this.result = this.handleResponse(response);
2174 // utility functions used internally
2175 getUrl : function(appendParams){
2176 var url = this.options.url || this.form.url || this.form.el.dom.action;
2178 var p = this.getParams();
2180 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2186 getMethod : function(){
2187 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2190 getParams : function(){
2191 var bp = this.form.baseParams;
2192 var p = this.options.params;
2194 if(typeof p == "object"){
2195 p = Roo.urlEncode(Roo.applyIf(p, bp));
2196 }else if(typeof p == 'string' && bp){
2197 p += '&' + Roo.urlEncode(bp);
2200 p = Roo.urlEncode(bp);
2205 createCallback : function(){
2207 success: this.success,
2208 failure: this.failure,
2210 timeout: (this.form.timeout*1000),
2211 upload: this.form.fileUpload ? this.success : undefined
2216 Roo.form.Action.Submit = function(form, options){
2217 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2220 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2223 haveProgress : false,
2224 uploadComplete : false,
2226 // uploadProgress indicator.
2227 uploadProgress : function()
2229 if (!this.form.progressUrl) {
2233 if (!this.haveProgress) {
2234 Roo.MessageBox.progress("Uploading", "Uploading");
2236 if (this.uploadComplete) {
2237 Roo.MessageBox.hide();
2241 this.haveProgress = true;
2243 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2245 var c = new Roo.data.Connection();
2247 url : this.form.progressUrl,
2252 success : function(req){
2253 //console.log(data);
2257 rdata = Roo.decode(req.responseText)
2259 Roo.log("Invalid data from server..");
2263 if (!rdata || !rdata.success) {
2265 Roo.MessageBox.alert(Roo.encode(rdata));
2268 var data = rdata.data;
2270 if (this.uploadComplete) {
2271 Roo.MessageBox.hide();
2276 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2277 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2280 this.uploadProgress.defer(2000,this);
2283 failure: function(data) {
2284 Roo.log('progress url failed ');
2295 // run get Values on the form, so it syncs any secondary forms.
2296 this.form.getValues();
2298 var o = this.options;
2299 var method = this.getMethod();
2300 var isPost = method == 'POST';
2301 if(o.clientValidation === false || this.form.isValid()){
2303 if (this.form.progressUrl) {
2304 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2305 (new Date() * 1) + '' + Math.random());
2310 Roo.Ajax.request(Roo.apply(this.createCallback(), {
2311 form:this.form.el.dom,
2312 url:this.getUrl(!isPost),
2314 params:isPost ? this.getParams() : null,
2315 isUpload: this.form.fileUpload
2318 this.uploadProgress();
2320 }else if (o.clientValidation !== false){ // client validation failed
2321 this.failureType = Roo.form.Action.CLIENT_INVALID;
2322 this.form.afterAction(this, false);
2326 success : function(response)
2328 this.uploadComplete= true;
2329 if (this.haveProgress) {
2330 Roo.MessageBox.hide();
2334 var result = this.processResponse(response);
2335 if(result === true || result.success){
2336 this.form.afterAction(this, true);
2340 this.form.markInvalid(result.errors);
2341 this.failureType = Roo.form.Action.SERVER_INVALID;
2343 this.form.afterAction(this, false);
2345 failure : function(response)
2347 this.uploadComplete= true;
2348 if (this.haveProgress) {
2349 Roo.MessageBox.hide();
2352 this.response = response;
2353 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2354 this.form.afterAction(this, false);
2357 handleResponse : function(response){
2358 if(this.form.errorReader){
2359 var rs = this.form.errorReader.read(response);
2362 for(var i = 0, len = rs.records.length; i < len; i++) {
2363 var r = rs.records[i];
2367 if(errors.length < 1){
2371 success : rs.success,
2377 ret = Roo.decode(response.responseText);
2381 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2391 Roo.form.Action.Load = function(form, options){
2392 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2393 this.reader = this.form.reader;
2396 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2401 Roo.Ajax.request(Roo.apply(
2402 this.createCallback(), {
2403 method:this.getMethod(),
2404 url:this.getUrl(false),
2405 params:this.getParams()
2409 success : function(response){
2411 var result = this.processResponse(response);
2412 if(result === true || !result.success || !result.data){
2413 this.failureType = Roo.form.Action.LOAD_FAILURE;
2414 this.form.afterAction(this, false);
2417 this.form.clearInvalid();
2418 this.form.setValues(result.data);
2419 this.form.afterAction(this, true);
2422 handleResponse : function(response){
2423 if(this.form.reader){
2424 var rs = this.form.reader.read(response);
2425 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2427 success : rs.success,
2431 return Roo.decode(response.responseText);
2435 Roo.form.Action.ACTION_TYPES = {
2436 'load' : Roo.form.Action.Load,
2437 'submit' : Roo.form.Action.Submit
2446 * @class Roo.bootstrap.Form
2447 * @extends Roo.bootstrap.Component
2448 * Bootstrap Form class
2449 * @cfg {String} method GET | POST (default POST)
2450 * @cfg {String} labelAlign top | left (default top)
2451 * @cfg {String} align left | right - for navbars
2456 * @param {Object} config The config object
2460 Roo.bootstrap.Form = function(config){
2461 Roo.bootstrap.Form.superclass.constructor.call(this, config);
2464 * @event clientvalidation
2465 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2466 * @param {Form} this
2467 * @param {Boolean} valid true if the form has passed client-side validation
2469 clientvalidation: true,
2471 * @event beforeaction
2472 * Fires before any action is performed. Return false to cancel the action.
2473 * @param {Form} this
2474 * @param {Action} action The action to be performed
2478 * @event actionfailed
2479 * Fires when an action fails.
2480 * @param {Form} this
2481 * @param {Action} action The action that failed
2483 actionfailed : true,
2485 * @event actioncomplete
2486 * Fires when an action is completed.
2487 * @param {Form} this
2488 * @param {Action} action The action that completed
2490 actioncomplete : true
2495 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
2498 * @cfg {String} method
2499 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2504 * The URL to use for form actions if one isn't supplied in the action options.
2507 * @cfg {Boolean} fileUpload
2508 * Set to true if this form is a file upload.
2512 * @cfg {Object} baseParams
2513 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2517 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2521 * @cfg {Sting} align (left|right) for navbar forms
2526 activeAction : null,
2529 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2530 * element by passing it or its id or mask the form itself by passing in true.
2533 waitMsgTarget : false,
2538 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2539 * element by passing it or its id or mask the form itself by passing in true.
2543 getAutoCreate : function(){
2547 method : this.method || 'POST',
2548 id : this.id || Roo.id(),
2551 if (this.parent().xtype.match(/^Nav/)) {
2552 cfg.cls = 'navbar-form navbar-' + this.align;
2556 if (this.labelAlign == 'left' ) {
2557 cfg.cls += ' form-horizontal';
2563 initEvents : function()
2565 this.el.on('submit', this.onSubmit, this);
2570 onSubmit : function(e){
2575 * Returns true if client-side validation on the form is successful.
2578 isValid : function(){
2579 var items = this.getItems();
2581 items.each(function(f){
2590 * Returns true if any fields in this form have changed since their original load.
2593 isDirty : function(){
2595 var items = this.getItems();
2596 items.each(function(f){
2606 * Performs a predefined action (submit or load) or custom actions you define on this form.
2607 * @param {String} actionName The name of the action type
2608 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
2609 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2610 * accept other config options):
2612 Property Type Description
2613 ---------------- --------------- ----------------------------------------------------------------------------------
2614 url String The url for the action (defaults to the form's url)
2615 method String The form method to use (defaults to the form's method, or POST if not defined)
2616 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
2617 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
2618 validate the form on the client (defaults to false)
2620 * @return {BasicForm} this
2622 doAction : function(action, options){
2623 if(typeof action == 'string'){
2624 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2626 if(this.fireEvent('beforeaction', this, action) !== false){
2627 this.beforeAction(action);
2628 action.run.defer(100, action);
2634 beforeAction : function(action){
2635 var o = action.options;
2637 // not really supported yet.. ??
2639 //if(this.waitMsgTarget === true){
2640 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2641 //}else if(this.waitMsgTarget){
2642 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2643 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2645 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2651 afterAction : function(action, success){
2652 this.activeAction = null;
2653 var o = action.options;
2655 //if(this.waitMsgTarget === true){
2657 //}else if(this.waitMsgTarget){
2658 // this.waitMsgTarget.unmask();
2660 // Roo.MessageBox.updateProgress(1);
2661 // Roo.MessageBox.hide();
2668 Roo.callback(o.success, o.scope, [this, action]);
2669 this.fireEvent('actioncomplete', this, action);
2673 // failure condition..
2674 // we have a scenario where updates need confirming.
2675 // eg. if a locking scenario exists..
2676 // we look for { errors : { needs_confirm : true }} in the response.
2678 (typeof(action.result) != 'undefined') &&
2679 (typeof(action.result.errors) != 'undefined') &&
2680 (typeof(action.result.errors.needs_confirm) != 'undefined')
2683 Roo.log("not supported yet");
2686 Roo.MessageBox.confirm(
2687 "Change requires confirmation",
2688 action.result.errorMsg,
2693 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
2703 Roo.callback(o.failure, o.scope, [this, action]);
2704 // show an error message if no failed handler is set..
2705 if (!this.hasListener('actionfailed')) {
2706 Roo.log("need to add dialog support");
2708 Roo.MessageBox.alert("Error",
2709 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2710 action.result.errorMsg :
2711 "Saving Failed, please check your entries or try again"
2716 this.fireEvent('actionfailed', this, action);
2721 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2722 * @param {String} id The value to search for
2725 findField : function(id){
2726 var items = this.getItems();
2727 var field = items.get(id);
2729 items.each(function(f){
2730 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2737 return field || null;
2740 * Mark fields in this form invalid in bulk.
2741 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2742 * @return {BasicForm} this
2744 markInvalid : function(errors){
2745 if(errors instanceof Array){
2746 for(var i = 0, len = errors.length; i < len; i++){
2747 var fieldError = errors[i];
2748 var f = this.findField(fieldError.id);
2750 f.markInvalid(fieldError.msg);
2756 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2757 field.markInvalid(errors[id]);
2761 //Roo.each(this.childForms || [], function (f) {
2762 // f.markInvalid(errors);
2769 * Set values for fields in this form in bulk.
2770 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2771 * @return {BasicForm} this
2773 setValues : function(values){
2774 if(values instanceof Array){ // array of objects
2775 for(var i = 0, len = values.length; i < len; i++){
2777 var f = this.findField(v.id);
2779 f.setValue(v.value);
2780 if(this.trackResetOnLoad){
2781 f.originalValue = f.getValue();
2785 }else{ // object hash
2788 if(typeof values[id] != 'function' && (field = this.findField(id))){
2790 if (field.setFromData &&
2792 field.displayField &&
2793 // combos' with local stores can
2794 // be queried via setValue()
2795 // to set their value..
2796 (field.store && !field.store.isLocal)
2800 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2801 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2802 field.setFromData(sd);
2805 field.setValue(values[id]);
2809 if(this.trackResetOnLoad){
2810 field.originalValue = field.getValue();
2816 //Roo.each(this.childForms || [], function (f) {
2817 // f.setValues(values);
2824 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2825 * they are returned as an array.
2826 * @param {Boolean} asString
2829 getValues : function(asString){
2830 //if (this.childForms) {
2831 // copy values from the child forms
2832 // Roo.each(this.childForms, function (f) {
2833 // this.setValues(f.getValues());
2839 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2840 if(asString === true){
2843 return Roo.urlDecode(fs);
2847 * Returns the fields in this form as an object with key/value pairs.
2848 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2851 getFieldValues : function(with_hidden)
2853 var items = this.getItems();
2855 items.each(function(f){
2859 var v = f.getValue();
2860 if (f.inputType =='radio') {
2861 if (typeof(ret[f.getName()]) == 'undefined') {
2862 ret[f.getName()] = ''; // empty..
2865 if (!f.el.dom.checked) {
2873 // not sure if this supported any more..
2874 if ((typeof(v) == 'object') && f.getRawValue) {
2875 v = f.getRawValue() ; // dates..
2877 // combo boxes where name != hiddenName...
2878 if (f.name != f.getName()) {
2879 ret[f.name] = f.getRawValue();
2881 ret[f.getName()] = v;
2888 * Clears all invalid messages in this form.
2889 * @return {BasicForm} this
2891 clearInvalid : function(){
2892 var items = this.getItems();
2894 items.each(function(f){
2905 * @return {BasicForm} this
2908 var items = this.getItems();
2909 items.each(function(f){
2913 Roo.each(this.childForms || [], function (f) {
2920 getItems : function()
2922 var r=new Roo.util.MixedCollection(false, function(o){
2923 return o.id || (o.id = Roo.id());
2925 var iter = function(el) {
2932 Roo.each(el.items,function(e) {
2951 * Ext JS Library 1.1.1
2952 * Copyright(c) 2006-2007, Ext JS, LLC.
2954 * Originally Released Under LGPL - original licence link has changed is not relivant.
2957 * <script type="text/javascript">
2960 * @class Roo.form.VTypes
2961 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2964 Roo.form.VTypes = function(){
2965 // closure these in so they are only created once.
2966 var alpha = /^[a-zA-Z_]+$/;
2967 var alphanum = /^[a-zA-Z0-9_]+$/;
2968 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2969 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2971 // All these messages and functions are configurable
2974 * The function used to validate email addresses
2975 * @param {String} value The email address
2977 'email' : function(v){
2978 return email.test(v);
2981 * The error text to display when the email validation function returns false
2984 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2986 * The keystroke filter mask to be applied on email input
2989 'emailMask' : /[a-z0-9_\.\-@]/i,
2992 * The function used to validate URLs
2993 * @param {String} value The URL
2995 'url' : function(v){
2999 * The error text to display when the url validation function returns false
3002 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3005 * The function used to validate alpha values
3006 * @param {String} value The value
3008 'alpha' : function(v){
3009 return alpha.test(v);
3012 * The error text to display when the alpha validation function returns false
3015 'alphaText' : 'This field should only contain letters and _',
3017 * The keystroke filter mask to be applied on alpha input
3020 'alphaMask' : /[a-z_]/i,
3023 * The function used to validate alphanumeric values
3024 * @param {String} value The value
3026 'alphanum' : function(v){
3027 return alphanum.test(v);
3030 * The error text to display when the alphanumeric validation function returns false
3033 'alphanumText' : 'This field should only contain letters, numbers and _',
3035 * The keystroke filter mask to be applied on alphanumeric input
3038 'alphanumMask' : /[a-z0-9_]/i
3048 * @class Roo.bootstrap.Input
3049 * @extends Roo.bootstrap.Component
3050 * Bootstrap Input class
3051 * @cfg {Boolean} disabled is it disabled
3052 * @cfg {String} fieldLabel - the label associated
3053 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3054 * @cfg {String} name name of the input
3055 * @cfg {string} fieldLabel - the label associated
3056 * @cfg {string} inputType - input / file submit ...
3057 * @cfg {string} placeholder - placeholder to put in text.
3058 * @cfg {string} before - input group add on before
3059 * @cfg {string} after - input group add on after
3060 * @cfg {string} size - (lg|sm) or leave empty..
3061 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3062 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3063 * @cfg {Number} md colspan out of 12 for computer-sized screens
3064 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3068 * Create a new Input
3069 * @param {Object} config The config object
3072 Roo.bootstrap.Input = function(config){
3073 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3078 * Fires when this field receives input focus.
3079 * @param {Roo.form.Field} this
3084 * Fires when this field loses input focus.
3085 * @param {Roo.form.Field} this
3090 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3091 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3092 * @param {Roo.form.Field} this
3093 * @param {Roo.EventObject} e The event object
3098 * Fires just before the field blurs if the field value has changed.
3099 * @param {Roo.form.Field} this
3100 * @param {Mixed} newValue The new value
3101 * @param {Mixed} oldValue The original value
3106 * Fires after the field has been marked as invalid.
3107 * @param {Roo.form.Field} this
3108 * @param {String} msg The validation message
3113 * Fires after the field has been validated with no errors.
3114 * @param {Roo.form.Field} this
3119 * Fires after the key up
3120 * @param {Roo.form.Field} this
3121 * @param {Roo.EventObject} e The event Object
3127 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3129 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3130 automatic validation (defaults to "keyup").
3132 validationEvent : "keyup",
3134 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3136 validateOnBlur : true,
3138 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3140 validationDelay : 250,
3142 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3144 focusClass : "x-form-focus", // not needed???
3148 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3150 invalidClass : "has-error",
3153 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3155 selectOnFocus : false,
3158 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3162 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3167 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3169 disableKeyFilter : false,
3172 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3176 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3180 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3182 blankText : "This field is required",
3185 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3189 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3191 maxLength : Number.MAX_VALUE,
3193 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3195 minLengthText : "The minimum length for this field is {0}",
3197 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3199 maxLengthText : "The maximum length for this field is {0}",
3203 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3204 * If available, this function will be called only after the basic validators all return true, and will be passed the
3205 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3209 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3210 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3211 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
3215 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3234 getAutoCreate : function(){
3236 var parent = this.parent();
3238 var align = parent.labelAlign;
3243 cls: 'form-group' //input-group
3249 type : this.inputType,
3250 cls : 'form-control',
3251 placeholder : this.placeholder || ''
3255 input.name = this.name;
3258 input.cls += ' input-' + this.size;
3261 ['xs','sm','md','lg'].map(function(size){
3262 if (settings[size]) {
3263 cfg.cls += ' col-' + size + '-' + settings[size];
3267 var inputblock = input;
3269 if (this.before || this.after) {
3272 cls : 'input-group',
3276 inputblock.cn.push({
3278 cls : 'input-group-addon',
3282 inputblock.cn.push(input);
3284 inputblock.cn.push({
3286 cls : 'input-group-addon',
3294 Roo.log(this.fieldLabel.length);
3296 if (align ==='left' && this.fieldLabel.length) {
3297 Roo.log("left and has label");
3303 cls : 'col-sm-2 control-label',
3304 html : this.fieldLabel
3315 } else if ( this.fieldLabel.length) {
3321 //cls : 'input-group-addon',
3322 html : this.fieldLabel
3332 Roo.log(" no label && no align");
3345 if (this.disabled) {
3346 input.disabled=true;
3352 * return the real input element.
3354 inputEl: function ()
3356 return this.el.select('input.form-control',true).first();
3358 setDisabled : function(v)
3360 var i = this.inputEl().dom;
3362 i.removeAttribute('disabled');
3366 i.setAttribute('disabled','true');
3368 initEvents : function()
3371 this.inputEl().on("keydown" , this.fireKey, this);
3372 this.inputEl().on("focus", this.onFocus, this);
3373 this.inputEl().on("blur", this.onBlur, this);
3374 this.inputEl().relayEvent('keyup', this);
3376 // reference to original value for reset
3377 this.originalValue = this.getValue();
3378 //Roo.form.TextField.superclass.initEvents.call(this);
3379 if(this.validationEvent == 'keyup'){
3380 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3381 this.inputEl().on('keyup', this.filterValidation, this);
3383 else if(this.validationEvent !== false){
3384 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3387 if(this.selectOnFocus){
3388 this.on("focus", this.preFocus, this);
3391 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3392 this.inputEl().on("keypress", this.filterKeys, this);
3395 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
3396 this.el.on("click", this.autoSize, this);
3399 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3400 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3404 filterValidation : function(e){
3405 if(!e.isNavKeyPress()){
3406 this.validationTask.delay(this.validationDelay);
3410 * Validates the field value
3411 * @return {Boolean} True if the value is valid, else false
3413 validate : function(){
3414 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3415 if(this.disabled || this.validateValue(this.getRawValue())){
3416 this.clearInvalid();
3424 * Validates a value according to the field's validation rules and marks the field as invalid
3425 * if the validation fails
3426 * @param {Mixed} value The value to validate
3427 * @return {Boolean} True if the value is valid, else false
3429 validateValue : function(value){
3430 if(value.length < 1) { // if it's blank
3431 if(this.allowBlank){
3432 this.clearInvalid();
3435 this.markInvalid(this.blankText);
3439 if(value.length < this.minLength){
3440 this.markInvalid(String.format(this.minLengthText, this.minLength));
3443 if(value.length > this.maxLength){
3444 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3448 var vt = Roo.form.VTypes;
3449 if(!vt[this.vtype](value, this)){
3450 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3454 if(typeof this.validator == "function"){
3455 var msg = this.validator(value);
3457 this.markInvalid(msg);
3461 if(this.regex && !this.regex.test(value)){
3462 this.markInvalid(this.regexText);
3471 fireKey : function(e){
3472 //Roo.log('field ' + e.getKey());
3473 if(e.isNavKeyPress()){
3474 this.fireEvent("specialkey", this, e);
3477 focus : function (selectText){
3479 this.inputEl().focus();
3480 if(selectText === true){
3481 this.inputEl().dom.select();
3487 onFocus : function(){
3488 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3489 // this.el.addClass(this.focusClass);
3492 this.hasFocus = true;
3493 this.startValue = this.getValue();
3494 this.fireEvent("focus", this);
3498 beforeBlur : Roo.emptyFn,
3502 onBlur : function(){
3504 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3505 //this.el.removeClass(this.focusClass);
3507 this.hasFocus = false;
3508 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3511 var v = this.getValue();
3512 if(String(v) !== String(this.startValue)){
3513 this.fireEvent('change', this, v, this.startValue);
3515 this.fireEvent("blur", this);
3519 * Resets the current field value to the originally loaded value and clears any validation messages
3522 this.setValue(this.originalValue);
3523 this.clearInvalid();
3526 * Returns the name of the field
3527 * @return {Mixed} name The name field
3529 getName: function(){
3533 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
3534 * @return {Mixed} value The field value
3536 getValue : function(){
3537 var v = this.inputEl().getValue();
3541 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
3542 * @return {Mixed} value The field value
3544 getRawValue : function(){
3545 var v = this.inputEl().getValue();
3550 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
3551 * @param {Mixed} value The value to set
3553 setValue : function(v){
3556 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3562 processValue : function(value){
3563 if(this.stripCharsRe){
3564 var newValue = value.replace(this.stripCharsRe, '');
3565 if(newValue !== value){
3566 this.setRawValue(newValue);
3573 preFocus : function(){
3575 if(this.selectOnFocus){
3576 this.inputEl().dom.select();
3579 filterKeys : function(e){
3581 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3584 var c = e.getCharCode(), cc = String.fromCharCode(c);
3585 if(Roo.isIE && (e.isSpecialKey() || !cc)){
3588 if(!this.maskRe.test(cc)){
3593 * Clear any invalid styles/messages for this field
3595 clearInvalid : function(){
3597 if(!this.el || this.preventMark){ // not rendered
3600 this.el.removeClass(this.invalidClass);
3602 switch(this.msgTarget){
3604 this.el.dom.qtip = '';
3607 this.el.dom.title = '';
3611 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3616 this.errorIcon.dom.qtip = '';
3617 this.errorIcon.hide();
3618 this.un('resize', this.alignErrorIcon, this);
3622 var t = Roo.getDom(this.msgTarget);
3624 t.style.display = 'none';
3628 this.fireEvent('valid', this);
3631 * Mark this field as invalid
3632 * @param {String} msg The validation message
3634 markInvalid : function(msg){
3635 if(!this.el || this.preventMark){ // not rendered
3638 this.el.addClass(this.invalidClass);
3640 msg = msg || this.invalidText;
3641 switch(this.msgTarget){
3643 this.el.dom.qtip = msg;
3644 this.el.dom.qclass = 'x-form-invalid-tip';
3645 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3646 Roo.QuickTips.enable();
3650 this.el.dom.title = msg;
3654 var elp = this.el.findParent('.x-form-element', 5, true);
3655 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3656 this.errorEl.setWidth(elp.getWidth(true)-20);
3658 this.errorEl.update(msg);
3659 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3662 if(!this.errorIcon){
3663 var elp = this.el.findParent('.x-form-element', 5, true);
3664 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3666 this.alignErrorIcon();
3667 this.errorIcon.dom.qtip = msg;
3668 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3669 this.errorIcon.show();
3670 this.on('resize', this.alignErrorIcon, this);
3673 var t = Roo.getDom(this.msgTarget);
3675 t.style.display = this.msgDisplay;
3679 this.fireEvent('invalid', this, msg);
3682 SafariOnKeyDown : function(event)
3684 // this is a workaround for a password hang bug on chrome/ webkit.
3686 var isSelectAll = false;
3688 if(this.inputEl().dom.selectionEnd > 0){
3689 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3691 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3692 event.preventDefault();
3697 if(isSelectAll){ // backspace and delete key
3699 event.preventDefault();
3700 // this is very hacky as keydown always get's upper case.
3702 var cc = String.fromCharCode(event.getCharCode());
3703 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
3715 * trigger field - base class for combo..
3720 * @class Roo.bootstrap.TriggerField
3721 * @extends Roo.bootstrap.Input
3722 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3723 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3724 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3725 * for which you can provide a custom implementation. For example:
3727 var trigger = new Roo.bootstrap.TriggerField();
3728 trigger.onTriggerClick = myTriggerFn;
3729 trigger.applyTo('my-field');
3732 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3733 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3734 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
3735 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3737 * Create a new TriggerField.
3738 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3739 * to the base TextField)
3741 Roo.bootstrap.TriggerField = function(config){
3742 this.mimicing = false;
3743 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3746 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
3748 * @cfg {String} triggerClass A CSS class to apply to the trigger
3751 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3755 /** @cfg {Boolean} grow @hide */
3756 /** @cfg {Number} growMin @hide */
3757 /** @cfg {Number} growMax @hide */
3763 autoSize: Roo.emptyFn,
3770 actionMode : 'wrap',
3774 getAutoCreate : function(){
3776 var parent = this.parent();
3778 var align = parent.labelAlign;
3783 cls: 'form-group' //input-group
3790 type : this.inputType,
3791 cls : 'form-control',
3792 autocomplete: 'off',
3793 placeholder : this.placeholder || ''
3797 input.name = this.name;
3800 input.cls += ' input-' + this.size;
3803 cls: 'combobox-container input-group',
3808 cls: 'form-hidden-field'
3813 cls : 'typeahead typeahead-long dropdown-menu',
3814 style : 'display:none'
3818 cls : 'input-group-addon btn dropdown-toggle',
3826 cls: 'combobox-clear',
3843 if (align ==='left' && this.fieldLabel.length) {
3847 Roo.log("left and has label");
3853 cls : 'col-sm-2 control-label',
3854 html : this.fieldLabel
3865 } else if ( this.fieldLabel.length) {
3871 //cls : 'input-group-addon',
3872 html : this.fieldLabel
3882 Roo.log(" no label && no align");
3889 ['xs','sm','md','lg'].map(function(size){
3890 if (settings[size]) {
3891 cfg.cls += ' col-' + size + '-' + settings[size];
3897 if (this.disabled) {
3898 input.disabled=true;
3907 onResize : function(w, h){
3908 Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3909 if(typeof w == 'number'){
3910 var x = w - this.trigger.getWidth();
3911 this.inputEl().setWidth(this.adjustWidth('input', x));
3912 this.trigger.setStyle('left', x+'px');
3917 adjustSize : Roo.BoxComponent.prototype.adjustSize,
3920 getResizeEl : function(){
3921 return this.inputEl();
3925 getPositionEl : function(){
3926 return this.inputEl();
3930 alignErrorIcon : function(){
3931 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3935 initEvents : function(){
3937 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3939 this.trigger = this.el.select('span.dropdown-toggle',true).first();
3940 if(this.hideTrigger){
3941 this.trigger.setDisplayed(false);
3943 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3944 //this.trigger.addClassOnOver('x-form-trigger-over');
3945 //this.trigger.addClassOnClick('x-form-trigger-click');
3948 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3953 initTrigger : function(){
3958 onDestroy : function(){
3960 this.trigger.removeAllListeners();
3961 // this.trigger.remove();
3964 // this.wrap.remove();
3966 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
3970 onFocus : function(){
3971 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
3974 this.wrap.addClass('x-trigger-wrap-focus');
3975 this.mimicing = true;
3976 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
3977 if(this.monitorTab){
3978 this.el.on("keydown", this.checkTab, this);
3985 checkTab : function(e){
3986 if(e.getKey() == e.TAB){
3992 onBlur : function(){
3997 mimicBlur : function(e, t){
3999 if(!this.wrap.contains(t) && this.validateBlur()){
4006 triggerBlur : function(){
4007 this.mimicing = false;
4008 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
4009 if(this.monitorTab){
4010 this.el.un("keydown", this.checkTab, this);
4012 //this.wrap.removeClass('x-trigger-wrap-focus');
4013 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4017 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4018 validateBlur : function(e, t){
4023 onDisable : function(){
4024 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4026 // this.wrap.addClass('x-item-disabled');
4031 onEnable : function(){
4032 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4034 // this.el.removeClass('x-item-disabled');
4039 onShow : function(){
4040 var ae = this.getActionEl();
4043 ae.dom.style.display = '';
4044 ae.dom.style.visibility = 'visible';
4050 onHide : function(){
4051 var ae = this.getActionEl();
4052 ae.dom.style.display = 'none';
4056 * The function that should handle the trigger's click event. This method does nothing by default until overridden
4057 * by an implementing function.
4059 * @param {EventObject} e
4061 onTriggerClick : Roo.emptyFn
4065 * Ext JS Library 1.1.1
4066 * Copyright(c) 2006-2007, Ext JS, LLC.
4068 * Originally Released Under LGPL - original licence link has changed is not relivant.
4071 * <script type="text/javascript">
4076 * @class Roo.data.SortTypes
4078 * Defines the default sorting (casting?) comparison functions used when sorting data.
4080 Roo.data.SortTypes = {
4082 * Default sort that does nothing
4083 * @param {Mixed} s The value being converted
4084 * @return {Mixed} The comparison value
4091 * The regular expression used to strip tags
4095 stripTagsRE : /<\/?[^>]+>/gi,
4098 * Strips all HTML tags to sort on text only
4099 * @param {Mixed} s The value being converted
4100 * @return {String} The comparison value
4102 asText : function(s){
4103 return String(s).replace(this.stripTagsRE, "");
4107 * Strips all HTML tags to sort on text only - Case insensitive
4108 * @param {Mixed} s The value being converted
4109 * @return {String} The comparison value
4111 asUCText : function(s){
4112 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4116 * Case insensitive string
4117 * @param {Mixed} s The value being converted
4118 * @return {String} The comparison value
4120 asUCString : function(s) {
4121 return String(s).toUpperCase();
4126 * @param {Mixed} s The value being converted
4127 * @return {Number} The comparison value
4129 asDate : function(s) {
4133 if(s instanceof Date){
4136 return Date.parse(String(s));
4141 * @param {Mixed} s The value being converted
4142 * @return {Float} The comparison value
4144 asFloat : function(s) {
4145 var val = parseFloat(String(s).replace(/,/g, ""));
4146 if(isNaN(val)) val = 0;
4152 * @param {Mixed} s The value being converted
4153 * @return {Number} The comparison value
4155 asInt : function(s) {
4156 var val = parseInt(String(s).replace(/,/g, ""));
4157 if(isNaN(val)) val = 0;
4162 * Ext JS Library 1.1.1
4163 * Copyright(c) 2006-2007, Ext JS, LLC.
4165 * Originally Released Under LGPL - original licence link has changed is not relivant.
4168 * <script type="text/javascript">
4172 * @class Roo.data.Record
4173 * Instances of this class encapsulate both record <em>definition</em> information, and record
4174 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4175 * to access Records cached in an {@link Roo.data.Store} object.<br>
4177 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4178 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4181 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4183 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4184 * {@link #create}. The parameters are the same.
4185 * @param {Array} data An associative Array of data values keyed by the field name.
4186 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4187 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4188 * not specified an integer id is generated.
4190 Roo.data.Record = function(data, id){
4191 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4196 * Generate a constructor for a specific record layout.
4197 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4198 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4199 * Each field definition object may contain the following properties: <ul>
4200 * <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,
4201 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4202 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4203 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4204 * is being used, then this is a string containing the javascript expression to reference the data relative to
4205 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4206 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4207 * this may be omitted.</p></li>
4208 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4209 * <ul><li>auto (Default, implies no conversion)</li>
4214 * <li>date</li></ul></p></li>
4215 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4216 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4217 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4218 * by the Reader into an object that will be stored in the Record. It is passed the
4219 * following parameters:<ul>
4220 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4222 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4224 * <br>usage:<br><pre><code>
4225 var TopicRecord = Roo.data.Record.create(
4226 {name: 'title', mapping: 'topic_title'},
4227 {name: 'author', mapping: 'username'},
4228 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4229 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4230 {name: 'lastPoster', mapping: 'user2'},
4231 {name: 'excerpt', mapping: 'post_text'}
4234 var myNewRecord = new TopicRecord({
4235 title: 'Do my job please',
4238 lastPost: new Date(),
4239 lastPoster: 'Animal',
4240 excerpt: 'No way dude!'
4242 myStore.add(myNewRecord);
4247 Roo.data.Record.create = function(o){
4249 f.superclass.constructor.apply(this, arguments);
4251 Roo.extend(f, Roo.data.Record);
4252 var p = f.prototype;
4253 p.fields = new Roo.util.MixedCollection(false, function(field){
4256 for(var i = 0, len = o.length; i < len; i++){
4257 p.fields.add(new Roo.data.Field(o[i]));
4259 f.getField = function(name){
4260 return p.fields.get(name);
4265 Roo.data.Record.AUTO_ID = 1000;
4266 Roo.data.Record.EDIT = 'edit';
4267 Roo.data.Record.REJECT = 'reject';
4268 Roo.data.Record.COMMIT = 'commit';
4270 Roo.data.Record.prototype = {
4272 * Readonly flag - true if this record has been modified.
4281 join : function(store){
4286 * Set the named field to the specified value.
4287 * @param {String} name The name of the field to set.
4288 * @param {Object} value The value to set the field to.
4290 set : function(name, value){
4291 if(this.data[name] == value){
4298 if(typeof this.modified[name] == 'undefined'){
4299 this.modified[name] = this.data[name];
4301 this.data[name] = value;
4302 if(!this.editing && this.store){
4303 this.store.afterEdit(this);
4308 * Get the value of the named field.
4309 * @param {String} name The name of the field to get the value of.
4310 * @return {Object} The value of the field.
4312 get : function(name){
4313 return this.data[name];
4317 beginEdit : function(){
4318 this.editing = true;
4323 cancelEdit : function(){
4324 this.editing = false;
4325 delete this.modified;
4329 endEdit : function(){
4330 this.editing = false;
4331 if(this.dirty && this.store){
4332 this.store.afterEdit(this);
4337 * Usually called by the {@link Roo.data.Store} which owns the Record.
4338 * Rejects all changes made to the Record since either creation, or the last commit operation.
4339 * Modified fields are reverted to their original values.
4341 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4342 * of reject operations.
4344 reject : function(){
4345 var m = this.modified;
4347 if(typeof m[n] != "function"){
4348 this.data[n] = m[n];
4352 delete this.modified;
4353 this.editing = false;
4355 this.store.afterReject(this);
4360 * Usually called by the {@link Roo.data.Store} which owns the Record.
4361 * Commits all changes made to the Record since either creation, or the last commit operation.
4363 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4364 * of commit operations.
4366 commit : function(){
4368 delete this.modified;
4369 this.editing = false;
4371 this.store.afterCommit(this);
4376 hasError : function(){
4377 return this.error != null;
4381 clearError : function(){
4386 * Creates a copy of this record.
4387 * @param {String} id (optional) A new record id if you don't want to use this record's id
4390 copy : function(newId) {
4391 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4395 * Ext JS Library 1.1.1
4396 * Copyright(c) 2006-2007, Ext JS, LLC.
4398 * Originally Released Under LGPL - original licence link has changed is not relivant.
4401 * <script type="text/javascript">
4407 * @class Roo.data.Store
4408 * @extends Roo.util.Observable
4409 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4410 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4412 * 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
4413 * has no knowledge of the format of the data returned by the Proxy.<br>
4415 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4416 * instances from the data object. These records are cached and made available through accessor functions.
4418 * Creates a new Store.
4419 * @param {Object} config A config object containing the objects needed for the Store to access data,
4420 * and read the data into Records.
4422 Roo.data.Store = function(config){
4423 this.data = new Roo.util.MixedCollection(false);
4424 this.data.getKey = function(o){
4427 this.baseParams = {};
4434 "multisort" : "_multisort"
4437 if(config && config.data){
4438 this.inlineData = config.data;
4442 Roo.apply(this, config);
4444 if(this.reader){ // reader passed
4445 this.reader = Roo.factory(this.reader, Roo.data);
4446 this.reader.xmodule = this.xmodule || false;
4447 if(!this.recordType){
4448 this.recordType = this.reader.recordType;
4450 if(this.reader.onMetaChange){
4451 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4455 if(this.recordType){
4456 this.fields = this.recordType.prototype.fields;
4462 * @event datachanged
4463 * Fires when the data cache has changed, and a widget which is using this Store
4464 * as a Record cache should refresh its view.
4465 * @param {Store} this
4470 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4471 * @param {Store} this
4472 * @param {Object} meta The JSON metadata
4477 * Fires when Records have been added to the Store
4478 * @param {Store} this
4479 * @param {Roo.data.Record[]} records The array of Records added
4480 * @param {Number} index The index at which the record(s) were added
4485 * Fires when a Record has been removed from the Store
4486 * @param {Store} this
4487 * @param {Roo.data.Record} record The Record that was removed
4488 * @param {Number} index The index at which the record was removed
4493 * Fires when a Record has been updated
4494 * @param {Store} this
4495 * @param {Roo.data.Record} record The Record that was updated
4496 * @param {String} operation The update operation being performed. Value may be one of:
4498 Roo.data.Record.EDIT
4499 Roo.data.Record.REJECT
4500 Roo.data.Record.COMMIT
4506 * Fires when the data cache has been cleared.
4507 * @param {Store} this
4512 * Fires before a request is made for a new data object. If the beforeload handler returns false
4513 * the load action will be canceled.
4514 * @param {Store} this
4515 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4519 * @event beforeloadadd
4520 * Fires after a new set of Records has been loaded.
4521 * @param {Store} this
4522 * @param {Roo.data.Record[]} records The Records that were loaded
4523 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4525 beforeloadadd : true,
4528 * Fires after a new set of Records has been loaded, before they are added to the store.
4529 * @param {Store} this
4530 * @param {Roo.data.Record[]} records The Records that were loaded
4531 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4532 * @params {Object} return from reader
4536 * @event loadexception
4537 * Fires if an exception occurs in the Proxy during loading.
4538 * Called with the signature of the Proxy's "loadexception" event.
4539 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4542 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4543 * @param {Object} load options
4544 * @param {Object} jsonData from your request (normally this contains the Exception)
4546 loadexception : true
4550 this.proxy = Roo.factory(this.proxy, Roo.data);
4551 this.proxy.xmodule = this.xmodule || false;
4552 this.relayEvents(this.proxy, ["loadexception"]);
4554 this.sortToggle = {};
4555 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4557 Roo.data.Store.superclass.constructor.call(this);
4559 if(this.inlineData){
4560 this.loadData(this.inlineData);
4561 delete this.inlineData;
4565 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4567 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4568 * without a remote query - used by combo/forms at present.
4572 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4575 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4578 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4579 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4582 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4583 * on any HTTP request
4586 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4589 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4593 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4594 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4599 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4600 * loaded or when a record is removed. (defaults to false).
4602 pruneModifiedRecords : false,
4608 * Add Records to the Store and fires the add event.
4609 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4611 add : function(records){
4612 records = [].concat(records);
4613 for(var i = 0, len = records.length; i < len; i++){
4614 records[i].join(this);
4616 var index = this.data.length;
4617 this.data.addAll(records);
4618 this.fireEvent("add", this, records, index);
4622 * Remove a Record from the Store and fires the remove event.
4623 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4625 remove : function(record){
4626 var index = this.data.indexOf(record);
4627 this.data.removeAt(index);
4628 if(this.pruneModifiedRecords){
4629 this.modified.remove(record);
4631 this.fireEvent("remove", this, record, index);
4635 * Remove all Records from the Store and fires the clear event.
4637 removeAll : function(){
4639 if(this.pruneModifiedRecords){
4642 this.fireEvent("clear", this);
4646 * Inserts Records to the Store at the given index and fires the add event.
4647 * @param {Number} index The start index at which to insert the passed Records.
4648 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4650 insert : function(index, records){
4651 records = [].concat(records);
4652 for(var i = 0, len = records.length; i < len; i++){
4653 this.data.insert(index, records[i]);
4654 records[i].join(this);
4656 this.fireEvent("add", this, records, index);
4660 * Get the index within the cache of the passed Record.
4661 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4662 * @return {Number} The index of the passed Record. Returns -1 if not found.
4664 indexOf : function(record){
4665 return this.data.indexOf(record);
4669 * Get the index within the cache of the Record with the passed id.
4670 * @param {String} id The id of the Record to find.
4671 * @return {Number} The index of the Record. Returns -1 if not found.
4673 indexOfId : function(id){
4674 return this.data.indexOfKey(id);
4678 * Get the Record with the specified id.
4679 * @param {String} id The id of the Record to find.
4680 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4682 getById : function(id){
4683 return this.data.key(id);
4687 * Get the Record at the specified index.
4688 * @param {Number} index The index of the Record to find.
4689 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4691 getAt : function(index){
4692 return this.data.itemAt(index);
4696 * Returns a range of Records between specified indices.
4697 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4698 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4699 * @return {Roo.data.Record[]} An array of Records
4701 getRange : function(start, end){
4702 return this.data.getRange(start, end);
4706 storeOptions : function(o){
4707 o = Roo.apply({}, o);
4710 this.lastOptions = o;
4714 * Loads the Record cache from the configured Proxy using the configured Reader.
4716 * If using remote paging, then the first load call must specify the <em>start</em>
4717 * and <em>limit</em> properties in the options.params property to establish the initial
4718 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4720 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4721 * and this call will return before the new data has been loaded. Perform any post-processing
4722 * in a callback function, or in a "load" event handler.</strong>
4724 * @param {Object} options An object containing properties which control loading options:<ul>
4725 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4726 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4727 * passed the following arguments:<ul>
4728 * <li>r : Roo.data.Record[]</li>
4729 * <li>options: Options object from the load call</li>
4730 * <li>success: Boolean success indicator</li></ul></li>
4731 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4732 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4735 load : function(options){
4736 options = options || {};
4737 if(this.fireEvent("beforeload", this, options) !== false){
4738 this.storeOptions(options);
4739 var p = Roo.apply(options.params || {}, this.baseParams);
4740 // if meta was not loaded from remote source.. try requesting it.
4741 if (!this.reader.metaFromRemote) {
4744 if(this.sortInfo && this.remoteSort){
4745 var pn = this.paramNames;
4746 p[pn["sort"]] = this.sortInfo.field;
4747 p[pn["dir"]] = this.sortInfo.direction;
4749 if (this.multiSort) {
4750 var pn = this.paramNames;
4751 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4754 this.proxy.load(p, this.reader, this.loadRecords, this, options);
4759 * Reloads the Record cache from the configured Proxy using the configured Reader and
4760 * the options from the last load operation performed.
4761 * @param {Object} options (optional) An object containing properties which may override the options
4762 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4763 * the most recently used options are reused).
4765 reload : function(options){
4766 this.load(Roo.applyIf(options||{}, this.lastOptions));
4770 // Called as a callback by the Reader during a load operation.
4771 loadRecords : function(o, options, success){
4772 if(!o || success === false){
4773 if(success !== false){
4774 this.fireEvent("load", this, [], options, o);
4776 if(options.callback){
4777 options.callback.call(options.scope || this, [], options, false);
4781 // if data returned failure - throw an exception.
4782 if (o.success === false) {
4783 // show a message if no listener is registered.
4784 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4785 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4787 // loadmask wil be hooked into this..
4788 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4791 var r = o.records, t = o.totalRecords || r.length;
4793 this.fireEvent("beforeloadadd", this, r, options, o);
4795 if(!options || options.add !== true){
4796 if(this.pruneModifiedRecords){
4799 for(var i = 0, len = r.length; i < len; i++){
4803 this.data = this.snapshot;
4804 delete this.snapshot;
4807 this.data.addAll(r);
4808 this.totalLength = t;
4810 this.fireEvent("datachanged", this);
4812 this.totalLength = Math.max(t, this.data.length+r.length);
4815 this.fireEvent("load", this, r, options, o);
4816 if(options.callback){
4817 options.callback.call(options.scope || this, r, options, true);
4823 * Loads data from a passed data block. A Reader which understands the format of the data
4824 * must have been configured in the constructor.
4825 * @param {Object} data The data block from which to read the Records. The format of the data expected
4826 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4827 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4829 loadData : function(o, append){
4830 var r = this.reader.readRecords(o);
4831 this.loadRecords(r, {add: append}, true);
4835 * Gets the number of cached records.
4837 * <em>If using paging, this may not be the total size of the dataset. If the data object
4838 * used by the Reader contains the dataset size, then the getTotalCount() function returns
4839 * the data set size</em>
4841 getCount : function(){
4842 return this.data.length || 0;
4846 * Gets the total number of records in the dataset as returned by the server.
4848 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4849 * the dataset size</em>
4851 getTotalCount : function(){
4852 return this.totalLength || 0;
4856 * Returns the sort state of the Store as an object with two properties:
4858 field {String} The name of the field by which the Records are sorted
4859 direction {String} The sort order, "ASC" or "DESC"
4862 getSortState : function(){
4863 return this.sortInfo;
4867 applySort : function(){
4868 if(this.sortInfo && !this.remoteSort){
4869 var s = this.sortInfo, f = s.field;
4870 var st = this.fields.get(f).sortType;
4871 var fn = function(r1, r2){
4872 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4873 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
4875 this.data.sort(s.direction, fn);
4876 if(this.snapshot && this.snapshot != this.data){
4877 this.snapshot.sort(s.direction, fn);
4883 * Sets the default sort column and order to be used by the next load operation.
4884 * @param {String} fieldName The name of the field to sort by.
4885 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4887 setDefaultSort : function(field, dir){
4888 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
4893 * If remote sorting is used, the sort is performed on the server, and the cache is
4894 * reloaded. If local sorting is used, the cache is sorted internally.
4895 * @param {String} fieldName The name of the field to sort by.
4896 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4898 sort : function(fieldName, dir){
4899 var f = this.fields.get(fieldName);
4901 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
4903 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
4904 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
4909 this.sortToggle[f.name] = dir;
4910 this.sortInfo = {field: f.name, direction: dir};
4911 if(!this.remoteSort){
4913 this.fireEvent("datachanged", this);
4915 this.load(this.lastOptions);
4920 * Calls the specified function for each of the Records in the cache.
4921 * @param {Function} fn The function to call. The Record is passed as the first parameter.
4922 * Returning <em>false</em> aborts and exits the iteration.
4923 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
4925 each : function(fn, scope){
4926 this.data.each(fn, scope);
4930 * Gets all records modified since the last commit. Modified records are persisted across load operations
4931 * (e.g., during paging).
4932 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
4934 getModifiedRecords : function(){
4935 return this.modified;
4939 createFilterFn : function(property, value, anyMatch){
4940 if(!value.exec){ // not a regex
4941 value = String(value);
4942 if(value.length == 0){
4945 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
4948 return value.test(r.data[property]);
4953 * Sums the value of <i>property</i> for each record between start and end and returns the result.
4954 * @param {String} property A field on your records
4955 * @param {Number} start The record index to start at (defaults to 0)
4956 * @param {Number} end The last record index to include (defaults to length - 1)
4957 * @return {Number} The sum
4959 sum : function(property, start, end){
4960 var rs = this.data.items, v = 0;
4962 end = (end || end === 0) ? end : rs.length-1;
4964 for(var i = start; i <= end; i++){
4965 v += (rs[i].data[property] || 0);
4971 * Filter the records by a specified property.
4972 * @param {String} field A field on your records
4973 * @param {String/RegExp} value Either a string that the field
4974 * should start with or a RegExp to test against the field
4975 * @param {Boolean} anyMatch True to match any part not just the beginning
4977 filter : function(property, value, anyMatch){
4978 var fn = this.createFilterFn(property, value, anyMatch);
4979 return fn ? this.filterBy(fn) : this.clearFilter();
4983 * Filter by a function. The specified function will be called with each
4984 * record in this data source. If the function returns true the record is included,
4985 * otherwise it is filtered.
4986 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4987 * @param {Object} scope (optional) The scope of the function (defaults to this)
4989 filterBy : function(fn, scope){
4990 this.snapshot = this.snapshot || this.data;
4991 this.data = this.queryBy(fn, scope||this);
4992 this.fireEvent("datachanged", this);
4996 * Query the records by a specified property.
4997 * @param {String} field A field on your records
4998 * @param {String/RegExp} value Either a string that the field
4999 * should start with or a RegExp to test against the field
5000 * @param {Boolean} anyMatch True to match any part not just the beginning
5001 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5003 query : function(property, value, anyMatch){
5004 var fn = this.createFilterFn(property, value, anyMatch);
5005 return fn ? this.queryBy(fn) : this.data.clone();
5009 * Query by a function. The specified function will be called with each
5010 * record in this data source. If the function returns true the record is included
5012 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5013 * @param {Object} scope (optional) The scope of the function (defaults to this)
5014 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5016 queryBy : function(fn, scope){
5017 var data = this.snapshot || this.data;
5018 return data.filterBy(fn, scope||this);
5022 * Collects unique values for a particular dataIndex from this store.
5023 * @param {String} dataIndex The property to collect
5024 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5025 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5026 * @return {Array} An array of the unique values
5028 collect : function(dataIndex, allowNull, bypassFilter){
5029 var d = (bypassFilter === true && this.snapshot) ?
5030 this.snapshot.items : this.data.items;
5031 var v, sv, r = [], l = {};
5032 for(var i = 0, len = d.length; i < len; i++){
5033 v = d[i].data[dataIndex];
5035 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5044 * Revert to a view of the Record cache with no filtering applied.
5045 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5047 clearFilter : function(suppressEvent){
5048 if(this.snapshot && this.snapshot != this.data){
5049 this.data = this.snapshot;
5050 delete this.snapshot;
5051 if(suppressEvent !== true){
5052 this.fireEvent("datachanged", this);
5058 afterEdit : function(record){
5059 if(this.modified.indexOf(record) == -1){
5060 this.modified.push(record);
5062 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5066 afterReject : function(record){
5067 this.modified.remove(record);
5068 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5072 afterCommit : function(record){
5073 this.modified.remove(record);
5074 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5078 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5079 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5081 commitChanges : function(){
5082 var m = this.modified.slice(0);
5084 for(var i = 0, len = m.length; i < len; i++){
5090 * Cancel outstanding changes on all changed records.
5092 rejectChanges : function(){
5093 var m = this.modified.slice(0);
5095 for(var i = 0, len = m.length; i < len; i++){
5100 onMetaChange : function(meta, rtype, o){
5101 this.recordType = rtype;
5102 this.fields = rtype.prototype.fields;
5103 delete this.snapshot;
5104 this.sortInfo = meta.sortInfo || this.sortInfo;
5106 this.fireEvent('metachange', this, this.reader.meta);
5110 * Ext JS Library 1.1.1
5111 * Copyright(c) 2006-2007, Ext JS, LLC.
5113 * Originally Released Under LGPL - original licence link has changed is not relivant.
5116 * <script type="text/javascript">
5120 * @class Roo.data.SimpleStore
5121 * @extends Roo.data.Store
5122 * Small helper class to make creating Stores from Array data easier.
5123 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5124 * @cfg {Array} fields An array of field definition objects, or field name strings.
5125 * @cfg {Array} data The multi-dimensional array of data
5127 * @param {Object} config
5129 Roo.data.SimpleStore = function(config){
5130 Roo.data.SimpleStore.superclass.constructor.call(this, {
5132 reader: new Roo.data.ArrayReader({
5135 Roo.data.Record.create(config.fields)
5137 proxy : new Roo.data.MemoryProxy(config.data)
5141 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5143 * Ext JS Library 1.1.1
5144 * Copyright(c) 2006-2007, Ext JS, LLC.
5146 * Originally Released Under LGPL - original licence link has changed is not relivant.
5149 * <script type="text/javascript">
5154 * @extends Roo.data.Store
5155 * @class Roo.data.JsonStore
5156 * Small helper class to make creating Stores for JSON data easier. <br/>
5158 var store = new Roo.data.JsonStore({
5159 url: 'get-images.php',
5161 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5164 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5165 * JsonReader and HttpProxy (unless inline data is provided).</b>
5166 * @cfg {Array} fields An array of field definition objects, or field name strings.
5168 * @param {Object} config
5170 Roo.data.JsonStore = function(c){
5171 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5172 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5173 reader: new Roo.data.JsonReader(c, c.fields)
5176 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5178 * Ext JS Library 1.1.1
5179 * Copyright(c) 2006-2007, Ext JS, LLC.
5181 * Originally Released Under LGPL - original licence link has changed is not relivant.
5184 * <script type="text/javascript">
5188 Roo.data.Field = function(config){
5189 if(typeof config == "string"){
5190 config = {name: config};
5192 Roo.apply(this, config);
5198 var st = Roo.data.SortTypes;
5199 // named sortTypes are supported, here we look them up
5200 if(typeof this.sortType == "string"){
5201 this.sortType = st[this.sortType];
5204 // set default sortType for strings and dates
5208 this.sortType = st.asUCString;
5211 this.sortType = st.asDate;
5214 this.sortType = st.none;
5219 var stripRe = /[\$,%]/g;
5221 // prebuilt conversion function for this field, instead of
5222 // switching every time we're reading a value
5224 var cv, dateFormat = this.dateFormat;
5229 cv = function(v){ return v; };
5232 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5236 return v !== undefined && v !== null && v !== '' ?
5237 parseInt(String(v).replace(stripRe, ""), 10) : '';
5242 return v !== undefined && v !== null && v !== '' ?
5243 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5248 cv = function(v){ return v === true || v === "true" || v == 1; };
5255 if(v instanceof Date){
5259 if(dateFormat == "timestamp"){
5260 return new Date(v*1000);
5262 return Date.parseDate(v, dateFormat);
5264 var parsed = Date.parse(v);
5265 return parsed ? new Date(parsed) : null;
5274 Roo.data.Field.prototype = {
5282 * Ext JS Library 1.1.1
5283 * Copyright(c) 2006-2007, Ext JS, LLC.
5285 * Originally Released Under LGPL - original licence link has changed is not relivant.
5288 * <script type="text/javascript">
5291 // Base class for reading structured data from a data source. This class is intended to be
5292 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5295 * @class Roo.data.DataReader
5296 * Base class for reading structured data from a data source. This class is intended to be
5297 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5300 Roo.data.DataReader = function(meta, recordType){
5304 this.recordType = recordType instanceof Array ?
5305 Roo.data.Record.create(recordType) : recordType;
5308 Roo.data.DataReader.prototype = {
5310 * Create an empty record
5311 * @param {Object} data (optional) - overlay some values
5312 * @return {Roo.data.Record} record created.
5314 newRow : function(d) {
5316 this.recordType.prototype.fields.each(function(c) {
5318 case 'int' : da[c.name] = 0; break;
5319 case 'date' : da[c.name] = new Date(); break;
5320 case 'float' : da[c.name] = 0.0; break;
5321 case 'boolean' : da[c.name] = false; break;
5322 default : da[c.name] = ""; break;
5326 return new this.recordType(Roo.apply(da, d));
5331 * Ext JS Library 1.1.1
5332 * Copyright(c) 2006-2007, Ext JS, LLC.
5334 * Originally Released Under LGPL - original licence link has changed is not relivant.
5337 * <script type="text/javascript">
5341 * @class Roo.data.DataProxy
5342 * @extends Roo.data.Observable
5343 * This class is an abstract base class for implementations which provide retrieval of
5344 * unformatted data objects.<br>
5346 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5347 * (of the appropriate type which knows how to parse the data object) to provide a block of
5348 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5350 * Custom implementations must implement the load method as described in
5351 * {@link Roo.data.HttpProxy#load}.
5353 Roo.data.DataProxy = function(){
5357 * Fires before a network request is made to retrieve a data object.
5358 * @param {Object} This DataProxy object.
5359 * @param {Object} params The params parameter to the load function.
5364 * Fires before the load method's callback is called.
5365 * @param {Object} This DataProxy object.
5366 * @param {Object} o The data object.
5367 * @param {Object} arg The callback argument object passed to the load function.
5371 * @event loadexception
5372 * Fires if an Exception occurs during data retrieval.
5373 * @param {Object} This DataProxy object.
5374 * @param {Object} o The data object.
5375 * @param {Object} arg The callback argument object passed to the load function.
5376 * @param {Object} e The Exception.
5378 loadexception : true
5380 Roo.data.DataProxy.superclass.constructor.call(this);
5383 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5386 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
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.MemoryProxy
5400 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5401 * to the Reader when its load method is called.
5403 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5405 Roo.data.MemoryProxy = function(data){
5409 Roo.data.MemoryProxy.superclass.constructor.call(this);
5413 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5415 * Load data from the requested source (in this case an in-memory
5416 * data object passed to the constructor), read the data object into
5417 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5418 * process that block using the passed callback.
5419 * @param {Object} params This parameter is not used by the MemoryProxy class.
5420 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5421 * object into a block of Roo.data.Records.
5422 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5423 * The function must be passed <ul>
5424 * <li>The Record block object</li>
5425 * <li>The "arg" argument from the load function</li>
5426 * <li>A boolean success indicator</li>
5428 * @param {Object} scope The scope in which to call the callback
5429 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5431 load : function(params, reader, callback, scope, arg){
5432 params = params || {};
5435 result = reader.readRecords(this.data);
5437 this.fireEvent("loadexception", this, arg, null, e);
5438 callback.call(scope, null, arg, false);
5441 callback.call(scope, result, arg, true);
5445 update : function(params, records){
5450 * Ext JS Library 1.1.1
5451 * Copyright(c) 2006-2007, Ext JS, LLC.
5453 * Originally Released Under LGPL - original licence link has changed is not relivant.
5456 * <script type="text/javascript">
5459 * @class Roo.data.HttpProxy
5460 * @extends Roo.data.DataProxy
5461 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5462 * configured to reference a certain URL.<br><br>
5464 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5465 * from which the running page was served.<br><br>
5467 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5469 * Be aware that to enable the browser to parse an XML document, the server must set
5470 * the Content-Type header in the HTTP response to "text/xml".
5472 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5473 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5474 * will be used to make the request.
5476 Roo.data.HttpProxy = function(conn){
5477 Roo.data.HttpProxy.superclass.constructor.call(this);
5478 // is conn a conn config or a real conn?
5480 this.useAjax = !conn || !conn.events;
5484 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5485 // thse are take from connection...
5488 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5491 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5492 * extra parameters to each request made by this object. (defaults to undefined)
5495 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5496 * to each request made by this object. (defaults to undefined)
5499 * @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)
5502 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5505 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5511 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5515 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5516 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5517 * a finer-grained basis than the DataProxy events.
5519 getConnection : function(){
5520 return this.useAjax ? Roo.Ajax : this.conn;
5524 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5525 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5526 * process that block using the passed callback.
5527 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5528 * for the request to the remote server.
5529 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5530 * object into a block of Roo.data.Records.
5531 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5532 * The function must be passed <ul>
5533 * <li>The Record block object</li>
5534 * <li>The "arg" argument from the load function</li>
5535 * <li>A boolean success indicator</li>
5537 * @param {Object} scope The scope in which to call the callback
5538 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5540 load : function(params, reader, callback, scope, arg){
5541 if(this.fireEvent("beforeload", this, params) !== false){
5543 params : params || {},
5545 callback : callback,
5550 callback : this.loadResponse,
5554 Roo.applyIf(o, this.conn);
5555 if(this.activeRequest){
5556 Roo.Ajax.abort(this.activeRequest);
5558 this.activeRequest = Roo.Ajax.request(o);
5560 this.conn.request(o);
5563 callback.call(scope||this, null, arg, false);
5568 loadResponse : function(o, success, response){
5569 delete this.activeRequest;
5571 this.fireEvent("loadexception", this, o, response);
5572 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5577 result = o.reader.read(response);
5579 this.fireEvent("loadexception", this, o, response, e);
5580 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5584 this.fireEvent("load", this, o, o.request.arg);
5585 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5589 update : function(dataSet){
5594 updateResponse : function(dataSet){
5599 * Ext JS Library 1.1.1
5600 * Copyright(c) 2006-2007, Ext JS, LLC.
5602 * Originally Released Under LGPL - original licence link has changed is not relivant.
5605 * <script type="text/javascript">
5609 * @class Roo.data.ScriptTagProxy
5610 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5611 * other than the originating domain of the running page.<br><br>
5613 * <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
5614 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5616 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5617 * source code that is used as the source inside a <script> tag.<br><br>
5619 * In order for the browser to process the returned data, the server must wrap the data object
5620 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5621 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5622 * depending on whether the callback name was passed:
5625 boolean scriptTag = false;
5626 String cb = request.getParameter("callback");
5629 response.setContentType("text/javascript");
5631 response.setContentType("application/x-json");
5633 Writer out = response.getWriter();
5635 out.write(cb + "(");
5637 out.print(dataBlock.toJsonString());
5644 * @param {Object} config A configuration object.
5646 Roo.data.ScriptTagProxy = function(config){
5647 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5648 Roo.apply(this, config);
5649 this.head = document.getElementsByTagName("head")[0];
5652 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5654 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5656 * @cfg {String} url The URL from which to request the data object.
5659 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5663 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5664 * the server the name of the callback function set up by the load call to process the returned data object.
5665 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5666 * javascript output which calls this named function passing the data object as its only parameter.
5668 callbackParam : "callback",
5670 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5671 * name to the request.
5676 * Load data from the configured URL, read the data object into
5677 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5678 * process that block using the passed callback.
5679 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5680 * for the request to the remote server.
5681 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5682 * object into a block of Roo.data.Records.
5683 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5684 * The function must be passed <ul>
5685 * <li>The Record block object</li>
5686 * <li>The "arg" argument from the load function</li>
5687 * <li>A boolean success indicator</li>
5689 * @param {Object} scope The scope in which to call the callback
5690 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5692 load : function(params, reader, callback, scope, arg){
5693 if(this.fireEvent("beforeload", this, params) !== false){
5695 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5698 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5700 url += "&_dc=" + (new Date().getTime());
5702 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5705 cb : "stcCallback"+transId,
5706 scriptId : "stcScript"+transId,
5710 callback : callback,
5716 window[trans.cb] = function(o){
5717 conn.handleResponse(o, trans);
5720 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5722 if(this.autoAbort !== false){
5726 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5728 var script = document.createElement("script");
5729 script.setAttribute("src", url);
5730 script.setAttribute("type", "text/javascript");
5731 script.setAttribute("id", trans.scriptId);
5732 this.head.appendChild(script);
5736 callback.call(scope||this, null, arg, false);
5741 isLoading : function(){
5742 return this.trans ? true : false;
5746 * Abort the current server request.
5749 if(this.isLoading()){
5750 this.destroyTrans(this.trans);
5755 destroyTrans : function(trans, isLoaded){
5756 this.head.removeChild(document.getElementById(trans.scriptId));
5757 clearTimeout(trans.timeoutId);
5759 window[trans.cb] = undefined;
5761 delete window[trans.cb];
5764 // if hasn't been loaded, wait for load to remove it to prevent script error
5765 window[trans.cb] = function(){
5766 window[trans.cb] = undefined;
5768 delete window[trans.cb];
5775 handleResponse : function(o, trans){
5777 this.destroyTrans(trans, true);
5780 result = trans.reader.readRecords(o);
5782 this.fireEvent("loadexception", this, o, trans.arg, e);
5783 trans.callback.call(trans.scope||window, null, trans.arg, false);
5786 this.fireEvent("load", this, o, trans.arg);
5787 trans.callback.call(trans.scope||window, result, trans.arg, true);
5791 handleFailure : function(trans){
5793 this.destroyTrans(trans, false);
5794 this.fireEvent("loadexception", this, null, trans.arg);
5795 trans.callback.call(trans.scope||window, null, trans.arg, false);
5799 * Ext JS Library 1.1.1
5800 * Copyright(c) 2006-2007, Ext JS, LLC.
5802 * Originally Released Under LGPL - original licence link has changed is not relivant.
5805 * <script type="text/javascript">
5809 * @class Roo.data.JsonReader
5810 * @extends Roo.data.DataReader
5811 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5812 * based on mappings in a provided Roo.data.Record constructor.
5814 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5815 * in the reply previously.
5820 var RecordDef = Roo.data.Record.create([
5821 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
5822 {name: 'occupation'} // This field will use "occupation" as the mapping.
5824 var myReader = new Roo.data.JsonReader({
5825 totalProperty: "results", // The property which contains the total dataset size (optional)
5826 root: "rows", // The property which contains an Array of row objects
5827 id: "id" // The property within each row object that provides an ID for the record (optional)
5831 * This would consume a JSON file like this:
5833 { 'results': 2, 'rows': [
5834 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5835 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5838 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5839 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5840 * paged from the remote server.
5841 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5842 * @cfg {String} root name of the property which contains the Array of row objects.
5843 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5845 * Create a new JsonReader
5846 * @param {Object} meta Metadata configuration options
5847 * @param {Object} recordType Either an Array of field definition objects,
5848 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5850 Roo.data.JsonReader = function(meta, recordType){
5853 // set some defaults:
5855 totalProperty: 'total',
5856 successProperty : 'success',
5861 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5863 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5866 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
5867 * Used by Store query builder to append _requestMeta to params.
5870 metaFromRemote : false,
5872 * This method is only used by a DataProxy which has retrieved data from a remote server.
5873 * @param {Object} response The XHR object which contains the JSON data in its responseText.
5874 * @return {Object} data A data block which is used by an Roo.data.Store object as
5875 * a cache of Roo.data.Records.
5877 read : function(response){
5878 var json = response.responseText;
5880 var o = /* eval:var:o */ eval("("+json+")");
5882 throw {message: "JsonReader.read: Json object not found"};
5888 this.metaFromRemote = true;
5889 this.meta = o.metaData;
5890 this.recordType = Roo.data.Record.create(o.metaData.fields);
5891 this.onMetaChange(this.meta, this.recordType, o);
5893 return this.readRecords(o);
5896 // private function a store will implement
5897 onMetaChange : function(meta, recordType, o){
5904 simpleAccess: function(obj, subsc) {
5911 getJsonAccessor: function(){
5913 return function(expr) {
5915 return(re.test(expr))
5916 ? new Function("obj", "return obj." + expr)
5926 * Create a data block containing Roo.data.Records from an XML document.
5927 * @param {Object} o An object which contains an Array of row objects in the property specified
5928 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
5929 * which contains the total size of the dataset.
5930 * @return {Object} data A data block which is used by an Roo.data.Store object as
5931 * a cache of Roo.data.Records.
5933 readRecords : function(o){
5935 * After any data loads, the raw JSON data is available for further custom processing.
5939 var s = this.meta, Record = this.recordType,
5940 f = Record.prototype.fields, fi = f.items, fl = f.length;
5942 // Generate extraction functions for the totalProperty, the root, the id, and for each field
5944 if(s.totalProperty) {
5945 this.getTotal = this.getJsonAccessor(s.totalProperty);
5947 if(s.successProperty) {
5948 this.getSuccess = this.getJsonAccessor(s.successProperty);
5950 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
5952 var g = this.getJsonAccessor(s.id);
5953 this.getId = function(rec) {
5955 return (r === undefined || r === "") ? null : r;
5958 this.getId = function(){return null;};
5961 for(var jj = 0; jj < fl; jj++){
5963 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
5964 this.ef[jj] = this.getJsonAccessor(map);
5968 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
5969 if(s.totalProperty){
5970 var vt = parseInt(this.getTotal(o), 10);
5975 if(s.successProperty){
5976 var vs = this.getSuccess(o);
5977 if(vs === false || vs === 'false'){
5982 for(var i = 0; i < c; i++){
5985 var id = this.getId(n);
5986 for(var j = 0; j < fl; j++){
5988 var v = this.ef[j](n);
5990 Roo.log('missing convert for ' + f.name);
5994 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
5996 var record = new Record(values, id);
5998 records[i] = record;
6004 totalRecords : totalRecords
6009 * Ext JS Library 1.1.1
6010 * Copyright(c) 2006-2007, Ext JS, LLC.
6012 * Originally Released Under LGPL - original licence link has changed is not relivant.
6015 * <script type="text/javascript">
6019 * @class Roo.data.ArrayReader
6020 * @extends Roo.data.DataReader
6021 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6022 * Each element of that Array represents a row of data fields. The
6023 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6024 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6028 var RecordDef = Roo.data.Record.create([
6029 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6030 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6032 var myReader = new Roo.data.ArrayReader({
6033 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6037 * This would consume an Array like this:
6039 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6041 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6043 * Create a new JsonReader
6044 * @param {Object} meta Metadata configuration options.
6045 * @param {Object} recordType Either an Array of field definition objects
6046 * as specified to {@link Roo.data.Record#create},
6047 * or an {@link Roo.data.Record} object
6048 * created using {@link Roo.data.Record#create}.
6050 Roo.data.ArrayReader = function(meta, recordType){
6051 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6054 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6056 * Create a data block containing Roo.data.Records from an XML document.
6057 * @param {Object} o An Array of row objects which represents the dataset.
6058 * @return {Object} data A data block which is used by an Roo.data.Store object as
6059 * a cache of Roo.data.Records.
6061 readRecords : function(o){
6062 var sid = this.meta ? this.meta.id : null;
6063 var recordType = this.recordType, fields = recordType.prototype.fields;
6066 for(var i = 0; i < root.length; i++){
6069 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6070 for(var j = 0, jlen = fields.length; j < jlen; j++){
6071 var f = fields.items[j];
6072 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6073 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6077 var record = new recordType(values, id);
6079 records[records.length] = record;
6083 totalRecords : records.length
6092 * @class Roo.bootstrap.ComboBox
6093 * @extends Roo.bootstrap.TriggerField
6094 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6096 * Create a new ComboBox.
6097 * @param {Object} config Configuration options
6099 Roo.bootstrap.ComboBox = function(config){
6100 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6104 * Fires when the dropdown list is expanded
6105 * @param {Roo.bootstrap.ComboBox} combo This combo box
6110 * Fires when the dropdown list is collapsed
6111 * @param {Roo.bootstrap.ComboBox} combo This combo box
6115 * @event beforeselect
6116 * Fires before a list item is selected. Return false to cancel the selection.
6117 * @param {Roo.bootstrap.ComboBox} combo This combo box
6118 * @param {Roo.data.Record} record The data record returned from the underlying store
6119 * @param {Number} index The index of the selected item in the dropdown list
6121 'beforeselect' : true,
6124 * Fires when a list item is selected
6125 * @param {Roo.bootstrap.ComboBox} combo This combo box
6126 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6127 * @param {Number} index The index of the selected item in the dropdown list
6131 * @event beforequery
6132 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6133 * The event object passed has these properties:
6134 * @param {Roo.bootstrap.ComboBox} combo This combo box
6135 * @param {String} query The query
6136 * @param {Boolean} forceAll true to force "all" query
6137 * @param {Boolean} cancel true to cancel the query
6138 * @param {Object} e The query event object
6140 'beforequery': true,
6143 * Fires when the 'add' icon is pressed (add a listener to enable add button)
6144 * @param {Roo.bootstrap.ComboBox} combo This combo box
6149 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6150 * @param {Roo.bootstrap.ComboBox} combo This combo box
6151 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6159 this.selectedIndex = -1;
6160 if(this.mode == 'local'){
6161 if(config.queryDelay === undefined){
6162 this.queryDelay = 10;
6164 if(config.minChars === undefined){
6170 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6173 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6174 * rendering into an Roo.Editor, defaults to false)
6177 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6178 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6181 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6184 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6185 * the dropdown list (defaults to undefined, with no header element)
6189 * @cfg {String/Roo.Template} tpl The template to use to render the output
6193 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6195 listWidth: undefined,
6197 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6198 * mode = 'remote' or 'text' if mode = 'local')
6200 displayField: undefined,
6202 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6203 * mode = 'remote' or 'value' if mode = 'local').
6204 * Note: use of a valueField requires the user make a selection
6205 * in order for a value to be mapped.
6207 valueField: undefined,
6211 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6212 * field's data value (defaults to the underlying DOM element's name)
6214 hiddenName: undefined,
6216 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6220 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6222 selectedClass: 'active',
6225 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6229 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6230 * anchor positions (defaults to 'tl-bl')
6232 listAlign: 'tl-bl?',
6234 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6238 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
6239 * query specified by the allQuery config option (defaults to 'query')
6241 triggerAction: 'query',
6243 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6244 * (defaults to 4, does not apply if editable = false)
6248 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6249 * delay (typeAheadDelay) if it matches a known value (defaults to false)
6253 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6254 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6258 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6259 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
6263 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
6264 * when editable = true (defaults to false)
6266 selectOnFocus:false,
6268 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6270 queryParam: 'query',
6272 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
6273 * when mode = 'remote' (defaults to 'Loading...')
6275 loadingText: 'Loading...',
6277 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6281 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6285 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6286 * traditional select (defaults to true)
6290 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6294 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6298 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6299 * listWidth has a higher value)
6303 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6304 * allow the user to set arbitrary text into the field (defaults to false)
6306 forceSelection:false,
6308 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6309 * if typeAhead = true (defaults to 250)
6311 typeAheadDelay : 250,
6313 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6314 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6316 valueNotFoundText : undefined,
6318 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6323 * @cfg {Boolean} disableClear Disable showing of clear button.
6325 disableClear : false,
6327 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
6329 alwaysQuery : false,
6335 // element that contains real text value.. (when hidden is used..)
6338 initEvents: function(){
6341 throw "can not find store for combo";
6343 this.store = Roo.factory(this.store, Roo.data);
6347 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6350 if(this.hiddenName){
6352 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6354 this.hiddenField.dom.value =
6355 this.hiddenValue !== undefined ? this.hiddenValue :
6356 this.value !== undefined ? this.value : '';
6358 // prevent input submission
6359 this.el.dom.removeAttribute('name');
6360 this.hiddenField.dom.setAttribute('name', this.hiddenName);
6365 // this.el.dom.setAttribute('autocomplete', 'off');
6368 var cls = 'x-combo-list';
6369 this.list = this.el.select('ul',true).first();
6371 //this.list = new Roo.Layer({
6372 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6375 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6376 this.list.setWidth(lw);
6378 this.list.swallowEvent('mousewheel');
6379 this.assetHeight = 0;
6382 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6383 this.assetHeight += this.header.getHeight();
6386 this.innerList = this.list.createChild({cls:cls+'-inner'});
6387 this.innerList.on('mouseover', this.onViewOver, this);
6388 this.innerList.on('mousemove', this.onViewMove, this);
6389 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6391 if(this.allowBlank && !this.pageSize && !this.disableClear){
6392 this.footer = this.list.createChild({cls:cls+'-ft'});
6393 this.pageTb = new Roo.Toolbar(this.footer);
6397 this.footer = this.list.createChild({cls:cls+'-ft'});
6398 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6399 {pageSize: this.pageSize});
6403 if (this.pageTb && this.allowBlank && !this.disableClear) {
6405 this.pageTb.add(new Roo.Toolbar.Fill(), {
6406 cls: 'x-btn-icon x-btn-clear',
6412 _this.onSelect(false, -1);
6417 this.assetHeight += this.footer.getHeight();
6422 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6425 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6426 singleSelect:true, store: this.store, selectedClass: this.selectedClass
6428 //this.view.wrapEl.setDisplayed(false);
6429 this.view.on('click', this.onViewClick, this);
6433 this.store.on('beforeload', this.onBeforeLoad, this);
6434 this.store.on('load', this.onLoad, this);
6435 this.store.on('loadexception', this.onLoadException, this);
6438 this.resizer = new Roo.Resizable(this.list, {
6439 pinned:true, handles:'se'
6441 this.resizer.on('resize', function(r, w, h){
6442 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6444 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6445 this.restrictHeight();
6447 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6451 this.editable = true;
6452 this.setEditable(false);
6457 if (typeof(this.events.add.listeners) != 'undefined') {
6459 this.addicon = this.wrap.createChild(
6460 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
6462 this.addicon.on('click', function(e) {
6463 this.fireEvent('add', this);
6466 if (typeof(this.events.edit.listeners) != 'undefined') {
6468 this.editicon = this.wrap.createChild(
6469 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
6471 this.editicon.setStyle('margin-left', '40px');
6473 this.editicon.on('click', function(e) {
6475 // we fire even if inothing is selected..
6476 this.fireEvent('edit', this, this.lastData );
6483 this.keyNav = new Roo.KeyNav(this.inputEl(), {
6485 this.inKeyMode = true;
6489 "down" : function(e){
6490 if(!this.isExpanded()){
6491 this.onTriggerClick();
6493 this.inKeyMode = true;
6498 "enter" : function(e){
6503 "esc" : function(e){
6507 "tab" : function(e){
6508 this.onViewClick(false);
6509 this.fireEvent("specialkey", this, e);
6515 doRelay : function(foo, bar, hname){
6516 if(hname == 'down' || this.scope.isExpanded()){
6517 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6526 this.queryDelay = Math.max(this.queryDelay || 10,
6527 this.mode == 'local' ? 10 : 250);
6530 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6533 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6535 if(this.editable !== false){
6536 this.inputEl().on("keyup", this.onKeyUp, this);
6538 if(this.forceSelection){
6539 this.on('blur', this.doForce, this);
6543 onDestroy : function(){
6545 this.view.setStore(null);
6546 this.view.el.removeAllListeners();
6547 this.view.el.remove();
6548 this.view.purgeListeners();
6551 this.list.dom.innerHTML = '';
6554 this.store.un('beforeload', this.onBeforeLoad, this);
6555 this.store.un('load', this.onLoad, this);
6556 this.store.un('loadexception', this.onLoadException, this);
6558 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6562 fireKey : function(e){
6563 if(e.isNavKeyPress() && !this.list.isVisible()){
6564 this.fireEvent("specialkey", this, e);
6569 onResize: function(w, h){
6570 Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6572 if(typeof w != 'number'){
6573 // we do not handle it!?!?
6576 var tw = this.trigger.getWidth();
6577 // tw += this.addicon ? this.addicon.getWidth() : 0;
6578 // tw += this.editicon ? this.editicon.getWidth() : 0;
6580 this.inputEl().setWidth( this.adjustWidth('input', x));
6582 //this.trigger.setStyle('left', x+'px');
6584 if(this.list && this.listWidth === undefined){
6585 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6586 this.list.setWidth(lw);
6587 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6595 * Allow or prevent the user from directly editing the field text. If false is passed,
6596 * the user will only be able to select from the items defined in the dropdown list. This method
6597 * is the runtime equivalent of setting the 'editable' config option at config time.
6598 * @param {Boolean} value True to allow the user to directly edit the field text
6600 setEditable : function(value){
6601 if(value == this.editable){
6604 this.editable = value;
6606 this.inputEl().dom.setAttribute('readOnly', true);
6607 this.inputEl().on('mousedown', this.onTriggerClick, this);
6608 this.inputEl().addClass('x-combo-noedit');
6610 this.inputEl().dom.setAttribute('readOnly', false);
6611 this.inputEl().un('mousedown', this.onTriggerClick, this);
6612 this.inputEl().removeClass('x-combo-noedit');
6617 onBeforeLoad : function(){
6621 //this.innerList.update(this.loadingText ?
6622 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6623 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6625 this.restrictHeight();
6626 this.selectedIndex = -1;
6630 onLoad : function(){
6634 if(this.store.getCount() > 0){
6636 this.restrictHeight();
6637 if(this.lastQuery == this.allQuery){
6639 this.inputEl().dom.select();
6641 if(!this.selectByValue(this.value, true)){
6642 this.select(0, true);
6646 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6647 this.taTask.delay(this.typeAheadDelay);
6651 this.onEmptyResults();
6656 onLoadException : function()
6659 Roo.log(this.store.reader.jsonData);
6660 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6662 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6668 onTypeAhead : function(){
6669 if(this.store.getCount() > 0){
6670 var r = this.store.getAt(0);
6671 var newValue = r.data[this.displayField];
6672 var len = newValue.length;
6673 var selStart = this.getRawValue().length;
6674 if(selStart != len){
6675 this.setRawValue(newValue);
6676 this.selectText(selStart, newValue.length);
6682 onSelect : function(record, index){
6683 if(this.fireEvent('beforeselect', this, record, index) !== false){
6684 this.setFromData(index > -1 ? record.data : false);
6686 this.fireEvent('select', this, record, index);
6691 * Returns the currently selected field value or empty string if no value is set.
6692 * @return {String} value The selected value
6694 getValue : function(){
6695 if(this.valueField){
6696 return typeof this.value != 'undefined' ? this.value : '';
6698 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6703 * Clears any text/value currently set in the field
6705 clearValue : function(){
6706 if(this.hiddenField){
6707 this.hiddenField.dom.value = '';
6710 this.setRawValue('');
6711 this.lastSelectionText = '';
6716 * Sets the specified value into the field. If the value finds a match, the corresponding record text
6717 * will be displayed in the field. If the value does not match the data value of an existing item,
6718 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6719 * Otherwise the field will be blank (although the value will still be set).
6720 * @param {String} value The value to match
6722 setValue : function(v){
6724 if(this.valueField){
6725 var r = this.findRecord(this.valueField, v);
6727 text = r.data[this.displayField];
6728 }else if(this.valueNotFoundText !== undefined){
6729 text = this.valueNotFoundText;
6732 this.lastSelectionText = text;
6733 if(this.hiddenField){
6734 this.hiddenField.dom.value = v;
6736 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6740 * @property {Object} the last set data for the element
6745 * Sets the value of the field based on a object which is related to the record format for the store.
6746 * @param {Object} value the value to set as. or false on reset?
6748 setFromData : function(o){
6749 var dv = ''; // display value
6750 var vv = ''; // value value..
6752 if (this.displayField) {
6753 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6755 // this is an error condition!!!
6756 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
6759 if(this.valueField){
6760 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6762 if(this.hiddenField){
6763 this.hiddenField.dom.value = vv;
6765 this.lastSelectionText = dv;
6766 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6770 // no hidden field.. - we store the value in 'value', but still display
6771 // display field!!!!
6772 this.lastSelectionText = dv;
6773 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6780 // overridden so that last data is reset..
6781 this.setValue(this.originalValue);
6782 this.clearInvalid();
6783 this.lastData = false;
6785 this.view.clearSelections();
6789 findRecord : function(prop, value){
6791 if(this.store.getCount() > 0){
6792 this.store.each(function(r){
6793 if(r.data[prop] == value){
6805 // returns hidden if it's set..
6806 if (!this.rendered) {return ''};
6807 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
6811 onViewMove : function(e, t){
6812 this.inKeyMode = false;
6816 onViewOver : function(e, t){
6817 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6820 var item = this.view.findItemFromChild(t);
6822 var index = this.view.indexOf(item);
6823 this.select(index, false);
6828 onViewClick : function(doFocus)
6830 var index = this.view.getSelectedIndexes()[0];
6831 var r = this.store.getAt(index);
6833 this.onSelect(r, index);
6835 if(doFocus !== false && !this.blockFocus){
6836 this.inputEl().focus();
6841 restrictHeight : function(){
6842 //this.innerList.dom.style.height = '';
6843 //var inner = this.innerList.dom;
6844 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6845 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6846 //this.list.beginUpdate();
6847 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6848 this.list.alignTo(this.inputEl(), this.listAlign);
6849 //this.list.endUpdate();
6853 onEmptyResults : function(){
6858 * Returns true if the dropdown list is expanded, else false.
6860 isExpanded : function(){
6861 return this.list.isVisible();
6865 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6866 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6867 * @param {String} value The data value of the item to select
6868 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6869 * selected item if it is not currently in view (defaults to true)
6870 * @return {Boolean} True if the value matched an item in the list, else false
6872 selectByValue : function(v, scrollIntoView){
6873 if(v !== undefined && v !== null){
6874 var r = this.findRecord(this.valueField || this.displayField, v);
6876 this.select(this.store.indexOf(r), scrollIntoView);
6884 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
6885 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6886 * @param {Number} index The zero-based index of the list item to select
6887 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6888 * selected item if it is not currently in view (defaults to true)
6890 select : function(index, scrollIntoView){
6891 this.selectedIndex = index;
6892 this.view.select(index);
6893 if(scrollIntoView !== false){
6894 var el = this.view.getNode(index);
6896 //this.innerList.scrollChildIntoView(el, false);
6903 selectNext : function(){
6904 var ct = this.store.getCount();
6906 if(this.selectedIndex == -1){
6908 }else if(this.selectedIndex < ct-1){
6909 this.select(this.selectedIndex+1);
6915 selectPrev : function(){
6916 var ct = this.store.getCount();
6918 if(this.selectedIndex == -1){
6920 }else if(this.selectedIndex != 0){
6921 this.select(this.selectedIndex-1);
6927 onKeyUp : function(e){
6928 if(this.editable !== false && !e.isSpecialKey()){
6929 this.lastKey = e.getKey();
6930 this.dqTask.delay(this.queryDelay);
6935 validateBlur : function(){
6936 return !this.list || !this.list.isVisible();
6940 initQuery : function(){
6941 this.doQuery(this.getRawValue());
6945 doForce : function(){
6946 if(this.el.dom.value.length > 0){
6948 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
6954 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
6955 * query allowing the query action to be canceled if needed.
6956 * @param {String} query The SQL query to execute
6957 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
6958 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
6959 * saved in the current store (defaults to false)
6961 doQuery : function(q, forceAll){
6962 if(q === undefined || q === null){
6971 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
6975 forceAll = qe.forceAll;
6976 if(forceAll === true || (q.length >= this.minChars)){
6977 if(this.lastQuery != q || this.alwaysQuery){
6979 if(this.mode == 'local'){
6980 this.selectedIndex = -1;
6982 this.store.clearFilter();
6984 this.store.filter(this.displayField, q);
6988 this.store.baseParams[this.queryParam] = q;
6990 params: this.getParams(q)
6995 this.selectedIndex = -1;
7002 getParams : function(q){
7004 //p[this.queryParam] = q;
7007 p.limit = this.pageSize;
7013 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
7015 collapse : function(){
7016 if(!this.isExpanded()){
7020 Roo.get(document).un('mousedown', this.collapseIf, this);
7021 Roo.get(document).un('mousewheel', this.collapseIf, this);
7022 if (!this.editable) {
7023 Roo.get(document).un('keydown', this.listKeyPress, this);
7025 this.fireEvent('collapse', this);
7029 collapseIf : function(e){
7030 if(!e.within(this.el) && !e.within(this.el)){
7036 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
7038 expand : function(){
7040 if(this.isExpanded() || !this.hasFocus){
7043 this.list.alignTo(this.inputEl(), this.listAlign);
7045 Roo.get(document).on('mousedown', this.collapseIf, this);
7046 Roo.get(document).on('mousewheel', this.collapseIf, this);
7047 if (!this.editable) {
7048 Roo.get(document).on('keydown', this.listKeyPress, this);
7051 this.fireEvent('expand', this);
7055 // Implements the default empty TriggerField.onTriggerClick function
7056 onTriggerClick : function()
7058 Roo.log('trigger click');
7063 if(this.isExpanded()){
7065 if (!this.blockFocus) {
7066 this.inputEl().focus();
7070 this.hasFocus = true;
7071 if(this.triggerAction == 'all') {
7072 this.doQuery(this.allQuery, true);
7074 this.doQuery(this.getRawValue());
7076 if (!this.blockFocus) {
7077 this.inputEl().focus();
7081 listKeyPress : function(e)
7083 //Roo.log('listkeypress');
7084 // scroll to first matching element based on key pres..
7085 if (e.isSpecialKey()) {
7088 var k = String.fromCharCode(e.getKey()).toUpperCase();
7091 var csel = this.view.getSelectedNodes();
7092 var cselitem = false;
7094 var ix = this.view.indexOf(csel[0]);
7095 cselitem = this.store.getAt(ix);
7096 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7102 this.store.each(function(v) {
7104 // start at existing selection.
7105 if (cselitem.id == v.id) {
7111 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7112 match = this.store.indexOf(v);
7118 if (match === false) {
7119 return true; // no more action?
7122 this.view.select(match);
7123 var sn = Roo.get(this.view.getSelectedNodes()[0])
7124 //sn.scrollIntoView(sn.dom.parentNode, false);
7128 * @cfg {Boolean} grow
7132 * @cfg {Number} growMin
7136 * @cfg {Number} growMax
7145 * Ext JS Library 1.1.1
7146 * Copyright(c) 2006-2007, Ext JS, LLC.
7148 * Originally Released Under LGPL - original licence link has changed is not relivant.
7151 * <script type="text/javascript">
7156 * @extends Roo.util.Observable
7157 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
7158 * This class also supports single and multi selection modes. <br>
7159 * Create a data model bound view:
7161 var store = new Roo.data.Store(...);
7163 var view = new Roo.View({
7165 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
7168 selectedClass: "ydataview-selected",
7172 // listen for node click?
7173 view.on("click", function(vw, index, node, e){
7174 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7178 dataModel.load("foobar.xml");
7180 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7182 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7183 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7185 * Note: old style constructor is still suported (container, template, config)
7189 * @param {Object} config The config object
7192 Roo.View = function(config, depreciated_tpl, depreciated_config){
7194 if (typeof(depreciated_tpl) == 'undefined') {
7195 // new way.. - universal constructor.
7196 Roo.apply(this, config);
7197 this.el = Roo.get(this.el);
7200 this.el = Roo.get(config);
7201 this.tpl = depreciated_tpl;
7202 Roo.apply(this, depreciated_config);
7204 this.wrapEl = this.el.wrap().wrap();
7205 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7208 if(typeof(this.tpl) == "string"){
7209 this.tpl = new Roo.Template(this.tpl);
7211 // support xtype ctors..
7212 this.tpl = new Roo.factory(this.tpl, Roo);
7224 * @event beforeclick
7225 * Fires before a click is processed. Returns false to cancel the default action.
7226 * @param {Roo.View} this
7227 * @param {Number} index The index of the target node
7228 * @param {HTMLElement} node The target node
7229 * @param {Roo.EventObject} e The raw event object
7231 "beforeclick" : true,
7234 * Fires when a template node is clicked.
7235 * @param {Roo.View} this
7236 * @param {Number} index The index of the target node
7237 * @param {HTMLElement} node The target node
7238 * @param {Roo.EventObject} e The raw event object
7243 * Fires when a template node is double clicked.
7244 * @param {Roo.View} this
7245 * @param {Number} index The index of the target node
7246 * @param {HTMLElement} node The target node
7247 * @param {Roo.EventObject} e The raw event object
7251 * @event contextmenu
7252 * Fires when a template node is right clicked.
7253 * @param {Roo.View} this
7254 * @param {Number} index The index of the target node
7255 * @param {HTMLElement} node The target node
7256 * @param {Roo.EventObject} e The raw event object
7258 "contextmenu" : true,
7260 * @event selectionchange
7261 * Fires when the selected nodes change.
7262 * @param {Roo.View} this
7263 * @param {Array} selections Array of the selected nodes
7265 "selectionchange" : true,
7268 * @event beforeselect
7269 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7270 * @param {Roo.View} this
7271 * @param {HTMLElement} node The node to be selected
7272 * @param {Array} selections Array of currently selected nodes
7274 "beforeselect" : true,
7276 * @event preparedata
7277 * Fires on every row to render, to allow you to change the data.
7278 * @param {Roo.View} this
7279 * @param {Object} data to be rendered (change this)
7281 "preparedata" : true
7289 "click": this.onClick,
7290 "dblclick": this.onDblClick,
7291 "contextmenu": this.onContextMenu,
7295 this.selections = [];
7297 this.cmp = new Roo.CompositeElementLite([]);
7299 this.store = Roo.factory(this.store, Roo.data);
7300 this.setStore(this.store, true);
7303 if ( this.footer && this.footer.xtype) {
7305 var fctr = this.wrapEl.appendChild(document.createElement("div"));
7307 this.footer.dataSource = this.store
7308 this.footer.container = fctr;
7309 this.footer = Roo.factory(this.footer, Roo);
7310 fctr.insertFirst(this.el);
7312 // this is a bit insane - as the paging toolbar seems to detach the el..
7313 // dom.parentNode.parentNode.parentNode
7314 // they get detached?
7318 Roo.View.superclass.constructor.call(this);
7323 Roo.extend(Roo.View, Roo.util.Observable, {
7326 * @cfg {Roo.data.Store} store Data store to load data from.
7331 * @cfg {String|Roo.Element} el The container element.
7336 * @cfg {String|Roo.Template} tpl The template used by this View
7340 * @cfg {String} dataName the named area of the template to use as the data area
7341 * Works with domtemplates roo-name="name"
7345 * @cfg {String} selectedClass The css class to add to selected nodes
7347 selectedClass : "x-view-selected",
7349 * @cfg {String} emptyText The empty text to show when nothing is loaded.
7354 * @cfg {String} text to display on mask (default Loading)
7358 * @cfg {Boolean} multiSelect Allow multiple selection
7360 multiSelect : false,
7362 * @cfg {Boolean} singleSelect Allow single selection
7364 singleSelect: false,
7367 * @cfg {Boolean} toggleSelect - selecting
7369 toggleSelect : false,
7372 * Returns the element this view is bound to.
7373 * @return {Roo.Element}
7382 * Refreshes the view. - called by datachanged on the store. - do not call directly.
7384 refresh : function(){
7387 // if we are using something like 'domtemplate', then
7388 // the what gets used is:
7389 // t.applySubtemplate(NAME, data, wrapping data..)
7390 // the outer template then get' applied with
7391 // the store 'extra data'
7392 // and the body get's added to the
7393 // roo-name="data" node?
7394 // <span class='roo-tpl-{name}'></span> ?????
7398 this.clearSelections();
7401 var records = this.store.getRange();
7402 if(records.length < 1) {
7404 // is this valid?? = should it render a template??
7406 this.el.update(this.emptyText);
7410 if (this.dataName) {
7411 this.el.update(t.apply(this.store.meta)); //????
7412 el = this.el.child('.roo-tpl-' + this.dataName);
7415 for(var i = 0, len = records.length; i < len; i++){
7416 var data = this.prepareData(records[i].data, i, records[i]);
7417 this.fireEvent("preparedata", this, data, i, records[i]);
7418 html[html.length] = Roo.util.Format.trim(
7420 t.applySubtemplate(this.dataName, data, this.store.meta) :
7427 el.update(html.join(""));
7428 this.nodes = el.dom.childNodes;
7429 this.updateIndexes(0);
7433 * Function to override to reformat the data that is sent to
7434 * the template for each node.
7435 * DEPRICATED - use the preparedata event handler.
7436 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7437 * a JSON object for an UpdateManager bound view).
7439 prepareData : function(data, index, record)
7441 this.fireEvent("preparedata", this, data, index, record);
7445 onUpdate : function(ds, record){
7446 this.clearSelections();
7447 var index = this.store.indexOf(record);
7448 var n = this.nodes[index];
7449 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7450 n.parentNode.removeChild(n);
7451 this.updateIndexes(index, index);
7457 onAdd : function(ds, records, index)
7459 this.clearSelections();
7460 if(this.nodes.length == 0){
7464 var n = this.nodes[index];
7465 for(var i = 0, len = records.length; i < len; i++){
7466 var d = this.prepareData(records[i].data, i, records[i]);
7468 this.tpl.insertBefore(n, d);
7471 this.tpl.append(this.el, d);
7474 this.updateIndexes(index);
7477 onRemove : function(ds, record, index){
7478 this.clearSelections();
7479 var el = this.dataName ?
7480 this.el.child('.roo-tpl-' + this.dataName) :
7482 el.dom.removeChild(this.nodes[index]);
7483 this.updateIndexes(index);
7487 * Refresh an individual node.
7488 * @param {Number} index
7490 refreshNode : function(index){
7491 this.onUpdate(this.store, this.store.getAt(index));
7494 updateIndexes : function(startIndex, endIndex){
7495 var ns = this.nodes;
7496 startIndex = startIndex || 0;
7497 endIndex = endIndex || ns.length - 1;
7498 for(var i = startIndex; i <= endIndex; i++){
7499 ns[i].nodeIndex = i;
7504 * Changes the data store this view uses and refresh the view.
7505 * @param {Store} store
7507 setStore : function(store, initial){
7508 if(!initial && this.store){
7509 this.store.un("datachanged", this.refresh);
7510 this.store.un("add", this.onAdd);
7511 this.store.un("remove", this.onRemove);
7512 this.store.un("update", this.onUpdate);
7513 this.store.un("clear", this.refresh);
7514 this.store.un("beforeload", this.onBeforeLoad);
7515 this.store.un("load", this.onLoad);
7516 this.store.un("loadexception", this.onLoad);
7520 store.on("datachanged", this.refresh, this);
7521 store.on("add", this.onAdd, this);
7522 store.on("remove", this.onRemove, this);
7523 store.on("update", this.onUpdate, this);
7524 store.on("clear", this.refresh, this);
7525 store.on("beforeload", this.onBeforeLoad, this);
7526 store.on("load", this.onLoad, this);
7527 store.on("loadexception", this.onLoad, this);
7535 * onbeforeLoad - masks the loading area.
7538 onBeforeLoad : function()
7541 this.el.mask(this.mask ? this.mask : "Loading" );
7543 onLoad : function ()
7550 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7551 * @param {HTMLElement} node
7552 * @return {HTMLElement} The template node
7554 findItemFromChild : function(node){
7555 var el = this.dataName ?
7556 this.el.child('.roo-tpl-' + this.dataName,true) :
7559 if(!node || node.parentNode == el){
7562 var p = node.parentNode;
7563 while(p && p != el){
7564 if(p.parentNode == el){
7573 onClick : function(e){
7574 var item = this.findItemFromChild(e.getTarget());
7576 var index = this.indexOf(item);
7577 if(this.onItemClick(item, index, e) !== false){
7578 this.fireEvent("click", this, index, item, e);
7581 this.clearSelections();
7586 onContextMenu : function(e){
7587 var item = this.findItemFromChild(e.getTarget());
7589 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7594 onDblClick : function(e){
7595 var item = this.findItemFromChild(e.getTarget());
7597 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7601 onItemClick : function(item, index, e)
7603 if(this.fireEvent("beforeclick", this, index, item, e) === false){
7606 if (this.toggleSelect) {
7607 var m = this.isSelected(item) ? 'unselect' : 'select';
7610 _t[m](item, true, false);
7613 if(this.multiSelect || this.singleSelect){
7614 if(this.multiSelect && e.shiftKey && this.lastSelection){
7615 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7617 this.select(item, this.multiSelect && e.ctrlKey);
7618 this.lastSelection = item;
7626 * Get the number of selected nodes.
7629 getSelectionCount : function(){
7630 return this.selections.length;
7634 * Get the currently selected nodes.
7635 * @return {Array} An array of HTMLElements
7637 getSelectedNodes : function(){
7638 return this.selections;
7642 * Get the indexes of the selected nodes.
7645 getSelectedIndexes : function(){
7646 var indexes = [], s = this.selections;
7647 for(var i = 0, len = s.length; i < len; i++){
7648 indexes.push(s[i].nodeIndex);
7654 * Clear all selections
7655 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7657 clearSelections : function(suppressEvent){
7658 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7659 this.cmp.elements = this.selections;
7660 this.cmp.removeClass(this.selectedClass);
7661 this.selections = [];
7663 this.fireEvent("selectionchange", this, this.selections);
7669 * Returns true if the passed node is selected
7670 * @param {HTMLElement/Number} node The node or node index
7673 isSelected : function(node){
7674 var s = this.selections;
7678 node = this.getNode(node);
7679 return s.indexOf(node) !== -1;
7684 * @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
7685 * @param {Boolean} keepExisting (optional) true to keep existing selections
7686 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7688 select : function(nodeInfo, keepExisting, suppressEvent){
7689 if(nodeInfo instanceof Array){
7691 this.clearSelections(true);
7693 for(var i = 0, len = nodeInfo.length; i < len; i++){
7694 this.select(nodeInfo[i], true, true);
7698 var node = this.getNode(nodeInfo);
7699 if(!node || this.isSelected(node)){
7700 return; // already selected.
7703 this.clearSelections(true);
7705 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7706 Roo.fly(node).addClass(this.selectedClass);
7707 this.selections.push(node);
7709 this.fireEvent("selectionchange", this, this.selections);
7717 * @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
7718 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7719 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7721 unselect : function(nodeInfo, keepExisting, suppressEvent)
7723 if(nodeInfo instanceof Array){
7724 Roo.each(this.selections, function(s) {
7725 this.unselect(s, nodeInfo);
7729 var node = this.getNode(nodeInfo);
7730 if(!node || !this.isSelected(node)){
7731 Roo.log("not selected");
7732 return; // not selected.
7736 Roo.each(this.selections, function(s) {
7738 Roo.fly(node).removeClass(this.selectedClass);
7745 this.selections= ns;
7746 this.fireEvent("selectionchange", this, this.selections);
7750 * Gets a template node.
7751 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7752 * @return {HTMLElement} The node or null if it wasn't found
7754 getNode : function(nodeInfo){
7755 if(typeof nodeInfo == "string"){
7756 return document.getElementById(nodeInfo);
7757 }else if(typeof nodeInfo == "number"){
7758 return this.nodes[nodeInfo];
7764 * Gets a range template nodes.
7765 * @param {Number} startIndex
7766 * @param {Number} endIndex
7767 * @return {Array} An array of nodes
7769 getNodes : function(start, end){
7770 var ns = this.nodes;
7772 end = typeof end == "undefined" ? ns.length - 1 : end;
7775 for(var i = start; i <= end; i++){
7779 for(var i = start; i >= end; i--){
7787 * Finds the index of the passed node
7788 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7789 * @return {Number} The index of the node or -1
7791 indexOf : function(node){
7792 node = this.getNode(node);
7793 if(typeof node.nodeIndex == "number"){
7794 return node.nodeIndex;
7796 var ns = this.nodes;
7797 for(var i = 0, len = ns.length; i < len; i++){
7808 * based on jquery fullcalendar
7814 * @class Roo.bootstrap.Calendar
7815 * @extends Roo.bootstrap.Component
7816 * Bootstrap Calendar class
7819 * Create a new Container
7820 * @param {Object} config The config object
7823 Roo.bootstrap.Calendar = function(config){
7824 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7828 * Fires when a date is selected
7829 * @param {DatePicker} this
7830 * @param {Date} date The selected date
7834 * @event monthchange
7835 * Fires when the displayed month changes
7836 * @param {DatePicker} this
7837 * @param {Date} date The selected month
7839 'monthchange': true,
7842 * Fires when mouse over an event
7843 * @param {Calendar} this
7844 * @param {event} Event
7849 * Fires when the mouse leaves an
7850 * @param {Calendar} this
7859 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
7862 * @cfg {Number} startDay
7863 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
7867 getAutoCreate : function(){
7870 fc_button = function(name, corner, style, content ) {
7871 return Roo.apply({},{
7873 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
7875 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
7878 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
7886 style : 'width:100%',
7893 cls : 'fc-header-left',
7895 fc_button('prev', 'left', 'arrow', '‹' ),
7896 fc_button('next', 'right', 'arrow', '›' ),
7897 { tag: 'span', cls: 'fc-header-space' },
7898 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
7906 cls : 'fc-header-center',
7910 cls: 'fc-header-title',
7913 html : 'month / year'
7921 cls : 'fc-header-right',
7923 /* fc_button('month', 'left', '', 'month' ),
7924 fc_button('week', '', '', 'week' ),
7925 fc_button('day', 'right', '', 'day' )
7937 var cal_heads = function() {
7939 // fixme - handle this.
7941 for (var i =0; i < Date.dayNames.length; i++) {
7942 var d = Date.dayNames[i];
7945 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
7946 html : d.substring(0,3)
7950 ret[0].cls += ' fc-first';
7951 ret[6].cls += ' fc-last';
7954 var cal_cell = function(n) {
7957 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
7962 cls: 'fc-day-number',
7966 cls: 'fc-day-content',
7970 style: 'position: relative;' // height: 17px;
7982 var cal_rows = function() {
7984 for (var r = 0; r < 6; r++) {
7991 for (var i =0; i < Date.dayNames.length; i++) {
7992 var d = Date.dayNames[i];
7993 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
7996 row.cn[0].cls+=' fc-first';
7997 row.cn[0].cn[0].style = 'min-height:90px';
7998 row.cn[6].cls+=' fc-last';
8002 ret[0].cls += ' fc-first';
8004 ret[5].cls += ' fc-last';
8010 cls: 'fc-border-separate',
8011 style : 'width:100%',
8019 cls : 'fc-first fc-last',
8038 style : "position: relative;",
8041 cls : 'fc-view fc-view-month fc-grid',
8042 style : 'position: relative',
8043 unselectable : 'on',
8046 cls : 'fc-event-container',
8047 style : 'position:absolute;z-index:8;top:0;left:0;'
8065 initEvents : function()
8068 this.cells = this.el.select('.fc-day',true);
8069 this.textNodes = this.el.query('.fc-day-number');
8070 this.update(new Date().clearTime());
8071 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8072 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8073 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8074 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8075 this.cells.addClassOnOver('fc-state-hover');
8079 this.calevents = [];
8083 end : new Date().add(Date.DAY, 2),
8087 start: new Date().add(Date.DAY, -5),
8088 end : new Date().add(Date.DAY, 2),
8093 end : new Date().add(Date.HOUR, 2),
8098 end : new Date().add(Date.HOUR, 2),
8101 this.renderEvents();
8103 resize : function() {
8104 var sz = this.el.getSize();
8106 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8107 this.el.select('.fc-day-content div',true).setHeight(34);
8112 showPrevMonth : function(e){
8113 this.update(this.activeDate.add("mo", -1));
8115 showToday : function(e){
8116 this.update(new Date().clearTime());
8119 showNextMonth : function(e){
8120 this.update(this.activeDate.add("mo", 1));
8124 showPrevYear : function(){
8125 this.update(this.activeDate.add("y", -1));
8129 showNextYear : function(){
8130 this.update(this.activeDate.add("y", 1));
8135 update : function(date)
8138 var vd = this.activeDate;
8139 this.activeDate = date;
8141 var t = date.getTime();
8142 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8143 Roo.log('using add remove');
8144 this.cells.removeClass("fc-state-highlight");
8145 this.cells.each(function(c){
8146 if(c.dateValue == t){
8147 c.addClass("fc-state-highlight");
8148 setTimeout(function(){
8149 try{c.dom.firstChild.focus();}catch(e){}
8159 var days = date.getDaysInMonth();
8160 var firstOfMonth = date.getFirstDateOfMonth();
8161 var startingPos = firstOfMonth.getDay()-this.startDay;
8163 if(startingPos <= this.startDay){
8167 var pm = date.add("mo", -1);
8168 var prevStart = pm.getDaysInMonth()-startingPos;
8170 var cells = this.cells.elements;
8171 var textEls = this.textNodes;
8172 days += startingPos;
8174 // convert everything to numbers so it's fast
8176 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8177 var today = new Date().clearTime().getTime();
8178 var sel = date.clearTime().getTime();
8179 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8180 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8181 var ddMatch = this.disabledDatesRE;
8182 var ddText = this.disabledDatesText;
8183 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8184 var ddaysText = this.disabledDaysText;
8185 var format = this.format;
8187 var setCellClass = function(cal, cell){
8189 var t = d.getTime();
8192 cell.className += " fc-today";
8193 cell.title = cal.todayText;
8196 cell.className += " fc-state-highlight";
8197 //setTimeout(function(){
8198 // try{cell.firstChild.focus();}catch(e){}
8203 cell.className = " fc-state-disabled";
8204 cell.title = cal.minText;
8208 cell.className = " fc-state-disabled";
8209 cell.title = cal.maxText;
8213 if(ddays.indexOf(d.getDay()) != -1){
8214 cell.title = ddaysText;
8215 cell.className = " fc-state-disabled";
8218 if(ddMatch && format){
8219 var fvalue = d.dateFormat(format);
8220 if(ddMatch.test(fvalue)){
8221 cell.title = ddText.replace("%0", fvalue);
8222 cell.className = " fc-state-disabled";
8225 if (!cell.initialClassName) {
8226 cell.initialClassName = cell.dom.className;
8228 cell.dom.className = cell.initialClassName + ' ' + cell.className;
8232 for(; i < startingPos; i++) {
8233 textEls[i].innerHTML = (++prevStart);
8234 d.setDate(d.getDate()+1);
8235 cells[i].className = "fc-past fc-other-month";
8236 setCellClass(this, cells[i]);
8238 for(; i < days; i++){
8239 intDay = i - startingPos + 1;
8240 textEls[i].innerHTML = (intDay);
8241 d.setDate(d.getDate()+1);
8242 cells[i].className = ''; // "x-date-active";
8243 setCellClass(this, cells[i]);
8246 for(; i < 42; i++) {
8247 textEls[i].innerHTML = (++extraDays);
8248 d.setDate(d.getDate()+1);
8249 cells[i].className = "fc-future fc-other-month";
8250 setCellClass(this, cells[i]);
8253 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8254 this.fireEvent('monthchange', this, date);
8258 if(!this.internalRender){
8259 var main = this.el.dom.firstChild;
8260 var w = main.offsetWidth;
8261 this.el.setWidth(w + this.el.getBorderWidth("lr"));
8262 Roo.fly(main).setWidth(w);
8263 this.internalRender = true;
8264 // opera does not respect the auto grow header center column
8265 // then, after it gets a width opera refuses to recalculate
8266 // without a second pass
8267 if(Roo.isOpera && !this.secondPass){
8268 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8269 this.secondPass = true;
8270 this.update.defer(10, this, [date]);
8277 findCell : function(dt) {
8278 dt = dt.clearTime().getTime();
8280 this.cells.each(function(c){
8281 //Roo.log("check " +c.dateValue + '?=' + dt);
8282 if(c.dateValue == dt){
8292 findCells : function(ev) {
8293 var s = ev.start.clone().clearTime().getTime();
8294 var e= ev.end.clone().clearTime().getTime();
8296 this.cells.each(function(c){
8297 //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8299 if(c.dateValue > e){
8302 if(c.dateValue < s){
8311 findBestRow: function(cells)
8314 for (var i =0 ; i < cells.length;i++) {
8315 ret = Math.max(cells[i].rows || 0,ret);
8318 //d.setDate(d.ev()+1);
8323 addItem : function(ev)
8326 // look for vertical location slot in
8327 var cells = this.findCells(ev);
8328 ev.row = this.findBestRow(cells);
8330 // work out the location.
8334 for(var i =0; i < cells.length; i++) {
8342 if (crow.start.getY() == cells[i].getY()) {
8344 crow.end = cells[i];
8359 for (var i = 0; i < cells.length;i++) {
8360 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8364 this.calevents.push(ev);
8367 clearEvents: function() {
8368 Roo.each(this.calevents, function(e) {
8369 Roo.each(e.els, function(el) {
8370 el.un('mouseenter' ,this.onEventEnter, this);
8371 el.un('mouseleave' ,this.onEventLeave, this);
8378 renderEvents: function()
8381 // first make sure there is enough space..
8382 this.cells.each(function(c) {
8383 Roo.log(c.select('.fc-day-content div',true).first(), Math.max(34, c.rows * 20));
8384 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8387 for (var e = 0; e < this.calevents.length; e++) {
8388 var ev = this.calevents[e];
8389 var cells = ev.cells;
8392 for(var i =0; i < rows.length; i++) {
8395 // how many rows should it span..
8398 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8399 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8401 unselectable : "on",
8404 cls: 'fc-event-inner',
8408 cls: 'fc-event-time',
8409 html : cells.length > 1 ? '' : '7pm'
8413 cls: 'fc-event-title',
8414 html : String.format('{0}', ev.title)
8421 cls: 'ui-resizable-handle ui-resizable-e',
8422 html : '  '
8428 cfg.cls += ' fc-event-start';
8430 if ((i+1) == rows.length) {
8431 cfg.cls += ' fc-event-end';
8434 var ctr = this.el.select('.fc-event-container',true).first();
8435 var cg = ctr.createChild(cfg);
8438 cg.on('mouseenter' ,this.onEventEnter, this);
8439 cg.on('mouseleave' ,this.onEventLeave, this);
8442 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8443 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8445 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
8446 cg.setWidth(ebox.right - sbox.x -2);
8453 onEventEnter: function (e, el,c,d) {
8455 this.fireEvent('evententer', this, el);
8458 onEventLeave: function (e, el,c,d) {
8460 this.fireEvent('eventleave', this, el);
8474 * @class Roo.bootstrap.Popover
8475 * @extends Roo.bootstrap.Component
8476 * Bootstrap Popover class
8477 * @cfg {String} html contents of the popover (or false to use children..)
8478 * @cfg {String} title of popover (or false to hide)
8479 * @cfg {String} placement how it is placed
8480 * @cfg {String} trigger click || hover (or false to trigger manually)
8481 * @cfg {String} over what (parent or false to trigger manually.)
8484 * Create a new Popover
8485 * @param {Object} config The config object
8488 Roo.bootstrap.Popover = function(config){
8489 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8492 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
8494 title: 'Fill in a title',
8497 placement : 'right',
8498 trigger : 'hover', // hover
8502 getChildContainer : function()
8504 return this.el.select('.popover-content',true).first();
8507 getAutoCreate : function(){
8508 Roo.log('make popover?');
8511 style: 'display:block',
8517 cls : 'popover-inner',
8521 cls: 'popover-title',
8525 cls : 'popover-content',
8536 // as it get's added to the bottom of the page.
8537 onRender : function(ct, position)
8539 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8541 var cfg = Roo.apply({}, this.getAutoCreate());
8545 cfg.cls += ' ' + this.cls;
8548 cfg.style = this.style;
8550 Roo.log("adding to ")
8551 this.el = Roo.get(document.body).createChild(cfg, position);
8557 initEvents : function()
8559 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8560 this.el.enableDisplayMode('block');
8562 if (this.over === false) {
8565 if (this.triggers === false) {
8568 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8569 var triggers = this.trigger ? this.trigger.split(' ') : [];
8570 Roo.each(triggers, function(trigger) {
8572 if (trigger == 'click') {
8573 on_el.on('click', this.toggle, this);
8574 } else if (trigger != 'manual') {
8575 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
8576 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8578 on_el.on(eventIn ,this.enter, this);
8579 on_el.on(eventOut, this.leave, this);
8590 toggle : function () {
8591 this.hoverState == 'in' ? this.leave() : this.enter();
8594 enter : function () {
8597 clearTimeout(this.timeout);
8599 this.hoverState = 'in'
8601 if (!this.delay || !this.delay.show) {
8606 this.timeout = setTimeout(function () {
8607 if (_t.hoverState == 'in') {
8612 leave : function() {
8613 clearTimeout(this.timeout);
8615 this.hoverState = 'out'
8617 if (!this.delay || !this.delay.hide) {
8622 this.timeout = setTimeout(function () {
8623 if (_t.hoverState == 'out') {
8629 show : function (on_el)
8632 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8635 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8636 if (this.html !== false) {
8637 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8639 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8640 if (!this.title.length) {
8641 this.el.select('.popover-title',true).hide();
8644 var placement = typeof this.placement == 'function' ?
8645 this.placement.call(this, this.el, on_el) :
8648 var autoToken = /\s?auto?\s?/i;
8649 var autoPlace = autoToken.test(placement);
8651 placement = placement.replace(autoToken, '') || 'top';
8655 //this.el.setXY([0,0]);
8657 this.el.dom.style.display='block';
8658 this.el.addClass(placement);
8660 //this.el.appendTo(on_el);
8662 var p = this.getPosition();
8663 var box = this.el.getBox();
8668 var align = Roo.bootstrap.Popover.alignment[placement]
8669 this.el.alignTo(on_el, align[0],align[1]);
8670 //var arrow = this.el.select('.arrow',true).first();
8671 //arrow.set(align[2],
8673 this.el.addClass('in');
8674 this.hoverState = null;
8676 if (this.el.hasClass('fade')) {
8683 this.el.setXY([0,0]);
8684 this.el.removeClass('in');
8691 Roo.bootstrap.Popover.alignment = {
8692 'left' : ['r-l', [-10,0], 'right'],
8693 'right' : ['l-r', [10,0], 'left'],
8694 'bottom' : ['t-b', [0,10], 'top'],
8695 'top' : [ 'b-t', [0,-10], 'bottom']