4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
284 Roo.bootstrap.Body = function(config){
285 Roo.bootstrap.Body.superclass.constructor.call(this, config);
286 this.el = Roo.get(document.body);
289 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
294 onRender : function(ct, position){
297 //this.el.addClass([this.fieldClass, this.cls]);
315 * @class Roo.bootstrap.ButtonGroup
316 * @extends Roo.bootstrap.Component
317 * Bootstrap ButtonGroup class
318 * @cfg {String} size lg | sm | xs (default empty normal)
319 * @cfg {String} align vertical | justified (default none)
320 * @cfg {String} direction up | down (default down)
321 * @cfg {Boolean} toolbar false | true
322 * @cfg {Boolean} btn true | false
327 * @param {Object} config The config object
330 Roo.bootstrap.ButtonGroup = function(config){
331 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
334 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
342 getAutoCreate : function(){
348 cfg.html = this.html || cfg.html;
359 if (['vertical','justified'].indexOf(this.align)!==-1) {
360 cfg.cls = 'btn-group-' + this.align;
362 if (this.align == 'justified') {
363 console.log(this.items);
367 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
368 cfg.cls += ' btn-group-' + this.size;
371 if (this.direction == 'up') {
372 cfg.cls += ' dropup' ;
388 * @class Roo.bootstrap.Button
389 * @extends Roo.bootstrap.Component
390 * Bootstrap Button class
391 * @cfg {String} html The button content
392 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
393 * @cfg {String} size empty | lg | sm | xs
394 * @cfg {String} tag empty | a | input | submit
395 * @cfg {String} href empty or href
396 * @cfg {Boolean} disabled false | true
397 * @cfg {Boolean} isClose false | true
398 * @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
399 * @cfg {String} badge text for badge
400 * @cfg {String} theme default (or empty) | glow
401 * @cfg {Boolean} inverse false | true
402 * @cfg {Boolean} toggle false | true
403 * @cfg {String} ontext text for on toggle state
404 * @cfg {String} offtext text for off toggle state
405 * @cfg {Boolean} defaulton true | false
406 * @cfg {Boolean} preventDefault (true | false) default true
407 * @cfg {Boolean} removeClass true | false remove the standard class..
408 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
411 * Create a new button
412 * @param {Object} config The config object
416 Roo.bootstrap.Button = function(config){
417 Roo.bootstrap.Button.superclass.constructor.call(this, config);
422 * When a butotn is pressed
423 * @param {Roo.EventObject} e
428 * After the button has been toggles
429 * @param {Roo.EventObject} e
430 * @param {boolean} pressed (also available as button.pressed)
436 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
454 preventDefault: true,
463 getAutoCreate : function(){
471 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
472 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
477 cfg.html = this.html || cfg.html;
479 if (this.toggle === true) {
482 cls: 'slider-frame roo-button',
487 'data-off-text':'OFF',
488 cls: 'slider-button',
494 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
495 cfg.cls += ' '+this.weight;
504 cfg["aria-hidden"] = true;
506 cfg.html = "×";
512 if (this.theme==='default') {
513 cfg.cls = 'btn roo-button';
515 //if (this.parentType != 'Navbar') {
516 this.weight = this.weight.length ? this.weight : 'default';
518 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
520 cfg.cls += ' btn-' + this.weight;
522 } else if (this.theme==='glow') {
525 cfg.cls = 'btn-glow roo-button';
527 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
529 cfg.cls += ' ' + this.weight;
535 this.cls += ' inverse';
540 cfg.cls += ' active';
544 cfg.disabled = 'disabled';
548 Roo.log('changing to ul' );
550 this.glyphicon = 'caret';
553 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
555 //gsRoo.log(this.parentType);
556 if (this.parentType === 'Navbar' && !this.parent().bar) {
557 Roo.log('changing to li?');
566 href : this.href || '#'
569 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
570 cfg.cls += ' dropdown';
577 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
579 if (this.glyphicon) {
580 cfg.html = ' ' + cfg.html;
585 cls: 'glyphicon glyphicon-' + this.glyphicon
595 // cfg.cls='btn roo-button';
599 var value = cfg.html;
604 cls: 'glyphicon glyphicon-' + this.glyphicon,
623 cfg.cls += ' dropdown';
624 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
627 if (cfg.tag !== 'a' && this.href !== '') {
628 throw "Tag must be a to set href.";
629 } else if (this.href.length > 0) {
630 cfg.href = this.href;
633 if(this.removeClass){
638 cfg.target = this.target;
643 initEvents: function() {
644 // Roo.log('init events?');
645 // Roo.log(this.el.dom);
646 if (this.el.hasClass('roo-button')) {
647 this.el.on('click', this.onClick, this);
649 this.el.select('.roo-button').on('click', this.onClick, this);
655 onClick : function(e)
657 Roo.log('button on click ');
658 if(this.preventDefault){
661 if (this.pressed === true || this.pressed === false) {
662 this.pressed = !this.pressed;
663 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
664 this.fireEvent('toggle', this, e, this.pressed);
668 this.fireEvent('click', this, e);
682 * @class Roo.bootstrap.Column
683 * @extends Roo.bootstrap.Component
684 * Bootstrap Column class
685 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
686 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
687 * @cfg {Number} md colspan out of 12 for computer-sized screens
688 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
689 * @cfg {String} html content of column.
692 * Create a new Column
693 * @param {Object} config The config object
696 Roo.bootstrap.Column = function(config){
697 Roo.bootstrap.Column.superclass.constructor.call(this, config);
700 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
709 getAutoCreate : function(){
710 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
718 ['xs','sm','md','lg'].map(function(size){
719 if (settings[size]) {
720 cfg.cls += ' col-' + size + '-' + settings[size];
723 if (this.html.length) {
724 cfg.html = this.html;
743 * @class Roo.bootstrap.Container
744 * @extends Roo.bootstrap.Component
745 * Bootstrap Container class
746 * @cfg {Boolean} jumbotron is it a jumbotron element
747 * @cfg {String} html content of element
748 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
749 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
750 * @cfg {String} header content of header (for panel)
751 * @cfg {String} footer content of footer (for panel)
752 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
755 * Create a new Container
756 * @param {Object} config The config object
759 Roo.bootstrap.Container = function(config){
760 Roo.bootstrap.Container.superclass.constructor.call(this, config);
763 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
773 getChildContainer : function() {
779 if (this.panel.length) {
780 return this.el.select('.panel-body',true).first();
787 getAutoCreate : function(){
793 if (this.jumbotron) {
794 cfg.cls = 'jumbotron';
797 cfg.cls = this.cls + '';
800 if (this.sticky.length) {
802 var bd = Roo.get(document.body);
803 if (!bd.hasClass('bootstrap-sticky')) {
804 bd.addClass('bootstrap-sticky');
805 Roo.select('html',true).setStyle('height', '100%');
808 cfg.cls += 'bootstrap-sticky-' + this.sticky;
812 if (this.well.length) {
816 cfg.cls +=' well well-' +this.well;
826 if (this.panel.length) {
827 cfg.cls += ' panel panel-' + this.panel;
829 if (this.header.length) {
832 cls : 'panel-heading',
848 if (this.footer.length) {
850 cls : 'panel-footer',
858 body.html = this.html || cfg.html;
860 if (!cfg.cls.length) {
861 cfg.cls = 'container';
878 * @class Roo.bootstrap.Img
879 * @extends Roo.bootstrap.Component
880 * Bootstrap Img class
881 * @cfg {Boolean} imgResponsive false | true
882 * @cfg {String} border rounded | circle | thumbnail
883 * @cfg {String} src image source
884 * @cfg {String} alt image alternative text
885 * @cfg {String} href a tag href
886 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
890 * @param {Object} config The config object
893 Roo.bootstrap.Img = function(config){
894 Roo.bootstrap.Img.superclass.constructor.call(this, config);
900 * The img click event for the img.
901 * @param {Roo.EventObject} e
907 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
915 getAutoCreate : function(){
919 cls: 'img-responsive',
923 cfg.html = this.html || cfg.html;
925 cfg.src = this.src || cfg.src;
927 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
928 cfg.cls += ' img-' + this.border;
945 a.target = this.target;
951 return (this.href) ? a : cfg;
954 initEvents: function() {
957 this.el.on('click', this.onClick, this);
961 onClick : function(e)
963 Roo.log('img onclick');
964 this.fireEvent('click', this, e);
977 * @class Roo.bootstrap.Header
978 * @extends Roo.bootstrap.Component
979 * Bootstrap Header class
980 * @cfg {String} html content of header
981 * @cfg {Number} level (1|2|3|4|5|6) default 1
984 * Create a new Header
985 * @param {Object} config The config object
989 Roo.bootstrap.Header = function(config){
990 Roo.bootstrap.Header.superclass.constructor.call(this, config);
993 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1001 getAutoCreate : function(){
1004 tag: 'h' + (1 *this.level),
1005 html: this.html || 'fill in html'
1023 * @class Roo.bootstrap.Menu
1024 * @extends Roo.bootstrap.Component
1025 * Bootstrap Menu class - container for MenuItems
1026 * @cfg {String} type type of menu
1030 * @param {Object} config The config object
1034 Roo.bootstrap.Menu = function(config){
1035 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1036 Roo.bootstrap.Menu.register(this);
1039 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1047 getChildContainer : function() {
1051 getAutoCreate : function(){
1053 //if (['right'].indexOf(this.align)!==-1) {
1054 // cfg.cn[1].cls += ' pull-right'
1058 cls : 'dropdown-menu'
1062 if (this.type==='submenu') {
1063 cfg.cls='submenu active'
1068 initEvents : function() {
1069 // Roo.log("ADD event");
1070 // Roo.log(this.triggerEl.dom);
1071 this.triggerEl.on('click', this.toggle, this);
1072 this.triggerEl.addClass('dropdown-toggle');
1075 toggle : function(e)
1077 //Roo.log(e.getTarget());
1078 // Roo.log(this.triggerEl.dom);
1079 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1082 var isActive = this.triggerEl.hasClass('open');
1083 // if disabled.. ingore
1084 this.hideMenuItems(e);
1085 //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
1086 // if mobile we use a backdrop because click events don't delegate
1087 // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
1090 //var relatedTarget = { relatedTarget: this }
1091 //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
1093 //if (e.isDefaultPrevented()) return;
1095 this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
1097 // .trigger('shown.bs.dropdown', relatedTarget)
1099 this.triggerEl.focus();
1109 hideMenuItems : function()
1111 //$(backdrop).remove()
1112 Roo.select('.dropdown-toggle',true).each(function(aa) {
1113 if (!aa.hasClass('open')) {
1117 aa.removeClass('open');
1118 //var parent = getParent($(this))
1119 //var relatedTarget = { relatedTarget: this }
1121 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1122 //if (e.isDefaultPrevented()) return
1123 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1130 Roo.apply(Roo.bootstrap.Menu, {
1134 register : function(menu)
1136 if (!this.menus.length) {
1137 Roo.get(document.body).on( 'click', Roo.bootstrap.Menu.onClick)
1140 this.menus.push(menu);
1144 onClick : function(e)
1149 show : function(menu) {
1168 * @class Roo.bootstrap.MenuItem
1169 * @extends Roo.bootstrap.Component
1170 * Bootstrap MenuItem class
1171 * @cfg {String} html the menu label
1172 * @cfg {String} href the link
1173 * @cfg {Boolean} preventDefault (true | false) default true
1177 * Create a new MenuItem
1178 * @param {Object} config The config object
1182 Roo.bootstrap.MenuItem = function(config){
1183 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1188 * The raw click event for the entire grid.
1189 * @param {Roo.EventObject} e
1195 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1199 preventDefault: true,
1201 getAutoCreate : function(){
1213 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1214 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1218 initEvents: function() {
1220 this.el.on('click', this.onClick, this);
1223 onClick : function(e)
1225 Roo.log('item on click ');
1226 if(this.preventDefault){
1229 this.parent().hideMenuItems();
1231 this.fireEvent('click', this, e);
1247 * @class Roo.bootstrap.MenuSeparator
1248 * @extends Roo.bootstrap.Component
1249 * Bootstrap MenuSeparator class
1252 * Create a new MenuItem
1253 * @param {Object} config The config object
1257 Roo.bootstrap.MenuSeparator = function(config){
1258 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1261 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1263 getAutoCreate : function(){
1278 <div class="modal fade">
1279 <div class="modal-dialog">
1280 <div class="modal-content">
1281 <div class="modal-header">
1282 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1283 <h4 class="modal-title">Modal title</h4>
1285 <div class="modal-body">
1286 <p>One fine body…</p>
1288 <div class="modal-footer">
1289 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1290 <button type="button" class="btn btn-primary">Save changes</button>
1292 </div><!-- /.modal-content -->
1293 </div><!-- /.modal-dialog -->
1294 </div><!-- /.modal -->
1304 * @class Roo.bootstrap.Modal
1305 * @extends Roo.bootstrap.Component
1306 * Bootstrap Modal class
1307 * @cfg {String} title Title of dialog
1308 * @cfg {Array} buttons Array of buttons or standard button set..
1311 * Create a new Modal Dialog
1312 * @param {Object} config The config object
1315 Roo.bootstrap.Modal = function(config){
1316 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1321 * The raw btnclick event for the button
1322 * @param {Roo.EventObject} e
1328 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1330 title : 'test dialog',
1334 onRender : function(ct, position)
1336 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1339 var cfg = Roo.apply({}, this.getAutoCreate());
1342 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1344 //if (!cfg.name.length) {
1348 cfg.cls += ' ' + this.cls;
1351 cfg.style = this.style;
1353 this.el = Roo.get(document.body).createChild(cfg, position);
1355 //var type = this.el.dom.type;
1357 if(this.tabIndex !== undefined){
1358 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1363 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1364 this.maskEl.enableDisplayMode("block");
1366 //this.el.addClass("x-dlg-modal");
1369 Roo.each(this.buttons, function(bb) {
1370 b = Roo.apply({}, bb);
1371 b.xns = b.xns || Roo.bootstrap;
1372 b.xtype = b.xtype || 'Button';
1373 if (typeof(b.listeners) == 'undefined') {
1374 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1377 var btn = Roo.factory(b);
1379 btn.onRender(this.el.select('.modal-footer').first());
1383 // render the children.
1386 if(typeof(this.items) != 'undefined'){
1387 var items = this.items;
1390 for(var i =0;i < items.length;i++) {
1391 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1395 this.items = nitems;
1397 //this.el.addClass([this.fieldClass, this.cls]);
1400 getAutoCreate : function(){
1405 html : this.html || ''
1413 cls: "modal-dialog",
1416 cls : "modal-content",
1419 cls : 'modal-header',
1428 cls : 'modal-title',
1436 cls : 'modal-footer'
1452 getChildContainer : function() {
1454 return this.el.select('.modal-body',true).first();
1457 getButtonContainer : function() {
1458 return this.el.select('.modal-footer',true).first();
1461 initEvents : function()
1463 this.el.select('.modal-header .close').on('click', this.hide, this);
1465 // this.addxtype(this);
1469 if (!this.rendered) {
1473 this.el.addClass('on');
1474 this.el.removeClass('fade');
1475 this.el.setStyle('display', 'block');
1476 Roo.get(document.body).addClass("x-body-masked");
1477 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1479 this.el.setStyle('zIndex', '10001');
1480 this.fireEvent('show', this);
1486 Roo.log('Modal hide?!');
1488 Roo.get(document.body).removeClass("x-body-masked");
1489 this.el.removeClass('on');
1490 this.el.addClass('fade');
1491 this.el.setStyle('display', 'none');
1492 this.fireEvent('hide', this);
1494 onButtonClick: function(btn,e)
1497 this.fireEvent('btnclick', btn.name, e);
1502 Roo.apply(Roo.bootstrap.Modal, {
1504 * Button config that displays a single OK button
1513 * Button config that displays Yes and No buttons
1529 * Button config that displays OK and Cancel buttons
1544 * Button config that displays Yes, No and Cancel buttons
1571 * @class Roo.bootstrap.Navbar
1572 * @extends Roo.bootstrap.Component
1573 * Bootstrap Navbar class
1574 * @cfg {Boolean} sidebar has side bar
1575 * @cfg {Boolean} bar is a bar?
1576 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1577 * @cfg {String} brand what is brand
1578 * @cfg {Boolean} inverse is inverted color
1579 * @cfg {String} type (nav | pills | tabs)
1580 * @cfg {Boolean} arrangement stacked | justified
1581 * @cfg {String} align (left | right) alignment
1582 * @cfg {String} brand_href href of the brand
1583 * @cfg {Boolean} main (true|false) main nav bar? default false
1587 * Create a new Navbar
1588 * @param {Object} config The config object
1592 Roo.bootstrap.Navbar = function(config){
1593 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1596 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
1610 getAutoCreate : function(){
1615 if (this.sidebar === true) {
1623 if (this.bar === true) {
1631 cls: 'navbar-header',
1636 cls: 'navbar-toggle',
1637 'data-toggle': 'collapse',
1642 html: 'Toggle navigation'
1662 cls: 'collapse navbar-collapse'
1667 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1669 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1670 cfg.cls += ' navbar-' + this.position;
1671 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
1674 if (this.brand !== '') {
1677 href: this.brand_href ? this.brand_href : '#',
1678 cls: 'navbar-brand',
1686 cfg.cls += ' main-nav';
1692 } else if (this.bar === false) {
1695 Roo.log('Property \'bar\' in of Navbar must be either true or false')
1705 if (['tabs','pills'].indexOf(this.type)!==-1) {
1706 cfg.cn[0].cls += ' nav-' + this.type
1708 if (this.type!=='nav') {
1709 Roo.log('nav type must be nav/tabs/pills')
1711 cfg.cn[0].cls += ' navbar-nav'
1714 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1715 cfg.cn[0].cls += ' nav-' + this.arrangement;
1718 if (this.align === 'right') {
1719 cfg.cn[0].cls += ' navbar-right';
1722 cfg.cls += ' navbar-inverse';
1730 initEvents :function ()
1732 //Roo.log(this.el.select('.navbar-toggle',true));
1733 this.el.select('.navbar-toggle',true).on('click', function() {
1734 // Roo.log('click');
1735 this.el.select('.navbar-collapse',true).toggleClass('in');
1740 getChildContainer : function()
1742 if (this.bar === true) {
1743 return this.el.select('.collapse',true).first();
1761 * @class Roo.bootstrap.NavGroup
1762 * @extends Roo.bootstrap.Component
1763 * Bootstrap NavGroup class
1764 * @cfg {String} align left | right
1765 * @cfg {Boolean} inverse false | true
1766 * @cfg {String} type (nav|pills|tab) default nav
1769 * Create a new nav group
1770 * @param {Object} config The config object
1773 Roo.bootstrap.NavGroup = function(config){
1774 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1777 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
1784 getAutoCreate : function(){
1785 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1792 if (['tabs','pills'].indexOf(this.type)!==-1) {
1793 cfg.cls += ' nav-' + this.type
1795 if (this.type!=='nav') {
1796 Roo.log('nav type must be nav/tabs/pills')
1798 cfg.cls += ' navbar-nav'
1801 if (this.parent().sidebar === true) {
1804 cls: 'dashboard-menu'
1810 if (this.form === true) {
1816 if (this.align === 'right') {
1817 cfg.cls += ' navbar-right';
1819 cfg.cls += ' navbar-left';
1823 if (this.align === 'right') {
1824 cfg.cls += ' navbar-right';
1828 cfg.cls += ' navbar-inverse';
1848 * @class Roo.bootstrap.Navbar.Item
1849 * @extends Roo.bootstrap.Component
1850 * Bootstrap Navbar.Button class
1851 * @cfg {String} href link to
1852 * @cfg {String} html content of button
1853 * @cfg {String} badge text inside badge
1854 * @cfg {String} glyphicon name of glyphicon
1855 * @cfg {String} icon name of font awesome icon
1856 * @cfg {Boolena} active Is item active
1857 * @cfg {Boolean} preventDefault (true | false) default false
1860 * Create a new Navbar Button
1861 * @param {Object} config The config object
1863 Roo.bootstrap.Navbar.Item = function(config){
1864 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1869 * The raw click event for the entire grid.
1870 * @param {Roo.EventObject} e
1876 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
1885 preventDefault : false,
1887 getAutoCreate : function(){
1889 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1891 if (this.parent().parent().sidebar === true) {
1904 cfg.cn[0].html = this.html;
1908 this.cls += ' active';
1912 cfg.cn[0].cls += ' dropdown-toggle';
1913 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1917 cfg.cn[0].tag = 'a',
1918 cfg.cn[0].href = this.href;
1921 if (this.glyphicon) {
1922 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1926 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1938 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
1948 if (this.glyphicon) {
1949 if(cfg.html){cfg.html = ' ' + this.html};
1953 cls: 'glyphicon glyphicon-' + this.glyphicon
1958 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1963 cfg.cn[0].html += " <span class='caret'></span>";
1964 //}else if (!this.href) {
1965 // cfg.cn[0].tag='p';
1966 // cfg.cn[0].cls='navbar-text';
1969 cfg.cn[0].href=this.href||'#';
1970 cfg.cn[0].html=this.html;
1973 if (this.badge !== '') {
1976 cfg.cn[0].html + ' ',
1987 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1992 initEvents: function() {
1993 // Roo.log('init events?');
1994 // Roo.log(this.el.dom);
1995 this.el.select('a',true).on('click', this.onClick, this);
1998 onClick : function(e)
2000 if(this.preventDefault){
2004 if(this.fireEvent('click', this, e) === false){
2008 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
2009 this.onTabsClick(e);
2013 onTabsClick : function(e)
2015 Roo.each(this.parent().el.select('.active',true).elements, function(v){
2016 v.removeClass('active');
2019 this.el.addClass('active');
2021 if(this.href && this.href.substring(0,1) == '#'){
2022 var tab = Roo.select('[tabId=' + this.href + ']', true).first();
2024 Roo.each(tab.findParent('.tab-content', 0, true).select('.active', true).elements, function(v){
2025 v.removeClass('active');
2028 tab.addClass('active');
2043 * @class Roo.bootstrap.Row
2044 * @extends Roo.bootstrap.Component
2045 * Bootstrap Row class (contains columns...)
2049 * @param {Object} config The config object
2052 Roo.bootstrap.Row = function(config){
2053 Roo.bootstrap.Row.superclass.constructor.call(this, config);
2056 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2058 getAutoCreate : function(){
2077 * @class Roo.bootstrap.Element
2078 * @extends Roo.bootstrap.Component
2079 * Bootstrap Element class
2080 * @cfg {String} html contents of the element
2081 * @cfg {String} tag tag of the element
2082 * @cfg {String} cls class of the element
2085 * Create a new Element
2086 * @param {Object} config The config object
2089 Roo.bootstrap.Element = function(config){
2090 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2093 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2100 getAutoCreate : function(){
2125 * @class Roo.bootstrap.Pagination
2126 * @extends Roo.bootstrap.Component
2127 * Bootstrap Pagination class
2128 * @cfg {String} size xs | sm | md | lg
2129 * @cfg {Boolean} inverse false | true
2132 * Create a new Pagination
2133 * @param {Object} config The config object
2136 Roo.bootstrap.Pagination = function(config){
2137 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2140 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2146 getAutoCreate : function(){
2152 cfg.cls += ' inverse';
2158 cfg.cls += " " + this.cls;
2176 * @class Roo.bootstrap.PaginationItem
2177 * @extends Roo.bootstrap.Component
2178 * Bootstrap PaginationItem class
2179 * @cfg {String} html text
2180 * @cfg {String} href the link
2181 * @cfg {Boolean} preventDefault (true | false) default true
2182 * @cfg {Boolean} active (true | false) default false
2186 * Create a new PaginationItem
2187 * @param {Object} config The config object
2191 Roo.bootstrap.PaginationItem = function(config){
2192 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2197 * The raw click event for the entire grid.
2198 * @param {Roo.EventObject} e
2204 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2208 preventDefault: true,
2212 getAutoCreate : function(){
2218 href : this.href ? this.href : '#',
2219 html : this.html ? this.html : ''
2229 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2235 initEvents: function() {
2237 this.el.on('click', this.onClick, this);
2240 onClick : function(e)
2242 Roo.log('PaginationItem on click ');
2243 if(this.preventDefault){
2247 this.fireEvent('click', this, e);
2263 * @class Roo.bootstrap.Slider
2264 * @extends Roo.bootstrap.Component
2265 * Bootstrap Slider class
2268 * Create a new Slider
2269 * @param {Object} config The config object
2272 Roo.bootstrap.Slider = function(config){
2273 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2276 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2278 getAutoCreate : function(){
2282 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2286 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2304 * @class Roo.bootstrap.Table
2305 * @extends Roo.bootstrap.Component
2306 * Bootstrap Table class
2307 * @cfg {String} cls table class
2308 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2309 * @cfg {String} bgcolor Specifies the background color for a table
2310 * @cfg {Number} border Specifies whether the table cells should have borders or not
2311 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2312 * @cfg {Number} cellspacing Specifies the space between cells
2313 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2314 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2315 * @cfg {String} sortable Specifies that the table should be sortable
2316 * @cfg {String} summary Specifies a summary of the content of a table
2317 * @cfg {Number} width Specifies the width of a table
2319 * @cfg {boolean} striped Should the rows be alternative striped
2320 * @cfg {boolean} bordered Add borders to the table
2321 * @cfg {boolean} hover Add hover highlighting
2322 * @cfg {boolean} condensed Format condensed
2323 * @cfg {boolean} responsive Format condensed
2329 * Create a new Table
2330 * @param {Object} config The config object
2333 Roo.bootstrap.Table = function(config){
2334 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2337 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2338 this.sm = this.selModel;
2339 this.sm.xmodule = this.xmodule || false;
2341 if (this.cm && typeof(this.cm.config) == 'undefined') {
2342 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2343 this.cm = this.colModel;
2344 this.cm.xmodule = this.xmodule || false;
2347 this.store= Roo.factory(this.store, Roo.data);
2348 this.ds = this.store;
2349 this.ds.xmodule = this.xmodule || false;
2354 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2376 getAutoCreate : function(){
2377 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2386 cfg.cls += ' table-striped';
2389 cfg.cls += ' table-hover';
2391 if (this.bordered) {
2392 cfg.cls += ' table-bordered';
2394 if (this.condensed) {
2395 cfg.cls += ' table-condensed';
2397 if (this.responsive) {
2398 cfg.cls += ' table-responsive';
2405 cfg.cls+= ' ' +this.cls;
2408 // this lot should be simplifed...
2411 cfg.align=this.align;
2414 cfg.bgcolor=this.bgcolor;
2417 cfg.border=this.border;
2419 if (this.cellpadding) {
2420 cfg.cellpadding=this.cellpadding;
2422 if (this.cellspacing) {
2423 cfg.cellspacing=this.cellspacing;
2426 cfg.frame=this.frame;
2429 cfg.rules=this.rules;
2431 if (this.sortable) {
2432 cfg.sortable=this.sortable;
2435 cfg.summary=this.summary;
2438 cfg.width=this.width;
2441 if(this.store || this.cm){
2442 cfg.cn.push(this.renderHeader());
2443 cfg.cn.push(this.renderBody());
2444 cfg.cn.push(this.renderFooter());
2446 cfg.cls+= ' TableGrid';
2452 // initTableGrid : function()
2461 // var cm = this.cm;
2463 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2466 // html: cm.getColumnHeader(i)
2470 // cfg.push(header);
2477 initEvents : function()
2479 if(!this.store || !this.cm){
2483 Roo.log('initEvents with ds!!!!');
2485 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
2486 // this.maskEl.enableDisplayMode("block");
2487 // this.maskEl.show();
2489 this.store.on('load', this.onLoad, this);
2490 this.store.on('beforeload', this.onBeforeLoad, this);
2498 renderHeader : function()
2507 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2510 html: cm.getColumnHeader(i)
2517 renderBody : function()
2527 renderFooter : function()
2539 Roo.log('ds onload');
2543 var tbody = this.el.select('tbody', true).first();
2547 if(this.store.getCount() > 0){
2548 this.store.data.each(function(d){
2554 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2555 var renderer = cm.getRenderer(i);
2559 if(typeof(renderer) !== 'undefined'){
2560 value = renderer(d.data[cm.getDataIndex(i)], false, d);
2563 if(typeof(value) === 'object'){
2573 html: (typeof(value) === 'object') ? '' : value
2578 tbody.createChild(row);
2584 Roo.each(renders, function(r){
2585 r.cfg.render(Roo.get(r.id));
2589 // if(this.loadMask){
2590 // this.maskEl.hide();
2594 onBeforeLoad : function()
2596 Roo.log('ds onBeforeLoad');
2600 // if(this.loadMask){
2601 // this.maskEl.show();
2607 this.el.select('tbody', true).first().dom.innerHTML = '';
2610 getSelectionModel : function(){
2612 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
2614 return this.selModel;
2629 * @class Roo.bootstrap.TableCell
2630 * @extends Roo.bootstrap.Component
2631 * Bootstrap TableCell class
2632 * @cfg {String} html cell contain text
2633 * @cfg {String} cls cell class
2634 * @cfg {String} tag cell tag (td|th) default td
2635 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
2636 * @cfg {String} align Aligns the content in a cell
2637 * @cfg {String} axis Categorizes cells
2638 * @cfg {String} bgcolor Specifies the background color of a cell
2639 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2640 * @cfg {Number} colspan Specifies the number of columns a cell should span
2641 * @cfg {String} headers Specifies one or more header cells a cell is related to
2642 * @cfg {Number} height Sets the height of a cell
2643 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
2644 * @cfg {Number} rowspan Sets the number of rows a cell should span
2645 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
2646 * @cfg {String} valign Vertical aligns the content in a cell
2647 * @cfg {Number} width Specifies the width of a cell
2650 * Create a new TableCell
2651 * @param {Object} config The config object
2654 Roo.bootstrap.TableCell = function(config){
2655 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2658 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
2678 getAutoCreate : function(){
2679 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2699 cfg.align=this.align
2705 cfg.bgcolor=this.bgcolor
2708 cfg.charoff=this.charoff
2711 cfg.colspan=this.colspan
2714 cfg.headers=this.headers
2717 cfg.height=this.height
2720 cfg.nowrap=this.nowrap
2723 cfg.rowspan=this.rowspan
2726 cfg.scope=this.scope
2729 cfg.valign=this.valign
2732 cfg.width=this.width
2751 * @class Roo.bootstrap.TableRow
2752 * @extends Roo.bootstrap.Component
2753 * Bootstrap TableRow class
2754 * @cfg {String} cls row class
2755 * @cfg {String} align Aligns the content in a table row
2756 * @cfg {String} bgcolor Specifies a background color for a table row
2757 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
2758 * @cfg {String} valign Vertical aligns the content in a table row
2761 * Create a new TableRow
2762 * @param {Object} config The config object
2765 Roo.bootstrap.TableRow = function(config){
2766 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2769 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
2777 getAutoCreate : function(){
2778 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2788 cfg.align = this.align;
2791 cfg.bgcolor = this.bgcolor;
2794 cfg.charoff = this.charoff;
2797 cfg.valign = this.valign;
2815 * @class Roo.bootstrap.TableBody
2816 * @extends Roo.bootstrap.Component
2817 * Bootstrap TableBody class
2818 * @cfg {String} cls element class
2819 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
2820 * @cfg {String} align Aligns the content inside the element
2821 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
2822 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
2825 * Create a new TableBody
2826 * @param {Object} config The config object
2829 Roo.bootstrap.TableBody = function(config){
2830 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
2833 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
2841 getAutoCreate : function(){
2842 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
2856 cfg.align = this.align;
2859 cfg.charoff = this.charoff;
2862 cfg.valign = this.valign;
2869 // initEvents : function()
2876 // this.store = Roo.factory(this.store, Roo.data);
2877 // this.store.on('load', this.onLoad, this);
2879 // this.store.load();
2883 // onLoad: function ()
2885 // this.fireEvent('load', this);
2895 * Ext JS Library 1.1.1
2896 * Copyright(c) 2006-2007, Ext JS, LLC.
2898 * Originally Released Under LGPL - original licence link has changed is not relivant.
2901 * <script type="text/javascript">
2904 // as we use this in bootstrap.
2905 Roo.namespace('Roo.form');
2907 * @class Roo.form.Action
2908 * Internal Class used to handle form actions
2910 * @param {Roo.form.BasicForm} el The form element or its id
2911 * @param {Object} config Configuration options
2916 // define the action interface
2917 Roo.form.Action = function(form, options){
2919 this.options = options || {};
2922 * Client Validation Failed
2925 Roo.form.Action.CLIENT_INVALID = 'client';
2927 * Server Validation Failed
2930 Roo.form.Action.SERVER_INVALID = 'server';
2932 * Connect to Server Failed
2935 Roo.form.Action.CONNECT_FAILURE = 'connect';
2937 * Reading Data from Server Failed
2940 Roo.form.Action.LOAD_FAILURE = 'load';
2942 Roo.form.Action.prototype = {
2944 failureType : undefined,
2945 response : undefined,
2949 run : function(options){
2954 success : function(response){
2959 handleResponse : function(response){
2963 // default connection failure
2964 failure : function(response){
2966 this.response = response;
2967 this.failureType = Roo.form.Action.CONNECT_FAILURE;
2968 this.form.afterAction(this, false);
2971 processResponse : function(response){
2972 this.response = response;
2973 if(!response.responseText){
2976 this.result = this.handleResponse(response);
2980 // utility functions used internally
2981 getUrl : function(appendParams){
2982 var url = this.options.url || this.form.url || this.form.el.dom.action;
2984 var p = this.getParams();
2986 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2992 getMethod : function(){
2993 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2996 getParams : function(){
2997 var bp = this.form.baseParams;
2998 var p = this.options.params;
3000 if(typeof p == "object"){
3001 p = Roo.urlEncode(Roo.applyIf(p, bp));
3002 }else if(typeof p == 'string' && bp){
3003 p += '&' + Roo.urlEncode(bp);
3006 p = Roo.urlEncode(bp);
3011 createCallback : function(){
3013 success: this.success,
3014 failure: this.failure,
3016 timeout: (this.form.timeout*1000),
3017 upload: this.form.fileUpload ? this.success : undefined
3022 Roo.form.Action.Submit = function(form, options){
3023 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
3026 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
3029 haveProgress : false,
3030 uploadComplete : false,
3032 // uploadProgress indicator.
3033 uploadProgress : function()
3035 if (!this.form.progressUrl) {
3039 if (!this.haveProgress) {
3040 Roo.MessageBox.progress("Uploading", "Uploading");
3042 if (this.uploadComplete) {
3043 Roo.MessageBox.hide();
3047 this.haveProgress = true;
3049 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
3051 var c = new Roo.data.Connection();
3053 url : this.form.progressUrl,
3058 success : function(req){
3059 //console.log(data);
3063 rdata = Roo.decode(req.responseText)
3065 Roo.log("Invalid data from server..");
3069 if (!rdata || !rdata.success) {
3071 Roo.MessageBox.alert(Roo.encode(rdata));
3074 var data = rdata.data;
3076 if (this.uploadComplete) {
3077 Roo.MessageBox.hide();
3082 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3083 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3086 this.uploadProgress.defer(2000,this);
3089 failure: function(data) {
3090 Roo.log('progress url failed ');
3101 // run get Values on the form, so it syncs any secondary forms.
3102 this.form.getValues();
3104 var o = this.options;
3105 var method = this.getMethod();
3106 var isPost = method == 'POST';
3107 if(o.clientValidation === false || this.form.isValid()){
3109 if (this.form.progressUrl) {
3110 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3111 (new Date() * 1) + '' + Math.random());
3116 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3117 form:this.form.el.dom,
3118 url:this.getUrl(!isPost),
3120 params:isPost ? this.getParams() : null,
3121 isUpload: this.form.fileUpload
3124 this.uploadProgress();
3126 }else if (o.clientValidation !== false){ // client validation failed
3127 this.failureType = Roo.form.Action.CLIENT_INVALID;
3128 this.form.afterAction(this, false);
3132 success : function(response)
3134 this.uploadComplete= true;
3135 if (this.haveProgress) {
3136 Roo.MessageBox.hide();
3140 var result = this.processResponse(response);
3141 if(result === true || result.success){
3142 this.form.afterAction(this, true);
3146 this.form.markInvalid(result.errors);
3147 this.failureType = Roo.form.Action.SERVER_INVALID;
3149 this.form.afterAction(this, false);
3151 failure : function(response)
3153 this.uploadComplete= true;
3154 if (this.haveProgress) {
3155 Roo.MessageBox.hide();
3158 this.response = response;
3159 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3160 this.form.afterAction(this, false);
3163 handleResponse : function(response){
3164 if(this.form.errorReader){
3165 var rs = this.form.errorReader.read(response);
3168 for(var i = 0, len = rs.records.length; i < len; i++) {
3169 var r = rs.records[i];
3173 if(errors.length < 1){
3177 success : rs.success,
3183 ret = Roo.decode(response.responseText);
3187 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3197 Roo.form.Action.Load = function(form, options){
3198 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3199 this.reader = this.form.reader;
3202 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3207 Roo.Ajax.request(Roo.apply(
3208 this.createCallback(), {
3209 method:this.getMethod(),
3210 url:this.getUrl(false),
3211 params:this.getParams()
3215 success : function(response){
3217 var result = this.processResponse(response);
3218 if(result === true || !result.success || !result.data){
3219 this.failureType = Roo.form.Action.LOAD_FAILURE;
3220 this.form.afterAction(this, false);
3223 this.form.clearInvalid();
3224 this.form.setValues(result.data);
3225 this.form.afterAction(this, true);
3228 handleResponse : function(response){
3229 if(this.form.reader){
3230 var rs = this.form.reader.read(response);
3231 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3233 success : rs.success,
3237 return Roo.decode(response.responseText);
3241 Roo.form.Action.ACTION_TYPES = {
3242 'load' : Roo.form.Action.Load,
3243 'submit' : Roo.form.Action.Submit
3252 * @class Roo.bootstrap.Form
3253 * @extends Roo.bootstrap.Component
3254 * Bootstrap Form class
3255 * @cfg {String} method GET | POST (default POST)
3256 * @cfg {String} labelAlign top | left (default top)
3257 * @cfg {String} align left | right - for navbars
3262 * @param {Object} config The config object
3266 Roo.bootstrap.Form = function(config){
3267 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3270 * @event clientvalidation
3271 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3272 * @param {Form} this
3273 * @param {Boolean} valid true if the form has passed client-side validation
3275 clientvalidation: true,
3277 * @event beforeaction
3278 * Fires before any action is performed. Return false to cancel the action.
3279 * @param {Form} this
3280 * @param {Action} action The action to be performed
3284 * @event actionfailed
3285 * Fires when an action fails.
3286 * @param {Form} this
3287 * @param {Action} action The action that failed
3289 actionfailed : true,
3291 * @event actioncomplete
3292 * Fires when an action is completed.
3293 * @param {Form} this
3294 * @param {Action} action The action that completed
3296 actioncomplete : true
3301 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3304 * @cfg {String} method
3305 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3310 * The URL to use for form actions if one isn't supplied in the action options.
3313 * @cfg {Boolean} fileUpload
3314 * Set to true if this form is a file upload.
3318 * @cfg {Object} baseParams
3319 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3323 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3327 * @cfg {Sting} align (left|right) for navbar forms
3332 activeAction : null,
3335 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3336 * element by passing it or its id or mask the form itself by passing in true.
3339 waitMsgTarget : false,
3344 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3345 * element by passing it or its id or mask the form itself by passing in true.
3349 getAutoCreate : function(){
3353 method : this.method || 'POST',
3354 id : this.id || Roo.id(),
3357 if (this.parent().xtype.match(/^Nav/)) {
3358 cfg.cls = 'navbar-form navbar-' + this.align;
3362 if (this.labelAlign == 'left' ) {
3363 cfg.cls += ' form-horizontal';
3369 initEvents : function()
3371 this.el.on('submit', this.onSubmit, this);
3376 onSubmit : function(e){
3381 * Returns true if client-side validation on the form is successful.
3384 isValid : function(){
3385 var items = this.getItems();
3387 items.each(function(f){
3396 * Returns true if any fields in this form have changed since their original load.
3399 isDirty : function(){
3401 var items = this.getItems();
3402 items.each(function(f){
3412 * Performs a predefined action (submit or load) or custom actions you define on this form.
3413 * @param {String} actionName The name of the action type
3414 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3415 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3416 * accept other config options):
3418 Property Type Description
3419 ---------------- --------------- ----------------------------------------------------------------------------------
3420 url String The url for the action (defaults to the form's url)
3421 method String The form method to use (defaults to the form's method, or POST if not defined)
3422 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3423 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3424 validate the form on the client (defaults to false)
3426 * @return {BasicForm} this
3428 doAction : function(action, options){
3429 if(typeof action == 'string'){
3430 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3432 if(this.fireEvent('beforeaction', this, action) !== false){
3433 this.beforeAction(action);
3434 action.run.defer(100, action);
3440 beforeAction : function(action){
3441 var o = action.options;
3443 // not really supported yet.. ??
3445 //if(this.waitMsgTarget === true){
3446 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3447 //}else if(this.waitMsgTarget){
3448 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3449 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3451 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3457 afterAction : function(action, success){
3458 this.activeAction = null;
3459 var o = action.options;
3461 //if(this.waitMsgTarget === true){
3463 //}else if(this.waitMsgTarget){
3464 // this.waitMsgTarget.unmask();
3466 // Roo.MessageBox.updateProgress(1);
3467 // Roo.MessageBox.hide();
3474 Roo.callback(o.success, o.scope, [this, action]);
3475 this.fireEvent('actioncomplete', this, action);
3479 // failure condition..
3480 // we have a scenario where updates need confirming.
3481 // eg. if a locking scenario exists..
3482 // we look for { errors : { needs_confirm : true }} in the response.
3484 (typeof(action.result) != 'undefined') &&
3485 (typeof(action.result.errors) != 'undefined') &&
3486 (typeof(action.result.errors.needs_confirm) != 'undefined')
3489 Roo.log("not supported yet");
3492 Roo.MessageBox.confirm(
3493 "Change requires confirmation",
3494 action.result.errorMsg,
3499 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3509 Roo.callback(o.failure, o.scope, [this, action]);
3510 // show an error message if no failed handler is set..
3511 if (!this.hasListener('actionfailed')) {
3512 Roo.log("need to add dialog support");
3514 Roo.MessageBox.alert("Error",
3515 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3516 action.result.errorMsg :
3517 "Saving Failed, please check your entries or try again"
3522 this.fireEvent('actionfailed', this, action);
3527 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3528 * @param {String} id The value to search for
3531 findField : function(id){
3532 var items = this.getItems();
3533 var field = items.get(id);
3535 items.each(function(f){
3536 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3543 return field || null;
3546 * Mark fields in this form invalid in bulk.
3547 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3548 * @return {BasicForm} this
3550 markInvalid : function(errors){
3551 if(errors instanceof Array){
3552 for(var i = 0, len = errors.length; i < len; i++){
3553 var fieldError = errors[i];
3554 var f = this.findField(fieldError.id);
3556 f.markInvalid(fieldError.msg);
3562 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3563 field.markInvalid(errors[id]);
3567 //Roo.each(this.childForms || [], function (f) {
3568 // f.markInvalid(errors);
3575 * Set values for fields in this form in bulk.
3576 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
3577 * @return {BasicForm} this
3579 setValues : function(values){
3580 if(values instanceof Array){ // array of objects
3581 for(var i = 0, len = values.length; i < len; i++){
3583 var f = this.findField(v.id);
3585 f.setValue(v.value);
3586 if(this.trackResetOnLoad){
3587 f.originalValue = f.getValue();
3591 }else{ // object hash
3594 if(typeof values[id] != 'function' && (field = this.findField(id))){
3596 if (field.setFromData &&
3598 field.displayField &&
3599 // combos' with local stores can
3600 // be queried via setValue()
3601 // to set their value..
3602 (field.store && !field.store.isLocal)
3606 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
3607 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
3608 field.setFromData(sd);
3611 field.setValue(values[id]);
3615 if(this.trackResetOnLoad){
3616 field.originalValue = field.getValue();
3622 //Roo.each(this.childForms || [], function (f) {
3623 // f.setValues(values);
3630 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
3631 * they are returned as an array.
3632 * @param {Boolean} asString
3635 getValues : function(asString){
3636 //if (this.childForms) {
3637 // copy values from the child forms
3638 // Roo.each(this.childForms, function (f) {
3639 // this.setValues(f.getValues());
3645 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
3646 if(asString === true){
3649 return Roo.urlDecode(fs);
3653 * Returns the fields in this form as an object with key/value pairs.
3654 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
3657 getFieldValues : function(with_hidden)
3659 var items = this.getItems();
3661 items.each(function(f){
3665 var v = f.getValue();
3666 if (f.inputType =='radio') {
3667 if (typeof(ret[f.getName()]) == 'undefined') {
3668 ret[f.getName()] = ''; // empty..
3671 if (!f.el.dom.checked) {
3679 // not sure if this supported any more..
3680 if ((typeof(v) == 'object') && f.getRawValue) {
3681 v = f.getRawValue() ; // dates..
3683 // combo boxes where name != hiddenName...
3684 if (f.name != f.getName()) {
3685 ret[f.name] = f.getRawValue();
3687 ret[f.getName()] = v;
3694 * Clears all invalid messages in this form.
3695 * @return {BasicForm} this
3697 clearInvalid : function(){
3698 var items = this.getItems();
3700 items.each(function(f){
3711 * @return {BasicForm} this
3714 var items = this.getItems();
3715 items.each(function(f){
3719 Roo.each(this.childForms || [], function (f) {
3726 getItems : function()
3728 var r=new Roo.util.MixedCollection(false, function(o){
3729 return o.id || (o.id = Roo.id());
3731 var iter = function(el) {
3738 Roo.each(el.items,function(e) {
3757 * Ext JS Library 1.1.1
3758 * Copyright(c) 2006-2007, Ext JS, LLC.
3760 * Originally Released Under LGPL - original licence link has changed is not relivant.
3763 * <script type="text/javascript">
3766 * @class Roo.form.VTypes
3767 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
3770 Roo.form.VTypes = function(){
3771 // closure these in so they are only created once.
3772 var alpha = /^[a-zA-Z_]+$/;
3773 var alphanum = /^[a-zA-Z0-9_]+$/;
3774 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
3775 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
3777 // All these messages and functions are configurable
3780 * The function used to validate email addresses
3781 * @param {String} value The email address
3783 'email' : function(v){
3784 return email.test(v);
3787 * The error text to display when the email validation function returns false
3790 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
3792 * The keystroke filter mask to be applied on email input
3795 'emailMask' : /[a-z0-9_\.\-@]/i,
3798 * The function used to validate URLs
3799 * @param {String} value The URL
3801 'url' : function(v){
3805 * The error text to display when the url validation function returns false
3808 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
3811 * The function used to validate alpha values
3812 * @param {String} value The value
3814 'alpha' : function(v){
3815 return alpha.test(v);
3818 * The error text to display when the alpha validation function returns false
3821 'alphaText' : 'This field should only contain letters and _',
3823 * The keystroke filter mask to be applied on alpha input
3826 'alphaMask' : /[a-z_]/i,
3829 * The function used to validate alphanumeric values
3830 * @param {String} value The value
3832 'alphanum' : function(v){
3833 return alphanum.test(v);
3836 * The error text to display when the alphanumeric validation function returns false
3839 'alphanumText' : 'This field should only contain letters, numbers and _',
3841 * The keystroke filter mask to be applied on alphanumeric input
3844 'alphanumMask' : /[a-z0-9_]/i
3854 * @class Roo.bootstrap.Input
3855 * @extends Roo.bootstrap.Component
3856 * Bootstrap Input class
3857 * @cfg {Boolean} disabled is it disabled
3858 * @cfg {String} fieldLabel - the label associated
3859 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3860 * @cfg {String} name name of the input
3861 * @cfg {string} fieldLabel - the label associated
3862 * @cfg {string} inputType - input / file submit ...
3863 * @cfg {string} placeholder - placeholder to put in text.
3864 * @cfg {string} before - input group add on before
3865 * @cfg {string} after - input group add on after
3866 * @cfg {string} size - (lg|sm) or leave empty..
3867 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3868 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3869 * @cfg {Number} md colspan out of 12 for computer-sized screens
3870 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3871 * @cfg {string} value default value of the input
3872 * @cfg {Number} labelWidth set the width of label (0-12)
3873 * @cfg {String} labelAlign (top|left)
3877 * Create a new Input
3878 * @param {Object} config The config object
3881 Roo.bootstrap.Input = function(config){
3882 Roo.bootstrap.Input.superclass.constructor.call(this, config);
3887 * Fires when this field receives input focus.
3888 * @param {Roo.form.Field} this
3893 * Fires when this field loses input focus.
3894 * @param {Roo.form.Field} this
3899 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
3900 * {@link Roo.EventObject#getKey} to determine which key was pressed.
3901 * @param {Roo.form.Field} this
3902 * @param {Roo.EventObject} e The event object
3907 * Fires just before the field blurs if the field value has changed.
3908 * @param {Roo.form.Field} this
3909 * @param {Mixed} newValue The new value
3910 * @param {Mixed} oldValue The original value
3915 * Fires after the field has been marked as invalid.
3916 * @param {Roo.form.Field} this
3917 * @param {String} msg The validation message
3922 * Fires after the field has been validated with no errors.
3923 * @param {Roo.form.Field} this
3928 * Fires after the key up
3929 * @param {Roo.form.Field} this
3930 * @param {Roo.EventObject} e The event Object
3936 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
3938 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3939 automatic validation (defaults to "keyup").
3941 validationEvent : "keyup",
3943 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3945 validateOnBlur : true,
3947 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3949 validationDelay : 250,
3951 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3953 focusClass : "x-form-focus", // not needed???
3957 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3959 invalidClass : "has-error",
3962 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3964 selectOnFocus : false,
3967 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3971 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3976 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3978 disableKeyFilter : false,
3981 * @cfg {Boolean} disabled True to disable the field (defaults to false).
3985 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3989 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3991 blankText : "This field is required",
3994 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3998 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
4000 maxLength : Number.MAX_VALUE,
4002 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
4004 minLengthText : "The minimum length for this field is {0}",
4006 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
4008 maxLengthText : "The maximum length for this field is {0}",
4012 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
4013 * If available, this function will be called only after the basic validators all return true, and will be passed the
4014 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
4018 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
4019 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
4020 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
4024 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
4046 parentLabelAlign : function()
4049 while (parent.parent()) {
4050 parent = parent.parent();
4051 if (typeof(parent.labelAlign) !='undefined') {
4052 return parent.labelAlign;
4059 getAutoCreate : function(){
4061 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4067 if(this.inputType != 'hidden'){
4068 cfg.cls = 'form-group' //input-group
4074 type : this.inputType,
4076 cls : 'form-control',
4077 placeholder : this.placeholder || ''
4081 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4082 input.maxLength = this.maxLength;
4085 if (this.disabled) {
4086 input.disabled=true;
4090 input.name = this.name;
4093 input.cls += ' input-' + this.size;
4096 ['xs','sm','md','lg'].map(function(size){
4097 if (settings[size]) {
4098 cfg.cls += ' col-' + size + '-' + settings[size];
4102 var inputblock = input;
4104 if (this.before || this.after) {
4107 cls : 'input-group',
4111 inputblock.cn.push({
4113 cls : 'input-group-addon',
4117 inputblock.cn.push(input);
4119 inputblock.cn.push({
4121 cls : 'input-group-addon',
4128 if (align ==='left' && this.fieldLabel.length) {
4129 Roo.log("left and has label");
4135 cls : 'control-label col-sm-' + this.labelWidth,
4136 html : this.fieldLabel
4140 cls : "col-sm-" + (12 - this.labelWidth),
4147 } else if ( this.fieldLabel.length) {
4153 //cls : 'input-group-addon',
4154 html : this.fieldLabel
4164 Roo.log(" no label && no align");
4173 Roo.log('input-parentType: ' + this.parentType);
4175 if (this.parentType === 'Navbar' && this.parent().bar) {
4176 cfg.cls += ' navbar-form';
4184 * return the real input element.
4186 inputEl: function ()
4188 return this.el.select('input.form-control',true).first();
4190 setDisabled : function(v)
4192 var i = this.inputEl().dom;
4194 i.removeAttribute('disabled');
4198 i.setAttribute('disabled','true');
4200 initEvents : function()
4203 this.inputEl().on("keydown" , this.fireKey, this);
4204 this.inputEl().on("focus", this.onFocus, this);
4205 this.inputEl().on("blur", this.onBlur, this);
4207 this.inputEl().relayEvent('keyup', this);
4209 // reference to original value for reset
4210 this.originalValue = this.getValue();
4211 //Roo.form.TextField.superclass.initEvents.call(this);
4212 if(this.validationEvent == 'keyup'){
4213 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4214 this.inputEl().on('keyup', this.filterValidation, this);
4216 else if(this.validationEvent !== false){
4217 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4220 if(this.selectOnFocus){
4221 this.on("focus", this.preFocus, this);
4224 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4225 this.inputEl().on("keypress", this.filterKeys, this);
4228 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4229 this.el.on("click", this.autoSize, this);
4232 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4233 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4237 filterValidation : function(e){
4238 if(!e.isNavKeyPress()){
4239 this.validationTask.delay(this.validationDelay);
4243 * Validates the field value
4244 * @return {Boolean} True if the value is valid, else false
4246 validate : function(){
4247 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4248 if(this.disabled || this.validateValue(this.getRawValue())){
4249 this.clearInvalid();
4257 * Validates a value according to the field's validation rules and marks the field as invalid
4258 * if the validation fails
4259 * @param {Mixed} value The value to validate
4260 * @return {Boolean} True if the value is valid, else false
4262 validateValue : function(value){
4263 if(value.length < 1) { // if it's blank
4264 if(this.allowBlank){
4265 this.clearInvalid();
4268 this.markInvalid(this.blankText);
4272 if(value.length < this.minLength){
4273 this.markInvalid(String.format(this.minLengthText, this.minLength));
4276 if(value.length > this.maxLength){
4277 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4281 var vt = Roo.form.VTypes;
4282 if(!vt[this.vtype](value, this)){
4283 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4287 if(typeof this.validator == "function"){
4288 var msg = this.validator(value);
4290 this.markInvalid(msg);
4294 if(this.regex && !this.regex.test(value)){
4295 this.markInvalid(this.regexText);
4304 fireKey : function(e){
4305 //Roo.log('field ' + e.getKey());
4306 if(e.isNavKeyPress()){
4307 this.fireEvent("specialkey", this, e);
4310 focus : function (selectText){
4312 this.inputEl().focus();
4313 if(selectText === true){
4314 this.inputEl().dom.select();
4320 onFocus : function(){
4321 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4322 // this.el.addClass(this.focusClass);
4325 this.hasFocus = true;
4326 this.startValue = this.getValue();
4327 this.fireEvent("focus", this);
4331 beforeBlur : Roo.emptyFn,
4335 onBlur : function(){
4337 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4338 //this.el.removeClass(this.focusClass);
4340 this.hasFocus = false;
4341 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4344 var v = this.getValue();
4345 if(String(v) !== String(this.startValue)){
4346 this.fireEvent('change', this, v, this.startValue);
4348 this.fireEvent("blur", this);
4352 * Resets the current field value to the originally loaded value and clears any validation messages
4355 this.setValue(this.originalValue);
4356 this.clearInvalid();
4359 * Returns the name of the field
4360 * @return {Mixed} name The name field
4362 getName: function(){
4366 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4367 * @return {Mixed} value The field value
4369 getValue : function(){
4370 return this.inputEl().getValue();
4373 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4374 * @return {Mixed} value The field value
4376 getRawValue : function(){
4377 var v = this.inputEl().getValue();
4383 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4384 * @param {Mixed} value The value to set
4386 setRawValue : function(v){
4387 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4390 selectText : function(start, end){
4391 var v = this.getRawValue();
4393 start = start === undefined ? 0 : start;
4394 end = end === undefined ? v.length : end;
4395 var d = this.inputEl().dom;
4396 if(d.setSelectionRange){
4397 d.setSelectionRange(start, end);
4398 }else if(d.createTextRange){
4399 var range = d.createTextRange();
4400 range.moveStart("character", start);
4401 range.moveEnd("character", v.length-end);
4408 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4409 * @param {Mixed} value The value to set
4411 setValue : function(v){
4414 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4420 processValue : function(value){
4421 if(this.stripCharsRe){
4422 var newValue = value.replace(this.stripCharsRe, '');
4423 if(newValue !== value){
4424 this.setRawValue(newValue);
4431 preFocus : function(){
4433 if(this.selectOnFocus){
4434 this.inputEl().dom.select();
4437 filterKeys : function(e){
4439 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4442 var c = e.getCharCode(), cc = String.fromCharCode(c);
4443 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4446 if(!this.maskRe.test(cc)){
4451 * Clear any invalid styles/messages for this field
4453 clearInvalid : function(){
4455 if(!this.el || this.preventMark){ // not rendered
4458 this.el.removeClass(this.invalidClass);
4460 switch(this.msgTarget){
4462 this.el.dom.qtip = '';
4465 this.el.dom.title = '';
4469 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4474 this.errorIcon.dom.qtip = '';
4475 this.errorIcon.hide();
4476 this.un('resize', this.alignErrorIcon, this);
4480 var t = Roo.getDom(this.msgTarget);
4482 t.style.display = 'none';
4486 this.fireEvent('valid', this);
4489 * Mark this field as invalid
4490 * @param {String} msg The validation message
4492 markInvalid : function(msg){
4493 if(!this.el || this.preventMark){ // not rendered
4496 this.el.addClass(this.invalidClass);
4498 msg = msg || this.invalidText;
4499 switch(this.msgTarget){
4501 this.el.dom.qtip = msg;
4502 this.el.dom.qclass = 'x-form-invalid-tip';
4503 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4504 Roo.QuickTips.enable();
4508 this.el.dom.title = msg;
4512 var elp = this.el.findParent('.x-form-element', 5, true);
4513 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4514 this.errorEl.setWidth(elp.getWidth(true)-20);
4516 this.errorEl.update(msg);
4517 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4520 if(!this.errorIcon){
4521 var elp = this.el.findParent('.x-form-element', 5, true);
4522 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4524 this.alignErrorIcon();
4525 this.errorIcon.dom.qtip = msg;
4526 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4527 this.errorIcon.show();
4528 this.on('resize', this.alignErrorIcon, this);
4531 var t = Roo.getDom(this.msgTarget);
4533 t.style.display = this.msgDisplay;
4537 this.fireEvent('invalid', this, msg);
4540 SafariOnKeyDown : function(event)
4542 // this is a workaround for a password hang bug on chrome/ webkit.
4544 var isSelectAll = false;
4546 if(this.inputEl().dom.selectionEnd > 0){
4547 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4549 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4550 event.preventDefault();
4555 if(isSelectAll){ // backspace and delete key
4557 event.preventDefault();
4558 // this is very hacky as keydown always get's upper case.
4560 var cc = String.fromCharCode(event.getCharCode());
4561 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4565 adjustWidth : function(tag, w){
4566 tag = tag.toLowerCase();
4567 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
4568 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
4572 if(tag == 'textarea'){
4575 }else if(Roo.isOpera){
4579 if(tag == 'textarea'){
4598 * @class Roo.bootstrap.TextArea
4599 * @extends Roo.bootstrap.Input
4600 * Bootstrap TextArea class
4601 * @cfg {Number} cols Specifies the visible width of a text area
4602 * @cfg {Number} rows Specifies the visible number of lines in a text area
4603 * @cfg {Number} readOnly Specifies that a text area should be read-only
4604 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
4605 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
4606 * @cfg {string} html text
4609 * Create a new TextArea
4610 * @param {Object} config The config object
4613 Roo.bootstrap.TextArea = function(config){
4614 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
4618 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
4628 getAutoCreate : function(){
4630 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4641 value : this.value || '',
4642 html: this.html || '',
4643 cls : 'form-control',
4644 placeholder : this.placeholder || ''
4648 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4649 input.maxLength = this.maxLength;
4653 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
4657 input.cols = this.cols;
4660 if (this.readOnly) {
4661 input.readonly = true;
4665 input.name = this.name;
4669 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
4673 ['xs','sm','md','lg'].map(function(size){
4674 if (settings[size]) {
4675 cfg.cls += ' col-' + size + '-' + settings[size];
4679 var inputblock = input;
4681 if (this.before || this.after) {
4684 cls : 'input-group',
4688 inputblock.cn.push({
4690 cls : 'input-group-addon',
4694 inputblock.cn.push(input);
4696 inputblock.cn.push({
4698 cls : 'input-group-addon',
4705 if (align ==='left' && this.fieldLabel.length) {
4706 Roo.log("left and has label");
4712 cls : 'control-label col-sm-' + this.labelWidth,
4713 html : this.fieldLabel
4717 cls : "col-sm-" + (12 - this.labelWidth),
4724 } else if ( this.fieldLabel.length) {
4730 //cls : 'input-group-addon',
4731 html : this.fieldLabel
4741 Roo.log(" no label && no align");
4751 if (this.disabled) {
4752 input.disabled=true;
4759 * return the real textarea element.
4761 inputEl: function ()
4763 return this.el.select('textarea.form-control',true).first();
4771 * trigger field - base class for combo..
4776 * @class Roo.bootstrap.TriggerField
4777 * @extends Roo.bootstrap.Input
4778 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
4779 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
4780 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
4781 * for which you can provide a custom implementation. For example:
4783 var trigger = new Roo.bootstrap.TriggerField();
4784 trigger.onTriggerClick = myTriggerFn;
4785 trigger.applyTo('my-field');
4788 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
4789 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
4790 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
4791 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
4793 * Create a new TriggerField.
4794 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
4795 * to the base TextField)
4797 Roo.bootstrap.TriggerField = function(config){
4798 this.mimicing = false;
4799 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
4802 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
4804 * @cfg {String} triggerClass A CSS class to apply to the trigger
4807 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
4811 /** @cfg {Boolean} grow @hide */
4812 /** @cfg {Number} growMin @hide */
4813 /** @cfg {Number} growMax @hide */
4819 autoSize: Roo.emptyFn,
4826 actionMode : 'wrap',
4830 getAutoCreate : function(){
4832 var parent = this.parent();
4834 var align = this.parentLabelAlign();
4839 cls: 'form-group' //input-group
4846 type : this.inputType,
4847 cls : 'form-control',
4848 autocomplete: 'off',
4849 placeholder : this.placeholder || ''
4853 input.name = this.name;
4856 input.cls += ' input-' + this.size;
4859 cls: 'combobox-container input-group',
4864 cls: 'form-hidden-field'
4869 cls : 'typeahead typeahead-long dropdown-menu',
4870 style : 'display:none'
4874 cls : 'input-group-addon btn dropdown-toggle',
4882 cls: 'combobox-clear',
4899 if (align ==='left' && this.fieldLabel.length) {
4903 Roo.log("left and has label");
4909 cls : 'col-sm-2 control-label',
4910 html : this.fieldLabel
4921 } else if ( this.fieldLabel.length) {
4927 //cls : 'input-group-addon',
4928 html : this.fieldLabel
4938 Roo.log(" no label && no align");
4945 ['xs','sm','md','lg'].map(function(size){
4946 if (settings[size]) {
4947 cfg.cls += ' col-' + size + '-' + settings[size];
4953 if (this.disabled) {
4954 input.disabled=true;
4963 onResize : function(w, h){
4964 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
4965 // if(typeof w == 'number'){
4966 // var x = w - this.trigger.getWidth();
4967 // this.inputEl().setWidth(this.adjustWidth('input', x));
4968 // this.trigger.setStyle('left', x+'px');
4973 adjustSize : Roo.BoxComponent.prototype.adjustSize,
4976 getResizeEl : function(){
4977 return this.inputEl();
4981 getPositionEl : function(){
4982 return this.inputEl();
4986 alignErrorIcon : function(){
4987 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
4991 initEvents : function(){
4993 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
4994 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
4996 this.trigger = this.el.select('span.dropdown-toggle',true).first();
4997 if(this.hideTrigger){
4998 this.trigger.setDisplayed(false);
5000 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
5001 //this.trigger.addClassOnOver('x-form-trigger-over');
5002 //this.trigger.addClassOnClick('x-form-trigger-click');
5005 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
5010 initTrigger : function(){
5015 onDestroy : function(){
5017 this.trigger.removeAllListeners();
5018 // this.trigger.remove();
5021 // this.wrap.remove();
5023 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
5027 onFocus : function(){
5028 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
5031 this.wrap.addClass('x-trigger-wrap-focus');
5032 this.mimicing = true;
5033 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
5034 if(this.monitorTab){
5035 this.el.on("keydown", this.checkTab, this);
5042 checkTab : function(e){
5043 if(e.getKey() == e.TAB){
5049 onBlur : function(){
5054 mimicBlur : function(e, t){
5056 if(!this.wrap.contains(t) && this.validateBlur()){
5063 triggerBlur : function(){
5064 this.mimicing = false;
5065 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
5066 if(this.monitorTab){
5067 this.el.un("keydown", this.checkTab, this);
5069 //this.wrap.removeClass('x-trigger-wrap-focus');
5070 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
5074 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
5075 validateBlur : function(e, t){
5080 onDisable : function(){
5081 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5083 // this.wrap.addClass('x-item-disabled');
5088 onEnable : function(){
5089 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5091 // this.el.removeClass('x-item-disabled');
5096 onShow : function(){
5097 var ae = this.getActionEl();
5100 ae.dom.style.display = '';
5101 ae.dom.style.visibility = 'visible';
5107 onHide : function(){
5108 var ae = this.getActionEl();
5109 ae.dom.style.display = 'none';
5113 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5114 * by an implementing function.
5116 * @param {EventObject} e
5118 onTriggerClick : Roo.emptyFn
5122 * Ext JS Library 1.1.1
5123 * Copyright(c) 2006-2007, Ext JS, LLC.
5125 * Originally Released Under LGPL - original licence link has changed is not relivant.
5128 * <script type="text/javascript">
5133 * @class Roo.data.SortTypes
5135 * Defines the default sorting (casting?) comparison functions used when sorting data.
5137 Roo.data.SortTypes = {
5139 * Default sort that does nothing
5140 * @param {Mixed} s The value being converted
5141 * @return {Mixed} The comparison value
5148 * The regular expression used to strip tags
5152 stripTagsRE : /<\/?[^>]+>/gi,
5155 * Strips all HTML tags to sort on text only
5156 * @param {Mixed} s The value being converted
5157 * @return {String} The comparison value
5159 asText : function(s){
5160 return String(s).replace(this.stripTagsRE, "");
5164 * Strips all HTML tags to sort on text only - Case insensitive
5165 * @param {Mixed} s The value being converted
5166 * @return {String} The comparison value
5168 asUCText : function(s){
5169 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5173 * Case insensitive string
5174 * @param {Mixed} s The value being converted
5175 * @return {String} The comparison value
5177 asUCString : function(s) {
5178 return String(s).toUpperCase();
5183 * @param {Mixed} s The value being converted
5184 * @return {Number} The comparison value
5186 asDate : function(s) {
5190 if(s instanceof Date){
5193 return Date.parse(String(s));
5198 * @param {Mixed} s The value being converted
5199 * @return {Float} The comparison value
5201 asFloat : function(s) {
5202 var val = parseFloat(String(s).replace(/,/g, ""));
5203 if(isNaN(val)) val = 0;
5209 * @param {Mixed} s The value being converted
5210 * @return {Number} The comparison value
5212 asInt : function(s) {
5213 var val = parseInt(String(s).replace(/,/g, ""));
5214 if(isNaN(val)) val = 0;
5219 * Ext JS Library 1.1.1
5220 * Copyright(c) 2006-2007, Ext JS, LLC.
5222 * Originally Released Under LGPL - original licence link has changed is not relivant.
5225 * <script type="text/javascript">
5229 * @class Roo.data.Record
5230 * Instances of this class encapsulate both record <em>definition</em> information, and record
5231 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5232 * to access Records cached in an {@link Roo.data.Store} object.<br>
5234 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5235 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5238 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5240 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5241 * {@link #create}. The parameters are the same.
5242 * @param {Array} data An associative Array of data values keyed by the field name.
5243 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5244 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5245 * not specified an integer id is generated.
5247 Roo.data.Record = function(data, id){
5248 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5253 * Generate a constructor for a specific record layout.
5254 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5255 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5256 * Each field definition object may contain the following properties: <ul>
5257 * <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,
5258 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5259 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5260 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5261 * is being used, then this is a string containing the javascript expression to reference the data relative to
5262 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5263 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5264 * this may be omitted.</p></li>
5265 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5266 * <ul><li>auto (Default, implies no conversion)</li>
5271 * <li>date</li></ul></p></li>
5272 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5273 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5274 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5275 * by the Reader into an object that will be stored in the Record. It is passed the
5276 * following parameters:<ul>
5277 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5279 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5281 * <br>usage:<br><pre><code>
5282 var TopicRecord = Roo.data.Record.create(
5283 {name: 'title', mapping: 'topic_title'},
5284 {name: 'author', mapping: 'username'},
5285 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5286 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5287 {name: 'lastPoster', mapping: 'user2'},
5288 {name: 'excerpt', mapping: 'post_text'}
5291 var myNewRecord = new TopicRecord({
5292 title: 'Do my job please',
5295 lastPost: new Date(),
5296 lastPoster: 'Animal',
5297 excerpt: 'No way dude!'
5299 myStore.add(myNewRecord);
5304 Roo.data.Record.create = function(o){
5306 f.superclass.constructor.apply(this, arguments);
5308 Roo.extend(f, Roo.data.Record);
5309 var p = f.prototype;
5310 p.fields = new Roo.util.MixedCollection(false, function(field){
5313 for(var i = 0, len = o.length; i < len; i++){
5314 p.fields.add(new Roo.data.Field(o[i]));
5316 f.getField = function(name){
5317 return p.fields.get(name);
5322 Roo.data.Record.AUTO_ID = 1000;
5323 Roo.data.Record.EDIT = 'edit';
5324 Roo.data.Record.REJECT = 'reject';
5325 Roo.data.Record.COMMIT = 'commit';
5327 Roo.data.Record.prototype = {
5329 * Readonly flag - true if this record has been modified.
5338 join : function(store){
5343 * Set the named field to the specified value.
5344 * @param {String} name The name of the field to set.
5345 * @param {Object} value The value to set the field to.
5347 set : function(name, value){
5348 if(this.data[name] == value){
5355 if(typeof this.modified[name] == 'undefined'){
5356 this.modified[name] = this.data[name];
5358 this.data[name] = value;
5359 if(!this.editing && this.store){
5360 this.store.afterEdit(this);
5365 * Get the value of the named field.
5366 * @param {String} name The name of the field to get the value of.
5367 * @return {Object} The value of the field.
5369 get : function(name){
5370 return this.data[name];
5374 beginEdit : function(){
5375 this.editing = true;
5380 cancelEdit : function(){
5381 this.editing = false;
5382 delete this.modified;
5386 endEdit : function(){
5387 this.editing = false;
5388 if(this.dirty && this.store){
5389 this.store.afterEdit(this);
5394 * Usually called by the {@link Roo.data.Store} which owns the Record.
5395 * Rejects all changes made to the Record since either creation, or the last commit operation.
5396 * Modified fields are reverted to their original values.
5398 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5399 * of reject operations.
5401 reject : function(){
5402 var m = this.modified;
5404 if(typeof m[n] != "function"){
5405 this.data[n] = m[n];
5409 delete this.modified;
5410 this.editing = false;
5412 this.store.afterReject(this);
5417 * Usually called by the {@link Roo.data.Store} which owns the Record.
5418 * Commits all changes made to the Record since either creation, or the last commit operation.
5420 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5421 * of commit operations.
5423 commit : function(){
5425 delete this.modified;
5426 this.editing = false;
5428 this.store.afterCommit(this);
5433 hasError : function(){
5434 return this.error != null;
5438 clearError : function(){
5443 * Creates a copy of this record.
5444 * @param {String} id (optional) A new record id if you don't want to use this record's id
5447 copy : function(newId) {
5448 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5452 * Ext JS Library 1.1.1
5453 * Copyright(c) 2006-2007, Ext JS, LLC.
5455 * Originally Released Under LGPL - original licence link has changed is not relivant.
5458 * <script type="text/javascript">
5464 * @class Roo.data.Store
5465 * @extends Roo.util.Observable
5466 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5467 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5469 * 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
5470 * has no knowledge of the format of the data returned by the Proxy.<br>
5472 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5473 * instances from the data object. These records are cached and made available through accessor functions.
5475 * Creates a new Store.
5476 * @param {Object} config A config object containing the objects needed for the Store to access data,
5477 * and read the data into Records.
5479 Roo.data.Store = function(config){
5480 this.data = new Roo.util.MixedCollection(false);
5481 this.data.getKey = function(o){
5484 this.baseParams = {};
5491 "multisort" : "_multisort"
5494 if(config && config.data){
5495 this.inlineData = config.data;
5499 Roo.apply(this, config);
5501 if(this.reader){ // reader passed
5502 this.reader = Roo.factory(this.reader, Roo.data);
5503 this.reader.xmodule = this.xmodule || false;
5504 if(!this.recordType){
5505 this.recordType = this.reader.recordType;
5507 if(this.reader.onMetaChange){
5508 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
5512 if(this.recordType){
5513 this.fields = this.recordType.prototype.fields;
5519 * @event datachanged
5520 * Fires when the data cache has changed, and a widget which is using this Store
5521 * as a Record cache should refresh its view.
5522 * @param {Store} this
5527 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
5528 * @param {Store} this
5529 * @param {Object} meta The JSON metadata
5534 * Fires when Records have been added to the Store
5535 * @param {Store} this
5536 * @param {Roo.data.Record[]} records The array of Records added
5537 * @param {Number} index The index at which the record(s) were added
5542 * Fires when a Record has been removed from the Store
5543 * @param {Store} this
5544 * @param {Roo.data.Record} record The Record that was removed
5545 * @param {Number} index The index at which the record was removed
5550 * Fires when a Record has been updated
5551 * @param {Store} this
5552 * @param {Roo.data.Record} record The Record that was updated
5553 * @param {String} operation The update operation being performed. Value may be one of:
5555 Roo.data.Record.EDIT
5556 Roo.data.Record.REJECT
5557 Roo.data.Record.COMMIT
5563 * Fires when the data cache has been cleared.
5564 * @param {Store} this
5569 * Fires before a request is made for a new data object. If the beforeload handler returns false
5570 * the load action will be canceled.
5571 * @param {Store} this
5572 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5576 * @event beforeloadadd
5577 * Fires after a new set of Records has been loaded.
5578 * @param {Store} this
5579 * @param {Roo.data.Record[]} records The Records that were loaded
5580 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5582 beforeloadadd : true,
5585 * Fires after a new set of Records has been loaded, before they are added to the store.
5586 * @param {Store} this
5587 * @param {Roo.data.Record[]} records The Records that were loaded
5588 * @param {Object} options The loading options that were specified (see {@link #load} for details)
5589 * @params {Object} return from reader
5593 * @event loadexception
5594 * Fires if an exception occurs in the Proxy during loading.
5595 * Called with the signature of the Proxy's "loadexception" event.
5596 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
5599 * @param {Object} return from JsonData.reader() - success, totalRecords, records
5600 * @param {Object} load options
5601 * @param {Object} jsonData from your request (normally this contains the Exception)
5603 loadexception : true
5607 this.proxy = Roo.factory(this.proxy, Roo.data);
5608 this.proxy.xmodule = this.xmodule || false;
5609 this.relayEvents(this.proxy, ["loadexception"]);
5611 this.sortToggle = {};
5612 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
5614 Roo.data.Store.superclass.constructor.call(this);
5616 if(this.inlineData){
5617 this.loadData(this.inlineData);
5618 delete this.inlineData;
5622 Roo.extend(Roo.data.Store, Roo.util.Observable, {
5624 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
5625 * without a remote query - used by combo/forms at present.
5629 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
5632 * @cfg {Array} data Inline data to be loaded when the store is initialized.
5635 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
5636 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
5639 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
5640 * on any HTTP request
5643 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
5646 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
5650 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
5651 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
5656 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
5657 * loaded or when a record is removed. (defaults to false).
5659 pruneModifiedRecords : false,
5665 * Add Records to the Store and fires the add event.
5666 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5668 add : function(records){
5669 records = [].concat(records);
5670 for(var i = 0, len = records.length; i < len; i++){
5671 records[i].join(this);
5673 var index = this.data.length;
5674 this.data.addAll(records);
5675 this.fireEvent("add", this, records, index);
5679 * Remove a Record from the Store and fires the remove event.
5680 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
5682 remove : function(record){
5683 var index = this.data.indexOf(record);
5684 this.data.removeAt(index);
5685 if(this.pruneModifiedRecords){
5686 this.modified.remove(record);
5688 this.fireEvent("remove", this, record, index);
5692 * Remove all Records from the Store and fires the clear event.
5694 removeAll : function(){
5696 if(this.pruneModifiedRecords){
5699 this.fireEvent("clear", this);
5703 * Inserts Records to the Store at the given index and fires the add event.
5704 * @param {Number} index The start index at which to insert the passed Records.
5705 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
5707 insert : function(index, records){
5708 records = [].concat(records);
5709 for(var i = 0, len = records.length; i < len; i++){
5710 this.data.insert(index, records[i]);
5711 records[i].join(this);
5713 this.fireEvent("add", this, records, index);
5717 * Get the index within the cache of the passed Record.
5718 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
5719 * @return {Number} The index of the passed Record. Returns -1 if not found.
5721 indexOf : function(record){
5722 return this.data.indexOf(record);
5726 * Get the index within the cache of the Record with the passed id.
5727 * @param {String} id The id of the Record to find.
5728 * @return {Number} The index of the Record. Returns -1 if not found.
5730 indexOfId : function(id){
5731 return this.data.indexOfKey(id);
5735 * Get the Record with the specified id.
5736 * @param {String} id The id of the Record to find.
5737 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
5739 getById : function(id){
5740 return this.data.key(id);
5744 * Get the Record at the specified index.
5745 * @param {Number} index The index of the Record to find.
5746 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5748 getAt : function(index){
5749 return this.data.itemAt(index);
5753 * Returns a range of Records between specified indices.
5754 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5755 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5756 * @return {Roo.data.Record[]} An array of Records
5758 getRange : function(start, end){
5759 return this.data.getRange(start, end);
5763 storeOptions : function(o){
5764 o = Roo.apply({}, o);
5767 this.lastOptions = o;
5771 * Loads the Record cache from the configured Proxy using the configured Reader.
5773 * If using remote paging, then the first load call must specify the <em>start</em>
5774 * and <em>limit</em> properties in the options.params property to establish the initial
5775 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5777 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5778 * and this call will return before the new data has been loaded. Perform any post-processing
5779 * in a callback function, or in a "load" event handler.</strong>
5781 * @param {Object} options An object containing properties which control loading options:<ul>
5782 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5783 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5784 * passed the following arguments:<ul>
5785 * <li>r : Roo.data.Record[]</li>
5786 * <li>options: Options object from the load call</li>
5787 * <li>success: Boolean success indicator</li></ul></li>
5788 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5789 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5792 load : function(options){
5793 options = options || {};
5794 if(this.fireEvent("beforeload", this, options) !== false){
5795 this.storeOptions(options);
5796 var p = Roo.apply(options.params || {}, this.baseParams);
5797 // if meta was not loaded from remote source.. try requesting it.
5798 if (!this.reader.metaFromRemote) {
5801 if(this.sortInfo && this.remoteSort){
5802 var pn = this.paramNames;
5803 p[pn["sort"]] = this.sortInfo.field;
5804 p[pn["dir"]] = this.sortInfo.direction;
5806 if (this.multiSort) {
5807 var pn = this.paramNames;
5808 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5811 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5816 * Reloads the Record cache from the configured Proxy using the configured Reader and
5817 * the options from the last load operation performed.
5818 * @param {Object} options (optional) An object containing properties which may override the options
5819 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5820 * the most recently used options are reused).
5822 reload : function(options){
5823 this.load(Roo.applyIf(options||{}, this.lastOptions));
5827 // Called as a callback by the Reader during a load operation.
5828 loadRecords : function(o, options, success){
5829 if(!o || success === false){
5830 if(success !== false){
5831 this.fireEvent("load", this, [], options, o);
5833 if(options.callback){
5834 options.callback.call(options.scope || this, [], options, false);
5838 // if data returned failure - throw an exception.
5839 if (o.success === false) {
5840 // show a message if no listener is registered.
5841 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5842 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5844 // loadmask wil be hooked into this..
5845 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5848 var r = o.records, t = o.totalRecords || r.length;
5850 this.fireEvent("beforeloadadd", this, r, options, o);
5852 if(!options || options.add !== true){
5853 if(this.pruneModifiedRecords){
5856 for(var i = 0, len = r.length; i < len; i++){
5860 this.data = this.snapshot;
5861 delete this.snapshot;
5864 this.data.addAll(r);
5865 this.totalLength = t;
5867 this.fireEvent("datachanged", this);
5869 this.totalLength = Math.max(t, this.data.length+r.length);
5872 this.fireEvent("load", this, r, options, o);
5873 if(options.callback){
5874 options.callback.call(options.scope || this, r, options, true);
5880 * Loads data from a passed data block. A Reader which understands the format of the data
5881 * must have been configured in the constructor.
5882 * @param {Object} data The data block from which to read the Records. The format of the data expected
5883 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5884 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5886 loadData : function(o, append){
5887 var r = this.reader.readRecords(o);
5888 this.loadRecords(r, {add: append}, true);
5892 * Gets the number of cached records.
5894 * <em>If using paging, this may not be the total size of the dataset. If the data object
5895 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5896 * the data set size</em>
5898 getCount : function(){
5899 return this.data.length || 0;
5903 * Gets the total number of records in the dataset as returned by the server.
5905 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5906 * the dataset size</em>
5908 getTotalCount : function(){
5909 return this.totalLength || 0;
5913 * Returns the sort state of the Store as an object with two properties:
5915 field {String} The name of the field by which the Records are sorted
5916 direction {String} The sort order, "ASC" or "DESC"
5919 getSortState : function(){
5920 return this.sortInfo;
5924 applySort : function(){
5925 if(this.sortInfo && !this.remoteSort){
5926 var s = this.sortInfo, f = s.field;
5927 var st = this.fields.get(f).sortType;
5928 var fn = function(r1, r2){
5929 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5930 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5932 this.data.sort(s.direction, fn);
5933 if(this.snapshot && this.snapshot != this.data){
5934 this.snapshot.sort(s.direction, fn);
5940 * Sets the default sort column and order to be used by the next load operation.
5941 * @param {String} fieldName The name of the field to sort by.
5942 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5944 setDefaultSort : function(field, dir){
5945 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5950 * If remote sorting is used, the sort is performed on the server, and the cache is
5951 * reloaded. If local sorting is used, the cache is sorted internally.
5952 * @param {String} fieldName The name of the field to sort by.
5953 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5955 sort : function(fieldName, dir){
5956 var f = this.fields.get(fieldName);
5958 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5960 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5961 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5966 this.sortToggle[f.name] = dir;
5967 this.sortInfo = {field: f.name, direction: dir};
5968 if(!this.remoteSort){
5970 this.fireEvent("datachanged", this);
5972 this.load(this.lastOptions);
5977 * Calls the specified function for each of the Records in the cache.
5978 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5979 * Returning <em>false</em> aborts and exits the iteration.
5980 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5982 each : function(fn, scope){
5983 this.data.each(fn, scope);
5987 * Gets all records modified since the last commit. Modified records are persisted across load operations
5988 * (e.g., during paging).
5989 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5991 getModifiedRecords : function(){
5992 return this.modified;
5996 createFilterFn : function(property, value, anyMatch){
5997 if(!value.exec){ // not a regex
5998 value = String(value);
5999 if(value.length == 0){
6002 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
6005 return value.test(r.data[property]);
6010 * Sums the value of <i>property</i> for each record between start and end and returns the result.
6011 * @param {String} property A field on your records
6012 * @param {Number} start The record index to start at (defaults to 0)
6013 * @param {Number} end The last record index to include (defaults to length - 1)
6014 * @return {Number} The sum
6016 sum : function(property, start, end){
6017 var rs = this.data.items, v = 0;
6019 end = (end || end === 0) ? end : rs.length-1;
6021 for(var i = start; i <= end; i++){
6022 v += (rs[i].data[property] || 0);
6028 * Filter the records by a specified property.
6029 * @param {String} field A field on your records
6030 * @param {String/RegExp} value Either a string that the field
6031 * should start with or a RegExp to test against the field
6032 * @param {Boolean} anyMatch True to match any part not just the beginning
6034 filter : function(property, value, anyMatch){
6035 var fn = this.createFilterFn(property, value, anyMatch);
6036 return fn ? this.filterBy(fn) : this.clearFilter();
6040 * Filter by a function. The specified function will be called with each
6041 * record in this data source. If the function returns true the record is included,
6042 * otherwise it is filtered.
6043 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6044 * @param {Object} scope (optional) The scope of the function (defaults to this)
6046 filterBy : function(fn, scope){
6047 this.snapshot = this.snapshot || this.data;
6048 this.data = this.queryBy(fn, scope||this);
6049 this.fireEvent("datachanged", this);
6053 * Query the records by a specified property.
6054 * @param {String} field A field on your records
6055 * @param {String/RegExp} value Either a string that the field
6056 * should start with or a RegExp to test against the field
6057 * @param {Boolean} anyMatch True to match any part not just the beginning
6058 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6060 query : function(property, value, anyMatch){
6061 var fn = this.createFilterFn(property, value, anyMatch);
6062 return fn ? this.queryBy(fn) : this.data.clone();
6066 * Query by a function. The specified function will be called with each
6067 * record in this data source. If the function returns true the record is included
6069 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6070 * @param {Object} scope (optional) The scope of the function (defaults to this)
6071 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6073 queryBy : function(fn, scope){
6074 var data = this.snapshot || this.data;
6075 return data.filterBy(fn, scope||this);
6079 * Collects unique values for a particular dataIndex from this store.
6080 * @param {String} dataIndex The property to collect
6081 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
6082 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6083 * @return {Array} An array of the unique values
6085 collect : function(dataIndex, allowNull, bypassFilter){
6086 var d = (bypassFilter === true && this.snapshot) ?
6087 this.snapshot.items : this.data.items;
6088 var v, sv, r = [], l = {};
6089 for(var i = 0, len = d.length; i < len; i++){
6090 v = d[i].data[dataIndex];
6092 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6101 * Revert to a view of the Record cache with no filtering applied.
6102 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6104 clearFilter : function(suppressEvent){
6105 if(this.snapshot && this.snapshot != this.data){
6106 this.data = this.snapshot;
6107 delete this.snapshot;
6108 if(suppressEvent !== true){
6109 this.fireEvent("datachanged", this);
6115 afterEdit : function(record){
6116 if(this.modified.indexOf(record) == -1){
6117 this.modified.push(record);
6119 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6123 afterReject : function(record){
6124 this.modified.remove(record);
6125 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6129 afterCommit : function(record){
6130 this.modified.remove(record);
6131 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6135 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6136 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6138 commitChanges : function(){
6139 var m = this.modified.slice(0);
6141 for(var i = 0, len = m.length; i < len; i++){
6147 * Cancel outstanding changes on all changed records.
6149 rejectChanges : function(){
6150 var m = this.modified.slice(0);
6152 for(var i = 0, len = m.length; i < len; i++){
6157 onMetaChange : function(meta, rtype, o){
6158 this.recordType = rtype;
6159 this.fields = rtype.prototype.fields;
6160 delete this.snapshot;
6161 this.sortInfo = meta.sortInfo || this.sortInfo;
6163 this.fireEvent('metachange', this, this.reader.meta);
6167 * Ext JS Library 1.1.1
6168 * Copyright(c) 2006-2007, Ext JS, LLC.
6170 * Originally Released Under LGPL - original licence link has changed is not relivant.
6173 * <script type="text/javascript">
6177 * @class Roo.data.SimpleStore
6178 * @extends Roo.data.Store
6179 * Small helper class to make creating Stores from Array data easier.
6180 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6181 * @cfg {Array} fields An array of field definition objects, or field name strings.
6182 * @cfg {Array} data The multi-dimensional array of data
6184 * @param {Object} config
6186 Roo.data.SimpleStore = function(config){
6187 Roo.data.SimpleStore.superclass.constructor.call(this, {
6189 reader: new Roo.data.ArrayReader({
6192 Roo.data.Record.create(config.fields)
6194 proxy : new Roo.data.MemoryProxy(config.data)
6198 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6200 * Ext JS Library 1.1.1
6201 * Copyright(c) 2006-2007, Ext JS, LLC.
6203 * Originally Released Under LGPL - original licence link has changed is not relivant.
6206 * <script type="text/javascript">
6211 * @extends Roo.data.Store
6212 * @class Roo.data.JsonStore
6213 * Small helper class to make creating Stores for JSON data easier. <br/>
6215 var store = new Roo.data.JsonStore({
6216 url: 'get-images.php',
6218 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6221 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6222 * JsonReader and HttpProxy (unless inline data is provided).</b>
6223 * @cfg {Array} fields An array of field definition objects, or field name strings.
6225 * @param {Object} config
6227 Roo.data.JsonStore = function(c){
6228 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6229 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6230 reader: new Roo.data.JsonReader(c, c.fields)
6233 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6235 * Ext JS Library 1.1.1
6236 * Copyright(c) 2006-2007, Ext JS, LLC.
6238 * Originally Released Under LGPL - original licence link has changed is not relivant.
6241 * <script type="text/javascript">
6245 Roo.data.Field = function(config){
6246 if(typeof config == "string"){
6247 config = {name: config};
6249 Roo.apply(this, config);
6255 var st = Roo.data.SortTypes;
6256 // named sortTypes are supported, here we look them up
6257 if(typeof this.sortType == "string"){
6258 this.sortType = st[this.sortType];
6261 // set default sortType for strings and dates
6265 this.sortType = st.asUCString;
6268 this.sortType = st.asDate;
6271 this.sortType = st.none;
6276 var stripRe = /[\$,%]/g;
6278 // prebuilt conversion function for this field, instead of
6279 // switching every time we're reading a value
6281 var cv, dateFormat = this.dateFormat;
6286 cv = function(v){ return v; };
6289 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6293 return v !== undefined && v !== null && v !== '' ?
6294 parseInt(String(v).replace(stripRe, ""), 10) : '';
6299 return v !== undefined && v !== null && v !== '' ?
6300 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6305 cv = function(v){ return v === true || v === "true" || v == 1; };
6312 if(v instanceof Date){
6316 if(dateFormat == "timestamp"){
6317 return new Date(v*1000);
6319 return Date.parseDate(v, dateFormat);
6321 var parsed = Date.parse(v);
6322 return parsed ? new Date(parsed) : null;
6331 Roo.data.Field.prototype = {
6339 * Ext JS Library 1.1.1
6340 * Copyright(c) 2006-2007, Ext JS, LLC.
6342 * Originally Released Under LGPL - original licence link has changed is not relivant.
6345 * <script type="text/javascript">
6348 // Base class for reading structured data from a data source. This class is intended to be
6349 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6352 * @class Roo.data.DataReader
6353 * Base class for reading structured data from a data source. This class is intended to be
6354 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6357 Roo.data.DataReader = function(meta, recordType){
6361 this.recordType = recordType instanceof Array ?
6362 Roo.data.Record.create(recordType) : recordType;
6365 Roo.data.DataReader.prototype = {
6367 * Create an empty record
6368 * @param {Object} data (optional) - overlay some values
6369 * @return {Roo.data.Record} record created.
6371 newRow : function(d) {
6373 this.recordType.prototype.fields.each(function(c) {
6375 case 'int' : da[c.name] = 0; break;
6376 case 'date' : da[c.name] = new Date(); break;
6377 case 'float' : da[c.name] = 0.0; break;
6378 case 'boolean' : da[c.name] = false; break;
6379 default : da[c.name] = ""; break;
6383 return new this.recordType(Roo.apply(da, d));
6388 * Ext JS Library 1.1.1
6389 * Copyright(c) 2006-2007, Ext JS, LLC.
6391 * Originally Released Under LGPL - original licence link has changed is not relivant.
6394 * <script type="text/javascript">
6398 * @class Roo.data.DataProxy
6399 * @extends Roo.data.Observable
6400 * This class is an abstract base class for implementations which provide retrieval of
6401 * unformatted data objects.<br>
6403 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6404 * (of the appropriate type which knows how to parse the data object) to provide a block of
6405 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6407 * Custom implementations must implement the load method as described in
6408 * {@link Roo.data.HttpProxy#load}.
6410 Roo.data.DataProxy = function(){
6414 * Fires before a network request is made to retrieve a data object.
6415 * @param {Object} This DataProxy object.
6416 * @param {Object} params The params parameter to the load function.
6421 * Fires before the load method's callback is called.
6422 * @param {Object} This DataProxy object.
6423 * @param {Object} o The data object.
6424 * @param {Object} arg The callback argument object passed to the load function.
6428 * @event loadexception
6429 * Fires if an Exception occurs during data retrieval.
6430 * @param {Object} This DataProxy object.
6431 * @param {Object} o The data object.
6432 * @param {Object} arg The callback argument object passed to the load function.
6433 * @param {Object} e The Exception.
6435 loadexception : true
6437 Roo.data.DataProxy.superclass.constructor.call(this);
6440 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6443 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6447 * Ext JS Library 1.1.1
6448 * Copyright(c) 2006-2007, Ext JS, LLC.
6450 * Originally Released Under LGPL - original licence link has changed is not relivant.
6453 * <script type="text/javascript">
6456 * @class Roo.data.MemoryProxy
6457 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6458 * to the Reader when its load method is called.
6460 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6462 Roo.data.MemoryProxy = function(data){
6466 Roo.data.MemoryProxy.superclass.constructor.call(this);
6470 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6472 * Load data from the requested source (in this case an in-memory
6473 * data object passed to the constructor), read the data object into
6474 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6475 * process that block using the passed callback.
6476 * @param {Object} params This parameter is not used by the MemoryProxy class.
6477 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6478 * object into a block of Roo.data.Records.
6479 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6480 * The function must be passed <ul>
6481 * <li>The Record block object</li>
6482 * <li>The "arg" argument from the load function</li>
6483 * <li>A boolean success indicator</li>
6485 * @param {Object} scope The scope in which to call the callback
6486 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6488 load : function(params, reader, callback, scope, arg){
6489 params = params || {};
6492 result = reader.readRecords(this.data);
6494 this.fireEvent("loadexception", this, arg, null, e);
6495 callback.call(scope, null, arg, false);
6498 callback.call(scope, result, arg, true);
6502 update : function(params, records){
6507 * Ext JS Library 1.1.1
6508 * Copyright(c) 2006-2007, Ext JS, LLC.
6510 * Originally Released Under LGPL - original licence link has changed is not relivant.
6513 * <script type="text/javascript">
6516 * @class Roo.data.HttpProxy
6517 * @extends Roo.data.DataProxy
6518 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
6519 * configured to reference a certain URL.<br><br>
6521 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
6522 * from which the running page was served.<br><br>
6524 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
6526 * Be aware that to enable the browser to parse an XML document, the server must set
6527 * the Content-Type header in the HTTP response to "text/xml".
6529 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
6530 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
6531 * will be used to make the request.
6533 Roo.data.HttpProxy = function(conn){
6534 Roo.data.HttpProxy.superclass.constructor.call(this);
6535 // is conn a conn config or a real conn?
6537 this.useAjax = !conn || !conn.events;
6541 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
6542 // thse are take from connection...
6545 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
6548 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6549 * extra parameters to each request made by this object. (defaults to undefined)
6552 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6553 * to each request made by this object. (defaults to undefined)
6556 * @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)
6559 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6562 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6568 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6572 * Return the {@link Roo.data.Connection} object being used by this Proxy.
6573 * @return {Connection} The Connection object. This object may be used to subscribe to events on
6574 * a finer-grained basis than the DataProxy events.
6576 getConnection : function(){
6577 return this.useAjax ? Roo.Ajax : this.conn;
6581 * Load data from the configured {@link Roo.data.Connection}, read the data object into
6582 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
6583 * process that block using the passed callback.
6584 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6585 * for the request to the remote server.
6586 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6587 * object into a block of Roo.data.Records.
6588 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6589 * The function must be passed <ul>
6590 * <li>The Record block object</li>
6591 * <li>The "arg" argument from the load function</li>
6592 * <li>A boolean success indicator</li>
6594 * @param {Object} scope The scope in which to call the callback
6595 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6597 load : function(params, reader, callback, scope, arg){
6598 if(this.fireEvent("beforeload", this, params) !== false){
6600 params : params || {},
6602 callback : callback,
6607 callback : this.loadResponse,
6611 Roo.applyIf(o, this.conn);
6612 if(this.activeRequest){
6613 Roo.Ajax.abort(this.activeRequest);
6615 this.activeRequest = Roo.Ajax.request(o);
6617 this.conn.request(o);
6620 callback.call(scope||this, null, arg, false);
6625 loadResponse : function(o, success, response){
6626 delete this.activeRequest;
6628 this.fireEvent("loadexception", this, o, response);
6629 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6634 result = o.reader.read(response);
6636 this.fireEvent("loadexception", this, o, response, e);
6637 o.request.callback.call(o.request.scope, null, o.request.arg, false);
6641 this.fireEvent("load", this, o, o.request.arg);
6642 o.request.callback.call(o.request.scope, result, o.request.arg, true);
6646 update : function(dataSet){
6651 updateResponse : function(dataSet){
6656 * Ext JS Library 1.1.1
6657 * Copyright(c) 2006-2007, Ext JS, LLC.
6659 * Originally Released Under LGPL - original licence link has changed is not relivant.
6662 * <script type="text/javascript">
6666 * @class Roo.data.ScriptTagProxy
6667 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
6668 * other than the originating domain of the running page.<br><br>
6670 * <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
6671 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
6673 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
6674 * source code that is used as the source inside a <script> tag.<br><br>
6676 * In order for the browser to process the returned data, the server must wrap the data object
6677 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
6678 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
6679 * depending on whether the callback name was passed:
6682 boolean scriptTag = false;
6683 String cb = request.getParameter("callback");
6686 response.setContentType("text/javascript");
6688 response.setContentType("application/x-json");
6690 Writer out = response.getWriter();
6692 out.write(cb + "(");
6694 out.print(dataBlock.toJsonString());
6701 * @param {Object} config A configuration object.
6703 Roo.data.ScriptTagProxy = function(config){
6704 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
6705 Roo.apply(this, config);
6706 this.head = document.getElementsByTagName("head")[0];
6709 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
6711 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
6713 * @cfg {String} url The URL from which to request the data object.
6716 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
6720 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
6721 * the server the name of the callback function set up by the load call to process the returned data object.
6722 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
6723 * javascript output which calls this named function passing the data object as its only parameter.
6725 callbackParam : "callback",
6727 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
6728 * name to the request.
6733 * Load data from the configured URL, read the data object into
6734 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6735 * process that block using the passed callback.
6736 * @param {Object} params An object containing properties which are to be used as HTTP parameters
6737 * for the request to the remote server.
6738 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6739 * object into a block of Roo.data.Records.
6740 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6741 * The function must be passed <ul>
6742 * <li>The Record block object</li>
6743 * <li>The "arg" argument from the load function</li>
6744 * <li>A boolean success indicator</li>
6746 * @param {Object} scope The scope in which to call the callback
6747 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6749 load : function(params, reader, callback, scope, arg){
6750 if(this.fireEvent("beforeload", this, params) !== false){
6752 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6755 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6757 url += "&_dc=" + (new Date().getTime());
6759 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6762 cb : "stcCallback"+transId,
6763 scriptId : "stcScript"+transId,
6767 callback : callback,
6773 window[trans.cb] = function(o){
6774 conn.handleResponse(o, trans);
6777 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6779 if(this.autoAbort !== false){
6783 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6785 var script = document.createElement("script");
6786 script.setAttribute("src", url);
6787 script.setAttribute("type", "text/javascript");
6788 script.setAttribute("id", trans.scriptId);
6789 this.head.appendChild(script);
6793 callback.call(scope||this, null, arg, false);
6798 isLoading : function(){
6799 return this.trans ? true : false;
6803 * Abort the current server request.
6806 if(this.isLoading()){
6807 this.destroyTrans(this.trans);
6812 destroyTrans : function(trans, isLoaded){
6813 this.head.removeChild(document.getElementById(trans.scriptId));
6814 clearTimeout(trans.timeoutId);
6816 window[trans.cb] = undefined;
6818 delete window[trans.cb];
6821 // if hasn't been loaded, wait for load to remove it to prevent script error
6822 window[trans.cb] = function(){
6823 window[trans.cb] = undefined;
6825 delete window[trans.cb];
6832 handleResponse : function(o, trans){
6834 this.destroyTrans(trans, true);
6837 result = trans.reader.readRecords(o);
6839 this.fireEvent("loadexception", this, o, trans.arg, e);
6840 trans.callback.call(trans.scope||window, null, trans.arg, false);
6843 this.fireEvent("load", this, o, trans.arg);
6844 trans.callback.call(trans.scope||window, result, trans.arg, true);
6848 handleFailure : function(trans){
6850 this.destroyTrans(trans, false);
6851 this.fireEvent("loadexception", this, null, trans.arg);
6852 trans.callback.call(trans.scope||window, null, trans.arg, false);
6856 * Ext JS Library 1.1.1
6857 * Copyright(c) 2006-2007, Ext JS, LLC.
6859 * Originally Released Under LGPL - original licence link has changed is not relivant.
6862 * <script type="text/javascript">
6866 * @class Roo.data.JsonReader
6867 * @extends Roo.data.DataReader
6868 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6869 * based on mappings in a provided Roo.data.Record constructor.
6871 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6872 * in the reply previously.
6877 var RecordDef = Roo.data.Record.create([
6878 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6879 {name: 'occupation'} // This field will use "occupation" as the mapping.
6881 var myReader = new Roo.data.JsonReader({
6882 totalProperty: "results", // The property which contains the total dataset size (optional)
6883 root: "rows", // The property which contains an Array of row objects
6884 id: "id" // The property within each row object that provides an ID for the record (optional)
6888 * This would consume a JSON file like this:
6890 { 'results': 2, 'rows': [
6891 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6892 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6895 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6896 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6897 * paged from the remote server.
6898 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6899 * @cfg {String} root name of the property which contains the Array of row objects.
6900 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6902 * Create a new JsonReader
6903 * @param {Object} meta Metadata configuration options
6904 * @param {Object} recordType Either an Array of field definition objects,
6905 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6907 Roo.data.JsonReader = function(meta, recordType){
6910 // set some defaults:
6912 totalProperty: 'total',
6913 successProperty : 'success',
6918 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6920 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6923 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6924 * Used by Store query builder to append _requestMeta to params.
6927 metaFromRemote : false,
6929 * This method is only used by a DataProxy which has retrieved data from a remote server.
6930 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6931 * @return {Object} data A data block which is used by an Roo.data.Store object as
6932 * a cache of Roo.data.Records.
6934 read : function(response){
6935 var json = response.responseText;
6937 var o = /* eval:var:o */ eval("("+json+")");
6939 throw {message: "JsonReader.read: Json object not found"};
6945 this.metaFromRemote = true;
6946 this.meta = o.metaData;
6947 this.recordType = Roo.data.Record.create(o.metaData.fields);
6948 this.onMetaChange(this.meta, this.recordType, o);
6950 return this.readRecords(o);
6953 // private function a store will implement
6954 onMetaChange : function(meta, recordType, o){
6961 simpleAccess: function(obj, subsc) {
6968 getJsonAccessor: function(){
6970 return function(expr) {
6972 return(re.test(expr))
6973 ? new Function("obj", "return obj." + expr)
6983 * Create a data block containing Roo.data.Records from an XML document.
6984 * @param {Object} o An object which contains an Array of row objects in the property specified
6985 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6986 * which contains the total size of the dataset.
6987 * @return {Object} data A data block which is used by an Roo.data.Store object as
6988 * a cache of Roo.data.Records.
6990 readRecords : function(o){
6992 * After any data loads, the raw JSON data is available for further custom processing.
6996 var s = this.meta, Record = this.recordType,
6997 f = Record.prototype.fields, fi = f.items, fl = f.length;
6999 // Generate extraction functions for the totalProperty, the root, the id, and for each field
7001 if(s.totalProperty) {
7002 this.getTotal = this.getJsonAccessor(s.totalProperty);
7004 if(s.successProperty) {
7005 this.getSuccess = this.getJsonAccessor(s.successProperty);
7007 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
7009 var g = this.getJsonAccessor(s.id);
7010 this.getId = function(rec) {
7012 return (r === undefined || r === "") ? null : r;
7015 this.getId = function(){return null;};
7018 for(var jj = 0; jj < fl; jj++){
7020 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
7021 this.ef[jj] = this.getJsonAccessor(map);
7025 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
7026 if(s.totalProperty){
7027 var vt = parseInt(this.getTotal(o), 10);
7032 if(s.successProperty){
7033 var vs = this.getSuccess(o);
7034 if(vs === false || vs === 'false'){
7039 for(var i = 0; i < c; i++){
7042 var id = this.getId(n);
7043 for(var j = 0; j < fl; j++){
7045 var v = this.ef[j](n);
7047 Roo.log('missing convert for ' + f.name);
7051 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
7053 var record = new Record(values, id);
7055 records[i] = record;
7061 totalRecords : totalRecords
7066 * Ext JS Library 1.1.1
7067 * Copyright(c) 2006-2007, Ext JS, LLC.
7069 * Originally Released Under LGPL - original licence link has changed is not relivant.
7072 * <script type="text/javascript">
7076 * @class Roo.data.ArrayReader
7077 * @extends Roo.data.DataReader
7078 * Data reader class to create an Array of Roo.data.Record objects from an Array.
7079 * Each element of that Array represents a row of data fields. The
7080 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
7081 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7085 var RecordDef = Roo.data.Record.create([
7086 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7087 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7089 var myReader = new Roo.data.ArrayReader({
7090 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7094 * This would consume an Array like this:
7096 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7098 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7100 * Create a new JsonReader
7101 * @param {Object} meta Metadata configuration options.
7102 * @param {Object} recordType Either an Array of field definition objects
7103 * as specified to {@link Roo.data.Record#create},
7104 * or an {@link Roo.data.Record} object
7105 * created using {@link Roo.data.Record#create}.
7107 Roo.data.ArrayReader = function(meta, recordType){
7108 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7111 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7113 * Create a data block containing Roo.data.Records from an XML document.
7114 * @param {Object} o An Array of row objects which represents the dataset.
7115 * @return {Object} data A data block which is used by an Roo.data.Store object as
7116 * a cache of Roo.data.Records.
7118 readRecords : function(o){
7119 var sid = this.meta ? this.meta.id : null;
7120 var recordType = this.recordType, fields = recordType.prototype.fields;
7123 for(var i = 0; i < root.length; i++){
7126 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7127 for(var j = 0, jlen = fields.length; j < jlen; j++){
7128 var f = fields.items[j];
7129 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7130 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7134 var record = new recordType(values, id);
7136 records[records.length] = record;
7140 totalRecords : records.length
7149 * @class Roo.bootstrap.ComboBox
7150 * @extends Roo.bootstrap.TriggerField
7151 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7153 * Create a new ComboBox.
7154 * @param {Object} config Configuration options
7156 Roo.bootstrap.ComboBox = function(config){
7157 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7161 * Fires when the dropdown list is expanded
7162 * @param {Roo.bootstrap.ComboBox} combo This combo box
7167 * Fires when the dropdown list is collapsed
7168 * @param {Roo.bootstrap.ComboBox} combo This combo box
7172 * @event beforeselect
7173 * Fires before a list item is selected. Return false to cancel the selection.
7174 * @param {Roo.bootstrap.ComboBox} combo This combo box
7175 * @param {Roo.data.Record} record The data record returned from the underlying store
7176 * @param {Number} index The index of the selected item in the dropdown list
7178 'beforeselect' : true,
7181 * Fires when a list item is selected
7182 * @param {Roo.bootstrap.ComboBox} combo This combo box
7183 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7184 * @param {Number} index The index of the selected item in the dropdown list
7188 * @event beforequery
7189 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7190 * The event object passed has these properties:
7191 * @param {Roo.bootstrap.ComboBox} combo This combo box
7192 * @param {String} query The query
7193 * @param {Boolean} forceAll true to force "all" query
7194 * @param {Boolean} cancel true to cancel the query
7195 * @param {Object} e The query event object
7197 'beforequery': true,
7200 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7201 * @param {Roo.bootstrap.ComboBox} combo This combo box
7206 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7207 * @param {Roo.bootstrap.ComboBox} combo This combo box
7208 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7216 this.selectedIndex = -1;
7217 if(this.mode == 'local'){
7218 if(config.queryDelay === undefined){
7219 this.queryDelay = 10;
7221 if(config.minChars === undefined){
7227 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7230 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7231 * rendering into an Roo.Editor, defaults to false)
7234 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7235 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7238 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7241 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7242 * the dropdown list (defaults to undefined, with no header element)
7246 * @cfg {String/Roo.Template} tpl The template to use to render the output
7250 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7252 listWidth: undefined,
7254 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7255 * mode = 'remote' or 'text' if mode = 'local')
7257 displayField: undefined,
7259 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7260 * mode = 'remote' or 'value' if mode = 'local').
7261 * Note: use of a valueField requires the user make a selection
7262 * in order for a value to be mapped.
7264 valueField: undefined,
7268 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7269 * field's data value (defaults to the underlying DOM element's name)
7271 hiddenName: undefined,
7273 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7277 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7279 selectedClass: 'active',
7282 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7286 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7287 * anchor positions (defaults to 'tl-bl')
7289 listAlign: 'tl-bl?',
7291 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7295 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7296 * query specified by the allQuery config option (defaults to 'query')
7298 triggerAction: 'query',
7300 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7301 * (defaults to 4, does not apply if editable = false)
7305 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7306 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7310 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7311 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7315 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7316 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7320 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7321 * when editable = true (defaults to false)
7323 selectOnFocus:false,
7325 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7327 queryParam: 'query',
7329 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7330 * when mode = 'remote' (defaults to 'Loading...')
7332 loadingText: 'Loading...',
7334 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7338 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7342 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7343 * traditional select (defaults to true)
7347 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7351 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7355 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7356 * listWidth has a higher value)
7360 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7361 * allow the user to set arbitrary text into the field (defaults to false)
7363 forceSelection:false,
7365 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7366 * if typeAhead = true (defaults to 250)
7368 typeAheadDelay : 250,
7370 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7371 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7373 valueNotFoundText : undefined,
7375 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7380 * @cfg {Boolean} disableClear Disable showing of clear button.
7382 disableClear : false,
7384 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7386 alwaysQuery : false,
7392 // element that contains real text value.. (when hidden is used..)
7395 initEvents: function(){
7398 throw "can not find store for combo";
7400 this.store = Roo.factory(this.store, Roo.data);
7404 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7407 if(this.hiddenName){
7409 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7411 this.hiddenField.dom.value =
7412 this.hiddenValue !== undefined ? this.hiddenValue :
7413 this.value !== undefined ? this.value : '';
7415 // prevent input submission
7416 this.el.dom.removeAttribute('name');
7417 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7422 // this.el.dom.setAttribute('autocomplete', 'off');
7425 var cls = 'x-combo-list';
7426 this.list = this.el.select('ul',true).first();
7428 //this.list = new Roo.Layer({
7429 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7432 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7433 this.list.setWidth(lw);
7435 this.list.on('mouseover', this.onViewOver, this);
7436 this.list.on('mousemove', this.onViewMove, this);
7439 this.list.swallowEvent('mousewheel');
7440 this.assetHeight = 0;
7443 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7444 this.assetHeight += this.header.getHeight();
7447 this.innerList = this.list.createChild({cls:cls+'-inner'});
7448 this.innerList.on('mouseover', this.onViewOver, this);
7449 this.innerList.on('mousemove', this.onViewMove, this);
7450 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7452 if(this.allowBlank && !this.pageSize && !this.disableClear){
7453 this.footer = this.list.createChild({cls:cls+'-ft'});
7454 this.pageTb = new Roo.Toolbar(this.footer);
7458 this.footer = this.list.createChild({cls:cls+'-ft'});
7459 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7460 {pageSize: this.pageSize});
7464 if (this.pageTb && this.allowBlank && !this.disableClear) {
7466 this.pageTb.add(new Roo.Toolbar.Fill(), {
7467 cls: 'x-btn-icon x-btn-clear',
7473 _this.onSelect(false, -1);
7478 this.assetHeight += this.footer.getHeight();
7483 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
7486 this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
7487 singleSelect:true, store: this.store, selectedClass: this.selectedClass
7489 //this.view.wrapEl.setDisplayed(false);
7490 this.view.on('click', this.onViewClick, this);
7494 this.store.on('beforeload', this.onBeforeLoad, this);
7495 this.store.on('load', this.onLoad, this);
7496 this.store.on('loadexception', this.onLoadException, this);
7499 this.resizer = new Roo.Resizable(this.list, {
7500 pinned:true, handles:'se'
7502 this.resizer.on('resize', function(r, w, h){
7503 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
7505 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
7506 this.restrictHeight();
7508 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
7512 this.editable = true;
7513 this.setEditable(false);
7518 if (typeof(this.events.add.listeners) != 'undefined') {
7520 this.addicon = this.wrap.createChild(
7521 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
7523 this.addicon.on('click', function(e) {
7524 this.fireEvent('add', this);
7527 if (typeof(this.events.edit.listeners) != 'undefined') {
7529 this.editicon = this.wrap.createChild(
7530 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
7532 this.editicon.setStyle('margin-left', '40px');
7534 this.editicon.on('click', function(e) {
7536 // we fire even if inothing is selected..
7537 this.fireEvent('edit', this, this.lastData );
7544 this.keyNav = new Roo.KeyNav(this.inputEl(), {
7546 this.inKeyMode = true;
7550 "down" : function(e){
7551 if(!this.isExpanded()){
7552 this.onTriggerClick();
7554 this.inKeyMode = true;
7559 "enter" : function(e){
7564 "esc" : function(e){
7568 "tab" : function(e){
7571 if(this.fireEvent("specialkey", this, e)){
7572 this.onViewClick(false);
7580 doRelay : function(foo, bar, hname){
7581 if(hname == 'down' || this.scope.isExpanded()){
7582 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
7591 this.queryDelay = Math.max(this.queryDelay || 10,
7592 this.mode == 'local' ? 10 : 250);
7595 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
7598 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
7600 if(this.editable !== false){
7601 this.inputEl().on("keyup", this.onKeyUp, this);
7603 if(this.forceSelection){
7604 this.on('blur', this.doForce, this);
7608 onDestroy : function(){
7610 this.view.setStore(null);
7611 this.view.el.removeAllListeners();
7612 this.view.el.remove();
7613 this.view.purgeListeners();
7616 this.list.dom.innerHTML = '';
7619 this.store.un('beforeload', this.onBeforeLoad, this);
7620 this.store.un('load', this.onLoad, this);
7621 this.store.un('loadexception', this.onLoadException, this);
7623 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
7627 fireKey : function(e){
7628 if(e.isNavKeyPress() && !this.list.isVisible()){
7629 this.fireEvent("specialkey", this, e);
7634 onResize: function(w, h){
7635 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
7637 // if(typeof w != 'number'){
7638 // // we do not handle it!?!?
7641 // var tw = this.trigger.getWidth();
7642 // // tw += this.addicon ? this.addicon.getWidth() : 0;
7643 // // tw += this.editicon ? this.editicon.getWidth() : 0;
7645 // this.inputEl().setWidth( this.adjustWidth('input', x));
7647 // //this.trigger.setStyle('left', x+'px');
7649 // if(this.list && this.listWidth === undefined){
7650 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
7651 // this.list.setWidth(lw);
7652 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7660 * Allow or prevent the user from directly editing the field text. If false is passed,
7661 * the user will only be able to select from the items defined in the dropdown list. This method
7662 * is the runtime equivalent of setting the 'editable' config option at config time.
7663 * @param {Boolean} value True to allow the user to directly edit the field text
7665 setEditable : function(value){
7666 if(value == this.editable){
7669 this.editable = value;
7671 this.inputEl().dom.setAttribute('readOnly', true);
7672 this.inputEl().on('mousedown', this.onTriggerClick, this);
7673 this.inputEl().addClass('x-combo-noedit');
7675 this.inputEl().dom.setAttribute('readOnly', false);
7676 this.inputEl().un('mousedown', this.onTriggerClick, this);
7677 this.inputEl().removeClass('x-combo-noedit');
7682 onBeforeLoad : function(){
7686 //this.innerList.update(this.loadingText ?
7687 // '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
7688 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
7690 this.restrictHeight();
7691 this.selectedIndex = -1;
7695 onLoad : function(){
7699 if(this.store.getCount() > 0){
7701 this.restrictHeight();
7702 if(this.lastQuery == this.allQuery){
7704 this.inputEl().dom.select();
7706 if(!this.selectByValue(this.value, true)){
7707 this.select(0, true);
7711 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
7712 this.taTask.delay(this.typeAheadDelay);
7716 this.onEmptyResults();
7721 onLoadException : function()
7724 Roo.log(this.store.reader.jsonData);
7725 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7727 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7733 onTypeAhead : function(){
7734 if(this.store.getCount() > 0){
7735 var r = this.store.getAt(0);
7736 var newValue = r.data[this.displayField];
7737 var len = newValue.length;
7738 var selStart = this.getRawValue().length;
7740 if(selStart != len){
7741 this.setRawValue(newValue);
7742 this.selectText(selStart, newValue.length);
7748 onSelect : function(record, index){
7749 if(this.fireEvent('beforeselect', this, record, index) !== false){
7750 this.setFromData(index > -1 ? record.data : false);
7752 this.fireEvent('select', this, record, index);
7757 * Returns the currently selected field value or empty string if no value is set.
7758 * @return {String} value The selected value
7760 getValue : function(){
7761 if(this.valueField){
7762 return typeof this.value != 'undefined' ? this.value : '';
7764 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
7769 * Clears any text/value currently set in the field
7771 clearValue : function(){
7772 if(this.hiddenField){
7773 this.hiddenField.dom.value = '';
7776 this.setRawValue('');
7777 this.lastSelectionText = '';
7782 * Sets the specified value into the field. If the value finds a match, the corresponding record text
7783 * will be displayed in the field. If the value does not match the data value of an existing item,
7784 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
7785 * Otherwise the field will be blank (although the value will still be set).
7786 * @param {String} value The value to match
7788 setValue : function(v){
7790 if(this.valueField){
7791 var r = this.findRecord(this.valueField, v);
7793 text = r.data[this.displayField];
7794 }else if(this.valueNotFoundText !== undefined){
7795 text = this.valueNotFoundText;
7798 this.lastSelectionText = text;
7799 if(this.hiddenField){
7800 this.hiddenField.dom.value = v;
7802 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
7806 * @property {Object} the last set data for the element
7811 * Sets the value of the field based on a object which is related to the record format for the store.
7812 * @param {Object} value the value to set as. or false on reset?
7814 setFromData : function(o){
7815 var dv = ''; // display value
7816 var vv = ''; // value value..
7818 if (this.displayField) {
7819 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
7821 // this is an error condition!!!
7822 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
7825 if(this.valueField){
7826 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
7828 if(this.hiddenField){
7829 this.hiddenField.dom.value = vv;
7831 this.lastSelectionText = dv;
7832 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7836 // no hidden field.. - we store the value in 'value', but still display
7837 // display field!!!!
7838 this.lastSelectionText = dv;
7839 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
7846 // overridden so that last data is reset..
7847 this.setValue(this.originalValue);
7848 this.clearInvalid();
7849 this.lastData = false;
7851 this.view.clearSelections();
7855 findRecord : function(prop, value){
7857 if(this.store.getCount() > 0){
7858 this.store.each(function(r){
7859 if(r.data[prop] == value){
7871 // returns hidden if it's set..
7872 if (!this.rendered) {return ''};
7873 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
7877 onViewMove : function(e, t){
7878 this.inKeyMode = false;
7882 onViewOver : function(e, t){
7883 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
7886 var item = this.view.findItemFromChild(t);
7888 var index = this.view.indexOf(item);
7889 this.select(index, false);
7894 onViewClick : function(doFocus)
7896 var index = this.view.getSelectedIndexes()[0];
7897 var r = this.store.getAt(index);
7899 this.onSelect(r, index);
7901 if(doFocus !== false && !this.blockFocus){
7902 this.inputEl().focus();
7907 restrictHeight : function(){
7908 //this.innerList.dom.style.height = '';
7909 //var inner = this.innerList.dom;
7910 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
7911 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
7912 //this.list.beginUpdate();
7913 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
7914 this.list.alignTo(this.inputEl(), this.listAlign);
7915 //this.list.endUpdate();
7919 onEmptyResults : function(){
7924 * Returns true if the dropdown list is expanded, else false.
7926 isExpanded : function(){
7927 return this.list.isVisible();
7931 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
7932 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7933 * @param {String} value The data value of the item to select
7934 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7935 * selected item if it is not currently in view (defaults to true)
7936 * @return {Boolean} True if the value matched an item in the list, else false
7938 selectByValue : function(v, scrollIntoView){
7939 if(v !== undefined && v !== null){
7940 var r = this.findRecord(this.valueField || this.displayField, v);
7942 this.select(this.store.indexOf(r), scrollIntoView);
7950 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
7951 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
7952 * @param {Number} index The zero-based index of the list item to select
7953 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
7954 * selected item if it is not currently in view (defaults to true)
7956 select : function(index, scrollIntoView){
7957 this.selectedIndex = index;
7958 this.view.select(index);
7959 if(scrollIntoView !== false){
7960 var el = this.view.getNode(index);
7962 //this.innerList.scrollChildIntoView(el, false);
7969 selectNext : function(){
7970 var ct = this.store.getCount();
7972 if(this.selectedIndex == -1){
7974 }else if(this.selectedIndex < ct-1){
7975 this.select(this.selectedIndex+1);
7981 selectPrev : function(){
7982 var ct = this.store.getCount();
7984 if(this.selectedIndex == -1){
7986 }else if(this.selectedIndex != 0){
7987 this.select(this.selectedIndex-1);
7993 onKeyUp : function(e){
7994 if(this.editable !== false && !e.isSpecialKey()){
7995 this.lastKey = e.getKey();
7996 this.dqTask.delay(this.queryDelay);
8001 validateBlur : function(){
8002 return !this.list || !this.list.isVisible();
8006 initQuery : function(){
8007 this.doQuery(this.getRawValue());
8011 doForce : function(){
8012 if(this.el.dom.value.length > 0){
8014 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
8020 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
8021 * query allowing the query action to be canceled if needed.
8022 * @param {String} query The SQL query to execute
8023 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
8024 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
8025 * saved in the current store (defaults to false)
8027 doQuery : function(q, forceAll){
8028 if(q === undefined || q === null){
8037 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
8041 forceAll = qe.forceAll;
8042 if(forceAll === true || (q.length >= this.minChars)){
8043 if(this.lastQuery != q || this.alwaysQuery){
8045 if(this.mode == 'local'){
8046 this.selectedIndex = -1;
8048 this.store.clearFilter();
8050 this.store.filter(this.displayField, q);
8054 this.store.baseParams[this.queryParam] = q;
8056 params: this.getParams(q)
8061 this.selectedIndex = -1;
8068 getParams : function(q){
8070 //p[this.queryParam] = q;
8073 p.limit = this.pageSize;
8079 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
8081 collapse : function(){
8082 if(!this.isExpanded()){
8086 Roo.get(document).un('mousedown', this.collapseIf, this);
8087 Roo.get(document).un('mousewheel', this.collapseIf, this);
8088 if (!this.editable) {
8089 Roo.get(document).un('keydown', this.listKeyPress, this);
8091 this.fireEvent('collapse', this);
8095 collapseIf : function(e){
8096 if(!e.within(this.el) && !e.within(this.el)){
8102 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8104 expand : function(){
8106 if(this.isExpanded() || !this.hasFocus){
8109 this.list.alignTo(this.inputEl(), this.listAlign);
8111 Roo.get(document).on('mousedown', this.collapseIf, this);
8112 Roo.get(document).on('mousewheel', this.collapseIf, this);
8113 if (!this.editable) {
8114 Roo.get(document).on('keydown', this.listKeyPress, this);
8117 this.fireEvent('expand', this);
8121 // Implements the default empty TriggerField.onTriggerClick function
8122 onTriggerClick : function()
8124 Roo.log('trigger click');
8129 if(this.isExpanded()){
8131 if (!this.blockFocus) {
8132 this.inputEl().focus();
8136 this.hasFocus = true;
8137 if(this.triggerAction == 'all') {
8138 this.doQuery(this.allQuery, true);
8140 this.doQuery(this.getRawValue());
8142 if (!this.blockFocus) {
8143 this.inputEl().focus();
8147 listKeyPress : function(e)
8149 //Roo.log('listkeypress');
8150 // scroll to first matching element based on key pres..
8151 if (e.isSpecialKey()) {
8154 var k = String.fromCharCode(e.getKey()).toUpperCase();
8157 var csel = this.view.getSelectedNodes();
8158 var cselitem = false;
8160 var ix = this.view.indexOf(csel[0]);
8161 cselitem = this.store.getAt(ix);
8162 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8168 this.store.each(function(v) {
8170 // start at existing selection.
8171 if (cselitem.id == v.id) {
8177 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
8178 match = this.store.indexOf(v);
8184 if (match === false) {
8185 return true; // no more action?
8188 this.view.select(match);
8189 var sn = Roo.get(this.view.getSelectedNodes()[0])
8190 //sn.scrollIntoView(sn.dom.parentNode, false);
8194 * @cfg {Boolean} grow
8198 * @cfg {Number} growMin
8202 * @cfg {Number} growMax
8211 * Ext JS Library 1.1.1
8212 * Copyright(c) 2006-2007, Ext JS, LLC.
8214 * Originally Released Under LGPL - original licence link has changed is not relivant.
8217 * <script type="text/javascript">
8222 * @extends Roo.util.Observable
8223 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8224 * This class also supports single and multi selection modes. <br>
8225 * Create a data model bound view:
8227 var store = new Roo.data.Store(...);
8229 var view = new Roo.View({
8231 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8234 selectedClass: "ydataview-selected",
8238 // listen for node click?
8239 view.on("click", function(vw, index, node, e){
8240 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8244 dataModel.load("foobar.xml");
8246 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8248 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8249 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8251 * Note: old style constructor is still suported (container, template, config)
8255 * @param {Object} config The config object
8258 Roo.View = function(config, depreciated_tpl, depreciated_config){
8260 if (typeof(depreciated_tpl) == 'undefined') {
8261 // new way.. - universal constructor.
8262 Roo.apply(this, config);
8263 this.el = Roo.get(this.el);
8266 this.el = Roo.get(config);
8267 this.tpl = depreciated_tpl;
8268 Roo.apply(this, depreciated_config);
8270 this.wrapEl = this.el.wrap().wrap();
8271 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8274 if(typeof(this.tpl) == "string"){
8275 this.tpl = new Roo.Template(this.tpl);
8277 // support xtype ctors..
8278 this.tpl = new Roo.factory(this.tpl, Roo);
8290 * @event beforeclick
8291 * Fires before a click is processed. Returns false to cancel the default action.
8292 * @param {Roo.View} this
8293 * @param {Number} index The index of the target node
8294 * @param {HTMLElement} node The target node
8295 * @param {Roo.EventObject} e The raw event object
8297 "beforeclick" : true,
8300 * Fires when a template node is clicked.
8301 * @param {Roo.View} this
8302 * @param {Number} index The index of the target node
8303 * @param {HTMLElement} node The target node
8304 * @param {Roo.EventObject} e The raw event object
8309 * Fires when a template node is double clicked.
8310 * @param {Roo.View} this
8311 * @param {Number} index The index of the target node
8312 * @param {HTMLElement} node The target node
8313 * @param {Roo.EventObject} e The raw event object
8317 * @event contextmenu
8318 * Fires when a template node is right clicked.
8319 * @param {Roo.View} this
8320 * @param {Number} index The index of the target node
8321 * @param {HTMLElement} node The target node
8322 * @param {Roo.EventObject} e The raw event object
8324 "contextmenu" : true,
8326 * @event selectionchange
8327 * Fires when the selected nodes change.
8328 * @param {Roo.View} this
8329 * @param {Array} selections Array of the selected nodes
8331 "selectionchange" : true,
8334 * @event beforeselect
8335 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
8336 * @param {Roo.View} this
8337 * @param {HTMLElement} node The node to be selected
8338 * @param {Array} selections Array of currently selected nodes
8340 "beforeselect" : true,
8342 * @event preparedata
8343 * Fires on every row to render, to allow you to change the data.
8344 * @param {Roo.View} this
8345 * @param {Object} data to be rendered (change this)
8347 "preparedata" : true
8355 "click": this.onClick,
8356 "dblclick": this.onDblClick,
8357 "contextmenu": this.onContextMenu,
8361 this.selections = [];
8363 this.cmp = new Roo.CompositeElementLite([]);
8365 this.store = Roo.factory(this.store, Roo.data);
8366 this.setStore(this.store, true);
8369 if ( this.footer && this.footer.xtype) {
8371 var fctr = this.wrapEl.appendChild(document.createElement("div"));
8373 this.footer.dataSource = this.store
8374 this.footer.container = fctr;
8375 this.footer = Roo.factory(this.footer, Roo);
8376 fctr.insertFirst(this.el);
8378 // this is a bit insane - as the paging toolbar seems to detach the el..
8379 // dom.parentNode.parentNode.parentNode
8380 // they get detached?
8384 Roo.View.superclass.constructor.call(this);
8389 Roo.extend(Roo.View, Roo.util.Observable, {
8392 * @cfg {Roo.data.Store} store Data store to load data from.
8397 * @cfg {String|Roo.Element} el The container element.
8402 * @cfg {String|Roo.Template} tpl The template used by this View
8406 * @cfg {String} dataName the named area of the template to use as the data area
8407 * Works with domtemplates roo-name="name"
8411 * @cfg {String} selectedClass The css class to add to selected nodes
8413 selectedClass : "x-view-selected",
8415 * @cfg {String} emptyText The empty text to show when nothing is loaded.
8420 * @cfg {String} text to display on mask (default Loading)
8424 * @cfg {Boolean} multiSelect Allow multiple selection
8426 multiSelect : false,
8428 * @cfg {Boolean} singleSelect Allow single selection
8430 singleSelect: false,
8433 * @cfg {Boolean} toggleSelect - selecting
8435 toggleSelect : false,
8438 * Returns the element this view is bound to.
8439 * @return {Roo.Element}
8448 * Refreshes the view. - called by datachanged on the store. - do not call directly.
8450 refresh : function(){
8453 // if we are using something like 'domtemplate', then
8454 // the what gets used is:
8455 // t.applySubtemplate(NAME, data, wrapping data..)
8456 // the outer template then get' applied with
8457 // the store 'extra data'
8458 // and the body get's added to the
8459 // roo-name="data" node?
8460 // <span class='roo-tpl-{name}'></span> ?????
8464 this.clearSelections();
8467 var records = this.store.getRange();
8468 if(records.length < 1) {
8470 // is this valid?? = should it render a template??
8472 this.el.update(this.emptyText);
8476 if (this.dataName) {
8477 this.el.update(t.apply(this.store.meta)); //????
8478 el = this.el.child('.roo-tpl-' + this.dataName);
8481 for(var i = 0, len = records.length; i < len; i++){
8482 var data = this.prepareData(records[i].data, i, records[i]);
8483 this.fireEvent("preparedata", this, data, i, records[i]);
8484 html[html.length] = Roo.util.Format.trim(
8486 t.applySubtemplate(this.dataName, data, this.store.meta) :
8493 el.update(html.join(""));
8494 this.nodes = el.dom.childNodes;
8495 this.updateIndexes(0);
8499 * Function to override to reformat the data that is sent to
8500 * the template for each node.
8501 * DEPRICATED - use the preparedata event handler.
8502 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
8503 * a JSON object for an UpdateManager bound view).
8505 prepareData : function(data, index, record)
8507 this.fireEvent("preparedata", this, data, index, record);
8511 onUpdate : function(ds, record){
8512 this.clearSelections();
8513 var index = this.store.indexOf(record);
8514 var n = this.nodes[index];
8515 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
8516 n.parentNode.removeChild(n);
8517 this.updateIndexes(index, index);
8523 onAdd : function(ds, records, index)
8525 this.clearSelections();
8526 if(this.nodes.length == 0){
8530 var n = this.nodes[index];
8531 for(var i = 0, len = records.length; i < len; i++){
8532 var d = this.prepareData(records[i].data, i, records[i]);
8534 this.tpl.insertBefore(n, d);
8537 this.tpl.append(this.el, d);
8540 this.updateIndexes(index);
8543 onRemove : function(ds, record, index){
8544 this.clearSelections();
8545 var el = this.dataName ?
8546 this.el.child('.roo-tpl-' + this.dataName) :
8548 el.dom.removeChild(this.nodes[index]);
8549 this.updateIndexes(index);
8553 * Refresh an individual node.
8554 * @param {Number} index
8556 refreshNode : function(index){
8557 this.onUpdate(this.store, this.store.getAt(index));
8560 updateIndexes : function(startIndex, endIndex){
8561 var ns = this.nodes;
8562 startIndex = startIndex || 0;
8563 endIndex = endIndex || ns.length - 1;
8564 for(var i = startIndex; i <= endIndex; i++){
8565 ns[i].nodeIndex = i;
8570 * Changes the data store this view uses and refresh the view.
8571 * @param {Store} store
8573 setStore : function(store, initial){
8574 if(!initial && this.store){
8575 this.store.un("datachanged", this.refresh);
8576 this.store.un("add", this.onAdd);
8577 this.store.un("remove", this.onRemove);
8578 this.store.un("update", this.onUpdate);
8579 this.store.un("clear", this.refresh);
8580 this.store.un("beforeload", this.onBeforeLoad);
8581 this.store.un("load", this.onLoad);
8582 this.store.un("loadexception", this.onLoad);
8586 store.on("datachanged", this.refresh, this);
8587 store.on("add", this.onAdd, this);
8588 store.on("remove", this.onRemove, this);
8589 store.on("update", this.onUpdate, this);
8590 store.on("clear", this.refresh, this);
8591 store.on("beforeload", this.onBeforeLoad, this);
8592 store.on("load", this.onLoad, this);
8593 store.on("loadexception", this.onLoad, this);
8601 * onbeforeLoad - masks the loading area.
8604 onBeforeLoad : function()
8607 this.el.mask(this.mask ? this.mask : "Loading" );
8609 onLoad : function ()
8616 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
8617 * @param {HTMLElement} node
8618 * @return {HTMLElement} The template node
8620 findItemFromChild : function(node){
8621 var el = this.dataName ?
8622 this.el.child('.roo-tpl-' + this.dataName,true) :
8625 if(!node || node.parentNode == el){
8628 var p = node.parentNode;
8629 while(p && p != el){
8630 if(p.parentNode == el){
8639 onClick : function(e){
8640 var item = this.findItemFromChild(e.getTarget());
8642 var index = this.indexOf(item);
8643 if(this.onItemClick(item, index, e) !== false){
8644 this.fireEvent("click", this, index, item, e);
8647 this.clearSelections();
8652 onContextMenu : function(e){
8653 var item = this.findItemFromChild(e.getTarget());
8655 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
8660 onDblClick : function(e){
8661 var item = this.findItemFromChild(e.getTarget());
8663 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
8667 onItemClick : function(item, index, e)
8669 if(this.fireEvent("beforeclick", this, index, item, e) === false){
8672 if (this.toggleSelect) {
8673 var m = this.isSelected(item) ? 'unselect' : 'select';
8676 _t[m](item, true, false);
8679 if(this.multiSelect || this.singleSelect){
8680 if(this.multiSelect && e.shiftKey && this.lastSelection){
8681 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
8683 this.select(item, this.multiSelect && e.ctrlKey);
8684 this.lastSelection = item;
8692 * Get the number of selected nodes.
8695 getSelectionCount : function(){
8696 return this.selections.length;
8700 * Get the currently selected nodes.
8701 * @return {Array} An array of HTMLElements
8703 getSelectedNodes : function(){
8704 return this.selections;
8708 * Get the indexes of the selected nodes.
8711 getSelectedIndexes : function(){
8712 var indexes = [], s = this.selections;
8713 for(var i = 0, len = s.length; i < len; i++){
8714 indexes.push(s[i].nodeIndex);
8720 * Clear all selections
8721 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
8723 clearSelections : function(suppressEvent){
8724 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
8725 this.cmp.elements = this.selections;
8726 this.cmp.removeClass(this.selectedClass);
8727 this.selections = [];
8729 this.fireEvent("selectionchange", this, this.selections);
8735 * Returns true if the passed node is selected
8736 * @param {HTMLElement/Number} node The node or node index
8739 isSelected : function(node){
8740 var s = this.selections;
8744 node = this.getNode(node);
8745 return s.indexOf(node) !== -1;
8750 * @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
8751 * @param {Boolean} keepExisting (optional) true to keep existing selections
8752 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8754 select : function(nodeInfo, keepExisting, suppressEvent){
8755 if(nodeInfo instanceof Array){
8757 this.clearSelections(true);
8759 for(var i = 0, len = nodeInfo.length; i < len; i++){
8760 this.select(nodeInfo[i], true, true);
8764 var node = this.getNode(nodeInfo);
8765 if(!node || this.isSelected(node)){
8766 return; // already selected.
8769 this.clearSelections(true);
8771 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
8772 Roo.fly(node).addClass(this.selectedClass);
8773 this.selections.push(node);
8775 this.fireEvent("selectionchange", this, this.selections);
8783 * @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
8784 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
8785 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
8787 unselect : function(nodeInfo, keepExisting, suppressEvent)
8789 if(nodeInfo instanceof Array){
8790 Roo.each(this.selections, function(s) {
8791 this.unselect(s, nodeInfo);
8795 var node = this.getNode(nodeInfo);
8796 if(!node || !this.isSelected(node)){
8797 Roo.log("not selected");
8798 return; // not selected.
8802 Roo.each(this.selections, function(s) {
8804 Roo.fly(node).removeClass(this.selectedClass);
8811 this.selections= ns;
8812 this.fireEvent("selectionchange", this, this.selections);
8816 * Gets a template node.
8817 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8818 * @return {HTMLElement} The node or null if it wasn't found
8820 getNode : function(nodeInfo){
8821 if(typeof nodeInfo == "string"){
8822 return document.getElementById(nodeInfo);
8823 }else if(typeof nodeInfo == "number"){
8824 return this.nodes[nodeInfo];
8830 * Gets a range template nodes.
8831 * @param {Number} startIndex
8832 * @param {Number} endIndex
8833 * @return {Array} An array of nodes
8835 getNodes : function(start, end){
8836 var ns = this.nodes;
8838 end = typeof end == "undefined" ? ns.length - 1 : end;
8841 for(var i = start; i <= end; i++){
8845 for(var i = start; i >= end; i--){
8853 * Finds the index of the passed node
8854 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
8855 * @return {Number} The index of the node or -1
8857 indexOf : function(node){
8858 node = this.getNode(node);
8859 if(typeof node.nodeIndex == "number"){
8860 return node.nodeIndex;
8862 var ns = this.nodes;
8863 for(var i = 0, len = ns.length; i < len; i++){
8874 * based on jquery fullcalendar
8878 Roo.bootstrap = Roo.bootstrap || {};
8880 * @class Roo.bootstrap.Calendar
8881 * @extends Roo.bootstrap.Component
8882 * Bootstrap Calendar class
8883 * @cfg {Boolean} loadMask (true|false) default false
8886 * Create a new Container
8887 * @param {Object} config The config object
8892 Roo.bootstrap.Calendar = function(config){
8893 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
8897 * Fires when a date is selected
8898 * @param {DatePicker} this
8899 * @param {Date} date The selected date
8903 * @event monthchange
8904 * Fires when the displayed month changes
8905 * @param {DatePicker} this
8906 * @param {Date} date The selected month
8908 'monthchange': true,
8911 * Fires when mouse over an event
8912 * @param {Calendar} this
8913 * @param {event} Event
8918 * Fires when the mouse leaves an
8919 * @param {Calendar} this
8925 * Fires when the mouse click an
8926 * @param {Calendar} this
8935 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
8938 * @cfg {Number} startDay
8939 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
8945 getAutoCreate : function(){
8948 var fc_button = function(name, corner, style, content ) {
8949 return Roo.apply({},{
8951 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
8953 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
8956 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
8964 style : 'width:100%',
8971 cls : 'fc-header-left',
8973 fc_button('prev', 'left', 'arrow', '‹' ),
8974 fc_button('next', 'right', 'arrow', '›' ),
8975 { tag: 'span', cls: 'fc-header-space' },
8976 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
8984 cls : 'fc-header-center',
8988 cls: 'fc-header-title',
8991 html : 'month / year'
8999 cls : 'fc-header-right',
9001 /* fc_button('month', 'left', '', 'month' ),
9002 fc_button('week', '', '', 'week' ),
9003 fc_button('day', 'right', '', 'day' )
9015 var cal_heads = function() {
9017 // fixme - handle this.
9019 for (var i =0; i < Date.dayNames.length; i++) {
9020 var d = Date.dayNames[i];
9023 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
9024 html : d.substring(0,3)
9028 ret[0].cls += ' fc-first';
9029 ret[6].cls += ' fc-last';
9032 var cal_cell = function(n) {
9035 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
9040 cls: 'fc-day-number',
9044 cls: 'fc-day-content',
9048 style: 'position: relative;' // height: 17px;
9060 var cal_rows = function() {
9063 for (var r = 0; r < 6; r++) {
9070 for (var i =0; i < Date.dayNames.length; i++) {
9071 var d = Date.dayNames[i];
9072 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
9075 row.cn[0].cls+=' fc-first';
9076 row.cn[0].cn[0].style = 'min-height:90px';
9077 row.cn[6].cls+=' fc-last';
9081 ret[0].cls += ' fc-first';
9082 ret[4].cls += ' fc-prev-last';
9083 ret[5].cls += ' fc-last';
9090 cls: 'fc-border-separate',
9091 style : 'width:100%',
9099 cls : 'fc-first fc-last',
9118 style : "position: relative;",
9121 cls : 'fc-view fc-view-month fc-grid',
9122 style : 'position: relative',
9123 unselectable : 'on',
9126 cls : 'fc-event-container',
9127 style : 'position:absolute;z-index:8;top:0;left:0;'
9145 initEvents : function()
9148 throw "can not find store for calendar";
9154 style: "text-align:center",
9158 style: "background-color:white;width:50%;margin:250 auto",
9162 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
9173 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
9175 var size = this.el.select('.fc-content', true).first().getSize();
9176 this.maskEl.setSize(size.width, size.height);
9177 this.maskEl.enableDisplayMode("block");
9182 this.store = Roo.factory(this.store, Roo.data);
9183 this.store.on('load', this.onLoad, this);
9184 this.store.on('beforeload', this.onBeforeLoad, this);
9188 this.cells = this.el.select('.fc-day',true);
9189 //Roo.log(this.cells);
9190 this.textNodes = this.el.query('.fc-day-number');
9191 this.cells.addClassOnOver('fc-state-hover');
9193 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
9194 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
9195 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
9196 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
9198 this.on('monthchange', this.onMonthChange, this);
9200 // this.update(new Date().clearTime());
9203 resize : function() {
9204 var sz = this.el.getSize();
9206 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
9207 this.el.select('.fc-day-content div',true).setHeight(34);
9212 showPrevMonth : function(e){
9213 this.update(this.activeDate.add("mo", -1));
9215 showToday : function(e){
9216 this.update(new Date().clearTime());
9219 showNextMonth : function(e){
9220 this.update(this.activeDate.add("mo", 1));
9224 showPrevYear : function(){
9225 this.update(this.activeDate.add("y", -1));
9229 showNextYear : function(){
9230 this.update(this.activeDate.add("y", 1));
9235 update : function(date)
9237 var vd = this.activeDate;
9238 this.activeDate = date;
9239 // if(vd && this.el){
9240 // var t = date.getTime();
9241 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
9242 // Roo.log('using add remove');
9244 // this.fireEvent('monthchange', this, date);
9246 // this.cells.removeClass("fc-state-highlight");
9247 // this.cells.each(function(c){
9248 // if(c.dateValue == t){
9249 // c.addClass("fc-state-highlight");
9250 // setTimeout(function(){
9251 // try{c.dom.firstChild.focus();}catch(e){}
9261 var days = date.getDaysInMonth();
9263 var firstOfMonth = date.getFirstDateOfMonth();
9264 var startingPos = firstOfMonth.getDay()-this.startDay;
9266 if(startingPos < this.startDay){
9270 var pm = date.add(Date.MONTH, -1);
9271 var prevStart = pm.getDaysInMonth()-startingPos;
9273 this.cells = this.el.select('.fc-day',true);
9274 this.textNodes = this.el.query('.fc-day-number');
9275 this.cells.addClassOnOver('fc-state-hover');
9277 var cells = this.cells.elements;
9278 var textEls = this.textNodes;
9280 Roo.each(cells, function(cell){
9281 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
9284 days += startingPos;
9286 // convert everything to numbers so it's fast
9288 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
9291 //Roo.log(prevStart);
9293 var today = new Date().clearTime().getTime();
9294 var sel = date.clearTime().getTime();
9295 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
9296 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
9297 var ddMatch = this.disabledDatesRE;
9298 var ddText = this.disabledDatesText;
9299 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
9300 var ddaysText = this.disabledDaysText;
9301 var format = this.format;
9303 var setCellClass = function(cal, cell){
9305 //Roo.log('set Cell Class');
9307 var t = d.getTime();
9313 cell.className += " fc-today";
9314 cell.className += " fc-state-highlight";
9315 cell.title = cal.todayText;
9318 // disable highlight in other month..
9319 //cell.className += " fc-state-highlight";
9324 cell.className = " fc-state-disabled";
9325 cell.title = cal.minText;
9329 cell.className = " fc-state-disabled";
9330 cell.title = cal.maxText;
9334 if(ddays.indexOf(d.getDay()) != -1){
9335 cell.title = ddaysText;
9336 cell.className = " fc-state-disabled";
9339 if(ddMatch && format){
9340 var fvalue = d.dateFormat(format);
9341 if(ddMatch.test(fvalue)){
9342 cell.title = ddText.replace("%0", fvalue);
9343 cell.className = " fc-state-disabled";
9347 if (!cell.initialClassName) {
9348 cell.initialClassName = cell.dom.className;
9351 cell.dom.className = cell.initialClassName + ' ' + cell.className;
9356 for(; i < startingPos; i++) {
9357 textEls[i].innerHTML = (++prevStart);
9358 d.setDate(d.getDate()+1);
9360 cells[i].className = "fc-past fc-other-month";
9361 setCellClass(this, cells[i]);
9366 for(; i < days; i++){
9367 intDay = i - startingPos + 1;
9368 textEls[i].innerHTML = (intDay);
9369 d.setDate(d.getDate()+1);
9371 cells[i].className = ''; // "x-date-active";
9372 setCellClass(this, cells[i]);
9376 for(; i < 42; i++) {
9377 textEls[i].innerHTML = (++extraDays);
9378 d.setDate(d.getDate()+1);
9380 cells[i].className = "fc-future fc-other-month";
9381 setCellClass(this, cells[i]);
9384 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
9386 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
9388 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
9389 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
9392 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
9393 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
9396 this.fireEvent('monthchange', this, date);
9400 if(!this.internalRender){
9401 var main = this.el.dom.firstChild;
9402 var w = main.offsetWidth;
9403 this.el.setWidth(w + this.el.getBorderWidth("lr"));
9404 Roo.fly(main).setWidth(w);
9405 this.internalRender = true;
9406 // opera does not respect the auto grow header center column
9407 // then, after it gets a width opera refuses to recalculate
9408 // without a second pass
9409 if(Roo.isOpera && !this.secondPass){
9410 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
9411 this.secondPass = true;
9412 this.update.defer(10, this, [date]);
9419 findCell : function(dt) {
9420 dt = dt.clearTime().getTime();
9422 this.cells.each(function(c){
9423 //Roo.log("check " +c.dateValue + '?=' + dt);
9424 if(c.dateValue == dt){
9434 findCells : function(ev) {
9435 var s = ev.start.clone().clearTime().getTime();
9437 var e= ev.end.clone().clearTime().getTime();
9440 this.cells.each(function(c){
9441 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
9443 if(c.dateValue > e){
9446 if(c.dateValue < s){
9455 findBestRow: function(cells)
9459 for (var i =0 ; i < cells.length;i++) {
9460 ret = Math.max(cells[i].rows || 0,ret);
9467 addItem : function(ev)
9469 // look for vertical location slot in
9470 var cells = this.findCells(ev);
9472 ev.row = this.findBestRow(cells);
9474 // work out the location.
9478 for(var i =0; i < cells.length; i++) {
9486 if (crow.start.getY() == cells[i].getY()) {
9488 crow.end = cells[i];
9504 for (var i = 0; i < cells.length;i++) {
9505 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
9509 this.calevents.push(ev);
9512 clearEvents: function() {
9514 if(!this.calevents){
9518 Roo.each(this.cells.elements, function(c){
9522 Roo.each(this.calevents, function(e) {
9523 Roo.each(e.els, function(el) {
9524 el.un('mouseenter' ,this.onEventEnter, this);
9525 el.un('mouseleave' ,this.onEventLeave, this);
9532 renderEvents: function()
9534 // first make sure there is enough space..
9536 this.cells.each(function(c) {
9538 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
9541 for (var e = 0; e < this.calevents.length; e++) {
9542 var ev = this.calevents[e];
9543 var cells = ev.cells;
9546 for(var i =0; i < rows.length; i++) {
9549 // how many rows should it span..
9552 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
9553 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
9555 unselectable : "on",
9558 cls: 'fc-event-inner',
9562 cls: 'fc-event-time',
9563 html : cells.length > 1 ? '' : ev.time
9567 cls: 'fc-event-title',
9568 html : String.format('{0}', ev.title)
9575 cls: 'ui-resizable-handle ui-resizable-e',
9576 html : '  '
9582 cfg.cls += ' fc-event-start';
9584 if ((i+1) == rows.length) {
9585 cfg.cls += ' fc-event-end';
9588 var ctr = this.el.select('.fc-event-container',true).first();
9589 var cg = ctr.createChild(cfg);
9591 cg.on('mouseenter' ,this.onEventEnter, this, ev);
9592 cg.on('mouseleave' ,this.onEventLeave, this, ev);
9593 cg.on('click', this.onEventClick, this, ev);
9597 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
9598 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
9600 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
9601 cg.setWidth(ebox.right - sbox.x -2);
9609 onEventEnter: function (e, el,event,d) {
9610 this.fireEvent('evententer', this, el, event);
9613 onEventLeave: function (e, el,event,d) {
9614 this.fireEvent('eventleave', this, el, event);
9617 onEventClick: function (e, el,event,d) {
9618 this.fireEvent('eventclick', this, el, event);
9621 onMonthChange: function () {
9627 this.calevents = [];
9629 if(this.store.getCount() > 0){
9630 this.store.data.each(function(d){
9633 start: new Date(d.data.start_dt),
9634 end : new Date(d.data.end_dt),
9635 time : d.data.start_time,
9636 title : d.data.title,
9637 description : d.data.description,
9638 venue : d.data.venue
9643 this.renderEvents();
9650 onBeforeLoad: function()
9669 * @class Roo.bootstrap.Popover
9670 * @extends Roo.bootstrap.Component
9671 * Bootstrap Popover class
9672 * @cfg {String} html contents of the popover (or false to use children..)
9673 * @cfg {String} title of popover (or false to hide)
9674 * @cfg {String} placement how it is placed
9675 * @cfg {String} trigger click || hover (or false to trigger manually)
9676 * @cfg {String} over what (parent or false to trigger manually.)
9679 * Create a new Popover
9680 * @param {Object} config The config object
9683 Roo.bootstrap.Popover = function(config){
9684 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
9687 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
9689 title: 'Fill in a title',
9692 placement : 'right',
9693 trigger : 'hover', // hover
9697 can_build_overlaid : false,
9699 getChildContainer : function()
9701 return this.el.select('.popover-content',true).first();
9704 getAutoCreate : function(){
9705 Roo.log('make popover?');
9707 cls : 'popover roo-dynamic',
9708 style: 'display:block',
9714 cls : 'popover-inner',
9718 cls: 'popover-title',
9722 cls : 'popover-content',
9733 setTitle: function(str)
9735 this.el.select('.popover-title',true).first().dom.innerHTML = str;
9737 setContent: function(str)
9739 this.el.select('.popover-content',true).first().dom.innerHTML = str;
9741 // as it get's added to the bottom of the page.
9742 onRender : function(ct, position)
9744 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
9746 var cfg = Roo.apply({}, this.getAutoCreate());
9750 cfg.cls += ' ' + this.cls;
9753 cfg.style = this.style;
9755 Roo.log("adding to ")
9756 this.el = Roo.get(document.body).createChild(cfg, position);
9762 initEvents : function()
9764 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
9765 this.el.enableDisplayMode('block');
9767 if (this.over === false) {
9770 if (this.triggers === false) {
9773 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9774 var triggers = this.trigger ? this.trigger.split(' ') : [];
9775 Roo.each(triggers, function(trigger) {
9777 if (trigger == 'click') {
9778 on_el.on('click', this.toggle, this);
9779 } else if (trigger != 'manual') {
9780 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
9781 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
9783 on_el.on(eventIn ,this.enter, this);
9784 on_el.on(eventOut, this.leave, this);
9795 toggle : function () {
9796 this.hoverState == 'in' ? this.leave() : this.enter();
9799 enter : function () {
9802 clearTimeout(this.timeout);
9804 this.hoverState = 'in'
9806 if (!this.delay || !this.delay.show) {
9811 this.timeout = setTimeout(function () {
9812 if (_t.hoverState == 'in') {
9817 leave : function() {
9818 clearTimeout(this.timeout);
9820 this.hoverState = 'out'
9822 if (!this.delay || !this.delay.hide) {
9827 this.timeout = setTimeout(function () {
9828 if (_t.hoverState == 'out') {
9834 show : function (on_el)
9837 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
9840 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
9841 if (this.html !== false) {
9842 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
9844 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
9845 if (!this.title.length) {
9846 this.el.select('.popover-title',true).hide();
9849 var placement = typeof this.placement == 'function' ?
9850 this.placement.call(this, this.el, on_el) :
9853 var autoToken = /\s?auto?\s?/i;
9854 var autoPlace = autoToken.test(placement);
9856 placement = placement.replace(autoToken, '') || 'top';
9860 //this.el.setXY([0,0]);
9862 this.el.dom.style.display='block';
9863 this.el.addClass(placement);
9865 //this.el.appendTo(on_el);
9867 var p = this.getPosition();
9868 var box = this.el.getBox();
9873 var align = Roo.bootstrap.Popover.alignment[placement]
9874 this.el.alignTo(on_el, align[0],align[1]);
9875 //var arrow = this.el.select('.arrow',true).first();
9876 //arrow.set(align[2],
9878 this.el.addClass('in');
9879 this.hoverState = null;
9881 if (this.el.hasClass('fade')) {
9888 this.el.setXY([0,0]);
9889 this.el.removeClass('in');
9896 Roo.bootstrap.Popover.alignment = {
9897 'left' : ['r-l', [-10,0], 'right'],
9898 'right' : ['l-r', [10,0], 'left'],
9899 'bottom' : ['t-b', [0,10], 'top'],
9900 'top' : [ 'b-t', [0,-10], 'bottom']
9911 * @class Roo.bootstrap.Progress
9912 * @extends Roo.bootstrap.Component
9913 * Bootstrap Progress class
9914 * @cfg {Boolean} striped striped of the progress bar
9915 * @cfg {Boolean} active animated of the progress bar
9919 * Create a new Progress
9920 * @param {Object} config The config object
9923 Roo.bootstrap.Progress = function(config){
9924 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
9927 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
9932 getAutoCreate : function(){
9940 cfg.cls += ' progress-striped';
9944 cfg.cls += ' active';
9963 * @class Roo.bootstrap.ProgressBar
9964 * @extends Roo.bootstrap.Component
9965 * Bootstrap ProgressBar class
9966 * @cfg {Number} aria_valuenow aria-value now
9967 * @cfg {Number} aria_valuemin aria-value min
9968 * @cfg {Number} aria_valuemax aria-value max
9969 * @cfg {String} label label for the progress bar
9970 * @cfg {String} panel (success | info | warning | danger )
9971 * @cfg {String} role role of the progress bar
9972 * @cfg {String} sr_only text
9976 * Create a new ProgressBar
9977 * @param {Object} config The config object
9980 Roo.bootstrap.ProgressBar = function(config){
9981 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
9984 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
9988 aria_valuemax : 100,
9994 getAutoCreate : function()
9999 cls: 'progress-bar',
10000 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
10012 cfg.role = this.role;
10015 if(this.aria_valuenow){
10016 cfg['aria-valuenow'] = this.aria_valuenow;
10019 if(this.aria_valuemin){
10020 cfg['aria-valuemin'] = this.aria_valuemin;
10023 if(this.aria_valuemax){
10024 cfg['aria-valuemax'] = this.aria_valuemax;
10027 if(this.label && !this.sr_only){
10028 cfg.html = this.label;
10032 cfg.cls += ' progress-bar-' + this.panel;
10038 update : function(aria_valuenow)
10040 this.aria_valuenow = aria_valuenow;
10042 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
10057 * @class Roo.bootstrap.TabPanel
10058 * @extends Roo.bootstrap.Component
10059 * Bootstrap TabPanel class
10060 * @cfg {Boolean} active panel active
10061 * @cfg {String} html panel content
10062 * @cfg {String} tabId tab relate id
10066 * Create a new TabPanel
10067 * @param {Object} config The config object
10070 Roo.bootstrap.TabPanel = function(config){
10071 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
10074 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
10080 getAutoCreate : function(){
10084 html: this.html || ''
10088 cfg.cls += ' active';
10092 cfg.tabId = this.tabId;
10110 * @class Roo.bootstrap.DateField
10111 * @extends Roo.bootstrap.Input
10112 * Bootstrap DateField class
10113 * @cfg {Number} weekStart default 0
10114 * @cfg {Number} weekStart default 0
10115 * @cfg {Number} viewMode default empty, (months|years)
10116 * @cfg {Number} minViewMode default empty, (months|years)
10117 * @cfg {Number} startDate default -Infinity
10118 * @cfg {Number} endDate default Infinity
10119 * @cfg {Boolean} todayHighlight default false
10120 * @cfg {Boolean} todayBtn default false
10121 * @cfg {Boolean} calendarWeeks default false
10122 * @cfg {Object} daysOfWeekDisabled default empty
10124 * @cfg {Boolean} keyboardNavigation default true
10125 * @cfg {String} language default en
10128 * Create a new DateField
10129 * @param {Object} config The config object
10132 Roo.bootstrap.DateField = function(config){
10133 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
10136 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
10139 * @cfg {String} format
10140 * The default date format string which can be overriden for localization support. The format must be
10141 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10145 * @cfg {String} altFormats
10146 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
10147 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
10149 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
10157 todayHighlight : false,
10163 keyboardNavigation: true,
10165 calendarWeeks: false,
10167 startDate: -Infinity,
10171 daysOfWeekDisabled: [],
10175 UTCDate: function()
10177 return new Date(Date.UTC.apply(Date, arguments));
10180 UTCToday: function()
10182 var today = new Date();
10183 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
10186 getDate: function() {
10187 var d = this.getUTCDate();
10188 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
10191 getUTCDate: function() {
10195 setDate: function(d) {
10196 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
10199 setUTCDate: function(d) {
10201 this.setValue(this.formatDate(this.date));
10204 onRender: function(ct, position)
10207 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
10209 this.language = this.language || 'en';
10210 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
10211 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
10213 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
10214 this.format = this.format || 'm/d/y';
10215 this.isInline = false;
10216 this.isInput = true;
10217 this.component = this.el.select('.add-on', true).first() || false;
10218 this.component = (this.component && this.component.length === 0) ? false : this.component;
10219 this.hasInput = this.component && this.inputEL().length;
10221 if (typeof(this.minViewMode === 'string')) {
10222 switch (this.minViewMode) {
10224 this.minViewMode = 1;
10227 this.minViewMode = 2;
10230 this.minViewMode = 0;
10235 if (typeof(this.viewMode === 'string')) {
10236 switch (this.viewMode) {
10249 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
10251 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10253 this.picker().on('mousedown', this.onMousedown, this);
10254 this.picker().on('click', this.onClick, this);
10256 this.picker().addClass('datepicker-dropdown');
10258 this.startViewMode = this.viewMode;
10261 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
10262 if(!this.calendarWeeks){
10267 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
10268 v.attr('colspan', function(i, val){
10269 return parseInt(val) + 1;
10274 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
10276 this.setStartDate(this.startDate);
10277 this.setEndDate(this.endDate);
10279 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
10286 if(this.isInline) {
10291 picker : function()
10293 return this.el.select('.datepicker', true).first();
10296 fillDow: function()
10298 var dowCnt = this.weekStart;
10307 if(this.calendarWeeks){
10315 while (dowCnt < this.weekStart + 7) {
10319 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
10323 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
10326 fillMonths: function()
10329 var months = this.picker().select('>.datepicker-months td', true).first();
10331 months.dom.innerHTML = '';
10337 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
10340 months.createChild(month);
10345 update: function(){
10347 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
10349 if (this.date < this.startDate) {
10350 this.viewDate = new Date(this.startDate);
10351 } else if (this.date > this.endDate) {
10352 this.viewDate = new Date(this.endDate);
10354 this.viewDate = new Date(this.date);
10361 var d = new Date(this.viewDate),
10362 year = d.getUTCFullYear(),
10363 month = d.getUTCMonth(),
10364 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
10365 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
10366 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
10367 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
10368 currentDate = this.date && this.date.valueOf(),
10369 today = this.UTCToday();
10371 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
10373 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
10375 // this.picker.select('>tfoot th.today').
10376 // .text(dates[this.language].today)
10377 // .toggle(this.todayBtn !== false);
10379 this.updateNavArrows();
10382 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
10384 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
10386 prevMonth.setUTCDate(day);
10388 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
10390 var nextMonth = new Date(prevMonth);
10392 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
10394 nextMonth = nextMonth.valueOf();
10396 var fillMonths = false;
10398 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
10400 while(prevMonth.valueOf() < nextMonth) {
10403 if (prevMonth.getUTCDay() === this.weekStart) {
10405 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
10413 if(this.calendarWeeks){
10414 // ISO 8601: First week contains first thursday.
10415 // ISO also states week starts on Monday, but we can be more abstract here.
10417 // Start of current week: based on weekstart/current date
10418 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
10419 // Thursday of this week
10420 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
10421 // First Thursday of year, year from thursday
10422 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
10423 // Calendar week: ms between thursdays, div ms per day, div 7 days
10424 calWeek = (th - yth) / 864e5 / 7 + 1;
10426 fillMonths.cn.push({
10434 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
10436 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
10439 if (this.todayHighlight &&
10440 prevMonth.getUTCFullYear() == today.getFullYear() &&
10441 prevMonth.getUTCMonth() == today.getMonth() &&
10442 prevMonth.getUTCDate() == today.getDate()) {
10443 clsName += ' today';
10446 if (currentDate && prevMonth.valueOf() === currentDate) {
10447 clsName += ' active';
10450 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
10451 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
10452 clsName += ' disabled';
10455 fillMonths.cn.push({
10457 cls: 'day ' + clsName,
10458 html: prevMonth.getDate()
10461 prevMonth.setDate(prevMonth.getDate()+1);
10464 var currentYear = this.date && this.date.getUTCFullYear();
10465 var currentMonth = this.date && this.date.getUTCMonth();
10467 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
10469 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
10470 v.removeClass('active');
10472 if(currentYear === year && k === currentMonth){
10473 v.addClass('active');
10476 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
10477 v.addClass('disabled');
10483 year = parseInt(year/10, 10) * 10;
10485 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
10487 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
10490 for (var i = -1; i < 11; i++) {
10491 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
10493 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
10501 showMode: function(dir) {
10503 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
10505 Roo.each(this.picker().select('>div',true).elements, function(v){
10506 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10509 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
10514 if(this.isInline) return;
10516 this.picker().removeClass(['bottom', 'top']);
10518 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
10520 * place to the top of element!
10524 this.picker().addClass('top');
10525 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10530 this.picker().addClass('bottom');
10532 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
10535 parseDate : function(value){
10536 if(!value || value instanceof Date){
10539 var v = Date.parseDate(value, this.format);
10540 if (!v && this.useIso) {
10541 v = Date.parseDate(value, 'Y-m-d');
10543 if(!v && this.altFormats){
10544 if(!this.altFormatsArray){
10545 this.altFormatsArray = this.altFormats.split("|");
10547 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
10548 v = Date.parseDate(value, this.altFormatsArray[i]);
10554 formatDate : function(date, fmt){
10555 return (!date || !(date instanceof Date)) ?
10556 date : date.dateFormat(fmt || this.format);
10559 onFocus : function()
10561 Roo.bootstrap.DateField.superclass.onFocus.call(this);
10565 onBlur : function()
10567 Roo.bootstrap.DateField.superclass.onBlur.call(this);
10573 this.picker().show();
10580 if(this.isInline) return;
10581 this.picker().hide();
10582 this.viewMode = this.startViewMode;
10587 onMousedown: function(e){
10588 e.stopPropagation();
10589 e.preventDefault();
10592 keyup: function(e){
10593 Roo.bootstrap.DateField.superclass.keyup.call(this);
10598 fireKey: function(e){
10599 if (!this.picker().isVisible()){
10600 if (e.keyCode == 27) // allow escape to hide and re-show picker
10604 var dateChanged = false,
10606 newDate, newViewDate;
10610 e.preventDefault();
10614 if (!this.keyboardNavigation) break;
10615 dir = e.keyCode == 37 ? -1 : 1;
10618 newDate = this.moveYear(this.date, dir);
10619 newViewDate = this.moveYear(this.viewDate, dir);
10620 } else if (e.shiftKey){
10621 newDate = this.moveMonth(this.date, dir);
10622 newViewDate = this.moveMonth(this.viewDate, dir);
10624 newDate = new Date(this.date);
10625 newDate.setUTCDate(this.date.getUTCDate() + dir);
10626 newViewDate = new Date(this.viewDate);
10627 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
10629 if (this.dateWithinRange(newDate)){
10630 this.date = newDate;
10631 this.viewDate = newViewDate;
10632 this.setValue(this.formatDate(this.date));
10634 e.preventDefault();
10635 dateChanged = true;
10640 if (!this.keyboardNavigation) break;
10641 dir = e.keyCode == 38 ? -1 : 1;
10643 newDate = this.moveYear(this.date, dir);
10644 newViewDate = this.moveYear(this.viewDate, dir);
10645 } else if (e.shiftKey){
10646 newDate = this.moveMonth(this.date, dir);
10647 newViewDate = this.moveMonth(this.viewDate, dir);
10649 newDate = new Date(this.date);
10650 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
10651 newViewDate = new Date(this.viewDate);
10652 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
10654 if (this.dateWithinRange(newDate)){
10655 this.date = newDate;
10656 this.viewDate = newViewDate;
10657 this.setValue(this.formatDate(this.date));
10659 e.preventDefault();
10660 dateChanged = true;
10664 this.setValue(this.formatDate(this.date));
10666 e.preventDefault();
10669 this.setValue(this.formatDate(this.date));
10676 onClick: function(e) {
10677 e.stopPropagation();
10678 e.preventDefault();
10680 var target = e.getTarget();
10682 if(target.nodeName.toLowerCase() === 'i'){
10683 target = Roo.get(target).dom.parentNode;
10686 var nodeName = target.nodeName;
10687 var className = target.className;
10688 var html = target.innerHTML;
10690 switch(nodeName.toLowerCase()) {
10692 switch(className) {
10698 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
10699 switch(this.viewMode){
10701 this.viewDate = this.moveMonth(this.viewDate, dir);
10705 this.viewDate = this.moveYear(this.viewDate, dir);
10711 var date = new Date();
10712 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
10714 this.setValue(this.formatDate(this.date));
10720 if (className.indexOf('disabled') === -1) {
10721 this.viewDate.setUTCDate(1);
10722 if (className.indexOf('month') !== -1) {
10723 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
10725 var year = parseInt(html, 10) || 0;
10726 this.viewDate.setUTCFullYear(year);
10735 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
10736 var day = parseInt(html, 10) || 1;
10737 var year = this.viewDate.getUTCFullYear(),
10738 month = this.viewDate.getUTCMonth();
10740 if (className.indexOf('old') !== -1) {
10747 } else if (className.indexOf('new') !== -1) {
10755 this.date = this.UTCDate(year, month, day,0,0,0,0);
10756 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
10758 this.setValue(this.formatDate(this.date));
10765 setStartDate: function(startDate){
10766 this.startDate = startDate || -Infinity;
10767 if (this.startDate !== -Infinity) {
10768 this.startDate = this.parseDate(this.startDate);
10771 this.updateNavArrows();
10774 setEndDate: function(endDate){
10775 this.endDate = endDate || Infinity;
10776 if (this.endDate !== Infinity) {
10777 this.endDate = this.parseDate(this.endDate);
10780 this.updateNavArrows();
10783 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
10784 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
10785 if (typeof(this.daysOfWeekDisabled) !== 'object') {
10786 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
10788 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
10789 return parseInt(d, 10);
10792 this.updateNavArrows();
10795 updateNavArrows: function() {
10796 var d = new Date(this.viewDate),
10797 year = d.getUTCFullYear(),
10798 month = d.getUTCMonth();
10800 Roo.each(this.picker().select('.prev', true).elements, function(v){
10802 switch (this.viewMode) {
10805 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
10811 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
10818 Roo.each(this.picker().select('.next', true).elements, function(v){
10820 switch (this.viewMode) {
10823 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
10829 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
10837 moveMonth: function(date, dir){
10838 if (!dir) return date;
10839 var new_date = new Date(date.valueOf()),
10840 day = new_date.getUTCDate(),
10841 month = new_date.getUTCMonth(),
10842 mag = Math.abs(dir),
10844 dir = dir > 0 ? 1 : -1;
10847 // If going back one month, make sure month is not current month
10848 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
10850 return new_date.getUTCMonth() == month;
10852 // If going forward one month, make sure month is as expected
10853 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
10855 return new_date.getUTCMonth() != new_month;
10857 new_month = month + dir;
10858 new_date.setUTCMonth(new_month);
10859 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
10860 if (new_month < 0 || new_month > 11)
10861 new_month = (new_month + 12) % 12;
10863 // For magnitudes >1, move one month at a time...
10864 for (var i=0; i<mag; i++)
10865 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
10866 new_date = this.moveMonth(new_date, dir);
10867 // ...then reset the day, keeping it in the new month
10868 new_month = new_date.getUTCMonth();
10869 new_date.setUTCDate(day);
10871 return new_month != new_date.getUTCMonth();
10874 // Common date-resetting loop -- if date is beyond end of month, make it
10877 new_date.setUTCDate(--day);
10878 new_date.setUTCMonth(new_month);
10883 moveYear: function(date, dir){
10884 return this.moveMonth(date, dir*12);
10887 dateWithinRange: function(date){
10888 return date >= this.startDate && date <= this.endDate;
10892 remove: function() {
10893 this.picker().remove();
10898 Roo.apply(Roo.bootstrap.DateField, {
10909 html: '<i class="icon-arrow-left"/>'
10919 html: '<i class="icon-arrow-right"/>'
10961 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
10962 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
10963 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
10964 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10965 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
10978 navFnc: 'FullYear',
10983 navFnc: 'FullYear',
10988 Roo.apply(Roo.bootstrap.DateField, {
10992 cls: 'datepicker dropdown-menu',
10996 cls: 'datepicker-days',
11000 cls: 'table-condensed',
11002 Roo.bootstrap.DateField.head,
11006 Roo.bootstrap.DateField.footer
11013 cls: 'datepicker-months',
11017 cls: 'table-condensed',
11019 Roo.bootstrap.DateField.head,
11020 Roo.bootstrap.DateField.content,
11021 Roo.bootstrap.DateField.footer
11028 cls: 'datepicker-years',
11032 cls: 'table-condensed',
11034 Roo.bootstrap.DateField.head,
11035 Roo.bootstrap.DateField.content,
11036 Roo.bootstrap.DateField.footer
11055 * @class Roo.bootstrap.CheckBox
11056 * @extends Roo.bootstrap.Input
11057 * Bootstrap CheckBox class
11059 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
11060 * @cfg {String} boxLabel The text that appears beside the checkbox
11061 * @cfg {Boolean} checked initnal the element
11064 * Create a new CheckBox
11065 * @param {Object} config The config object
11068 Roo.bootstrap.CheckBox = function(config){
11069 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
11074 * Fires when the element is checked or unchecked.
11075 * @param {Roo.bootstrap.CheckBox} this This input
11076 * @param {Boolean} checked The new checked value
11082 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
11084 inputType: 'checkbox',
11090 getAutoCreate : function()
11092 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11098 cfg.cls = 'form-group' //input-group
11103 type : this.inputType,
11104 value : (!this.checked) ? this.valueOff : this.value,
11106 placeholder : this.placeholder || ''
11110 if (this.disabled) {
11111 input.disabled=true;
11115 input.checked = this.checked;
11119 input.name = this.name;
11123 input.cls += ' input-' + this.size;
11127 ['xs','sm','md','lg'].map(function(size){
11128 if (settings[size]) {
11129 cfg.cls += ' col-' + size + '-' + settings[size];
11133 var inputblock = input;
11135 if (this.before || this.after) {
11138 cls : 'input-group',
11142 inputblock.cn.push({
11144 cls : 'input-group-addon',
11148 inputblock.cn.push(input);
11150 inputblock.cn.push({
11152 cls : 'input-group-addon',
11159 if (align ==='left' && this.fieldLabel.length) {
11160 Roo.log("left and has label");
11166 cls : 'control-label col-md-' + this.labelWidth,
11167 html : this.fieldLabel
11171 cls : "col-md-" + (12 - this.labelWidth),
11178 } else if ( this.fieldLabel.length) {
11185 cls: 'control-label box-input-label',
11186 //cls : 'input-group-addon',
11187 html : this.fieldLabel
11197 Roo.log(" no label && no align");
11212 html: this.boxLabel
11221 * return the real input element.
11223 inputEl: function ()
11225 return this.el.select('input.form-box',true).first();
11228 initEvents : function()
11230 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
11232 this.inputEl().on('click', this.onClick, this);
11236 onClick : function()
11238 this.setChecked(!this.checked);
11241 setChecked : function(state,suppressEvent)
11243 this.checked = state;
11245 if(suppressEvent !== true){
11246 this.fireEvent('check', this, state);
11249 this.inputEl().dom.value = state ? this.value : this.valueOff;
11263 * @class Roo.bootstrap.Radio
11264 * @extends Roo.bootstrap.CheckBox
11265 * Bootstrap Radio class
11268 * Create a new Radio
11269 * @param {Object} config The config object
11272 Roo.bootstrap.Radio = function(config){
11273 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
11277 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
11279 inputType: 'radio',
11281 getAutoCreate : function()
11283 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11289 cfg.cls = 'form-group' //input-group
11294 type : this.inputType,
11295 value : (!this.checked) ? this.valueOff : this.value,
11297 placeholder : this.placeholder || ''
11301 if (this.disabled) {
11302 input.disabled=true;
11306 input.checked = this.checked;
11310 input.name = this.name;
11314 input.cls += ' input-' + this.size;
11318 ['xs','sm','md','lg'].map(function(size){
11319 if (settings[size]) {
11320 cfg.cls += ' col-' + size + '-' + settings[size];
11324 var inputblock = input;
11326 if (this.before || this.after) {
11329 cls : 'input-group',
11333 inputblock.cn.push({
11335 cls : 'input-group-addon',
11339 inputblock.cn.push(input);
11341 inputblock.cn.push({
11343 cls : 'input-group-addon',
11350 if (align ==='left' && this.fieldLabel.length) {
11351 Roo.log("left and has label");
11357 cls : 'control-label col-md-' + this.labelWidth,
11358 html : this.fieldLabel
11362 cls : "col-md-" + (12 - this.labelWidth),
11369 } else if ( this.fieldLabel.length) {
11376 cls: 'control-label box-input-label',
11377 //cls : 'input-group-addon',
11378 html : this.fieldLabel
11388 Roo.log(" no label && no align");
11403 html: this.boxLabel
11411 onClick : function()
11413 this.setChecked(true);
11416 setChecked : function(state,suppressEvent)
11418 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
11422 this.checked = state;
11424 if(suppressEvent !== true){
11425 this.fireEvent('check', this, state);
11428 this.inputEl().dom.value = state ? this.value : this.valueOff;
11432 getGroupValue : function()
11434 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
11438 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
11442 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11443 * @return {Mixed} value The field value
11445 getValue : function(){
11446 return this.getGroupValue();
11460 * @class Roo.bootstrap.HtmlEditor
11461 * @extends Roo.bootstrap.Component
11462 * Bootstrap HtmlEditor class
11465 * Create a new HtmlEditor
11466 * @param {Object} config The config object
11469 Roo.bootstrap.HtmlEditor = function(config){
11470 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
11471 if (!this.toolbars) {
11472 this.toolbars = [];
11474 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
11477 * @event initialize
11478 * Fires when the editor is fully initialized (including the iframe)
11479 * @param {HtmlEditor} this
11484 * Fires when the editor is first receives the focus. Any insertion must wait
11485 * until after this event.
11486 * @param {HtmlEditor} this
11490 * @event beforesync
11491 * Fires before the textarea is updated with content from the editor iframe. Return false
11492 * to cancel the sync.
11493 * @param {HtmlEditor} this
11494 * @param {String} html
11498 * @event beforepush
11499 * Fires before the iframe editor is updated with content from the textarea. Return false
11500 * to cancel the push.
11501 * @param {HtmlEditor} this
11502 * @param {String} html
11507 * Fires when the textarea is updated with content from the editor iframe.
11508 * @param {HtmlEditor} this
11509 * @param {String} html
11514 * Fires when the iframe editor is updated with content from the textarea.
11515 * @param {HtmlEditor} this
11516 * @param {String} html
11520 * @event editmodechange
11521 * Fires when the editor switches edit modes
11522 * @param {HtmlEditor} this
11523 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
11525 editmodechange: true,
11527 * @event editorevent
11528 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
11529 * @param {HtmlEditor} this
11533 * @event firstfocus
11534 * Fires when on first focus - needed by toolbars..
11535 * @param {HtmlEditor} this
11540 * Auto save the htmlEditor value as a file into Events
11541 * @param {HtmlEditor} this
11545 * @event savedpreview
11546 * preview the saved version of htmlEditor
11547 * @param {HtmlEditor} this
11554 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
11558 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
11563 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
11568 * @cfg {Number} height (in pixels)
11572 * @cfg {Number} width (in pixels)
11577 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
11580 stylesheets: false,
11585 // private properties
11586 validationEvent : false,
11588 initialized : false,
11591 onFocus : Roo.emptyFn,
11593 hideMode:'offsets',
11596 tbContainer : false,
11598 toolbarContainer :function() {
11599 return this.wrap.select('.x-html-editor-tb',true).first();
11603 * Protected method that will not generally be called directly. It
11604 * is called when the editor creates its toolbar. Override this method if you need to
11605 * add custom toolbar buttons.
11606 * @param {HtmlEditor} editor
11608 createToolbar : function(){
11610 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
11611 this.toolbars[0].render(this.toolbarContainer());
11613 Roo.log("create toolbars");
11615 if (!editor.toolbars || !editor.toolbars.length) {
11616 editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
11619 for (var i =0 ; i < editor.toolbars.length;i++) {
11620 editor.toolbars[i] = Roo.factory(
11621 typeof(editor.toolbars[i]) == 'string' ?
11622 { xtype: editor.toolbars[i]} : editor.toolbars[i],
11623 Roo.bootstrap.HtmlEditor);
11624 editor.toolbars[i].init(editor);
11632 onRender : function(ct, position)
11634 // Roo.log("Call onRender: " + this.xtype);
11636 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
11638 this.wrap = this.inputEl().wrap({
11639 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
11642 this.editorcore.onRender(ct, position);
11644 if (this.resizable) {
11645 this.resizeEl = new Roo.Resizable(this.wrap, {
11649 minHeight : this.height,
11650 height: this.height,
11651 handles : this.resizable,
11654 resize : function(r, w, h) {
11655 _t.onResize(w,h); // -something
11661 this.createToolbar(this);
11665 this.setSize(this.wrap.getSize());
11667 if (this.resizeEl) {
11668 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
11669 // should trigger onReize..
11672 // if(this.autosave && this.w){
11673 // this.autoSaveFn = setInterval(this.autosave, 1000);
11678 onResize : function(w, h)
11680 Roo.log('resize: ' +w + ',' + h );
11681 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
11685 if(this.inputEl() ){
11686 if(typeof w == 'number'){
11687 var aw = w - this.wrap.getFrameWidth('lr');
11688 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
11691 if(typeof h == 'number'){
11692 var tbh = -11; // fixme it needs to tool bar size!
11693 for (var i =0; i < this.toolbars.length;i++) {
11694 // fixme - ask toolbars for heights?
11695 tbh += this.toolbars[i].el.getHeight();
11696 //if (this.toolbars[i].footer) {
11697 // tbh += this.toolbars[i].footer.el.getHeight();
11705 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
11706 ah -= 5; // knock a few pixes off for look..
11707 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
11711 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
11712 this.editorcore.onResize(ew,eh);
11717 * Toggles the editor between standard and source edit mode.
11718 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
11720 toggleSourceEdit : function(sourceEditMode)
11722 this.editorcore.toggleSourceEdit(sourceEditMode);
11724 if(this.editorcore.sourceEditMode){
11725 Roo.log('editor - showing textarea');
11728 // Roo.log(this.syncValue());
11729 this.editorcore.syncValue();
11730 this.inputEl().removeClass('hide');
11731 this.inputEl().dom.removeAttribute('tabIndex');
11732 this.inputEl().focus();
11734 Roo.log('editor - hiding textarea');
11736 // Roo.log(this.pushValue());
11737 this.editorcore.pushValue();
11739 this.inputEl().addClass('hide');
11740 this.inputEl().dom.setAttribute('tabIndex', -1);
11741 //this.deferFocus();
11744 this.setSize(this.wrap.getSize());
11745 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
11748 // private (for BoxComponent)
11749 adjustSize : Roo.BoxComponent.prototype.adjustSize,
11751 // private (for BoxComponent)
11752 getResizeEl : function(){
11756 // private (for BoxComponent)
11757 getPositionEl : function(){
11762 initEvents : function(){
11763 this.originalValue = this.getValue();
11767 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
11770 markInvalid : Roo.emptyFn,
11772 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
11775 clearInvalid : Roo.emptyFn,
11777 setValue : function(v){
11778 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
11779 this.editorcore.pushValue();
11784 deferFocus : function(){
11785 this.focus.defer(10, this);
11789 focus : function(){
11790 this.editorcore.focus();
11796 onDestroy : function(){
11802 for (var i =0; i < this.toolbars.length;i++) {
11803 // fixme - ask toolbars for heights?
11804 this.toolbars[i].onDestroy();
11807 this.wrap.dom.innerHTML = '';
11808 this.wrap.remove();
11813 onFirstFocus : function(){
11814 //Roo.log("onFirstFocus");
11815 this.editorcore.onFirstFocus();
11816 for (var i =0; i < this.toolbars.length;i++) {
11817 this.toolbars[i].onFirstFocus();
11823 syncValue : function()
11825 this.editorcore.syncValue();
11829 // hide stuff that is not compatible
11843 * @event specialkey
11847 * @cfg {String} fieldClass @hide
11850 * @cfg {String} focusClass @hide
11853 * @cfg {String} autoCreate @hide
11856 * @cfg {String} inputType @hide
11859 * @cfg {String} invalidClass @hide
11862 * @cfg {String} invalidText @hide
11865 * @cfg {String} msgFx @hide
11868 * @cfg {String} validateOnBlur @hide
11878 * @class Roo.bootstrap.Table.AbstractSelectionModel
11879 * @extends Roo.util.Observable
11880 * Abstract base class for grid SelectionModels. It provides the interface that should be
11881 * implemented by descendant classes. This class should not be directly instantiated.
11884 Roo.bootstrap.Table.AbstractSelectionModel = function(){
11885 this.locked = false;
11886 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
11890 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
11891 /** @ignore Called by the grid automatically. Do not call directly. */
11892 init : function(grid){
11898 * Locks the selections.
11901 this.locked = true;
11905 * Unlocks the selections.
11907 unlock : function(){
11908 this.locked = false;
11912 * Returns true if the selections are locked.
11913 * @return {Boolean}
11915 isLocked : function(){
11916 return this.locked;
11920 * @class Roo.bootstrap.Table.ColumnModel
11921 * @extends Roo.util.Observable
11922 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
11923 * the columns in the table.
11926 * @param {Object} config An Array of column config objects. See this class's
11927 * config objects for details.
11929 Roo.bootstrap.Table.ColumnModel = function(config){
11931 * The config passed into the constructor
11933 this.config = config;
11936 // if no id, create one
11937 // if the column does not have a dataIndex mapping,
11938 // map it to the order it is in the config
11939 for(var i = 0, len = config.length; i < len; i++){
11941 if(typeof c.dataIndex == "undefined"){
11944 if(typeof c.renderer == "string"){
11945 c.renderer = Roo.util.Format[c.renderer];
11947 if(typeof c.id == "undefined"){
11950 // if(c.editor && c.editor.xtype){
11951 // c.editor = Roo.factory(c.editor, Roo.grid);
11953 // if(c.editor && c.editor.isFormField){
11954 // c.editor = new Roo.grid.GridEditor(c.editor);
11957 this.lookup[c.id] = c;
11961 * The width of columns which have no width specified (defaults to 100)
11964 this.defaultWidth = 100;
11967 * Default sortable of columns which have no sortable specified (defaults to false)
11970 this.defaultSortable = false;
11974 * @event widthchange
11975 * Fires when the width of a column changes.
11976 * @param {ColumnModel} this
11977 * @param {Number} columnIndex The column index
11978 * @param {Number} newWidth The new width
11980 "widthchange": true,
11982 * @event headerchange
11983 * Fires when the text of a header changes.
11984 * @param {ColumnModel} this
11985 * @param {Number} columnIndex The column index
11986 * @param {Number} newText The new header text
11988 "headerchange": true,
11990 * @event hiddenchange
11991 * Fires when a column is hidden or "unhidden".
11992 * @param {ColumnModel} this
11993 * @param {Number} columnIndex The column index
11994 * @param {Boolean} hidden true if hidden, false otherwise
11996 "hiddenchange": true,
11998 * @event columnmoved
11999 * Fires when a column is moved.
12000 * @param {ColumnModel} this
12001 * @param {Number} oldIndex
12002 * @param {Number} newIndex
12004 "columnmoved" : true,
12006 * @event columlockchange
12007 * Fires when a column's locked state is changed
12008 * @param {ColumnModel} this
12009 * @param {Number} colIndex
12010 * @param {Boolean} locked true if locked
12012 "columnlockchange" : true
12014 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
12016 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
12018 * @cfg {String} header The header text to display in the Grid view.
12021 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
12022 * {@link Roo.data.Record} definition from which to draw the column's value. If not
12023 * specified, the column's index is used as an index into the Record's data Array.
12026 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
12027 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
12030 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
12031 * Defaults to the value of the {@link #defaultSortable} property.
12032 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
12035 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
12038 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
12041 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
12044 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
12047 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
12048 * given the cell's data value. See {@link #setRenderer}. If not specified, the
12049 * default renderer uses the raw data value.
12052 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
12056 * Returns the id of the column at the specified index.
12057 * @param {Number} index The column index
12058 * @return {String} the id
12060 getColumnId : function(index){
12061 return this.config[index].id;
12065 * Returns the column for a specified id.
12066 * @param {String} id The column id
12067 * @return {Object} the column
12069 getColumnById : function(id){
12070 return this.lookup[id];
12075 * Returns the column for a specified dataIndex.
12076 * @param {String} dataIndex The column dataIndex
12077 * @return {Object|Boolean} the column or false if not found
12079 getColumnByDataIndex: function(dataIndex){
12080 var index = this.findColumnIndex(dataIndex);
12081 return index > -1 ? this.config[index] : false;
12085 * Returns the index for a specified column id.
12086 * @param {String} id The column id
12087 * @return {Number} the index, or -1 if not found
12089 getIndexById : function(id){
12090 for(var i = 0, len = this.config.length; i < len; i++){
12091 if(this.config[i].id == id){
12099 * Returns the index for a specified column dataIndex.
12100 * @param {String} dataIndex The column dataIndex
12101 * @return {Number} the index, or -1 if not found
12104 findColumnIndex : function(dataIndex){
12105 for(var i = 0, len = this.config.length; i < len; i++){
12106 if(this.config[i].dataIndex == dataIndex){
12114 moveColumn : function(oldIndex, newIndex){
12115 var c = this.config[oldIndex];
12116 this.config.splice(oldIndex, 1);
12117 this.config.splice(newIndex, 0, c);
12118 this.dataMap = null;
12119 this.fireEvent("columnmoved", this, oldIndex, newIndex);
12122 isLocked : function(colIndex){
12123 return this.config[colIndex].locked === true;
12126 setLocked : function(colIndex, value, suppressEvent){
12127 if(this.isLocked(colIndex) == value){
12130 this.config[colIndex].locked = value;
12131 if(!suppressEvent){
12132 this.fireEvent("columnlockchange", this, colIndex, value);
12136 getTotalLockedWidth : function(){
12137 var totalWidth = 0;
12138 for(var i = 0; i < this.config.length; i++){
12139 if(this.isLocked(i) && !this.isHidden(i)){
12140 this.totalWidth += this.getColumnWidth(i);
12146 getLockedCount : function(){
12147 for(var i = 0, len = this.config.length; i < len; i++){
12148 if(!this.isLocked(i)){
12155 * Returns the number of columns.
12158 getColumnCount : function(visibleOnly){
12159 if(visibleOnly === true){
12161 for(var i = 0, len = this.config.length; i < len; i++){
12162 if(!this.isHidden(i)){
12168 return this.config.length;
12172 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
12173 * @param {Function} fn
12174 * @param {Object} scope (optional)
12175 * @return {Array} result
12177 getColumnsBy : function(fn, scope){
12179 for(var i = 0, len = this.config.length; i < len; i++){
12180 var c = this.config[i];
12181 if(fn.call(scope||this, c, i) === true){
12189 * Returns true if the specified column is sortable.
12190 * @param {Number} col The column index
12191 * @return {Boolean}
12193 isSortable : function(col){
12194 if(typeof this.config[col].sortable == "undefined"){
12195 return this.defaultSortable;
12197 return this.config[col].sortable;
12201 * Returns the rendering (formatting) function defined for the column.
12202 * @param {Number} col The column index.
12203 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
12205 getRenderer : function(col){
12206 if(!this.config[col].renderer){
12207 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
12209 return this.config[col].renderer;
12213 * Sets the rendering (formatting) function for a column.
12214 * @param {Number} col The column index
12215 * @param {Function} fn The function to use to process the cell's raw data
12216 * to return HTML markup for the grid view. The render function is called with
12217 * the following parameters:<ul>
12218 * <li>Data value.</li>
12219 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
12220 * <li>css A CSS style string to apply to the table cell.</li>
12221 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
12222 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
12223 * <li>Row index</li>
12224 * <li>Column index</li>
12225 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
12227 setRenderer : function(col, fn){
12228 this.config[col].renderer = fn;
12232 * Returns the width for the specified column.
12233 * @param {Number} col The column index
12236 getColumnWidth : function(col){
12237 return this.config[col].width * 1 || this.defaultWidth;
12241 * Sets the width for a column.
12242 * @param {Number} col The column index
12243 * @param {Number} width The new width
12245 setColumnWidth : function(col, width, suppressEvent){
12246 this.config[col].width = width;
12247 this.totalWidth = null;
12248 if(!suppressEvent){
12249 this.fireEvent("widthchange", this, col, width);
12254 * Returns the total width of all columns.
12255 * @param {Boolean} includeHidden True to include hidden column widths
12258 getTotalWidth : function(includeHidden){
12259 if(!this.totalWidth){
12260 this.totalWidth = 0;
12261 for(var i = 0, len = this.config.length; i < len; i++){
12262 if(includeHidden || !this.isHidden(i)){
12263 this.totalWidth += this.getColumnWidth(i);
12267 return this.totalWidth;
12271 * Returns the header for the specified column.
12272 * @param {Number} col The column index
12275 getColumnHeader : function(col){
12276 return this.config[col].header;
12280 * Sets the header for a column.
12281 * @param {Number} col The column index
12282 * @param {String} header The new header
12284 setColumnHeader : function(col, header){
12285 this.config[col].header = header;
12286 this.fireEvent("headerchange", this, col, header);
12290 * Returns the tooltip for the specified column.
12291 * @param {Number} col The column index
12294 getColumnTooltip : function(col){
12295 return this.config[col].tooltip;
12298 * Sets the tooltip for a column.
12299 * @param {Number} col The column index
12300 * @param {String} tooltip The new tooltip
12302 setColumnTooltip : function(col, tooltip){
12303 this.config[col].tooltip = tooltip;
12307 * Returns the dataIndex for the specified column.
12308 * @param {Number} col The column index
12311 getDataIndex : function(col){
12312 return this.config[col].dataIndex;
12316 * Sets the dataIndex for a column.
12317 * @param {Number} col The column index
12318 * @param {Number} dataIndex The new dataIndex
12320 setDataIndex : function(col, dataIndex){
12321 this.config[col].dataIndex = dataIndex;
12327 * Returns true if the cell is editable.
12328 * @param {Number} colIndex The column index
12329 * @param {Number} rowIndex The row index
12330 * @return {Boolean}
12332 isCellEditable : function(colIndex, rowIndex){
12333 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
12337 * Returns the editor defined for the cell/column.
12338 * return false or null to disable editing.
12339 * @param {Number} colIndex The column index
12340 * @param {Number} rowIndex The row index
12343 getCellEditor : function(colIndex, rowIndex){
12344 return this.config[colIndex].editor;
12348 * Sets if a column is editable.
12349 * @param {Number} col The column index
12350 * @param {Boolean} editable True if the column is editable
12352 setEditable : function(col, editable){
12353 this.config[col].editable = editable;
12358 * Returns true if the column is hidden.
12359 * @param {Number} colIndex The column index
12360 * @return {Boolean}
12362 isHidden : function(colIndex){
12363 return this.config[colIndex].hidden;
12368 * Returns true if the column width cannot be changed
12370 isFixed : function(colIndex){
12371 return this.config[colIndex].fixed;
12375 * Returns true if the column can be resized
12376 * @return {Boolean}
12378 isResizable : function(colIndex){
12379 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
12382 * Sets if a column is hidden.
12383 * @param {Number} colIndex The column index
12384 * @param {Boolean} hidden True if the column is hidden
12386 setHidden : function(colIndex, hidden){
12387 this.config[colIndex].hidden = hidden;
12388 this.totalWidth = null;
12389 this.fireEvent("hiddenchange", this, colIndex, hidden);
12393 * Sets the editor for a column.
12394 * @param {Number} col The column index
12395 * @param {Object} editor The editor object
12397 setEditor : function(col, editor){
12398 this.config[col].editor = editor;
12402 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
12403 if(typeof value == "string" && value.length < 1){
12409 // Alias for backwards compatibility
12410 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
12413 * @extends Roo.bootstrap.Table.AbstractSelectionModel
12414 * @class Roo.bootstrap.Table.RowSelectionModel
12415 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
12416 * It supports multiple selections and keyboard selection/navigation.
12418 * @param {Object} config
12421 Roo.bootstrap.Table.RowSelectionModel = function(config){
12422 Roo.apply(this, config);
12423 this.selections = new Roo.util.MixedCollection(false, function(o){
12428 this.lastActive = false;
12432 * @event selectionchange
12433 * Fires when the selection changes
12434 * @param {SelectionModel} this
12436 "selectionchange" : true,
12438 * @event afterselectionchange
12439 * Fires after the selection changes (eg. by key press or clicking)
12440 * @param {SelectionModel} this
12442 "afterselectionchange" : true,
12444 * @event beforerowselect
12445 * Fires when a row is selected being selected, return false to cancel.
12446 * @param {SelectionModel} this
12447 * @param {Number} rowIndex The selected index
12448 * @param {Boolean} keepExisting False if other selections will be cleared
12450 "beforerowselect" : true,
12453 * Fires when a row is selected.
12454 * @param {SelectionModel} this
12455 * @param {Number} rowIndex The selected index
12456 * @param {Roo.data.Record} r The record
12458 "rowselect" : true,
12460 * @event rowdeselect
12461 * Fires when a row is deselected.
12462 * @param {SelectionModel} this
12463 * @param {Number} rowIndex The selected index
12465 "rowdeselect" : true
12467 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
12468 this.locked = false;
12471 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
12473 * @cfg {Boolean} singleSelect
12474 * True to allow selection of only one row at a time (defaults to false)
12476 singleSelect : false,
12479 initEvents : function(){
12481 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
12482 this.grid.on("mousedown", this.handleMouseDown, this);
12483 }else{ // allow click to work like normal
12484 this.grid.on("rowclick", this.handleDragableRowClick, this);
12487 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
12488 "up" : function(e){
12490 this.selectPrevious(e.shiftKey);
12491 }else if(this.last !== false && this.lastActive !== false){
12492 var last = this.last;
12493 this.selectRange(this.last, this.lastActive-1);
12494 this.grid.getView().focusRow(this.lastActive);
12495 if(last !== false){
12499 this.selectFirstRow();
12501 this.fireEvent("afterselectionchange", this);
12503 "down" : function(e){
12505 this.selectNext(e.shiftKey);
12506 }else if(this.last !== false && this.lastActive !== false){
12507 var last = this.last;
12508 this.selectRange(this.last, this.lastActive+1);
12509 this.grid.getView().focusRow(this.lastActive);
12510 if(last !== false){
12514 this.selectFirstRow();
12516 this.fireEvent("afterselectionchange", this);
12521 var view = this.grid.view;
12522 view.on("refresh", this.onRefresh, this);
12523 view.on("rowupdated", this.onRowUpdated, this);
12524 view.on("rowremoved", this.onRemove, this);
12528 onRefresh : function(){
12529 var ds = this.grid.dataSource, i, v = this.grid.view;
12530 var s = this.selections;
12531 s.each(function(r){
12532 if((i = ds.indexOfId(r.id)) != -1){
12541 onRemove : function(v, index, r){
12542 this.selections.remove(r);
12546 onRowUpdated : function(v, index, r){
12547 if(this.isSelected(r)){
12548 v.onRowSelect(index);
12554 * @param {Array} records The records to select
12555 * @param {Boolean} keepExisting (optional) True to keep existing selections
12557 selectRecords : function(records, keepExisting){
12559 this.clearSelections();
12561 var ds = this.grid.dataSource;
12562 for(var i = 0, len = records.length; i < len; i++){
12563 this.selectRow(ds.indexOf(records[i]), true);
12568 * Gets the number of selected rows.
12571 getCount : function(){
12572 return this.selections.length;
12576 * Selects the first row in the grid.
12578 selectFirstRow : function(){
12583 * Select the last row.
12584 * @param {Boolean} keepExisting (optional) True to keep existing selections
12586 selectLastRow : function(keepExisting){
12587 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
12591 * Selects the row immediately following the last selected row.
12592 * @param {Boolean} keepExisting (optional) True to keep existing selections
12594 selectNext : function(keepExisting){
12595 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
12596 this.selectRow(this.last+1, keepExisting);
12597 this.grid.getView().focusRow(this.last);
12602 * Selects the row that precedes the last selected row.
12603 * @param {Boolean} keepExisting (optional) True to keep existing selections
12605 selectPrevious : function(keepExisting){
12607 this.selectRow(this.last-1, keepExisting);
12608 this.grid.getView().focusRow(this.last);
12613 * Returns the selected records
12614 * @return {Array} Array of selected records
12616 getSelections : function(){
12617 return [].concat(this.selections.items);
12621 * Returns the first selected record.
12624 getSelected : function(){
12625 return this.selections.itemAt(0);
12630 * Clears all selections.
12632 clearSelections : function(fast){
12633 if(this.locked) return;
12635 var ds = this.grid.dataSource;
12636 var s = this.selections;
12637 s.each(function(r){
12638 this.deselectRow(ds.indexOfId(r.id));
12642 this.selections.clear();
12649 * Selects all rows.
12651 selectAll : function(){
12652 if(this.locked) return;
12653 this.selections.clear();
12654 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
12655 this.selectRow(i, true);
12660 * Returns True if there is a selection.
12661 * @return {Boolean}
12663 hasSelection : function(){
12664 return this.selections.length > 0;
12668 * Returns True if the specified row is selected.
12669 * @param {Number/Record} record The record or index of the record to check
12670 * @return {Boolean}
12672 isSelected : function(index){
12673 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
12674 return (r && this.selections.key(r.id) ? true : false);
12678 * Returns True if the specified record id is selected.
12679 * @param {String} id The id of record to check
12680 * @return {Boolean}
12682 isIdSelected : function(id){
12683 return (this.selections.key(id) ? true : false);
12687 handleMouseDown : function(e, t){
12688 var view = this.grid.getView(), rowIndex;
12689 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
12692 if(e.shiftKey && this.last !== false){
12693 var last = this.last;
12694 this.selectRange(last, rowIndex, e.ctrlKey);
12695 this.last = last; // reset the last
12696 view.focusRow(rowIndex);
12698 var isSelected = this.isSelected(rowIndex);
12699 if(e.button !== 0 && isSelected){
12700 view.focusRow(rowIndex);
12701 }else if(e.ctrlKey && isSelected){
12702 this.deselectRow(rowIndex);
12703 }else if(!isSelected){
12704 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
12705 view.focusRow(rowIndex);
12708 this.fireEvent("afterselectionchange", this);
12711 handleDragableRowClick : function(grid, rowIndex, e)
12713 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
12714 this.selectRow(rowIndex, false);
12715 grid.view.focusRow(rowIndex);
12716 this.fireEvent("afterselectionchange", this);
12721 * Selects multiple rows.
12722 * @param {Array} rows Array of the indexes of the row to select
12723 * @param {Boolean} keepExisting (optional) True to keep existing selections
12725 selectRows : function(rows, keepExisting){
12727 this.clearSelections();
12729 for(var i = 0, len = rows.length; i < len; i++){
12730 this.selectRow(rows[i], true);
12735 * Selects a range of rows. All rows in between startRow and endRow are also selected.
12736 * @param {Number} startRow The index of the first row in the range
12737 * @param {Number} endRow The index of the last row in the range
12738 * @param {Boolean} keepExisting (optional) True to retain existing selections
12740 selectRange : function(startRow, endRow, keepExisting){
12741 if(this.locked) return;
12743 this.clearSelections();
12745 if(startRow <= endRow){
12746 for(var i = startRow; i <= endRow; i++){
12747 this.selectRow(i, true);
12750 for(var i = startRow; i >= endRow; i--){
12751 this.selectRow(i, true);
12757 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
12758 * @param {Number} startRow The index of the first row in the range
12759 * @param {Number} endRow The index of the last row in the range
12761 deselectRange : function(startRow, endRow, preventViewNotify){
12762 if(this.locked) return;
12763 for(var i = startRow; i <= endRow; i++){
12764 this.deselectRow(i, preventViewNotify);
12770 * @param {Number} row The index of the row to select
12771 * @param {Boolean} keepExisting (optional) True to keep existing selections
12773 selectRow : function(index, keepExisting, preventViewNotify){
12774 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
12775 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
12776 if(!keepExisting || this.singleSelect){
12777 this.clearSelections();
12779 var r = this.grid.dataSource.getAt(index);
12780 this.selections.add(r);
12781 this.last = this.lastActive = index;
12782 if(!preventViewNotify){
12783 this.grid.getView().onRowSelect(index);
12785 this.fireEvent("rowselect", this, index, r);
12786 this.fireEvent("selectionchange", this);
12792 * @param {Number} row The index of the row to deselect
12794 deselectRow : function(index, preventViewNotify){
12795 if(this.locked) return;
12796 if(this.last == index){
12799 if(this.lastActive == index){
12800 this.lastActive = false;
12802 var r = this.grid.dataSource.getAt(index);
12803 this.selections.remove(r);
12804 if(!preventViewNotify){
12805 this.grid.getView().onRowDeselect(index);
12807 this.fireEvent("rowdeselect", this, index);
12808 this.fireEvent("selectionchange", this);
12812 restoreLast : function(){
12814 this.last = this._last;
12819 acceptsNav : function(row, col, cm){
12820 return !cm.isHidden(col) && cm.isCellEditable(col, row);
12824 onEditorKey : function(field, e){
12825 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
12830 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
12832 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
12834 }else if(k == e.ENTER && !e.ctrlKey){
12838 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
12840 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
12842 }else if(k == e.ESC){
12846 g.startEditing(newCell[0], newCell[1]);