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](false));
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](false));
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](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @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
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
972 * @class Roo.bootstrap.Img
973 * @extends Roo.bootstrap.Component
974 * Bootstrap Img class
975 * @cfg {Boolean} imgResponsive false | true
976 * @cfg {String} border rounded | circle | thumbnail
977 * @cfg {String} src image source
978 * @cfg {String} alt image alternative text
979 * @cfg {String} href a tag href
980 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
984 * @param {Object} config The config object
987 Roo.bootstrap.Img = function(config){
988 Roo.bootstrap.Img.superclass.constructor.call(this, config);
994 * The img click event for the img.
995 * @param {Roo.EventObject} e
1001 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1003 imgResponsive: true,
1009 getAutoCreate : function(){
1013 cls: (this.imgResponsive) ? 'img-responsive' : '',
1017 cfg.html = this.html || cfg.html;
1019 cfg.src = this.src || cfg.src;
1021 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1022 cfg.cls += ' img-' + this.border;
1039 a.target = this.target;
1045 return (this.href) ? a : cfg;
1048 initEvents: function() {
1051 this.el.on('click', this.onClick, this);
1055 onClick : function(e)
1057 Roo.log('img onclick');
1058 this.fireEvent('click', this, e);
1072 * @class Roo.bootstrap.Link
1073 * @extends Roo.bootstrap.Component
1074 * Bootstrap Link Class
1075 * @cfg {String} alt image alternative text
1076 * @cfg {String} href a tag href
1077 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1078 * @cfg {String} html the content of the link.
1082 * Create a new Input
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Link = function(config){
1087 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1093 * The img click event for the img.
1094 * @param {Roo.EventObject} e
1100 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1105 getAutoCreate : function(){
1109 html : this.html || 'html-missing'
1116 cfg.href = this.href || '#';
1118 cfg.target = this.target;
1124 initEvents: function() {
1127 this.el.on('click', this.onClick, this);
1131 onClick : function(e)
1133 //Roo.log('img onclick');
1134 this.fireEvent('click', this, e);
1147 * @class Roo.bootstrap.Header
1148 * @extends Roo.bootstrap.Component
1149 * Bootstrap Header class
1150 * @cfg {String} html content of header
1151 * @cfg {Number} level (1|2|3|4|5|6) default 1
1154 * Create a new Header
1155 * @param {Object} config The config object
1159 Roo.bootstrap.Header = function(config){
1160 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1163 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1171 getAutoCreate : function(){
1174 tag: 'h' + (1 *this.level),
1175 html: this.html || 'fill in html'
1187 * Ext JS Library 1.1.1
1188 * Copyright(c) 2006-2007, Ext JS, LLC.
1190 * Originally Released Under LGPL - original licence link has changed is not relivant.
1193 * <script type="text/javascript">
1197 * @class Roo.bootstrap.MenuMgr
1198 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1201 Roo.bootstrap.MenuMgr = function(){
1202 var menus, active, groups = {}, attached = false, lastShow = new Date();
1204 // private - called when first menu is created
1207 active = new Roo.util.MixedCollection();
1208 Roo.get(document).addKeyListener(27, function(){
1209 if(active.length > 0){
1217 if(active && active.length > 0){
1218 var c = active.clone();
1228 if(active.length < 1){
1229 Roo.get(document).un("mouseup", onMouseDown);
1237 var last = active.last();
1238 lastShow = new Date();
1241 Roo.get(document).on("mouseup", onMouseDown);
1246 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1247 m.parentMenu.activeChild = m;
1248 }else if(last && last.isVisible()){
1249 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1254 function onBeforeHide(m){
1256 m.activeChild.hide();
1258 if(m.autoHideTimer){
1259 clearTimeout(m.autoHideTimer);
1260 delete m.autoHideTimer;
1265 function onBeforeShow(m){
1266 var pm = m.parentMenu;
1267 if(!pm && !m.allowOtherMenus){
1269 }else if(pm && pm.activeChild && active != m){
1270 pm.activeChild.hide();
1275 function onMouseDown(e){
1276 Roo.log("on MouseDown");
1277 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1285 function onBeforeCheck(mi, state){
1287 var g = groups[mi.group];
1288 for(var i = 0, l = g.length; i < l; i++){
1290 g[i].setChecked(false);
1299 * Hides all menus that are currently visible
1301 hideAll : function(){
1306 register : function(menu){
1310 menus[menu.id] = menu;
1311 menu.on("beforehide", onBeforeHide);
1312 menu.on("hide", onHide);
1313 menu.on("beforeshow", onBeforeShow);
1314 menu.on("show", onShow);
1316 if(g && menu.events["checkchange"]){
1320 groups[g].push(menu);
1321 menu.on("checkchange", onCheck);
1326 * Returns a {@link Roo.menu.Menu} object
1327 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1328 * be used to generate and return a new Menu instance.
1330 get : function(menu){
1331 if(typeof menu == "string"){ // menu id
1333 }else if(menu.events){ // menu instance
1336 /*else if(typeof menu.length == 'number'){ // array of menu items?
1337 return new Roo.bootstrap.Menu({items:menu});
1338 }else{ // otherwise, must be a config
1339 return new Roo.bootstrap.Menu(menu);
1346 unregister : function(menu){
1347 delete menus[menu.id];
1348 menu.un("beforehide", onBeforeHide);
1349 menu.un("hide", onHide);
1350 menu.un("beforeshow", onBeforeShow);
1351 menu.un("show", onShow);
1353 if(g && menu.events["checkchange"]){
1354 groups[g].remove(menu);
1355 menu.un("checkchange", onCheck);
1360 registerCheckable : function(menuItem){
1361 var g = menuItem.group;
1366 groups[g].push(menuItem);
1367 menuItem.on("beforecheckchange", onBeforeCheck);
1372 unregisterCheckable : function(menuItem){
1373 var g = menuItem.group;
1375 groups[g].remove(menuItem);
1376 menuItem.un("beforecheckchange", onBeforeCheck);
1388 * @class Roo.bootstrap.Menu
1389 * @extends Roo.bootstrap.Component
1390 * Bootstrap Menu class - container for MenuItems
1391 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1395 * @param {Object} config The config object
1399 Roo.bootstrap.Menu = function(config){
1400 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1401 if (this.registerMenu) {
1402 Roo.bootstrap.MenuMgr.register(this);
1407 * Fires before this menu is displayed
1408 * @param {Roo.menu.Menu} this
1413 * Fires before this menu is hidden
1414 * @param {Roo.menu.Menu} this
1419 * Fires after this menu is displayed
1420 * @param {Roo.menu.Menu} this
1425 * Fires after this menu is hidden
1426 * @param {Roo.menu.Menu} this
1431 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1432 * @param {Roo.menu.Menu} this
1433 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1434 * @param {Roo.EventObject} e
1439 * Fires when the mouse is hovering over this menu
1440 * @param {Roo.menu.Menu} this
1441 * @param {Roo.EventObject} e
1442 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1447 * Fires when the mouse exits this menu
1448 * @param {Roo.menu.Menu} this
1449 * @param {Roo.EventObject} e
1450 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1455 * Fires when a menu item contained in this menu is clicked
1456 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1457 * @param {Roo.EventObject} e
1461 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1464 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1468 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1471 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1473 registerMenu : true,
1475 menuItems :false, // stores the menu items..
1481 getChildContainer : function() {
1485 getAutoCreate : function(){
1487 //if (['right'].indexOf(this.align)!==-1) {
1488 // cfg.cn[1].cls += ' pull-right'
1494 cls : 'dropdown-menu' ,
1495 style : 'z-index:1000'
1499 if (this.type === 'submenu') {
1500 cfg.cls = 'submenu active';
1502 if (this.type === 'treeview') {
1503 cfg.cls = 'treeview-menu';
1508 initEvents : function() {
1510 // Roo.log("ADD event");
1511 // Roo.log(this.triggerEl.dom);
1512 this.triggerEl.on('click', this.onTriggerPress, this);
1513 this.triggerEl.addClass('dropdown-toggle');
1514 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1516 this.el.on("mouseover", this.onMouseOver, this);
1517 this.el.on("mouseout", this.onMouseOut, this);
1521 findTargetItem : function(e){
1522 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1526 //Roo.log(t); Roo.log(t.id);
1528 //Roo.log(this.menuitems);
1529 return this.menuitems.get(t.id);
1531 //return this.items.get(t.menuItemId);
1536 onClick : function(e){
1537 Roo.log("menu.onClick");
1538 var t = this.findTargetItem(e);
1544 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1545 if(t == this.activeItem && t.shouldDeactivate(e)){
1546 this.activeItem.deactivate();
1547 delete this.activeItem;
1551 this.setActiveItem(t, true);
1558 Roo.log('pass click event');
1562 this.fireEvent("click", this, t, e);
1566 onMouseOver : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t.canActivate && !t.disabled){
1571 // this.setActiveItem(t, true);
1575 this.fireEvent("mouseover", this, e, t);
1577 isVisible : function(){
1578 return !this.hidden;
1580 onMouseOut : function(e){
1581 var t = this.findTargetItem(e);
1584 // if(t == this.activeItem && t.shouldDeactivate(e)){
1585 // this.activeItem.deactivate();
1586 // delete this.activeItem;
1589 this.fireEvent("mouseout", this, e, t);
1594 * Displays this menu relative to another element
1595 * @param {String/HTMLElement/Roo.Element} element The element to align to
1596 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1597 * the element (defaults to this.defaultAlign)
1598 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1600 show : function(el, pos, parentMenu){
1601 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1606 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1609 * Displays this menu at a specific xy position
1610 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1611 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1613 showAt : function(xy, parentMenu, /* private: */_e){
1614 this.parentMenu = parentMenu;
1619 this.fireEvent("beforeshow", this);
1621 //xy = this.el.adjustForConstraints(xy);
1623 //this.el.setXY(xy);
1625 this.hideMenuItems();
1626 this.hidden = false;
1627 this.triggerEl.addClass('open');
1629 this.fireEvent("show", this);
1635 this.doFocus.defer(50, this);
1639 doFocus : function(){
1641 this.focusEl.focus();
1646 * Hides this menu and optionally all parent menus
1647 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1649 hide : function(deep){
1651 this.hideMenuItems();
1652 if(this.el && this.isVisible()){
1653 this.fireEvent("beforehide", this);
1654 if(this.activeItem){
1655 this.activeItem.deactivate();
1656 this.activeItem = null;
1658 this.triggerEl.removeClass('open');;
1660 this.fireEvent("hide", this);
1662 if(deep === true && this.parentMenu){
1663 this.parentMenu.hide(true);
1667 onTriggerPress : function(e)
1670 Roo.log('trigger press');
1671 //Roo.log(e.getTarget());
1672 // Roo.log(this.triggerEl.dom);
1673 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1676 if (this.isVisible()) {
1680 this.show(this.triggerEl, false, false);
1689 hideMenuItems : function()
1691 //$(backdrop).remove()
1692 Roo.select('.open',true).each(function(aa) {
1694 aa.removeClass('open');
1695 //var parent = getParent($(this))
1696 //var relatedTarget = { relatedTarget: this }
1698 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1699 //if (e.isDefaultPrevented()) return
1700 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1703 addxtypeChild : function (tree, cntr) {
1704 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1706 this.menuitems.add(comp);
1727 * @class Roo.bootstrap.MenuItem
1728 * @extends Roo.bootstrap.Component
1729 * Bootstrap MenuItem class
1730 * @cfg {String} html the menu label
1731 * @cfg {String} href the link
1732 * @cfg {Boolean} preventDefault (true | false) default true
1736 * Create a new MenuItem
1737 * @param {Object} config The config object
1741 Roo.bootstrap.MenuItem = function(config){
1742 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1747 * The raw click event for the entire grid.
1748 * @param {Roo.EventObject} e
1754 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1758 preventDefault: true,
1760 getAutoCreate : function(){
1763 cls: 'dropdown-menu-item',
1772 if (this.parent().type == 'treeview') {
1773 cfg.cls = 'treeview-menu';
1776 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1777 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1781 initEvents: function() {
1783 //this.el.select('a').on('click', this.onClick, this);
1786 onClick : function(e)
1788 Roo.log('item on click ');
1789 //if(this.preventDefault){
1790 // e.preventDefault();
1792 //this.parent().hideMenuItems();
1794 this.fireEvent('click', this, e);
1813 * @class Roo.bootstrap.MenuSeparator
1814 * @extends Roo.bootstrap.Component
1815 * Bootstrap MenuSeparator class
1818 * Create a new MenuItem
1819 * @param {Object} config The config object
1823 Roo.bootstrap.MenuSeparator = function(config){
1824 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1827 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1829 getAutoCreate : function(){
1844 <div class="modal fade">
1845 <div class="modal-dialog">
1846 <div class="modal-content">
1847 <div class="modal-header">
1848 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1849 <h4 class="modal-title">Modal title</h4>
1851 <div class="modal-body">
1852 <p>One fine body…</p>
1854 <div class="modal-footer">
1855 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1856 <button type="button" class="btn btn-primary">Save changes</button>
1858 </div><!-- /.modal-content -->
1859 </div><!-- /.modal-dialog -->
1860 </div><!-- /.modal -->
1870 * @class Roo.bootstrap.Modal
1871 * @extends Roo.bootstrap.Component
1872 * Bootstrap Modal class
1873 * @cfg {String} title Title of dialog
1874 * @cfg {Boolean} specificTitle (true|false) default false
1875 * @cfg {Array} buttons Array of buttons or standard button set..
1876 * @cfg {String} buttonPosition (left|right|center) default right
1879 * Create a new Modal Dialog
1880 * @param {Object} config The config object
1883 Roo.bootstrap.Modal = function(config){
1884 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1889 * The raw btnclick event for the button
1890 * @param {Roo.EventObject} e
1894 this.buttons = this.buttons || [];
1897 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1899 title : 'test dialog',
1906 specificTitle: false,
1908 buttonPosition: 'right',
1910 onRender : function(ct, position)
1912 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1915 var cfg = Roo.apply({}, this.getAutoCreate());
1918 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1920 //if (!cfg.name.length) {
1924 cfg.cls += ' ' + this.cls;
1927 cfg.style = this.style;
1929 this.el = Roo.get(document.body).createChild(cfg, position);
1931 //var type = this.el.dom.type;
1933 if(this.tabIndex !== undefined){
1934 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1939 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1940 this.maskEl.enableDisplayMode("block");
1942 //this.el.addClass("x-dlg-modal");
1944 if (this.buttons.length) {
1945 Roo.each(this.buttons, function(bb) {
1946 b = Roo.apply({}, bb);
1947 b.xns = b.xns || Roo.bootstrap;
1948 b.xtype = b.xtype || 'Button';
1949 if (typeof(b.listeners) == 'undefined') {
1950 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1953 var btn = Roo.factory(b);
1955 btn.onRender(this.el.select('.modal-footer div').first());
1959 // render the children.
1962 if(typeof(this.items) != 'undefined'){
1963 var items = this.items;
1966 for(var i =0;i < items.length;i++) {
1967 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1971 this.items = nitems;
1973 this.body = this.el.select('.modal-body',true).first();
1974 this.close = this.el.select('.modal-header .close', true).first();
1975 this.footer = this.el.select('.modal-footer',true).first();
1977 //this.el.addClass([this.fieldClass, this.cls]);
1980 getAutoCreate : function(){
1985 html : this.html || ''
1990 cls : 'modal-title',
1994 if(this.specificTitle){
2000 style : 'display: none',
2003 cls: "modal-dialog",
2006 cls : "modal-content",
2009 cls : 'modal-header',
2021 cls : 'modal-footer',
2025 cls: 'btn-' + this.buttonPosition
2044 getChildContainer : function() {
2046 return this.el.select('.modal-body',true).first();
2049 getButtonContainer : function() {
2050 return this.el.select('.modal-footer div',true).first();
2053 initEvents : function()
2055 this.el.select('.modal-header .close').on('click', this.hide, this);
2057 // this.addxtype(this);
2061 if (!this.rendered) {
2065 this.el.addClass('on');
2066 this.el.removeClass('fade');
2067 this.el.setStyle('display', 'block');
2068 Roo.get(document.body).addClass("x-body-masked");
2069 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2071 this.el.setStyle('zIndex', '10001');
2072 this.fireEvent('show', this);
2078 Roo.log('Modal hide?!');
2080 Roo.get(document.body).removeClass("x-body-masked");
2081 this.el.removeClass('on');
2082 this.el.addClass('fade');
2083 this.el.setStyle('display', 'none');
2084 this.fireEvent('hide', this);
2087 addButton : function(str, cb)
2091 var b = Roo.apply({}, { html : str } );
2092 b.xns = b.xns || Roo.bootstrap;
2093 b.xtype = b.xtype || 'Button';
2094 if (typeof(b.listeners) == 'undefined') {
2095 b.listeners = { click : cb.createDelegate(this) };
2098 var btn = Roo.factory(b);
2100 btn.onRender(this.el.select('.modal-footer div').first());
2106 setDefaultButton : function(btn)
2108 //this.el.select('.modal-footer').()
2110 resizeTo: function(w,h)
2114 setContentSize : function(w, h)
2118 onButtonClick: function(btn,e)
2121 this.fireEvent('btnclick', btn.name, e);
2123 setTitle: function(str) {
2124 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2130 Roo.apply(Roo.bootstrap.Modal, {
2132 * Button config that displays a single OK button
2141 * Button config that displays Yes and No buttons
2157 * Button config that displays OK and Cancel buttons
2172 * Button config that displays Yes, No and Cancel buttons
2194 * messagebox - can be used as a replace
2198 * @class Roo.MessageBox
2199 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2203 Roo.Msg.alert('Status', 'Changes saved successfully.');
2205 // Prompt for user data:
2206 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2208 // process text value...
2212 // Show a dialog using config options:
2214 title:'Save Changes?',
2215 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2216 buttons: Roo.Msg.YESNOCANCEL,
2223 Roo.bootstrap.MessageBox = function(){
2224 var dlg, opt, mask, waitTimer;
2225 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2226 var buttons, activeTextEl, bwidth;
2230 var handleButton = function(button){
2232 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2236 var handleHide = function(){
2238 dlg.el.removeClass(opt.cls);
2241 // Roo.TaskMgr.stop(waitTimer);
2242 // waitTimer = null;
2247 var updateButtons = function(b){
2250 buttons["ok"].hide();
2251 buttons["cancel"].hide();
2252 buttons["yes"].hide();
2253 buttons["no"].hide();
2254 //dlg.footer.dom.style.display = 'none';
2257 dlg.footer.dom.style.display = '';
2258 for(var k in buttons){
2259 if(typeof buttons[k] != "function"){
2262 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2263 width += buttons[k].el.getWidth()+15;
2273 var handleEsc = function(d, k, e){
2274 if(opt && opt.closable !== false){
2284 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2285 * @return {Roo.BasicDialog} The BasicDialog element
2287 getDialog : function(){
2289 dlg = new Roo.bootstrap.Modal( {
2292 //constraintoviewport:false,
2294 //collapsible : false,
2299 //buttonAlign:"center",
2300 closeClick : function(){
2301 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2304 handleButton("cancel");
2309 dlg.on("hide", handleHide);
2311 //dlg.addKeyListener(27, handleEsc);
2313 this.buttons = buttons;
2314 var bt = this.buttonText;
2315 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2316 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2317 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2318 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2320 bodyEl = dlg.body.createChild({
2322 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2323 '<textarea class="roo-mb-textarea"></textarea>' +
2324 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2326 msgEl = bodyEl.dom.firstChild;
2327 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2328 textboxEl.enableDisplayMode();
2329 textboxEl.addKeyListener([10,13], function(){
2330 if(dlg.isVisible() && opt && opt.buttons){
2333 }else if(opt.buttons.yes){
2334 handleButton("yes");
2338 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2339 textareaEl.enableDisplayMode();
2340 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2341 progressEl.enableDisplayMode();
2342 var pf = progressEl.dom.firstChild;
2344 pp = Roo.get(pf.firstChild);
2345 pp.setHeight(pf.offsetHeight);
2353 * Updates the message box body text
2354 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2355 * the XHTML-compliant non-breaking space character '&#160;')
2356 * @return {Roo.MessageBox} This message box
2358 updateText : function(text){
2359 if(!dlg.isVisible() && !opt.width){
2360 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2362 msgEl.innerHTML = text || ' ';
2364 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2365 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2367 Math.min(opt.width || cw , this.maxWidth),
2368 Math.max(opt.minWidth || this.minWidth, bwidth)
2371 activeTextEl.setWidth(w);
2373 if(dlg.isVisible()){
2374 dlg.fixedcenter = false;
2376 // to big, make it scroll. = But as usual stupid IE does not support
2379 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2380 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2381 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2383 bodyEl.dom.style.height = '';
2384 bodyEl.dom.style.overflowY = '';
2387 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2389 bodyEl.dom.style.overflowX = '';
2392 dlg.setContentSize(w, bodyEl.getHeight());
2393 if(dlg.isVisible()){
2394 dlg.fixedcenter = true;
2400 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2401 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2402 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2403 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2404 * @return {Roo.MessageBox} This message box
2406 updateProgress : function(value, text){
2408 this.updateText(text);
2410 if (pp) { // weird bug on my firefox - for some reason this is not defined
2411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2417 * Returns true if the message box is currently displayed
2418 * @return {Boolean} True if the message box is visible, else false
2420 isVisible : function(){
2421 return dlg && dlg.isVisible();
2425 * Hides the message box if it is displayed
2428 if(this.isVisible()){
2434 * Displays a new message box, or reinitializes an existing message box, based on the config options
2435 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2436 * The following config object properties are supported:
2438 Property Type Description
2439 ---------- --------------- ------------------------------------------------------------------------------------
2440 animEl String/Element An id or Element from which the message box should animate as it opens and
2441 closes (defaults to undefined)
2442 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2443 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2444 closable Boolean False to hide the top-right close button (defaults to true). Note that
2445 progress and wait dialogs will ignore this property and always hide the
2446 close button as they can only be closed programmatically.
2447 cls String A custom CSS class to apply to the message box element
2448 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2449 displayed (defaults to 75)
2450 fn Function A callback function to execute after closing the dialog. The arguments to the
2451 function will be btn (the name of the button that was clicked, if applicable,
2452 e.g. "ok"), and text (the value of the active text field, if applicable).
2453 Progress and wait dialogs will ignore this option since they do not respond to
2454 user actions and can only be closed programmatically, so any required function
2455 should be called by the same code after it closes the dialog.
2456 icon String A CSS class that provides a background image to be used as an icon for
2457 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2458 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2459 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2460 modal Boolean False to allow user interaction with the page while the message box is
2461 displayed (defaults to true)
2462 msg String A string that will replace the existing message box body text (defaults
2463 to the XHTML-compliant non-breaking space character ' ')
2464 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2465 progress Boolean True to display a progress bar (defaults to false)
2466 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2467 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2468 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2469 title String The title text
2470 value String The string value to set into the active textbox element if displayed
2471 wait Boolean True to display a progress bar (defaults to false)
2472 width Number The width of the dialog in pixels
2479 msg: 'Please enter your address:',
2481 buttons: Roo.MessageBox.OKCANCEL,
2484 animEl: 'addAddressBtn'
2487 * @param {Object} config Configuration options
2488 * @return {Roo.MessageBox} This message box
2490 show : function(options)
2493 // this causes nightmares if you show one dialog after another
2494 // especially on callbacks..
2496 if(this.isVisible()){
2499 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2500 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2501 Roo.log("New Dialog Message:" + options.msg )
2502 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2503 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2506 var d = this.getDialog();
2508 d.setTitle(opt.title || " ");
2509 d.close.setDisplayed(opt.closable !== false);
2510 activeTextEl = textboxEl;
2511 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2516 textareaEl.setHeight(typeof opt.multiline == "number" ?
2517 opt.multiline : this.defaultTextHeight);
2518 activeTextEl = textareaEl;
2527 progressEl.setDisplayed(opt.progress === true);
2528 this.updateProgress(0);
2529 activeTextEl.dom.value = opt.value || "";
2531 dlg.setDefaultButton(activeTextEl);
2533 var bs = opt.buttons;
2537 }else if(bs && bs.yes){
2538 db = buttons["yes"];
2540 dlg.setDefaultButton(db);
2542 bwidth = updateButtons(opt.buttons);
2543 this.updateText(opt.msg);
2545 d.el.addClass(opt.cls);
2547 d.proxyDrag = opt.proxyDrag === true;
2548 d.modal = opt.modal !== false;
2549 d.mask = opt.modal !== false ? mask : false;
2551 // force it to the end of the z-index stack so it gets a cursor in FF
2552 document.body.appendChild(dlg.el.dom);
2553 d.animateTarget = null;
2554 d.show(options.animEl);
2560 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2561 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2562 * and closing the message box when the process is complete.
2563 * @param {String} title The title bar text
2564 * @param {String} msg The message box body text
2565 * @return {Roo.MessageBox} This message box
2567 progress : function(title, msg){
2574 minWidth: this.minProgressWidth,
2581 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2582 * If a callback function is passed it will be called after the user clicks the button, and the
2583 * id of the button that was clicked will be passed as the only parameter to the callback
2584 * (could also be the top-right close button).
2585 * @param {String} title The title bar text
2586 * @param {String} msg The message box body text
2587 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2588 * @param {Object} scope (optional) The scope of the callback function
2589 * @return {Roo.MessageBox} This message box
2591 alert : function(title, msg, fn, scope){
2604 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2605 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2606 * You are responsible for closing the message box when the process is complete.
2607 * @param {String} msg The message box body text
2608 * @param {String} title (optional) The title bar text
2609 * @return {Roo.MessageBox} This message box
2611 wait : function(msg, title){
2622 waitTimer = Roo.TaskMgr.start({
2624 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2632 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2633 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2634 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2635 * @param {String} title The title bar text
2636 * @param {String} msg The message box body text
2637 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2638 * @param {Object} scope (optional) The scope of the callback function
2639 * @return {Roo.MessageBox} This message box
2641 confirm : function(title, msg, fn, scope){
2645 buttons: this.YESNO,
2654 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2655 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2656 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2657 * (could also be the top-right close button) and the text that was entered will be passed as the two
2658 * parameters to the callback.
2659 * @param {String} title The title bar text
2660 * @param {String} msg The message box body text
2661 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2662 * @param {Object} scope (optional) The scope of the callback function
2663 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2664 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2665 * @return {Roo.MessageBox} This message box
2667 prompt : function(title, msg, fn, scope, multiline){
2671 buttons: this.OKCANCEL,
2676 multiline: multiline,
2683 * Button config that displays a single OK button
2688 * Button config that displays Yes and No buttons
2691 YESNO : {yes:true, no:true},
2693 * Button config that displays OK and Cancel buttons
2696 OKCANCEL : {ok:true, cancel:true},
2698 * Button config that displays Yes, No and Cancel buttons
2701 YESNOCANCEL : {yes:true, no:true, cancel:true},
2704 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2707 defaultTextHeight : 75,
2709 * The maximum width in pixels of the message box (defaults to 600)
2714 * The minimum width in pixels of the message box (defaults to 100)
2719 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2720 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2723 minProgressWidth : 250,
2725 * An object containing the default button text strings that can be overriden for localized language support.
2726 * Supported properties are: ok, cancel, yes and no.
2727 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2740 * Shorthand for {@link Roo.MessageBox}
2742 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2743 Roo.Msg = Roo.Msg || Roo.MessageBox;
2752 * @class Roo.bootstrap.Navbar
2753 * @extends Roo.bootstrap.Component
2754 * Bootstrap Navbar class
2757 * Create a new Navbar
2758 * @param {Object} config The config object
2762 Roo.bootstrap.Navbar = function(config){
2763 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2767 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2776 getAutoCreate : function(){
2779 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2783 initEvents :function ()
2785 //Roo.log(this.el.select('.navbar-toggle',true));
2786 this.el.select('.navbar-toggle',true).on('click', function() {
2787 // Roo.log('click');
2788 this.el.select('.navbar-collapse',true).toggleClass('in');
2796 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2798 var size = this.el.getSize();
2799 this.maskEl.setSize(size.width, size.height);
2800 this.maskEl.enableDisplayMode("block");
2809 getChildContainer : function()
2811 if (this.el.select('.collapse').getCount()) {
2812 return this.el.select('.collapse',true).first();
2845 * @class Roo.bootstrap.NavSimplebar
2846 * @extends Roo.bootstrap.Navbar
2847 * Bootstrap Sidebar class
2849 * @cfg {Boolean} inverse is inverted color
2851 * @cfg {String} type (nav | pills | tabs)
2852 * @cfg {Boolean} arrangement stacked | justified
2853 * @cfg {String} align (left | right) alignment
2855 * @cfg {Boolean} main (true|false) main nav bar? default false
2856 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2858 * @cfg {String} tag (header|footer|nav|div) default is nav
2864 * Create a new Sidebar
2865 * @param {Object} config The config object
2869 Roo.bootstrap.NavSimplebar = function(config){
2870 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2873 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2889 getAutoCreate : function(){
2893 tag : this.tag || 'div',
2906 this.type = this.type || 'nav';
2907 if (['tabs','pills'].indexOf(this.type)!==-1) {
2908 cfg.cn[0].cls += ' nav-' + this.type
2912 if (this.type!=='nav') {
2913 Roo.log('nav type must be nav/tabs/pills')
2915 cfg.cn[0].cls += ' navbar-nav'
2921 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2922 cfg.cn[0].cls += ' nav-' + this.arrangement;
2926 if (this.align === 'right') {
2927 cfg.cn[0].cls += ' navbar-right';
2931 cfg.cls += ' navbar-inverse';
2958 * @class Roo.bootstrap.NavHeaderbar
2959 * @extends Roo.bootstrap.NavSimplebar
2960 * Bootstrap Sidebar class
2962 * @cfg {String} brand what is brand
2963 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2964 * @cfg {String} brand_href href of the brand
2967 * Create a new Sidebar
2968 * @param {Object} config The config object
2972 Roo.bootstrap.NavHeaderbar = function(config){
2973 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2976 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2983 getAutoCreate : function(){
2988 tag: this.nav || 'nav',
2994 cls: 'navbar-header',
2999 cls: 'navbar-toggle',
3000 'data-toggle': 'collapse',
3005 html: 'Toggle navigation'
3025 cls: 'collapse navbar-collapse'
3030 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3032 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3033 cfg.cls += ' navbar-' + this.position;
3035 // tag can override this..
3037 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3040 if (this.brand !== '') {
3043 href: this.brand_href ? this.brand_href : '#',
3044 cls: 'navbar-brand',
3052 cfg.cls += ' main-nav';
3077 * @class Roo.bootstrap.NavSidebar
3078 * @extends Roo.bootstrap.Navbar
3079 * Bootstrap Sidebar class
3082 * Create a new Sidebar
3083 * @param {Object} config The config object
3087 Roo.bootstrap.NavSidebar = function(config){
3088 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3091 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3093 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3095 getAutoCreate : function(){
3100 cls: 'sidebar sidebar-nav'
3122 * @class Roo.bootstrap.NavGroup
3123 * @extends Roo.bootstrap.Component
3124 * Bootstrap NavGroup class
3125 * @cfg {String} align left | right
3126 * @cfg {Boolean} inverse false | true
3127 * @cfg {String} type (nav|pills|tab) default nav
3128 * @cfg {String} navId - reference Id for navbar.
3132 * Create a new nav group
3133 * @param {Object} config The config object
3136 Roo.bootstrap.NavGroup = function(config){
3137 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3139 Roo.bootstrap.NavGroup.register(this);
3143 * Fires when the active item changes
3144 * @param {Roo.bootstrap.NavGroup} this
3145 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3146 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3153 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3164 getAutoCreate : function()
3166 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3173 if (['tabs','pills'].indexOf(this.type)!==-1) {
3174 cfg.cls += ' nav-' + this.type
3176 if (this.type!=='nav') {
3177 Roo.log('nav type must be nav/tabs/pills')
3179 cfg.cls += ' navbar-nav'
3182 if (this.parent().sidebar) {
3185 cls: 'dashboard-menu sidebar-menu'
3191 if (this.form === true) {
3197 if (this.align === 'right') {
3198 cfg.cls += ' navbar-right';
3200 cfg.cls += ' navbar-left';
3204 if (this.align === 'right') {
3205 cfg.cls += ' navbar-right';
3209 cfg.cls += ' navbar-inverse';
3217 setActiveItem : function(item)
3220 Roo.each(this.navItems, function(v){
3225 v.setActive(false, true);
3232 item.setActive(true, true);
3233 this.fireEvent('changed', this, item, prev);
3238 addItem : function(cfg)
3240 var cn = new Roo.bootstrap.NavItem(cfg);
3242 cn.parentId = this.id;
3243 cn.onRender(this.el, null);
3247 register : function(item)
3249 this.navItems.push( item);
3250 item.navId = this.navId;
3253 getNavItem: function(tabId)
3256 Roo.each(this.navItems, function(e) {
3257 if (e.tabId == tabId) {
3273 Roo.apply(Roo.bootstrap.NavGroup, {
3277 register : function(navgrp)
3279 this.groups[navgrp.navId] = navgrp;
3282 get: function(navId) {
3283 return this.groups[navId];
3298 * @class Roo.bootstrap.NavItem
3299 * @extends Roo.bootstrap.Component
3300 * Bootstrap Navbar.NavItem class
3301 * @cfg {String} href link to
3302 * @cfg {String} html content of button
3303 * @cfg {String} badge text inside badge
3304 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3305 * @cfg {String} glyphicon name of glyphicon
3306 * @cfg {String} icon name of font awesome icon
3307 * @cfg {Boolean} active Is item active
3308 * @cfg {Boolean} disabled Is item disabled
3310 * @cfg {Boolean} preventDefault (true | false) default false
3311 * @cfg {String} tabId the tab that this item activates.
3312 * @cfg {String} tagtype (a|span) render as a href or span?
3315 * Create a new Navbar Item
3316 * @param {Object} config The config object
3318 Roo.bootstrap.NavItem = function(config){
3319 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3324 * The raw click event for the entire grid.
3325 * @param {Roo.EventObject} e
3330 * Fires when the active item active state changes
3331 * @param {Roo.bootstrap.NavItem} this
3332 * @param {boolean} state the new state
3340 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3348 preventDefault : false,
3353 getAutoCreate : function(){
3361 href : this.href || "#",
3362 html: this.html || ''
3368 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3371 // glyphicon and icon go before content..
3372 if (this.glyphicon || this.icon) {
3374 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3376 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3384 cfg.cn[0].html += " <span class='caret'></span>";
3388 if (this.badge !== '') {
3390 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3392 if (this.disabled) {
3393 cfg.cls += ' disabled';
3399 initEvents: function() {
3400 // Roo.log('init events?');
3401 // Roo.log(this.el.dom);
3402 if (typeof (this.menu) != 'undefined') {
3403 this.menu.parentType = this.xtype;
3404 this.menu.triggerEl = this.el;
3405 this.addxtype(Roo.apply({}, this.menu));
3409 this.el.select('a',true).on('click', this.onClick, this);
3410 // at this point parent should be available..
3411 this.parent().register(this);
3414 onClick : function(e)
3417 if(this.preventDefault){
3420 if (this.disabled) {
3423 Roo.log("fire event clicked");
3424 if(this.fireEvent('click', this, e) === false){
3428 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3429 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3430 this.parent().setActiveItem(this);
3438 isActive: function () {
3441 setActive : function(state, fire)
3443 this.active = state;
3445 this.el.removeClass('active');
3446 } else if (!this.el.hasClass('active')) {
3447 this.el.addClass('active');
3450 this.fireEvent('changed', this, state);
3455 // this should not be here...
3456 setDisabled : function(state)
3458 this.disabled = state;
3460 this.el.removeClass('disabled');
3461 } else if (!this.el.hasClass('disabled')) {
3462 this.el.addClass('disabled');
3475 * <span> icon </span>
3476 * <span> text </span>
3477 * <span>badge </span>
3481 * @class Roo.bootstrap.NavSidebarItem
3482 * @extends Roo.bootstrap.NavItem
3483 * Bootstrap Navbar.NavSidebarItem class
3485 * Create a new Navbar Button
3486 * @param {Object} config The config object
3488 Roo.bootstrap.NavSidebarItem = function(config){
3489 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3494 * The raw click event for the entire grid.
3495 * @param {Roo.EventObject} e
3500 * Fires when the active item active state changes
3501 * @param {Roo.bootstrap.NavSidebarItem} this
3502 * @param {boolean} state the new state
3510 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3513 getAutoCreate : function(){
3518 href : this.href || '#',
3530 html : this.html || ''
3535 cfg.cls += ' active';
3539 if (this.glyphicon || this.icon) {
3540 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3541 a.cn.push({ tag : 'i', cls : c }) ;
3546 if (this.badge !== '') {
3547 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3551 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3552 a.cls += 'dropdown-toggle treeview' ;
3576 * @class Roo.bootstrap.Row
3577 * @extends Roo.bootstrap.Component
3578 * Bootstrap Row class (contains columns...)
3582 * @param {Object} config The config object
3585 Roo.bootstrap.Row = function(config){
3586 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3589 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3591 getAutoCreate : function(){
3610 * @class Roo.bootstrap.Element
3611 * @extends Roo.bootstrap.Component
3612 * Bootstrap Element class
3613 * @cfg {String} html contents of the element
3614 * @cfg {String} tag tag of the element
3615 * @cfg {String} cls class of the element
3618 * Create a new Element
3619 * @param {Object} config The config object
3622 Roo.bootstrap.Element = function(config){
3623 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3626 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3658 * @class Roo.bootstrap.Pagination
3659 * @extends Roo.bootstrap.Component
3660 * Bootstrap Pagination class
3661 * @cfg {String} size xs | sm | md | lg
3662 * @cfg {Boolean} inverse false | true
3665 * Create a new Pagination
3666 * @param {Object} config The config object
3669 Roo.bootstrap.Pagination = function(config){
3670 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3673 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3679 getAutoCreate : function(){
3685 cfg.cls += ' inverse';
3691 cfg.cls += " " + this.cls;
3709 * @class Roo.bootstrap.PaginationItem
3710 * @extends Roo.bootstrap.Component
3711 * Bootstrap PaginationItem class
3712 * @cfg {String} html text
3713 * @cfg {String} href the link
3714 * @cfg {Boolean} preventDefault (true | false) default true
3715 * @cfg {Boolean} active (true | false) default false
3719 * Create a new PaginationItem
3720 * @param {Object} config The config object
3724 Roo.bootstrap.PaginationItem = function(config){
3725 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3730 * The raw click event for the entire grid.
3731 * @param {Roo.EventObject} e
3737 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3741 preventDefault: true,
3745 getAutoCreate : function(){
3751 href : this.href ? this.href : '#',
3752 html : this.html ? this.html : ''
3762 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3768 initEvents: function() {
3770 this.el.on('click', this.onClick, this);
3773 onClick : function(e)
3775 Roo.log('PaginationItem on click ');
3776 if(this.preventDefault){
3780 this.fireEvent('click', this, e);
3796 * @class Roo.bootstrap.Slider
3797 * @extends Roo.bootstrap.Component
3798 * Bootstrap Slider class
3801 * Create a new Slider
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Slider = function(config){
3806 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3811 getAutoCreate : function(){
3815 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3819 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3837 * @class Roo.bootstrap.Table
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Table class
3840 * @cfg {String} cls table class
3841 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3842 * @cfg {String} bgcolor Specifies the background color for a table
3843 * @cfg {Number} border Specifies whether the table cells should have borders or not
3844 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3845 * @cfg {Number} cellspacing Specifies the space between cells
3846 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3847 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3848 * @cfg {String} sortable Specifies that the table should be sortable
3849 * @cfg {String} summary Specifies a summary of the content of a table
3850 * @cfg {Number} width Specifies the width of a table
3852 * @cfg {boolean} striped Should the rows be alternative striped
3853 * @cfg {boolean} bordered Add borders to the table
3854 * @cfg {boolean} hover Add hover highlighting
3855 * @cfg {boolean} condensed Format condensed
3856 * @cfg {boolean} responsive Format condensed
3857 * @cfg {Boolean} loadMask (true|false) default false
3859 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
3863 * Create a new Table
3864 * @param {Object} config The config object
3867 Roo.bootstrap.Table = function(config){
3868 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3871 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3872 this.sm = this.selModel;
3873 this.sm.xmodule = this.xmodule || false;
3875 if (this.cm && typeof(this.cm.config) == 'undefined') {
3876 this.colModel = new Roo.grid.ColumnModel(this.cm);
3877 this.cm = this.colModel;
3878 this.cm.xmodule = this.xmodule || false;
3881 this.store= Roo.factory(this.store, Roo.data);
3882 this.ds = this.store;
3883 this.ds.xmodule = this.xmodule || false;
3886 if (this.footer && this.store) {
3887 this.footer.dataSource = this.ds;
3888 this.footer = Roo.factory(this.footer);
3892 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3915 getAutoCreate : function(){
3916 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3925 cfg.cls += ' table-striped';
3928 cfg.cls += ' table-hover';
3930 if (this.bordered) {
3931 cfg.cls += ' table-bordered';
3933 if (this.condensed) {
3934 cfg.cls += ' table-condensed';
3936 if (this.responsive) {
3937 cfg.cls += ' table-responsive';
3944 cfg.cls+= ' ' +this.cls;
3947 // this lot should be simplifed...
3950 cfg.align=this.align;
3953 cfg.bgcolor=this.bgcolor;
3956 cfg.border=this.border;
3958 if (this.cellpadding) {
3959 cfg.cellpadding=this.cellpadding;
3961 if (this.cellspacing) {
3962 cfg.cellspacing=this.cellspacing;
3965 cfg.frame=this.frame;
3968 cfg.rules=this.rules;
3970 if (this.sortable) {
3971 cfg.sortable=this.sortable;
3974 cfg.summary=this.summary;
3977 cfg.width=this.width;
3980 if(this.store || this.cm){
3981 cfg.cn.push(this.renderHeader());
3982 cfg.cn.push(this.renderBody());
3983 cfg.cn.push(this.renderFooter());
3985 cfg.cls+= ' TableGrid';
3991 // initTableGrid : function()
4000 // var cm = this.cm;
4002 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4005 // html: cm.getColumnHeader(i)
4009 // cfg.push(header);
4016 initEvents : function()
4018 if(!this.store || !this.cm){
4022 Roo.log('initEvents with ds!!!!');
4026 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4027 e.on('click', _this.sort, _this);
4029 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4030 // this.maskEl.enableDisplayMode("block");
4031 // this.maskEl.show();
4033 this.parent().el.setStyle('position', 'relative');
4035 this.footer.parentId = this.id;
4036 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4040 // mask should be using Roo.bootstrap.Mask...
4045 style: "text-align:center",
4049 style: "background-color:white;width:50%;margin:100 auto; display:none",
4053 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
4064 this.maskEl = Roo.DomHelper.append(document.body, mark, true);
4066 var size = this.parent().el.getSize();
4068 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4070 this.maskEl.enableDisplayMode("block");
4072 this.store.on('load', this.onLoad, this);
4073 this.store.on('beforeload', this.onBeforeLoad, this);
4075 // load should be trigger on render..
4076 //this.store.load();
4082 sort : function(e,el)
4084 var col = Roo.get(el)
4086 if(!col.hasClass('sortable')){
4090 var sort = col.attr('sort');
4093 if(col.hasClass('glyphicon-arrow-up')){
4097 this.store.sortInfo = {field : sort, direction : dir};
4102 renderHeader : function()
4111 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4113 var config = cm.config[i];
4115 if(typeof(config.hidden) != 'undefined' && config.hidden){
4121 html: cm.getColumnHeader(i)
4124 if(typeof(config.dataIndex) != 'undefined'){
4125 c.sort = config.dataIndex;
4128 if(typeof(config.sortable) != 'undefined' && config.sortable){
4132 if(typeof(config.width) != 'undefined'){
4133 c.style = 'width:' + config.width + 'px';
4142 renderBody : function()
4152 renderFooter : function()
4174 Roo.log('ds onload');
4179 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4180 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4182 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4183 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4186 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4187 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4191 var tbody = this.el.select('tbody', true).first();
4195 if(this.store.getCount() > 0){
4196 this.store.data.each(function(d){
4202 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4203 var config = cm.config[i];
4205 if(typeof(config.hidden) != 'undefined' && config.hidden){
4209 var renderer = cm.getRenderer(i);
4213 if(typeof(renderer) !== 'undefined'){
4214 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4217 if(typeof(value) === 'object'){
4227 html: (typeof(value) === 'object') ? '' : value
4230 if(typeof(config.width) != 'undefined'){
4231 td.style = 'width:' + config.width + 'px';
4238 tbody.createChild(row);
4246 Roo.each(renders, function(r){
4247 _this.renderColumn(r);
4256 onBeforeLoad : function()
4258 Roo.log('ds onBeforeLoad');
4269 this.el.select('tbody', true).first().dom.innerHTML = '';
4272 getSelectionModel : function(){
4274 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4276 return this.selModel;
4279 renderColumn : function(r)
4282 r.cfg.render(Roo.get(r.id));
4285 Roo.each(r.cfg.cn, function(c){
4290 _this.renderColumn(child);
4307 * @class Roo.bootstrap.TableCell
4308 * @extends Roo.bootstrap.Component
4309 * Bootstrap TableCell class
4310 * @cfg {String} html cell contain text
4311 * @cfg {String} cls cell class
4312 * @cfg {String} tag cell tag (td|th) default td
4313 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4314 * @cfg {String} align Aligns the content in a cell
4315 * @cfg {String} axis Categorizes cells
4316 * @cfg {String} bgcolor Specifies the background color of a cell
4317 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4318 * @cfg {Number} colspan Specifies the number of columns a cell should span
4319 * @cfg {String} headers Specifies one or more header cells a cell is related to
4320 * @cfg {Number} height Sets the height of a cell
4321 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4322 * @cfg {Number} rowspan Sets the number of rows a cell should span
4323 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4324 * @cfg {String} valign Vertical aligns the content in a cell
4325 * @cfg {Number} width Specifies the width of a cell
4328 * Create a new TableCell
4329 * @param {Object} config The config object
4332 Roo.bootstrap.TableCell = function(config){
4333 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4336 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4356 getAutoCreate : function(){
4357 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4377 cfg.align=this.align
4383 cfg.bgcolor=this.bgcolor
4386 cfg.charoff=this.charoff
4389 cfg.colspan=this.colspan
4392 cfg.headers=this.headers
4395 cfg.height=this.height
4398 cfg.nowrap=this.nowrap
4401 cfg.rowspan=this.rowspan
4404 cfg.scope=this.scope
4407 cfg.valign=this.valign
4410 cfg.width=this.width
4429 * @class Roo.bootstrap.TableRow
4430 * @extends Roo.bootstrap.Component
4431 * Bootstrap TableRow class
4432 * @cfg {String} cls row class
4433 * @cfg {String} align Aligns the content in a table row
4434 * @cfg {String} bgcolor Specifies a background color for a table row
4435 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4436 * @cfg {String} valign Vertical aligns the content in a table row
4439 * Create a new TableRow
4440 * @param {Object} config The config object
4443 Roo.bootstrap.TableRow = function(config){
4444 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4447 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4455 getAutoCreate : function(){
4456 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4466 cfg.align = this.align;
4469 cfg.bgcolor = this.bgcolor;
4472 cfg.charoff = this.charoff;
4475 cfg.valign = this.valign;
4493 * @class Roo.bootstrap.TableBody
4494 * @extends Roo.bootstrap.Component
4495 * Bootstrap TableBody class
4496 * @cfg {String} cls element class
4497 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4498 * @cfg {String} align Aligns the content inside the element
4499 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4500 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4503 * Create a new TableBody
4504 * @param {Object} config The config object
4507 Roo.bootstrap.TableBody = function(config){
4508 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4511 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4519 getAutoCreate : function(){
4520 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4534 cfg.align = this.align;
4537 cfg.charoff = this.charoff;
4540 cfg.valign = this.valign;
4547 // initEvents : function()
4554 // this.store = Roo.factory(this.store, Roo.data);
4555 // this.store.on('load', this.onLoad, this);
4557 // this.store.load();
4561 // onLoad: function ()
4563 // this.fireEvent('load', this);
4573 * Ext JS Library 1.1.1
4574 * Copyright(c) 2006-2007, Ext JS, LLC.
4576 * Originally Released Under LGPL - original licence link has changed is not relivant.
4579 * <script type="text/javascript">
4582 // as we use this in bootstrap.
4583 Roo.namespace('Roo.form');
4585 * @class Roo.form.Action
4586 * Internal Class used to handle form actions
4588 * @param {Roo.form.BasicForm} el The form element or its id
4589 * @param {Object} config Configuration options
4594 // define the action interface
4595 Roo.form.Action = function(form, options){
4597 this.options = options || {};
4600 * Client Validation Failed
4603 Roo.form.Action.CLIENT_INVALID = 'client';
4605 * Server Validation Failed
4608 Roo.form.Action.SERVER_INVALID = 'server';
4610 * Connect to Server Failed
4613 Roo.form.Action.CONNECT_FAILURE = 'connect';
4615 * Reading Data from Server Failed
4618 Roo.form.Action.LOAD_FAILURE = 'load';
4620 Roo.form.Action.prototype = {
4622 failureType : undefined,
4623 response : undefined,
4627 run : function(options){
4632 success : function(response){
4637 handleResponse : function(response){
4641 // default connection failure
4642 failure : function(response){
4644 this.response = response;
4645 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4646 this.form.afterAction(this, false);
4649 processResponse : function(response){
4650 this.response = response;
4651 if(!response.responseText){
4654 this.result = this.handleResponse(response);
4658 // utility functions used internally
4659 getUrl : function(appendParams){
4660 var url = this.options.url || this.form.url || this.form.el.dom.action;
4662 var p = this.getParams();
4664 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4670 getMethod : function(){
4671 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4674 getParams : function(){
4675 var bp = this.form.baseParams;
4676 var p = this.options.params;
4678 if(typeof p == "object"){
4679 p = Roo.urlEncode(Roo.applyIf(p, bp));
4680 }else if(typeof p == 'string' && bp){
4681 p += '&' + Roo.urlEncode(bp);
4684 p = Roo.urlEncode(bp);
4689 createCallback : function(){
4691 success: this.success,
4692 failure: this.failure,
4694 timeout: (this.form.timeout*1000),
4695 upload: this.form.fileUpload ? this.success : undefined
4700 Roo.form.Action.Submit = function(form, options){
4701 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4704 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4707 haveProgress : false,
4708 uploadComplete : false,
4710 // uploadProgress indicator.
4711 uploadProgress : function()
4713 if (!this.form.progressUrl) {
4717 if (!this.haveProgress) {
4718 Roo.MessageBox.progress("Uploading", "Uploading");
4720 if (this.uploadComplete) {
4721 Roo.MessageBox.hide();
4725 this.haveProgress = true;
4727 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4729 var c = new Roo.data.Connection();
4731 url : this.form.progressUrl,
4736 success : function(req){
4737 //console.log(data);
4741 rdata = Roo.decode(req.responseText)
4743 Roo.log("Invalid data from server..");
4747 if (!rdata || !rdata.success) {
4749 Roo.MessageBox.alert(Roo.encode(rdata));
4752 var data = rdata.data;
4754 if (this.uploadComplete) {
4755 Roo.MessageBox.hide();
4760 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4761 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4764 this.uploadProgress.defer(2000,this);
4767 failure: function(data) {
4768 Roo.log('progress url failed ');
4779 // run get Values on the form, so it syncs any secondary forms.
4780 this.form.getValues();
4782 var o = this.options;
4783 var method = this.getMethod();
4784 var isPost = method == 'POST';
4785 if(o.clientValidation === false || this.form.isValid()){
4787 if (this.form.progressUrl) {
4788 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4789 (new Date() * 1) + '' + Math.random());
4794 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4795 form:this.form.el.dom,
4796 url:this.getUrl(!isPost),
4798 params:isPost ? this.getParams() : null,
4799 isUpload: this.form.fileUpload
4802 this.uploadProgress();
4804 }else if (o.clientValidation !== false){ // client validation failed
4805 this.failureType = Roo.form.Action.CLIENT_INVALID;
4806 this.form.afterAction(this, false);
4810 success : function(response)
4812 this.uploadComplete= true;
4813 if (this.haveProgress) {
4814 Roo.MessageBox.hide();
4818 var result = this.processResponse(response);
4819 if(result === true || result.success){
4820 this.form.afterAction(this, true);
4824 this.form.markInvalid(result.errors);
4825 this.failureType = Roo.form.Action.SERVER_INVALID;
4827 this.form.afterAction(this, false);
4829 failure : function(response)
4831 this.uploadComplete= true;
4832 if (this.haveProgress) {
4833 Roo.MessageBox.hide();
4836 this.response = response;
4837 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4838 this.form.afterAction(this, false);
4841 handleResponse : function(response){
4842 if(this.form.errorReader){
4843 var rs = this.form.errorReader.read(response);
4846 for(var i = 0, len = rs.records.length; i < len; i++) {
4847 var r = rs.records[i];
4851 if(errors.length < 1){
4855 success : rs.success,
4861 ret = Roo.decode(response.responseText);
4865 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4875 Roo.form.Action.Load = function(form, options){
4876 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4877 this.reader = this.form.reader;
4880 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4885 Roo.Ajax.request(Roo.apply(
4886 this.createCallback(), {
4887 method:this.getMethod(),
4888 url:this.getUrl(false),
4889 params:this.getParams()
4893 success : function(response){
4895 var result = this.processResponse(response);
4896 if(result === true || !result.success || !result.data){
4897 this.failureType = Roo.form.Action.LOAD_FAILURE;
4898 this.form.afterAction(this, false);
4901 this.form.clearInvalid();
4902 this.form.setValues(result.data);
4903 this.form.afterAction(this, true);
4906 handleResponse : function(response){
4907 if(this.form.reader){
4908 var rs = this.form.reader.read(response);
4909 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4911 success : rs.success,
4915 return Roo.decode(response.responseText);
4919 Roo.form.Action.ACTION_TYPES = {
4920 'load' : Roo.form.Action.Load,
4921 'submit' : Roo.form.Action.Submit
4930 * @class Roo.bootstrap.Form
4931 * @extends Roo.bootstrap.Component
4932 * Bootstrap Form class
4933 * @cfg {String} method GET | POST (default POST)
4934 * @cfg {String} labelAlign top | left (default top)
4935 * @cfg {String} align left | right - for navbars
4940 * @param {Object} config The config object
4944 Roo.bootstrap.Form = function(config){
4945 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4948 * @event clientvalidation
4949 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4950 * @param {Form} this
4951 * @param {Boolean} valid true if the form has passed client-side validation
4953 clientvalidation: true,
4955 * @event beforeaction
4956 * Fires before any action is performed. Return false to cancel the action.
4957 * @param {Form} this
4958 * @param {Action} action The action to be performed
4962 * @event actionfailed
4963 * Fires when an action fails.
4964 * @param {Form} this
4965 * @param {Action} action The action that failed
4967 actionfailed : true,
4969 * @event actioncomplete
4970 * Fires when an action is completed.
4971 * @param {Form} this
4972 * @param {Action} action The action that completed
4974 actioncomplete : true
4979 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4982 * @cfg {String} method
4983 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4988 * The URL to use for form actions if one isn't supplied in the action options.
4991 * @cfg {Boolean} fileUpload
4992 * Set to true if this form is a file upload.
4996 * @cfg {Object} baseParams
4997 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5001 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5005 * @cfg {Sting} align (left|right) for navbar forms
5010 activeAction : null,
5013 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5014 * element by passing it or its id or mask the form itself by passing in true.
5017 waitMsgTarget : false,
5022 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5023 * element by passing it or its id or mask the form itself by passing in true.
5027 getAutoCreate : function(){
5031 method : this.method || 'POST',
5032 id : this.id || Roo.id(),
5035 if (this.parent().xtype.match(/^Nav/)) {
5036 cfg.cls = 'navbar-form navbar-' + this.align;
5040 if (this.labelAlign == 'left' ) {
5041 cfg.cls += ' form-horizontal';
5047 initEvents : function()
5049 this.el.on('submit', this.onSubmit, this);
5054 onSubmit : function(e){
5059 * Returns true if client-side validation on the form is successful.
5062 isValid : function(){
5063 var items = this.getItems();
5065 items.each(function(f){
5074 * Returns true if any fields in this form have changed since their original load.
5077 isDirty : function(){
5079 var items = this.getItems();
5080 items.each(function(f){
5090 * Performs a predefined action (submit or load) or custom actions you define on this form.
5091 * @param {String} actionName The name of the action type
5092 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5093 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5094 * accept other config options):
5096 Property Type Description
5097 ---------------- --------------- ----------------------------------------------------------------------------------
5098 url String The url for the action (defaults to the form's url)
5099 method String The form method to use (defaults to the form's method, or POST if not defined)
5100 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5101 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5102 validate the form on the client (defaults to false)
5104 * @return {BasicForm} this
5106 doAction : function(action, options){
5107 if(typeof action == 'string'){
5108 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5110 if(this.fireEvent('beforeaction', this, action) !== false){
5111 this.beforeAction(action);
5112 action.run.defer(100, action);
5118 beforeAction : function(action){
5119 var o = action.options;
5121 // not really supported yet.. ??
5123 //if(this.waitMsgTarget === true){
5124 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5125 //}else if(this.waitMsgTarget){
5126 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5127 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5129 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5135 afterAction : function(action, success){
5136 this.activeAction = null;
5137 var o = action.options;
5139 //if(this.waitMsgTarget === true){
5141 //}else if(this.waitMsgTarget){
5142 // this.waitMsgTarget.unmask();
5144 // Roo.MessageBox.updateProgress(1);
5145 // Roo.MessageBox.hide();
5152 Roo.callback(o.success, o.scope, [this, action]);
5153 this.fireEvent('actioncomplete', this, action);
5157 // failure condition..
5158 // we have a scenario where updates need confirming.
5159 // eg. if a locking scenario exists..
5160 // we look for { errors : { needs_confirm : true }} in the response.
5162 (typeof(action.result) != 'undefined') &&
5163 (typeof(action.result.errors) != 'undefined') &&
5164 (typeof(action.result.errors.needs_confirm) != 'undefined')
5167 Roo.log("not supported yet");
5170 Roo.MessageBox.confirm(
5171 "Change requires confirmation",
5172 action.result.errorMsg,
5177 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5187 Roo.callback(o.failure, o.scope, [this, action]);
5188 // show an error message if no failed handler is set..
5189 if (!this.hasListener('actionfailed')) {
5190 Roo.log("need to add dialog support");
5192 Roo.MessageBox.alert("Error",
5193 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5194 action.result.errorMsg :
5195 "Saving Failed, please check your entries or try again"
5200 this.fireEvent('actionfailed', this, action);
5205 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5206 * @param {String} id The value to search for
5209 findField : function(id){
5210 var items = this.getItems();
5211 var field = items.get(id);
5213 items.each(function(f){
5214 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5221 return field || null;
5224 * Mark fields in this form invalid in bulk.
5225 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5226 * @return {BasicForm} this
5228 markInvalid : function(errors){
5229 if(errors instanceof Array){
5230 for(var i = 0, len = errors.length; i < len; i++){
5231 var fieldError = errors[i];
5232 var f = this.findField(fieldError.id);
5234 f.markInvalid(fieldError.msg);
5240 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5241 field.markInvalid(errors[id]);
5245 //Roo.each(this.childForms || [], function (f) {
5246 // f.markInvalid(errors);
5253 * Set values for fields in this form in bulk.
5254 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5255 * @return {BasicForm} this
5257 setValues : function(values){
5258 if(values instanceof Array){ // array of objects
5259 for(var i = 0, len = values.length; i < len; i++){
5261 var f = this.findField(v.id);
5263 f.setValue(v.value);
5264 if(this.trackResetOnLoad){
5265 f.originalValue = f.getValue();
5269 }else{ // object hash
5272 if(typeof values[id] != 'function' && (field = this.findField(id))){
5274 if (field.setFromData &&
5276 field.displayField &&
5277 // combos' with local stores can
5278 // be queried via setValue()
5279 // to set their value..
5280 (field.store && !field.store.isLocal)
5284 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5285 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5286 field.setFromData(sd);
5289 field.setValue(values[id]);
5293 if(this.trackResetOnLoad){
5294 field.originalValue = field.getValue();
5300 //Roo.each(this.childForms || [], function (f) {
5301 // f.setValues(values);
5308 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5309 * they are returned as an array.
5310 * @param {Boolean} asString
5313 getValues : function(asString){
5314 //if (this.childForms) {
5315 // copy values from the child forms
5316 // Roo.each(this.childForms, function (f) {
5317 // this.setValues(f.getValues());
5323 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5324 if(asString === true){
5327 return Roo.urlDecode(fs);
5331 * Returns the fields in this form as an object with key/value pairs.
5332 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5335 getFieldValues : function(with_hidden)
5337 var items = this.getItems();
5339 items.each(function(f){
5343 var v = f.getValue();
5344 if (f.inputType =='radio') {
5345 if (typeof(ret[f.getName()]) == 'undefined') {
5346 ret[f.getName()] = ''; // empty..
5349 if (!f.el.dom.checked) {
5357 // not sure if this supported any more..
5358 if ((typeof(v) == 'object') && f.getRawValue) {
5359 v = f.getRawValue() ; // dates..
5361 // combo boxes where name != hiddenName...
5362 if (f.name != f.getName()) {
5363 ret[f.name] = f.getRawValue();
5365 ret[f.getName()] = v;
5372 * Clears all invalid messages in this form.
5373 * @return {BasicForm} this
5375 clearInvalid : function(){
5376 var items = this.getItems();
5378 items.each(function(f){
5389 * @return {BasicForm} this
5392 var items = this.getItems();
5393 items.each(function(f){
5397 Roo.each(this.childForms || [], function (f) {
5404 getItems : function()
5406 var r=new Roo.util.MixedCollection(false, function(o){
5407 return o.id || (o.id = Roo.id());
5409 var iter = function(el) {
5416 Roo.each(el.items,function(e) {
5435 * Ext JS Library 1.1.1
5436 * Copyright(c) 2006-2007, Ext JS, LLC.
5438 * Originally Released Under LGPL - original licence link has changed is not relivant.
5441 * <script type="text/javascript">
5444 * @class Roo.form.VTypes
5445 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5448 Roo.form.VTypes = function(){
5449 // closure these in so they are only created once.
5450 var alpha = /^[a-zA-Z_]+$/;
5451 var alphanum = /^[a-zA-Z0-9_]+$/;
5452 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5453 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5455 // All these messages and functions are configurable
5458 * The function used to validate email addresses
5459 * @param {String} value The email address
5461 'email' : function(v){
5462 return email.test(v);
5465 * The error text to display when the email validation function returns false
5468 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5470 * The keystroke filter mask to be applied on email input
5473 'emailMask' : /[a-z0-9_\.\-@]/i,
5476 * The function used to validate URLs
5477 * @param {String} value The URL
5479 'url' : function(v){
5483 * The error text to display when the url validation function returns false
5486 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5489 * The function used to validate alpha values
5490 * @param {String} value The value
5492 'alpha' : function(v){
5493 return alpha.test(v);
5496 * The error text to display when the alpha validation function returns false
5499 'alphaText' : 'This field should only contain letters and _',
5501 * The keystroke filter mask to be applied on alpha input
5504 'alphaMask' : /[a-z_]/i,
5507 * The function used to validate alphanumeric values
5508 * @param {String} value The value
5510 'alphanum' : function(v){
5511 return alphanum.test(v);
5514 * The error text to display when the alphanumeric validation function returns false
5517 'alphanumText' : 'This field should only contain letters, numbers and _',
5519 * The keystroke filter mask to be applied on alphanumeric input
5522 'alphanumMask' : /[a-z0-9_]/i
5532 * @class Roo.bootstrap.Input
5533 * @extends Roo.bootstrap.Component
5534 * Bootstrap Input class
5535 * @cfg {Boolean} disabled is it disabled
5536 * @cfg {String} fieldLabel - the label associated
5537 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5538 * @cfg {String} name name of the input
5539 * @cfg {string} fieldLabel - the label associated
5540 * @cfg {string} inputType - input / file submit ...
5541 * @cfg {string} placeholder - placeholder to put in text.
5542 * @cfg {string} before - input group add on before
5543 * @cfg {string} after - input group add on after
5544 * @cfg {string} size - (lg|sm) or leave empty..
5545 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5546 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5547 * @cfg {Number} md colspan out of 12 for computer-sized screens
5548 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5549 * @cfg {string} value default value of the input
5550 * @cfg {Number} labelWidth set the width of label (0-12)
5551 * @cfg {String} labelAlign (top|left)
5552 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5556 * Create a new Input
5557 * @param {Object} config The config object
5560 Roo.bootstrap.Input = function(config){
5561 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5566 * Fires when this field receives input focus.
5567 * @param {Roo.form.Field} this
5572 * Fires when this field loses input focus.
5573 * @param {Roo.form.Field} this
5578 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5579 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5580 * @param {Roo.form.Field} this
5581 * @param {Roo.EventObject} e The event object
5586 * Fires just before the field blurs if the field value has changed.
5587 * @param {Roo.form.Field} this
5588 * @param {Mixed} newValue The new value
5589 * @param {Mixed} oldValue The original value
5594 * Fires after the field has been marked as invalid.
5595 * @param {Roo.form.Field} this
5596 * @param {String} msg The validation message
5601 * Fires after the field has been validated with no errors.
5602 * @param {Roo.form.Field} this
5607 * Fires after the key up
5608 * @param {Roo.form.Field} this
5609 * @param {Roo.EventObject} e The event Object
5615 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5617 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5618 automatic validation (defaults to "keyup").
5620 validationEvent : "keyup",
5622 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5624 validateOnBlur : true,
5626 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5628 validationDelay : 250,
5630 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5632 focusClass : "x-form-focus", // not needed???
5636 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5638 invalidClass : "has-error",
5641 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5643 selectOnFocus : false,
5646 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5650 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5655 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5657 disableKeyFilter : false,
5660 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5664 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5668 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5670 blankText : "This field is required",
5673 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5677 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5679 maxLength : Number.MAX_VALUE,
5681 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5683 minLengthText : "The minimum length for this field is {0}",
5685 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5687 maxLengthText : "The maximum length for this field is {0}",
5691 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5692 * If available, this function will be called only after the basic validators all return true, and will be passed the
5693 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5697 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5698 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5699 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5703 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5726 parentLabelAlign : function()
5729 while (parent.parent()) {
5730 parent = parent.parent();
5731 if (typeof(parent.labelAlign) !='undefined') {
5732 return parent.labelAlign;
5739 getAutoCreate : function(){
5741 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5747 if(this.inputType != 'hidden'){
5748 cfg.cls = 'form-group' //input-group
5754 type : this.inputType,
5756 cls : 'form-control',
5757 placeholder : this.placeholder || ''
5761 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5762 input.maxLength = this.maxLength;
5765 if (this.disabled) {
5766 input.disabled=true;
5769 if (this.readOnly) {
5770 input.readonly=true;
5774 input.name = this.name;
5777 input.cls += ' input-' + this.size;
5780 ['xs','sm','md','lg'].map(function(size){
5781 if (settings[size]) {
5782 cfg.cls += ' col-' + size + '-' + settings[size];
5786 var inputblock = input;
5788 if (this.before || this.after) {
5791 cls : 'input-group',
5794 if (this.before && typeof(this.before) == 'string') {
5796 inputblock.cn.push({
5798 cls : 'roo-input-before input-group-addon',
5802 if (this.before && typeof(this.before) == 'object') {
5803 this.before = Roo.factory(this.before);
5804 Roo.log(this.before);
5805 inputblock.cn.push({
5807 cls : 'roo-input-before input-group-' +
5808 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5812 inputblock.cn.push(input);
5814 if (this.after && typeof(this.after) == 'string') {
5815 inputblock.cn.push({
5817 cls : 'roo-input-after input-group-addon',
5821 if (this.after && typeof(this.after) == 'object') {
5822 this.after = Roo.factory(this.after);
5823 Roo.log(this.after);
5824 inputblock.cn.push({
5826 cls : 'roo-input-after input-group-' +
5827 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5832 if (align ==='left' && this.fieldLabel.length) {
5833 Roo.log("left and has label");
5839 cls : 'control-label col-sm-' + this.labelWidth,
5840 html : this.fieldLabel
5844 cls : "col-sm-" + (12 - this.labelWidth),
5851 } else if ( this.fieldLabel.length) {
5857 //cls : 'input-group-addon',
5858 html : this.fieldLabel
5868 Roo.log(" no label && no align");
5877 Roo.log('input-parentType: ' + this.parentType);
5879 if (this.parentType === 'Navbar' && this.parent().bar) {
5880 cfg.cls += ' navbar-form';
5888 * return the real input element.
5890 inputEl: function ()
5892 return this.el.select('input.form-control',true).first();
5894 setDisabled : function(v)
5896 var i = this.inputEl().dom;
5898 i.removeAttribute('disabled');
5902 i.setAttribute('disabled','true');
5904 initEvents : function()
5907 this.inputEl().on("keydown" , this.fireKey, this);
5908 this.inputEl().on("focus", this.onFocus, this);
5909 this.inputEl().on("blur", this.onBlur, this);
5911 this.inputEl().relayEvent('keyup', this);
5913 // reference to original value for reset
5914 this.originalValue = this.getValue();
5915 //Roo.form.TextField.superclass.initEvents.call(this);
5916 if(this.validationEvent == 'keyup'){
5917 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5918 this.inputEl().on('keyup', this.filterValidation, this);
5920 else if(this.validationEvent !== false){
5921 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5924 if(this.selectOnFocus){
5925 this.on("focus", this.preFocus, this);
5928 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5929 this.inputEl().on("keypress", this.filterKeys, this);
5932 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5933 this.el.on("click", this.autoSize, this);
5936 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5937 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5940 if (typeof(this.before) == 'object') {
5941 this.before.render(this.el.select('.roo-input-before',true).first());
5943 if (typeof(this.after) == 'object') {
5944 this.after.render(this.el.select('.roo-input-after',true).first());
5949 filterValidation : function(e){
5950 if(!e.isNavKeyPress()){
5951 this.validationTask.delay(this.validationDelay);
5955 * Validates the field value
5956 * @return {Boolean} True if the value is valid, else false
5958 validate : function(){
5959 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5960 if(this.disabled || this.validateValue(this.getRawValue())){
5961 this.clearInvalid();
5969 * Validates a value according to the field's validation rules and marks the field as invalid
5970 * if the validation fails
5971 * @param {Mixed} value The value to validate
5972 * @return {Boolean} True if the value is valid, else false
5974 validateValue : function(value){
5975 if(value.length < 1) { // if it's blank
5976 if(this.allowBlank){
5977 this.clearInvalid();
5980 this.markInvalid(this.blankText);
5984 if(value.length < this.minLength){
5985 this.markInvalid(String.format(this.minLengthText, this.minLength));
5988 if(value.length > this.maxLength){
5989 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5993 var vt = Roo.form.VTypes;
5994 if(!vt[this.vtype](value, this)){
5995 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5999 if(typeof this.validator == "function"){
6000 var msg = this.validator(value);
6002 this.markInvalid(msg);
6006 if(this.regex && !this.regex.test(value)){
6007 this.markInvalid(this.regexText);
6016 fireKey : function(e){
6017 //Roo.log('field ' + e.getKey());
6018 if(e.isNavKeyPress()){
6019 this.fireEvent("specialkey", this, e);
6022 focus : function (selectText){
6024 this.inputEl().focus();
6025 if(selectText === true){
6026 this.inputEl().dom.select();
6032 onFocus : function(){
6033 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6034 // this.el.addClass(this.focusClass);
6037 this.hasFocus = true;
6038 this.startValue = this.getValue();
6039 this.fireEvent("focus", this);
6043 beforeBlur : Roo.emptyFn,
6047 onBlur : function(){
6049 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6050 //this.el.removeClass(this.focusClass);
6052 this.hasFocus = false;
6053 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6056 var v = this.getValue();
6057 if(String(v) !== String(this.startValue)){
6058 this.fireEvent('change', this, v, this.startValue);
6060 this.fireEvent("blur", this);
6064 * Resets the current field value to the originally loaded value and clears any validation messages
6067 this.setValue(this.originalValue);
6068 this.clearInvalid();
6071 * Returns the name of the field
6072 * @return {Mixed} name The name field
6074 getName: function(){
6078 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6079 * @return {Mixed} value The field value
6081 getValue : function(){
6082 return this.inputEl().getValue();
6085 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6086 * @return {Mixed} value The field value
6088 getRawValue : function(){
6089 var v = this.inputEl().getValue();
6095 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6096 * @param {Mixed} value The value to set
6098 setRawValue : function(v){
6099 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6102 selectText : function(start, end){
6103 var v = this.getRawValue();
6105 start = start === undefined ? 0 : start;
6106 end = end === undefined ? v.length : end;
6107 var d = this.inputEl().dom;
6108 if(d.setSelectionRange){
6109 d.setSelectionRange(start, end);
6110 }else if(d.createTextRange){
6111 var range = d.createTextRange();
6112 range.moveStart("character", start);
6113 range.moveEnd("character", v.length-end);
6120 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6121 * @param {Mixed} value The value to set
6123 setValue : function(v){
6126 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6132 processValue : function(value){
6133 if(this.stripCharsRe){
6134 var newValue = value.replace(this.stripCharsRe, '');
6135 if(newValue !== value){
6136 this.setRawValue(newValue);
6143 preFocus : function(){
6145 if(this.selectOnFocus){
6146 this.inputEl().dom.select();
6149 filterKeys : function(e){
6151 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6154 var c = e.getCharCode(), cc = String.fromCharCode(c);
6155 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6158 if(!this.maskRe.test(cc)){
6163 * Clear any invalid styles/messages for this field
6165 clearInvalid : function(){
6167 if(!this.el || this.preventMark){ // not rendered
6170 this.el.removeClass(this.invalidClass);
6172 switch(this.msgTarget){
6174 this.el.dom.qtip = '';
6177 this.el.dom.title = '';
6181 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6186 this.errorIcon.dom.qtip = '';
6187 this.errorIcon.hide();
6188 this.un('resize', this.alignErrorIcon, this);
6192 var t = Roo.getDom(this.msgTarget);
6194 t.style.display = 'none';
6198 this.fireEvent('valid', this);
6201 * Mark this field as invalid
6202 * @param {String} msg The validation message
6204 markInvalid : function(msg){
6205 if(!this.el || this.preventMark){ // not rendered
6208 this.el.addClass(this.invalidClass);
6210 msg = msg || this.invalidText;
6211 switch(this.msgTarget){
6213 this.el.dom.qtip = msg;
6214 this.el.dom.qclass = 'x-form-invalid-tip';
6215 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6216 Roo.QuickTips.enable();
6220 this.el.dom.title = msg;
6224 var elp = this.el.findParent('.x-form-element', 5, true);
6225 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6226 this.errorEl.setWidth(elp.getWidth(true)-20);
6228 this.errorEl.update(msg);
6229 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6232 if(!this.errorIcon){
6233 var elp = this.el.findParent('.x-form-element', 5, true);
6234 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6236 this.alignErrorIcon();
6237 this.errorIcon.dom.qtip = msg;
6238 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6239 this.errorIcon.show();
6240 this.on('resize', this.alignErrorIcon, this);
6243 var t = Roo.getDom(this.msgTarget);
6245 t.style.display = this.msgDisplay;
6249 this.fireEvent('invalid', this, msg);
6252 SafariOnKeyDown : function(event)
6254 // this is a workaround for a password hang bug on chrome/ webkit.
6256 var isSelectAll = false;
6258 if(this.inputEl().dom.selectionEnd > 0){
6259 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6261 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6262 event.preventDefault();
6267 if(isSelectAll){ // backspace and delete key
6269 event.preventDefault();
6270 // this is very hacky as keydown always get's upper case.
6272 var cc = String.fromCharCode(event.getCharCode());
6273 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6277 adjustWidth : function(tag, w){
6278 tag = tag.toLowerCase();
6279 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6280 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6284 if(tag == 'textarea'){
6287 }else if(Roo.isOpera){
6291 if(tag == 'textarea'){
6310 * @class Roo.bootstrap.TextArea
6311 * @extends Roo.bootstrap.Input
6312 * Bootstrap TextArea class
6313 * @cfg {Number} cols Specifies the visible width of a text area
6314 * @cfg {Number} rows Specifies the visible number of lines in a text area
6315 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6316 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6317 * @cfg {string} html text
6320 * Create a new TextArea
6321 * @param {Object} config The config object
6324 Roo.bootstrap.TextArea = function(config){
6325 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6329 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6339 getAutoCreate : function(){
6341 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6352 value : this.value || '',
6353 html: this.html || '',
6354 cls : 'form-control',
6355 placeholder : this.placeholder || ''
6359 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6360 input.maxLength = this.maxLength;
6364 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6368 input.cols = this.cols;
6371 if (this.readOnly) {
6372 input.readonly = true;
6376 input.name = this.name;
6380 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6384 ['xs','sm','md','lg'].map(function(size){
6385 if (settings[size]) {
6386 cfg.cls += ' col-' + size + '-' + settings[size];
6390 var inputblock = input;
6392 if (this.before || this.after) {
6395 cls : 'input-group',
6399 inputblock.cn.push({
6401 cls : 'input-group-addon',
6405 inputblock.cn.push(input);
6407 inputblock.cn.push({
6409 cls : 'input-group-addon',
6416 if (align ==='left' && this.fieldLabel.length) {
6417 Roo.log("left and has label");
6423 cls : 'control-label col-sm-' + this.labelWidth,
6424 html : this.fieldLabel
6428 cls : "col-sm-" + (12 - this.labelWidth),
6435 } else if ( this.fieldLabel.length) {
6441 //cls : 'input-group-addon',
6442 html : this.fieldLabel
6452 Roo.log(" no label && no align");
6462 if (this.disabled) {
6463 input.disabled=true;
6470 * return the real textarea element.
6472 inputEl: function ()
6474 return this.el.select('textarea.form-control',true).first();
6482 * trigger field - base class for combo..
6487 * @class Roo.bootstrap.TriggerField
6488 * @extends Roo.bootstrap.Input
6489 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6490 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6491 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6492 * for which you can provide a custom implementation. For example:
6494 var trigger = new Roo.bootstrap.TriggerField();
6495 trigger.onTriggerClick = myTriggerFn;
6496 trigger.applyTo('my-field');
6499 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6500 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6501 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6502 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6504 * Create a new TriggerField.
6505 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6506 * to the base TextField)
6508 Roo.bootstrap.TriggerField = function(config){
6509 this.mimicing = false;
6510 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6513 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6515 * @cfg {String} triggerClass A CSS class to apply to the trigger
6518 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6522 /** @cfg {Boolean} grow @hide */
6523 /** @cfg {Number} growMin @hide */
6524 /** @cfg {Number} growMax @hide */
6530 autoSize: Roo.emptyFn,
6537 actionMode : 'wrap',
6541 getAutoCreate : function(){
6543 var parent = this.parent();
6545 var align = this.labelAlign || this.parentLabelAlign();
6550 cls: 'form-group' //input-group
6557 type : this.inputType,
6558 cls : 'form-control',
6559 autocomplete: 'off',
6560 placeholder : this.placeholder || ''
6564 input.name = this.name;
6567 input.cls += ' input-' + this.size;
6570 if (this.disabled) {
6571 input.disabled=true;
6574 var inputblock = input;
6576 if (this.before || this.after) {
6579 cls : 'input-group',
6583 inputblock.cn.push({
6585 cls : 'input-group-addon',
6589 inputblock.cn.push(input);
6591 inputblock.cn.push({
6593 cls : 'input-group-addon',
6606 cls: 'form-hidden-field'
6614 Roo.log('multiple');
6622 cls: 'form-hidden-field'
6626 cls: 'select2-choices',
6630 cls: 'select2-search-field',
6643 cls: 'select2-container input-group',
6648 cls: 'typeahead typeahead-long dropdown-menu',
6649 style: 'display:none'
6657 cls : 'input-group-addon btn dropdown-toggle',
6665 cls: 'combobox-clear',
6679 combobox.cls += ' select2-container-multi';
6682 if (align ==='left' && this.fieldLabel.length) {
6684 Roo.log("left and has label");
6690 cls : 'control-label col-sm-' + this.labelWidth,
6691 html : this.fieldLabel
6695 cls : "col-sm-" + (12 - this.labelWidth),
6702 } else if ( this.fieldLabel.length) {
6708 //cls : 'input-group-addon',
6709 html : this.fieldLabel
6719 Roo.log(" no label && no align");
6726 ['xs','sm','md','lg'].map(function(size){
6727 if (settings[size]) {
6728 cfg.cls += ' col-' + size + '-' + settings[size];
6739 onResize : function(w, h){
6740 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6741 // if(typeof w == 'number'){
6742 // var x = w - this.trigger.getWidth();
6743 // this.inputEl().setWidth(this.adjustWidth('input', x));
6744 // this.trigger.setStyle('left', x+'px');
6749 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6752 getResizeEl : function(){
6753 return this.inputEl();
6757 getPositionEl : function(){
6758 return this.inputEl();
6762 alignErrorIcon : function(){
6763 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6767 initEvents : function(){
6769 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6770 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6772 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6773 if(this.hideTrigger){
6774 this.trigger.setDisplayed(false);
6776 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6780 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6783 //this.trigger.addClassOnOver('x-form-trigger-over');
6784 //this.trigger.addClassOnClick('x-form-trigger-click');
6787 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6792 initTrigger : function(){
6797 onDestroy : function(){
6799 this.trigger.removeAllListeners();
6800 // this.trigger.remove();
6803 // this.wrap.remove();
6805 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6809 onFocus : function(){
6810 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6813 this.wrap.addClass('x-trigger-wrap-focus');
6814 this.mimicing = true;
6815 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6816 if(this.monitorTab){
6817 this.el.on("keydown", this.checkTab, this);
6824 checkTab : function(e){
6825 if(e.getKey() == e.TAB){
6831 onBlur : function(){
6836 mimicBlur : function(e, t){
6838 if(!this.wrap.contains(t) && this.validateBlur()){
6845 triggerBlur : function(){
6846 this.mimicing = false;
6847 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6848 if(this.monitorTab){
6849 this.el.un("keydown", this.checkTab, this);
6851 //this.wrap.removeClass('x-trigger-wrap-focus');
6852 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6856 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6857 validateBlur : function(e, t){
6862 onDisable : function(){
6863 this.inputEl().dom.disabled = true;
6864 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6866 // this.wrap.addClass('x-item-disabled');
6871 onEnable : function(){
6872 this.inputEl().dom.disabled = false;
6873 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6875 // this.el.removeClass('x-item-disabled');
6880 onShow : function(){
6881 var ae = this.getActionEl();
6884 ae.dom.style.display = '';
6885 ae.dom.style.visibility = 'visible';
6891 onHide : function(){
6892 var ae = this.getActionEl();
6893 ae.dom.style.display = 'none';
6897 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6898 * by an implementing function.
6900 * @param {EventObject} e
6902 onTriggerClick : Roo.emptyFn
6906 * Ext JS Library 1.1.1
6907 * Copyright(c) 2006-2007, Ext JS, LLC.
6909 * Originally Released Under LGPL - original licence link has changed is not relivant.
6912 * <script type="text/javascript">
6917 * @class Roo.data.SortTypes
6919 * Defines the default sorting (casting?) comparison functions used when sorting data.
6921 Roo.data.SortTypes = {
6923 * Default sort that does nothing
6924 * @param {Mixed} s The value being converted
6925 * @return {Mixed} The comparison value
6932 * The regular expression used to strip tags
6936 stripTagsRE : /<\/?[^>]+>/gi,
6939 * Strips all HTML tags to sort on text only
6940 * @param {Mixed} s The value being converted
6941 * @return {String} The comparison value
6943 asText : function(s){
6944 return String(s).replace(this.stripTagsRE, "");
6948 * Strips all HTML tags to sort on text only - Case insensitive
6949 * @param {Mixed} s The value being converted
6950 * @return {String} The comparison value
6952 asUCText : function(s){
6953 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6957 * Case insensitive string
6958 * @param {Mixed} s The value being converted
6959 * @return {String} The comparison value
6961 asUCString : function(s) {
6962 return String(s).toUpperCase();
6967 * @param {Mixed} s The value being converted
6968 * @return {Number} The comparison value
6970 asDate : function(s) {
6974 if(s instanceof Date){
6977 return Date.parse(String(s));
6982 * @param {Mixed} s The value being converted
6983 * @return {Float} The comparison value
6985 asFloat : function(s) {
6986 var val = parseFloat(String(s).replace(/,/g, ""));
6987 if(isNaN(val)) val = 0;
6993 * @param {Mixed} s The value being converted
6994 * @return {Number} The comparison value
6996 asInt : function(s) {
6997 var val = parseInt(String(s).replace(/,/g, ""));
6998 if(isNaN(val)) val = 0;
7003 * Ext JS Library 1.1.1
7004 * Copyright(c) 2006-2007, Ext JS, LLC.
7006 * Originally Released Under LGPL - original licence link has changed is not relivant.
7009 * <script type="text/javascript">
7013 * @class Roo.data.Record
7014 * Instances of this class encapsulate both record <em>definition</em> information, and record
7015 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7016 * to access Records cached in an {@link Roo.data.Store} object.<br>
7018 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7019 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7022 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7024 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7025 * {@link #create}. The parameters are the same.
7026 * @param {Array} data An associative Array of data values keyed by the field name.
7027 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7028 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7029 * not specified an integer id is generated.
7031 Roo.data.Record = function(data, id){
7032 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7037 * Generate a constructor for a specific record layout.
7038 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7039 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7040 * Each field definition object may contain the following properties: <ul>
7041 * <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,
7042 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7043 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7044 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7045 * is being used, then this is a string containing the javascript expression to reference the data relative to
7046 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7047 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7048 * this may be omitted.</p></li>
7049 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7050 * <ul><li>auto (Default, implies no conversion)</li>
7055 * <li>date</li></ul></p></li>
7056 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7057 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7058 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7059 * by the Reader into an object that will be stored in the Record. It is passed the
7060 * following parameters:<ul>
7061 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7063 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7065 * <br>usage:<br><pre><code>
7066 var TopicRecord = Roo.data.Record.create(
7067 {name: 'title', mapping: 'topic_title'},
7068 {name: 'author', mapping: 'username'},
7069 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7070 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7071 {name: 'lastPoster', mapping: 'user2'},
7072 {name: 'excerpt', mapping: 'post_text'}
7075 var myNewRecord = new TopicRecord({
7076 title: 'Do my job please',
7079 lastPost: new Date(),
7080 lastPoster: 'Animal',
7081 excerpt: 'No way dude!'
7083 myStore.add(myNewRecord);
7088 Roo.data.Record.create = function(o){
7090 f.superclass.constructor.apply(this, arguments);
7092 Roo.extend(f, Roo.data.Record);
7093 var p = f.prototype;
7094 p.fields = new Roo.util.MixedCollection(false, function(field){
7097 for(var i = 0, len = o.length; i < len; i++){
7098 p.fields.add(new Roo.data.Field(o[i]));
7100 f.getField = function(name){
7101 return p.fields.get(name);
7106 Roo.data.Record.AUTO_ID = 1000;
7107 Roo.data.Record.EDIT = 'edit';
7108 Roo.data.Record.REJECT = 'reject';
7109 Roo.data.Record.COMMIT = 'commit';
7111 Roo.data.Record.prototype = {
7113 * Readonly flag - true if this record has been modified.
7122 join : function(store){
7127 * Set the named field to the specified value.
7128 * @param {String} name The name of the field to set.
7129 * @param {Object} value The value to set the field to.
7131 set : function(name, value){
7132 if(this.data[name] == value){
7139 if(typeof this.modified[name] == 'undefined'){
7140 this.modified[name] = this.data[name];
7142 this.data[name] = value;
7143 if(!this.editing && this.store){
7144 this.store.afterEdit(this);
7149 * Get the value of the named field.
7150 * @param {String} name The name of the field to get the value of.
7151 * @return {Object} The value of the field.
7153 get : function(name){
7154 return this.data[name];
7158 beginEdit : function(){
7159 this.editing = true;
7164 cancelEdit : function(){
7165 this.editing = false;
7166 delete this.modified;
7170 endEdit : function(){
7171 this.editing = false;
7172 if(this.dirty && this.store){
7173 this.store.afterEdit(this);
7178 * Usually called by the {@link Roo.data.Store} which owns the Record.
7179 * Rejects all changes made to the Record since either creation, or the last commit operation.
7180 * Modified fields are reverted to their original values.
7182 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7183 * of reject operations.
7185 reject : function(){
7186 var m = this.modified;
7188 if(typeof m[n] != "function"){
7189 this.data[n] = m[n];
7193 delete this.modified;
7194 this.editing = false;
7196 this.store.afterReject(this);
7201 * Usually called by the {@link Roo.data.Store} which owns the Record.
7202 * Commits all changes made to the Record since either creation, or the last commit operation.
7204 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7205 * of commit operations.
7207 commit : function(){
7209 delete this.modified;
7210 this.editing = false;
7212 this.store.afterCommit(this);
7217 hasError : function(){
7218 return this.error != null;
7222 clearError : function(){
7227 * Creates a copy of this record.
7228 * @param {String} id (optional) A new record id if you don't want to use this record's id
7231 copy : function(newId) {
7232 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7236 * Ext JS Library 1.1.1
7237 * Copyright(c) 2006-2007, Ext JS, LLC.
7239 * Originally Released Under LGPL - original licence link has changed is not relivant.
7242 * <script type="text/javascript">
7248 * @class Roo.data.Store
7249 * @extends Roo.util.Observable
7250 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7251 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7253 * 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
7254 * has no knowledge of the format of the data returned by the Proxy.<br>
7256 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7257 * instances from the data object. These records are cached and made available through accessor functions.
7259 * Creates a new Store.
7260 * @param {Object} config A config object containing the objects needed for the Store to access data,
7261 * and read the data into Records.
7263 Roo.data.Store = function(config){
7264 this.data = new Roo.util.MixedCollection(false);
7265 this.data.getKey = function(o){
7268 this.baseParams = {};
7275 "multisort" : "_multisort"
7278 if(config && config.data){
7279 this.inlineData = config.data;
7283 Roo.apply(this, config);
7285 if(this.reader){ // reader passed
7286 this.reader = Roo.factory(this.reader, Roo.data);
7287 this.reader.xmodule = this.xmodule || false;
7288 if(!this.recordType){
7289 this.recordType = this.reader.recordType;
7291 if(this.reader.onMetaChange){
7292 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7296 if(this.recordType){
7297 this.fields = this.recordType.prototype.fields;
7303 * @event datachanged
7304 * Fires when the data cache has changed, and a widget which is using this Store
7305 * as a Record cache should refresh its view.
7306 * @param {Store} this
7311 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7312 * @param {Store} this
7313 * @param {Object} meta The JSON metadata
7318 * Fires when Records have been added to the Store
7319 * @param {Store} this
7320 * @param {Roo.data.Record[]} records The array of Records added
7321 * @param {Number} index The index at which the record(s) were added
7326 * Fires when a Record has been removed from the Store
7327 * @param {Store} this
7328 * @param {Roo.data.Record} record The Record that was removed
7329 * @param {Number} index The index at which the record was removed
7334 * Fires when a Record has been updated
7335 * @param {Store} this
7336 * @param {Roo.data.Record} record The Record that was updated
7337 * @param {String} operation The update operation being performed. Value may be one of:
7339 Roo.data.Record.EDIT
7340 Roo.data.Record.REJECT
7341 Roo.data.Record.COMMIT
7347 * Fires when the data cache has been cleared.
7348 * @param {Store} this
7353 * Fires before a request is made for a new data object. If the beforeload handler returns false
7354 * the load action will be canceled.
7355 * @param {Store} this
7356 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7360 * @event beforeloadadd
7361 * Fires after a new set of Records has been loaded.
7362 * @param {Store} this
7363 * @param {Roo.data.Record[]} records The Records that were loaded
7364 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7366 beforeloadadd : true,
7369 * Fires after a new set of Records has been loaded, before they are added to the store.
7370 * @param {Store} this
7371 * @param {Roo.data.Record[]} records The Records that were loaded
7372 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7373 * @params {Object} return from reader
7377 * @event loadexception
7378 * Fires if an exception occurs in the Proxy during loading.
7379 * Called with the signature of the Proxy's "loadexception" event.
7380 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7383 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7384 * @param {Object} load options
7385 * @param {Object} jsonData from your request (normally this contains the Exception)
7387 loadexception : true
7391 this.proxy = Roo.factory(this.proxy, Roo.data);
7392 this.proxy.xmodule = this.xmodule || false;
7393 this.relayEvents(this.proxy, ["loadexception"]);
7395 this.sortToggle = {};
7396 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7398 Roo.data.Store.superclass.constructor.call(this);
7400 if(this.inlineData){
7401 this.loadData(this.inlineData);
7402 delete this.inlineData;
7406 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7408 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7409 * without a remote query - used by combo/forms at present.
7413 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7416 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7419 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7420 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7423 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7424 * on any HTTP request
7427 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7430 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7434 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7435 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7440 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7441 * loaded or when a record is removed. (defaults to false).
7443 pruneModifiedRecords : false,
7449 * Add Records to the Store and fires the add event.
7450 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7452 add : function(records){
7453 records = [].concat(records);
7454 for(var i = 0, len = records.length; i < len; i++){
7455 records[i].join(this);
7457 var index = this.data.length;
7458 this.data.addAll(records);
7459 this.fireEvent("add", this, records, index);
7463 * Remove a Record from the Store and fires the remove event.
7464 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7466 remove : function(record){
7467 var index = this.data.indexOf(record);
7468 this.data.removeAt(index);
7469 if(this.pruneModifiedRecords){
7470 this.modified.remove(record);
7472 this.fireEvent("remove", this, record, index);
7476 * Remove all Records from the Store and fires the clear event.
7478 removeAll : function(){
7480 if(this.pruneModifiedRecords){
7483 this.fireEvent("clear", this);
7487 * Inserts Records to the Store at the given index and fires the add event.
7488 * @param {Number} index The start index at which to insert the passed Records.
7489 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7491 insert : function(index, records){
7492 records = [].concat(records);
7493 for(var i = 0, len = records.length; i < len; i++){
7494 this.data.insert(index, records[i]);
7495 records[i].join(this);
7497 this.fireEvent("add", this, records, index);
7501 * Get the index within the cache of the passed Record.
7502 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7503 * @return {Number} The index of the passed Record. Returns -1 if not found.
7505 indexOf : function(record){
7506 return this.data.indexOf(record);
7510 * Get the index within the cache of the Record with the passed id.
7511 * @param {String} id The id of the Record to find.
7512 * @return {Number} The index of the Record. Returns -1 if not found.
7514 indexOfId : function(id){
7515 return this.data.indexOfKey(id);
7519 * Get the Record with the specified id.
7520 * @param {String} id The id of the Record to find.
7521 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7523 getById : function(id){
7524 return this.data.key(id);
7528 * Get the Record at the specified index.
7529 * @param {Number} index The index of the Record to find.
7530 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7532 getAt : function(index){
7533 return this.data.itemAt(index);
7537 * Returns a range of Records between specified indices.
7538 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7539 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7540 * @return {Roo.data.Record[]} An array of Records
7542 getRange : function(start, end){
7543 return this.data.getRange(start, end);
7547 storeOptions : function(o){
7548 o = Roo.apply({}, o);
7551 this.lastOptions = o;
7555 * Loads the Record cache from the configured Proxy using the configured Reader.
7557 * If using remote paging, then the first load call must specify the <em>start</em>
7558 * and <em>limit</em> properties in the options.params property to establish the initial
7559 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7561 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7562 * and this call will return before the new data has been loaded. Perform any post-processing
7563 * in a callback function, or in a "load" event handler.</strong>
7565 * @param {Object} options An object containing properties which control loading options:<ul>
7566 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7567 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7568 * passed the following arguments:<ul>
7569 * <li>r : Roo.data.Record[]</li>
7570 * <li>options: Options object from the load call</li>
7571 * <li>success: Boolean success indicator</li></ul></li>
7572 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7573 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7576 load : function(options){
7577 options = options || {};
7578 if(this.fireEvent("beforeload", this, options) !== false){
7579 this.storeOptions(options);
7580 var p = Roo.apply(options.params || {}, this.baseParams);
7581 // if meta was not loaded from remote source.. try requesting it.
7582 if (!this.reader.metaFromRemote) {
7585 if(this.sortInfo && this.remoteSort){
7586 var pn = this.paramNames;
7587 p[pn["sort"]] = this.sortInfo.field;
7588 p[pn["dir"]] = this.sortInfo.direction;
7590 if (this.multiSort) {
7591 var pn = this.paramNames;
7592 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7595 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7600 * Reloads the Record cache from the configured Proxy using the configured Reader and
7601 * the options from the last load operation performed.
7602 * @param {Object} options (optional) An object containing properties which may override the options
7603 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7604 * the most recently used options are reused).
7606 reload : function(options){
7607 this.load(Roo.applyIf(options||{}, this.lastOptions));
7611 // Called as a callback by the Reader during a load operation.
7612 loadRecords : function(o, options, success){
7613 if(!o || success === false){
7614 if(success !== false){
7615 this.fireEvent("load", this, [], options, o);
7617 if(options.callback){
7618 options.callback.call(options.scope || this, [], options, false);
7622 // if data returned failure - throw an exception.
7623 if (o.success === false) {
7624 // show a message if no listener is registered.
7625 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7626 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7628 // loadmask wil be hooked into this..
7629 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7632 var r = o.records, t = o.totalRecords || r.length;
7634 this.fireEvent("beforeloadadd", this, r, options, o);
7636 if(!options || options.add !== true){
7637 if(this.pruneModifiedRecords){
7640 for(var i = 0, len = r.length; i < len; i++){
7644 this.data = this.snapshot;
7645 delete this.snapshot;
7648 this.data.addAll(r);
7649 this.totalLength = t;
7651 this.fireEvent("datachanged", this);
7653 this.totalLength = Math.max(t, this.data.length+r.length);
7656 this.fireEvent("load", this, r, options, o);
7657 if(options.callback){
7658 options.callback.call(options.scope || this, r, options, true);
7664 * Loads data from a passed data block. A Reader which understands the format of the data
7665 * must have been configured in the constructor.
7666 * @param {Object} data The data block from which to read the Records. The format of the data expected
7667 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7668 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7670 loadData : function(o, append){
7671 var r = this.reader.readRecords(o);
7672 this.loadRecords(r, {add: append}, true);
7676 * Gets the number of cached records.
7678 * <em>If using paging, this may not be the total size of the dataset. If the data object
7679 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7680 * the data set size</em>
7682 getCount : function(){
7683 return this.data.length || 0;
7687 * Gets the total number of records in the dataset as returned by the server.
7689 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7690 * the dataset size</em>
7692 getTotalCount : function(){
7693 return this.totalLength || 0;
7697 * Returns the sort state of the Store as an object with two properties:
7699 field {String} The name of the field by which the Records are sorted
7700 direction {String} The sort order, "ASC" or "DESC"
7703 getSortState : function(){
7704 return this.sortInfo;
7708 applySort : function(){
7709 if(this.sortInfo && !this.remoteSort){
7710 var s = this.sortInfo, f = s.field;
7711 var st = this.fields.get(f).sortType;
7712 var fn = function(r1, r2){
7713 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7714 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7716 this.data.sort(s.direction, fn);
7717 if(this.snapshot && this.snapshot != this.data){
7718 this.snapshot.sort(s.direction, fn);
7724 * Sets the default sort column and order to be used by the next load operation.
7725 * @param {String} fieldName The name of the field to sort by.
7726 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7728 setDefaultSort : function(field, dir){
7729 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7734 * If remote sorting is used, the sort is performed on the server, and the cache is
7735 * reloaded. If local sorting is used, the cache is sorted internally.
7736 * @param {String} fieldName The name of the field to sort by.
7737 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7739 sort : function(fieldName, dir){
7740 var f = this.fields.get(fieldName);
7742 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7744 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7745 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7750 this.sortToggle[f.name] = dir;
7751 this.sortInfo = {field: f.name, direction: dir};
7752 if(!this.remoteSort){
7754 this.fireEvent("datachanged", this);
7756 this.load(this.lastOptions);
7761 * Calls the specified function for each of the Records in the cache.
7762 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7763 * Returning <em>false</em> aborts and exits the iteration.
7764 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7766 each : function(fn, scope){
7767 this.data.each(fn, scope);
7771 * Gets all records modified since the last commit. Modified records are persisted across load operations
7772 * (e.g., during paging).
7773 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7775 getModifiedRecords : function(){
7776 return this.modified;
7780 createFilterFn : function(property, value, anyMatch){
7781 if(!value.exec){ // not a regex
7782 value = String(value);
7783 if(value.length == 0){
7786 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7789 return value.test(r.data[property]);
7794 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7795 * @param {String} property A field on your records
7796 * @param {Number} start The record index to start at (defaults to 0)
7797 * @param {Number} end The last record index to include (defaults to length - 1)
7798 * @return {Number} The sum
7800 sum : function(property, start, end){
7801 var rs = this.data.items, v = 0;
7803 end = (end || end === 0) ? end : rs.length-1;
7805 for(var i = start; i <= end; i++){
7806 v += (rs[i].data[property] || 0);
7812 * Filter the records by a specified property.
7813 * @param {String} field A field on your records
7814 * @param {String/RegExp} value Either a string that the field
7815 * should start with or a RegExp to test against the field
7816 * @param {Boolean} anyMatch True to match any part not just the beginning
7818 filter : function(property, value, anyMatch){
7819 var fn = this.createFilterFn(property, value, anyMatch);
7820 return fn ? this.filterBy(fn) : this.clearFilter();
7824 * Filter by a function. The specified function will be called with each
7825 * record in this data source. If the function returns true the record is included,
7826 * otherwise it is filtered.
7827 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7828 * @param {Object} scope (optional) The scope of the function (defaults to this)
7830 filterBy : function(fn, scope){
7831 this.snapshot = this.snapshot || this.data;
7832 this.data = this.queryBy(fn, scope||this);
7833 this.fireEvent("datachanged", this);
7837 * Query the records by a specified property.
7838 * @param {String} field A field on your records
7839 * @param {String/RegExp} value Either a string that the field
7840 * should start with or a RegExp to test against the field
7841 * @param {Boolean} anyMatch True to match any part not just the beginning
7842 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7844 query : function(property, value, anyMatch){
7845 var fn = this.createFilterFn(property, value, anyMatch);
7846 return fn ? this.queryBy(fn) : this.data.clone();
7850 * Query by a function. The specified function will be called with each
7851 * record in this data source. If the function returns true the record is included
7853 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7854 * @param {Object} scope (optional) The scope of the function (defaults to this)
7855 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7857 queryBy : function(fn, scope){
7858 var data = this.snapshot || this.data;
7859 return data.filterBy(fn, scope||this);
7863 * Collects unique values for a particular dataIndex from this store.
7864 * @param {String} dataIndex The property to collect
7865 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7866 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7867 * @return {Array} An array of the unique values
7869 collect : function(dataIndex, allowNull, bypassFilter){
7870 var d = (bypassFilter === true && this.snapshot) ?
7871 this.snapshot.items : this.data.items;
7872 var v, sv, r = [], l = {};
7873 for(var i = 0, len = d.length; i < len; i++){
7874 v = d[i].data[dataIndex];
7876 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7885 * Revert to a view of the Record cache with no filtering applied.
7886 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7888 clearFilter : function(suppressEvent){
7889 if(this.snapshot && this.snapshot != this.data){
7890 this.data = this.snapshot;
7891 delete this.snapshot;
7892 if(suppressEvent !== true){
7893 this.fireEvent("datachanged", this);
7899 afterEdit : function(record){
7900 if(this.modified.indexOf(record) == -1){
7901 this.modified.push(record);
7903 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7907 afterReject : function(record){
7908 this.modified.remove(record);
7909 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7913 afterCommit : function(record){
7914 this.modified.remove(record);
7915 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7919 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7920 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7922 commitChanges : function(){
7923 var m = this.modified.slice(0);
7925 for(var i = 0, len = m.length; i < len; i++){
7931 * Cancel outstanding changes on all changed records.
7933 rejectChanges : function(){
7934 var m = this.modified.slice(0);
7936 for(var i = 0, len = m.length; i < len; i++){
7941 onMetaChange : function(meta, rtype, o){
7942 this.recordType = rtype;
7943 this.fields = rtype.prototype.fields;
7944 delete this.snapshot;
7945 this.sortInfo = meta.sortInfo || this.sortInfo;
7947 this.fireEvent('metachange', this, this.reader.meta);
7950 moveIndex : function(data, type)
7952 var index = this.indexOf(data);
7954 var newIndex = index + type;
7958 this.insert(newIndex, data);
7963 * Ext JS Library 1.1.1
7964 * Copyright(c) 2006-2007, Ext JS, LLC.
7966 * Originally Released Under LGPL - original licence link has changed is not relivant.
7969 * <script type="text/javascript">
7973 * @class Roo.data.SimpleStore
7974 * @extends Roo.data.Store
7975 * Small helper class to make creating Stores from Array data easier.
7976 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7977 * @cfg {Array} fields An array of field definition objects, or field name strings.
7978 * @cfg {Array} data The multi-dimensional array of data
7980 * @param {Object} config
7982 Roo.data.SimpleStore = function(config){
7983 Roo.data.SimpleStore.superclass.constructor.call(this, {
7985 reader: new Roo.data.ArrayReader({
7988 Roo.data.Record.create(config.fields)
7990 proxy : new Roo.data.MemoryProxy(config.data)
7994 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7996 * Ext JS Library 1.1.1
7997 * Copyright(c) 2006-2007, Ext JS, LLC.
7999 * Originally Released Under LGPL - original licence link has changed is not relivant.
8002 * <script type="text/javascript">
8007 * @extends Roo.data.Store
8008 * @class Roo.data.JsonStore
8009 * Small helper class to make creating Stores for JSON data easier. <br/>
8011 var store = new Roo.data.JsonStore({
8012 url: 'get-images.php',
8014 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8017 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8018 * JsonReader and HttpProxy (unless inline data is provided).</b>
8019 * @cfg {Array} fields An array of field definition objects, or field name strings.
8021 * @param {Object} config
8023 Roo.data.JsonStore = function(c){
8024 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8025 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8026 reader: new Roo.data.JsonReader(c, c.fields)
8029 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8031 * Ext JS Library 1.1.1
8032 * Copyright(c) 2006-2007, Ext JS, LLC.
8034 * Originally Released Under LGPL - original licence link has changed is not relivant.
8037 * <script type="text/javascript">
8041 Roo.data.Field = function(config){
8042 if(typeof config == "string"){
8043 config = {name: config};
8045 Roo.apply(this, config);
8051 var st = Roo.data.SortTypes;
8052 // named sortTypes are supported, here we look them up
8053 if(typeof this.sortType == "string"){
8054 this.sortType = st[this.sortType];
8057 // set default sortType for strings and dates
8061 this.sortType = st.asUCString;
8064 this.sortType = st.asDate;
8067 this.sortType = st.none;
8072 var stripRe = /[\$,%]/g;
8074 // prebuilt conversion function for this field, instead of
8075 // switching every time we're reading a value
8077 var cv, dateFormat = this.dateFormat;
8082 cv = function(v){ return v; };
8085 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8089 return v !== undefined && v !== null && v !== '' ?
8090 parseInt(String(v).replace(stripRe, ""), 10) : '';
8095 return v !== undefined && v !== null && v !== '' ?
8096 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8101 cv = function(v){ return v === true || v === "true" || v == 1; };
8108 if(v instanceof Date){
8112 if(dateFormat == "timestamp"){
8113 return new Date(v*1000);
8115 return Date.parseDate(v, dateFormat);
8117 var parsed = Date.parse(v);
8118 return parsed ? new Date(parsed) : null;
8127 Roo.data.Field.prototype = {
8135 * Ext JS Library 1.1.1
8136 * Copyright(c) 2006-2007, Ext JS, LLC.
8138 * Originally Released Under LGPL - original licence link has changed is not relivant.
8141 * <script type="text/javascript">
8144 // Base class for reading structured data from a data source. This class is intended to be
8145 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8148 * @class Roo.data.DataReader
8149 * Base class for reading structured data from a data source. This class is intended to be
8150 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8153 Roo.data.DataReader = function(meta, recordType){
8157 this.recordType = recordType instanceof Array ?
8158 Roo.data.Record.create(recordType) : recordType;
8161 Roo.data.DataReader.prototype = {
8163 * Create an empty record
8164 * @param {Object} data (optional) - overlay some values
8165 * @return {Roo.data.Record} record created.
8167 newRow : function(d) {
8169 this.recordType.prototype.fields.each(function(c) {
8171 case 'int' : da[c.name] = 0; break;
8172 case 'date' : da[c.name] = new Date(); break;
8173 case 'float' : da[c.name] = 0.0; break;
8174 case 'boolean' : da[c.name] = false; break;
8175 default : da[c.name] = ""; break;
8179 return new this.recordType(Roo.apply(da, d));
8184 * Ext JS Library 1.1.1
8185 * Copyright(c) 2006-2007, Ext JS, LLC.
8187 * Originally Released Under LGPL - original licence link has changed is not relivant.
8190 * <script type="text/javascript">
8194 * @class Roo.data.DataProxy
8195 * @extends Roo.data.Observable
8196 * This class is an abstract base class for implementations which provide retrieval of
8197 * unformatted data objects.<br>
8199 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8200 * (of the appropriate type which knows how to parse the data object) to provide a block of
8201 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8203 * Custom implementations must implement the load method as described in
8204 * {@link Roo.data.HttpProxy#load}.
8206 Roo.data.DataProxy = function(){
8210 * Fires before a network request is made to retrieve a data object.
8211 * @param {Object} This DataProxy object.
8212 * @param {Object} params The params parameter to the load function.
8217 * Fires before the load method's callback is called.
8218 * @param {Object} This DataProxy object.
8219 * @param {Object} o The data object.
8220 * @param {Object} arg The callback argument object passed to the load function.
8224 * @event loadexception
8225 * Fires if an Exception occurs during data retrieval.
8226 * @param {Object} This DataProxy object.
8227 * @param {Object} o The data object.
8228 * @param {Object} arg The callback argument object passed to the load function.
8229 * @param {Object} e The Exception.
8231 loadexception : true
8233 Roo.data.DataProxy.superclass.constructor.call(this);
8236 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8239 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8243 * Ext JS Library 1.1.1
8244 * Copyright(c) 2006-2007, Ext JS, LLC.
8246 * Originally Released Under LGPL - original licence link has changed is not relivant.
8249 * <script type="text/javascript">
8252 * @class Roo.data.MemoryProxy
8253 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8254 * to the Reader when its load method is called.
8256 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8258 Roo.data.MemoryProxy = function(data){
8262 Roo.data.MemoryProxy.superclass.constructor.call(this);
8266 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8268 * Load data from the requested source (in this case an in-memory
8269 * data object passed to the constructor), read the data object into
8270 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8271 * process that block using the passed callback.
8272 * @param {Object} params This parameter is not used by the MemoryProxy class.
8273 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8274 * object into a block of Roo.data.Records.
8275 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8276 * The function must be passed <ul>
8277 * <li>The Record block object</li>
8278 * <li>The "arg" argument from the load function</li>
8279 * <li>A boolean success indicator</li>
8281 * @param {Object} scope The scope in which to call the callback
8282 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8284 load : function(params, reader, callback, scope, arg){
8285 params = params || {};
8288 result = reader.readRecords(this.data);
8290 this.fireEvent("loadexception", this, arg, null, e);
8291 callback.call(scope, null, arg, false);
8294 callback.call(scope, result, arg, true);
8298 update : function(params, records){
8303 * Ext JS Library 1.1.1
8304 * Copyright(c) 2006-2007, Ext JS, LLC.
8306 * Originally Released Under LGPL - original licence link has changed is not relivant.
8309 * <script type="text/javascript">
8312 * @class Roo.data.HttpProxy
8313 * @extends Roo.data.DataProxy
8314 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8315 * configured to reference a certain URL.<br><br>
8317 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8318 * from which the running page was served.<br><br>
8320 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8322 * Be aware that to enable the browser to parse an XML document, the server must set
8323 * the Content-Type header in the HTTP response to "text/xml".
8325 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8326 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8327 * will be used to make the request.
8329 Roo.data.HttpProxy = function(conn){
8330 Roo.data.HttpProxy.superclass.constructor.call(this);
8331 // is conn a conn config or a real conn?
8333 this.useAjax = !conn || !conn.events;
8337 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8338 // thse are take from connection...
8341 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8344 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8345 * extra parameters to each request made by this object. (defaults to undefined)
8348 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8349 * to each request made by this object. (defaults to undefined)
8352 * @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)
8355 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8358 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8364 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8368 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8369 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8370 * a finer-grained basis than the DataProxy events.
8372 getConnection : function(){
8373 return this.useAjax ? Roo.Ajax : this.conn;
8377 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8378 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8379 * process that block using the passed callback.
8380 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8381 * for the request to the remote server.
8382 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8383 * object into a block of Roo.data.Records.
8384 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8385 * The function must be passed <ul>
8386 * <li>The Record block object</li>
8387 * <li>The "arg" argument from the load function</li>
8388 * <li>A boolean success indicator</li>
8390 * @param {Object} scope The scope in which to call the callback
8391 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8393 load : function(params, reader, callback, scope, arg){
8394 if(this.fireEvent("beforeload", this, params) !== false){
8396 params : params || {},
8398 callback : callback,
8403 callback : this.loadResponse,
8407 Roo.applyIf(o, this.conn);
8408 if(this.activeRequest){
8409 Roo.Ajax.abort(this.activeRequest);
8411 this.activeRequest = Roo.Ajax.request(o);
8413 this.conn.request(o);
8416 callback.call(scope||this, null, arg, false);
8421 loadResponse : function(o, success, response){
8422 delete this.activeRequest;
8424 this.fireEvent("loadexception", this, o, response);
8425 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8430 result = o.reader.read(response);
8432 this.fireEvent("loadexception", this, o, response, e);
8433 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8437 this.fireEvent("load", this, o, o.request.arg);
8438 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8442 update : function(dataSet){
8447 updateResponse : function(dataSet){
8452 * Ext JS Library 1.1.1
8453 * Copyright(c) 2006-2007, Ext JS, LLC.
8455 * Originally Released Under LGPL - original licence link has changed is not relivant.
8458 * <script type="text/javascript">
8462 * @class Roo.data.ScriptTagProxy
8463 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8464 * other than the originating domain of the running page.<br><br>
8466 * <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
8467 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8469 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8470 * source code that is used as the source inside a <script> tag.<br><br>
8472 * In order for the browser to process the returned data, the server must wrap the data object
8473 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8474 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8475 * depending on whether the callback name was passed:
8478 boolean scriptTag = false;
8479 String cb = request.getParameter("callback");
8482 response.setContentType("text/javascript");
8484 response.setContentType("application/x-json");
8486 Writer out = response.getWriter();
8488 out.write(cb + "(");
8490 out.print(dataBlock.toJsonString());
8497 * @param {Object} config A configuration object.
8499 Roo.data.ScriptTagProxy = function(config){
8500 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8501 Roo.apply(this, config);
8502 this.head = document.getElementsByTagName("head")[0];
8505 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8507 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8509 * @cfg {String} url The URL from which to request the data object.
8512 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8516 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8517 * the server the name of the callback function set up by the load call to process the returned data object.
8518 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8519 * javascript output which calls this named function passing the data object as its only parameter.
8521 callbackParam : "callback",
8523 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8524 * name to the request.
8529 * Load data from the configured URL, read the data object into
8530 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8531 * process that block using the passed callback.
8532 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8533 * for the request to the remote server.
8534 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8535 * object into a block of Roo.data.Records.
8536 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8537 * The function must be passed <ul>
8538 * <li>The Record block object</li>
8539 * <li>The "arg" argument from the load function</li>
8540 * <li>A boolean success indicator</li>
8542 * @param {Object} scope The scope in which to call the callback
8543 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8545 load : function(params, reader, callback, scope, arg){
8546 if(this.fireEvent("beforeload", this, params) !== false){
8548 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8551 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8553 url += "&_dc=" + (new Date().getTime());
8555 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8558 cb : "stcCallback"+transId,
8559 scriptId : "stcScript"+transId,
8563 callback : callback,
8569 window[trans.cb] = function(o){
8570 conn.handleResponse(o, trans);
8573 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8575 if(this.autoAbort !== false){
8579 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8581 var script = document.createElement("script");
8582 script.setAttribute("src", url);
8583 script.setAttribute("type", "text/javascript");
8584 script.setAttribute("id", trans.scriptId);
8585 this.head.appendChild(script);
8589 callback.call(scope||this, null, arg, false);
8594 isLoading : function(){
8595 return this.trans ? true : false;
8599 * Abort the current server request.
8602 if(this.isLoading()){
8603 this.destroyTrans(this.trans);
8608 destroyTrans : function(trans, isLoaded){
8609 this.head.removeChild(document.getElementById(trans.scriptId));
8610 clearTimeout(trans.timeoutId);
8612 window[trans.cb] = undefined;
8614 delete window[trans.cb];
8617 // if hasn't been loaded, wait for load to remove it to prevent script error
8618 window[trans.cb] = function(){
8619 window[trans.cb] = undefined;
8621 delete window[trans.cb];
8628 handleResponse : function(o, trans){
8630 this.destroyTrans(trans, true);
8633 result = trans.reader.readRecords(o);
8635 this.fireEvent("loadexception", this, o, trans.arg, e);
8636 trans.callback.call(trans.scope||window, null, trans.arg, false);
8639 this.fireEvent("load", this, o, trans.arg);
8640 trans.callback.call(trans.scope||window, result, trans.arg, true);
8644 handleFailure : function(trans){
8646 this.destroyTrans(trans, false);
8647 this.fireEvent("loadexception", this, null, trans.arg);
8648 trans.callback.call(trans.scope||window, null, trans.arg, false);
8652 * Ext JS Library 1.1.1
8653 * Copyright(c) 2006-2007, Ext JS, LLC.
8655 * Originally Released Under LGPL - original licence link has changed is not relivant.
8658 * <script type="text/javascript">
8662 * @class Roo.data.JsonReader
8663 * @extends Roo.data.DataReader
8664 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8665 * based on mappings in a provided Roo.data.Record constructor.
8667 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8668 * in the reply previously.
8673 var RecordDef = Roo.data.Record.create([
8674 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8675 {name: 'occupation'} // This field will use "occupation" as the mapping.
8677 var myReader = new Roo.data.JsonReader({
8678 totalProperty: "results", // The property which contains the total dataset size (optional)
8679 root: "rows", // The property which contains an Array of row objects
8680 id: "id" // The property within each row object that provides an ID for the record (optional)
8684 * This would consume a JSON file like this:
8686 { 'results': 2, 'rows': [
8687 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8688 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8691 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8692 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8693 * paged from the remote server.
8694 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8695 * @cfg {String} root name of the property which contains the Array of row objects.
8696 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8698 * Create a new JsonReader
8699 * @param {Object} meta Metadata configuration options
8700 * @param {Object} recordType Either an Array of field definition objects,
8701 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8703 Roo.data.JsonReader = function(meta, recordType){
8706 // set some defaults:
8708 totalProperty: 'total',
8709 successProperty : 'success',
8714 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8716 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8719 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8720 * Used by Store query builder to append _requestMeta to params.
8723 metaFromRemote : false,
8725 * This method is only used by a DataProxy which has retrieved data from a remote server.
8726 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8727 * @return {Object} data A data block which is used by an Roo.data.Store object as
8728 * a cache of Roo.data.Records.
8730 read : function(response){
8731 var json = response.responseText;
8733 var o = /* eval:var:o */ eval("("+json+")");
8735 throw {message: "JsonReader.read: Json object not found"};
8741 this.metaFromRemote = true;
8742 this.meta = o.metaData;
8743 this.recordType = Roo.data.Record.create(o.metaData.fields);
8744 this.onMetaChange(this.meta, this.recordType, o);
8746 return this.readRecords(o);
8749 // private function a store will implement
8750 onMetaChange : function(meta, recordType, o){
8757 simpleAccess: function(obj, subsc) {
8764 getJsonAccessor: function(){
8766 return function(expr) {
8768 return(re.test(expr))
8769 ? new Function("obj", "return obj." + expr)
8779 * Create a data block containing Roo.data.Records from an XML document.
8780 * @param {Object} o An object which contains an Array of row objects in the property specified
8781 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8782 * which contains the total size of the dataset.
8783 * @return {Object} data A data block which is used by an Roo.data.Store object as
8784 * a cache of Roo.data.Records.
8786 readRecords : function(o){
8788 * After any data loads, the raw JSON data is available for further custom processing.
8792 var s = this.meta, Record = this.recordType,
8793 f = Record.prototype.fields, fi = f.items, fl = f.length;
8795 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8797 if(s.totalProperty) {
8798 this.getTotal = this.getJsonAccessor(s.totalProperty);
8800 if(s.successProperty) {
8801 this.getSuccess = this.getJsonAccessor(s.successProperty);
8803 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8805 var g = this.getJsonAccessor(s.id);
8806 this.getId = function(rec) {
8808 return (r === undefined || r === "") ? null : r;
8811 this.getId = function(){return null;};
8814 for(var jj = 0; jj < fl; jj++){
8816 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8817 this.ef[jj] = this.getJsonAccessor(map);
8821 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8822 if(s.totalProperty){
8823 var vt = parseInt(this.getTotal(o), 10);
8828 if(s.successProperty){
8829 var vs = this.getSuccess(o);
8830 if(vs === false || vs === 'false'){
8835 for(var i = 0; i < c; i++){
8838 var id = this.getId(n);
8839 for(var j = 0; j < fl; j++){
8841 var v = this.ef[j](n);
8843 Roo.log('missing convert for ' + f.name);
8847 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8849 var record = new Record(values, id);
8851 records[i] = record;
8857 totalRecords : totalRecords
8862 * Ext JS Library 1.1.1
8863 * Copyright(c) 2006-2007, Ext JS, LLC.
8865 * Originally Released Under LGPL - original licence link has changed is not relivant.
8868 * <script type="text/javascript">
8872 * @class Roo.data.ArrayReader
8873 * @extends Roo.data.DataReader
8874 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8875 * Each element of that Array represents a row of data fields. The
8876 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8877 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8881 var RecordDef = Roo.data.Record.create([
8882 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8883 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8885 var myReader = new Roo.data.ArrayReader({
8886 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8890 * This would consume an Array like this:
8892 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8894 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8896 * Create a new JsonReader
8897 * @param {Object} meta Metadata configuration options.
8898 * @param {Object} recordType Either an Array of field definition objects
8899 * as specified to {@link Roo.data.Record#create},
8900 * or an {@link Roo.data.Record} object
8901 * created using {@link Roo.data.Record#create}.
8903 Roo.data.ArrayReader = function(meta, recordType){
8904 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8907 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8909 * Create a data block containing Roo.data.Records from an XML document.
8910 * @param {Object} o An Array of row objects which represents the dataset.
8911 * @return {Object} data A data block which is used by an Roo.data.Store object as
8912 * a cache of Roo.data.Records.
8914 readRecords : function(o){
8915 var sid = this.meta ? this.meta.id : null;
8916 var recordType = this.recordType, fields = recordType.prototype.fields;
8919 for(var i = 0; i < root.length; i++){
8922 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8923 for(var j = 0, jlen = fields.length; j < jlen; j++){
8924 var f = fields.items[j];
8925 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8926 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8930 var record = new recordType(values, id);
8932 records[records.length] = record;
8936 totalRecords : records.length
8945 * @class Roo.bootstrap.ComboBox
8946 * @extends Roo.bootstrap.TriggerField
8947 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8948 * @cfg {Boolean} append (true|false) default false
8950 * Create a new ComboBox.
8951 * @param {Object} config Configuration options
8953 Roo.bootstrap.ComboBox = function(config){
8954 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8958 * Fires when the dropdown list is expanded
8959 * @param {Roo.bootstrap.ComboBox} combo This combo box
8964 * Fires when the dropdown list is collapsed
8965 * @param {Roo.bootstrap.ComboBox} combo This combo box
8969 * @event beforeselect
8970 * Fires before a list item is selected. Return false to cancel the selection.
8971 * @param {Roo.bootstrap.ComboBox} combo This combo box
8972 * @param {Roo.data.Record} record The data record returned from the underlying store
8973 * @param {Number} index The index of the selected item in the dropdown list
8975 'beforeselect' : true,
8978 * Fires when a list item is selected
8979 * @param {Roo.bootstrap.ComboBox} combo This combo box
8980 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8981 * @param {Number} index The index of the selected item in the dropdown list
8985 * @event beforequery
8986 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8987 * The event object passed has these properties:
8988 * @param {Roo.bootstrap.ComboBox} combo This combo box
8989 * @param {String} query The query
8990 * @param {Boolean} forceAll true to force "all" query
8991 * @param {Boolean} cancel true to cancel the query
8992 * @param {Object} e The query event object
8994 'beforequery': true,
8997 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8998 * @param {Roo.bootstrap.ComboBox} combo This combo box
9003 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9004 * @param {Roo.bootstrap.ComboBox} combo This combo box
9005 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9010 * Fires when the remove value from the combobox array
9011 * @param {Roo.bootstrap.ComboBox} combo This combo box
9018 this.selectedIndex = -1;
9019 if(this.mode == 'local'){
9020 if(config.queryDelay === undefined){
9021 this.queryDelay = 10;
9023 if(config.minChars === undefined){
9029 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9032 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9033 * rendering into an Roo.Editor, defaults to false)
9036 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9037 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9040 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9043 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9044 * the dropdown list (defaults to undefined, with no header element)
9048 * @cfg {String/Roo.Template} tpl The template to use to render the output
9052 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9054 listWidth: undefined,
9056 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9057 * mode = 'remote' or 'text' if mode = 'local')
9059 displayField: undefined,
9061 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9062 * mode = 'remote' or 'value' if mode = 'local').
9063 * Note: use of a valueField requires the user make a selection
9064 * in order for a value to be mapped.
9066 valueField: undefined,
9070 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9071 * field's data value (defaults to the underlying DOM element's name)
9073 hiddenName: undefined,
9075 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9079 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9081 selectedClass: 'active',
9084 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9088 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9089 * anchor positions (defaults to 'tl-bl')
9091 listAlign: 'tl-bl?',
9093 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9097 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9098 * query specified by the allQuery config option (defaults to 'query')
9100 triggerAction: 'query',
9102 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9103 * (defaults to 4, does not apply if editable = false)
9107 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9108 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9112 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9113 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9117 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9118 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9122 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9123 * when editable = true (defaults to false)
9125 selectOnFocus:false,
9127 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9129 queryParam: 'query',
9131 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9132 * when mode = 'remote' (defaults to 'Loading...')
9134 loadingText: 'Loading...',
9136 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9140 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9144 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9145 * traditional select (defaults to true)
9149 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9153 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9157 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9158 * listWidth has a higher value)
9162 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9163 * allow the user to set arbitrary text into the field (defaults to false)
9165 forceSelection:false,
9167 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9168 * if typeAhead = true (defaults to 250)
9170 typeAheadDelay : 250,
9172 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9173 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9175 valueNotFoundText : undefined,
9177 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9182 * @cfg {Boolean} disableClear Disable showing of clear button.
9184 disableClear : false,
9186 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9188 alwaysQuery : false,
9191 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9205 // element that contains real text value.. (when hidden is used..)
9208 initEvents: function(){
9211 throw "can not find store for combo";
9213 this.store = Roo.factory(this.store, Roo.data);
9217 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9220 if(this.hiddenName){
9222 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9224 this.hiddenField.dom.value =
9225 this.hiddenValue !== undefined ? this.hiddenValue :
9226 this.value !== undefined ? this.value : '';
9228 // prevent input submission
9229 this.el.dom.removeAttribute('name');
9230 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9235 // this.el.dom.setAttribute('autocomplete', 'off');
9238 var cls = 'x-combo-list';
9239 this.list = this.el.select('ul.dropdown-menu',true).first();
9241 //this.list = new Roo.Layer({
9242 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9245 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9246 this.list.setWidth(lw);
9248 this.list.on('mouseover', this.onViewOver, this);
9249 this.list.on('mousemove', this.onViewMove, this);
9251 this.list.on('scroll', this.onViewScroll, this);
9254 this.list.swallowEvent('mousewheel');
9255 this.assetHeight = 0;
9258 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9259 this.assetHeight += this.header.getHeight();
9262 this.innerList = this.list.createChild({cls:cls+'-inner'});
9263 this.innerList.on('mouseover', this.onViewOver, this);
9264 this.innerList.on('mousemove', this.onViewMove, this);
9265 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9267 if(this.allowBlank && !this.pageSize && !this.disableClear){
9268 this.footer = this.list.createChild({cls:cls+'-ft'});
9269 this.pageTb = new Roo.Toolbar(this.footer);
9273 this.footer = this.list.createChild({cls:cls+'-ft'});
9274 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9275 {pageSize: this.pageSize});
9279 if (this.pageTb && this.allowBlank && !this.disableClear) {
9281 this.pageTb.add(new Roo.Toolbar.Fill(), {
9282 cls: 'x-btn-icon x-btn-clear',
9288 _this.onSelect(false, -1);
9293 this.assetHeight += this.footer.getHeight();
9298 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9301 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9302 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9304 //this.view.wrapEl.setDisplayed(false);
9305 this.view.on('click', this.onViewClick, this);
9309 this.store.on('beforeload', this.onBeforeLoad, this);
9310 this.store.on('load', this.onLoad, this);
9311 this.store.on('loadexception', this.onLoadException, this);
9314 this.resizer = new Roo.Resizable(this.list, {
9315 pinned:true, handles:'se'
9317 this.resizer.on('resize', function(r, w, h){
9318 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9320 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9321 this.restrictHeight();
9323 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9327 this.editable = true;
9328 this.setEditable(false);
9333 if (typeof(this.events.add.listeners) != 'undefined') {
9335 this.addicon = this.wrap.createChild(
9336 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9338 this.addicon.on('click', function(e) {
9339 this.fireEvent('add', this);
9342 if (typeof(this.events.edit.listeners) != 'undefined') {
9344 this.editicon = this.wrap.createChild(
9345 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9347 this.editicon.setStyle('margin-left', '40px');
9349 this.editicon.on('click', function(e) {
9351 // we fire even if inothing is selected..
9352 this.fireEvent('edit', this, this.lastData );
9358 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9360 this.inKeyMode = true;
9364 "down" : function(e){
9365 if(!this.isExpanded()){
9366 this.onTriggerClick();
9368 this.inKeyMode = true;
9373 "enter" : function(e){
9378 "esc" : function(e){
9382 "tab" : function(e){
9385 if(this.fireEvent("specialkey", this, e)){
9386 this.onViewClick(false);
9394 doRelay : function(foo, bar, hname){
9395 if(hname == 'down' || this.scope.isExpanded()){
9396 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9405 this.queryDelay = Math.max(this.queryDelay || 10,
9406 this.mode == 'local' ? 10 : 250);
9409 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9412 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9414 if(this.editable !== false){
9415 this.inputEl().on("keyup", this.onKeyUp, this);
9417 if(this.forceSelection){
9418 this.inputEl().on('blur', this.doForce, this);
9422 this.choices = this.el.select('ul.select2-choices', true).first();
9423 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9427 onDestroy : function(){
9429 this.view.setStore(null);
9430 this.view.el.removeAllListeners();
9431 this.view.el.remove();
9432 this.view.purgeListeners();
9435 this.list.dom.innerHTML = '';
9438 this.store.un('beforeload', this.onBeforeLoad, this);
9439 this.store.un('load', this.onLoad, this);
9440 this.store.un('loadexception', this.onLoadException, this);
9442 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9446 fireKey : function(e){
9447 if(e.isNavKeyPress() && !this.list.isVisible()){
9448 this.fireEvent("specialkey", this, e);
9453 onResize: function(w, h){
9454 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9456 // if(typeof w != 'number'){
9457 // // we do not handle it!?!?
9460 // var tw = this.trigger.getWidth();
9461 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9462 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9464 // this.inputEl().setWidth( this.adjustWidth('input', x));
9466 // //this.trigger.setStyle('left', x+'px');
9468 // if(this.list && this.listWidth === undefined){
9469 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9470 // this.list.setWidth(lw);
9471 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9479 * Allow or prevent the user from directly editing the field text. If false is passed,
9480 * the user will only be able to select from the items defined in the dropdown list. This method
9481 * is the runtime equivalent of setting the 'editable' config option at config time.
9482 * @param {Boolean} value True to allow the user to directly edit the field text
9484 setEditable : function(value){
9485 if(value == this.editable){
9488 this.editable = value;
9490 this.inputEl().dom.setAttribute('readOnly', true);
9491 this.inputEl().on('mousedown', this.onTriggerClick, this);
9492 this.inputEl().addClass('x-combo-noedit');
9494 this.inputEl().dom.setAttribute('readOnly', false);
9495 this.inputEl().un('mousedown', this.onTriggerClick, this);
9496 this.inputEl().removeClass('x-combo-noedit');
9502 onBeforeLoad : function(combo,opts){
9507 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9509 this.restrictHeight();
9510 this.selectedIndex = -1;
9514 onLoad : function(){
9516 this.hasQuery = false;
9522 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9523 this.loading.hide();
9526 if(this.store.getCount() > 0){
9528 this.restrictHeight();
9529 if(this.lastQuery == this.allQuery){
9531 this.inputEl().dom.select();
9533 if(!this.selectByValue(this.value, true)){
9534 this.select(0, true);
9538 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9539 this.taTask.delay(this.typeAheadDelay);
9543 this.onEmptyResults();
9549 onLoadException : function()
9551 this.hasQuery = false;
9553 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9554 this.loading.hide();
9558 Roo.log(this.store.reader.jsonData);
9559 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9561 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9567 onTypeAhead : function(){
9568 if(this.store.getCount() > 0){
9569 var r = this.store.getAt(0);
9570 var newValue = r.data[this.displayField];
9571 var len = newValue.length;
9572 var selStart = this.getRawValue().length;
9574 if(selStart != len){
9575 this.setRawValue(newValue);
9576 this.selectText(selStart, newValue.length);
9582 onSelect : function(record, index){
9584 if(this.fireEvent('beforeselect', this, record, index) !== false){
9586 this.setFromData(index > -1 ? record.data : false);
9589 this.fireEvent('select', this, record, index);
9594 * Returns the currently selected field value or empty string if no value is set.
9595 * @return {String} value The selected value
9597 getValue : function(){
9600 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9603 if(this.valueField){
9604 return typeof this.value != 'undefined' ? this.value : '';
9606 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9611 * Clears any text/value currently set in the field
9613 clearValue : function(){
9614 if(this.hiddenField){
9615 this.hiddenField.dom.value = '';
9618 this.setRawValue('');
9619 this.lastSelectionText = '';
9624 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9625 * will be displayed in the field. If the value does not match the data value of an existing item,
9626 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9627 * Otherwise the field will be blank (although the value will still be set).
9628 * @param {String} value The value to match
9630 setValue : function(v){
9637 if(this.valueField){
9638 var r = this.findRecord(this.valueField, v);
9640 text = r.data[this.displayField];
9641 }else if(this.valueNotFoundText !== undefined){
9642 text = this.valueNotFoundText;
9645 this.lastSelectionText = text;
9646 if(this.hiddenField){
9647 this.hiddenField.dom.value = v;
9649 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9653 * @property {Object} the last set data for the element
9658 * Sets the value of the field based on a object which is related to the record format for the store.
9659 * @param {Object} value the value to set as. or false on reset?
9661 setFromData : function(o){
9668 var dv = ''; // display value
9669 var vv = ''; // value value..
9671 if (this.displayField) {
9672 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9674 // this is an error condition!!!
9675 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9678 if(this.valueField){
9679 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9682 if(this.hiddenField){
9683 this.hiddenField.dom.value = vv;
9685 this.lastSelectionText = dv;
9686 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9690 // no hidden field.. - we store the value in 'value', but still display
9691 // display field!!!!
9692 this.lastSelectionText = dv;
9693 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9700 // overridden so that last data is reset..
9701 this.setValue(this.originalValue);
9702 this.clearInvalid();
9703 this.lastData = false;
9705 this.view.clearSelections();
9709 findRecord : function(prop, value){
9711 if(this.store.getCount() > 0){
9712 this.store.each(function(r){
9713 if(r.data[prop] == value){
9725 // returns hidden if it's set..
9726 if (!this.rendered) {return ''};
9727 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9731 onViewMove : function(e, t){
9732 this.inKeyMode = false;
9736 onViewOver : function(e, t){
9737 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9740 var item = this.view.findItemFromChild(t);
9742 var index = this.view.indexOf(item);
9743 this.select(index, false);
9748 onViewClick : function(doFocus)
9750 var index = this.view.getSelectedIndexes()[0];
9751 var r = this.store.getAt(index);
9753 this.onSelect(r, index);
9755 if(doFocus !== false && !this.blockFocus){
9756 this.inputEl().focus();
9761 restrictHeight : function(){
9762 //this.innerList.dom.style.height = '';
9763 //var inner = this.innerList.dom;
9764 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9765 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9766 //this.list.beginUpdate();
9767 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9768 this.list.alignTo(this.inputEl(), this.listAlign);
9769 //this.list.endUpdate();
9773 onEmptyResults : function(){
9778 * Returns true if the dropdown list is expanded, else false.
9780 isExpanded : function(){
9781 return this.list.isVisible();
9785 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9786 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9787 * @param {String} value The data value of the item to select
9788 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9789 * selected item if it is not currently in view (defaults to true)
9790 * @return {Boolean} True if the value matched an item in the list, else false
9792 selectByValue : function(v, scrollIntoView){
9793 if(v !== undefined && v !== null){
9794 var r = this.findRecord(this.valueField || this.displayField, v);
9796 this.select(this.store.indexOf(r), scrollIntoView);
9804 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9805 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9806 * @param {Number} index The zero-based index of the list item to select
9807 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9808 * selected item if it is not currently in view (defaults to true)
9810 select : function(index, scrollIntoView){
9811 this.selectedIndex = index;
9812 this.view.select(index);
9813 if(scrollIntoView !== false){
9814 var el = this.view.getNode(index);
9816 //this.innerList.scrollChildIntoView(el, false);
9823 selectNext : function(){
9824 var ct = this.store.getCount();
9826 if(this.selectedIndex == -1){
9828 }else if(this.selectedIndex < ct-1){
9829 this.select(this.selectedIndex+1);
9835 selectPrev : function(){
9836 var ct = this.store.getCount();
9838 if(this.selectedIndex == -1){
9840 }else if(this.selectedIndex != 0){
9841 this.select(this.selectedIndex-1);
9847 onKeyUp : function(e){
9848 if(this.editable !== false && !e.isSpecialKey()){
9849 this.lastKey = e.getKey();
9850 this.dqTask.delay(this.queryDelay);
9855 validateBlur : function(){
9856 return !this.list || !this.list.isVisible();
9860 initQuery : function(){
9861 this.doQuery(this.getRawValue());
9865 doForce : function(){
9866 if(this.inputEl().dom.value.length > 0){
9867 this.inputEl().dom.value =
9868 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9874 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9875 * query allowing the query action to be canceled if needed.
9876 * @param {String} query The SQL query to execute
9877 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9878 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9879 * saved in the current store (defaults to false)
9881 doQuery : function(q, forceAll){
9883 if(q === undefined || q === null){
9892 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9897 forceAll = qe.forceAll;
9898 if(forceAll === true || (q.length >= this.minChars)){
9900 this.hasQuery = true;
9902 if(this.lastQuery != q || this.alwaysQuery){
9904 if(this.mode == 'local'){
9905 this.selectedIndex = -1;
9907 this.store.clearFilter();
9909 this.store.filter(this.displayField, q);
9913 this.store.baseParams[this.queryParam] = q;
9915 var options = {params : this.getParams(q)};
9919 options.params.start = this.page * this.pageSize;
9922 this.store.load(options);
9926 this.selectedIndex = -1;
9931 this.loadNext = false;
9935 getParams : function(q){
9937 //p[this.queryParam] = q;
9941 p.limit = this.pageSize;
9947 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9949 collapse : function(){
9950 if(!this.isExpanded()){
9955 Roo.get(document).un('mousedown', this.collapseIf, this);
9956 Roo.get(document).un('mousewheel', this.collapseIf, this);
9957 if (!this.editable) {
9958 Roo.get(document).un('keydown', this.listKeyPress, this);
9960 this.fireEvent('collapse', this);
9964 collapseIf : function(e){
9965 var in_combo = e.within(this.el);
9966 var in_list = e.within(this.list);
9968 if (in_combo || in_list) {
9969 //e.stopPropagation();
9978 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9980 expand : function(){
9982 if(this.isExpanded() || !this.hasFocus){
9986 this.list.alignTo(this.inputEl(), this.listAlign);
9988 Roo.get(document).on('mousedown', this.collapseIf, this);
9989 Roo.get(document).on('mousewheel', this.collapseIf, this);
9990 if (!this.editable) {
9991 Roo.get(document).on('keydown', this.listKeyPress, this);
9994 this.fireEvent('expand', this);
9998 // Implements the default empty TriggerField.onTriggerClick function
9999 onTriggerClick : function()
10001 Roo.log('trigger click');
10008 this.loadNext = false;
10010 if(this.isExpanded()){
10012 if (!this.blockFocus) {
10013 this.inputEl().focus();
10017 this.hasFocus = true;
10018 if(this.triggerAction == 'all') {
10019 this.doQuery(this.allQuery, true);
10021 this.doQuery(this.getRawValue());
10023 if (!this.blockFocus) {
10024 this.inputEl().focus();
10028 listKeyPress : function(e)
10030 //Roo.log('listkeypress');
10031 // scroll to first matching element based on key pres..
10032 if (e.isSpecialKey()) {
10035 var k = String.fromCharCode(e.getKey()).toUpperCase();
10038 var csel = this.view.getSelectedNodes();
10039 var cselitem = false;
10041 var ix = this.view.indexOf(csel[0]);
10042 cselitem = this.store.getAt(ix);
10043 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10049 this.store.each(function(v) {
10051 // start at existing selection.
10052 if (cselitem.id == v.id) {
10058 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10059 match = this.store.indexOf(v);
10065 if (match === false) {
10066 return true; // no more action?
10069 this.view.select(match);
10070 var sn = Roo.get(this.view.getSelectedNodes()[0])
10071 //sn.scrollIntoView(sn.dom.parentNode, false);
10074 onViewScroll : function(e, t){
10076 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10080 this.hasQuery = true;
10082 this.loading = this.list.select('.loading', true).first();
10084 if(this.loading === null){
10085 this.list.createChild({
10087 cls: 'loading select2-more-results select2-active',
10088 html: 'Loading more results...'
10091 this.loading = this.list.select('.loading', true).first();
10093 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10095 this.loading.hide();
10098 this.loading.show();
10103 this.loadNext = true;
10105 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10110 addItem : function(o)
10112 var dv = ''; // display value
10114 if (this.displayField) {
10115 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10117 // this is an error condition!!!
10118 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10125 var choice = this.choices.createChild({
10127 cls: 'select2-search-choice',
10136 cls: 'select2-search-choice-close',
10141 }, this.searchField);
10143 var close = choice.select('a.select2-search-choice-close', true).first()
10145 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10152 this.inputEl().dom.value = '';
10156 onRemoveItem : function(e, _self, o)
10158 e.preventDefault();
10159 var index = this.item.indexOf(o.data) * 1;
10162 Roo.log('not this item?!');
10166 this.item.splice(index, 1);
10171 this.fireEvent('remove', this, e);
10175 syncValue : function()
10177 if(!this.item.length){
10184 Roo.each(this.item, function(i){
10185 if(_this.valueField){
10186 value.push(i[_this.valueField]);
10193 this.value = value.join(',');
10195 if(this.hiddenField){
10196 this.hiddenField.dom.value = this.value;
10200 clearItem : function()
10202 if(!this.multiple){
10208 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10218 * @cfg {Boolean} grow
10222 * @cfg {Number} growMin
10226 * @cfg {Number} growMax
10236 * Ext JS Library 1.1.1
10237 * Copyright(c) 2006-2007, Ext JS, LLC.
10239 * Originally Released Under LGPL - original licence link has changed is not relivant.
10242 * <script type="text/javascript">
10247 * @extends Roo.util.Observable
10248 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10249 * This class also supports single and multi selection modes. <br>
10250 * Create a data model bound view:
10252 var store = new Roo.data.Store(...);
10254 var view = new Roo.View({
10256 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10258 singleSelect: true,
10259 selectedClass: "ydataview-selected",
10263 // listen for node click?
10264 view.on("click", function(vw, index, node, e){
10265 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10269 dataModel.load("foobar.xml");
10271 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10273 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10274 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10276 * Note: old style constructor is still suported (container, template, config)
10279 * Create a new View
10280 * @param {Object} config The config object
10283 Roo.View = function(config, depreciated_tpl, depreciated_config){
10285 if (typeof(depreciated_tpl) == 'undefined') {
10286 // new way.. - universal constructor.
10287 Roo.apply(this, config);
10288 this.el = Roo.get(this.el);
10291 this.el = Roo.get(config);
10292 this.tpl = depreciated_tpl;
10293 Roo.apply(this, depreciated_config);
10295 this.wrapEl = this.el.wrap().wrap();
10296 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10299 if(typeof(this.tpl) == "string"){
10300 this.tpl = new Roo.Template(this.tpl);
10302 // support xtype ctors..
10303 this.tpl = new Roo.factory(this.tpl, Roo);
10307 this.tpl.compile();
10315 * @event beforeclick
10316 * Fires before a click is processed. Returns false to cancel the default action.
10317 * @param {Roo.View} this
10318 * @param {Number} index The index of the target node
10319 * @param {HTMLElement} node The target node
10320 * @param {Roo.EventObject} e The raw event object
10322 "beforeclick" : true,
10325 * Fires when a template node is clicked.
10326 * @param {Roo.View} this
10327 * @param {Number} index The index of the target node
10328 * @param {HTMLElement} node The target node
10329 * @param {Roo.EventObject} e The raw event object
10334 * Fires when a template node is double clicked.
10335 * @param {Roo.View} this
10336 * @param {Number} index The index of the target node
10337 * @param {HTMLElement} node The target node
10338 * @param {Roo.EventObject} e The raw event object
10342 * @event contextmenu
10343 * Fires when a template node is right clicked.
10344 * @param {Roo.View} this
10345 * @param {Number} index The index of the target node
10346 * @param {HTMLElement} node The target node
10347 * @param {Roo.EventObject} e The raw event object
10349 "contextmenu" : true,
10351 * @event selectionchange
10352 * Fires when the selected nodes change.
10353 * @param {Roo.View} this
10354 * @param {Array} selections Array of the selected nodes
10356 "selectionchange" : true,
10359 * @event beforeselect
10360 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10361 * @param {Roo.View} this
10362 * @param {HTMLElement} node The node to be selected
10363 * @param {Array} selections Array of currently selected nodes
10365 "beforeselect" : true,
10367 * @event preparedata
10368 * Fires on every row to render, to allow you to change the data.
10369 * @param {Roo.View} this
10370 * @param {Object} data to be rendered (change this)
10372 "preparedata" : true
10380 "click": this.onClick,
10381 "dblclick": this.onDblClick,
10382 "contextmenu": this.onContextMenu,
10386 this.selections = [];
10388 this.cmp = new Roo.CompositeElementLite([]);
10390 this.store = Roo.factory(this.store, Roo.data);
10391 this.setStore(this.store, true);
10394 if ( this.footer && this.footer.xtype) {
10396 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10398 this.footer.dataSource = this.store
10399 this.footer.container = fctr;
10400 this.footer = Roo.factory(this.footer, Roo);
10401 fctr.insertFirst(this.el);
10403 // this is a bit insane - as the paging toolbar seems to detach the el..
10404 // dom.parentNode.parentNode.parentNode
10405 // they get detached?
10409 Roo.View.superclass.constructor.call(this);
10414 Roo.extend(Roo.View, Roo.util.Observable, {
10417 * @cfg {Roo.data.Store} store Data store to load data from.
10422 * @cfg {String|Roo.Element} el The container element.
10427 * @cfg {String|Roo.Template} tpl The template used by this View
10431 * @cfg {String} dataName the named area of the template to use as the data area
10432 * Works with domtemplates roo-name="name"
10436 * @cfg {String} selectedClass The css class to add to selected nodes
10438 selectedClass : "x-view-selected",
10440 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10445 * @cfg {String} text to display on mask (default Loading)
10449 * @cfg {Boolean} multiSelect Allow multiple selection
10451 multiSelect : false,
10453 * @cfg {Boolean} singleSelect Allow single selection
10455 singleSelect: false,
10458 * @cfg {Boolean} toggleSelect - selecting
10460 toggleSelect : false,
10463 * Returns the element this view is bound to.
10464 * @return {Roo.Element}
10466 getEl : function(){
10467 return this.wrapEl;
10473 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10475 refresh : function(){
10476 Roo.log('refresh');
10479 // if we are using something like 'domtemplate', then
10480 // the what gets used is:
10481 // t.applySubtemplate(NAME, data, wrapping data..)
10482 // the outer template then get' applied with
10483 // the store 'extra data'
10484 // and the body get's added to the
10485 // roo-name="data" node?
10486 // <span class='roo-tpl-{name}'></span> ?????
10490 this.clearSelections();
10491 this.el.update("");
10493 var records = this.store.getRange();
10494 if(records.length < 1) {
10496 // is this valid?? = should it render a template??
10498 this.el.update(this.emptyText);
10502 if (this.dataName) {
10503 this.el.update(t.apply(this.store.meta)); //????
10504 el = this.el.child('.roo-tpl-' + this.dataName);
10507 for(var i = 0, len = records.length; i < len; i++){
10508 var data = this.prepareData(records[i].data, i, records[i]);
10509 this.fireEvent("preparedata", this, data, i, records[i]);
10510 html[html.length] = Roo.util.Format.trim(
10512 t.applySubtemplate(this.dataName, data, this.store.meta) :
10519 el.update(html.join(""));
10520 this.nodes = el.dom.childNodes;
10521 this.updateIndexes(0);
10526 * Function to override to reformat the data that is sent to
10527 * the template for each node.
10528 * DEPRICATED - use the preparedata event handler.
10529 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10530 * a JSON object for an UpdateManager bound view).
10532 prepareData : function(data, index, record)
10534 this.fireEvent("preparedata", this, data, index, record);
10538 onUpdate : function(ds, record){
10539 Roo.log('on update');
10540 this.clearSelections();
10541 var index = this.store.indexOf(record);
10542 var n = this.nodes[index];
10543 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10544 n.parentNode.removeChild(n);
10545 this.updateIndexes(index, index);
10551 onAdd : function(ds, records, index)
10553 Roo.log(['on Add', ds, records, index] );
10554 this.clearSelections();
10555 if(this.nodes.length == 0){
10559 var n = this.nodes[index];
10560 for(var i = 0, len = records.length; i < len; i++){
10561 var d = this.prepareData(records[i].data, i, records[i]);
10563 this.tpl.insertBefore(n, d);
10566 this.tpl.append(this.el, d);
10569 this.updateIndexes(index);
10572 onRemove : function(ds, record, index){
10573 Roo.log('onRemove');
10574 this.clearSelections();
10575 var el = this.dataName ?
10576 this.el.child('.roo-tpl-' + this.dataName) :
10579 el.dom.removeChild(this.nodes[index]);
10580 this.updateIndexes(index);
10584 * Refresh an individual node.
10585 * @param {Number} index
10587 refreshNode : function(index){
10588 this.onUpdate(this.store, this.store.getAt(index));
10591 updateIndexes : function(startIndex, endIndex){
10592 var ns = this.nodes;
10593 startIndex = startIndex || 0;
10594 endIndex = endIndex || ns.length - 1;
10595 for(var i = startIndex; i <= endIndex; i++){
10596 ns[i].nodeIndex = i;
10601 * Changes the data store this view uses and refresh the view.
10602 * @param {Store} store
10604 setStore : function(store, initial){
10605 if(!initial && this.store){
10606 this.store.un("datachanged", this.refresh);
10607 this.store.un("add", this.onAdd);
10608 this.store.un("remove", this.onRemove);
10609 this.store.un("update", this.onUpdate);
10610 this.store.un("clear", this.refresh);
10611 this.store.un("beforeload", this.onBeforeLoad);
10612 this.store.un("load", this.onLoad);
10613 this.store.un("loadexception", this.onLoad);
10617 store.on("datachanged", this.refresh, this);
10618 store.on("add", this.onAdd, this);
10619 store.on("remove", this.onRemove, this);
10620 store.on("update", this.onUpdate, this);
10621 store.on("clear", this.refresh, this);
10622 store.on("beforeload", this.onBeforeLoad, this);
10623 store.on("load", this.onLoad, this);
10624 store.on("loadexception", this.onLoad, this);
10632 * onbeforeLoad - masks the loading area.
10635 onBeforeLoad : function(store,opts)
10637 Roo.log('onBeforeLoad');
10639 this.el.update("");
10641 this.el.mask(this.mask ? this.mask : "Loading" );
10643 onLoad : function ()
10650 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10651 * @param {HTMLElement} node
10652 * @return {HTMLElement} The template node
10654 findItemFromChild : function(node){
10655 var el = this.dataName ?
10656 this.el.child('.roo-tpl-' + this.dataName,true) :
10659 if(!node || node.parentNode == el){
10662 var p = node.parentNode;
10663 while(p && p != el){
10664 if(p.parentNode == el){
10673 onClick : function(e){
10674 var item = this.findItemFromChild(e.getTarget());
10676 var index = this.indexOf(item);
10677 if(this.onItemClick(item, index, e) !== false){
10678 this.fireEvent("click", this, index, item, e);
10681 this.clearSelections();
10686 onContextMenu : function(e){
10687 var item = this.findItemFromChild(e.getTarget());
10689 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10694 onDblClick : function(e){
10695 var item = this.findItemFromChild(e.getTarget());
10697 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10701 onItemClick : function(item, index, e)
10703 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10706 if (this.toggleSelect) {
10707 var m = this.isSelected(item) ? 'unselect' : 'select';
10710 _t[m](item, true, false);
10713 if(this.multiSelect || this.singleSelect){
10714 if(this.multiSelect && e.shiftKey && this.lastSelection){
10715 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10717 this.select(item, this.multiSelect && e.ctrlKey);
10718 this.lastSelection = item;
10720 e.preventDefault();
10726 * Get the number of selected nodes.
10729 getSelectionCount : function(){
10730 return this.selections.length;
10734 * Get the currently selected nodes.
10735 * @return {Array} An array of HTMLElements
10737 getSelectedNodes : function(){
10738 return this.selections;
10742 * Get the indexes of the selected nodes.
10745 getSelectedIndexes : function(){
10746 var indexes = [], s = this.selections;
10747 for(var i = 0, len = s.length; i < len; i++){
10748 indexes.push(s[i].nodeIndex);
10754 * Clear all selections
10755 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10757 clearSelections : function(suppressEvent){
10758 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10759 this.cmp.elements = this.selections;
10760 this.cmp.removeClass(this.selectedClass);
10761 this.selections = [];
10762 if(!suppressEvent){
10763 this.fireEvent("selectionchange", this, this.selections);
10769 * Returns true if the passed node is selected
10770 * @param {HTMLElement/Number} node The node or node index
10771 * @return {Boolean}
10773 isSelected : function(node){
10774 var s = this.selections;
10778 node = this.getNode(node);
10779 return s.indexOf(node) !== -1;
10784 * @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
10785 * @param {Boolean} keepExisting (optional) true to keep existing selections
10786 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10788 select : function(nodeInfo, keepExisting, suppressEvent){
10789 if(nodeInfo instanceof Array){
10791 this.clearSelections(true);
10793 for(var i = 0, len = nodeInfo.length; i < len; i++){
10794 this.select(nodeInfo[i], true, true);
10798 var node = this.getNode(nodeInfo);
10799 if(!node || this.isSelected(node)){
10800 return; // already selected.
10803 this.clearSelections(true);
10805 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10806 Roo.fly(node).addClass(this.selectedClass);
10807 this.selections.push(node);
10808 if(!suppressEvent){
10809 this.fireEvent("selectionchange", this, this.selections);
10817 * @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
10818 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10819 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10821 unselect : function(nodeInfo, keepExisting, suppressEvent)
10823 if(nodeInfo instanceof Array){
10824 Roo.each(this.selections, function(s) {
10825 this.unselect(s, nodeInfo);
10829 var node = this.getNode(nodeInfo);
10830 if(!node || !this.isSelected(node)){
10831 Roo.log("not selected");
10832 return; // not selected.
10836 Roo.each(this.selections, function(s) {
10838 Roo.fly(node).removeClass(this.selectedClass);
10845 this.selections= ns;
10846 this.fireEvent("selectionchange", this, this.selections);
10850 * Gets a template node.
10851 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10852 * @return {HTMLElement} The node or null if it wasn't found
10854 getNode : function(nodeInfo){
10855 if(typeof nodeInfo == "string"){
10856 return document.getElementById(nodeInfo);
10857 }else if(typeof nodeInfo == "number"){
10858 return this.nodes[nodeInfo];
10864 * Gets a range template nodes.
10865 * @param {Number} startIndex
10866 * @param {Number} endIndex
10867 * @return {Array} An array of nodes
10869 getNodes : function(start, end){
10870 var ns = this.nodes;
10871 start = start || 0;
10872 end = typeof end == "undefined" ? ns.length - 1 : end;
10875 for(var i = start; i <= end; i++){
10879 for(var i = start; i >= end; i--){
10887 * Finds the index of the passed node
10888 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10889 * @return {Number} The index of the node or -1
10891 indexOf : function(node){
10892 node = this.getNode(node);
10893 if(typeof node.nodeIndex == "number"){
10894 return node.nodeIndex;
10896 var ns = this.nodes;
10897 for(var i = 0, len = ns.length; i < len; i++){
10908 * based on jquery fullcalendar
10912 Roo.bootstrap = Roo.bootstrap || {};
10914 * @class Roo.bootstrap.Calendar
10915 * @extends Roo.bootstrap.Component
10916 * Bootstrap Calendar class
10917 * @cfg {Boolean} loadMask (true|false) default false
10918 * @cfg {Object} header generate the user specific header of the calendar, default false
10921 * Create a new Container
10922 * @param {Object} config The config object
10927 Roo.bootstrap.Calendar = function(config){
10928 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10932 * Fires when a date is selected
10933 * @param {DatePicker} this
10934 * @param {Date} date The selected date
10938 * @event monthchange
10939 * Fires when the displayed month changes
10940 * @param {DatePicker} this
10941 * @param {Date} date The selected month
10943 'monthchange': true,
10945 * @event evententer
10946 * Fires when mouse over an event
10947 * @param {Calendar} this
10948 * @param {event} Event
10950 'evententer': true,
10952 * @event eventleave
10953 * Fires when the mouse leaves an
10954 * @param {Calendar} this
10957 'eventleave': true,
10959 * @event eventclick
10960 * Fires when the mouse click an
10961 * @param {Calendar} this
10970 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10973 * @cfg {Number} startDay
10974 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10982 getAutoCreate : function(){
10985 var fc_button = function(name, corner, style, content ) {
10986 return Roo.apply({},{
10988 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10990 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10993 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11004 style : 'width:100%',
11011 cls : 'fc-header-left',
11013 fc_button('prev', 'left', 'arrow', '‹' ),
11014 fc_button('next', 'right', 'arrow', '›' ),
11015 { tag: 'span', cls: 'fc-header-space' },
11016 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11024 cls : 'fc-header-center',
11028 cls: 'fc-header-title',
11031 html : 'month / year'
11039 cls : 'fc-header-right',
11041 /* fc_button('month', 'left', '', 'month' ),
11042 fc_button('week', '', '', 'week' ),
11043 fc_button('day', 'right', '', 'day' )
11055 header = this.header;
11058 var cal_heads = function() {
11060 // fixme - handle this.
11062 for (var i =0; i < Date.dayNames.length; i++) {
11063 var d = Date.dayNames[i];
11066 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11067 html : d.substring(0,3)
11071 ret[0].cls += ' fc-first';
11072 ret[6].cls += ' fc-last';
11075 var cal_cell = function(n) {
11078 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11083 cls: 'fc-day-number',
11087 cls: 'fc-day-content',
11091 style: 'position: relative;' // height: 17px;
11103 var cal_rows = function() {
11106 for (var r = 0; r < 6; r++) {
11113 for (var i =0; i < Date.dayNames.length; i++) {
11114 var d = Date.dayNames[i];
11115 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11118 row.cn[0].cls+=' fc-first';
11119 row.cn[0].cn[0].style = 'min-height:90px';
11120 row.cn[6].cls+=' fc-last';
11124 ret[0].cls += ' fc-first';
11125 ret[4].cls += ' fc-prev-last';
11126 ret[5].cls += ' fc-last';
11133 cls: 'fc-border-separate',
11134 style : 'width:100%',
11142 cls : 'fc-first fc-last',
11160 cls : 'fc-content',
11161 style : "position: relative;",
11164 cls : 'fc-view fc-view-month fc-grid',
11165 style : 'position: relative',
11166 unselectable : 'on',
11169 cls : 'fc-event-container',
11170 style : 'position:absolute;z-index:8;top:0;left:0;'
11188 initEvents : function()
11191 throw "can not find store for calendar";
11197 style: "text-align:center",
11201 style: "background-color:white;width:50%;margin:250 auto",
11205 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
11216 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11218 var size = this.el.select('.fc-content', true).first().getSize();
11219 this.maskEl.setSize(size.width, size.height);
11220 this.maskEl.enableDisplayMode("block");
11221 if(!this.loadMask){
11222 this.maskEl.hide();
11225 this.store = Roo.factory(this.store, Roo.data);
11226 this.store.on('load', this.onLoad, this);
11227 this.store.on('beforeload', this.onBeforeLoad, this);
11231 this.cells = this.el.select('.fc-day',true);
11232 //Roo.log(this.cells);
11233 this.textNodes = this.el.query('.fc-day-number');
11234 this.cells.addClassOnOver('fc-state-hover');
11236 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11237 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11238 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11239 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11241 this.on('monthchange', this.onMonthChange, this);
11243 this.update(new Date().clearTime());
11246 resize : function() {
11247 var sz = this.el.getSize();
11249 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11250 this.el.select('.fc-day-content div',true).setHeight(34);
11255 showPrevMonth : function(e){
11256 this.update(this.activeDate.add("mo", -1));
11258 showToday : function(e){
11259 this.update(new Date().clearTime());
11262 showNextMonth : function(e){
11263 this.update(this.activeDate.add("mo", 1));
11267 showPrevYear : function(){
11268 this.update(this.activeDate.add("y", -1));
11272 showNextYear : function(){
11273 this.update(this.activeDate.add("y", 1));
11278 update : function(date)
11280 var vd = this.activeDate;
11281 this.activeDate = date;
11282 // if(vd && this.el){
11283 // var t = date.getTime();
11284 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11285 // Roo.log('using add remove');
11287 // this.fireEvent('monthchange', this, date);
11289 // this.cells.removeClass("fc-state-highlight");
11290 // this.cells.each(function(c){
11291 // if(c.dateValue == t){
11292 // c.addClass("fc-state-highlight");
11293 // setTimeout(function(){
11294 // try{c.dom.firstChild.focus();}catch(e){}
11304 var days = date.getDaysInMonth();
11306 var firstOfMonth = date.getFirstDateOfMonth();
11307 var startingPos = firstOfMonth.getDay()-this.startDay;
11309 if(startingPos < this.startDay){
11313 var pm = date.add(Date.MONTH, -1);
11314 var prevStart = pm.getDaysInMonth()-startingPos;
11316 this.cells = this.el.select('.fc-day',true);
11317 this.textNodes = this.el.query('.fc-day-number');
11318 this.cells.addClassOnOver('fc-state-hover');
11320 var cells = this.cells.elements;
11321 var textEls = this.textNodes;
11323 Roo.each(cells, function(cell){
11324 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11327 days += startingPos;
11329 // convert everything to numbers so it's fast
11330 var day = 86400000;
11331 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11334 //Roo.log(prevStart);
11336 var today = new Date().clearTime().getTime();
11337 var sel = date.clearTime().getTime();
11338 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11339 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11340 var ddMatch = this.disabledDatesRE;
11341 var ddText = this.disabledDatesText;
11342 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11343 var ddaysText = this.disabledDaysText;
11344 var format = this.format;
11346 var setCellClass = function(cal, cell){
11350 //Roo.log('set Cell Class');
11352 var t = d.getTime();
11356 cell.dateValue = t;
11358 cell.className += " fc-today";
11359 cell.className += " fc-state-highlight";
11360 cell.title = cal.todayText;
11363 // disable highlight in other month..
11364 //cell.className += " fc-state-highlight";
11369 cell.className = " fc-state-disabled";
11370 cell.title = cal.minText;
11374 cell.className = " fc-state-disabled";
11375 cell.title = cal.maxText;
11379 if(ddays.indexOf(d.getDay()) != -1){
11380 cell.title = ddaysText;
11381 cell.className = " fc-state-disabled";
11384 if(ddMatch && format){
11385 var fvalue = d.dateFormat(format);
11386 if(ddMatch.test(fvalue)){
11387 cell.title = ddText.replace("%0", fvalue);
11388 cell.className = " fc-state-disabled";
11392 if (!cell.initialClassName) {
11393 cell.initialClassName = cell.dom.className;
11396 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11401 for(; i < startingPos; i++) {
11402 textEls[i].innerHTML = (++prevStart);
11403 d.setDate(d.getDate()+1);
11405 cells[i].className = "fc-past fc-other-month";
11406 setCellClass(this, cells[i]);
11411 for(; i < days; i++){
11412 intDay = i - startingPos + 1;
11413 textEls[i].innerHTML = (intDay);
11414 d.setDate(d.getDate()+1);
11416 cells[i].className = ''; // "x-date-active";
11417 setCellClass(this, cells[i]);
11421 for(; i < 42; i++) {
11422 textEls[i].innerHTML = (++extraDays);
11423 d.setDate(d.getDate()+1);
11425 cells[i].className = "fc-future fc-other-month";
11426 setCellClass(this, cells[i]);
11429 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11431 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11433 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11434 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11436 if(totalRows != 6){
11437 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11438 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11441 this.fireEvent('monthchange', this, date);
11445 if(!this.internalRender){
11446 var main = this.el.dom.firstChild;
11447 var w = main.offsetWidth;
11448 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11449 Roo.fly(main).setWidth(w);
11450 this.internalRender = true;
11451 // opera does not respect the auto grow header center column
11452 // then, after it gets a width opera refuses to recalculate
11453 // without a second pass
11454 if(Roo.isOpera && !this.secondPass){
11455 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11456 this.secondPass = true;
11457 this.update.defer(10, this, [date]);
11464 findCell : function(dt) {
11465 dt = dt.clearTime().getTime();
11467 this.cells.each(function(c){
11468 //Roo.log("check " +c.dateValue + '?=' + dt);
11469 if(c.dateValue == dt){
11479 findCells : function(ev) {
11480 var s = ev.start.clone().clearTime().getTime();
11482 var e= ev.end.clone().clearTime().getTime();
11485 this.cells.each(function(c){
11486 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11488 if(c.dateValue > e){
11491 if(c.dateValue < s){
11500 // findBestRow: function(cells)
11504 // for (var i =0 ; i < cells.length;i++) {
11505 // ret = Math.max(cells[i].rows || 0,ret);
11512 addItem : function(ev)
11514 // look for vertical location slot in
11515 var cells = this.findCells(ev);
11517 // ev.row = this.findBestRow(cells);
11519 // work out the location.
11523 for(var i =0; i < cells.length; i++) {
11525 cells[i].row = cells[0].row;
11528 cells[i].row = cells[i].row + 1;
11538 if (crow.start.getY() == cells[i].getY()) {
11540 crow.end = cells[i];
11557 cells[0].events.push(ev);
11559 this.calevents.push(ev);
11562 clearEvents: function() {
11564 if(!this.calevents){
11568 Roo.each(this.cells.elements, function(c){
11574 Roo.each(this.calevents, function(e) {
11575 Roo.each(e.els, function(el) {
11576 el.un('mouseenter' ,this.onEventEnter, this);
11577 el.un('mouseleave' ,this.onEventLeave, this);
11582 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11588 renderEvents: function()
11592 this.cells.each(function(c) {
11601 if(c.row != c.events.length){
11602 r = 4 - (4 - (c.row - c.events.length));
11605 c.events = ev.slice(0, r);
11606 c.more = ev.slice(r);
11608 if(c.more.length && c.more.length == 1){
11609 c.events.push(c.more.pop());
11612 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
11616 this.cells.each(function(c) {
11618 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
11621 for (var e = 0; e < c.events.length; e++){
11622 var ev = c.events[e];
11623 var rows = ev.rows;
11625 for(var i = 0; i < rows.length; i++) {
11627 // how many rows should it span..
11630 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11631 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11633 unselectable : "on",
11636 cls: 'fc-event-inner',
11640 // cls: 'fc-event-time',
11641 // html : cells.length > 1 ? '' : ev.time
11645 cls: 'fc-event-title',
11646 html : String.format('{0}', ev.title)
11653 cls: 'ui-resizable-handle ui-resizable-e',
11654 html : '  '
11661 cfg.cls += ' fc-event-start';
11663 if ((i+1) == rows.length) {
11664 cfg.cls += ' fc-event-end';
11667 var ctr = _this.el.select('.fc-event-container',true).first();
11668 var cg = ctr.createChild(cfg);
11670 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11671 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11673 var r = (c.more.length) ? 1 : 0;
11674 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
11675 cg.setWidth(ebox.right - sbox.x -2);
11677 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11678 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11679 cg.on('click', _this.onEventClick, _this, ev);
11690 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11691 style : 'position: absolute',
11692 unselectable : "on",
11695 cls: 'fc-event-inner',
11699 cls: 'fc-event-title',
11707 cls: 'ui-resizable-handle ui-resizable-e',
11708 html : '  '
11714 var ctr = _this.el.select('.fc-event-container',true).first();
11715 var cg = ctr.createChild(cfg);
11717 var sbox = c.select('.fc-day-content',true).first().getBox();
11718 var ebox = c.select('.fc-day-content',true).first().getBox();
11720 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
11721 cg.setWidth(ebox.right - sbox.x -2);
11723 cg.on('click', _this.onMoreEventClick, _this, c.more);
11733 onEventEnter: function (e, el,event,d) {
11734 this.fireEvent('evententer', this, el, event);
11737 onEventLeave: function (e, el,event,d) {
11738 this.fireEvent('eventleave', this, el, event);
11741 onEventClick: function (e, el,event,d) {
11742 this.fireEvent('eventclick', this, el, event);
11745 onMonthChange: function () {
11749 onMoreEventClick: function(e, el, more)
11753 this.calpopover.placement = 'right';
11754 this.calpopover.setTitle('More');
11756 this.calpopover.setContent('');
11758 var ctr = this.calpopover.el.select('.popover-content', true).first();
11760 Roo.each(more, function(m){
11762 cls : 'fc-event-hori fc-event-draggable',
11765 var cg = ctr.createChild(cfg);
11767 cg.on('click', _this.onEventClick, _this, m);
11770 this.calpopover.show(el);
11775 onLoad: function ()
11777 this.calevents = [];
11780 if(this.store.getCount() > 0){
11781 this.store.data.each(function(d){
11784 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11785 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11786 time : d.data.start_time,
11787 title : d.data.title,
11788 description : d.data.description,
11789 venue : d.data.venue
11794 this.renderEvents();
11796 if(this.calevents.length && this.loadMask){
11797 this.maskEl.hide();
11801 onBeforeLoad: function()
11803 this.clearEvents();
11805 this.maskEl.show();
11819 * @class Roo.bootstrap.Popover
11820 * @extends Roo.bootstrap.Component
11821 * Bootstrap Popover class
11822 * @cfg {String} html contents of the popover (or false to use children..)
11823 * @cfg {String} title of popover (or false to hide)
11824 * @cfg {String} placement how it is placed
11825 * @cfg {String} trigger click || hover (or false to trigger manually)
11826 * @cfg {String} over what (parent or false to trigger manually.)
11829 * Create a new Popover
11830 * @param {Object} config The config object
11833 Roo.bootstrap.Popover = function(config){
11834 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11837 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11839 title: 'Fill in a title',
11842 placement : 'right',
11843 trigger : 'hover', // hover
11847 can_build_overlaid : false,
11849 getChildContainer : function()
11851 return this.el.select('.popover-content',true).first();
11854 getAutoCreate : function(){
11855 Roo.log('make popover?');
11857 cls : 'popover roo-dynamic',
11858 style: 'display:block',
11864 cls : 'popover-inner',
11868 cls: 'popover-title',
11872 cls : 'popover-content',
11883 setTitle: function(str)
11885 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11887 setContent: function(str)
11889 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11891 // as it get's added to the bottom of the page.
11892 onRender : function(ct, position)
11894 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11896 var cfg = Roo.apply({}, this.getAutoCreate());
11900 cfg.cls += ' ' + this.cls;
11903 cfg.style = this.style;
11905 Roo.log("adding to ")
11906 this.el = Roo.get(document.body).createChild(cfg, position);
11912 initEvents : function()
11914 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11915 this.el.enableDisplayMode('block');
11917 if (this.over === false) {
11920 if (this.triggers === false) {
11923 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11924 var triggers = this.trigger ? this.trigger.split(' ') : [];
11925 Roo.each(triggers, function(trigger) {
11927 if (trigger == 'click') {
11928 on_el.on('click', this.toggle, this);
11929 } else if (trigger != 'manual') {
11930 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11931 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11933 on_el.on(eventIn ,this.enter, this);
11934 on_el.on(eventOut, this.leave, this);
11945 toggle : function () {
11946 this.hoverState == 'in' ? this.leave() : this.enter();
11949 enter : function () {
11952 clearTimeout(this.timeout);
11954 this.hoverState = 'in'
11956 if (!this.delay || !this.delay.show) {
11961 this.timeout = setTimeout(function () {
11962 if (_t.hoverState == 'in') {
11965 }, this.delay.show)
11967 leave : function() {
11968 clearTimeout(this.timeout);
11970 this.hoverState = 'out'
11972 if (!this.delay || !this.delay.hide) {
11977 this.timeout = setTimeout(function () {
11978 if (_t.hoverState == 'out') {
11981 }, this.delay.hide)
11984 show : function (on_el)
11987 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11990 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11991 if (this.html !== false) {
11992 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11994 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11995 if (!this.title.length) {
11996 this.el.select('.popover-title',true).hide();
11999 var placement = typeof this.placement == 'function' ?
12000 this.placement.call(this, this.el, on_el) :
12003 var autoToken = /\s?auto?\s?/i;
12004 var autoPlace = autoToken.test(placement);
12006 placement = placement.replace(autoToken, '') || 'top';
12010 //this.el.setXY([0,0]);
12012 this.el.dom.style.display='block';
12013 this.el.addClass(placement);
12015 //this.el.appendTo(on_el);
12017 var p = this.getPosition();
12018 var box = this.el.getBox();
12023 var align = Roo.bootstrap.Popover.alignment[placement]
12024 this.el.alignTo(on_el, align[0],align[1]);
12025 //var arrow = this.el.select('.arrow',true).first();
12026 //arrow.set(align[2],
12028 this.el.addClass('in');
12029 this.hoverState = null;
12031 if (this.el.hasClass('fade')) {
12038 this.el.setXY([0,0]);
12039 this.el.removeClass('in');
12046 Roo.bootstrap.Popover.alignment = {
12047 'left' : ['r-l', [-10,0], 'right'],
12048 'right' : ['l-r', [10,0], 'left'],
12049 'bottom' : ['t-b', [0,10], 'top'],
12050 'top' : [ 'b-t', [0,-10], 'bottom']
12061 * @class Roo.bootstrap.Progress
12062 * @extends Roo.bootstrap.Component
12063 * Bootstrap Progress class
12064 * @cfg {Boolean} striped striped of the progress bar
12065 * @cfg {Boolean} active animated of the progress bar
12069 * Create a new Progress
12070 * @param {Object} config The config object
12073 Roo.bootstrap.Progress = function(config){
12074 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12077 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12082 getAutoCreate : function(){
12090 cfg.cls += ' progress-striped';
12094 cfg.cls += ' active';
12113 * @class Roo.bootstrap.ProgressBar
12114 * @extends Roo.bootstrap.Component
12115 * Bootstrap ProgressBar class
12116 * @cfg {Number} aria_valuenow aria-value now
12117 * @cfg {Number} aria_valuemin aria-value min
12118 * @cfg {Number} aria_valuemax aria-value max
12119 * @cfg {String} label label for the progress bar
12120 * @cfg {String} panel (success | info | warning | danger )
12121 * @cfg {String} role role of the progress bar
12122 * @cfg {String} sr_only text
12126 * Create a new ProgressBar
12127 * @param {Object} config The config object
12130 Roo.bootstrap.ProgressBar = function(config){
12131 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12134 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12138 aria_valuemax : 100,
12144 getAutoCreate : function()
12149 cls: 'progress-bar',
12150 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12162 cfg.role = this.role;
12165 if(this.aria_valuenow){
12166 cfg['aria-valuenow'] = this.aria_valuenow;
12169 if(this.aria_valuemin){
12170 cfg['aria-valuemin'] = this.aria_valuemin;
12173 if(this.aria_valuemax){
12174 cfg['aria-valuemax'] = this.aria_valuemax;
12177 if(this.label && !this.sr_only){
12178 cfg.html = this.label;
12182 cfg.cls += ' progress-bar-' + this.panel;
12188 update : function(aria_valuenow)
12190 this.aria_valuenow = aria_valuenow;
12192 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12207 * @class Roo.bootstrap.TabPanel
12208 * @extends Roo.bootstrap.Component
12209 * Bootstrap TabPanel class
12210 * @cfg {Boolean} active panel active
12211 * @cfg {String} html panel content
12212 * @cfg {String} tabId tab relate id
12213 * @cfg {String} navId The navbar which triggers show hide
12217 * Create a new TabPanel
12218 * @param {Object} config The config object
12221 Roo.bootstrap.TabPanel = function(config){
12222 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12226 * Fires when the active status changes
12227 * @param {Roo.bootstrap.TabPanel} this
12228 * @param {Boolean} state the new state
12235 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12242 getAutoCreate : function(){
12246 html: this.html || ''
12250 cfg.cls += ' active';
12254 cfg.tabId = this.tabId;
12259 onRender : function(ct, position)
12261 // Roo.log("Call onRender: " + this.xtype);
12263 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12265 if (this.navId && this.tabId) {
12266 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12268 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12270 item.on('changed', function(item, state) {
12271 this.setActive(state);
12277 setActive: function(state)
12279 Roo.log("panel - set active " + this.tabId + "=" + state);
12281 this.active = state;
12283 this.el.removeClass('active');
12285 } else if (!this.el.hasClass('active')) {
12286 this.el.addClass('active');
12288 this.fireEvent('changed', this, state);
12305 * @class Roo.bootstrap.DateField
12306 * @extends Roo.bootstrap.Input
12307 * Bootstrap DateField class
12308 * @cfg {Number} weekStart default 0
12309 * @cfg {Number} weekStart default 0
12310 * @cfg {Number} viewMode default empty, (months|years)
12311 * @cfg {Number} minViewMode default empty, (months|years)
12312 * @cfg {Number} startDate default -Infinity
12313 * @cfg {Number} endDate default Infinity
12314 * @cfg {Boolean} todayHighlight default false
12315 * @cfg {Boolean} todayBtn default false
12316 * @cfg {Boolean} calendarWeeks default false
12317 * @cfg {Object} daysOfWeekDisabled default empty
12319 * @cfg {Boolean} keyboardNavigation default true
12320 * @cfg {String} language default en
12323 * Create a new DateField
12324 * @param {Object} config The config object
12327 Roo.bootstrap.DateField = function(config){
12328 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12332 * Fires when this field show.
12333 * @param {Roo.bootstrap.DateField} this
12334 * @param {Mixed} date The date value
12339 * Fires when this field hide.
12340 * @param {Roo.bootstrap.DateField} this
12341 * @param {Mixed} date The date value
12346 * Fires when select a date.
12347 * @param {Roo.bootstrap.DateField} this
12348 * @param {Mixed} date The date value
12354 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12357 * @cfg {String} format
12358 * The default date format string which can be overriden for localization support. The format must be
12359 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12363 * @cfg {String} altFormats
12364 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12365 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12367 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12375 todayHighlight : false,
12381 keyboardNavigation: true,
12383 calendarWeeks: false,
12385 startDate: -Infinity,
12389 daysOfWeekDisabled: [],
12393 UTCDate: function()
12395 return new Date(Date.UTC.apply(Date, arguments));
12398 UTCToday: function()
12400 var today = new Date();
12401 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12404 getDate: function() {
12405 var d = this.getUTCDate();
12406 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12409 getUTCDate: function() {
12413 setDate: function(d) {
12414 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12417 setUTCDate: function(d) {
12419 this.setValue(this.formatDate(this.date));
12422 onRender: function(ct, position)
12425 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12427 this.language = this.language || 'en';
12428 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12429 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12431 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12432 this.format = this.format || 'm/d/y';
12433 this.isInline = false;
12434 this.isInput = true;
12435 this.component = this.el.select('.add-on', true).first() || false;
12436 this.component = (this.component && this.component.length === 0) ? false : this.component;
12437 this.hasInput = this.component && this.inputEL().length;
12439 if (typeof(this.minViewMode === 'string')) {
12440 switch (this.minViewMode) {
12442 this.minViewMode = 1;
12445 this.minViewMode = 2;
12448 this.minViewMode = 0;
12453 if (typeof(this.viewMode === 'string')) {
12454 switch (this.viewMode) {
12467 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12469 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12471 this.picker().on('mousedown', this.onMousedown, this);
12472 this.picker().on('click', this.onClick, this);
12474 this.picker().addClass('datepicker-dropdown');
12476 this.startViewMode = this.viewMode;
12479 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12480 if(!this.calendarWeeks){
12485 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12486 v.attr('colspan', function(i, val){
12487 return parseInt(val) + 1;
12492 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12494 this.setStartDate(this.startDate);
12495 this.setEndDate(this.endDate);
12497 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12504 if(this.isInline) {
12509 picker : function()
12511 return this.el.select('.datepicker', true).first();
12514 fillDow: function()
12516 var dowCnt = this.weekStart;
12525 if(this.calendarWeeks){
12533 while (dowCnt < this.weekStart + 7) {
12537 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12541 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12544 fillMonths: function()
12547 var months = this.picker().select('>.datepicker-months td', true).first();
12549 months.dom.innerHTML = '';
12555 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12558 months.createChild(month);
12563 update: function(){
12565 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12567 if (this.date < this.startDate) {
12568 this.viewDate = new Date(this.startDate);
12569 } else if (this.date > this.endDate) {
12570 this.viewDate = new Date(this.endDate);
12572 this.viewDate = new Date(this.date);
12579 var d = new Date(this.viewDate),
12580 year = d.getUTCFullYear(),
12581 month = d.getUTCMonth(),
12582 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12583 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12584 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12585 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12586 currentDate = this.date && this.date.valueOf(),
12587 today = this.UTCToday();
12589 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12591 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12593 // this.picker.select('>tfoot th.today').
12594 // .text(dates[this.language].today)
12595 // .toggle(this.todayBtn !== false);
12597 this.updateNavArrows();
12600 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12602 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12604 prevMonth.setUTCDate(day);
12606 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12608 var nextMonth = new Date(prevMonth);
12610 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12612 nextMonth = nextMonth.valueOf();
12614 var fillMonths = false;
12616 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12618 while(prevMonth.valueOf() < nextMonth) {
12621 if (prevMonth.getUTCDay() === this.weekStart) {
12623 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12631 if(this.calendarWeeks){
12632 // ISO 8601: First week contains first thursday.
12633 // ISO also states week starts on Monday, but we can be more abstract here.
12635 // Start of current week: based on weekstart/current date
12636 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12637 // Thursday of this week
12638 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12639 // First Thursday of year, year from thursday
12640 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12641 // Calendar week: ms between thursdays, div ms per day, div 7 days
12642 calWeek = (th - yth) / 864e5 / 7 + 1;
12644 fillMonths.cn.push({
12652 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12654 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12657 if (this.todayHighlight &&
12658 prevMonth.getUTCFullYear() == today.getFullYear() &&
12659 prevMonth.getUTCMonth() == today.getMonth() &&
12660 prevMonth.getUTCDate() == today.getDate()) {
12661 clsName += ' today';
12664 if (currentDate && prevMonth.valueOf() === currentDate) {
12665 clsName += ' active';
12668 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12669 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12670 clsName += ' disabled';
12673 fillMonths.cn.push({
12675 cls: 'day ' + clsName,
12676 html: prevMonth.getDate()
12679 prevMonth.setDate(prevMonth.getDate()+1);
12682 var currentYear = this.date && this.date.getUTCFullYear();
12683 var currentMonth = this.date && this.date.getUTCMonth();
12685 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12687 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12688 v.removeClass('active');
12690 if(currentYear === year && k === currentMonth){
12691 v.addClass('active');
12694 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12695 v.addClass('disabled');
12701 year = parseInt(year/10, 10) * 10;
12703 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12705 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12708 for (var i = -1; i < 11; i++) {
12709 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12711 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12719 showMode: function(dir) {
12721 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12723 Roo.each(this.picker().select('>div',true).elements, function(v){
12724 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12727 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12732 if(this.isInline) return;
12734 this.picker().removeClass(['bottom', 'top']);
12736 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12738 * place to the top of element!
12742 this.picker().addClass('top');
12743 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12748 this.picker().addClass('bottom');
12750 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12753 parseDate : function(value){
12754 if(!value || value instanceof Date){
12757 var v = Date.parseDate(value, this.format);
12758 if (!v && this.useIso) {
12759 v = Date.parseDate(value, 'Y-m-d');
12761 if(!v && this.altFormats){
12762 if(!this.altFormatsArray){
12763 this.altFormatsArray = this.altFormats.split("|");
12765 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12766 v = Date.parseDate(value, this.altFormatsArray[i]);
12772 formatDate : function(date, fmt){
12773 return (!date || !(date instanceof Date)) ?
12774 date : date.dateFormat(fmt || this.format);
12777 onFocus : function()
12779 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12783 onBlur : function()
12785 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12791 this.picker().show();
12795 this.fireEvent('show', this, this.date);
12800 if(this.isInline) return;
12801 this.picker().hide();
12802 this.viewMode = this.startViewMode;
12805 this.fireEvent('hide', this, this.date);
12809 onMousedown: function(e){
12810 e.stopPropagation();
12811 e.preventDefault();
12814 keyup: function(e){
12815 Roo.bootstrap.DateField.superclass.keyup.call(this);
12820 setValue: function(v){
12821 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12823 this.fireEvent('select', this, this.date);
12827 fireKey: function(e){
12828 if (!this.picker().isVisible()){
12829 if (e.keyCode == 27) // allow escape to hide and re-show picker
12833 var dateChanged = false,
12835 newDate, newViewDate;
12839 e.preventDefault();
12843 if (!this.keyboardNavigation) break;
12844 dir = e.keyCode == 37 ? -1 : 1;
12847 newDate = this.moveYear(this.date, dir);
12848 newViewDate = this.moveYear(this.viewDate, dir);
12849 } else if (e.shiftKey){
12850 newDate = this.moveMonth(this.date, dir);
12851 newViewDate = this.moveMonth(this.viewDate, dir);
12853 newDate = new Date(this.date);
12854 newDate.setUTCDate(this.date.getUTCDate() + dir);
12855 newViewDate = new Date(this.viewDate);
12856 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12858 if (this.dateWithinRange(newDate)){
12859 this.date = newDate;
12860 this.viewDate = newViewDate;
12861 this.setValue(this.formatDate(this.date));
12863 e.preventDefault();
12864 dateChanged = true;
12869 if (!this.keyboardNavigation) break;
12870 dir = e.keyCode == 38 ? -1 : 1;
12872 newDate = this.moveYear(this.date, dir);
12873 newViewDate = this.moveYear(this.viewDate, dir);
12874 } else if (e.shiftKey){
12875 newDate = this.moveMonth(this.date, dir);
12876 newViewDate = this.moveMonth(this.viewDate, dir);
12878 newDate = new Date(this.date);
12879 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12880 newViewDate = new Date(this.viewDate);
12881 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12883 if (this.dateWithinRange(newDate)){
12884 this.date = newDate;
12885 this.viewDate = newViewDate;
12886 this.setValue(this.formatDate(this.date));
12888 e.preventDefault();
12889 dateChanged = true;
12893 this.setValue(this.formatDate(this.date));
12895 e.preventDefault();
12898 this.setValue(this.formatDate(this.date));
12905 onClick: function(e) {
12906 e.stopPropagation();
12907 e.preventDefault();
12909 var target = e.getTarget();
12911 if(target.nodeName.toLowerCase() === 'i'){
12912 target = Roo.get(target).dom.parentNode;
12915 var nodeName = target.nodeName;
12916 var className = target.className;
12917 var html = target.innerHTML;
12919 switch(nodeName.toLowerCase()) {
12921 switch(className) {
12927 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12928 switch(this.viewMode){
12930 this.viewDate = this.moveMonth(this.viewDate, dir);
12934 this.viewDate = this.moveYear(this.viewDate, dir);
12940 var date = new Date();
12941 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12943 this.setValue(this.formatDate(this.date));
12949 if (className.indexOf('disabled') === -1) {
12950 this.viewDate.setUTCDate(1);
12951 if (className.indexOf('month') !== -1) {
12952 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12954 var year = parseInt(html, 10) || 0;
12955 this.viewDate.setUTCFullYear(year);
12964 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12965 var day = parseInt(html, 10) || 1;
12966 var year = this.viewDate.getUTCFullYear(),
12967 month = this.viewDate.getUTCMonth();
12969 if (className.indexOf('old') !== -1) {
12976 } else if (className.indexOf('new') !== -1) {
12984 this.date = this.UTCDate(year, month, day,0,0,0,0);
12985 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12987 this.setValue(this.formatDate(this.date));
12994 setStartDate: function(startDate){
12995 this.startDate = startDate || -Infinity;
12996 if (this.startDate !== -Infinity) {
12997 this.startDate = this.parseDate(this.startDate);
13000 this.updateNavArrows();
13003 setEndDate: function(endDate){
13004 this.endDate = endDate || Infinity;
13005 if (this.endDate !== Infinity) {
13006 this.endDate = this.parseDate(this.endDate);
13009 this.updateNavArrows();
13012 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13013 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13014 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13015 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13017 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13018 return parseInt(d, 10);
13021 this.updateNavArrows();
13024 updateNavArrows: function() {
13025 var d = new Date(this.viewDate),
13026 year = d.getUTCFullYear(),
13027 month = d.getUTCMonth();
13029 Roo.each(this.picker().select('.prev', true).elements, function(v){
13031 switch (this.viewMode) {
13034 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13040 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13047 Roo.each(this.picker().select('.next', true).elements, function(v){
13049 switch (this.viewMode) {
13052 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13058 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13066 moveMonth: function(date, dir){
13067 if (!dir) return date;
13068 var new_date = new Date(date.valueOf()),
13069 day = new_date.getUTCDate(),
13070 month = new_date.getUTCMonth(),
13071 mag = Math.abs(dir),
13073 dir = dir > 0 ? 1 : -1;
13076 // If going back one month, make sure month is not current month
13077 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13079 return new_date.getUTCMonth() == month;
13081 // If going forward one month, make sure month is as expected
13082 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13084 return new_date.getUTCMonth() != new_month;
13086 new_month = month + dir;
13087 new_date.setUTCMonth(new_month);
13088 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13089 if (new_month < 0 || new_month > 11)
13090 new_month = (new_month + 12) % 12;
13092 // For magnitudes >1, move one month at a time...
13093 for (var i=0; i<mag; i++)
13094 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13095 new_date = this.moveMonth(new_date, dir);
13096 // ...then reset the day, keeping it in the new month
13097 new_month = new_date.getUTCMonth();
13098 new_date.setUTCDate(day);
13100 return new_month != new_date.getUTCMonth();
13103 // Common date-resetting loop -- if date is beyond end of month, make it
13106 new_date.setUTCDate(--day);
13107 new_date.setUTCMonth(new_month);
13112 moveYear: function(date, dir){
13113 return this.moveMonth(date, dir*12);
13116 dateWithinRange: function(date){
13117 return date >= this.startDate && date <= this.endDate;
13121 remove: function() {
13122 this.picker().remove();
13127 Roo.apply(Roo.bootstrap.DateField, {
13138 html: '<i class="icon-arrow-left"/>'
13148 html: '<i class="icon-arrow-right"/>'
13190 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13191 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13192 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13193 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13194 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13207 navFnc: 'FullYear',
13212 navFnc: 'FullYear',
13217 Roo.apply(Roo.bootstrap.DateField, {
13221 cls: 'datepicker dropdown-menu',
13225 cls: 'datepicker-days',
13229 cls: 'table-condensed',
13231 Roo.bootstrap.DateField.head,
13235 Roo.bootstrap.DateField.footer
13242 cls: 'datepicker-months',
13246 cls: 'table-condensed',
13248 Roo.bootstrap.DateField.head,
13249 Roo.bootstrap.DateField.content,
13250 Roo.bootstrap.DateField.footer
13257 cls: 'datepicker-years',
13261 cls: 'table-condensed',
13263 Roo.bootstrap.DateField.head,
13264 Roo.bootstrap.DateField.content,
13265 Roo.bootstrap.DateField.footer
13284 * @class Roo.bootstrap.TimeField
13285 * @extends Roo.bootstrap.Input
13286 * Bootstrap DateField class
13290 * Create a new TimeField
13291 * @param {Object} config The config object
13294 Roo.bootstrap.TimeField = function(config){
13295 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13299 * Fires when this field show.
13300 * @param {Roo.bootstrap.DateField} this
13301 * @param {Mixed} date The date value
13306 * Fires when this field hide.
13307 * @param {Roo.bootstrap.DateField} this
13308 * @param {Mixed} date The date value
13313 * Fires when select a date.
13314 * @param {Roo.bootstrap.DateField} this
13315 * @param {Mixed} date The date value
13321 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13324 * @cfg {String} format
13325 * The default time format string which can be overriden for localization support. The format must be
13326 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13330 onRender: function(ct, position)
13333 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13335 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13337 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13339 this.pop = this.picker().select('>.datepicker-time',true).first();
13340 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13342 this.picker().on('mousedown', this.onMousedown, this);
13343 this.picker().on('click', this.onClick, this);
13345 this.picker().addClass('datepicker-dropdown');
13350 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13351 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13352 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13353 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13354 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13355 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13359 fireKey: function(e){
13360 if (!this.picker().isVisible()){
13361 if (e.keyCode == 27) // allow escape to hide and re-show picker
13366 e.preventDefault();
13374 this.onTogglePeriod();
13377 this.onIncrementMinutes();
13380 this.onDecrementMinutes();
13389 onClick: function(e) {
13390 e.stopPropagation();
13391 e.preventDefault();
13394 picker : function()
13396 return this.el.select('.datepicker', true).first();
13399 fillTime: function()
13401 var time = this.pop.select('tbody', true).first();
13403 time.dom.innerHTML = '';
13418 cls: 'hours-up glyphicon glyphicon-chevron-up'
13438 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13459 cls: 'timepicker-hour',
13474 cls: 'timepicker-minute',
13489 cls: 'btn btn-primary period',
13511 cls: 'hours-down glyphicon glyphicon-chevron-down'
13531 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13549 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13556 var hours = this.time.getHours();
13557 var minutes = this.time.getMinutes();
13570 hours = hours - 12;
13574 hours = '0' + hours;
13578 minutes = '0' + minutes;
13581 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13582 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13583 this.pop.select('button', true).first().dom.innerHTML = period;
13589 this.picker().removeClass(['bottom', 'top']);
13591 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13593 * place to the top of element!
13597 this.picker().addClass('top');
13598 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13603 this.picker().addClass('bottom');
13605 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13608 onFocus : function()
13610 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13614 onBlur : function()
13616 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13622 this.picker().show();
13627 this.fireEvent('show', this, this.date);
13632 this.picker().hide();
13635 this.fireEvent('hide', this, this.date);
13638 setTime : function()
13641 this.setValue(this.time.format(this.format));
13643 this.fireEvent('select', this, this.date);
13648 onMousedown: function(e){
13649 e.stopPropagation();
13650 e.preventDefault();
13653 onIncrementHours: function()
13655 Roo.log('onIncrementHours');
13656 this.time = this.time.add(Date.HOUR, 1);
13661 onDecrementHours: function()
13663 Roo.log('onDecrementHours');
13664 this.time = this.time.add(Date.HOUR, -1);
13668 onIncrementMinutes: function()
13670 Roo.log('onIncrementMinutes');
13671 this.time = this.time.add(Date.MINUTE, 1);
13675 onDecrementMinutes: function()
13677 Roo.log('onDecrementMinutes');
13678 this.time = this.time.add(Date.MINUTE, -1);
13682 onTogglePeriod: function()
13684 Roo.log('onTogglePeriod');
13685 this.time = this.time.add(Date.HOUR, 12);
13692 Roo.apply(Roo.bootstrap.TimeField, {
13722 cls: 'btn btn-info ok',
13734 Roo.apply(Roo.bootstrap.TimeField, {
13738 cls: 'datepicker dropdown-menu',
13742 cls: 'datepicker-time',
13746 cls: 'table-condensed',
13748 Roo.bootstrap.TimeField.content,
13749 Roo.bootstrap.TimeField.footer
13768 * @class Roo.bootstrap.CheckBox
13769 * @extends Roo.bootstrap.Input
13770 * Bootstrap CheckBox class
13772 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13773 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13774 * @cfg {String} boxLabel The text that appears beside the checkbox
13775 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13776 * @cfg {Boolean} checked initnal the element
13780 * Create a new CheckBox
13781 * @param {Object} config The config object
13784 Roo.bootstrap.CheckBox = function(config){
13785 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13790 * Fires when the element is checked or unchecked.
13791 * @param {Roo.bootstrap.CheckBox} this This input
13792 * @param {Boolean} checked The new checked value
13798 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13800 inputType: 'checkbox',
13807 getAutoCreate : function()
13809 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13815 cfg.cls = 'form-group checkbox' //input-group
13823 type : this.inputType,
13824 value : (!this.checked) ? this.valueOff : this.inputValue,
13825 cls : 'roo-checkbox', //'form-box',
13826 placeholder : this.placeholder || ''
13830 if (this.weight) { // Validity check?
13831 cfg.cls += " checkbox-" + this.weight;
13834 if (this.disabled) {
13835 input.disabled=true;
13839 input.checked = this.checked;
13843 input.name = this.name;
13847 input.cls += ' input-' + this.size;
13851 ['xs','sm','md','lg'].map(function(size){
13852 if (settings[size]) {
13853 cfg.cls += ' col-' + size + '-' + settings[size];
13859 var inputblock = input;
13864 if (this.before || this.after) {
13867 cls : 'input-group',
13871 inputblock.cn.push({
13873 cls : 'input-group-addon',
13877 inputblock.cn.push(input);
13879 inputblock.cn.push({
13881 cls : 'input-group-addon',
13888 if (align ==='left' && this.fieldLabel.length) {
13889 Roo.log("left and has label");
13895 cls : 'control-label col-md-' + this.labelWidth,
13896 html : this.fieldLabel
13900 cls : "col-md-" + (12 - this.labelWidth),
13907 } else if ( this.fieldLabel.length) {
13912 tag: this.boxLabel ? 'span' : 'label',
13914 cls: 'control-label box-input-label',
13915 //cls : 'input-group-addon',
13916 html : this.fieldLabel
13926 Roo.log(" no label && no align");
13927 cfg.cn = [ inputblock ] ;
13936 html: this.boxLabel
13948 * return the real input element.
13950 inputEl: function ()
13952 return this.el.select('input.roo-checkbox',true).first();
13957 return this.el.select('label.control-label',true).first();
13960 initEvents : function()
13962 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13964 this.inputEl().on('click', this.onClick, this);
13968 onClick : function()
13970 this.setChecked(!this.checked);
13973 setChecked : function(state,suppressEvent)
13975 this.checked = state;
13977 this.inputEl().dom.checked = state;
13979 if(suppressEvent !== true){
13980 this.fireEvent('check', this, state);
13983 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13987 setValue : function(v,suppressEvent)
13989 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14003 * @class Roo.bootstrap.Radio
14004 * @extends Roo.bootstrap.CheckBox
14005 * Bootstrap Radio class
14008 * Create a new Radio
14009 * @param {Object} config The config object
14012 Roo.bootstrap.Radio = function(config){
14013 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14017 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14019 inputType: 'radio',
14023 getAutoCreate : function()
14025 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14031 cfg.cls = 'form-group radio' //input-group
14036 type : this.inputType,
14037 value : (!this.checked) ? this.valueOff : this.inputValue,
14039 placeholder : this.placeholder || ''
14042 if (this.weight) { // Validity check?
14043 cfg.cls += " radio-" + this.weight;
14045 if (this.disabled) {
14046 input.disabled=true;
14050 input.checked = this.checked;
14054 input.name = this.name;
14058 input.cls += ' input-' + this.size;
14062 ['xs','sm','md','lg'].map(function(size){
14063 if (settings[size]) {
14064 cfg.cls += ' col-' + size + '-' + settings[size];
14068 var inputblock = input;
14070 if (this.before || this.after) {
14073 cls : 'input-group',
14077 inputblock.cn.push({
14079 cls : 'input-group-addon',
14083 inputblock.cn.push(input);
14085 inputblock.cn.push({
14087 cls : 'input-group-addon',
14094 if (align ==='left' && this.fieldLabel.length) {
14095 Roo.log("left and has label");
14101 cls : 'control-label col-md-' + this.labelWidth,
14102 html : this.fieldLabel
14106 cls : "col-md-" + (12 - this.labelWidth),
14113 } else if ( this.fieldLabel.length) {
14120 cls: 'control-label box-input-label',
14121 //cls : 'input-group-addon',
14122 html : this.fieldLabel
14132 Roo.log(" no label && no align");
14147 html: this.boxLabel
14154 inputEl: function ()
14156 return this.el.select('input.roo-radio',true).first();
14158 onClick : function()
14160 this.setChecked(true);
14163 setChecked : function(state,suppressEvent)
14166 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14167 v.dom.checked = false;
14171 this.checked = state;
14172 this.inputEl().dom.checked = state;
14174 if(suppressEvent !== true){
14175 this.fireEvent('check', this, state);
14178 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14182 getGroupValue : function()
14185 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14186 if(v.dom.checked == true){
14187 value = v.dom.value;
14195 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14196 * @return {Mixed} value The field value
14198 getValue : function(){
14199 return this.getGroupValue();
14205 //<script type="text/javascript">
14208 * Based Ext JS Library 1.1.1
14209 * Copyright(c) 2006-2007, Ext JS, LLC.
14215 * @class Roo.HtmlEditorCore
14216 * @extends Roo.Component
14217 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14219 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14222 Roo.HtmlEditorCore = function(config){
14225 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14228 * @event initialize
14229 * Fires when the editor is fully initialized (including the iframe)
14230 * @param {Roo.HtmlEditorCore} this
14235 * Fires when the editor is first receives the focus. Any insertion must wait
14236 * until after this event.
14237 * @param {Roo.HtmlEditorCore} this
14241 * @event beforesync
14242 * Fires before the textarea is updated with content from the editor iframe. Return false
14243 * to cancel the sync.
14244 * @param {Roo.HtmlEditorCore} this
14245 * @param {String} html
14249 * @event beforepush
14250 * Fires before the iframe editor is updated with content from the textarea. Return false
14251 * to cancel the push.
14252 * @param {Roo.HtmlEditorCore} this
14253 * @param {String} html
14258 * Fires when the textarea is updated with content from the editor iframe.
14259 * @param {Roo.HtmlEditorCore} this
14260 * @param {String} html
14265 * Fires when the iframe editor is updated with content from the textarea.
14266 * @param {Roo.HtmlEditorCore} this
14267 * @param {String} html
14272 * @event editorevent
14273 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14274 * @param {Roo.HtmlEditorCore} this
14282 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14286 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14292 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14297 * @cfg {Number} height (in pixels)
14301 * @cfg {Number} width (in pixels)
14306 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14309 stylesheets: false,
14314 // private properties
14315 validationEvent : false,
14317 initialized : false,
14319 sourceEditMode : false,
14320 onFocus : Roo.emptyFn,
14322 hideMode:'offsets',
14330 * Protected method that will not generally be called directly. It
14331 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14332 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14334 getDocMarkup : function(){
14337 Roo.log(this.stylesheets);
14339 // inherit styels from page...??
14340 if (this.stylesheets === false) {
14342 Roo.get(document.head).select('style').each(function(node) {
14343 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14346 Roo.get(document.head).select('link').each(function(node) {
14347 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14350 } else if (!this.stylesheets.length) {
14352 st = '<style type="text/css">' +
14353 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14356 Roo.each(this.stylesheets, function(s) {
14357 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14362 st += '<style type="text/css">' +
14363 'IMG { cursor: pointer } ' +
14367 return '<html><head>' + st +
14368 //<style type="text/css">' +
14369 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14371 ' </head><body class="roo-htmleditor-body"></body></html>';
14375 onRender : function(ct, position)
14378 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14379 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14382 this.el.dom.style.border = '0 none';
14383 this.el.dom.setAttribute('tabIndex', -1);
14384 this.el.addClass('x-hidden hide');
14388 if(Roo.isIE){ // fix IE 1px bogus margin
14389 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14393 this.frameId = Roo.id();
14397 var iframe = this.owner.wrap.createChild({
14399 cls: 'form-control', // bootstrap..
14401 name: this.frameId,
14402 frameBorder : 'no',
14403 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14408 this.iframe = iframe.dom;
14410 this.assignDocWin();
14412 this.doc.designMode = 'on';
14415 this.doc.write(this.getDocMarkup());
14419 var task = { // must defer to wait for browser to be ready
14421 //console.log("run task?" + this.doc.readyState);
14422 this.assignDocWin();
14423 if(this.doc.body || this.doc.readyState == 'complete'){
14425 this.doc.designMode="on";
14429 Roo.TaskMgr.stop(task);
14430 this.initEditor.defer(10, this);
14437 Roo.TaskMgr.start(task);
14444 onResize : function(w, h)
14446 Roo.log('resize: ' +w + ',' + h );
14447 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14451 if(typeof w == 'number'){
14453 this.iframe.style.width = w + 'px';
14455 if(typeof h == 'number'){
14457 this.iframe.style.height = h + 'px';
14459 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14466 * Toggles the editor between standard and source edit mode.
14467 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14469 toggleSourceEdit : function(sourceEditMode){
14471 this.sourceEditMode = sourceEditMode === true;
14473 if(this.sourceEditMode){
14475 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14478 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14479 //this.iframe.className = '';
14482 //this.setSize(this.owner.wrap.getSize());
14483 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14490 * Protected method that will not generally be called directly. If you need/want
14491 * custom HTML cleanup, this is the method you should override.
14492 * @param {String} html The HTML to be cleaned
14493 * return {String} The cleaned HTML
14495 cleanHtml : function(html){
14496 html = String(html);
14497 if(html.length > 5){
14498 if(Roo.isSafari){ // strip safari nonsense
14499 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14502 if(html == ' '){
14509 * HTML Editor -> Textarea
14510 * Protected method that will not generally be called directly. Syncs the contents
14511 * of the editor iframe with the textarea.
14513 syncValue : function(){
14514 if(this.initialized){
14515 var bd = (this.doc.body || this.doc.documentElement);
14516 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14517 var html = bd.innerHTML;
14519 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14520 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14522 html = '<div style="'+m[0]+'">' + html + '</div>';
14525 html = this.cleanHtml(html);
14526 // fix up the special chars.. normaly like back quotes in word...
14527 // however we do not want to do this with chinese..
14528 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14529 var cc = b.charCodeAt();
14531 (cc >= 0x4E00 && cc < 0xA000 ) ||
14532 (cc >= 0x3400 && cc < 0x4E00 ) ||
14533 (cc >= 0xf900 && cc < 0xfb00 )
14539 if(this.owner.fireEvent('beforesync', this, html) !== false){
14540 this.el.dom.value = html;
14541 this.owner.fireEvent('sync', this, html);
14547 * Protected method that will not generally be called directly. Pushes the value of the textarea
14548 * into the iframe editor.
14550 pushValue : function(){
14551 if(this.initialized){
14552 var v = this.el.dom.value.trim();
14554 // if(v.length < 1){
14558 if(this.owner.fireEvent('beforepush', this, v) !== false){
14559 var d = (this.doc.body || this.doc.documentElement);
14561 this.cleanUpPaste();
14562 this.el.dom.value = d.innerHTML;
14563 this.owner.fireEvent('push', this, v);
14569 deferFocus : function(){
14570 this.focus.defer(10, this);
14574 focus : function(){
14575 if(this.win && !this.sourceEditMode){
14582 assignDocWin: function()
14584 var iframe = this.iframe;
14587 this.doc = iframe.contentWindow.document;
14588 this.win = iframe.contentWindow;
14590 if (!Roo.get(this.frameId)) {
14593 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14594 this.win = Roo.get(this.frameId).dom.contentWindow;
14599 initEditor : function(){
14600 //console.log("INIT EDITOR");
14601 this.assignDocWin();
14605 this.doc.designMode="on";
14607 this.doc.write(this.getDocMarkup());
14610 var dbody = (this.doc.body || this.doc.documentElement);
14611 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14612 // this copies styles from the containing element into thsi one..
14613 // not sure why we need all of this..
14614 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14616 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
14617 //ss['background-attachment'] = 'fixed'; // w3c
14618 dbody.bgProperties = 'fixed'; // ie
14619 //Roo.DomHelper.applyStyles(dbody, ss);
14620 Roo.EventManager.on(this.doc, {
14621 //'mousedown': this.onEditorEvent,
14622 'mouseup': this.onEditorEvent,
14623 'dblclick': this.onEditorEvent,
14624 'click': this.onEditorEvent,
14625 'keyup': this.onEditorEvent,
14630 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14632 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14633 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14635 this.initialized = true;
14637 this.owner.fireEvent('initialize', this);
14642 onDestroy : function(){
14648 //for (var i =0; i < this.toolbars.length;i++) {
14649 // // fixme - ask toolbars for heights?
14650 // this.toolbars[i].onDestroy();
14653 //this.wrap.dom.innerHTML = '';
14654 //this.wrap.remove();
14659 onFirstFocus : function(){
14661 this.assignDocWin();
14664 this.activated = true;
14667 if(Roo.isGecko){ // prevent silly gecko errors
14669 var s = this.win.getSelection();
14670 if(!s.focusNode || s.focusNode.nodeType != 3){
14671 var r = s.getRangeAt(0);
14672 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14677 this.execCmd('useCSS', true);
14678 this.execCmd('styleWithCSS', false);
14681 this.owner.fireEvent('activate', this);
14685 adjustFont: function(btn){
14686 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14687 //if(Roo.isSafari){ // safari
14690 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14691 if(Roo.isSafari){ // safari
14692 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14693 v = (v < 10) ? 10 : v;
14694 v = (v > 48) ? 48 : v;
14695 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14700 v = Math.max(1, v+adjust);
14702 this.execCmd('FontSize', v );
14705 onEditorEvent : function(e){
14706 this.owner.fireEvent('editorevent', this, e);
14707 // this.updateToolbar();
14708 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14711 insertTag : function(tg)
14713 // could be a bit smarter... -> wrap the current selected tRoo..
14714 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14716 range = this.createRange(this.getSelection());
14717 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14718 wrappingNode.appendChild(range.extractContents());
14719 range.insertNode(wrappingNode);
14726 this.execCmd("formatblock", tg);
14730 insertText : function(txt)
14734 var range = this.createRange();
14735 range.deleteContents();
14736 //alert(Sender.getAttribute('label'));
14738 range.insertNode(this.doc.createTextNode(txt));
14744 * Executes a Midas editor command on the editor document and performs necessary focus and
14745 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14746 * @param {String} cmd The Midas command
14747 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14749 relayCmd : function(cmd, value){
14751 this.execCmd(cmd, value);
14752 this.owner.fireEvent('editorevent', this);
14753 //this.updateToolbar();
14754 this.owner.deferFocus();
14758 * Executes a Midas editor command directly on the editor document.
14759 * For visual commands, you should use {@link #relayCmd} instead.
14760 * <b>This should only be called after the editor is initialized.</b>
14761 * @param {String} cmd The Midas command
14762 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14764 execCmd : function(cmd, value){
14765 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14772 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14774 * @param {String} text | dom node..
14776 insertAtCursor : function(text)
14781 if(!this.activated){
14787 var r = this.doc.selection.createRange();
14798 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14802 // from jquery ui (MIT licenced)
14804 var win = this.win;
14806 if (win.getSelection && win.getSelection().getRangeAt) {
14807 range = win.getSelection().getRangeAt(0);
14808 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14809 range.insertNode(node);
14810 } else if (win.document.selection && win.document.selection.createRange) {
14811 // no firefox support
14812 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14813 win.document.selection.createRange().pasteHTML(txt);
14815 // no firefox support
14816 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14817 this.execCmd('InsertHTML', txt);
14826 mozKeyPress : function(e){
14828 var c = e.getCharCode(), cmd;
14831 c = String.fromCharCode(c).toLowerCase();
14845 this.cleanUpPaste.defer(100, this);
14853 e.preventDefault();
14861 fixKeys : function(){ // load time branching for fastest keydown performance
14863 return function(e){
14864 var k = e.getKey(), r;
14867 r = this.doc.selection.createRange();
14870 r.pasteHTML('    ');
14877 r = this.doc.selection.createRange();
14879 var target = r.parentElement();
14880 if(!target || target.tagName.toLowerCase() != 'li'){
14882 r.pasteHTML('<br />');
14888 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14889 this.cleanUpPaste.defer(100, this);
14895 }else if(Roo.isOpera){
14896 return function(e){
14897 var k = e.getKey();
14901 this.execCmd('InsertHTML','    ');
14904 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14905 this.cleanUpPaste.defer(100, this);
14910 }else if(Roo.isSafari){
14911 return function(e){
14912 var k = e.getKey();
14916 this.execCmd('InsertText','\t');
14920 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14921 this.cleanUpPaste.defer(100, this);
14929 getAllAncestors: function()
14931 var p = this.getSelectedNode();
14934 a.push(p); // push blank onto stack..
14935 p = this.getParentElement();
14939 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14943 a.push(this.doc.body);
14947 lastSelNode : false,
14950 getSelection : function()
14952 this.assignDocWin();
14953 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14956 getSelectedNode: function()
14958 // this may only work on Gecko!!!
14960 // should we cache this!!!!
14965 var range = this.createRange(this.getSelection()).cloneRange();
14968 var parent = range.parentElement();
14970 var testRange = range.duplicate();
14971 testRange.moveToElementText(parent);
14972 if (testRange.inRange(range)) {
14975 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14978 parent = parent.parentElement;
14983 // is ancestor a text element.
14984 var ac = range.commonAncestorContainer;
14985 if (ac.nodeType == 3) {
14986 ac = ac.parentNode;
14989 var ar = ac.childNodes;
14992 var other_nodes = [];
14993 var has_other_nodes = false;
14994 for (var i=0;i<ar.length;i++) {
14995 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14998 // fullly contained node.
15000 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15005 // probably selected..
15006 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15007 other_nodes.push(ar[i]);
15011 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15016 has_other_nodes = true;
15018 if (!nodes.length && other_nodes.length) {
15019 nodes= other_nodes;
15021 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15027 createRange: function(sel)
15029 // this has strange effects when using with
15030 // top toolbar - not sure if it's a great idea.
15031 //this.editor.contentWindow.focus();
15032 if (typeof sel != "undefined") {
15034 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15036 return this.doc.createRange();
15039 return this.doc.createRange();
15042 getParentElement: function()
15045 this.assignDocWin();
15046 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15048 var range = this.createRange(sel);
15051 var p = range.commonAncestorContainer;
15052 while (p.nodeType == 3) { // text node
15063 * Range intersection.. the hard stuff...
15067 * [ -- selected range --- ]
15071 * if end is before start or hits it. fail.
15072 * if start is after end or hits it fail.
15074 * if either hits (but other is outside. - then it's not
15080 // @see http://www.thismuchiknow.co.uk/?p=64.
15081 rangeIntersectsNode : function(range, node)
15083 var nodeRange = node.ownerDocument.createRange();
15085 nodeRange.selectNode(node);
15087 nodeRange.selectNodeContents(node);
15090 var rangeStartRange = range.cloneRange();
15091 rangeStartRange.collapse(true);
15093 var rangeEndRange = range.cloneRange();
15094 rangeEndRange.collapse(false);
15096 var nodeStartRange = nodeRange.cloneRange();
15097 nodeStartRange.collapse(true);
15099 var nodeEndRange = nodeRange.cloneRange();
15100 nodeEndRange.collapse(false);
15102 return rangeStartRange.compareBoundaryPoints(
15103 Range.START_TO_START, nodeEndRange) == -1 &&
15104 rangeEndRange.compareBoundaryPoints(
15105 Range.START_TO_START, nodeStartRange) == 1;
15109 rangeCompareNode : function(range, node)
15111 var nodeRange = node.ownerDocument.createRange();
15113 nodeRange.selectNode(node);
15115 nodeRange.selectNodeContents(node);
15119 range.collapse(true);
15121 nodeRange.collapse(true);
15123 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15124 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15126 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15128 var nodeIsBefore = ss == 1;
15129 var nodeIsAfter = ee == -1;
15131 if (nodeIsBefore && nodeIsAfter)
15133 if (!nodeIsBefore && nodeIsAfter)
15134 return 1; //right trailed.
15136 if (nodeIsBefore && !nodeIsAfter)
15137 return 2; // left trailed.
15142 // private? - in a new class?
15143 cleanUpPaste : function()
15145 // cleans up the whole document..
15146 Roo.log('cleanuppaste');
15148 this.cleanUpChildren(this.doc.body);
15149 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15150 if (clean != this.doc.body.innerHTML) {
15151 this.doc.body.innerHTML = clean;
15156 cleanWordChars : function(input) {// change the chars to hex code
15157 var he = Roo.HtmlEditorCore;
15159 var output = input;
15160 Roo.each(he.swapCodes, function(sw) {
15161 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15163 output = output.replace(swapper, sw[1]);
15170 cleanUpChildren : function (n)
15172 if (!n.childNodes.length) {
15175 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15176 this.cleanUpChild(n.childNodes[i]);
15183 cleanUpChild : function (node)
15186 //console.log(node);
15187 if (node.nodeName == "#text") {
15188 // clean up silly Windows -- stuff?
15191 if (node.nodeName == "#comment") {
15192 node.parentNode.removeChild(node);
15193 // clean up silly Windows -- stuff?
15197 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15199 node.parentNode.removeChild(node);
15204 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15206 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15207 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15209 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15210 // remove_keep_children = true;
15213 if (remove_keep_children) {
15214 this.cleanUpChildren(node);
15215 // inserts everything just before this node...
15216 while (node.childNodes.length) {
15217 var cn = node.childNodes[0];
15218 node.removeChild(cn);
15219 node.parentNode.insertBefore(cn, node);
15221 node.parentNode.removeChild(node);
15225 if (!node.attributes || !node.attributes.length) {
15226 this.cleanUpChildren(node);
15230 function cleanAttr(n,v)
15233 if (v.match(/^\./) || v.match(/^\//)) {
15236 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15239 if (v.match(/^#/)) {
15242 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15243 node.removeAttribute(n);
15247 function cleanStyle(n,v)
15249 if (v.match(/expression/)) { //XSS?? should we even bother..
15250 node.removeAttribute(n);
15253 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15254 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15257 var parts = v.split(/;/);
15260 Roo.each(parts, function(p) {
15261 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15265 var l = p.split(':').shift().replace(/\s+/g,'');
15266 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15268 if ( cblack.indexOf(l) > -1) {
15269 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15270 //node.removeAttribute(n);
15274 // only allow 'c whitelisted system attributes'
15275 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15276 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15277 //node.removeAttribute(n);
15287 if (clean.length) {
15288 node.setAttribute(n, clean.join(';'));
15290 node.removeAttribute(n);
15296 for (var i = node.attributes.length-1; i > -1 ; i--) {
15297 var a = node.attributes[i];
15300 if (a.name.toLowerCase().substr(0,2)=='on') {
15301 node.removeAttribute(a.name);
15304 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15305 node.removeAttribute(a.name);
15308 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15309 cleanAttr(a.name,a.value); // fixme..
15312 if (a.name == 'style') {
15313 cleanStyle(a.name,a.value);
15316 /// clean up MS crap..
15317 // tecnically this should be a list of valid class'es..
15320 if (a.name == 'class') {
15321 if (a.value.match(/^Mso/)) {
15322 node.className = '';
15325 if (a.value.match(/body/)) {
15326 node.className = '';
15337 this.cleanUpChildren(node);
15342 * Clean up MS wordisms...
15344 cleanWord : function(node)
15347 var cleanWordChildren = function()
15349 if (!node.childNodes.length) {
15352 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15353 _t.cleanWord(node.childNodes[i]);
15359 this.cleanWord(this.doc.body);
15362 if (node.nodeName == "#text") {
15363 // clean up silly Windows -- stuff?
15366 if (node.nodeName == "#comment") {
15367 node.parentNode.removeChild(node);
15368 // clean up silly Windows -- stuff?
15372 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15373 node.parentNode.removeChild(node);
15377 // remove - but keep children..
15378 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15379 while (node.childNodes.length) {
15380 var cn = node.childNodes[0];
15381 node.removeChild(cn);
15382 node.parentNode.insertBefore(cn, node);
15384 node.parentNode.removeChild(node);
15385 cleanWordChildren();
15389 if (node.className.length) {
15391 var cn = node.className.split(/\W+/);
15393 Roo.each(cn, function(cls) {
15394 if (cls.match(/Mso[a-zA-Z]+/)) {
15399 node.className = cna.length ? cna.join(' ') : '';
15401 node.removeAttribute("class");
15405 if (node.hasAttribute("lang")) {
15406 node.removeAttribute("lang");
15409 if (node.hasAttribute("style")) {
15411 var styles = node.getAttribute("style").split(";");
15413 Roo.each(styles, function(s) {
15414 if (!s.match(/:/)) {
15417 var kv = s.split(":");
15418 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15421 // what ever is left... we allow.
15424 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15425 if (!nstyle.length) {
15426 node.removeAttribute('style');
15430 cleanWordChildren();
15434 domToHTML : function(currentElement, depth, nopadtext) {
15436 depth = depth || 0;
15437 nopadtext = nopadtext || false;
15439 if (!currentElement) {
15440 return this.domToHTML(this.doc.body);
15443 //Roo.log(currentElement);
15445 var allText = false;
15446 var nodeName = currentElement.nodeName;
15447 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15449 if (nodeName == '#text') {
15450 return currentElement.nodeValue;
15455 if (nodeName != 'BODY') {
15458 // Prints the node tagName, such as <A>, <IMG>, etc
15461 for(i = 0; i < currentElement.attributes.length;i++) {
15463 var aname = currentElement.attributes.item(i).name;
15464 if (!currentElement.attributes.item(i).value.length) {
15467 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15470 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15479 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15482 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15487 // Traverse the tree
15489 var currentElementChild = currentElement.childNodes.item(i);
15490 var allText = true;
15491 var innerHTML = '';
15493 while (currentElementChild) {
15494 // Formatting code (indent the tree so it looks nice on the screen)
15495 var nopad = nopadtext;
15496 if (lastnode == 'SPAN') {
15500 if (currentElementChild.nodeName == '#text') {
15501 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15502 if (!nopad && toadd.length > 80) {
15503 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15505 innerHTML += toadd;
15508 currentElementChild = currentElement.childNodes.item(i);
15514 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15516 // Recursively traverse the tree structure of the child node
15517 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15518 lastnode = currentElementChild.nodeName;
15520 currentElementChild=currentElement.childNodes.item(i);
15526 // The remaining code is mostly for formatting the tree
15527 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15532 ret+= "</"+tagName+">";
15538 // hide stuff that is not compatible
15552 * @event specialkey
15556 * @cfg {String} fieldClass @hide
15559 * @cfg {String} focusClass @hide
15562 * @cfg {String} autoCreate @hide
15565 * @cfg {String} inputType @hide
15568 * @cfg {String} invalidClass @hide
15571 * @cfg {String} invalidText @hide
15574 * @cfg {String} msgFx @hide
15577 * @cfg {String} validateOnBlur @hide
15581 Roo.HtmlEditorCore.white = [
15582 'area', 'br', 'img', 'input', 'hr', 'wbr',
15584 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15585 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15586 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15587 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15588 'table', 'ul', 'xmp',
15590 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15593 'dir', 'menu', 'ol', 'ul', 'dl',
15599 Roo.HtmlEditorCore.black = [
15600 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15602 'base', 'basefont', 'bgsound', 'blink', 'body',
15603 'frame', 'frameset', 'head', 'html', 'ilayer',
15604 'iframe', 'layer', 'link', 'meta', 'object',
15605 'script', 'style' ,'title', 'xml' // clean later..
15607 Roo.HtmlEditorCore.clean = [
15608 'script', 'style', 'title', 'xml'
15610 Roo.HtmlEditorCore.remove = [
15615 Roo.HtmlEditorCore.ablack = [
15619 Roo.HtmlEditorCore.aclean = [
15620 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15624 Roo.HtmlEditorCore.pwhite= [
15625 'http', 'https', 'mailto'
15628 // white listed style attributes.
15629 Roo.HtmlEditorCore.cwhite= [
15630 // 'text-align', /// default is to allow most things..
15636 // black listed style attributes.
15637 Roo.HtmlEditorCore.cblack= [
15638 // 'font-size' -- this can be set by the project
15642 Roo.HtmlEditorCore.swapCodes =[
15661 * @class Roo.bootstrap.HtmlEditor
15662 * @extends Roo.bootstrap.TextArea
15663 * Bootstrap HtmlEditor class
15666 * Create a new HtmlEditor
15667 * @param {Object} config The config object
15670 Roo.bootstrap.HtmlEditor = function(config){
15671 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15672 if (!this.toolbars) {
15673 this.toolbars = [];
15675 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15678 * @event initialize
15679 * Fires when the editor is fully initialized (including the iframe)
15680 * @param {HtmlEditor} this
15685 * Fires when the editor is first receives the focus. Any insertion must wait
15686 * until after this event.
15687 * @param {HtmlEditor} this
15691 * @event beforesync
15692 * Fires before the textarea is updated with content from the editor iframe. Return false
15693 * to cancel the sync.
15694 * @param {HtmlEditor} this
15695 * @param {String} html
15699 * @event beforepush
15700 * Fires before the iframe editor is updated with content from the textarea. Return false
15701 * to cancel the push.
15702 * @param {HtmlEditor} this
15703 * @param {String} html
15708 * Fires when the textarea is updated with content from the editor iframe.
15709 * @param {HtmlEditor} this
15710 * @param {String} html
15715 * Fires when the iframe editor is updated with content from the textarea.
15716 * @param {HtmlEditor} this
15717 * @param {String} html
15721 * @event editmodechange
15722 * Fires when the editor switches edit modes
15723 * @param {HtmlEditor} this
15724 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15726 editmodechange: true,
15728 * @event editorevent
15729 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15730 * @param {HtmlEditor} this
15734 * @event firstfocus
15735 * Fires when on first focus - needed by toolbars..
15736 * @param {HtmlEditor} this
15741 * Auto save the htmlEditor value as a file into Events
15742 * @param {HtmlEditor} this
15746 * @event savedpreview
15747 * preview the saved version of htmlEditor
15748 * @param {HtmlEditor} this
15755 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15759 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15764 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15769 * @cfg {Number} height (in pixels)
15773 * @cfg {Number} width (in pixels)
15778 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15781 stylesheets: false,
15786 // private properties
15787 validationEvent : false,
15789 initialized : false,
15792 onFocus : Roo.emptyFn,
15794 hideMode:'offsets',
15797 tbContainer : false,
15799 toolbarContainer :function() {
15800 return this.wrap.select('.x-html-editor-tb',true).first();
15804 * Protected method that will not generally be called directly. It
15805 * is called when the editor creates its toolbar. Override this method if you need to
15806 * add custom toolbar buttons.
15807 * @param {HtmlEditor} editor
15809 createToolbar : function(){
15811 Roo.log("create toolbars");
15813 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
15814 this.toolbars[0].render(this.toolbarContainer());
15818 // if (!editor.toolbars || !editor.toolbars.length) {
15819 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15822 // for (var i =0 ; i < editor.toolbars.length;i++) {
15823 // editor.toolbars[i] = Roo.factory(
15824 // typeof(editor.toolbars[i]) == 'string' ?
15825 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15826 // Roo.bootstrap.HtmlEditor);
15827 // editor.toolbars[i].init(editor);
15833 onRender : function(ct, position)
15835 // Roo.log("Call onRender: " + this.xtype);
15837 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15839 this.wrap = this.inputEl().wrap({
15840 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15843 this.editorcore.onRender(ct, position);
15845 if (this.resizable) {
15846 this.resizeEl = new Roo.Resizable(this.wrap, {
15850 minHeight : this.height,
15851 height: this.height,
15852 handles : this.resizable,
15855 resize : function(r, w, h) {
15856 _t.onResize(w,h); // -something
15862 this.createToolbar(this);
15865 if(!this.width && this.resizable){
15866 this.setSize(this.wrap.getSize());
15868 if (this.resizeEl) {
15869 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15870 // should trigger onReize..
15876 onResize : function(w, h)
15878 Roo.log('resize: ' +w + ',' + h );
15879 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15883 if(this.inputEl() ){
15884 if(typeof w == 'number'){
15885 var aw = w - this.wrap.getFrameWidth('lr');
15886 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15889 if(typeof h == 'number'){
15890 var tbh = -11; // fixme it needs to tool bar size!
15891 for (var i =0; i < this.toolbars.length;i++) {
15892 // fixme - ask toolbars for heights?
15893 tbh += this.toolbars[i].el.getHeight();
15894 //if (this.toolbars[i].footer) {
15895 // tbh += this.toolbars[i].footer.el.getHeight();
15903 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15904 ah -= 5; // knock a few pixes off for look..
15905 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15909 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15910 this.editorcore.onResize(ew,eh);
15915 * Toggles the editor between standard and source edit mode.
15916 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15918 toggleSourceEdit : function(sourceEditMode)
15920 this.editorcore.toggleSourceEdit(sourceEditMode);
15922 if(this.editorcore.sourceEditMode){
15923 Roo.log('editor - showing textarea');
15926 // Roo.log(this.syncValue());
15928 this.inputEl().removeClass('hide');
15929 this.inputEl().dom.removeAttribute('tabIndex');
15930 this.inputEl().focus();
15932 Roo.log('editor - hiding textarea');
15934 // Roo.log(this.pushValue());
15937 this.inputEl().addClass('hide');
15938 this.inputEl().dom.setAttribute('tabIndex', -1);
15939 //this.deferFocus();
15942 if(this.resizable){
15943 this.setSize(this.wrap.getSize());
15946 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15949 // private (for BoxComponent)
15950 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15952 // private (for BoxComponent)
15953 getResizeEl : function(){
15957 // private (for BoxComponent)
15958 getPositionEl : function(){
15963 initEvents : function(){
15964 this.originalValue = this.getValue();
15968 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15971 // markInvalid : Roo.emptyFn,
15973 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15976 // clearInvalid : Roo.emptyFn,
15978 setValue : function(v){
15979 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15980 this.editorcore.pushValue();
15985 deferFocus : function(){
15986 this.focus.defer(10, this);
15990 focus : function(){
15991 this.editorcore.focus();
15997 onDestroy : function(){
16003 for (var i =0; i < this.toolbars.length;i++) {
16004 // fixme - ask toolbars for heights?
16005 this.toolbars[i].onDestroy();
16008 this.wrap.dom.innerHTML = '';
16009 this.wrap.remove();
16014 onFirstFocus : function(){
16015 //Roo.log("onFirstFocus");
16016 this.editorcore.onFirstFocus();
16017 for (var i =0; i < this.toolbars.length;i++) {
16018 this.toolbars[i].onFirstFocus();
16024 syncValue : function()
16026 this.editorcore.syncValue();
16029 pushValue : function()
16031 this.editorcore.pushValue();
16035 // hide stuff that is not compatible
16049 * @event specialkey
16053 * @cfg {String} fieldClass @hide
16056 * @cfg {String} focusClass @hide
16059 * @cfg {String} autoCreate @hide
16062 * @cfg {String} inputType @hide
16065 * @cfg {String} invalidClass @hide
16068 * @cfg {String} invalidText @hide
16071 * @cfg {String} msgFx @hide
16074 * @cfg {String} validateOnBlur @hide
16083 Roo.namespace('Roo.bootstrap.htmleditor');
16085 * @class Roo.bootstrap.HtmlEditorToolbar1
16090 new Roo.bootstrap.HtmlEditor({
16093 new Roo.bootstrap.HtmlEditorToolbar1({
16094 disable : { fonts: 1 , format: 1, ..., ... , ...],
16100 * @cfg {Object} disable List of elements to disable..
16101 * @cfg {Array} btns List of additional buttons.
16105 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16108 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16111 Roo.apply(this, config);
16113 // default disabled, based on 'good practice'..
16114 this.disable = this.disable || {};
16115 Roo.applyIf(this.disable, {
16118 specialElements : true
16120 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16122 this.editor = config.editor;
16123 this.editorcore = config.editor.editorcore;
16125 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16127 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16128 // dont call parent... till later.
16130 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16135 editorcore : false,
16140 "h1","h2","h3","h4","h5","h6",
16142 "abbr", "acronym", "address", "cite", "samp", "var",
16146 onRender : function(ct, position)
16148 // Roo.log("Call onRender: " + this.xtype);
16150 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16152 this.el.dom.style.marginBottom = '0';
16154 var editorcore = this.editorcore;
16155 var editor= this.editor;
16158 var btn = function(id,cmd , toggle, handler){
16160 var event = toggle ? 'toggle' : 'click';
16165 xns: Roo.bootstrap,
16168 enableToggle:toggle !== false,
16170 pressed : toggle ? false : null,
16173 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16174 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16183 xns: Roo.bootstrap,
16184 glyphicon : 'font',
16188 xns: Roo.bootstrap,
16192 Roo.each(this.formats, function(f) {
16193 style.menu.items.push({
16195 xns: Roo.bootstrap,
16196 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16201 editorcore.insertTag(this.tagname);
16208 children.push(style);
16211 btn('bold',false,true);
16212 btn('italic',false,true);
16213 btn('align-left', 'justifyleft',true);
16214 btn('align-center', 'justifycenter',true);
16215 btn('align-right' , 'justifyright',true);
16216 btn('link', false, false, function(btn) {
16217 //Roo.log("create link?");
16218 var url = prompt(this.createLinkText, this.defaultLinkValue);
16219 if(url && url != 'http:/'+'/'){
16220 this.editorcore.relayCmd('createlink', url);
16223 btn('list','insertunorderedlist',true);
16224 btn('pencil', false,true, function(btn){
16227 this.toggleSourceEdit(btn.pressed);
16233 xns: Roo.bootstrap,
16238 xns: Roo.bootstrap,
16243 cog.menu.items.push({
16245 xns: Roo.bootstrap,
16246 html : Clean styles,
16251 editorcore.insertTag(this.tagname);
16260 this.xtype = 'NavSimplebar';
16262 for(var i=0;i< children.length;i++) {
16264 this.buttons.add(this.addxtypeChild(children[i]));
16268 editor.on('editorevent', this.updateToolbar, this);
16270 onBtnClick : function(id)
16272 this.editorcore.relayCmd(id);
16273 this.editorcore.focus();
16277 * Protected method that will not generally be called directly. It triggers
16278 * a toolbar update by reading the markup state of the current selection in the editor.
16280 updateToolbar: function(){
16282 if(!this.editorcore.activated){
16283 this.editor.onFirstFocus(); // is this neeed?
16287 var btns = this.buttons;
16288 var doc = this.editorcore.doc;
16289 btns.get('bold').setActive(doc.queryCommandState('bold'));
16290 btns.get('italic').setActive(doc.queryCommandState('italic'));
16291 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16293 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16294 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16295 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16297 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16298 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16301 var ans = this.editorcore.getAllAncestors();
16302 if (this.formatCombo) {
16305 var store = this.formatCombo.store;
16306 this.formatCombo.setValue("");
16307 for (var i =0; i < ans.length;i++) {
16308 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16310 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16318 // hides menus... - so this cant be on a menu...
16319 Roo.bootstrap.MenuMgr.hideAll();
16321 Roo.bootstrap.MenuMgr.hideAll();
16322 //this.editorsyncValue();
16324 onFirstFocus: function() {
16325 this.buttons.each(function(item){
16329 toggleSourceEdit : function(sourceEditMode){
16332 if(sourceEditMode){
16333 Roo.log("disabling buttons");
16334 this.buttons.each( function(item){
16335 if(item.cmd != 'pencil'){
16341 Roo.log("enabling buttons");
16342 if(this.editorcore.initialized){
16343 this.buttons.each( function(item){
16349 Roo.log("calling toggole on editor");
16350 // tell the editor that it's been pressed..
16351 this.editor.toggleSourceEdit(sourceEditMode);
16361 * Ext JS Library 1.1.1
16362 * Copyright(c) 2006-2007, Ext JS, LLC.
16364 * Originally Released Under LGPL - original licence link has changed is not relivant.
16367 * <script type="text/javascript">
16372 * @class Roo.grid.ColumnModel
16373 * @extends Roo.util.Observable
16374 * This is the default implementation of a ColumnModel used by the Grid. It defines
16375 * the columns in the grid.
16378 var colModel = new Roo.grid.ColumnModel([
16379 {header: "Ticker", width: 60, sortable: true, locked: true},
16380 {header: "Company Name", width: 150, sortable: true},
16381 {header: "Market Cap.", width: 100, sortable: true},
16382 {header: "$ Sales", width: 100, sortable: true, renderer: money},
16383 {header: "Employees", width: 100, sortable: true, resizable: false}
16388 * The config options listed for this class are options which may appear in each
16389 * individual column definition.
16390 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
16392 * @param {Object} config An Array of column config objects. See this class's
16393 * config objects for details.
16395 Roo.grid.ColumnModel = function(config){
16397 * The config passed into the constructor
16399 this.config = config;
16402 // if no id, create one
16403 // if the column does not have a dataIndex mapping,
16404 // map it to the order it is in the config
16405 for(var i = 0, len = config.length; i < len; i++){
16407 if(typeof c.dataIndex == "undefined"){
16410 if(typeof c.renderer == "string"){
16411 c.renderer = Roo.util.Format[c.renderer];
16413 if(typeof c.id == "undefined"){
16416 if(c.editor && c.editor.xtype){
16417 c.editor = Roo.factory(c.editor, Roo.grid);
16419 if(c.editor && c.editor.isFormField){
16420 c.editor = new Roo.grid.GridEditor(c.editor);
16422 this.lookup[c.id] = c;
16426 * The width of columns which have no width specified (defaults to 100)
16429 this.defaultWidth = 100;
16432 * Default sortable of columns which have no sortable specified (defaults to false)
16435 this.defaultSortable = false;
16439 * @event widthchange
16440 * Fires when the width of a column changes.
16441 * @param {ColumnModel} this
16442 * @param {Number} columnIndex The column index
16443 * @param {Number} newWidth The new width
16445 "widthchange": true,
16447 * @event headerchange
16448 * Fires when the text of a header changes.
16449 * @param {ColumnModel} this
16450 * @param {Number} columnIndex The column index
16451 * @param {Number} newText The new header text
16453 "headerchange": true,
16455 * @event hiddenchange
16456 * Fires when a column is hidden or "unhidden".
16457 * @param {ColumnModel} this
16458 * @param {Number} columnIndex The column index
16459 * @param {Boolean} hidden true if hidden, false otherwise
16461 "hiddenchange": true,
16463 * @event columnmoved
16464 * Fires when a column is moved.
16465 * @param {ColumnModel} this
16466 * @param {Number} oldIndex
16467 * @param {Number} newIndex
16469 "columnmoved" : true,
16471 * @event columlockchange
16472 * Fires when a column's locked state is changed
16473 * @param {ColumnModel} this
16474 * @param {Number} colIndex
16475 * @param {Boolean} locked true if locked
16477 "columnlockchange" : true
16479 Roo.grid.ColumnModel.superclass.constructor.call(this);
16481 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
16483 * @cfg {String} header The header text to display in the Grid view.
16486 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16487 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16488 * specified, the column's index is used as an index into the Record's data Array.
16491 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16492 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16495 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16496 * Defaults to the value of the {@link #defaultSortable} property.
16497 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16500 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16503 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16506 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16509 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16512 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16513 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16514 * default renderer uses the raw data value.
16517 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
16520 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16524 * Returns the id of the column at the specified index.
16525 * @param {Number} index The column index
16526 * @return {String} the id
16528 getColumnId : function(index){
16529 return this.config[index].id;
16533 * Returns the column for a specified id.
16534 * @param {String} id The column id
16535 * @return {Object} the column
16537 getColumnById : function(id){
16538 return this.lookup[id];
16543 * Returns the column for a specified dataIndex.
16544 * @param {String} dataIndex The column dataIndex
16545 * @return {Object|Boolean} the column or false if not found
16547 getColumnByDataIndex: function(dataIndex){
16548 var index = this.findColumnIndex(dataIndex);
16549 return index > -1 ? this.config[index] : false;
16553 * Returns the index for a specified column id.
16554 * @param {String} id The column id
16555 * @return {Number} the index, or -1 if not found
16557 getIndexById : function(id){
16558 for(var i = 0, len = this.config.length; i < len; i++){
16559 if(this.config[i].id == id){
16567 * Returns the index for a specified column dataIndex.
16568 * @param {String} dataIndex The column dataIndex
16569 * @return {Number} the index, or -1 if not found
16572 findColumnIndex : function(dataIndex){
16573 for(var i = 0, len = this.config.length; i < len; i++){
16574 if(this.config[i].dataIndex == dataIndex){
16582 moveColumn : function(oldIndex, newIndex){
16583 var c = this.config[oldIndex];
16584 this.config.splice(oldIndex, 1);
16585 this.config.splice(newIndex, 0, c);
16586 this.dataMap = null;
16587 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16590 isLocked : function(colIndex){
16591 return this.config[colIndex].locked === true;
16594 setLocked : function(colIndex, value, suppressEvent){
16595 if(this.isLocked(colIndex) == value){
16598 this.config[colIndex].locked = value;
16599 if(!suppressEvent){
16600 this.fireEvent("columnlockchange", this, colIndex, value);
16604 getTotalLockedWidth : function(){
16605 var totalWidth = 0;
16606 for(var i = 0; i < this.config.length; i++){
16607 if(this.isLocked(i) && !this.isHidden(i)){
16608 this.totalWidth += this.getColumnWidth(i);
16614 getLockedCount : function(){
16615 for(var i = 0, len = this.config.length; i < len; i++){
16616 if(!this.isLocked(i)){
16623 * Returns the number of columns.
16626 getColumnCount : function(visibleOnly){
16627 if(visibleOnly === true){
16629 for(var i = 0, len = this.config.length; i < len; i++){
16630 if(!this.isHidden(i)){
16636 return this.config.length;
16640 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16641 * @param {Function} fn
16642 * @param {Object} scope (optional)
16643 * @return {Array} result
16645 getColumnsBy : function(fn, scope){
16647 for(var i = 0, len = this.config.length; i < len; i++){
16648 var c = this.config[i];
16649 if(fn.call(scope||this, c, i) === true){
16657 * Returns true if the specified column is sortable.
16658 * @param {Number} col The column index
16659 * @return {Boolean}
16661 isSortable : function(col){
16662 if(typeof this.config[col].sortable == "undefined"){
16663 return this.defaultSortable;
16665 return this.config[col].sortable;
16669 * Returns the rendering (formatting) function defined for the column.
16670 * @param {Number} col The column index.
16671 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16673 getRenderer : function(col){
16674 if(!this.config[col].renderer){
16675 return Roo.grid.ColumnModel.defaultRenderer;
16677 return this.config[col].renderer;
16681 * Sets the rendering (formatting) function for a column.
16682 * @param {Number} col The column index
16683 * @param {Function} fn The function to use to process the cell's raw data
16684 * to return HTML markup for the grid view. The render function is called with
16685 * the following parameters:<ul>
16686 * <li>Data value.</li>
16687 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16688 * <li>css A CSS style string to apply to the table cell.</li>
16689 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16690 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16691 * <li>Row index</li>
16692 * <li>Column index</li>
16693 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16695 setRenderer : function(col, fn){
16696 this.config[col].renderer = fn;
16700 * Returns the width for the specified column.
16701 * @param {Number} col The column index
16704 getColumnWidth : function(col){
16705 return this.config[col].width * 1 || this.defaultWidth;
16709 * Sets the width for a column.
16710 * @param {Number} col The column index
16711 * @param {Number} width The new width
16713 setColumnWidth : function(col, width, suppressEvent){
16714 this.config[col].width = width;
16715 this.totalWidth = null;
16716 if(!suppressEvent){
16717 this.fireEvent("widthchange", this, col, width);
16722 * Returns the total width of all columns.
16723 * @param {Boolean} includeHidden True to include hidden column widths
16726 getTotalWidth : function(includeHidden){
16727 if(!this.totalWidth){
16728 this.totalWidth = 0;
16729 for(var i = 0, len = this.config.length; i < len; i++){
16730 if(includeHidden || !this.isHidden(i)){
16731 this.totalWidth += this.getColumnWidth(i);
16735 return this.totalWidth;
16739 * Returns the header for the specified column.
16740 * @param {Number} col The column index
16743 getColumnHeader : function(col){
16744 return this.config[col].header;
16748 * Sets the header for a column.
16749 * @param {Number} col The column index
16750 * @param {String} header The new header
16752 setColumnHeader : function(col, header){
16753 this.config[col].header = header;
16754 this.fireEvent("headerchange", this, col, header);
16758 * Returns the tooltip for the specified column.
16759 * @param {Number} col The column index
16762 getColumnTooltip : function(col){
16763 return this.config[col].tooltip;
16766 * Sets the tooltip for a column.
16767 * @param {Number} col The column index
16768 * @param {String} tooltip The new tooltip
16770 setColumnTooltip : function(col, tooltip){
16771 this.config[col].tooltip = tooltip;
16775 * Returns the dataIndex for the specified column.
16776 * @param {Number} col The column index
16779 getDataIndex : function(col){
16780 return this.config[col].dataIndex;
16784 * Sets the dataIndex for a column.
16785 * @param {Number} col The column index
16786 * @param {Number} dataIndex The new dataIndex
16788 setDataIndex : function(col, dataIndex){
16789 this.config[col].dataIndex = dataIndex;
16795 * Returns true if the cell is editable.
16796 * @param {Number} colIndex The column index
16797 * @param {Number} rowIndex The row index
16798 * @return {Boolean}
16800 isCellEditable : function(colIndex, rowIndex){
16801 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16805 * Returns the editor defined for the cell/column.
16806 * return false or null to disable editing.
16807 * @param {Number} colIndex The column index
16808 * @param {Number} rowIndex The row index
16811 getCellEditor : function(colIndex, rowIndex){
16812 return this.config[colIndex].editor;
16816 * Sets if a column is editable.
16817 * @param {Number} col The column index
16818 * @param {Boolean} editable True if the column is editable
16820 setEditable : function(col, editable){
16821 this.config[col].editable = editable;
16826 * Returns true if the column is hidden.
16827 * @param {Number} colIndex The column index
16828 * @return {Boolean}
16830 isHidden : function(colIndex){
16831 return this.config[colIndex].hidden;
16836 * Returns true if the column width cannot be changed
16838 isFixed : function(colIndex){
16839 return this.config[colIndex].fixed;
16843 * Returns true if the column can be resized
16844 * @return {Boolean}
16846 isResizable : function(colIndex){
16847 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16850 * Sets if a column is hidden.
16851 * @param {Number} colIndex The column index
16852 * @param {Boolean} hidden True if the column is hidden
16854 setHidden : function(colIndex, hidden){
16855 this.config[colIndex].hidden = hidden;
16856 this.totalWidth = null;
16857 this.fireEvent("hiddenchange", this, colIndex, hidden);
16861 * Sets the editor for a column.
16862 * @param {Number} col The column index
16863 * @param {Object} editor The editor object
16865 setEditor : function(col, editor){
16866 this.config[col].editor = editor;
16870 Roo.grid.ColumnModel.defaultRenderer = function(value){
16871 if(typeof value == "string" && value.length < 1){
16877 // Alias for backwards compatibility
16878 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
16881 * @class Roo.bootstrap.Table.AbstractSelectionModel
16882 * @extends Roo.util.Observable
16883 * Abstract base class for grid SelectionModels. It provides the interface that should be
16884 * implemented by descendant classes. This class should not be directly instantiated.
16887 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16888 this.locked = false;
16889 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16893 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16894 /** @ignore Called by the grid automatically. Do not call directly. */
16895 init : function(grid){
16901 * Locks the selections.
16904 this.locked = true;
16908 * Unlocks the selections.
16910 unlock : function(){
16911 this.locked = false;
16915 * Returns true if the selections are locked.
16916 * @return {Boolean}
16918 isLocked : function(){
16919 return this.locked;
16923 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16924 * @class Roo.bootstrap.Table.RowSelectionModel
16925 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16926 * It supports multiple selections and keyboard selection/navigation.
16928 * @param {Object} config
16931 Roo.bootstrap.Table.RowSelectionModel = function(config){
16932 Roo.apply(this, config);
16933 this.selections = new Roo.util.MixedCollection(false, function(o){
16938 this.lastActive = false;
16942 * @event selectionchange
16943 * Fires when the selection changes
16944 * @param {SelectionModel} this
16946 "selectionchange" : true,
16948 * @event afterselectionchange
16949 * Fires after the selection changes (eg. by key press or clicking)
16950 * @param {SelectionModel} this
16952 "afterselectionchange" : true,
16954 * @event beforerowselect
16955 * Fires when a row is selected being selected, return false to cancel.
16956 * @param {SelectionModel} this
16957 * @param {Number} rowIndex The selected index
16958 * @param {Boolean} keepExisting False if other selections will be cleared
16960 "beforerowselect" : true,
16963 * Fires when a row is selected.
16964 * @param {SelectionModel} this
16965 * @param {Number} rowIndex The selected index
16966 * @param {Roo.data.Record} r The record
16968 "rowselect" : true,
16970 * @event rowdeselect
16971 * Fires when a row is deselected.
16972 * @param {SelectionModel} this
16973 * @param {Number} rowIndex The selected index
16975 "rowdeselect" : true
16977 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16978 this.locked = false;
16981 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16983 * @cfg {Boolean} singleSelect
16984 * True to allow selection of only one row at a time (defaults to false)
16986 singleSelect : false,
16989 initEvents : function(){
16991 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16992 this.grid.on("mousedown", this.handleMouseDown, this);
16993 }else{ // allow click to work like normal
16994 this.grid.on("rowclick", this.handleDragableRowClick, this);
16997 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16998 "up" : function(e){
17000 this.selectPrevious(e.shiftKey);
17001 }else if(this.last !== false && this.lastActive !== false){
17002 var last = this.last;
17003 this.selectRange(this.last, this.lastActive-1);
17004 this.grid.getView().focusRow(this.lastActive);
17005 if(last !== false){
17009 this.selectFirstRow();
17011 this.fireEvent("afterselectionchange", this);
17013 "down" : function(e){
17015 this.selectNext(e.shiftKey);
17016 }else if(this.last !== false && this.lastActive !== false){
17017 var last = this.last;
17018 this.selectRange(this.last, this.lastActive+1);
17019 this.grid.getView().focusRow(this.lastActive);
17020 if(last !== false){
17024 this.selectFirstRow();
17026 this.fireEvent("afterselectionchange", this);
17031 var view = this.grid.view;
17032 view.on("refresh", this.onRefresh, this);
17033 view.on("rowupdated", this.onRowUpdated, this);
17034 view.on("rowremoved", this.onRemove, this);
17038 onRefresh : function(){
17039 var ds = this.grid.dataSource, i, v = this.grid.view;
17040 var s = this.selections;
17041 s.each(function(r){
17042 if((i = ds.indexOfId(r.id)) != -1){
17051 onRemove : function(v, index, r){
17052 this.selections.remove(r);
17056 onRowUpdated : function(v, index, r){
17057 if(this.isSelected(r)){
17058 v.onRowSelect(index);
17064 * @param {Array} records The records to select
17065 * @param {Boolean} keepExisting (optional) True to keep existing selections
17067 selectRecords : function(records, keepExisting){
17069 this.clearSelections();
17071 var ds = this.grid.dataSource;
17072 for(var i = 0, len = records.length; i < len; i++){
17073 this.selectRow(ds.indexOf(records[i]), true);
17078 * Gets the number of selected rows.
17081 getCount : function(){
17082 return this.selections.length;
17086 * Selects the first row in the grid.
17088 selectFirstRow : function(){
17093 * Select the last row.
17094 * @param {Boolean} keepExisting (optional) True to keep existing selections
17096 selectLastRow : function(keepExisting){
17097 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17101 * Selects the row immediately following the last selected row.
17102 * @param {Boolean} keepExisting (optional) True to keep existing selections
17104 selectNext : function(keepExisting){
17105 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17106 this.selectRow(this.last+1, keepExisting);
17107 this.grid.getView().focusRow(this.last);
17112 * Selects the row that precedes the last selected row.
17113 * @param {Boolean} keepExisting (optional) True to keep existing selections
17115 selectPrevious : function(keepExisting){
17117 this.selectRow(this.last-1, keepExisting);
17118 this.grid.getView().focusRow(this.last);
17123 * Returns the selected records
17124 * @return {Array} Array of selected records
17126 getSelections : function(){
17127 return [].concat(this.selections.items);
17131 * Returns the first selected record.
17134 getSelected : function(){
17135 return this.selections.itemAt(0);
17140 * Clears all selections.
17142 clearSelections : function(fast){
17143 if(this.locked) return;
17145 var ds = this.grid.dataSource;
17146 var s = this.selections;
17147 s.each(function(r){
17148 this.deselectRow(ds.indexOfId(r.id));
17152 this.selections.clear();
17159 * Selects all rows.
17161 selectAll : function(){
17162 if(this.locked) return;
17163 this.selections.clear();
17164 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17165 this.selectRow(i, true);
17170 * Returns True if there is a selection.
17171 * @return {Boolean}
17173 hasSelection : function(){
17174 return this.selections.length > 0;
17178 * Returns True if the specified row is selected.
17179 * @param {Number/Record} record The record or index of the record to check
17180 * @return {Boolean}
17182 isSelected : function(index){
17183 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17184 return (r && this.selections.key(r.id) ? true : false);
17188 * Returns True if the specified record id is selected.
17189 * @param {String} id The id of record to check
17190 * @return {Boolean}
17192 isIdSelected : function(id){
17193 return (this.selections.key(id) ? true : false);
17197 handleMouseDown : function(e, t){
17198 var view = this.grid.getView(), rowIndex;
17199 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17202 if(e.shiftKey && this.last !== false){
17203 var last = this.last;
17204 this.selectRange(last, rowIndex, e.ctrlKey);
17205 this.last = last; // reset the last
17206 view.focusRow(rowIndex);
17208 var isSelected = this.isSelected(rowIndex);
17209 if(e.button !== 0 && isSelected){
17210 view.focusRow(rowIndex);
17211 }else if(e.ctrlKey && isSelected){
17212 this.deselectRow(rowIndex);
17213 }else if(!isSelected){
17214 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17215 view.focusRow(rowIndex);
17218 this.fireEvent("afterselectionchange", this);
17221 handleDragableRowClick : function(grid, rowIndex, e)
17223 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17224 this.selectRow(rowIndex, false);
17225 grid.view.focusRow(rowIndex);
17226 this.fireEvent("afterselectionchange", this);
17231 * Selects multiple rows.
17232 * @param {Array} rows Array of the indexes of the row to select
17233 * @param {Boolean} keepExisting (optional) True to keep existing selections
17235 selectRows : function(rows, keepExisting){
17237 this.clearSelections();
17239 for(var i = 0, len = rows.length; i < len; i++){
17240 this.selectRow(rows[i], true);
17245 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17246 * @param {Number} startRow The index of the first row in the range
17247 * @param {Number} endRow The index of the last row in the range
17248 * @param {Boolean} keepExisting (optional) True to retain existing selections
17250 selectRange : function(startRow, endRow, keepExisting){
17251 if(this.locked) return;
17253 this.clearSelections();
17255 if(startRow <= endRow){
17256 for(var i = startRow; i <= endRow; i++){
17257 this.selectRow(i, true);
17260 for(var i = startRow; i >= endRow; i--){
17261 this.selectRow(i, true);
17267 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17268 * @param {Number} startRow The index of the first row in the range
17269 * @param {Number} endRow The index of the last row in the range
17271 deselectRange : function(startRow, endRow, preventViewNotify){
17272 if(this.locked) return;
17273 for(var i = startRow; i <= endRow; i++){
17274 this.deselectRow(i, preventViewNotify);
17280 * @param {Number} row The index of the row to select
17281 * @param {Boolean} keepExisting (optional) True to keep existing selections
17283 selectRow : function(index, keepExisting, preventViewNotify){
17284 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17285 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17286 if(!keepExisting || this.singleSelect){
17287 this.clearSelections();
17289 var r = this.grid.dataSource.getAt(index);
17290 this.selections.add(r);
17291 this.last = this.lastActive = index;
17292 if(!preventViewNotify){
17293 this.grid.getView().onRowSelect(index);
17295 this.fireEvent("rowselect", this, index, r);
17296 this.fireEvent("selectionchange", this);
17302 * @param {Number} row The index of the row to deselect
17304 deselectRow : function(index, preventViewNotify){
17305 if(this.locked) return;
17306 if(this.last == index){
17309 if(this.lastActive == index){
17310 this.lastActive = false;
17312 var r = this.grid.dataSource.getAt(index);
17313 this.selections.remove(r);
17314 if(!preventViewNotify){
17315 this.grid.getView().onRowDeselect(index);
17317 this.fireEvent("rowdeselect", this, index);
17318 this.fireEvent("selectionchange", this);
17322 restoreLast : function(){
17324 this.last = this._last;
17329 acceptsNav : function(row, col, cm){
17330 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17334 onEditorKey : function(field, e){
17335 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17340 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17342 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17344 }else if(k == e.ENTER && !e.ctrlKey){
17348 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17350 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17352 }else if(k == e.ESC){
17356 g.startEditing(newCell[0], newCell[1]);
17361 * Ext JS Library 1.1.1
17362 * Copyright(c) 2006-2007, Ext JS, LLC.
17364 * Originally Released Under LGPL - original licence link has changed is not relivant.
17367 * <script type="text/javascript">
17371 * @class Roo.bootstrap.PagingToolbar
17373 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17375 * Create a new PagingToolbar
17376 * @param {Object} config The config object
17378 Roo.bootstrap.PagingToolbar = function(config)
17380 // old args format still supported... - xtype is prefered..
17381 // created from xtype...
17382 var ds = config.dataSource;
17384 if (config.items) {
17385 items = config.items;
17389 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
17396 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
17398 // supprot items array.
17400 Roo.each(items, function(e) {
17401 this.add(Roo.factory(e));
17410 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
17412 * @cfg {Roo.data.Store} dataSource
17413 * The underlying data store providing the paged data
17416 * @cfg {String/HTMLElement/Element} container
17417 * container The id or element that will contain the toolbar
17420 * @cfg {Boolean} displayInfo
17421 * True to display the displayMsg (defaults to false)
17424 * @cfg {Number} pageSize
17425 * The number of records to display per page (defaults to 20)
17429 * @cfg {String} displayMsg
17430 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
17432 displayMsg : 'Displaying {0} - {1} of {2}',
17434 * @cfg {String} emptyMsg
17435 * The message to display when no records are found (defaults to "No data to display")
17437 emptyMsg : 'No data to display',
17439 * Customizable piece of the default paging text (defaults to "Page")
17442 beforePageText : "Page",
17444 * Customizable piece of the default paging text (defaults to "of %0")
17447 afterPageText : "of {0}",
17449 * Customizable piece of the default paging text (defaults to "First Page")
17452 firstText : "First Page",
17454 * Customizable piece of the default paging text (defaults to "Previous Page")
17457 prevText : "Previous Page",
17459 * Customizable piece of the default paging text (defaults to "Next Page")
17462 nextText : "Next Page",
17464 * Customizable piece of the default paging text (defaults to "Last Page")
17467 lastText : "Last Page",
17469 * Customizable piece of the default paging text (defaults to "Refresh")
17472 refreshText : "Refresh",
17475 onRender : function(ct, position)
17477 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
17478 this.navgroup.parentId = this.id;
17479 this.navgroup.onRender(this.el, null);
17480 // add the buttons to the navgroup
17482 this.first = this.navgroup.addItem({
17483 tooltip: this.firstText,
17485 icon : 'fa fa-backward',
17487 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
17490 this.prev = this.navgroup.addItem({
17491 tooltip: this.prevText,
17493 icon : 'fa fa-step-backward',
17495 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
17497 //this.addSeparator();
17500 var field = this.navgroup.addItem( {
17502 cls : 'x-paging-position',
17504 html : this.beforePageText +
17505 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
17506 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
17509 this.field = field.el.select('input', true).first();
17510 this.field.on("keydown", this.onPagingKeydown, this);
17511 this.field.on("focus", function(){this.dom.select();});
17514 this.afterTextEl = field.el.select('.x-paging-after').first();
17515 //this.field.setHeight(18);
17516 //this.addSeparator();
17517 this.next = this.navgroup.addItem({
17518 tooltip: this.nextText,
17520 html : ' <i class="fa fa-step-forward">',
17522 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
17524 this.last = this.navgroup.addItem({
17525 tooltip: this.lastText,
17526 icon : 'fa fa-forward',
17529 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
17531 //this.addSeparator();
17532 this.loading = this.navgroup.addItem({
17533 tooltip: this.refreshText,
17534 icon: 'fa fa-refresh',
17536 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
17539 if(this.displayInfo){
17540 var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info' } );
17541 this.displayEl = navel.el.select('a',true).first();
17547 updateInfo : function(){
17548 if(this.displayEl){
17549 var count = this.ds.getCount();
17550 var msg = count == 0 ?
17554 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
17556 this.displayEl.update(msg);
17561 onLoad : function(ds, r, o){
17562 this.cursor = o.params ? o.params.start : 0;
17563 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
17565 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
17566 this.field.dom.value = ap;
17567 this.first.setDisabled(ap == 1);
17568 this.prev.setDisabled(ap == 1);
17569 this.next.setDisabled(ap == ps);
17570 this.last.setDisabled(ap == ps);
17571 this.loading.enable();
17576 getPageData : function(){
17577 var total = this.ds.getTotalCount();
17580 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
17581 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
17586 onLoadError : function(){
17587 this.loading.enable();
17591 onPagingKeydown : function(e){
17592 var k = e.getKey();
17593 var d = this.getPageData();
17595 var v = this.field.dom.value, pageNum;
17596 if(!v || isNaN(pageNum = parseInt(v, 10))){
17597 this.field.dom.value = d.activePage;
17600 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
17601 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17604 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
17606 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
17607 this.field.dom.value = pageNum;
17608 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
17611 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17613 var v = this.field.dom.value, pageNum;
17614 var increment = (e.shiftKey) ? 10 : 1;
17615 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17617 if(!v || isNaN(pageNum = parseInt(v, 10))) {
17618 this.field.dom.value = d.activePage;
17621 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
17623 this.field.dom.value = parseInt(v, 10) + increment;
17624 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
17625 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17632 beforeLoad : function(){
17634 this.loading.disable();
17639 onClick : function(which){
17646 ds.load({params:{start: 0, limit: this.pageSize}});
17649 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
17652 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
17655 var total = ds.getTotalCount();
17656 var extra = total % this.pageSize;
17657 var lastStart = extra ? (total - extra) : total-this.pageSize;
17658 ds.load({params:{start: lastStart, limit: this.pageSize}});
17661 ds.load({params:{start: this.cursor, limit: this.pageSize}});
17667 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
17668 * @param {Roo.data.Store} store The data store to unbind
17670 unbind : function(ds){
17671 ds.un("beforeload", this.beforeLoad, this);
17672 ds.un("load", this.onLoad, this);
17673 ds.un("loadexception", this.onLoadError, this);
17674 ds.un("remove", this.updateInfo, this);
17675 ds.un("add", this.updateInfo, this);
17676 this.ds = undefined;
17680 * Binds the paging toolbar to the specified {@link Roo.data.Store}
17681 * @param {Roo.data.Store} store The data store to bind
17683 bind : function(ds){
17684 ds.on("beforeload", this.beforeLoad, this);
17685 ds.on("load", this.onLoad, this);
17686 ds.on("loadexception", this.onLoadError, this);
17687 ds.on("remove", this.updateInfo, this);
17688 ds.on("add", this.updateInfo, this);
17699 * @class Roo.bootstrap.MessageBar
17700 * @extends Roo.bootstrap.Component
17701 * Bootstrap MessageBar class
17702 * @cfg {String} html contents of the MessageBar
17703 * @cfg {String} weight (info | success | warning | danger) default info
17704 * @cfg {String} beforeClass insert the bar before the given class
17705 * @cfg {Boolean} closable (true | false) default false
17706 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17709 * Create a new Element
17710 * @param {Object} config The config object
17713 Roo.bootstrap.MessageBar = function(config){
17714 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17717 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17723 beforeClass: 'bootstrap-sticky-wrap',
17725 getAutoCreate : function(){
17729 cls: 'alert alert-dismissable alert-' + this.weight,
17734 html: this.html || ''
17740 cfg.cls += ' alert-messages-fixed';
17754 onRender : function(ct, position)
17756 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17759 var cfg = Roo.apply({}, this.getAutoCreate());
17763 cfg.cls += ' ' + this.cls;
17766 cfg.style = this.style;
17768 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17770 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17773 this.el.select('>button.close').on('click', this.hide, this);
17779 if (!this.rendered) {
17785 this.fireEvent('show', this);
17791 if (!this.rendered) {
17797 this.fireEvent('hide', this);
17800 update : function()
17802 // var e = this.el.dom.firstChild;
17804 // if(this.closable){
17805 // e = e.nextSibling;
17808 // e.data = this.html || '';
17810 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';