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();
2844 * @class Roo.bootstrap.NavSimplebar
2845 * @extends Roo.bootstrap.Navbar
2846 * Bootstrap Sidebar class
2848 * @cfg {Boolean} inverse is inverted color
2850 * @cfg {String} type (nav | pills | tabs)
2851 * @cfg {Boolean} arrangement stacked | justified
2852 * @cfg {String} align (left | right) alignment
2854 * @cfg {Boolean} main (true|false) main nav bar? default false
2855 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2857 * @cfg {String} tag (header|footer|nav|div) default is nav
2863 * Create a new Sidebar
2864 * @param {Object} config The config object
2868 Roo.bootstrap.NavSimplebar = function(config){
2869 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2872 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2888 getAutoCreate : function(){
2892 tag : this.tag || 'div',
2905 this.type = this.type || 'nav';
2906 if (['tabs','pills'].indexOf(this.type)!==-1) {
2907 cfg.cn[0].cls += ' nav-' + this.type
2911 if (this.type!=='nav') {
2912 Roo.log('nav type must be nav/tabs/pills')
2914 cfg.cn[0].cls += ' navbar-nav'
2920 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2921 cfg.cn[0].cls += ' nav-' + this.arrangement;
2925 if (this.align === 'right') {
2926 cfg.cn[0].cls += ' navbar-right';
2930 cfg.cls += ' navbar-inverse';
2957 * @class Roo.bootstrap.NavHeaderbar
2958 * @extends Roo.bootstrap.NavSimplebar
2959 * Bootstrap Sidebar class
2961 * @cfg {String} brand what is brand
2962 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2963 * @cfg {String} brand_href href of the brand
2966 * Create a new Sidebar
2967 * @param {Object} config The config object
2971 Roo.bootstrap.NavHeaderbar = function(config){
2972 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2975 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2982 getAutoCreate : function(){
2987 tag: this.nav || 'nav',
2993 cls: 'navbar-header',
2998 cls: 'navbar-toggle',
2999 'data-toggle': 'collapse',
3004 html: 'Toggle navigation'
3024 cls: 'collapse navbar-collapse'
3029 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3031 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3032 cfg.cls += ' navbar-' + this.position;
3034 // tag can override this..
3036 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3039 if (this.brand !== '') {
3042 href: this.brand_href ? this.brand_href : '#',
3043 cls: 'navbar-brand',
3051 cfg.cls += ' main-nav';
3076 * @class Roo.bootstrap.NavSidebar
3077 * @extends Roo.bootstrap.Navbar
3078 * Bootstrap Sidebar class
3081 * Create a new Sidebar
3082 * @param {Object} config The config object
3086 Roo.bootstrap.NavSidebar = function(config){
3087 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3090 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3092 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3094 getAutoCreate : function(){
3099 cls: 'sidebar sidebar-nav'
3121 * @class Roo.bootstrap.NavGroup
3122 * @extends Roo.bootstrap.Component
3123 * Bootstrap NavGroup class
3124 * @cfg {String} align left | right
3125 * @cfg {Boolean} inverse false | true
3126 * @cfg {String} type (nav|pills|tab) default nav
3127 * @cfg {String} navId - reference Id for navbar.
3131 * Create a new nav group
3132 * @param {Object} config The config object
3135 Roo.bootstrap.NavGroup = function(config){
3136 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3138 Roo.bootstrap.NavGroup.register(this);
3142 * Fires when the active item changes
3143 * @param {Roo.bootstrap.NavGroup} this
3144 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3145 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3152 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3163 getAutoCreate : function()
3165 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3172 if (['tabs','pills'].indexOf(this.type)!==-1) {
3173 cfg.cls += ' nav-' + this.type
3175 if (this.type!=='nav') {
3176 Roo.log('nav type must be nav/tabs/pills')
3178 cfg.cls += ' navbar-nav'
3181 if (this.parent().sidebar) {
3184 cls: 'dashboard-menu sidebar-menu'
3190 if (this.form === true) {
3196 if (this.align === 'right') {
3197 cfg.cls += ' navbar-right';
3199 cfg.cls += ' navbar-left';
3203 if (this.align === 'right') {
3204 cfg.cls += ' navbar-right';
3208 cfg.cls += ' navbar-inverse';
3216 setActiveItem : function(item)
3219 Roo.each(this.navItems, function(v){
3224 v.setActive(false, true);
3231 item.setActive(true, true);
3232 this.fireEvent('changed', this, item, prev);
3238 register : function(item)
3240 this.navItems.push( item);
3241 item.navId = this.navId;
3244 getNavItem: function(tabId)
3247 Roo.each(this.navItems, function(e) {
3248 if (e.tabId == tabId) {
3260 Roo.apply(Roo.bootstrap.NavGroup, {
3264 register : function(navgrp)
3266 this.groups[navgrp.navId] = navgrp;
3269 get: function(navId) {
3270 return this.groups[navId];
3285 * @class Roo.bootstrap.Navbar.Item
3286 * @extends Roo.bootstrap.Component
3287 * Bootstrap Navbar.Button class
3288 * @cfg {String} href link to
3289 * @cfg {String} html content of button
3290 * @cfg {String} badge text inside badge
3291 * @cfg {String} glyphicon name of glyphicon
3292 * @cfg {String} icon name of font awesome icon
3293 * @cfg {Boolean} active Is item active
3294 * @cfg {Boolean} preventDefault (true | false) default false
3295 * @cfg {String} tabId the tab that this item activates.
3298 * Create a new Navbar Button
3299 * @param {Object} config The config object
3301 Roo.bootstrap.Navbar.Item = function(config){
3302 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3307 * The raw click event for the entire grid.
3308 * @param {Roo.EventObject} e
3313 * Fires when the active item active state changes
3314 * @param {Roo.bootstrap.Navbar.Item} this
3315 * @param {boolean} state the new state
3323 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3331 preventDefault : false,
3334 getAutoCreate : function(){
3336 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3338 if (this.parent().parent().sidebar === true) {
3351 cfg.cn[0].html = this.html;
3355 this.cls += ' active';
3359 cfg.cn[0].cls += ' dropdown-toggle';
3360 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3364 cfg.cn[0].tag = 'a',
3365 cfg.cn[0].href = this.href;
3368 if (this.glyphicon) {
3369 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3373 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3385 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3395 if (this.glyphicon) {
3396 if(cfg.html){cfg.html = ' ' + this.html};
3400 cls: 'glyphicon glyphicon-' + this.glyphicon
3405 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3410 cfg.cn[0].html += " <span class='caret'></span>";
3411 //}else if (!this.href) {
3412 // cfg.cn[0].tag='p';
3413 // cfg.cn[0].cls='navbar-text';
3416 cfg.cn[0].href=this.href||'#';
3417 cfg.cn[0].html=this.html;
3420 if (this.badge !== '') {
3423 cfg.cn[0].html + ' ',
3434 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3439 initEvents: function() {
3440 // Roo.log('init events?');
3441 // Roo.log(this.el.dom);
3442 this.el.select('a',true).on('click', this.onClick, this);
3443 // at this point parent should be available..
3444 this.parent().register(this);
3447 onClick : function(e)
3449 if(this.preventDefault){
3453 if (typeof (this.menu) != 'undefined') {
3454 this.menu.parentType = this.xtype;
3455 this.menu.triggerEl = this.el;
3456 this.addxtype(Roo.apply({}, this.menu));
3459 if(this.fireEvent('click', this, e) === false){
3463 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3464 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3465 this.parent().setActiveItem(this);
3471 isActive: function () {
3474 setActive : function(state, fire)
3476 this.active = state;
3478 this.el.removeClass('active');
3479 } else if (!this.el.hasClass('active')) {
3480 this.el.addClass('active');
3483 this.fireEvent('changed', this, state);
3488 // this should not be here...
3501 * @class Roo.bootstrap.NavItem
3502 * @extends Roo.bootstrap.Component
3503 * Bootstrap Navbar.NavItem class
3504 * @cfg {String} href link to
3505 * @cfg {String} html content of button
3506 * @cfg {String} badge text inside badge
3507 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3508 * @cfg {String} glyphicon name of glyphicon
3509 * @cfg {String} icon name of font awesome icon
3510 * @cfg {Boolean} active Is item active
3511 * @cfg {Boolean} preventDefault (true | false) default false
3512 * @cfg {String} tabId the tab that this item activates.
3515 * Create a new Navbar Item
3516 * @param {Object} config The config object
3518 Roo.bootstrap.NavItem = function(config){
3519 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3524 * The raw click event for the entire grid.
3525 * @param {Roo.EventObject} e
3530 * Fires when the active item active state changes
3531 * @param {Roo.bootstrap.NavItem} this
3532 * @param {boolean} state the new state
3540 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3548 preventDefault : false,
3551 getAutoCreate : function(){
3559 href : this.href || "#",
3560 html: this.html || ''
3566 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3569 // glyphicon and icon go before content..
3570 if (this.glyphicon || this.icon) {
3572 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html + '</span>'
3574 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span>' + cfg.cn[0].html;
3582 cfg.cn[0].html += " <span class='caret'></span>";
3586 if (this.badge !== '') {
3588 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3595 initEvents: function() {
3596 // Roo.log('init events?');
3597 // Roo.log(this.el.dom);
3598 if (typeof (this.menu) != 'undefined') {
3599 this.menu.parentType = this.xtype;
3600 this.menu.triggerEl = this.el;
3601 this.addxtype(Roo.apply({}, this.menu));
3605 this.el.select('a',true).on('click', this.onClick, this);
3606 // at this point parent should be available..
3607 this.parent().register(this);
3610 onClick : function(e)
3612 if(this.preventDefault){
3616 if(this.fireEvent('click', this, e) === false){
3620 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3621 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3622 this.parent().setActiveItem(this);
3630 isActive: function () {
3633 setActive : function(state, fire)
3635 this.active = state;
3637 this.el.removeClass('active');
3638 } else if (!this.el.hasClass('active')) {
3639 this.el.addClass('active');
3642 this.fireEvent('changed', this, state);
3647 // this should not be here...
3658 * <span> icon </span>
3659 * <span> text </span>
3660 * <span>badge </span>
3664 * @class Roo.bootstrap.NavSidebarItem
3665 * @extends Roo.bootstrap.NavItem
3666 * Bootstrap Navbar.NavSidebarItem class
3668 * Create a new Navbar Button
3669 * @param {Object} config The config object
3671 Roo.bootstrap.NavSidebarItem = function(config){
3672 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3677 * The raw click event for the entire grid.
3678 * @param {Roo.EventObject} e
3683 * Fires when the active item active state changes
3684 * @param {Roo.bootstrap.NavSidebarItem} this
3685 * @param {boolean} state the new state
3693 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3696 getAutoCreate : function(){
3701 href : this.href || '#',
3713 html : this.html || ''
3718 cfg.cls += ' active';
3722 if (this.glyphicon || this.icon) {
3723 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3724 a.cn.push({ tag : 'i', cls : c }) ;
3729 if (this.badge !== '') {
3730 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3734 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3735 a.cls += 'dropdown-toggle treeview' ;
3759 * @class Roo.bootstrap.Row
3760 * @extends Roo.bootstrap.Component
3761 * Bootstrap Row class (contains columns...)
3765 * @param {Object} config The config object
3768 Roo.bootstrap.Row = function(config){
3769 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3772 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3774 getAutoCreate : function(){
3793 * @class Roo.bootstrap.Element
3794 * @extends Roo.bootstrap.Component
3795 * Bootstrap Element class
3796 * @cfg {String} html contents of the element
3797 * @cfg {String} tag tag of the element
3798 * @cfg {String} cls class of the element
3801 * Create a new Element
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Element = function(config){
3806 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3816 getAutoCreate : function(){
3841 * @class Roo.bootstrap.Pagination
3842 * @extends Roo.bootstrap.Component
3843 * Bootstrap Pagination class
3844 * @cfg {String} size xs | sm | md | lg
3845 * @cfg {Boolean} inverse false | true
3848 * Create a new Pagination
3849 * @param {Object} config The config object
3852 Roo.bootstrap.Pagination = function(config){
3853 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3856 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3862 getAutoCreate : function(){
3868 cfg.cls += ' inverse';
3874 cfg.cls += " " + this.cls;
3892 * @class Roo.bootstrap.PaginationItem
3893 * @extends Roo.bootstrap.Component
3894 * Bootstrap PaginationItem class
3895 * @cfg {String} html text
3896 * @cfg {String} href the link
3897 * @cfg {Boolean} preventDefault (true | false) default true
3898 * @cfg {Boolean} active (true | false) default false
3902 * Create a new PaginationItem
3903 * @param {Object} config The config object
3907 Roo.bootstrap.PaginationItem = function(config){
3908 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3913 * The raw click event for the entire grid.
3914 * @param {Roo.EventObject} e
3920 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3924 preventDefault: true,
3928 getAutoCreate : function(){
3934 href : this.href ? this.href : '#',
3935 html : this.html ? this.html : ''
3945 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3951 initEvents: function() {
3953 this.el.on('click', this.onClick, this);
3956 onClick : function(e)
3958 Roo.log('PaginationItem on click ');
3959 if(this.preventDefault){
3963 this.fireEvent('click', this, e);
3979 * @class Roo.bootstrap.Slider
3980 * @extends Roo.bootstrap.Component
3981 * Bootstrap Slider class
3984 * Create a new Slider
3985 * @param {Object} config The config object
3988 Roo.bootstrap.Slider = function(config){
3989 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3992 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3994 getAutoCreate : function(){
3998 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4002 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4020 * @class Roo.bootstrap.Table
4021 * @extends Roo.bootstrap.Component
4022 * Bootstrap Table class
4023 * @cfg {String} cls table class
4024 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4025 * @cfg {String} bgcolor Specifies the background color for a table
4026 * @cfg {Number} border Specifies whether the table cells should have borders or not
4027 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4028 * @cfg {Number} cellspacing Specifies the space between cells
4029 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4030 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4031 * @cfg {String} sortable Specifies that the table should be sortable
4032 * @cfg {String} summary Specifies a summary of the content of a table
4033 * @cfg {Number} width Specifies the width of a table
4035 * @cfg {boolean} striped Should the rows be alternative striped
4036 * @cfg {boolean} bordered Add borders to the table
4037 * @cfg {boolean} hover Add hover highlighting
4038 * @cfg {boolean} condensed Format condensed
4039 * @cfg {boolean} responsive Format condensed
4040 * @cfg {Boolean} loadMask (true|false) default false
4046 * Create a new Table
4047 * @param {Object} config The config object
4050 Roo.bootstrap.Table = function(config){
4051 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4054 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4055 this.sm = this.selModel;
4056 this.sm.xmodule = this.xmodule || false;
4058 if (this.cm && typeof(this.cm.config) == 'undefined') {
4059 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
4060 this.cm = this.colModel;
4061 this.cm.xmodule = this.xmodule || false;
4064 this.store= Roo.factory(this.store, Roo.data);
4065 this.ds = this.store;
4066 this.ds.xmodule = this.xmodule || false;
4071 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4094 getAutoCreate : function(){
4095 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4104 cfg.cls += ' table-striped';
4107 cfg.cls += ' table-hover';
4109 if (this.bordered) {
4110 cfg.cls += ' table-bordered';
4112 if (this.condensed) {
4113 cfg.cls += ' table-condensed';
4115 if (this.responsive) {
4116 cfg.cls += ' table-responsive';
4123 cfg.cls+= ' ' +this.cls;
4126 // this lot should be simplifed...
4129 cfg.align=this.align;
4132 cfg.bgcolor=this.bgcolor;
4135 cfg.border=this.border;
4137 if (this.cellpadding) {
4138 cfg.cellpadding=this.cellpadding;
4140 if (this.cellspacing) {
4141 cfg.cellspacing=this.cellspacing;
4144 cfg.frame=this.frame;
4147 cfg.rules=this.rules;
4149 if (this.sortable) {
4150 cfg.sortable=this.sortable;
4153 cfg.summary=this.summary;
4156 cfg.width=this.width;
4159 if(this.store || this.cm){
4160 cfg.cn.push(this.renderHeader());
4161 cfg.cn.push(this.renderBody());
4162 cfg.cn.push(this.renderFooter());
4164 cfg.cls+= ' TableGrid';
4170 // initTableGrid : function()
4179 // var cm = this.cm;
4181 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4184 // html: cm.getColumnHeader(i)
4188 // cfg.push(header);
4195 initEvents : function()
4197 if(!this.store || !this.cm){
4201 Roo.log('initEvents with ds!!!!');
4205 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4206 e.on('click', _this.sort, _this);
4208 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4209 // this.maskEl.enableDisplayMode("block");
4210 // this.maskEl.show();
4212 this.parent().el.setStyle('position', 'relative');
4217 style: "text-align:center",
4221 style: "background-color:white;width:50%;margin:100 auto",
4225 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
4236 this.maskEl = Roo.DomHelper.append(this.parent().el, mark, true);
4238 var size = this.parent().el.getSize();
4240 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4242 this.maskEl.enableDisplayMode("block");
4244 this.store.on('load', this.onLoad, this);
4245 this.store.on('beforeload', this.onBeforeLoad, this);
4253 sort : function(e,el)
4255 var col = Roo.get(el)
4257 if(!col.hasClass('sortable')){
4261 var sort = col.attr('sort');
4264 if(col.hasClass('glyphicon-arrow-up')){
4268 this.store.sortInfo = {field : sort, direction : dir};
4273 renderHeader : function()
4282 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4284 var config = cm.config[i];
4286 if(typeof(config.hidden) != 'undefined' && config.hidden){
4292 html: cm.getColumnHeader(i)
4295 if(typeof(config.dataIndex) != 'undefined'){
4296 c.sort = config.dataIndex;
4299 if(typeof(config.sortable) != 'undefined' && config.sortable){
4303 if(typeof(config.width) != 'undefined'){
4304 c.style = 'width:' + config.width + 'px';
4313 renderBody : function()
4323 renderFooter : function()
4335 Roo.log('ds onload');
4340 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4341 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4343 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4344 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4347 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4348 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4352 var tbody = this.el.select('tbody', true).first();
4356 if(this.store.getCount() > 0){
4357 this.store.data.each(function(d){
4363 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4364 var config = cm.config[i];
4366 if(typeof(config.hidden) != 'undefined' && config.hidden){
4370 var renderer = cm.getRenderer(i);
4374 if(typeof(renderer) !== 'undefined'){
4375 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4378 if(typeof(value) === 'object'){
4388 html: (typeof(value) === 'object') ? '' : value
4391 if(typeof(config.width) != 'undefined'){
4392 td.style = 'width:' + config.width + 'px';
4399 tbody.createChild(row);
4407 Roo.each(renders, function(r){
4408 _this.renderColumn(r);
4417 onBeforeLoad : function()
4419 Roo.log('ds onBeforeLoad');
4430 this.el.select('tbody', true).first().dom.innerHTML = '';
4433 getSelectionModel : function(){
4435 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4437 return this.selModel;
4440 renderColumn : function(r)
4443 r.cfg.render(Roo.get(r.id));
4446 Roo.each(r.cfg.cn, function(c){
4451 _this.renderColumn(child);
4468 * @class Roo.bootstrap.TableCell
4469 * @extends Roo.bootstrap.Component
4470 * Bootstrap TableCell class
4471 * @cfg {String} html cell contain text
4472 * @cfg {String} cls cell class
4473 * @cfg {String} tag cell tag (td|th) default td
4474 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4475 * @cfg {String} align Aligns the content in a cell
4476 * @cfg {String} axis Categorizes cells
4477 * @cfg {String} bgcolor Specifies the background color of a cell
4478 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4479 * @cfg {Number} colspan Specifies the number of columns a cell should span
4480 * @cfg {String} headers Specifies one or more header cells a cell is related to
4481 * @cfg {Number} height Sets the height of a cell
4482 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4483 * @cfg {Number} rowspan Sets the number of rows a cell should span
4484 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4485 * @cfg {String} valign Vertical aligns the content in a cell
4486 * @cfg {Number} width Specifies the width of a cell
4489 * Create a new TableCell
4490 * @param {Object} config The config object
4493 Roo.bootstrap.TableCell = function(config){
4494 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4497 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4517 getAutoCreate : function(){
4518 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4538 cfg.align=this.align
4544 cfg.bgcolor=this.bgcolor
4547 cfg.charoff=this.charoff
4550 cfg.colspan=this.colspan
4553 cfg.headers=this.headers
4556 cfg.height=this.height
4559 cfg.nowrap=this.nowrap
4562 cfg.rowspan=this.rowspan
4565 cfg.scope=this.scope
4568 cfg.valign=this.valign
4571 cfg.width=this.width
4590 * @class Roo.bootstrap.TableRow
4591 * @extends Roo.bootstrap.Component
4592 * Bootstrap TableRow class
4593 * @cfg {String} cls row class
4594 * @cfg {String} align Aligns the content in a table row
4595 * @cfg {String} bgcolor Specifies a background color for a table row
4596 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4597 * @cfg {String} valign Vertical aligns the content in a table row
4600 * Create a new TableRow
4601 * @param {Object} config The config object
4604 Roo.bootstrap.TableRow = function(config){
4605 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4608 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4616 getAutoCreate : function(){
4617 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4627 cfg.align = this.align;
4630 cfg.bgcolor = this.bgcolor;
4633 cfg.charoff = this.charoff;
4636 cfg.valign = this.valign;
4654 * @class Roo.bootstrap.TableBody
4655 * @extends Roo.bootstrap.Component
4656 * Bootstrap TableBody class
4657 * @cfg {String} cls element class
4658 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4659 * @cfg {String} align Aligns the content inside the element
4660 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4661 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4664 * Create a new TableBody
4665 * @param {Object} config The config object
4668 Roo.bootstrap.TableBody = function(config){
4669 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4672 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4680 getAutoCreate : function(){
4681 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4695 cfg.align = this.align;
4698 cfg.charoff = this.charoff;
4701 cfg.valign = this.valign;
4708 // initEvents : function()
4715 // this.store = Roo.factory(this.store, Roo.data);
4716 // this.store.on('load', this.onLoad, this);
4718 // this.store.load();
4722 // onLoad: function ()
4724 // this.fireEvent('load', this);
4734 * Ext JS Library 1.1.1
4735 * Copyright(c) 2006-2007, Ext JS, LLC.
4737 * Originally Released Under LGPL - original licence link has changed is not relivant.
4740 * <script type="text/javascript">
4743 // as we use this in bootstrap.
4744 Roo.namespace('Roo.form');
4746 * @class Roo.form.Action
4747 * Internal Class used to handle form actions
4749 * @param {Roo.form.BasicForm} el The form element or its id
4750 * @param {Object} config Configuration options
4755 // define the action interface
4756 Roo.form.Action = function(form, options){
4758 this.options = options || {};
4761 * Client Validation Failed
4764 Roo.form.Action.CLIENT_INVALID = 'client';
4766 * Server Validation Failed
4769 Roo.form.Action.SERVER_INVALID = 'server';
4771 * Connect to Server Failed
4774 Roo.form.Action.CONNECT_FAILURE = 'connect';
4776 * Reading Data from Server Failed
4779 Roo.form.Action.LOAD_FAILURE = 'load';
4781 Roo.form.Action.prototype = {
4783 failureType : undefined,
4784 response : undefined,
4788 run : function(options){
4793 success : function(response){
4798 handleResponse : function(response){
4802 // default connection failure
4803 failure : function(response){
4805 this.response = response;
4806 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4807 this.form.afterAction(this, false);
4810 processResponse : function(response){
4811 this.response = response;
4812 if(!response.responseText){
4815 this.result = this.handleResponse(response);
4819 // utility functions used internally
4820 getUrl : function(appendParams){
4821 var url = this.options.url || this.form.url || this.form.el.dom.action;
4823 var p = this.getParams();
4825 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4831 getMethod : function(){
4832 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4835 getParams : function(){
4836 var bp = this.form.baseParams;
4837 var p = this.options.params;
4839 if(typeof p == "object"){
4840 p = Roo.urlEncode(Roo.applyIf(p, bp));
4841 }else if(typeof p == 'string' && bp){
4842 p += '&' + Roo.urlEncode(bp);
4845 p = Roo.urlEncode(bp);
4850 createCallback : function(){
4852 success: this.success,
4853 failure: this.failure,
4855 timeout: (this.form.timeout*1000),
4856 upload: this.form.fileUpload ? this.success : undefined
4861 Roo.form.Action.Submit = function(form, options){
4862 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4865 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4868 haveProgress : false,
4869 uploadComplete : false,
4871 // uploadProgress indicator.
4872 uploadProgress : function()
4874 if (!this.form.progressUrl) {
4878 if (!this.haveProgress) {
4879 Roo.MessageBox.progress("Uploading", "Uploading");
4881 if (this.uploadComplete) {
4882 Roo.MessageBox.hide();
4886 this.haveProgress = true;
4888 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4890 var c = new Roo.data.Connection();
4892 url : this.form.progressUrl,
4897 success : function(req){
4898 //console.log(data);
4902 rdata = Roo.decode(req.responseText)
4904 Roo.log("Invalid data from server..");
4908 if (!rdata || !rdata.success) {
4910 Roo.MessageBox.alert(Roo.encode(rdata));
4913 var data = rdata.data;
4915 if (this.uploadComplete) {
4916 Roo.MessageBox.hide();
4921 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4922 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4925 this.uploadProgress.defer(2000,this);
4928 failure: function(data) {
4929 Roo.log('progress url failed ');
4940 // run get Values on the form, so it syncs any secondary forms.
4941 this.form.getValues();
4943 var o = this.options;
4944 var method = this.getMethod();
4945 var isPost = method == 'POST';
4946 if(o.clientValidation === false || this.form.isValid()){
4948 if (this.form.progressUrl) {
4949 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4950 (new Date() * 1) + '' + Math.random());
4955 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4956 form:this.form.el.dom,
4957 url:this.getUrl(!isPost),
4959 params:isPost ? this.getParams() : null,
4960 isUpload: this.form.fileUpload
4963 this.uploadProgress();
4965 }else if (o.clientValidation !== false){ // client validation failed
4966 this.failureType = Roo.form.Action.CLIENT_INVALID;
4967 this.form.afterAction(this, false);
4971 success : function(response)
4973 this.uploadComplete= true;
4974 if (this.haveProgress) {
4975 Roo.MessageBox.hide();
4979 var result = this.processResponse(response);
4980 if(result === true || result.success){
4981 this.form.afterAction(this, true);
4985 this.form.markInvalid(result.errors);
4986 this.failureType = Roo.form.Action.SERVER_INVALID;
4988 this.form.afterAction(this, false);
4990 failure : function(response)
4992 this.uploadComplete= true;
4993 if (this.haveProgress) {
4994 Roo.MessageBox.hide();
4997 this.response = response;
4998 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4999 this.form.afterAction(this, false);
5002 handleResponse : function(response){
5003 if(this.form.errorReader){
5004 var rs = this.form.errorReader.read(response);
5007 for(var i = 0, len = rs.records.length; i < len; i++) {
5008 var r = rs.records[i];
5012 if(errors.length < 1){
5016 success : rs.success,
5022 ret = Roo.decode(response.responseText);
5026 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5036 Roo.form.Action.Load = function(form, options){
5037 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5038 this.reader = this.form.reader;
5041 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5046 Roo.Ajax.request(Roo.apply(
5047 this.createCallback(), {
5048 method:this.getMethod(),
5049 url:this.getUrl(false),
5050 params:this.getParams()
5054 success : function(response){
5056 var result = this.processResponse(response);
5057 if(result === true || !result.success || !result.data){
5058 this.failureType = Roo.form.Action.LOAD_FAILURE;
5059 this.form.afterAction(this, false);
5062 this.form.clearInvalid();
5063 this.form.setValues(result.data);
5064 this.form.afterAction(this, true);
5067 handleResponse : function(response){
5068 if(this.form.reader){
5069 var rs = this.form.reader.read(response);
5070 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5072 success : rs.success,
5076 return Roo.decode(response.responseText);
5080 Roo.form.Action.ACTION_TYPES = {
5081 'load' : Roo.form.Action.Load,
5082 'submit' : Roo.form.Action.Submit
5091 * @class Roo.bootstrap.Form
5092 * @extends Roo.bootstrap.Component
5093 * Bootstrap Form class
5094 * @cfg {String} method GET | POST (default POST)
5095 * @cfg {String} labelAlign top | left (default top)
5096 * @cfg {String} align left | right - for navbars
5101 * @param {Object} config The config object
5105 Roo.bootstrap.Form = function(config){
5106 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5109 * @event clientvalidation
5110 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5111 * @param {Form} this
5112 * @param {Boolean} valid true if the form has passed client-side validation
5114 clientvalidation: true,
5116 * @event beforeaction
5117 * Fires before any action is performed. Return false to cancel the action.
5118 * @param {Form} this
5119 * @param {Action} action The action to be performed
5123 * @event actionfailed
5124 * Fires when an action fails.
5125 * @param {Form} this
5126 * @param {Action} action The action that failed
5128 actionfailed : true,
5130 * @event actioncomplete
5131 * Fires when an action is completed.
5132 * @param {Form} this
5133 * @param {Action} action The action that completed
5135 actioncomplete : true
5140 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5143 * @cfg {String} method
5144 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5149 * The URL to use for form actions if one isn't supplied in the action options.
5152 * @cfg {Boolean} fileUpload
5153 * Set to true if this form is a file upload.
5157 * @cfg {Object} baseParams
5158 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5162 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5166 * @cfg {Sting} align (left|right) for navbar forms
5171 activeAction : null,
5174 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5175 * element by passing it or its id or mask the form itself by passing in true.
5178 waitMsgTarget : false,
5183 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5184 * element by passing it or its id or mask the form itself by passing in true.
5188 getAutoCreate : function(){
5192 method : this.method || 'POST',
5193 id : this.id || Roo.id(),
5196 if (this.parent().xtype.match(/^Nav/)) {
5197 cfg.cls = 'navbar-form navbar-' + this.align;
5201 if (this.labelAlign == 'left' ) {
5202 cfg.cls += ' form-horizontal';
5208 initEvents : function()
5210 this.el.on('submit', this.onSubmit, this);
5215 onSubmit : function(e){
5220 * Returns true if client-side validation on the form is successful.
5223 isValid : function(){
5224 var items = this.getItems();
5226 items.each(function(f){
5235 * Returns true if any fields in this form have changed since their original load.
5238 isDirty : function(){
5240 var items = this.getItems();
5241 items.each(function(f){
5251 * Performs a predefined action (submit or load) or custom actions you define on this form.
5252 * @param {String} actionName The name of the action type
5253 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5254 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5255 * accept other config options):
5257 Property Type Description
5258 ---------------- --------------- ----------------------------------------------------------------------------------
5259 url String The url for the action (defaults to the form's url)
5260 method String The form method to use (defaults to the form's method, or POST if not defined)
5261 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5262 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5263 validate the form on the client (defaults to false)
5265 * @return {BasicForm} this
5267 doAction : function(action, options){
5268 if(typeof action == 'string'){
5269 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5271 if(this.fireEvent('beforeaction', this, action) !== false){
5272 this.beforeAction(action);
5273 action.run.defer(100, action);
5279 beforeAction : function(action){
5280 var o = action.options;
5282 // not really supported yet.. ??
5284 //if(this.waitMsgTarget === true){
5285 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5286 //}else if(this.waitMsgTarget){
5287 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5288 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5290 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5296 afterAction : function(action, success){
5297 this.activeAction = null;
5298 var o = action.options;
5300 //if(this.waitMsgTarget === true){
5302 //}else if(this.waitMsgTarget){
5303 // this.waitMsgTarget.unmask();
5305 // Roo.MessageBox.updateProgress(1);
5306 // Roo.MessageBox.hide();
5313 Roo.callback(o.success, o.scope, [this, action]);
5314 this.fireEvent('actioncomplete', this, action);
5318 // failure condition..
5319 // we have a scenario where updates need confirming.
5320 // eg. if a locking scenario exists..
5321 // we look for { errors : { needs_confirm : true }} in the response.
5323 (typeof(action.result) != 'undefined') &&
5324 (typeof(action.result.errors) != 'undefined') &&
5325 (typeof(action.result.errors.needs_confirm) != 'undefined')
5328 Roo.log("not supported yet");
5331 Roo.MessageBox.confirm(
5332 "Change requires confirmation",
5333 action.result.errorMsg,
5338 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5348 Roo.callback(o.failure, o.scope, [this, action]);
5349 // show an error message if no failed handler is set..
5350 if (!this.hasListener('actionfailed')) {
5351 Roo.log("need to add dialog support");
5353 Roo.MessageBox.alert("Error",
5354 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5355 action.result.errorMsg :
5356 "Saving Failed, please check your entries or try again"
5361 this.fireEvent('actionfailed', this, action);
5366 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5367 * @param {String} id The value to search for
5370 findField : function(id){
5371 var items = this.getItems();
5372 var field = items.get(id);
5374 items.each(function(f){
5375 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5382 return field || null;
5385 * Mark fields in this form invalid in bulk.
5386 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5387 * @return {BasicForm} this
5389 markInvalid : function(errors){
5390 if(errors instanceof Array){
5391 for(var i = 0, len = errors.length; i < len; i++){
5392 var fieldError = errors[i];
5393 var f = this.findField(fieldError.id);
5395 f.markInvalid(fieldError.msg);
5401 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5402 field.markInvalid(errors[id]);
5406 //Roo.each(this.childForms || [], function (f) {
5407 // f.markInvalid(errors);
5414 * Set values for fields in this form in bulk.
5415 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5416 * @return {BasicForm} this
5418 setValues : function(values){
5419 if(values instanceof Array){ // array of objects
5420 for(var i = 0, len = values.length; i < len; i++){
5422 var f = this.findField(v.id);
5424 f.setValue(v.value);
5425 if(this.trackResetOnLoad){
5426 f.originalValue = f.getValue();
5430 }else{ // object hash
5433 if(typeof values[id] != 'function' && (field = this.findField(id))){
5435 if (field.setFromData &&
5437 field.displayField &&
5438 // combos' with local stores can
5439 // be queried via setValue()
5440 // to set their value..
5441 (field.store && !field.store.isLocal)
5445 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5446 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5447 field.setFromData(sd);
5450 field.setValue(values[id]);
5454 if(this.trackResetOnLoad){
5455 field.originalValue = field.getValue();
5461 //Roo.each(this.childForms || [], function (f) {
5462 // f.setValues(values);
5469 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5470 * they are returned as an array.
5471 * @param {Boolean} asString
5474 getValues : function(asString){
5475 //if (this.childForms) {
5476 // copy values from the child forms
5477 // Roo.each(this.childForms, function (f) {
5478 // this.setValues(f.getValues());
5484 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5485 if(asString === true){
5488 return Roo.urlDecode(fs);
5492 * Returns the fields in this form as an object with key/value pairs.
5493 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5496 getFieldValues : function(with_hidden)
5498 var items = this.getItems();
5500 items.each(function(f){
5504 var v = f.getValue();
5505 if (f.inputType =='radio') {
5506 if (typeof(ret[f.getName()]) == 'undefined') {
5507 ret[f.getName()] = ''; // empty..
5510 if (!f.el.dom.checked) {
5518 // not sure if this supported any more..
5519 if ((typeof(v) == 'object') && f.getRawValue) {
5520 v = f.getRawValue() ; // dates..
5522 // combo boxes where name != hiddenName...
5523 if (f.name != f.getName()) {
5524 ret[f.name] = f.getRawValue();
5526 ret[f.getName()] = v;
5533 * Clears all invalid messages in this form.
5534 * @return {BasicForm} this
5536 clearInvalid : function(){
5537 var items = this.getItems();
5539 items.each(function(f){
5550 * @return {BasicForm} this
5553 var items = this.getItems();
5554 items.each(function(f){
5558 Roo.each(this.childForms || [], function (f) {
5565 getItems : function()
5567 var r=new Roo.util.MixedCollection(false, function(o){
5568 return o.id || (o.id = Roo.id());
5570 var iter = function(el) {
5577 Roo.each(el.items,function(e) {
5596 * Ext JS Library 1.1.1
5597 * Copyright(c) 2006-2007, Ext JS, LLC.
5599 * Originally Released Under LGPL - original licence link has changed is not relivant.
5602 * <script type="text/javascript">
5605 * @class Roo.form.VTypes
5606 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5609 Roo.form.VTypes = function(){
5610 // closure these in so they are only created once.
5611 var alpha = /^[a-zA-Z_]+$/;
5612 var alphanum = /^[a-zA-Z0-9_]+$/;
5613 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5614 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5616 // All these messages and functions are configurable
5619 * The function used to validate email addresses
5620 * @param {String} value The email address
5622 'email' : function(v){
5623 return email.test(v);
5626 * The error text to display when the email validation function returns false
5629 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5631 * The keystroke filter mask to be applied on email input
5634 'emailMask' : /[a-z0-9_\.\-@]/i,
5637 * The function used to validate URLs
5638 * @param {String} value The URL
5640 'url' : function(v){
5644 * The error text to display when the url validation function returns false
5647 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5650 * The function used to validate alpha values
5651 * @param {String} value The value
5653 'alpha' : function(v){
5654 return alpha.test(v);
5657 * The error text to display when the alpha validation function returns false
5660 'alphaText' : 'This field should only contain letters and _',
5662 * The keystroke filter mask to be applied on alpha input
5665 'alphaMask' : /[a-z_]/i,
5668 * The function used to validate alphanumeric values
5669 * @param {String} value The value
5671 'alphanum' : function(v){
5672 return alphanum.test(v);
5675 * The error text to display when the alphanumeric validation function returns false
5678 'alphanumText' : 'This field should only contain letters, numbers and _',
5680 * The keystroke filter mask to be applied on alphanumeric input
5683 'alphanumMask' : /[a-z0-9_]/i
5693 * @class Roo.bootstrap.Input
5694 * @extends Roo.bootstrap.Component
5695 * Bootstrap Input class
5696 * @cfg {Boolean} disabled is it disabled
5697 * @cfg {String} fieldLabel - the label associated
5698 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5699 * @cfg {String} name name of the input
5700 * @cfg {string} fieldLabel - the label associated
5701 * @cfg {string} inputType - input / file submit ...
5702 * @cfg {string} placeholder - placeholder to put in text.
5703 * @cfg {string} before - input group add on before
5704 * @cfg {string} after - input group add on after
5705 * @cfg {string} size - (lg|sm) or leave empty..
5706 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5707 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5708 * @cfg {Number} md colspan out of 12 for computer-sized screens
5709 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5710 * @cfg {string} value default value of the input
5711 * @cfg {Number} labelWidth set the width of label (0-12)
5712 * @cfg {String} labelAlign (top|left)
5713 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5717 * Create a new Input
5718 * @param {Object} config The config object
5721 Roo.bootstrap.Input = function(config){
5722 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5727 * Fires when this field receives input focus.
5728 * @param {Roo.form.Field} this
5733 * Fires when this field loses input focus.
5734 * @param {Roo.form.Field} this
5739 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5740 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5741 * @param {Roo.form.Field} this
5742 * @param {Roo.EventObject} e The event object
5747 * Fires just before the field blurs if the field value has changed.
5748 * @param {Roo.form.Field} this
5749 * @param {Mixed} newValue The new value
5750 * @param {Mixed} oldValue The original value
5755 * Fires after the field has been marked as invalid.
5756 * @param {Roo.form.Field} this
5757 * @param {String} msg The validation message
5762 * Fires after the field has been validated with no errors.
5763 * @param {Roo.form.Field} this
5768 * Fires after the key up
5769 * @param {Roo.form.Field} this
5770 * @param {Roo.EventObject} e The event Object
5776 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5778 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5779 automatic validation (defaults to "keyup").
5781 validationEvent : "keyup",
5783 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5785 validateOnBlur : true,
5787 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5789 validationDelay : 250,
5791 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5793 focusClass : "x-form-focus", // not needed???
5797 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5799 invalidClass : "has-error",
5802 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5804 selectOnFocus : false,
5807 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5811 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5816 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5818 disableKeyFilter : false,
5821 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5825 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5829 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5831 blankText : "This field is required",
5834 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5838 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5840 maxLength : Number.MAX_VALUE,
5842 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5844 minLengthText : "The minimum length for this field is {0}",
5846 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5848 maxLengthText : "The maximum length for this field is {0}",
5852 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5853 * If available, this function will be called only after the basic validators all return true, and will be passed the
5854 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5858 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5859 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5860 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5864 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5887 parentLabelAlign : function()
5890 while (parent.parent()) {
5891 parent = parent.parent();
5892 if (typeof(parent.labelAlign) !='undefined') {
5893 return parent.labelAlign;
5900 getAutoCreate : function(){
5902 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5908 if(this.inputType != 'hidden'){
5909 cfg.cls = 'form-group' //input-group
5915 type : this.inputType,
5917 cls : 'form-control',
5918 placeholder : this.placeholder || ''
5922 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5923 input.maxLength = this.maxLength;
5926 if (this.disabled) {
5927 input.disabled=true;
5930 if (this.readOnly) {
5931 input.readonly=true;
5935 input.name = this.name;
5938 input.cls += ' input-' + this.size;
5941 ['xs','sm','md','lg'].map(function(size){
5942 if (settings[size]) {
5943 cfg.cls += ' col-' + size + '-' + settings[size];
5947 var inputblock = input;
5949 if (this.before || this.after) {
5952 cls : 'input-group',
5955 if (this.before && typeof(this.before) == 'string') {
5957 inputblock.cn.push({
5959 cls : 'roo-input-before input-group-addon',
5963 if (this.before && typeof(this.before) == 'object') {
5964 this.before = Roo.factory(this.before);
5965 Roo.log(this.before);
5966 inputblock.cn.push({
5968 cls : 'roo-input-before input-group-' +
5969 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5973 inputblock.cn.push(input);
5975 if (this.after && typeof(this.after) == 'string') {
5976 inputblock.cn.push({
5978 cls : 'roo-input-after input-group-addon',
5982 if (this.after && typeof(this.after) == 'object') {
5983 this.after = Roo.factory(this.after);
5984 Roo.log(this.after);
5985 inputblock.cn.push({
5987 cls : 'roo-input-after input-group-' +
5988 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5993 if (align ==='left' && this.fieldLabel.length) {
5994 Roo.log("left and has label");
6000 cls : 'control-label col-sm-' + this.labelWidth,
6001 html : this.fieldLabel
6005 cls : "col-sm-" + (12 - this.labelWidth),
6012 } else if ( this.fieldLabel.length) {
6018 //cls : 'input-group-addon',
6019 html : this.fieldLabel
6029 Roo.log(" no label && no align");
6038 Roo.log('input-parentType: ' + this.parentType);
6040 if (this.parentType === 'Navbar' && this.parent().bar) {
6041 cfg.cls += ' navbar-form';
6049 * return the real input element.
6051 inputEl: function ()
6053 return this.el.select('input.form-control',true).first();
6055 setDisabled : function(v)
6057 var i = this.inputEl().dom;
6059 i.removeAttribute('disabled');
6063 i.setAttribute('disabled','true');
6065 initEvents : function()
6068 this.inputEl().on("keydown" , this.fireKey, this);
6069 this.inputEl().on("focus", this.onFocus, this);
6070 this.inputEl().on("blur", this.onBlur, this);
6072 this.inputEl().relayEvent('keyup', this);
6074 // reference to original value for reset
6075 this.originalValue = this.getValue();
6076 //Roo.form.TextField.superclass.initEvents.call(this);
6077 if(this.validationEvent == 'keyup'){
6078 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6079 this.inputEl().on('keyup', this.filterValidation, this);
6081 else if(this.validationEvent !== false){
6082 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6085 if(this.selectOnFocus){
6086 this.on("focus", this.preFocus, this);
6089 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6090 this.inputEl().on("keypress", this.filterKeys, this);
6093 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6094 this.el.on("click", this.autoSize, this);
6097 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6098 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6101 if (typeof(this.before) == 'object') {
6102 this.before.render(this.el.select('.roo-input-before',true).first());
6104 if (typeof(this.after) == 'object') {
6105 this.after.render(this.el.select('.roo-input-after',true).first());
6110 filterValidation : function(e){
6111 if(!e.isNavKeyPress()){
6112 this.validationTask.delay(this.validationDelay);
6116 * Validates the field value
6117 * @return {Boolean} True if the value is valid, else false
6119 validate : function(){
6120 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6121 if(this.disabled || this.validateValue(this.getRawValue())){
6122 this.clearInvalid();
6130 * Validates a value according to the field's validation rules and marks the field as invalid
6131 * if the validation fails
6132 * @param {Mixed} value The value to validate
6133 * @return {Boolean} True if the value is valid, else false
6135 validateValue : function(value){
6136 if(value.length < 1) { // if it's blank
6137 if(this.allowBlank){
6138 this.clearInvalid();
6141 this.markInvalid(this.blankText);
6145 if(value.length < this.minLength){
6146 this.markInvalid(String.format(this.minLengthText, this.minLength));
6149 if(value.length > this.maxLength){
6150 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6154 var vt = Roo.form.VTypes;
6155 if(!vt[this.vtype](value, this)){
6156 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6160 if(typeof this.validator == "function"){
6161 var msg = this.validator(value);
6163 this.markInvalid(msg);
6167 if(this.regex && !this.regex.test(value)){
6168 this.markInvalid(this.regexText);
6177 fireKey : function(e){
6178 //Roo.log('field ' + e.getKey());
6179 if(e.isNavKeyPress()){
6180 this.fireEvent("specialkey", this, e);
6183 focus : function (selectText){
6185 this.inputEl().focus();
6186 if(selectText === true){
6187 this.inputEl().dom.select();
6193 onFocus : function(){
6194 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6195 // this.el.addClass(this.focusClass);
6198 this.hasFocus = true;
6199 this.startValue = this.getValue();
6200 this.fireEvent("focus", this);
6204 beforeBlur : Roo.emptyFn,
6208 onBlur : function(){
6210 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6211 //this.el.removeClass(this.focusClass);
6213 this.hasFocus = false;
6214 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6217 var v = this.getValue();
6218 if(String(v) !== String(this.startValue)){
6219 this.fireEvent('change', this, v, this.startValue);
6221 this.fireEvent("blur", this);
6225 * Resets the current field value to the originally loaded value and clears any validation messages
6228 this.setValue(this.originalValue);
6229 this.clearInvalid();
6232 * Returns the name of the field
6233 * @return {Mixed} name The name field
6235 getName: function(){
6239 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6240 * @return {Mixed} value The field value
6242 getValue : function(){
6243 return this.inputEl().getValue();
6246 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6247 * @return {Mixed} value The field value
6249 getRawValue : function(){
6250 var v = this.inputEl().getValue();
6256 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6257 * @param {Mixed} value The value to set
6259 setRawValue : function(v){
6260 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6263 selectText : function(start, end){
6264 var v = this.getRawValue();
6266 start = start === undefined ? 0 : start;
6267 end = end === undefined ? v.length : end;
6268 var d = this.inputEl().dom;
6269 if(d.setSelectionRange){
6270 d.setSelectionRange(start, end);
6271 }else if(d.createTextRange){
6272 var range = d.createTextRange();
6273 range.moveStart("character", start);
6274 range.moveEnd("character", v.length-end);
6281 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6282 * @param {Mixed} value The value to set
6284 setValue : function(v){
6287 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6293 processValue : function(value){
6294 if(this.stripCharsRe){
6295 var newValue = value.replace(this.stripCharsRe, '');
6296 if(newValue !== value){
6297 this.setRawValue(newValue);
6304 preFocus : function(){
6306 if(this.selectOnFocus){
6307 this.inputEl().dom.select();
6310 filterKeys : function(e){
6312 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6315 var c = e.getCharCode(), cc = String.fromCharCode(c);
6316 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6319 if(!this.maskRe.test(cc)){
6324 * Clear any invalid styles/messages for this field
6326 clearInvalid : function(){
6328 if(!this.el || this.preventMark){ // not rendered
6331 this.el.removeClass(this.invalidClass);
6333 switch(this.msgTarget){
6335 this.el.dom.qtip = '';
6338 this.el.dom.title = '';
6342 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6347 this.errorIcon.dom.qtip = '';
6348 this.errorIcon.hide();
6349 this.un('resize', this.alignErrorIcon, this);
6353 var t = Roo.getDom(this.msgTarget);
6355 t.style.display = 'none';
6359 this.fireEvent('valid', this);
6362 * Mark this field as invalid
6363 * @param {String} msg The validation message
6365 markInvalid : function(msg){
6366 if(!this.el || this.preventMark){ // not rendered
6369 this.el.addClass(this.invalidClass);
6371 msg = msg || this.invalidText;
6372 switch(this.msgTarget){
6374 this.el.dom.qtip = msg;
6375 this.el.dom.qclass = 'x-form-invalid-tip';
6376 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6377 Roo.QuickTips.enable();
6381 this.el.dom.title = msg;
6385 var elp = this.el.findParent('.x-form-element', 5, true);
6386 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6387 this.errorEl.setWidth(elp.getWidth(true)-20);
6389 this.errorEl.update(msg);
6390 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6393 if(!this.errorIcon){
6394 var elp = this.el.findParent('.x-form-element', 5, true);
6395 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6397 this.alignErrorIcon();
6398 this.errorIcon.dom.qtip = msg;
6399 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6400 this.errorIcon.show();
6401 this.on('resize', this.alignErrorIcon, this);
6404 var t = Roo.getDom(this.msgTarget);
6406 t.style.display = this.msgDisplay;
6410 this.fireEvent('invalid', this, msg);
6413 SafariOnKeyDown : function(event)
6415 // this is a workaround for a password hang bug on chrome/ webkit.
6417 var isSelectAll = false;
6419 if(this.inputEl().dom.selectionEnd > 0){
6420 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6422 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6423 event.preventDefault();
6428 if(isSelectAll){ // backspace and delete key
6430 event.preventDefault();
6431 // this is very hacky as keydown always get's upper case.
6433 var cc = String.fromCharCode(event.getCharCode());
6434 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6438 adjustWidth : function(tag, w){
6439 tag = tag.toLowerCase();
6440 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6441 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6445 if(tag == 'textarea'){
6448 }else if(Roo.isOpera){
6452 if(tag == 'textarea'){
6471 * @class Roo.bootstrap.TextArea
6472 * @extends Roo.bootstrap.Input
6473 * Bootstrap TextArea class
6474 * @cfg {Number} cols Specifies the visible width of a text area
6475 * @cfg {Number} rows Specifies the visible number of lines in a text area
6476 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6477 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6478 * @cfg {string} html text
6481 * Create a new TextArea
6482 * @param {Object} config The config object
6485 Roo.bootstrap.TextArea = function(config){
6486 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6490 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6500 getAutoCreate : function(){
6502 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6513 value : this.value || '',
6514 html: this.html || '',
6515 cls : 'form-control',
6516 placeholder : this.placeholder || ''
6520 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6521 input.maxLength = this.maxLength;
6525 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6529 input.cols = this.cols;
6532 if (this.readOnly) {
6533 input.readonly = true;
6537 input.name = this.name;
6541 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6545 ['xs','sm','md','lg'].map(function(size){
6546 if (settings[size]) {
6547 cfg.cls += ' col-' + size + '-' + settings[size];
6551 var inputblock = input;
6553 if (this.before || this.after) {
6556 cls : 'input-group',
6560 inputblock.cn.push({
6562 cls : 'input-group-addon',
6566 inputblock.cn.push(input);
6568 inputblock.cn.push({
6570 cls : 'input-group-addon',
6577 if (align ==='left' && this.fieldLabel.length) {
6578 Roo.log("left and has label");
6584 cls : 'control-label col-sm-' + this.labelWidth,
6585 html : this.fieldLabel
6589 cls : "col-sm-" + (12 - this.labelWidth),
6596 } else if ( this.fieldLabel.length) {
6602 //cls : 'input-group-addon',
6603 html : this.fieldLabel
6613 Roo.log(" no label && no align");
6623 if (this.disabled) {
6624 input.disabled=true;
6631 * return the real textarea element.
6633 inputEl: function ()
6635 return this.el.select('textarea.form-control',true).first();
6643 * trigger field - base class for combo..
6648 * @class Roo.bootstrap.TriggerField
6649 * @extends Roo.bootstrap.Input
6650 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6651 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6652 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6653 * for which you can provide a custom implementation. For example:
6655 var trigger = new Roo.bootstrap.TriggerField();
6656 trigger.onTriggerClick = myTriggerFn;
6657 trigger.applyTo('my-field');
6660 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6661 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6662 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6663 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6665 * Create a new TriggerField.
6666 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6667 * to the base TextField)
6669 Roo.bootstrap.TriggerField = function(config){
6670 this.mimicing = false;
6671 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6674 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6676 * @cfg {String} triggerClass A CSS class to apply to the trigger
6679 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6683 /** @cfg {Boolean} grow @hide */
6684 /** @cfg {Number} growMin @hide */
6685 /** @cfg {Number} growMax @hide */
6691 autoSize: Roo.emptyFn,
6698 actionMode : 'wrap',
6702 getAutoCreate : function(){
6704 var parent = this.parent();
6706 var align = this.labelAlign || this.parentLabelAlign();
6711 cls: 'form-group' //input-group
6718 type : this.inputType,
6719 cls : 'form-control',
6720 autocomplete: 'off',
6721 placeholder : this.placeholder || ''
6725 input.name = this.name;
6728 input.cls += ' input-' + this.size;
6731 if (this.disabled) {
6732 input.disabled=true;
6735 var inputblock = input;
6737 if (this.before || this.after) {
6740 cls : 'input-group',
6744 inputblock.cn.push({
6746 cls : 'input-group-addon',
6750 inputblock.cn.push(input);
6752 inputblock.cn.push({
6754 cls : 'input-group-addon',
6767 cls: 'form-hidden-field'
6775 Roo.log('multiple');
6783 cls: 'form-hidden-field'
6787 cls: 'select2-choices',
6791 cls: 'select2-search-field',
6804 cls: 'select2-container input-group',
6809 cls: 'typeahead typeahead-long dropdown-menu',
6810 style: 'display:none'
6818 cls : 'input-group-addon btn dropdown-toggle',
6826 cls: 'combobox-clear',
6840 combobox.cls += ' select2-container-multi';
6843 if (align ==='left' && this.fieldLabel.length) {
6845 Roo.log("left and has label");
6851 cls : 'control-label col-sm-' + this.labelWidth,
6852 html : this.fieldLabel
6856 cls : "col-sm-" + (12 - this.labelWidth),
6863 } else if ( this.fieldLabel.length) {
6869 //cls : 'input-group-addon',
6870 html : this.fieldLabel
6880 Roo.log(" no label && no align");
6887 ['xs','sm','md','lg'].map(function(size){
6888 if (settings[size]) {
6889 cfg.cls += ' col-' + size + '-' + settings[size];
6900 onResize : function(w, h){
6901 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6902 // if(typeof w == 'number'){
6903 // var x = w - this.trigger.getWidth();
6904 // this.inputEl().setWidth(this.adjustWidth('input', x));
6905 // this.trigger.setStyle('left', x+'px');
6910 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6913 getResizeEl : function(){
6914 return this.inputEl();
6918 getPositionEl : function(){
6919 return this.inputEl();
6923 alignErrorIcon : function(){
6924 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6928 initEvents : function(){
6930 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6931 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6933 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6934 if(this.hideTrigger){
6935 this.trigger.setDisplayed(false);
6937 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6941 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6944 //this.trigger.addClassOnOver('x-form-trigger-over');
6945 //this.trigger.addClassOnClick('x-form-trigger-click');
6948 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6953 initTrigger : function(){
6958 onDestroy : function(){
6960 this.trigger.removeAllListeners();
6961 // this.trigger.remove();
6964 // this.wrap.remove();
6966 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6970 onFocus : function(){
6971 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6974 this.wrap.addClass('x-trigger-wrap-focus');
6975 this.mimicing = true;
6976 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6977 if(this.monitorTab){
6978 this.el.on("keydown", this.checkTab, this);
6985 checkTab : function(e){
6986 if(e.getKey() == e.TAB){
6992 onBlur : function(){
6997 mimicBlur : function(e, t){
6999 if(!this.wrap.contains(t) && this.validateBlur()){
7006 triggerBlur : function(){
7007 this.mimicing = false;
7008 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7009 if(this.monitorTab){
7010 this.el.un("keydown", this.checkTab, this);
7012 //this.wrap.removeClass('x-trigger-wrap-focus');
7013 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7017 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7018 validateBlur : function(e, t){
7023 onDisable : function(){
7024 this.inputEl().dom.disabled = true;
7025 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7027 // this.wrap.addClass('x-item-disabled');
7032 onEnable : function(){
7033 this.inputEl().dom.disabled = false;
7034 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7036 // this.el.removeClass('x-item-disabled');
7041 onShow : function(){
7042 var ae = this.getActionEl();
7045 ae.dom.style.display = '';
7046 ae.dom.style.visibility = 'visible';
7052 onHide : function(){
7053 var ae = this.getActionEl();
7054 ae.dom.style.display = 'none';
7058 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7059 * by an implementing function.
7061 * @param {EventObject} e
7063 onTriggerClick : Roo.emptyFn
7067 * Ext JS Library 1.1.1
7068 * Copyright(c) 2006-2007, Ext JS, LLC.
7070 * Originally Released Under LGPL - original licence link has changed is not relivant.
7073 * <script type="text/javascript">
7078 * @class Roo.data.SortTypes
7080 * Defines the default sorting (casting?) comparison functions used when sorting data.
7082 Roo.data.SortTypes = {
7084 * Default sort that does nothing
7085 * @param {Mixed} s The value being converted
7086 * @return {Mixed} The comparison value
7093 * The regular expression used to strip tags
7097 stripTagsRE : /<\/?[^>]+>/gi,
7100 * Strips all HTML tags to sort on text only
7101 * @param {Mixed} s The value being converted
7102 * @return {String} The comparison value
7104 asText : function(s){
7105 return String(s).replace(this.stripTagsRE, "");
7109 * Strips all HTML tags to sort on text only - Case insensitive
7110 * @param {Mixed} s The value being converted
7111 * @return {String} The comparison value
7113 asUCText : function(s){
7114 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7118 * Case insensitive string
7119 * @param {Mixed} s The value being converted
7120 * @return {String} The comparison value
7122 asUCString : function(s) {
7123 return String(s).toUpperCase();
7128 * @param {Mixed} s The value being converted
7129 * @return {Number} The comparison value
7131 asDate : function(s) {
7135 if(s instanceof Date){
7138 return Date.parse(String(s));
7143 * @param {Mixed} s The value being converted
7144 * @return {Float} The comparison value
7146 asFloat : function(s) {
7147 var val = parseFloat(String(s).replace(/,/g, ""));
7148 if(isNaN(val)) val = 0;
7154 * @param {Mixed} s The value being converted
7155 * @return {Number} The comparison value
7157 asInt : function(s) {
7158 var val = parseInt(String(s).replace(/,/g, ""));
7159 if(isNaN(val)) val = 0;
7164 * Ext JS Library 1.1.1
7165 * Copyright(c) 2006-2007, Ext JS, LLC.
7167 * Originally Released Under LGPL - original licence link has changed is not relivant.
7170 * <script type="text/javascript">
7174 * @class Roo.data.Record
7175 * Instances of this class encapsulate both record <em>definition</em> information, and record
7176 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7177 * to access Records cached in an {@link Roo.data.Store} object.<br>
7179 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7180 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7183 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7185 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7186 * {@link #create}. The parameters are the same.
7187 * @param {Array} data An associative Array of data values keyed by the field name.
7188 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7189 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7190 * not specified an integer id is generated.
7192 Roo.data.Record = function(data, id){
7193 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7198 * Generate a constructor for a specific record layout.
7199 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7200 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7201 * Each field definition object may contain the following properties: <ul>
7202 * <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,
7203 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7204 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7205 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7206 * is being used, then this is a string containing the javascript expression to reference the data relative to
7207 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7208 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7209 * this may be omitted.</p></li>
7210 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7211 * <ul><li>auto (Default, implies no conversion)</li>
7216 * <li>date</li></ul></p></li>
7217 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7218 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7219 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7220 * by the Reader into an object that will be stored in the Record. It is passed the
7221 * following parameters:<ul>
7222 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7224 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7226 * <br>usage:<br><pre><code>
7227 var TopicRecord = Roo.data.Record.create(
7228 {name: 'title', mapping: 'topic_title'},
7229 {name: 'author', mapping: 'username'},
7230 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7231 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7232 {name: 'lastPoster', mapping: 'user2'},
7233 {name: 'excerpt', mapping: 'post_text'}
7236 var myNewRecord = new TopicRecord({
7237 title: 'Do my job please',
7240 lastPost: new Date(),
7241 lastPoster: 'Animal',
7242 excerpt: 'No way dude!'
7244 myStore.add(myNewRecord);
7249 Roo.data.Record.create = function(o){
7251 f.superclass.constructor.apply(this, arguments);
7253 Roo.extend(f, Roo.data.Record);
7254 var p = f.prototype;
7255 p.fields = new Roo.util.MixedCollection(false, function(field){
7258 for(var i = 0, len = o.length; i < len; i++){
7259 p.fields.add(new Roo.data.Field(o[i]));
7261 f.getField = function(name){
7262 return p.fields.get(name);
7267 Roo.data.Record.AUTO_ID = 1000;
7268 Roo.data.Record.EDIT = 'edit';
7269 Roo.data.Record.REJECT = 'reject';
7270 Roo.data.Record.COMMIT = 'commit';
7272 Roo.data.Record.prototype = {
7274 * Readonly flag - true if this record has been modified.
7283 join : function(store){
7288 * Set the named field to the specified value.
7289 * @param {String} name The name of the field to set.
7290 * @param {Object} value The value to set the field to.
7292 set : function(name, value){
7293 if(this.data[name] == value){
7300 if(typeof this.modified[name] == 'undefined'){
7301 this.modified[name] = this.data[name];
7303 this.data[name] = value;
7304 if(!this.editing && this.store){
7305 this.store.afterEdit(this);
7310 * Get the value of the named field.
7311 * @param {String} name The name of the field to get the value of.
7312 * @return {Object} The value of the field.
7314 get : function(name){
7315 return this.data[name];
7319 beginEdit : function(){
7320 this.editing = true;
7325 cancelEdit : function(){
7326 this.editing = false;
7327 delete this.modified;
7331 endEdit : function(){
7332 this.editing = false;
7333 if(this.dirty && this.store){
7334 this.store.afterEdit(this);
7339 * Usually called by the {@link Roo.data.Store} which owns the Record.
7340 * Rejects all changes made to the Record since either creation, or the last commit operation.
7341 * Modified fields are reverted to their original values.
7343 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7344 * of reject operations.
7346 reject : function(){
7347 var m = this.modified;
7349 if(typeof m[n] != "function"){
7350 this.data[n] = m[n];
7354 delete this.modified;
7355 this.editing = false;
7357 this.store.afterReject(this);
7362 * Usually called by the {@link Roo.data.Store} which owns the Record.
7363 * Commits all changes made to the Record since either creation, or the last commit operation.
7365 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7366 * of commit operations.
7368 commit : function(){
7370 delete this.modified;
7371 this.editing = false;
7373 this.store.afterCommit(this);
7378 hasError : function(){
7379 return this.error != null;
7383 clearError : function(){
7388 * Creates a copy of this record.
7389 * @param {String} id (optional) A new record id if you don't want to use this record's id
7392 copy : function(newId) {
7393 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7397 * Ext JS Library 1.1.1
7398 * Copyright(c) 2006-2007, Ext JS, LLC.
7400 * Originally Released Under LGPL - original licence link has changed is not relivant.
7403 * <script type="text/javascript">
7409 * @class Roo.data.Store
7410 * @extends Roo.util.Observable
7411 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7412 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7414 * 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
7415 * has no knowledge of the format of the data returned by the Proxy.<br>
7417 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7418 * instances from the data object. These records are cached and made available through accessor functions.
7420 * Creates a new Store.
7421 * @param {Object} config A config object containing the objects needed for the Store to access data,
7422 * and read the data into Records.
7424 Roo.data.Store = function(config){
7425 this.data = new Roo.util.MixedCollection(false);
7426 this.data.getKey = function(o){
7429 this.baseParams = {};
7436 "multisort" : "_multisort"
7439 if(config && config.data){
7440 this.inlineData = config.data;
7444 Roo.apply(this, config);
7446 if(this.reader){ // reader passed
7447 this.reader = Roo.factory(this.reader, Roo.data);
7448 this.reader.xmodule = this.xmodule || false;
7449 if(!this.recordType){
7450 this.recordType = this.reader.recordType;
7452 if(this.reader.onMetaChange){
7453 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7457 if(this.recordType){
7458 this.fields = this.recordType.prototype.fields;
7464 * @event datachanged
7465 * Fires when the data cache has changed, and a widget which is using this Store
7466 * as a Record cache should refresh its view.
7467 * @param {Store} this
7472 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7473 * @param {Store} this
7474 * @param {Object} meta The JSON metadata
7479 * Fires when Records have been added to the Store
7480 * @param {Store} this
7481 * @param {Roo.data.Record[]} records The array of Records added
7482 * @param {Number} index The index at which the record(s) were added
7487 * Fires when a Record has been removed from the Store
7488 * @param {Store} this
7489 * @param {Roo.data.Record} record The Record that was removed
7490 * @param {Number} index The index at which the record was removed
7495 * Fires when a Record has been updated
7496 * @param {Store} this
7497 * @param {Roo.data.Record} record The Record that was updated
7498 * @param {String} operation The update operation being performed. Value may be one of:
7500 Roo.data.Record.EDIT
7501 Roo.data.Record.REJECT
7502 Roo.data.Record.COMMIT
7508 * Fires when the data cache has been cleared.
7509 * @param {Store} this
7514 * Fires before a request is made for a new data object. If the beforeload handler returns false
7515 * the load action will be canceled.
7516 * @param {Store} this
7517 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7521 * @event beforeloadadd
7522 * Fires after a new set of Records has been loaded.
7523 * @param {Store} this
7524 * @param {Roo.data.Record[]} records The Records that were loaded
7525 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7527 beforeloadadd : true,
7530 * Fires after a new set of Records has been loaded, before they are added to the store.
7531 * @param {Store} this
7532 * @param {Roo.data.Record[]} records The Records that were loaded
7533 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7534 * @params {Object} return from reader
7538 * @event loadexception
7539 * Fires if an exception occurs in the Proxy during loading.
7540 * Called with the signature of the Proxy's "loadexception" event.
7541 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7544 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7545 * @param {Object} load options
7546 * @param {Object} jsonData from your request (normally this contains the Exception)
7548 loadexception : true
7552 this.proxy = Roo.factory(this.proxy, Roo.data);
7553 this.proxy.xmodule = this.xmodule || false;
7554 this.relayEvents(this.proxy, ["loadexception"]);
7556 this.sortToggle = {};
7557 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7559 Roo.data.Store.superclass.constructor.call(this);
7561 if(this.inlineData){
7562 this.loadData(this.inlineData);
7563 delete this.inlineData;
7567 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7569 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7570 * without a remote query - used by combo/forms at present.
7574 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7577 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7580 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7581 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7584 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7585 * on any HTTP request
7588 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7591 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7595 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7596 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7601 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7602 * loaded or when a record is removed. (defaults to false).
7604 pruneModifiedRecords : false,
7610 * Add Records to the Store and fires the add event.
7611 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7613 add : function(records){
7614 records = [].concat(records);
7615 for(var i = 0, len = records.length; i < len; i++){
7616 records[i].join(this);
7618 var index = this.data.length;
7619 this.data.addAll(records);
7620 this.fireEvent("add", this, records, index);
7624 * Remove a Record from the Store and fires the remove event.
7625 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7627 remove : function(record){
7628 var index = this.data.indexOf(record);
7629 this.data.removeAt(index);
7630 if(this.pruneModifiedRecords){
7631 this.modified.remove(record);
7633 this.fireEvent("remove", this, record, index);
7637 * Remove all Records from the Store and fires the clear event.
7639 removeAll : function(){
7641 if(this.pruneModifiedRecords){
7644 this.fireEvent("clear", this);
7648 * Inserts Records to the Store at the given index and fires the add event.
7649 * @param {Number} index The start index at which to insert the passed Records.
7650 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7652 insert : function(index, records){
7653 records = [].concat(records);
7654 for(var i = 0, len = records.length; i < len; i++){
7655 this.data.insert(index, records[i]);
7656 records[i].join(this);
7658 this.fireEvent("add", this, records, index);
7662 * Get the index within the cache of the passed Record.
7663 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7664 * @return {Number} The index of the passed Record. Returns -1 if not found.
7666 indexOf : function(record){
7667 return this.data.indexOf(record);
7671 * Get the index within the cache of the Record with the passed id.
7672 * @param {String} id The id of the Record to find.
7673 * @return {Number} The index of the Record. Returns -1 if not found.
7675 indexOfId : function(id){
7676 return this.data.indexOfKey(id);
7680 * Get the Record with the specified id.
7681 * @param {String} id The id of the Record to find.
7682 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7684 getById : function(id){
7685 return this.data.key(id);
7689 * Get the Record at the specified index.
7690 * @param {Number} index The index of the Record to find.
7691 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7693 getAt : function(index){
7694 return this.data.itemAt(index);
7698 * Returns a range of Records between specified indices.
7699 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7700 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7701 * @return {Roo.data.Record[]} An array of Records
7703 getRange : function(start, end){
7704 return this.data.getRange(start, end);
7708 storeOptions : function(o){
7709 o = Roo.apply({}, o);
7712 this.lastOptions = o;
7716 * Loads the Record cache from the configured Proxy using the configured Reader.
7718 * If using remote paging, then the first load call must specify the <em>start</em>
7719 * and <em>limit</em> properties in the options.params property to establish the initial
7720 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7722 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7723 * and this call will return before the new data has been loaded. Perform any post-processing
7724 * in a callback function, or in a "load" event handler.</strong>
7726 * @param {Object} options An object containing properties which control loading options:<ul>
7727 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7728 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7729 * passed the following arguments:<ul>
7730 * <li>r : Roo.data.Record[]</li>
7731 * <li>options: Options object from the load call</li>
7732 * <li>success: Boolean success indicator</li></ul></li>
7733 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7734 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7737 load : function(options){
7738 options = options || {};
7739 if(this.fireEvent("beforeload", this, options) !== false){
7740 this.storeOptions(options);
7741 var p = Roo.apply(options.params || {}, this.baseParams);
7742 // if meta was not loaded from remote source.. try requesting it.
7743 if (!this.reader.metaFromRemote) {
7746 if(this.sortInfo && this.remoteSort){
7747 var pn = this.paramNames;
7748 p[pn["sort"]] = this.sortInfo.field;
7749 p[pn["dir"]] = this.sortInfo.direction;
7751 if (this.multiSort) {
7752 var pn = this.paramNames;
7753 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7756 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7761 * Reloads the Record cache from the configured Proxy using the configured Reader and
7762 * the options from the last load operation performed.
7763 * @param {Object} options (optional) An object containing properties which may override the options
7764 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7765 * the most recently used options are reused).
7767 reload : function(options){
7768 this.load(Roo.applyIf(options||{}, this.lastOptions));
7772 // Called as a callback by the Reader during a load operation.
7773 loadRecords : function(o, options, success){
7774 if(!o || success === false){
7775 if(success !== false){
7776 this.fireEvent("load", this, [], options, o);
7778 if(options.callback){
7779 options.callback.call(options.scope || this, [], options, false);
7783 // if data returned failure - throw an exception.
7784 if (o.success === false) {
7785 // show a message if no listener is registered.
7786 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7787 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7789 // loadmask wil be hooked into this..
7790 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7793 var r = o.records, t = o.totalRecords || r.length;
7795 this.fireEvent("beforeloadadd", this, r, options, o);
7797 if(!options || options.add !== true){
7798 if(this.pruneModifiedRecords){
7801 for(var i = 0, len = r.length; i < len; i++){
7805 this.data = this.snapshot;
7806 delete this.snapshot;
7809 this.data.addAll(r);
7810 this.totalLength = t;
7812 this.fireEvent("datachanged", this);
7814 this.totalLength = Math.max(t, this.data.length+r.length);
7817 this.fireEvent("load", this, r, options, o);
7818 if(options.callback){
7819 options.callback.call(options.scope || this, r, options, true);
7825 * Loads data from a passed data block. A Reader which understands the format of the data
7826 * must have been configured in the constructor.
7827 * @param {Object} data The data block from which to read the Records. The format of the data expected
7828 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7829 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7831 loadData : function(o, append){
7832 var r = this.reader.readRecords(o);
7833 this.loadRecords(r, {add: append}, true);
7837 * Gets the number of cached records.
7839 * <em>If using paging, this may not be the total size of the dataset. If the data object
7840 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7841 * the data set size</em>
7843 getCount : function(){
7844 return this.data.length || 0;
7848 * Gets the total number of records in the dataset as returned by the server.
7850 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7851 * the dataset size</em>
7853 getTotalCount : function(){
7854 return this.totalLength || 0;
7858 * Returns the sort state of the Store as an object with two properties:
7860 field {String} The name of the field by which the Records are sorted
7861 direction {String} The sort order, "ASC" or "DESC"
7864 getSortState : function(){
7865 return this.sortInfo;
7869 applySort : function(){
7870 if(this.sortInfo && !this.remoteSort){
7871 var s = this.sortInfo, f = s.field;
7872 var st = this.fields.get(f).sortType;
7873 var fn = function(r1, r2){
7874 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7875 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7877 this.data.sort(s.direction, fn);
7878 if(this.snapshot && this.snapshot != this.data){
7879 this.snapshot.sort(s.direction, fn);
7885 * Sets the default sort column and order to be used by the next load operation.
7886 * @param {String} fieldName The name of the field to sort by.
7887 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7889 setDefaultSort : function(field, dir){
7890 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7895 * If remote sorting is used, the sort is performed on the server, and the cache is
7896 * reloaded. If local sorting is used, the cache is sorted internally.
7897 * @param {String} fieldName The name of the field to sort by.
7898 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7900 sort : function(fieldName, dir){
7901 var f = this.fields.get(fieldName);
7903 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7905 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7906 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7911 this.sortToggle[f.name] = dir;
7912 this.sortInfo = {field: f.name, direction: dir};
7913 if(!this.remoteSort){
7915 this.fireEvent("datachanged", this);
7917 this.load(this.lastOptions);
7922 * Calls the specified function for each of the Records in the cache.
7923 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7924 * Returning <em>false</em> aborts and exits the iteration.
7925 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7927 each : function(fn, scope){
7928 this.data.each(fn, scope);
7932 * Gets all records modified since the last commit. Modified records are persisted across load operations
7933 * (e.g., during paging).
7934 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7936 getModifiedRecords : function(){
7937 return this.modified;
7941 createFilterFn : function(property, value, anyMatch){
7942 if(!value.exec){ // not a regex
7943 value = String(value);
7944 if(value.length == 0){
7947 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7950 return value.test(r.data[property]);
7955 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7956 * @param {String} property A field on your records
7957 * @param {Number} start The record index to start at (defaults to 0)
7958 * @param {Number} end The last record index to include (defaults to length - 1)
7959 * @return {Number} The sum
7961 sum : function(property, start, end){
7962 var rs = this.data.items, v = 0;
7964 end = (end || end === 0) ? end : rs.length-1;
7966 for(var i = start; i <= end; i++){
7967 v += (rs[i].data[property] || 0);
7973 * Filter the records by a specified property.
7974 * @param {String} field A field on your records
7975 * @param {String/RegExp} value Either a string that the field
7976 * should start with or a RegExp to test against the field
7977 * @param {Boolean} anyMatch True to match any part not just the beginning
7979 filter : function(property, value, anyMatch){
7980 var fn = this.createFilterFn(property, value, anyMatch);
7981 return fn ? this.filterBy(fn) : this.clearFilter();
7985 * Filter by a function. The specified function will be called with each
7986 * record in this data source. If the function returns true the record is included,
7987 * otherwise it is filtered.
7988 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7989 * @param {Object} scope (optional) The scope of the function (defaults to this)
7991 filterBy : function(fn, scope){
7992 this.snapshot = this.snapshot || this.data;
7993 this.data = this.queryBy(fn, scope||this);
7994 this.fireEvent("datachanged", this);
7998 * Query the records by a specified property.
7999 * @param {String} field A field on your records
8000 * @param {String/RegExp} value Either a string that the field
8001 * should start with or a RegExp to test against the field
8002 * @param {Boolean} anyMatch True to match any part not just the beginning
8003 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8005 query : function(property, value, anyMatch){
8006 var fn = this.createFilterFn(property, value, anyMatch);
8007 return fn ? this.queryBy(fn) : this.data.clone();
8011 * Query by a function. The specified function will be called with each
8012 * record in this data source. If the function returns true the record is included
8014 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8015 * @param {Object} scope (optional) The scope of the function (defaults to this)
8016 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8018 queryBy : function(fn, scope){
8019 var data = this.snapshot || this.data;
8020 return data.filterBy(fn, scope||this);
8024 * Collects unique values for a particular dataIndex from this store.
8025 * @param {String} dataIndex The property to collect
8026 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8027 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8028 * @return {Array} An array of the unique values
8030 collect : function(dataIndex, allowNull, bypassFilter){
8031 var d = (bypassFilter === true && this.snapshot) ?
8032 this.snapshot.items : this.data.items;
8033 var v, sv, r = [], l = {};
8034 for(var i = 0, len = d.length; i < len; i++){
8035 v = d[i].data[dataIndex];
8037 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8046 * Revert to a view of the Record cache with no filtering applied.
8047 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8049 clearFilter : function(suppressEvent){
8050 if(this.snapshot && this.snapshot != this.data){
8051 this.data = this.snapshot;
8052 delete this.snapshot;
8053 if(suppressEvent !== true){
8054 this.fireEvent("datachanged", this);
8060 afterEdit : function(record){
8061 if(this.modified.indexOf(record) == -1){
8062 this.modified.push(record);
8064 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8068 afterReject : function(record){
8069 this.modified.remove(record);
8070 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8074 afterCommit : function(record){
8075 this.modified.remove(record);
8076 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8080 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8081 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8083 commitChanges : function(){
8084 var m = this.modified.slice(0);
8086 for(var i = 0, len = m.length; i < len; i++){
8092 * Cancel outstanding changes on all changed records.
8094 rejectChanges : function(){
8095 var m = this.modified.slice(0);
8097 for(var i = 0, len = m.length; i < len; i++){
8102 onMetaChange : function(meta, rtype, o){
8103 this.recordType = rtype;
8104 this.fields = rtype.prototype.fields;
8105 delete this.snapshot;
8106 this.sortInfo = meta.sortInfo || this.sortInfo;
8108 this.fireEvent('metachange', this, this.reader.meta);
8111 moveIndex : function(data, type)
8113 var index = this.indexOf(data);
8115 var newIndex = index + type;
8119 this.insert(newIndex, data);
8124 * Ext JS Library 1.1.1
8125 * Copyright(c) 2006-2007, Ext JS, LLC.
8127 * Originally Released Under LGPL - original licence link has changed is not relivant.
8130 * <script type="text/javascript">
8134 * @class Roo.data.SimpleStore
8135 * @extends Roo.data.Store
8136 * Small helper class to make creating Stores from Array data easier.
8137 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8138 * @cfg {Array} fields An array of field definition objects, or field name strings.
8139 * @cfg {Array} data The multi-dimensional array of data
8141 * @param {Object} config
8143 Roo.data.SimpleStore = function(config){
8144 Roo.data.SimpleStore.superclass.constructor.call(this, {
8146 reader: new Roo.data.ArrayReader({
8149 Roo.data.Record.create(config.fields)
8151 proxy : new Roo.data.MemoryProxy(config.data)
8155 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8157 * Ext JS Library 1.1.1
8158 * Copyright(c) 2006-2007, Ext JS, LLC.
8160 * Originally Released Under LGPL - original licence link has changed is not relivant.
8163 * <script type="text/javascript">
8168 * @extends Roo.data.Store
8169 * @class Roo.data.JsonStore
8170 * Small helper class to make creating Stores for JSON data easier. <br/>
8172 var store = new Roo.data.JsonStore({
8173 url: 'get-images.php',
8175 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8178 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8179 * JsonReader and HttpProxy (unless inline data is provided).</b>
8180 * @cfg {Array} fields An array of field definition objects, or field name strings.
8182 * @param {Object} config
8184 Roo.data.JsonStore = function(c){
8185 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8186 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8187 reader: new Roo.data.JsonReader(c, c.fields)
8190 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8192 * Ext JS Library 1.1.1
8193 * Copyright(c) 2006-2007, Ext JS, LLC.
8195 * Originally Released Under LGPL - original licence link has changed is not relivant.
8198 * <script type="text/javascript">
8202 Roo.data.Field = function(config){
8203 if(typeof config == "string"){
8204 config = {name: config};
8206 Roo.apply(this, config);
8212 var st = Roo.data.SortTypes;
8213 // named sortTypes are supported, here we look them up
8214 if(typeof this.sortType == "string"){
8215 this.sortType = st[this.sortType];
8218 // set default sortType for strings and dates
8222 this.sortType = st.asUCString;
8225 this.sortType = st.asDate;
8228 this.sortType = st.none;
8233 var stripRe = /[\$,%]/g;
8235 // prebuilt conversion function for this field, instead of
8236 // switching every time we're reading a value
8238 var cv, dateFormat = this.dateFormat;
8243 cv = function(v){ return v; };
8246 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8250 return v !== undefined && v !== null && v !== '' ?
8251 parseInt(String(v).replace(stripRe, ""), 10) : '';
8256 return v !== undefined && v !== null && v !== '' ?
8257 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8262 cv = function(v){ return v === true || v === "true" || v == 1; };
8269 if(v instanceof Date){
8273 if(dateFormat == "timestamp"){
8274 return new Date(v*1000);
8276 return Date.parseDate(v, dateFormat);
8278 var parsed = Date.parse(v);
8279 return parsed ? new Date(parsed) : null;
8288 Roo.data.Field.prototype = {
8296 * Ext JS Library 1.1.1
8297 * Copyright(c) 2006-2007, Ext JS, LLC.
8299 * Originally Released Under LGPL - original licence link has changed is not relivant.
8302 * <script type="text/javascript">
8305 // Base class for reading structured data from a data source. This class is intended to be
8306 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8309 * @class Roo.data.DataReader
8310 * Base class for reading structured data from a data source. This class is intended to be
8311 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8314 Roo.data.DataReader = function(meta, recordType){
8318 this.recordType = recordType instanceof Array ?
8319 Roo.data.Record.create(recordType) : recordType;
8322 Roo.data.DataReader.prototype = {
8324 * Create an empty record
8325 * @param {Object} data (optional) - overlay some values
8326 * @return {Roo.data.Record} record created.
8328 newRow : function(d) {
8330 this.recordType.prototype.fields.each(function(c) {
8332 case 'int' : da[c.name] = 0; break;
8333 case 'date' : da[c.name] = new Date(); break;
8334 case 'float' : da[c.name] = 0.0; break;
8335 case 'boolean' : da[c.name] = false; break;
8336 default : da[c.name] = ""; break;
8340 return new this.recordType(Roo.apply(da, d));
8345 * Ext JS Library 1.1.1
8346 * Copyright(c) 2006-2007, Ext JS, LLC.
8348 * Originally Released Under LGPL - original licence link has changed is not relivant.
8351 * <script type="text/javascript">
8355 * @class Roo.data.DataProxy
8356 * @extends Roo.data.Observable
8357 * This class is an abstract base class for implementations which provide retrieval of
8358 * unformatted data objects.<br>
8360 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8361 * (of the appropriate type which knows how to parse the data object) to provide a block of
8362 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8364 * Custom implementations must implement the load method as described in
8365 * {@link Roo.data.HttpProxy#load}.
8367 Roo.data.DataProxy = function(){
8371 * Fires before a network request is made to retrieve a data object.
8372 * @param {Object} This DataProxy object.
8373 * @param {Object} params The params parameter to the load function.
8378 * Fires before the load method's callback is called.
8379 * @param {Object} This DataProxy object.
8380 * @param {Object} o The data object.
8381 * @param {Object} arg The callback argument object passed to the load function.
8385 * @event loadexception
8386 * Fires if an Exception occurs during data retrieval.
8387 * @param {Object} This DataProxy object.
8388 * @param {Object} o The data object.
8389 * @param {Object} arg The callback argument object passed to the load function.
8390 * @param {Object} e The Exception.
8392 loadexception : true
8394 Roo.data.DataProxy.superclass.constructor.call(this);
8397 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8400 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8404 * Ext JS Library 1.1.1
8405 * Copyright(c) 2006-2007, Ext JS, LLC.
8407 * Originally Released Under LGPL - original licence link has changed is not relivant.
8410 * <script type="text/javascript">
8413 * @class Roo.data.MemoryProxy
8414 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8415 * to the Reader when its load method is called.
8417 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8419 Roo.data.MemoryProxy = function(data){
8423 Roo.data.MemoryProxy.superclass.constructor.call(this);
8427 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8429 * Load data from the requested source (in this case an in-memory
8430 * data object passed to the constructor), read the data object into
8431 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8432 * process that block using the passed callback.
8433 * @param {Object} params This parameter is not used by the MemoryProxy class.
8434 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8435 * object into a block of Roo.data.Records.
8436 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8437 * The function must be passed <ul>
8438 * <li>The Record block object</li>
8439 * <li>The "arg" argument from the load function</li>
8440 * <li>A boolean success indicator</li>
8442 * @param {Object} scope The scope in which to call the callback
8443 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8445 load : function(params, reader, callback, scope, arg){
8446 params = params || {};
8449 result = reader.readRecords(this.data);
8451 this.fireEvent("loadexception", this, arg, null, e);
8452 callback.call(scope, null, arg, false);
8455 callback.call(scope, result, arg, true);
8459 update : function(params, records){
8464 * Ext JS Library 1.1.1
8465 * Copyright(c) 2006-2007, Ext JS, LLC.
8467 * Originally Released Under LGPL - original licence link has changed is not relivant.
8470 * <script type="text/javascript">
8473 * @class Roo.data.HttpProxy
8474 * @extends Roo.data.DataProxy
8475 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8476 * configured to reference a certain URL.<br><br>
8478 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8479 * from which the running page was served.<br><br>
8481 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8483 * Be aware that to enable the browser to parse an XML document, the server must set
8484 * the Content-Type header in the HTTP response to "text/xml".
8486 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8487 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8488 * will be used to make the request.
8490 Roo.data.HttpProxy = function(conn){
8491 Roo.data.HttpProxy.superclass.constructor.call(this);
8492 // is conn a conn config or a real conn?
8494 this.useAjax = !conn || !conn.events;
8498 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8499 // thse are take from connection...
8502 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8505 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8506 * extra parameters to each request made by this object. (defaults to undefined)
8509 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8510 * to each request made by this object. (defaults to undefined)
8513 * @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)
8516 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8519 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8525 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8529 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8530 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8531 * a finer-grained basis than the DataProxy events.
8533 getConnection : function(){
8534 return this.useAjax ? Roo.Ajax : this.conn;
8538 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8539 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8540 * process that block using the passed callback.
8541 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8542 * for the request to the remote server.
8543 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8544 * object into a block of Roo.data.Records.
8545 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8546 * The function must be passed <ul>
8547 * <li>The Record block object</li>
8548 * <li>The "arg" argument from the load function</li>
8549 * <li>A boolean success indicator</li>
8551 * @param {Object} scope The scope in which to call the callback
8552 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8554 load : function(params, reader, callback, scope, arg){
8555 if(this.fireEvent("beforeload", this, params) !== false){
8557 params : params || {},
8559 callback : callback,
8564 callback : this.loadResponse,
8568 Roo.applyIf(o, this.conn);
8569 if(this.activeRequest){
8570 Roo.Ajax.abort(this.activeRequest);
8572 this.activeRequest = Roo.Ajax.request(o);
8574 this.conn.request(o);
8577 callback.call(scope||this, null, arg, false);
8582 loadResponse : function(o, success, response){
8583 delete this.activeRequest;
8585 this.fireEvent("loadexception", this, o, response);
8586 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8591 result = o.reader.read(response);
8593 this.fireEvent("loadexception", this, o, response, e);
8594 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8598 this.fireEvent("load", this, o, o.request.arg);
8599 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8603 update : function(dataSet){
8608 updateResponse : function(dataSet){
8613 * Ext JS Library 1.1.1
8614 * Copyright(c) 2006-2007, Ext JS, LLC.
8616 * Originally Released Under LGPL - original licence link has changed is not relivant.
8619 * <script type="text/javascript">
8623 * @class Roo.data.ScriptTagProxy
8624 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8625 * other than the originating domain of the running page.<br><br>
8627 * <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
8628 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8630 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8631 * source code that is used as the source inside a <script> tag.<br><br>
8633 * In order for the browser to process the returned data, the server must wrap the data object
8634 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8635 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8636 * depending on whether the callback name was passed:
8639 boolean scriptTag = false;
8640 String cb = request.getParameter("callback");
8643 response.setContentType("text/javascript");
8645 response.setContentType("application/x-json");
8647 Writer out = response.getWriter();
8649 out.write(cb + "(");
8651 out.print(dataBlock.toJsonString());
8658 * @param {Object} config A configuration object.
8660 Roo.data.ScriptTagProxy = function(config){
8661 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8662 Roo.apply(this, config);
8663 this.head = document.getElementsByTagName("head")[0];
8666 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8668 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8670 * @cfg {String} url The URL from which to request the data object.
8673 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8677 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8678 * the server the name of the callback function set up by the load call to process the returned data object.
8679 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8680 * javascript output which calls this named function passing the data object as its only parameter.
8682 callbackParam : "callback",
8684 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8685 * name to the request.
8690 * Load data from the configured URL, read the data object into
8691 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8692 * process that block using the passed callback.
8693 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8694 * for the request to the remote server.
8695 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8696 * object into a block of Roo.data.Records.
8697 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8698 * The function must be passed <ul>
8699 * <li>The Record block object</li>
8700 * <li>The "arg" argument from the load function</li>
8701 * <li>A boolean success indicator</li>
8703 * @param {Object} scope The scope in which to call the callback
8704 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8706 load : function(params, reader, callback, scope, arg){
8707 if(this.fireEvent("beforeload", this, params) !== false){
8709 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8712 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8714 url += "&_dc=" + (new Date().getTime());
8716 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8719 cb : "stcCallback"+transId,
8720 scriptId : "stcScript"+transId,
8724 callback : callback,
8730 window[trans.cb] = function(o){
8731 conn.handleResponse(o, trans);
8734 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8736 if(this.autoAbort !== false){
8740 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8742 var script = document.createElement("script");
8743 script.setAttribute("src", url);
8744 script.setAttribute("type", "text/javascript");
8745 script.setAttribute("id", trans.scriptId);
8746 this.head.appendChild(script);
8750 callback.call(scope||this, null, arg, false);
8755 isLoading : function(){
8756 return this.trans ? true : false;
8760 * Abort the current server request.
8763 if(this.isLoading()){
8764 this.destroyTrans(this.trans);
8769 destroyTrans : function(trans, isLoaded){
8770 this.head.removeChild(document.getElementById(trans.scriptId));
8771 clearTimeout(trans.timeoutId);
8773 window[trans.cb] = undefined;
8775 delete window[trans.cb];
8778 // if hasn't been loaded, wait for load to remove it to prevent script error
8779 window[trans.cb] = function(){
8780 window[trans.cb] = undefined;
8782 delete window[trans.cb];
8789 handleResponse : function(o, trans){
8791 this.destroyTrans(trans, true);
8794 result = trans.reader.readRecords(o);
8796 this.fireEvent("loadexception", this, o, trans.arg, e);
8797 trans.callback.call(trans.scope||window, null, trans.arg, false);
8800 this.fireEvent("load", this, o, trans.arg);
8801 trans.callback.call(trans.scope||window, result, trans.arg, true);
8805 handleFailure : function(trans){
8807 this.destroyTrans(trans, false);
8808 this.fireEvent("loadexception", this, null, trans.arg);
8809 trans.callback.call(trans.scope||window, null, trans.arg, false);
8813 * Ext JS Library 1.1.1
8814 * Copyright(c) 2006-2007, Ext JS, LLC.
8816 * Originally Released Under LGPL - original licence link has changed is not relivant.
8819 * <script type="text/javascript">
8823 * @class Roo.data.JsonReader
8824 * @extends Roo.data.DataReader
8825 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8826 * based on mappings in a provided Roo.data.Record constructor.
8828 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8829 * in the reply previously.
8834 var RecordDef = Roo.data.Record.create([
8835 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8836 {name: 'occupation'} // This field will use "occupation" as the mapping.
8838 var myReader = new Roo.data.JsonReader({
8839 totalProperty: "results", // The property which contains the total dataset size (optional)
8840 root: "rows", // The property which contains an Array of row objects
8841 id: "id" // The property within each row object that provides an ID for the record (optional)
8845 * This would consume a JSON file like this:
8847 { 'results': 2, 'rows': [
8848 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8849 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8852 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8853 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8854 * paged from the remote server.
8855 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8856 * @cfg {String} root name of the property which contains the Array of row objects.
8857 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8859 * Create a new JsonReader
8860 * @param {Object} meta Metadata configuration options
8861 * @param {Object} recordType Either an Array of field definition objects,
8862 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8864 Roo.data.JsonReader = function(meta, recordType){
8867 // set some defaults:
8869 totalProperty: 'total',
8870 successProperty : 'success',
8875 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8877 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8880 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8881 * Used by Store query builder to append _requestMeta to params.
8884 metaFromRemote : false,
8886 * This method is only used by a DataProxy which has retrieved data from a remote server.
8887 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8888 * @return {Object} data A data block which is used by an Roo.data.Store object as
8889 * a cache of Roo.data.Records.
8891 read : function(response){
8892 var json = response.responseText;
8894 var o = /* eval:var:o */ eval("("+json+")");
8896 throw {message: "JsonReader.read: Json object not found"};
8902 this.metaFromRemote = true;
8903 this.meta = o.metaData;
8904 this.recordType = Roo.data.Record.create(o.metaData.fields);
8905 this.onMetaChange(this.meta, this.recordType, o);
8907 return this.readRecords(o);
8910 // private function a store will implement
8911 onMetaChange : function(meta, recordType, o){
8918 simpleAccess: function(obj, subsc) {
8925 getJsonAccessor: function(){
8927 return function(expr) {
8929 return(re.test(expr))
8930 ? new Function("obj", "return obj." + expr)
8940 * Create a data block containing Roo.data.Records from an XML document.
8941 * @param {Object} o An object which contains an Array of row objects in the property specified
8942 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8943 * which contains the total size of the dataset.
8944 * @return {Object} data A data block which is used by an Roo.data.Store object as
8945 * a cache of Roo.data.Records.
8947 readRecords : function(o){
8949 * After any data loads, the raw JSON data is available for further custom processing.
8953 var s = this.meta, Record = this.recordType,
8954 f = Record.prototype.fields, fi = f.items, fl = f.length;
8956 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8958 if(s.totalProperty) {
8959 this.getTotal = this.getJsonAccessor(s.totalProperty);
8961 if(s.successProperty) {
8962 this.getSuccess = this.getJsonAccessor(s.successProperty);
8964 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8966 var g = this.getJsonAccessor(s.id);
8967 this.getId = function(rec) {
8969 return (r === undefined || r === "") ? null : r;
8972 this.getId = function(){return null;};
8975 for(var jj = 0; jj < fl; jj++){
8977 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8978 this.ef[jj] = this.getJsonAccessor(map);
8982 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8983 if(s.totalProperty){
8984 var vt = parseInt(this.getTotal(o), 10);
8989 if(s.successProperty){
8990 var vs = this.getSuccess(o);
8991 if(vs === false || vs === 'false'){
8996 for(var i = 0; i < c; i++){
8999 var id = this.getId(n);
9000 for(var j = 0; j < fl; j++){
9002 var v = this.ef[j](n);
9004 Roo.log('missing convert for ' + f.name);
9008 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9010 var record = new Record(values, id);
9012 records[i] = record;
9018 totalRecords : totalRecords
9023 * Ext JS Library 1.1.1
9024 * Copyright(c) 2006-2007, Ext JS, LLC.
9026 * Originally Released Under LGPL - original licence link has changed is not relivant.
9029 * <script type="text/javascript">
9033 * @class Roo.data.ArrayReader
9034 * @extends Roo.data.DataReader
9035 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9036 * Each element of that Array represents a row of data fields. The
9037 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9038 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9042 var RecordDef = Roo.data.Record.create([
9043 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9044 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9046 var myReader = new Roo.data.ArrayReader({
9047 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9051 * This would consume an Array like this:
9053 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9055 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9057 * Create a new JsonReader
9058 * @param {Object} meta Metadata configuration options.
9059 * @param {Object} recordType Either an Array of field definition objects
9060 * as specified to {@link Roo.data.Record#create},
9061 * or an {@link Roo.data.Record} object
9062 * created using {@link Roo.data.Record#create}.
9064 Roo.data.ArrayReader = function(meta, recordType){
9065 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9068 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9070 * Create a data block containing Roo.data.Records from an XML document.
9071 * @param {Object} o An Array of row objects which represents the dataset.
9072 * @return {Object} data A data block which is used by an Roo.data.Store object as
9073 * a cache of Roo.data.Records.
9075 readRecords : function(o){
9076 var sid = this.meta ? this.meta.id : null;
9077 var recordType = this.recordType, fields = recordType.prototype.fields;
9080 for(var i = 0; i < root.length; i++){
9083 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9084 for(var j = 0, jlen = fields.length; j < jlen; j++){
9085 var f = fields.items[j];
9086 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9087 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9091 var record = new recordType(values, id);
9093 records[records.length] = record;
9097 totalRecords : records.length
9106 * @class Roo.bootstrap.ComboBox
9107 * @extends Roo.bootstrap.TriggerField
9108 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9109 * @cfg {Boolean} append (true|false) default false
9111 * Create a new ComboBox.
9112 * @param {Object} config Configuration options
9114 Roo.bootstrap.ComboBox = function(config){
9115 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9119 * Fires when the dropdown list is expanded
9120 * @param {Roo.bootstrap.ComboBox} combo This combo box
9125 * Fires when the dropdown list is collapsed
9126 * @param {Roo.bootstrap.ComboBox} combo This combo box
9130 * @event beforeselect
9131 * Fires before a list item is selected. Return false to cancel the selection.
9132 * @param {Roo.bootstrap.ComboBox} combo This combo box
9133 * @param {Roo.data.Record} record The data record returned from the underlying store
9134 * @param {Number} index The index of the selected item in the dropdown list
9136 'beforeselect' : true,
9139 * Fires when a list item is selected
9140 * @param {Roo.bootstrap.ComboBox} combo This combo box
9141 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9142 * @param {Number} index The index of the selected item in the dropdown list
9146 * @event beforequery
9147 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9148 * The event object passed has these properties:
9149 * @param {Roo.bootstrap.ComboBox} combo This combo box
9150 * @param {String} query The query
9151 * @param {Boolean} forceAll true to force "all" query
9152 * @param {Boolean} cancel true to cancel the query
9153 * @param {Object} e The query event object
9155 'beforequery': true,
9158 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9159 * @param {Roo.bootstrap.ComboBox} combo This combo box
9164 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9165 * @param {Roo.bootstrap.ComboBox} combo This combo box
9166 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9171 * Fires when the remove value from the combobox array
9172 * @param {Roo.bootstrap.ComboBox} combo This combo box
9179 this.selectedIndex = -1;
9180 if(this.mode == 'local'){
9181 if(config.queryDelay === undefined){
9182 this.queryDelay = 10;
9184 if(config.minChars === undefined){
9190 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9193 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9194 * rendering into an Roo.Editor, defaults to false)
9197 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9198 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9201 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9204 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9205 * the dropdown list (defaults to undefined, with no header element)
9209 * @cfg {String/Roo.Template} tpl The template to use to render the output
9213 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9215 listWidth: undefined,
9217 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9218 * mode = 'remote' or 'text' if mode = 'local')
9220 displayField: undefined,
9222 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9223 * mode = 'remote' or 'value' if mode = 'local').
9224 * Note: use of a valueField requires the user make a selection
9225 * in order for a value to be mapped.
9227 valueField: undefined,
9231 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9232 * field's data value (defaults to the underlying DOM element's name)
9234 hiddenName: undefined,
9236 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9240 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9242 selectedClass: 'active',
9245 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9249 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9250 * anchor positions (defaults to 'tl-bl')
9252 listAlign: 'tl-bl?',
9254 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9258 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9259 * query specified by the allQuery config option (defaults to 'query')
9261 triggerAction: 'query',
9263 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9264 * (defaults to 4, does not apply if editable = false)
9268 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9269 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9273 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9274 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9278 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9279 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9283 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9284 * when editable = true (defaults to false)
9286 selectOnFocus:false,
9288 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9290 queryParam: 'query',
9292 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9293 * when mode = 'remote' (defaults to 'Loading...')
9295 loadingText: 'Loading...',
9297 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9301 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9305 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9306 * traditional select (defaults to true)
9310 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9314 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9318 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9319 * listWidth has a higher value)
9323 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9324 * allow the user to set arbitrary text into the field (defaults to false)
9326 forceSelection:false,
9328 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9329 * if typeAhead = true (defaults to 250)
9331 typeAheadDelay : 250,
9333 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9334 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9336 valueNotFoundText : undefined,
9338 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9343 * @cfg {Boolean} disableClear Disable showing of clear button.
9345 disableClear : false,
9347 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9349 alwaysQuery : false,
9352 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9366 // element that contains real text value.. (when hidden is used..)
9369 initEvents: function(){
9372 throw "can not find store for combo";
9374 this.store = Roo.factory(this.store, Roo.data);
9378 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9381 if(this.hiddenName){
9383 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9385 this.hiddenField.dom.value =
9386 this.hiddenValue !== undefined ? this.hiddenValue :
9387 this.value !== undefined ? this.value : '';
9389 // prevent input submission
9390 this.el.dom.removeAttribute('name');
9391 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9396 // this.el.dom.setAttribute('autocomplete', 'off');
9399 var cls = 'x-combo-list';
9400 this.list = this.el.select('ul.dropdown-menu',true).first();
9402 //this.list = new Roo.Layer({
9403 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9406 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9407 this.list.setWidth(lw);
9409 this.list.on('mouseover', this.onViewOver, this);
9410 this.list.on('mousemove', this.onViewMove, this);
9412 this.list.on('scroll', this.onViewScroll, this);
9415 this.list.swallowEvent('mousewheel');
9416 this.assetHeight = 0;
9419 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9420 this.assetHeight += this.header.getHeight();
9423 this.innerList = this.list.createChild({cls:cls+'-inner'});
9424 this.innerList.on('mouseover', this.onViewOver, this);
9425 this.innerList.on('mousemove', this.onViewMove, this);
9426 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9428 if(this.allowBlank && !this.pageSize && !this.disableClear){
9429 this.footer = this.list.createChild({cls:cls+'-ft'});
9430 this.pageTb = new Roo.Toolbar(this.footer);
9434 this.footer = this.list.createChild({cls:cls+'-ft'});
9435 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9436 {pageSize: this.pageSize});
9440 if (this.pageTb && this.allowBlank && !this.disableClear) {
9442 this.pageTb.add(new Roo.Toolbar.Fill(), {
9443 cls: 'x-btn-icon x-btn-clear',
9449 _this.onSelect(false, -1);
9454 this.assetHeight += this.footer.getHeight();
9459 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9462 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9463 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9465 //this.view.wrapEl.setDisplayed(false);
9466 this.view.on('click', this.onViewClick, this);
9470 this.store.on('beforeload', this.onBeforeLoad, this);
9471 this.store.on('load', this.onLoad, this);
9472 this.store.on('loadexception', this.onLoadException, this);
9475 this.resizer = new Roo.Resizable(this.list, {
9476 pinned:true, handles:'se'
9478 this.resizer.on('resize', function(r, w, h){
9479 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9481 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9482 this.restrictHeight();
9484 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9488 this.editable = true;
9489 this.setEditable(false);
9494 if (typeof(this.events.add.listeners) != 'undefined') {
9496 this.addicon = this.wrap.createChild(
9497 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9499 this.addicon.on('click', function(e) {
9500 this.fireEvent('add', this);
9503 if (typeof(this.events.edit.listeners) != 'undefined') {
9505 this.editicon = this.wrap.createChild(
9506 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9508 this.editicon.setStyle('margin-left', '40px');
9510 this.editicon.on('click', function(e) {
9512 // we fire even if inothing is selected..
9513 this.fireEvent('edit', this, this.lastData );
9519 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9521 this.inKeyMode = true;
9525 "down" : function(e){
9526 if(!this.isExpanded()){
9527 this.onTriggerClick();
9529 this.inKeyMode = true;
9534 "enter" : function(e){
9539 "esc" : function(e){
9543 "tab" : function(e){
9546 if(this.fireEvent("specialkey", this, e)){
9547 this.onViewClick(false);
9555 doRelay : function(foo, bar, hname){
9556 if(hname == 'down' || this.scope.isExpanded()){
9557 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9566 this.queryDelay = Math.max(this.queryDelay || 10,
9567 this.mode == 'local' ? 10 : 250);
9570 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9573 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9575 if(this.editable !== false){
9576 this.inputEl().on("keyup", this.onKeyUp, this);
9578 if(this.forceSelection){
9579 this.inputEl().on('blur', this.doForce, this);
9583 this.choices = this.el.select('ul.select2-choices', true).first();
9584 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9588 onDestroy : function(){
9590 this.view.setStore(null);
9591 this.view.el.removeAllListeners();
9592 this.view.el.remove();
9593 this.view.purgeListeners();
9596 this.list.dom.innerHTML = '';
9599 this.store.un('beforeload', this.onBeforeLoad, this);
9600 this.store.un('load', this.onLoad, this);
9601 this.store.un('loadexception', this.onLoadException, this);
9603 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9607 fireKey : function(e){
9608 if(e.isNavKeyPress() && !this.list.isVisible()){
9609 this.fireEvent("specialkey", this, e);
9614 onResize: function(w, h){
9615 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9617 // if(typeof w != 'number'){
9618 // // we do not handle it!?!?
9621 // var tw = this.trigger.getWidth();
9622 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9623 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9625 // this.inputEl().setWidth( this.adjustWidth('input', x));
9627 // //this.trigger.setStyle('left', x+'px');
9629 // if(this.list && this.listWidth === undefined){
9630 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9631 // this.list.setWidth(lw);
9632 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9640 * Allow or prevent the user from directly editing the field text. If false is passed,
9641 * the user will only be able to select from the items defined in the dropdown list. This method
9642 * is the runtime equivalent of setting the 'editable' config option at config time.
9643 * @param {Boolean} value True to allow the user to directly edit the field text
9645 setEditable : function(value){
9646 if(value == this.editable){
9649 this.editable = value;
9651 this.inputEl().dom.setAttribute('readOnly', true);
9652 this.inputEl().on('mousedown', this.onTriggerClick, this);
9653 this.inputEl().addClass('x-combo-noedit');
9655 this.inputEl().dom.setAttribute('readOnly', false);
9656 this.inputEl().un('mousedown', this.onTriggerClick, this);
9657 this.inputEl().removeClass('x-combo-noedit');
9663 onBeforeLoad : function(combo,opts){
9668 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9670 this.restrictHeight();
9671 this.selectedIndex = -1;
9675 onLoad : function(){
9677 this.hasQuery = false;
9683 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9684 this.loading.hide();
9687 if(this.store.getCount() > 0){
9689 this.restrictHeight();
9690 if(this.lastQuery == this.allQuery){
9692 this.inputEl().dom.select();
9694 if(!this.selectByValue(this.value, true)){
9695 this.select(0, true);
9699 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9700 this.taTask.delay(this.typeAheadDelay);
9704 this.onEmptyResults();
9710 onLoadException : function()
9712 this.hasQuery = false;
9714 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9715 this.loading.hide();
9719 Roo.log(this.store.reader.jsonData);
9720 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9722 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9728 onTypeAhead : function(){
9729 if(this.store.getCount() > 0){
9730 var r = this.store.getAt(0);
9731 var newValue = r.data[this.displayField];
9732 var len = newValue.length;
9733 var selStart = this.getRawValue().length;
9735 if(selStart != len){
9736 this.setRawValue(newValue);
9737 this.selectText(selStart, newValue.length);
9743 onSelect : function(record, index){
9745 if(this.fireEvent('beforeselect', this, record, index) !== false){
9747 this.setFromData(index > -1 ? record.data : false);
9750 this.fireEvent('select', this, record, index);
9755 * Returns the currently selected field value or empty string if no value is set.
9756 * @return {String} value The selected value
9758 getValue : function(){
9761 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9764 if(this.valueField){
9765 return typeof this.value != 'undefined' ? this.value : '';
9767 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9772 * Clears any text/value currently set in the field
9774 clearValue : function(){
9775 if(this.hiddenField){
9776 this.hiddenField.dom.value = '';
9779 this.setRawValue('');
9780 this.lastSelectionText = '';
9785 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9786 * will be displayed in the field. If the value does not match the data value of an existing item,
9787 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9788 * Otherwise the field will be blank (although the value will still be set).
9789 * @param {String} value The value to match
9791 setValue : function(v){
9798 if(this.valueField){
9799 var r = this.findRecord(this.valueField, v);
9801 text = r.data[this.displayField];
9802 }else if(this.valueNotFoundText !== undefined){
9803 text = this.valueNotFoundText;
9806 this.lastSelectionText = text;
9807 if(this.hiddenField){
9808 this.hiddenField.dom.value = v;
9810 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9814 * @property {Object} the last set data for the element
9819 * Sets the value of the field based on a object which is related to the record format for the store.
9820 * @param {Object} value the value to set as. or false on reset?
9822 setFromData : function(o){
9829 var dv = ''; // display value
9830 var vv = ''; // value value..
9832 if (this.displayField) {
9833 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9835 // this is an error condition!!!
9836 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9839 if(this.valueField){
9840 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9843 if(this.hiddenField){
9844 this.hiddenField.dom.value = vv;
9846 this.lastSelectionText = dv;
9847 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9851 // no hidden field.. - we store the value in 'value', but still display
9852 // display field!!!!
9853 this.lastSelectionText = dv;
9854 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9861 // overridden so that last data is reset..
9862 this.setValue(this.originalValue);
9863 this.clearInvalid();
9864 this.lastData = false;
9866 this.view.clearSelections();
9870 findRecord : function(prop, value){
9872 if(this.store.getCount() > 0){
9873 this.store.each(function(r){
9874 if(r.data[prop] == value){
9886 // returns hidden if it's set..
9887 if (!this.rendered) {return ''};
9888 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9892 onViewMove : function(e, t){
9893 this.inKeyMode = false;
9897 onViewOver : function(e, t){
9898 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9901 var item = this.view.findItemFromChild(t);
9903 var index = this.view.indexOf(item);
9904 this.select(index, false);
9909 onViewClick : function(doFocus)
9911 var index = this.view.getSelectedIndexes()[0];
9912 var r = this.store.getAt(index);
9914 this.onSelect(r, index);
9916 if(doFocus !== false && !this.blockFocus){
9917 this.inputEl().focus();
9922 restrictHeight : function(){
9923 //this.innerList.dom.style.height = '';
9924 //var inner = this.innerList.dom;
9925 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9926 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9927 //this.list.beginUpdate();
9928 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9929 this.list.alignTo(this.inputEl(), this.listAlign);
9930 //this.list.endUpdate();
9934 onEmptyResults : function(){
9939 * Returns true if the dropdown list is expanded, else false.
9941 isExpanded : function(){
9942 return this.list.isVisible();
9946 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9947 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9948 * @param {String} value The data value of the item to select
9949 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9950 * selected item if it is not currently in view (defaults to true)
9951 * @return {Boolean} True if the value matched an item in the list, else false
9953 selectByValue : function(v, scrollIntoView){
9954 if(v !== undefined && v !== null){
9955 var r = this.findRecord(this.valueField || this.displayField, v);
9957 this.select(this.store.indexOf(r), scrollIntoView);
9965 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9966 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9967 * @param {Number} index The zero-based index of the list item to select
9968 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9969 * selected item if it is not currently in view (defaults to true)
9971 select : function(index, scrollIntoView){
9972 this.selectedIndex = index;
9973 this.view.select(index);
9974 if(scrollIntoView !== false){
9975 var el = this.view.getNode(index);
9977 //this.innerList.scrollChildIntoView(el, false);
9984 selectNext : function(){
9985 var ct = this.store.getCount();
9987 if(this.selectedIndex == -1){
9989 }else if(this.selectedIndex < ct-1){
9990 this.select(this.selectedIndex+1);
9996 selectPrev : function(){
9997 var ct = this.store.getCount();
9999 if(this.selectedIndex == -1){
10001 }else if(this.selectedIndex != 0){
10002 this.select(this.selectedIndex-1);
10008 onKeyUp : function(e){
10009 if(this.editable !== false && !e.isSpecialKey()){
10010 this.lastKey = e.getKey();
10011 this.dqTask.delay(this.queryDelay);
10016 validateBlur : function(){
10017 return !this.list || !this.list.isVisible();
10021 initQuery : function(){
10022 this.doQuery(this.getRawValue());
10026 doForce : function(){
10027 if(this.inputEl().dom.value.length > 0){
10028 this.inputEl().dom.value =
10029 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10035 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10036 * query allowing the query action to be canceled if needed.
10037 * @param {String} query The SQL query to execute
10038 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10039 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10040 * saved in the current store (defaults to false)
10042 doQuery : function(q, forceAll){
10044 if(q === undefined || q === null){
10049 forceAll: forceAll,
10053 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10058 forceAll = qe.forceAll;
10059 if(forceAll === true || (q.length >= this.minChars)){
10061 this.hasQuery = true;
10063 if(this.lastQuery != q || this.alwaysQuery){
10064 this.lastQuery = q;
10065 if(this.mode == 'local'){
10066 this.selectedIndex = -1;
10068 this.store.clearFilter();
10070 this.store.filter(this.displayField, q);
10074 this.store.baseParams[this.queryParam] = q;
10076 var options = {params : this.getParams(q)};
10079 options.add = true;
10080 options.params.start = this.page * this.pageSize;
10083 this.store.load(options);
10087 this.selectedIndex = -1;
10092 this.loadNext = false;
10096 getParams : function(q){
10098 //p[this.queryParam] = q;
10102 p.limit = this.pageSize;
10108 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10110 collapse : function(){
10111 if(!this.isExpanded()){
10116 Roo.get(document).un('mousedown', this.collapseIf, this);
10117 Roo.get(document).un('mousewheel', this.collapseIf, this);
10118 if (!this.editable) {
10119 Roo.get(document).un('keydown', this.listKeyPress, this);
10121 this.fireEvent('collapse', this);
10125 collapseIf : function(e){
10126 var in_combo = e.within(this.el);
10127 var in_list = e.within(this.list);
10129 if (in_combo || in_list) {
10130 //e.stopPropagation();
10139 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10141 expand : function(){
10143 if(this.isExpanded() || !this.hasFocus){
10147 this.list.alignTo(this.inputEl(), this.listAlign);
10149 Roo.get(document).on('mousedown', this.collapseIf, this);
10150 Roo.get(document).on('mousewheel', this.collapseIf, this);
10151 if (!this.editable) {
10152 Roo.get(document).on('keydown', this.listKeyPress, this);
10155 this.fireEvent('expand', this);
10159 // Implements the default empty TriggerField.onTriggerClick function
10160 onTriggerClick : function()
10162 Roo.log('trigger click');
10169 this.loadNext = false;
10171 if(this.isExpanded()){
10173 if (!this.blockFocus) {
10174 this.inputEl().focus();
10178 this.hasFocus = true;
10179 if(this.triggerAction == 'all') {
10180 this.doQuery(this.allQuery, true);
10182 this.doQuery(this.getRawValue());
10184 if (!this.blockFocus) {
10185 this.inputEl().focus();
10189 listKeyPress : function(e)
10191 //Roo.log('listkeypress');
10192 // scroll to first matching element based on key pres..
10193 if (e.isSpecialKey()) {
10196 var k = String.fromCharCode(e.getKey()).toUpperCase();
10199 var csel = this.view.getSelectedNodes();
10200 var cselitem = false;
10202 var ix = this.view.indexOf(csel[0]);
10203 cselitem = this.store.getAt(ix);
10204 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10210 this.store.each(function(v) {
10212 // start at existing selection.
10213 if (cselitem.id == v.id) {
10219 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10220 match = this.store.indexOf(v);
10226 if (match === false) {
10227 return true; // no more action?
10230 this.view.select(match);
10231 var sn = Roo.get(this.view.getSelectedNodes()[0])
10232 //sn.scrollIntoView(sn.dom.parentNode, false);
10235 onViewScroll : function(e, t){
10237 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10241 this.hasQuery = true;
10243 this.loading = this.list.select('.loading', true).first();
10245 if(this.loading === null){
10246 this.list.createChild({
10248 cls: 'loading select2-more-results select2-active',
10249 html: 'Loading more results...'
10252 this.loading = this.list.select('.loading', true).first();
10254 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10256 this.loading.hide();
10259 this.loading.show();
10264 this.loadNext = true;
10266 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10271 addItem : function(o)
10273 var dv = ''; // display value
10275 if (this.displayField) {
10276 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10278 // this is an error condition!!!
10279 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10286 var choice = this.choices.createChild({
10288 cls: 'select2-search-choice',
10297 cls: 'select2-search-choice-close',
10302 }, this.searchField);
10304 var close = choice.select('a.select2-search-choice-close', true).first()
10306 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10313 this.inputEl().dom.value = '';
10317 onRemoveItem : function(e, _self, o)
10319 e.preventDefault();
10320 var index = this.item.indexOf(o.data) * 1;
10323 Roo.log('not this item?!');
10327 this.item.splice(index, 1);
10332 this.fireEvent('remove', this, e);
10336 syncValue : function()
10338 if(!this.item.length){
10345 Roo.each(this.item, function(i){
10346 if(_this.valueField){
10347 value.push(i[_this.valueField]);
10354 this.value = value.join(',');
10356 if(this.hiddenField){
10357 this.hiddenField.dom.value = this.value;
10361 clearItem : function()
10363 if(!this.multiple){
10369 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10379 * @cfg {Boolean} grow
10383 * @cfg {Number} growMin
10387 * @cfg {Number} growMax
10397 * Ext JS Library 1.1.1
10398 * Copyright(c) 2006-2007, Ext JS, LLC.
10400 * Originally Released Under LGPL - original licence link has changed is not relivant.
10403 * <script type="text/javascript">
10408 * @extends Roo.util.Observable
10409 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10410 * This class also supports single and multi selection modes. <br>
10411 * Create a data model bound view:
10413 var store = new Roo.data.Store(...);
10415 var view = new Roo.View({
10417 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10419 singleSelect: true,
10420 selectedClass: "ydataview-selected",
10424 // listen for node click?
10425 view.on("click", function(vw, index, node, e){
10426 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10430 dataModel.load("foobar.xml");
10432 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10434 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10435 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10437 * Note: old style constructor is still suported (container, template, config)
10440 * Create a new View
10441 * @param {Object} config The config object
10444 Roo.View = function(config, depreciated_tpl, depreciated_config){
10446 if (typeof(depreciated_tpl) == 'undefined') {
10447 // new way.. - universal constructor.
10448 Roo.apply(this, config);
10449 this.el = Roo.get(this.el);
10452 this.el = Roo.get(config);
10453 this.tpl = depreciated_tpl;
10454 Roo.apply(this, depreciated_config);
10456 this.wrapEl = this.el.wrap().wrap();
10457 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10460 if(typeof(this.tpl) == "string"){
10461 this.tpl = new Roo.Template(this.tpl);
10463 // support xtype ctors..
10464 this.tpl = new Roo.factory(this.tpl, Roo);
10468 this.tpl.compile();
10476 * @event beforeclick
10477 * Fires before a click is processed. Returns false to cancel the default action.
10478 * @param {Roo.View} this
10479 * @param {Number} index The index of the target node
10480 * @param {HTMLElement} node The target node
10481 * @param {Roo.EventObject} e The raw event object
10483 "beforeclick" : true,
10486 * Fires when a template node is clicked.
10487 * @param {Roo.View} this
10488 * @param {Number} index The index of the target node
10489 * @param {HTMLElement} node The target node
10490 * @param {Roo.EventObject} e The raw event object
10495 * Fires when a template node is double clicked.
10496 * @param {Roo.View} this
10497 * @param {Number} index The index of the target node
10498 * @param {HTMLElement} node The target node
10499 * @param {Roo.EventObject} e The raw event object
10503 * @event contextmenu
10504 * Fires when a template node is right clicked.
10505 * @param {Roo.View} this
10506 * @param {Number} index The index of the target node
10507 * @param {HTMLElement} node The target node
10508 * @param {Roo.EventObject} e The raw event object
10510 "contextmenu" : true,
10512 * @event selectionchange
10513 * Fires when the selected nodes change.
10514 * @param {Roo.View} this
10515 * @param {Array} selections Array of the selected nodes
10517 "selectionchange" : true,
10520 * @event beforeselect
10521 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10522 * @param {Roo.View} this
10523 * @param {HTMLElement} node The node to be selected
10524 * @param {Array} selections Array of currently selected nodes
10526 "beforeselect" : true,
10528 * @event preparedata
10529 * Fires on every row to render, to allow you to change the data.
10530 * @param {Roo.View} this
10531 * @param {Object} data to be rendered (change this)
10533 "preparedata" : true
10541 "click": this.onClick,
10542 "dblclick": this.onDblClick,
10543 "contextmenu": this.onContextMenu,
10547 this.selections = [];
10549 this.cmp = new Roo.CompositeElementLite([]);
10551 this.store = Roo.factory(this.store, Roo.data);
10552 this.setStore(this.store, true);
10555 if ( this.footer && this.footer.xtype) {
10557 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10559 this.footer.dataSource = this.store
10560 this.footer.container = fctr;
10561 this.footer = Roo.factory(this.footer, Roo);
10562 fctr.insertFirst(this.el);
10564 // this is a bit insane - as the paging toolbar seems to detach the el..
10565 // dom.parentNode.parentNode.parentNode
10566 // they get detached?
10570 Roo.View.superclass.constructor.call(this);
10575 Roo.extend(Roo.View, Roo.util.Observable, {
10578 * @cfg {Roo.data.Store} store Data store to load data from.
10583 * @cfg {String|Roo.Element} el The container element.
10588 * @cfg {String|Roo.Template} tpl The template used by this View
10592 * @cfg {String} dataName the named area of the template to use as the data area
10593 * Works with domtemplates roo-name="name"
10597 * @cfg {String} selectedClass The css class to add to selected nodes
10599 selectedClass : "x-view-selected",
10601 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10606 * @cfg {String} text to display on mask (default Loading)
10610 * @cfg {Boolean} multiSelect Allow multiple selection
10612 multiSelect : false,
10614 * @cfg {Boolean} singleSelect Allow single selection
10616 singleSelect: false,
10619 * @cfg {Boolean} toggleSelect - selecting
10621 toggleSelect : false,
10624 * Returns the element this view is bound to.
10625 * @return {Roo.Element}
10627 getEl : function(){
10628 return this.wrapEl;
10634 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10636 refresh : function(){
10637 Roo.log('refresh');
10640 // if we are using something like 'domtemplate', then
10641 // the what gets used is:
10642 // t.applySubtemplate(NAME, data, wrapping data..)
10643 // the outer template then get' applied with
10644 // the store 'extra data'
10645 // and the body get's added to the
10646 // roo-name="data" node?
10647 // <span class='roo-tpl-{name}'></span> ?????
10651 this.clearSelections();
10652 this.el.update("");
10654 var records = this.store.getRange();
10655 if(records.length < 1) {
10657 // is this valid?? = should it render a template??
10659 this.el.update(this.emptyText);
10663 if (this.dataName) {
10664 this.el.update(t.apply(this.store.meta)); //????
10665 el = this.el.child('.roo-tpl-' + this.dataName);
10668 for(var i = 0, len = records.length; i < len; i++){
10669 var data = this.prepareData(records[i].data, i, records[i]);
10670 this.fireEvent("preparedata", this, data, i, records[i]);
10671 html[html.length] = Roo.util.Format.trim(
10673 t.applySubtemplate(this.dataName, data, this.store.meta) :
10680 el.update(html.join(""));
10681 this.nodes = el.dom.childNodes;
10682 this.updateIndexes(0);
10687 * Function to override to reformat the data that is sent to
10688 * the template for each node.
10689 * DEPRICATED - use the preparedata event handler.
10690 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10691 * a JSON object for an UpdateManager bound view).
10693 prepareData : function(data, index, record)
10695 this.fireEvent("preparedata", this, data, index, record);
10699 onUpdate : function(ds, record){
10700 Roo.log('on update');
10701 this.clearSelections();
10702 var index = this.store.indexOf(record);
10703 var n = this.nodes[index];
10704 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10705 n.parentNode.removeChild(n);
10706 this.updateIndexes(index, index);
10712 onAdd : function(ds, records, index)
10714 Roo.log(['on Add', ds, records, index] );
10715 this.clearSelections();
10716 if(this.nodes.length == 0){
10720 var n = this.nodes[index];
10721 for(var i = 0, len = records.length; i < len; i++){
10722 var d = this.prepareData(records[i].data, i, records[i]);
10724 this.tpl.insertBefore(n, d);
10727 this.tpl.append(this.el, d);
10730 this.updateIndexes(index);
10733 onRemove : function(ds, record, index){
10734 Roo.log('onRemove');
10735 this.clearSelections();
10736 var el = this.dataName ?
10737 this.el.child('.roo-tpl-' + this.dataName) :
10740 el.dom.removeChild(this.nodes[index]);
10741 this.updateIndexes(index);
10745 * Refresh an individual node.
10746 * @param {Number} index
10748 refreshNode : function(index){
10749 this.onUpdate(this.store, this.store.getAt(index));
10752 updateIndexes : function(startIndex, endIndex){
10753 var ns = this.nodes;
10754 startIndex = startIndex || 0;
10755 endIndex = endIndex || ns.length - 1;
10756 for(var i = startIndex; i <= endIndex; i++){
10757 ns[i].nodeIndex = i;
10762 * Changes the data store this view uses and refresh the view.
10763 * @param {Store} store
10765 setStore : function(store, initial){
10766 if(!initial && this.store){
10767 this.store.un("datachanged", this.refresh);
10768 this.store.un("add", this.onAdd);
10769 this.store.un("remove", this.onRemove);
10770 this.store.un("update", this.onUpdate);
10771 this.store.un("clear", this.refresh);
10772 this.store.un("beforeload", this.onBeforeLoad);
10773 this.store.un("load", this.onLoad);
10774 this.store.un("loadexception", this.onLoad);
10778 store.on("datachanged", this.refresh, this);
10779 store.on("add", this.onAdd, this);
10780 store.on("remove", this.onRemove, this);
10781 store.on("update", this.onUpdate, this);
10782 store.on("clear", this.refresh, this);
10783 store.on("beforeload", this.onBeforeLoad, this);
10784 store.on("load", this.onLoad, this);
10785 store.on("loadexception", this.onLoad, this);
10793 * onbeforeLoad - masks the loading area.
10796 onBeforeLoad : function(store,opts)
10798 Roo.log('onBeforeLoad');
10800 this.el.update("");
10802 this.el.mask(this.mask ? this.mask : "Loading" );
10804 onLoad : function ()
10811 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10812 * @param {HTMLElement} node
10813 * @return {HTMLElement} The template node
10815 findItemFromChild : function(node){
10816 var el = this.dataName ?
10817 this.el.child('.roo-tpl-' + this.dataName,true) :
10820 if(!node || node.parentNode == el){
10823 var p = node.parentNode;
10824 while(p && p != el){
10825 if(p.parentNode == el){
10834 onClick : function(e){
10835 var item = this.findItemFromChild(e.getTarget());
10837 var index = this.indexOf(item);
10838 if(this.onItemClick(item, index, e) !== false){
10839 this.fireEvent("click", this, index, item, e);
10842 this.clearSelections();
10847 onContextMenu : function(e){
10848 var item = this.findItemFromChild(e.getTarget());
10850 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10855 onDblClick : function(e){
10856 var item = this.findItemFromChild(e.getTarget());
10858 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10862 onItemClick : function(item, index, e)
10864 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10867 if (this.toggleSelect) {
10868 var m = this.isSelected(item) ? 'unselect' : 'select';
10871 _t[m](item, true, false);
10874 if(this.multiSelect || this.singleSelect){
10875 if(this.multiSelect && e.shiftKey && this.lastSelection){
10876 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10878 this.select(item, this.multiSelect && e.ctrlKey);
10879 this.lastSelection = item;
10881 e.preventDefault();
10887 * Get the number of selected nodes.
10890 getSelectionCount : function(){
10891 return this.selections.length;
10895 * Get the currently selected nodes.
10896 * @return {Array} An array of HTMLElements
10898 getSelectedNodes : function(){
10899 return this.selections;
10903 * Get the indexes of the selected nodes.
10906 getSelectedIndexes : function(){
10907 var indexes = [], s = this.selections;
10908 for(var i = 0, len = s.length; i < len; i++){
10909 indexes.push(s[i].nodeIndex);
10915 * Clear all selections
10916 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10918 clearSelections : function(suppressEvent){
10919 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10920 this.cmp.elements = this.selections;
10921 this.cmp.removeClass(this.selectedClass);
10922 this.selections = [];
10923 if(!suppressEvent){
10924 this.fireEvent("selectionchange", this, this.selections);
10930 * Returns true if the passed node is selected
10931 * @param {HTMLElement/Number} node The node or node index
10932 * @return {Boolean}
10934 isSelected : function(node){
10935 var s = this.selections;
10939 node = this.getNode(node);
10940 return s.indexOf(node) !== -1;
10945 * @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
10946 * @param {Boolean} keepExisting (optional) true to keep existing selections
10947 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10949 select : function(nodeInfo, keepExisting, suppressEvent){
10950 if(nodeInfo instanceof Array){
10952 this.clearSelections(true);
10954 for(var i = 0, len = nodeInfo.length; i < len; i++){
10955 this.select(nodeInfo[i], true, true);
10959 var node = this.getNode(nodeInfo);
10960 if(!node || this.isSelected(node)){
10961 return; // already selected.
10964 this.clearSelections(true);
10966 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10967 Roo.fly(node).addClass(this.selectedClass);
10968 this.selections.push(node);
10969 if(!suppressEvent){
10970 this.fireEvent("selectionchange", this, this.selections);
10978 * @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
10979 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10980 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10982 unselect : function(nodeInfo, keepExisting, suppressEvent)
10984 if(nodeInfo instanceof Array){
10985 Roo.each(this.selections, function(s) {
10986 this.unselect(s, nodeInfo);
10990 var node = this.getNode(nodeInfo);
10991 if(!node || !this.isSelected(node)){
10992 Roo.log("not selected");
10993 return; // not selected.
10997 Roo.each(this.selections, function(s) {
10999 Roo.fly(node).removeClass(this.selectedClass);
11006 this.selections= ns;
11007 this.fireEvent("selectionchange", this, this.selections);
11011 * Gets a template node.
11012 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11013 * @return {HTMLElement} The node or null if it wasn't found
11015 getNode : function(nodeInfo){
11016 if(typeof nodeInfo == "string"){
11017 return document.getElementById(nodeInfo);
11018 }else if(typeof nodeInfo == "number"){
11019 return this.nodes[nodeInfo];
11025 * Gets a range template nodes.
11026 * @param {Number} startIndex
11027 * @param {Number} endIndex
11028 * @return {Array} An array of nodes
11030 getNodes : function(start, end){
11031 var ns = this.nodes;
11032 start = start || 0;
11033 end = typeof end == "undefined" ? ns.length - 1 : end;
11036 for(var i = start; i <= end; i++){
11040 for(var i = start; i >= end; i--){
11048 * Finds the index of the passed node
11049 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11050 * @return {Number} The index of the node or -1
11052 indexOf : function(node){
11053 node = this.getNode(node);
11054 if(typeof node.nodeIndex == "number"){
11055 return node.nodeIndex;
11057 var ns = this.nodes;
11058 for(var i = 0, len = ns.length; i < len; i++){
11069 * based on jquery fullcalendar
11073 Roo.bootstrap = Roo.bootstrap || {};
11075 * @class Roo.bootstrap.Calendar
11076 * @extends Roo.bootstrap.Component
11077 * Bootstrap Calendar class
11078 * @cfg {Boolean} loadMask (true|false) default false
11079 * @cfg {Object} header generate the user specific header of the calendar, default false
11082 * Create a new Container
11083 * @param {Object} config The config object
11088 Roo.bootstrap.Calendar = function(config){
11089 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11093 * Fires when a date is selected
11094 * @param {DatePicker} this
11095 * @param {Date} date The selected date
11099 * @event monthchange
11100 * Fires when the displayed month changes
11101 * @param {DatePicker} this
11102 * @param {Date} date The selected month
11104 'monthchange': true,
11106 * @event evententer
11107 * Fires when mouse over an event
11108 * @param {Calendar} this
11109 * @param {event} Event
11111 'evententer': true,
11113 * @event eventleave
11114 * Fires when the mouse leaves an
11115 * @param {Calendar} this
11118 'eventleave': true,
11120 * @event eventclick
11121 * Fires when the mouse click an
11122 * @param {Calendar} this
11131 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11134 * @cfg {Number} startDay
11135 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11143 getAutoCreate : function(){
11146 var fc_button = function(name, corner, style, content ) {
11147 return Roo.apply({},{
11149 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11151 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11154 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11165 style : 'width:100%',
11172 cls : 'fc-header-left',
11174 fc_button('prev', 'left', 'arrow', '‹' ),
11175 fc_button('next', 'right', 'arrow', '›' ),
11176 { tag: 'span', cls: 'fc-header-space' },
11177 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11185 cls : 'fc-header-center',
11189 cls: 'fc-header-title',
11192 html : 'month / year'
11200 cls : 'fc-header-right',
11202 /* fc_button('month', 'left', '', 'month' ),
11203 fc_button('week', '', '', 'week' ),
11204 fc_button('day', 'right', '', 'day' )
11216 header = this.header;
11219 var cal_heads = function() {
11221 // fixme - handle this.
11223 for (var i =0; i < Date.dayNames.length; i++) {
11224 var d = Date.dayNames[i];
11227 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11228 html : d.substring(0,3)
11232 ret[0].cls += ' fc-first';
11233 ret[6].cls += ' fc-last';
11236 var cal_cell = function(n) {
11239 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11244 cls: 'fc-day-number',
11248 cls: 'fc-day-content',
11252 style: 'position: relative;' // height: 17px;
11264 var cal_rows = function() {
11267 for (var r = 0; r < 6; r++) {
11274 for (var i =0; i < Date.dayNames.length; i++) {
11275 var d = Date.dayNames[i];
11276 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11279 row.cn[0].cls+=' fc-first';
11280 row.cn[0].cn[0].style = 'min-height:90px';
11281 row.cn[6].cls+=' fc-last';
11285 ret[0].cls += ' fc-first';
11286 ret[4].cls += ' fc-prev-last';
11287 ret[5].cls += ' fc-last';
11294 cls: 'fc-border-separate',
11295 style : 'width:100%',
11303 cls : 'fc-first fc-last',
11321 cls : 'fc-content',
11322 style : "position: relative;",
11325 cls : 'fc-view fc-view-month fc-grid',
11326 style : 'position: relative',
11327 unselectable : 'on',
11330 cls : 'fc-event-container',
11331 style : 'position:absolute;z-index:8;top:0;left:0;'
11349 initEvents : function()
11352 throw "can not find store for calendar";
11358 style: "text-align:center",
11362 style: "background-color:white;width:50%;margin:250 auto",
11366 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11377 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11379 var size = this.el.select('.fc-content', true).first().getSize();
11380 this.maskEl.setSize(size.width, size.height);
11381 this.maskEl.enableDisplayMode("block");
11382 if(!this.loadMask){
11383 this.maskEl.hide();
11386 this.store = Roo.factory(this.store, Roo.data);
11387 this.store.on('load', this.onLoad, this);
11388 this.store.on('beforeload', this.onBeforeLoad, this);
11392 this.cells = this.el.select('.fc-day',true);
11393 //Roo.log(this.cells);
11394 this.textNodes = this.el.query('.fc-day-number');
11395 this.cells.addClassOnOver('fc-state-hover');
11397 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11398 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11399 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11400 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11402 this.on('monthchange', this.onMonthChange, this);
11404 this.update(new Date().clearTime());
11407 resize : function() {
11408 var sz = this.el.getSize();
11410 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11411 this.el.select('.fc-day-content div',true).setHeight(34);
11416 showPrevMonth : function(e){
11417 this.update(this.activeDate.add("mo", -1));
11419 showToday : function(e){
11420 this.update(new Date().clearTime());
11423 showNextMonth : function(e){
11424 this.update(this.activeDate.add("mo", 1));
11428 showPrevYear : function(){
11429 this.update(this.activeDate.add("y", -1));
11433 showNextYear : function(){
11434 this.update(this.activeDate.add("y", 1));
11439 update : function(date)
11441 var vd = this.activeDate;
11442 this.activeDate = date;
11443 // if(vd && this.el){
11444 // var t = date.getTime();
11445 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11446 // Roo.log('using add remove');
11448 // this.fireEvent('monthchange', this, date);
11450 // this.cells.removeClass("fc-state-highlight");
11451 // this.cells.each(function(c){
11452 // if(c.dateValue == t){
11453 // c.addClass("fc-state-highlight");
11454 // setTimeout(function(){
11455 // try{c.dom.firstChild.focus();}catch(e){}
11465 var days = date.getDaysInMonth();
11467 var firstOfMonth = date.getFirstDateOfMonth();
11468 var startingPos = firstOfMonth.getDay()-this.startDay;
11470 if(startingPos < this.startDay){
11474 var pm = date.add(Date.MONTH, -1);
11475 var prevStart = pm.getDaysInMonth()-startingPos;
11477 this.cells = this.el.select('.fc-day',true);
11478 this.textNodes = this.el.query('.fc-day-number');
11479 this.cells.addClassOnOver('fc-state-hover');
11481 var cells = this.cells.elements;
11482 var textEls = this.textNodes;
11484 Roo.each(cells, function(cell){
11485 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11488 days += startingPos;
11490 // convert everything to numbers so it's fast
11491 var day = 86400000;
11492 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11495 //Roo.log(prevStart);
11497 var today = new Date().clearTime().getTime();
11498 var sel = date.clearTime().getTime();
11499 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11500 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11501 var ddMatch = this.disabledDatesRE;
11502 var ddText = this.disabledDatesText;
11503 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11504 var ddaysText = this.disabledDaysText;
11505 var format = this.format;
11507 var setCellClass = function(cal, cell){
11509 //Roo.log('set Cell Class');
11511 var t = d.getTime();
11515 cell.dateValue = t;
11517 cell.className += " fc-today";
11518 cell.className += " fc-state-highlight";
11519 cell.title = cal.todayText;
11522 // disable highlight in other month..
11523 //cell.className += " fc-state-highlight";
11528 cell.className = " fc-state-disabled";
11529 cell.title = cal.minText;
11533 cell.className = " fc-state-disabled";
11534 cell.title = cal.maxText;
11538 if(ddays.indexOf(d.getDay()) != -1){
11539 cell.title = ddaysText;
11540 cell.className = " fc-state-disabled";
11543 if(ddMatch && format){
11544 var fvalue = d.dateFormat(format);
11545 if(ddMatch.test(fvalue)){
11546 cell.title = ddText.replace("%0", fvalue);
11547 cell.className = " fc-state-disabled";
11551 if (!cell.initialClassName) {
11552 cell.initialClassName = cell.dom.className;
11555 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11560 for(; i < startingPos; i++) {
11561 textEls[i].innerHTML = (++prevStart);
11562 d.setDate(d.getDate()+1);
11564 cells[i].className = "fc-past fc-other-month";
11565 setCellClass(this, cells[i]);
11570 for(; i < days; i++){
11571 intDay = i - startingPos + 1;
11572 textEls[i].innerHTML = (intDay);
11573 d.setDate(d.getDate()+1);
11575 cells[i].className = ''; // "x-date-active";
11576 setCellClass(this, cells[i]);
11580 for(; i < 42; i++) {
11581 textEls[i].innerHTML = (++extraDays);
11582 d.setDate(d.getDate()+1);
11584 cells[i].className = "fc-future fc-other-month";
11585 setCellClass(this, cells[i]);
11588 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11590 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11592 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11593 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11595 if(totalRows != 6){
11596 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11597 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11600 this.fireEvent('monthchange', this, date);
11604 if(!this.internalRender){
11605 var main = this.el.dom.firstChild;
11606 var w = main.offsetWidth;
11607 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11608 Roo.fly(main).setWidth(w);
11609 this.internalRender = true;
11610 // opera does not respect the auto grow header center column
11611 // then, after it gets a width opera refuses to recalculate
11612 // without a second pass
11613 if(Roo.isOpera && !this.secondPass){
11614 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11615 this.secondPass = true;
11616 this.update.defer(10, this, [date]);
11623 findCell : function(dt) {
11624 dt = dt.clearTime().getTime();
11626 this.cells.each(function(c){
11627 //Roo.log("check " +c.dateValue + '?=' + dt);
11628 if(c.dateValue == dt){
11638 findCells : function(ev) {
11639 var s = ev.start.clone().clearTime().getTime();
11641 var e= ev.end.clone().clearTime().getTime();
11644 this.cells.each(function(c){
11645 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11647 if(c.dateValue > e){
11650 if(c.dateValue < s){
11659 // findBestRow: function(cells)
11663 // for (var i =0 ; i < cells.length;i++) {
11664 // ret = Math.max(cells[i].rows || 0,ret);
11671 addItem : function(ev)
11673 // look for vertical location slot in
11674 var cells = this.findCells(ev);
11676 // ev.row = this.findBestRow(cells);
11678 // work out the location.
11682 for(var i =0; i < cells.length; i++) {
11690 if (crow.start.getY() == cells[i].getY()) {
11692 crow.end = cells[i];
11708 ev.rendered = false;
11709 // for (var i = 0; i < cells.length;i++) {
11710 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11714 this.calevents.push(ev);
11717 clearEvents: function() {
11719 if(!this.calevents){
11723 Roo.each(this.cells.elements, function(c){
11728 Roo.each(this.calevents, function(e) {
11729 Roo.each(e.els, function(el) {
11730 el.un('mouseenter' ,this.onEventEnter, this);
11731 el.un('mouseleave' ,this.onEventLeave, this);
11736 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11742 renderEvents: function()
11744 // first make sure there is enough space..
11745 this.cells.each(function(c) {
11750 for (var e = 0; e < this.calevents.length; e++) {
11752 var ev = this.calevents[e];
11753 var cells = ev.cells;
11754 var rows = ev.rows;
11756 for(var i = 0; i < cells.length; i++){
11758 var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11760 if(cells.length < 2 && cbox.rows.length > 3){
11761 cbox.more.push(ev);
11765 cbox.rows.push(ev);
11771 this.cells.each(function(c) {
11772 if(c.more.length && c.more.length == 1){
11773 c.rows.push(c.more.pop());
11776 var r = (c.more.length) ? c.rows.length + 1 : c.rows.length;
11777 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, r * 20));
11780 for (var e = 0; e < c.rows.length; e++){
11781 var ev = c.rows[e];
11787 var cells = ev.cells;
11788 var rows = ev.rows;
11790 for(var i = 0; i < rows.length; i++) {
11792 // how many rows should it span..
11795 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11796 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11798 unselectable : "on",
11801 cls: 'fc-event-inner',
11805 // cls: 'fc-event-time',
11806 // html : cells.length > 1 ? '' : ev.time
11810 cls: 'fc-event-title',
11811 html : String.format('{0}', ev.title)
11818 cls: 'ui-resizable-handle ui-resizable-e',
11819 html : '  '
11826 cfg.cls += ' fc-event-start';
11828 if ((i+1) == rows.length) {
11829 cfg.cls += ' fc-event-end';
11832 var ctr = _this.el.select('.fc-event-container',true).first();
11833 var cg = ctr.createChild(cfg);
11835 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11836 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11838 cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11839 cg.setWidth(ebox.right - sbox.x -2);
11841 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11842 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11843 cg.on('click', _this.onEventClick, _this, ev);
11847 ev.rendered = true;
11855 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11856 style : 'position: absolute',
11857 unselectable : "on",
11860 cls: 'fc-event-inner',
11864 cls: 'fc-event-title',
11872 cls: 'ui-resizable-handle ui-resizable-e',
11873 html : '  '
11879 var ctr = _this.el.select('.fc-event-container',true).first();
11880 var cg = ctr.createChild(cfg);
11882 var sbox = c.select('.fc-day-content',true).first().getBox();
11883 var ebox = c.select('.fc-day-content',true).first().getBox();
11885 cg.setXY([sbox.x +2, sbox.y +(c.rows.length * 20)]);
11886 cg.setWidth(ebox.right - sbox.x -2);
11888 cg.on('click', _this.onMoreEventClick, _this, c.more);
11898 onEventEnter: function (e, el,event,d) {
11899 this.fireEvent('evententer', this, el, event);
11902 onEventLeave: function (e, el,event,d) {
11903 this.fireEvent('eventleave', this, el, event);
11906 onEventClick: function (e, el,event,d) {
11907 this.fireEvent('eventclick', this, el, event);
11910 onMonthChange: function () {
11914 onMoreEventClick: function(e, el, more)
11918 this.calpopover.placement = 'right';
11919 this.calpopover.setTitle('More');
11921 this.calpopover.setContent('');
11923 var ctr = this.calpopover.el.select('.popover-content', true).first();
11925 Roo.each(more, function(m){
11927 cls : 'fc-event-hori fc-event-draggable',
11930 var cg = ctr.createChild(cfg);
11932 cg.on('click', _this.onEventClick, _this, m);
11935 this.calpopover.show(el);
11940 onLoad: function ()
11942 this.calevents = [];
11945 if(this.store.getCount() > 0){
11946 this.store.data.each(function(d){
11949 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11950 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11951 time : d.data.start_time,
11952 title : d.data.title,
11953 description : d.data.description,
11954 venue : d.data.venue
11959 this.renderEvents();
11961 if(this.calevents.length && this.loadMask){
11962 this.maskEl.hide();
11966 onBeforeLoad: function()
11968 this.clearEvents();
11970 this.maskEl.show();
11984 * @class Roo.bootstrap.Popover
11985 * @extends Roo.bootstrap.Component
11986 * Bootstrap Popover class
11987 * @cfg {String} html contents of the popover (or false to use children..)
11988 * @cfg {String} title of popover (or false to hide)
11989 * @cfg {String} placement how it is placed
11990 * @cfg {String} trigger click || hover (or false to trigger manually)
11991 * @cfg {String} over what (parent or false to trigger manually.)
11994 * Create a new Popover
11995 * @param {Object} config The config object
11998 Roo.bootstrap.Popover = function(config){
11999 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
12002 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
12004 title: 'Fill in a title',
12007 placement : 'right',
12008 trigger : 'hover', // hover
12012 can_build_overlaid : false,
12014 getChildContainer : function()
12016 return this.el.select('.popover-content',true).first();
12019 getAutoCreate : function(){
12020 Roo.log('make popover?');
12022 cls : 'popover roo-dynamic',
12023 style: 'display:block',
12029 cls : 'popover-inner',
12033 cls: 'popover-title',
12037 cls : 'popover-content',
12048 setTitle: function(str)
12050 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12052 setContent: function(str)
12054 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12056 // as it get's added to the bottom of the page.
12057 onRender : function(ct, position)
12059 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12061 var cfg = Roo.apply({}, this.getAutoCreate());
12065 cfg.cls += ' ' + this.cls;
12068 cfg.style = this.style;
12070 Roo.log("adding to ")
12071 this.el = Roo.get(document.body).createChild(cfg, position);
12077 initEvents : function()
12079 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12080 this.el.enableDisplayMode('block');
12082 if (this.over === false) {
12085 if (this.triggers === false) {
12088 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12089 var triggers = this.trigger ? this.trigger.split(' ') : [];
12090 Roo.each(triggers, function(trigger) {
12092 if (trigger == 'click') {
12093 on_el.on('click', this.toggle, this);
12094 } else if (trigger != 'manual') {
12095 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12096 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12098 on_el.on(eventIn ,this.enter, this);
12099 on_el.on(eventOut, this.leave, this);
12110 toggle : function () {
12111 this.hoverState == 'in' ? this.leave() : this.enter();
12114 enter : function () {
12117 clearTimeout(this.timeout);
12119 this.hoverState = 'in'
12121 if (!this.delay || !this.delay.show) {
12126 this.timeout = setTimeout(function () {
12127 if (_t.hoverState == 'in') {
12130 }, this.delay.show)
12132 leave : function() {
12133 clearTimeout(this.timeout);
12135 this.hoverState = 'out'
12137 if (!this.delay || !this.delay.hide) {
12142 this.timeout = setTimeout(function () {
12143 if (_t.hoverState == 'out') {
12146 }, this.delay.hide)
12149 show : function (on_el)
12152 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12155 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12156 if (this.html !== false) {
12157 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12159 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12160 if (!this.title.length) {
12161 this.el.select('.popover-title',true).hide();
12164 var placement = typeof this.placement == 'function' ?
12165 this.placement.call(this, this.el, on_el) :
12168 var autoToken = /\s?auto?\s?/i;
12169 var autoPlace = autoToken.test(placement);
12171 placement = placement.replace(autoToken, '') || 'top';
12175 //this.el.setXY([0,0]);
12177 this.el.dom.style.display='block';
12178 this.el.addClass(placement);
12180 //this.el.appendTo(on_el);
12182 var p = this.getPosition();
12183 var box = this.el.getBox();
12188 var align = Roo.bootstrap.Popover.alignment[placement]
12189 this.el.alignTo(on_el, align[0],align[1]);
12190 //var arrow = this.el.select('.arrow',true).first();
12191 //arrow.set(align[2],
12193 this.el.addClass('in');
12194 this.hoverState = null;
12196 if (this.el.hasClass('fade')) {
12203 this.el.setXY([0,0]);
12204 this.el.removeClass('in');
12211 Roo.bootstrap.Popover.alignment = {
12212 'left' : ['r-l', [-10,0], 'right'],
12213 'right' : ['l-r', [10,0], 'left'],
12214 'bottom' : ['t-b', [0,10], 'top'],
12215 'top' : [ 'b-t', [0,-10], 'bottom']
12226 * @class Roo.bootstrap.Progress
12227 * @extends Roo.bootstrap.Component
12228 * Bootstrap Progress class
12229 * @cfg {Boolean} striped striped of the progress bar
12230 * @cfg {Boolean} active animated of the progress bar
12234 * Create a new Progress
12235 * @param {Object} config The config object
12238 Roo.bootstrap.Progress = function(config){
12239 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12242 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12247 getAutoCreate : function(){
12255 cfg.cls += ' progress-striped';
12259 cfg.cls += ' active';
12278 * @class Roo.bootstrap.ProgressBar
12279 * @extends Roo.bootstrap.Component
12280 * Bootstrap ProgressBar class
12281 * @cfg {Number} aria_valuenow aria-value now
12282 * @cfg {Number} aria_valuemin aria-value min
12283 * @cfg {Number} aria_valuemax aria-value max
12284 * @cfg {String} label label for the progress bar
12285 * @cfg {String} panel (success | info | warning | danger )
12286 * @cfg {String} role role of the progress bar
12287 * @cfg {String} sr_only text
12291 * Create a new ProgressBar
12292 * @param {Object} config The config object
12295 Roo.bootstrap.ProgressBar = function(config){
12296 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12299 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12303 aria_valuemax : 100,
12309 getAutoCreate : function()
12314 cls: 'progress-bar',
12315 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12327 cfg.role = this.role;
12330 if(this.aria_valuenow){
12331 cfg['aria-valuenow'] = this.aria_valuenow;
12334 if(this.aria_valuemin){
12335 cfg['aria-valuemin'] = this.aria_valuemin;
12338 if(this.aria_valuemax){
12339 cfg['aria-valuemax'] = this.aria_valuemax;
12342 if(this.label && !this.sr_only){
12343 cfg.html = this.label;
12347 cfg.cls += ' progress-bar-' + this.panel;
12353 update : function(aria_valuenow)
12355 this.aria_valuenow = aria_valuenow;
12357 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12372 * @class Roo.bootstrap.TabPanel
12373 * @extends Roo.bootstrap.Component
12374 * Bootstrap TabPanel class
12375 * @cfg {Boolean} active panel active
12376 * @cfg {String} html panel content
12377 * @cfg {String} tabId tab relate id
12378 * @cfg {String} navId The navbar which triggers show hide
12382 * Create a new TabPanel
12383 * @param {Object} config The config object
12386 Roo.bootstrap.TabPanel = function(config){
12387 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12391 * Fires when the active status changes
12392 * @param {Roo.bootstrap.TabPanel} this
12393 * @param {Boolean} state the new state
12400 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12407 getAutoCreate : function(){
12411 html: this.html || ''
12415 cfg.cls += ' active';
12419 cfg.tabId = this.tabId;
12424 onRender : function(ct, position)
12426 // Roo.log("Call onRender: " + this.xtype);
12428 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12430 if (this.navId && this.tabId) {
12431 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12433 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12435 item.on('changed', function(item, state) {
12436 this.setActive(state);
12442 setActive: function(state)
12444 Roo.log("panel - set active " + this.tabId + "=" + state);
12446 this.active = state;
12448 this.el.removeClass('active');
12450 } else if (!this.el.hasClass('active')) {
12451 this.el.addClass('active');
12453 this.fireEvent('changed', this, state);
12470 * @class Roo.bootstrap.DateField
12471 * @extends Roo.bootstrap.Input
12472 * Bootstrap DateField class
12473 * @cfg {Number} weekStart default 0
12474 * @cfg {Number} weekStart default 0
12475 * @cfg {Number} viewMode default empty, (months|years)
12476 * @cfg {Number} minViewMode default empty, (months|years)
12477 * @cfg {Number} startDate default -Infinity
12478 * @cfg {Number} endDate default Infinity
12479 * @cfg {Boolean} todayHighlight default false
12480 * @cfg {Boolean} todayBtn default false
12481 * @cfg {Boolean} calendarWeeks default false
12482 * @cfg {Object} daysOfWeekDisabled default empty
12484 * @cfg {Boolean} keyboardNavigation default true
12485 * @cfg {String} language default en
12488 * Create a new DateField
12489 * @param {Object} config The config object
12492 Roo.bootstrap.DateField = function(config){
12493 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12497 * Fires when this field show.
12498 * @param {Roo.bootstrap.DateField} this
12499 * @param {Mixed} date The date value
12504 * Fires when this field hide.
12505 * @param {Roo.bootstrap.DateField} this
12506 * @param {Mixed} date The date value
12511 * Fires when select a date.
12512 * @param {Roo.bootstrap.DateField} this
12513 * @param {Mixed} date The date value
12519 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12522 * @cfg {String} format
12523 * The default date format string which can be overriden for localization support. The format must be
12524 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12528 * @cfg {String} altFormats
12529 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12530 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12532 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12540 todayHighlight : false,
12546 keyboardNavigation: true,
12548 calendarWeeks: false,
12550 startDate: -Infinity,
12554 daysOfWeekDisabled: [],
12558 UTCDate: function()
12560 return new Date(Date.UTC.apply(Date, arguments));
12563 UTCToday: function()
12565 var today = new Date();
12566 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12569 getDate: function() {
12570 var d = this.getUTCDate();
12571 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12574 getUTCDate: function() {
12578 setDate: function(d) {
12579 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12582 setUTCDate: function(d) {
12584 this.setValue(this.formatDate(this.date));
12587 onRender: function(ct, position)
12590 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12592 this.language = this.language || 'en';
12593 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12594 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12596 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12597 this.format = this.format || 'm/d/y';
12598 this.isInline = false;
12599 this.isInput = true;
12600 this.component = this.el.select('.add-on', true).first() || false;
12601 this.component = (this.component && this.component.length === 0) ? false : this.component;
12602 this.hasInput = this.component && this.inputEL().length;
12604 if (typeof(this.minViewMode === 'string')) {
12605 switch (this.minViewMode) {
12607 this.minViewMode = 1;
12610 this.minViewMode = 2;
12613 this.minViewMode = 0;
12618 if (typeof(this.viewMode === 'string')) {
12619 switch (this.viewMode) {
12632 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12634 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12636 this.picker().on('mousedown', this.onMousedown, this);
12637 this.picker().on('click', this.onClick, this);
12639 this.picker().addClass('datepicker-dropdown');
12641 this.startViewMode = this.viewMode;
12644 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12645 if(!this.calendarWeeks){
12650 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12651 v.attr('colspan', function(i, val){
12652 return parseInt(val) + 1;
12657 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12659 this.setStartDate(this.startDate);
12660 this.setEndDate(this.endDate);
12662 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12669 if(this.isInline) {
12674 picker : function()
12676 return this.el.select('.datepicker', true).first();
12679 fillDow: function()
12681 var dowCnt = this.weekStart;
12690 if(this.calendarWeeks){
12698 while (dowCnt < this.weekStart + 7) {
12702 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12706 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12709 fillMonths: function()
12712 var months = this.picker().select('>.datepicker-months td', true).first();
12714 months.dom.innerHTML = '';
12720 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12723 months.createChild(month);
12728 update: function(){
12730 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12732 if (this.date < this.startDate) {
12733 this.viewDate = new Date(this.startDate);
12734 } else if (this.date > this.endDate) {
12735 this.viewDate = new Date(this.endDate);
12737 this.viewDate = new Date(this.date);
12744 var d = new Date(this.viewDate),
12745 year = d.getUTCFullYear(),
12746 month = d.getUTCMonth(),
12747 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12748 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12749 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12750 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12751 currentDate = this.date && this.date.valueOf(),
12752 today = this.UTCToday();
12754 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12756 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12758 // this.picker.select('>tfoot th.today').
12759 // .text(dates[this.language].today)
12760 // .toggle(this.todayBtn !== false);
12762 this.updateNavArrows();
12765 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12767 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12769 prevMonth.setUTCDate(day);
12771 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12773 var nextMonth = new Date(prevMonth);
12775 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12777 nextMonth = nextMonth.valueOf();
12779 var fillMonths = false;
12781 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12783 while(prevMonth.valueOf() < nextMonth) {
12786 if (prevMonth.getUTCDay() === this.weekStart) {
12788 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12796 if(this.calendarWeeks){
12797 // ISO 8601: First week contains first thursday.
12798 // ISO also states week starts on Monday, but we can be more abstract here.
12800 // Start of current week: based on weekstart/current date
12801 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12802 // Thursday of this week
12803 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12804 // First Thursday of year, year from thursday
12805 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12806 // Calendar week: ms between thursdays, div ms per day, div 7 days
12807 calWeek = (th - yth) / 864e5 / 7 + 1;
12809 fillMonths.cn.push({
12817 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12819 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12822 if (this.todayHighlight &&
12823 prevMonth.getUTCFullYear() == today.getFullYear() &&
12824 prevMonth.getUTCMonth() == today.getMonth() &&
12825 prevMonth.getUTCDate() == today.getDate()) {
12826 clsName += ' today';
12829 if (currentDate && prevMonth.valueOf() === currentDate) {
12830 clsName += ' active';
12833 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12834 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12835 clsName += ' disabled';
12838 fillMonths.cn.push({
12840 cls: 'day ' + clsName,
12841 html: prevMonth.getDate()
12844 prevMonth.setDate(prevMonth.getDate()+1);
12847 var currentYear = this.date && this.date.getUTCFullYear();
12848 var currentMonth = this.date && this.date.getUTCMonth();
12850 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12852 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12853 v.removeClass('active');
12855 if(currentYear === year && k === currentMonth){
12856 v.addClass('active');
12859 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12860 v.addClass('disabled');
12866 year = parseInt(year/10, 10) * 10;
12868 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12870 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12873 for (var i = -1; i < 11; i++) {
12874 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12876 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12884 showMode: function(dir) {
12886 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12888 Roo.each(this.picker().select('>div',true).elements, function(v){
12889 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12892 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12897 if(this.isInline) return;
12899 this.picker().removeClass(['bottom', 'top']);
12901 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12903 * place to the top of element!
12907 this.picker().addClass('top');
12908 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12913 this.picker().addClass('bottom');
12915 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12918 parseDate : function(value){
12919 if(!value || value instanceof Date){
12922 var v = Date.parseDate(value, this.format);
12923 if (!v && this.useIso) {
12924 v = Date.parseDate(value, 'Y-m-d');
12926 if(!v && this.altFormats){
12927 if(!this.altFormatsArray){
12928 this.altFormatsArray = this.altFormats.split("|");
12930 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12931 v = Date.parseDate(value, this.altFormatsArray[i]);
12937 formatDate : function(date, fmt){
12938 return (!date || !(date instanceof Date)) ?
12939 date : date.dateFormat(fmt || this.format);
12942 onFocus : function()
12944 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12948 onBlur : function()
12950 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12956 this.picker().show();
12960 this.fireEvent('show', this, this.date);
12965 if(this.isInline) return;
12966 this.picker().hide();
12967 this.viewMode = this.startViewMode;
12970 this.fireEvent('hide', this, this.date);
12974 onMousedown: function(e){
12975 e.stopPropagation();
12976 e.preventDefault();
12979 keyup: function(e){
12980 Roo.bootstrap.DateField.superclass.keyup.call(this);
12985 setValue: function(v){
12986 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12988 this.fireEvent('select', this, this.date);
12992 fireKey: function(e){
12993 if (!this.picker().isVisible()){
12994 if (e.keyCode == 27) // allow escape to hide and re-show picker
12998 var dateChanged = false,
13000 newDate, newViewDate;
13004 e.preventDefault();
13008 if (!this.keyboardNavigation) break;
13009 dir = e.keyCode == 37 ? -1 : 1;
13012 newDate = this.moveYear(this.date, dir);
13013 newViewDate = this.moveYear(this.viewDate, dir);
13014 } else if (e.shiftKey){
13015 newDate = this.moveMonth(this.date, dir);
13016 newViewDate = this.moveMonth(this.viewDate, dir);
13018 newDate = new Date(this.date);
13019 newDate.setUTCDate(this.date.getUTCDate() + dir);
13020 newViewDate = new Date(this.viewDate);
13021 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13023 if (this.dateWithinRange(newDate)){
13024 this.date = newDate;
13025 this.viewDate = newViewDate;
13026 this.setValue(this.formatDate(this.date));
13028 e.preventDefault();
13029 dateChanged = true;
13034 if (!this.keyboardNavigation) break;
13035 dir = e.keyCode == 38 ? -1 : 1;
13037 newDate = this.moveYear(this.date, dir);
13038 newViewDate = this.moveYear(this.viewDate, dir);
13039 } else if (e.shiftKey){
13040 newDate = this.moveMonth(this.date, dir);
13041 newViewDate = this.moveMonth(this.viewDate, dir);
13043 newDate = new Date(this.date);
13044 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13045 newViewDate = new Date(this.viewDate);
13046 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13048 if (this.dateWithinRange(newDate)){
13049 this.date = newDate;
13050 this.viewDate = newViewDate;
13051 this.setValue(this.formatDate(this.date));
13053 e.preventDefault();
13054 dateChanged = true;
13058 this.setValue(this.formatDate(this.date));
13060 e.preventDefault();
13063 this.setValue(this.formatDate(this.date));
13070 onClick: function(e) {
13071 e.stopPropagation();
13072 e.preventDefault();
13074 var target = e.getTarget();
13076 if(target.nodeName.toLowerCase() === 'i'){
13077 target = Roo.get(target).dom.parentNode;
13080 var nodeName = target.nodeName;
13081 var className = target.className;
13082 var html = target.innerHTML;
13084 switch(nodeName.toLowerCase()) {
13086 switch(className) {
13092 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13093 switch(this.viewMode){
13095 this.viewDate = this.moveMonth(this.viewDate, dir);
13099 this.viewDate = this.moveYear(this.viewDate, dir);
13105 var date = new Date();
13106 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13108 this.setValue(this.formatDate(this.date));
13114 if (className.indexOf('disabled') === -1) {
13115 this.viewDate.setUTCDate(1);
13116 if (className.indexOf('month') !== -1) {
13117 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13119 var year = parseInt(html, 10) || 0;
13120 this.viewDate.setUTCFullYear(year);
13129 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13130 var day = parseInt(html, 10) || 1;
13131 var year = this.viewDate.getUTCFullYear(),
13132 month = this.viewDate.getUTCMonth();
13134 if (className.indexOf('old') !== -1) {
13141 } else if (className.indexOf('new') !== -1) {
13149 this.date = this.UTCDate(year, month, day,0,0,0,0);
13150 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13152 this.setValue(this.formatDate(this.date));
13159 setStartDate: function(startDate){
13160 this.startDate = startDate || -Infinity;
13161 if (this.startDate !== -Infinity) {
13162 this.startDate = this.parseDate(this.startDate);
13165 this.updateNavArrows();
13168 setEndDate: function(endDate){
13169 this.endDate = endDate || Infinity;
13170 if (this.endDate !== Infinity) {
13171 this.endDate = this.parseDate(this.endDate);
13174 this.updateNavArrows();
13177 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13178 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13179 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13180 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13182 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13183 return parseInt(d, 10);
13186 this.updateNavArrows();
13189 updateNavArrows: function() {
13190 var d = new Date(this.viewDate),
13191 year = d.getUTCFullYear(),
13192 month = d.getUTCMonth();
13194 Roo.each(this.picker().select('.prev', true).elements, function(v){
13196 switch (this.viewMode) {
13199 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13205 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13212 Roo.each(this.picker().select('.next', true).elements, function(v){
13214 switch (this.viewMode) {
13217 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13223 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13231 moveMonth: function(date, dir){
13232 if (!dir) return date;
13233 var new_date = new Date(date.valueOf()),
13234 day = new_date.getUTCDate(),
13235 month = new_date.getUTCMonth(),
13236 mag = Math.abs(dir),
13238 dir = dir > 0 ? 1 : -1;
13241 // If going back one month, make sure month is not current month
13242 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13244 return new_date.getUTCMonth() == month;
13246 // If going forward one month, make sure month is as expected
13247 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13249 return new_date.getUTCMonth() != new_month;
13251 new_month = month + dir;
13252 new_date.setUTCMonth(new_month);
13253 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13254 if (new_month < 0 || new_month > 11)
13255 new_month = (new_month + 12) % 12;
13257 // For magnitudes >1, move one month at a time...
13258 for (var i=0; i<mag; i++)
13259 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13260 new_date = this.moveMonth(new_date, dir);
13261 // ...then reset the day, keeping it in the new month
13262 new_month = new_date.getUTCMonth();
13263 new_date.setUTCDate(day);
13265 return new_month != new_date.getUTCMonth();
13268 // Common date-resetting loop -- if date is beyond end of month, make it
13271 new_date.setUTCDate(--day);
13272 new_date.setUTCMonth(new_month);
13277 moveYear: function(date, dir){
13278 return this.moveMonth(date, dir*12);
13281 dateWithinRange: function(date){
13282 return date >= this.startDate && date <= this.endDate;
13286 remove: function() {
13287 this.picker().remove();
13292 Roo.apply(Roo.bootstrap.DateField, {
13303 html: '<i class="icon-arrow-left"/>'
13313 html: '<i class="icon-arrow-right"/>'
13355 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13356 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13357 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13358 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13359 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13372 navFnc: 'FullYear',
13377 navFnc: 'FullYear',
13382 Roo.apply(Roo.bootstrap.DateField, {
13386 cls: 'datepicker dropdown-menu',
13390 cls: 'datepicker-days',
13394 cls: 'table-condensed',
13396 Roo.bootstrap.DateField.head,
13400 Roo.bootstrap.DateField.footer
13407 cls: 'datepicker-months',
13411 cls: 'table-condensed',
13413 Roo.bootstrap.DateField.head,
13414 Roo.bootstrap.DateField.content,
13415 Roo.bootstrap.DateField.footer
13422 cls: 'datepicker-years',
13426 cls: 'table-condensed',
13428 Roo.bootstrap.DateField.head,
13429 Roo.bootstrap.DateField.content,
13430 Roo.bootstrap.DateField.footer
13449 * @class Roo.bootstrap.TimeField
13450 * @extends Roo.bootstrap.Input
13451 * Bootstrap DateField class
13455 * Create a new TimeField
13456 * @param {Object} config The config object
13459 Roo.bootstrap.TimeField = function(config){
13460 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13464 * Fires when this field show.
13465 * @param {Roo.bootstrap.DateField} this
13466 * @param {Mixed} date The date value
13471 * Fires when this field hide.
13472 * @param {Roo.bootstrap.DateField} this
13473 * @param {Mixed} date The date value
13478 * Fires when select a date.
13479 * @param {Roo.bootstrap.DateField} this
13480 * @param {Mixed} date The date value
13486 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13489 * @cfg {String} format
13490 * The default time format string which can be overriden for localization support. The format must be
13491 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13495 onRender: function(ct, position)
13498 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13500 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13502 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13504 this.pop = this.picker().select('>.datepicker-time',true).first();
13505 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13507 this.picker().on('mousedown', this.onMousedown, this);
13508 this.picker().on('click', this.onClick, this);
13510 this.picker().addClass('datepicker-dropdown');
13515 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13516 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13517 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13518 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13519 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13520 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13524 fireKey: function(e){
13525 if (!this.picker().isVisible()){
13526 if (e.keyCode == 27) // allow escape to hide and re-show picker
13531 e.preventDefault();
13539 this.onTogglePeriod();
13542 this.onIncrementMinutes();
13545 this.onDecrementMinutes();
13554 onClick: function(e) {
13555 e.stopPropagation();
13556 e.preventDefault();
13559 picker : function()
13561 return this.el.select('.datepicker', true).first();
13564 fillTime: function()
13566 var time = this.pop.select('tbody', true).first();
13568 time.dom.innerHTML = '';
13583 cls: 'hours-up glyphicon glyphicon-chevron-up'
13603 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13624 cls: 'timepicker-hour',
13639 cls: 'timepicker-minute',
13654 cls: 'btn btn-primary period',
13676 cls: 'hours-down glyphicon glyphicon-chevron-down'
13696 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13714 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13721 var hours = this.time.getHours();
13722 var minutes = this.time.getMinutes();
13735 hours = hours - 12;
13739 hours = '0' + hours;
13743 minutes = '0' + minutes;
13746 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13747 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13748 this.pop.select('button', true).first().dom.innerHTML = period;
13754 this.picker().removeClass(['bottom', 'top']);
13756 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13758 * place to the top of element!
13762 this.picker().addClass('top');
13763 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13768 this.picker().addClass('bottom');
13770 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13773 onFocus : function()
13775 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13779 onBlur : function()
13781 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13787 this.picker().show();
13792 this.fireEvent('show', this, this.date);
13797 this.picker().hide();
13800 this.fireEvent('hide', this, this.date);
13803 setTime : function()
13806 this.setValue(this.time.format(this.format));
13808 this.fireEvent('select', this, this.date);
13813 onMousedown: function(e){
13814 e.stopPropagation();
13815 e.preventDefault();
13818 onIncrementHours: function()
13820 Roo.log('onIncrementHours');
13821 this.time = this.time.add(Date.HOUR, 1);
13826 onDecrementHours: function()
13828 Roo.log('onDecrementHours');
13829 this.time = this.time.add(Date.HOUR, -1);
13833 onIncrementMinutes: function()
13835 Roo.log('onIncrementMinutes');
13836 this.time = this.time.add(Date.MINUTE, 1);
13840 onDecrementMinutes: function()
13842 Roo.log('onDecrementMinutes');
13843 this.time = this.time.add(Date.MINUTE, -1);
13847 onTogglePeriod: function()
13849 Roo.log('onTogglePeriod');
13850 this.time = this.time.add(Date.HOUR, 12);
13857 Roo.apply(Roo.bootstrap.TimeField, {
13887 cls: 'btn btn-info ok',
13899 Roo.apply(Roo.bootstrap.TimeField, {
13903 cls: 'datepicker dropdown-menu',
13907 cls: 'datepicker-time',
13911 cls: 'table-condensed',
13913 Roo.bootstrap.TimeField.content,
13914 Roo.bootstrap.TimeField.footer
13933 * @class Roo.bootstrap.CheckBox
13934 * @extends Roo.bootstrap.Input
13935 * Bootstrap CheckBox class
13937 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13938 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13939 * @cfg {String} boxLabel The text that appears beside the checkbox
13940 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13941 * @cfg {Boolean} checked initnal the element
13945 * Create a new CheckBox
13946 * @param {Object} config The config object
13949 Roo.bootstrap.CheckBox = function(config){
13950 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13955 * Fires when the element is checked or unchecked.
13956 * @param {Roo.bootstrap.CheckBox} this This input
13957 * @param {Boolean} checked The new checked value
13963 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13965 inputType: 'checkbox',
13972 getAutoCreate : function()
13974 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13980 cfg.cls = 'form-group checkbox' //input-group
13988 type : this.inputType,
13989 value : (!this.checked) ? this.valueOff : this.inputValue,
13990 cls : 'roo-checkbox', //'form-box',
13991 placeholder : this.placeholder || ''
13995 if (this.weight) { // Validity check?
13996 cfg.cls += " checkbox-" + this.weight;
13999 if (this.disabled) {
14000 input.disabled=true;
14004 input.checked = this.checked;
14008 input.name = this.name;
14012 input.cls += ' input-' + this.size;
14016 ['xs','sm','md','lg'].map(function(size){
14017 if (settings[size]) {
14018 cfg.cls += ' col-' + size + '-' + settings[size];
14024 var inputblock = input;
14029 if (this.before || this.after) {
14032 cls : 'input-group',
14036 inputblock.cn.push({
14038 cls : 'input-group-addon',
14042 inputblock.cn.push(input);
14044 inputblock.cn.push({
14046 cls : 'input-group-addon',
14053 if (align ==='left' && this.fieldLabel.length) {
14054 Roo.log("left and has label");
14060 cls : 'control-label col-md-' + this.labelWidth,
14061 html : this.fieldLabel
14065 cls : "col-md-" + (12 - this.labelWidth),
14072 } else if ( this.fieldLabel.length) {
14077 tag: this.boxLabel ? 'span' : 'label',
14079 cls: 'control-label box-input-label',
14080 //cls : 'input-group-addon',
14081 html : this.fieldLabel
14091 Roo.log(" no label && no align");
14092 cfg.cn = [ inputblock ] ;
14101 html: this.boxLabel
14113 * return the real input element.
14115 inputEl: function ()
14117 return this.el.select('input.roo-checkbox',true).first();
14122 return this.el.select('label.control-label',true).first();
14125 initEvents : function()
14127 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14129 this.inputEl().on('click', this.onClick, this);
14133 onClick : function()
14135 this.setChecked(!this.checked);
14138 setChecked : function(state,suppressEvent)
14140 this.checked = state;
14142 this.inputEl().dom.checked = state;
14144 if(suppressEvent !== true){
14145 this.fireEvent('check', this, state);
14148 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14152 setValue : function(v,suppressEvent)
14154 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14168 * @class Roo.bootstrap.Radio
14169 * @extends Roo.bootstrap.CheckBox
14170 * Bootstrap Radio class
14173 * Create a new Radio
14174 * @param {Object} config The config object
14177 Roo.bootstrap.Radio = function(config){
14178 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14182 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14184 inputType: 'radio',
14188 getAutoCreate : function()
14190 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14196 cfg.cls = 'form-group radio' //input-group
14201 type : this.inputType,
14202 value : (!this.checked) ? this.valueOff : this.inputValue,
14204 placeholder : this.placeholder || ''
14207 if (this.weight) { // Validity check?
14208 cfg.cls += " radio-" + this.weight;
14210 if (this.disabled) {
14211 input.disabled=true;
14215 input.checked = this.checked;
14219 input.name = this.name;
14223 input.cls += ' input-' + this.size;
14227 ['xs','sm','md','lg'].map(function(size){
14228 if (settings[size]) {
14229 cfg.cls += ' col-' + size + '-' + settings[size];
14233 var inputblock = input;
14235 if (this.before || this.after) {
14238 cls : 'input-group',
14242 inputblock.cn.push({
14244 cls : 'input-group-addon',
14248 inputblock.cn.push(input);
14250 inputblock.cn.push({
14252 cls : 'input-group-addon',
14259 if (align ==='left' && this.fieldLabel.length) {
14260 Roo.log("left and has label");
14266 cls : 'control-label col-md-' + this.labelWidth,
14267 html : this.fieldLabel
14271 cls : "col-md-" + (12 - this.labelWidth),
14278 } else if ( this.fieldLabel.length) {
14285 cls: 'control-label box-input-label',
14286 //cls : 'input-group-addon',
14287 html : this.fieldLabel
14297 Roo.log(" no label && no align");
14312 html: this.boxLabel
14319 inputEl: function ()
14321 return this.el.select('input.roo-radio',true).first();
14323 onClick : function()
14325 this.setChecked(true);
14328 setChecked : function(state,suppressEvent)
14331 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14332 v.dom.checked = false;
14336 this.checked = state;
14337 this.inputEl().dom.checked = state;
14339 if(suppressEvent !== true){
14340 this.fireEvent('check', this, state);
14343 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14347 getGroupValue : function()
14350 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14351 if(v.dom.checked == true){
14352 value = v.dom.value;
14360 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14361 * @return {Mixed} value The field value
14363 getValue : function(){
14364 return this.getGroupValue();
14370 //<script type="text/javascript">
14373 * Based Ext JS Library 1.1.1
14374 * Copyright(c) 2006-2007, Ext JS, LLC.
14380 * @class Roo.HtmlEditorCore
14381 * @extends Roo.Component
14382 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14384 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14387 Roo.HtmlEditorCore = function(config){
14390 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14393 * @event initialize
14394 * Fires when the editor is fully initialized (including the iframe)
14395 * @param {Roo.HtmlEditorCore} this
14400 * Fires when the editor is first receives the focus. Any insertion must wait
14401 * until after this event.
14402 * @param {Roo.HtmlEditorCore} this
14406 * @event beforesync
14407 * Fires before the textarea is updated with content from the editor iframe. Return false
14408 * to cancel the sync.
14409 * @param {Roo.HtmlEditorCore} this
14410 * @param {String} html
14414 * @event beforepush
14415 * Fires before the iframe editor is updated with content from the textarea. Return false
14416 * to cancel the push.
14417 * @param {Roo.HtmlEditorCore} this
14418 * @param {String} html
14423 * Fires when the textarea is updated with content from the editor iframe.
14424 * @param {Roo.HtmlEditorCore} this
14425 * @param {String} html
14430 * Fires when the iframe editor is updated with content from the textarea.
14431 * @param {Roo.HtmlEditorCore} this
14432 * @param {String} html
14437 * @event editorevent
14438 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14439 * @param {Roo.HtmlEditorCore} this
14447 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14451 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14457 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14462 * @cfg {Number} height (in pixels)
14466 * @cfg {Number} width (in pixels)
14471 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14474 stylesheets: false,
14479 // private properties
14480 validationEvent : false,
14482 initialized : false,
14484 sourceEditMode : false,
14485 onFocus : Roo.emptyFn,
14487 hideMode:'offsets',
14495 * Protected method that will not generally be called directly. It
14496 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14497 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14499 getDocMarkup : function(){
14502 Roo.log(this.stylesheets);
14504 // inherit styels from page...??
14505 if (this.stylesheets === false) {
14507 Roo.get(document.head).select('style').each(function(node) {
14508 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14511 Roo.get(document.head).select('link').each(function(node) {
14512 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14515 } else if (!this.stylesheets.length) {
14517 st = '<style type="text/css">' +
14518 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14521 Roo.each(this.stylesheets, function(s) {
14522 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14527 st += '<style type="text/css">' +
14528 'IMG { cursor: pointer } ' +
14532 return '<html><head>' + st +
14533 //<style type="text/css">' +
14534 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14536 ' </head><body class="roo-htmleditor-body"></body></html>';
14540 onRender : function(ct, position)
14543 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14544 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14547 this.el.dom.style.border = '0 none';
14548 this.el.dom.setAttribute('tabIndex', -1);
14549 this.el.addClass('x-hidden hide');
14553 if(Roo.isIE){ // fix IE 1px bogus margin
14554 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14558 this.frameId = Roo.id();
14562 var iframe = this.owner.wrap.createChild({
14564 cls: 'form-control', // bootstrap..
14566 name: this.frameId,
14567 frameBorder : 'no',
14568 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14573 this.iframe = iframe.dom;
14575 this.assignDocWin();
14577 this.doc.designMode = 'on';
14580 this.doc.write(this.getDocMarkup());
14584 var task = { // must defer to wait for browser to be ready
14586 //console.log("run task?" + this.doc.readyState);
14587 this.assignDocWin();
14588 if(this.doc.body || this.doc.readyState == 'complete'){
14590 this.doc.designMode="on";
14594 Roo.TaskMgr.stop(task);
14595 this.initEditor.defer(10, this);
14602 Roo.TaskMgr.start(task);
14609 onResize : function(w, h)
14611 Roo.log('resize: ' +w + ',' + h );
14612 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14616 if(typeof w == 'number'){
14618 this.iframe.style.width = w + 'px';
14620 if(typeof h == 'number'){
14622 this.iframe.style.height = h + 'px';
14624 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14631 * Toggles the editor between standard and source edit mode.
14632 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14634 toggleSourceEdit : function(sourceEditMode){
14636 this.sourceEditMode = sourceEditMode === true;
14638 if(this.sourceEditMode){
14640 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14643 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14644 //this.iframe.className = '';
14647 //this.setSize(this.owner.wrap.getSize());
14648 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14655 * Protected method that will not generally be called directly. If you need/want
14656 * custom HTML cleanup, this is the method you should override.
14657 * @param {String} html The HTML to be cleaned
14658 * return {String} The cleaned HTML
14660 cleanHtml : function(html){
14661 html = String(html);
14662 if(html.length > 5){
14663 if(Roo.isSafari){ // strip safari nonsense
14664 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14667 if(html == ' '){
14674 * HTML Editor -> Textarea
14675 * Protected method that will not generally be called directly. Syncs the contents
14676 * of the editor iframe with the textarea.
14678 syncValue : function(){
14679 if(this.initialized){
14680 var bd = (this.doc.body || this.doc.documentElement);
14681 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14682 var html = bd.innerHTML;
14684 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14685 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14687 html = '<div style="'+m[0]+'">' + html + '</div>';
14690 html = this.cleanHtml(html);
14691 // fix up the special chars.. normaly like back quotes in word...
14692 // however we do not want to do this with chinese..
14693 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14694 var cc = b.charCodeAt();
14696 (cc >= 0x4E00 && cc < 0xA000 ) ||
14697 (cc >= 0x3400 && cc < 0x4E00 ) ||
14698 (cc >= 0xf900 && cc < 0xfb00 )
14704 if(this.owner.fireEvent('beforesync', this, html) !== false){
14705 this.el.dom.value = html;
14706 this.owner.fireEvent('sync', this, html);
14712 * Protected method that will not generally be called directly. Pushes the value of the textarea
14713 * into the iframe editor.
14715 pushValue : function(){
14716 if(this.initialized){
14717 var v = this.el.dom.value.trim();
14719 // if(v.length < 1){
14723 if(this.owner.fireEvent('beforepush', this, v) !== false){
14724 var d = (this.doc.body || this.doc.documentElement);
14726 this.cleanUpPaste();
14727 this.el.dom.value = d.innerHTML;
14728 this.owner.fireEvent('push', this, v);
14734 deferFocus : function(){
14735 this.focus.defer(10, this);
14739 focus : function(){
14740 if(this.win && !this.sourceEditMode){
14747 assignDocWin: function()
14749 var iframe = this.iframe;
14752 this.doc = iframe.contentWindow.document;
14753 this.win = iframe.contentWindow;
14755 if (!Roo.get(this.frameId)) {
14758 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14759 this.win = Roo.get(this.frameId).dom.contentWindow;
14764 initEditor : function(){
14765 //console.log("INIT EDITOR");
14766 this.assignDocWin();
14770 this.doc.designMode="on";
14772 this.doc.write(this.getDocMarkup());
14775 var dbody = (this.doc.body || this.doc.documentElement);
14776 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14777 // this copies styles from the containing element into thsi one..
14778 // not sure why we need all of this..
14779 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14780 ss['background-attachment'] = 'fixed'; // w3c
14781 dbody.bgProperties = 'fixed'; // ie
14782 Roo.DomHelper.applyStyles(dbody, ss);
14783 Roo.EventManager.on(this.doc, {
14784 //'mousedown': this.onEditorEvent,
14785 'mouseup': this.onEditorEvent,
14786 'dblclick': this.onEditorEvent,
14787 'click': this.onEditorEvent,
14788 'keyup': this.onEditorEvent,
14793 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14795 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14796 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14798 this.initialized = true;
14800 this.owner.fireEvent('initialize', this);
14805 onDestroy : function(){
14811 //for (var i =0; i < this.toolbars.length;i++) {
14812 // // fixme - ask toolbars for heights?
14813 // this.toolbars[i].onDestroy();
14816 //this.wrap.dom.innerHTML = '';
14817 //this.wrap.remove();
14822 onFirstFocus : function(){
14824 this.assignDocWin();
14827 this.activated = true;
14830 if(Roo.isGecko){ // prevent silly gecko errors
14832 var s = this.win.getSelection();
14833 if(!s.focusNode || s.focusNode.nodeType != 3){
14834 var r = s.getRangeAt(0);
14835 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14840 this.execCmd('useCSS', true);
14841 this.execCmd('styleWithCSS', false);
14844 this.owner.fireEvent('activate', this);
14848 adjustFont: function(btn){
14849 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14850 //if(Roo.isSafari){ // safari
14853 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14854 if(Roo.isSafari){ // safari
14855 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14856 v = (v < 10) ? 10 : v;
14857 v = (v > 48) ? 48 : v;
14858 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14863 v = Math.max(1, v+adjust);
14865 this.execCmd('FontSize', v );
14868 onEditorEvent : function(e){
14869 this.owner.fireEvent('editorevent', this, e);
14870 // this.updateToolbar();
14871 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14874 insertTag : function(tg)
14876 // could be a bit smarter... -> wrap the current selected tRoo..
14877 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14879 range = this.createRange(this.getSelection());
14880 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14881 wrappingNode.appendChild(range.extractContents());
14882 range.insertNode(wrappingNode);
14889 this.execCmd("formatblock", tg);
14893 insertText : function(txt)
14897 var range = this.createRange();
14898 range.deleteContents();
14899 //alert(Sender.getAttribute('label'));
14901 range.insertNode(this.doc.createTextNode(txt));
14907 * Executes a Midas editor command on the editor document and performs necessary focus and
14908 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14909 * @param {String} cmd The Midas command
14910 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14912 relayCmd : function(cmd, value){
14914 this.execCmd(cmd, value);
14915 this.owner.fireEvent('editorevent', this);
14916 //this.updateToolbar();
14917 this.owner.deferFocus();
14921 * Executes a Midas editor command directly on the editor document.
14922 * For visual commands, you should use {@link #relayCmd} instead.
14923 * <b>This should only be called after the editor is initialized.</b>
14924 * @param {String} cmd The Midas command
14925 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14927 execCmd : function(cmd, value){
14928 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14935 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14937 * @param {String} text | dom node..
14939 insertAtCursor : function(text)
14944 if(!this.activated){
14950 var r = this.doc.selection.createRange();
14961 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14965 // from jquery ui (MIT licenced)
14967 var win = this.win;
14969 if (win.getSelection && win.getSelection().getRangeAt) {
14970 range = win.getSelection().getRangeAt(0);
14971 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14972 range.insertNode(node);
14973 } else if (win.document.selection && win.document.selection.createRange) {
14974 // no firefox support
14975 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14976 win.document.selection.createRange().pasteHTML(txt);
14978 // no firefox support
14979 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14980 this.execCmd('InsertHTML', txt);
14989 mozKeyPress : function(e){
14991 var c = e.getCharCode(), cmd;
14994 c = String.fromCharCode(c).toLowerCase();
15008 this.cleanUpPaste.defer(100, this);
15016 e.preventDefault();
15024 fixKeys : function(){ // load time branching for fastest keydown performance
15026 return function(e){
15027 var k = e.getKey(), r;
15030 r = this.doc.selection.createRange();
15033 r.pasteHTML('    ');
15040 r = this.doc.selection.createRange();
15042 var target = r.parentElement();
15043 if(!target || target.tagName.toLowerCase() != 'li'){
15045 r.pasteHTML('<br />');
15051 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15052 this.cleanUpPaste.defer(100, this);
15058 }else if(Roo.isOpera){
15059 return function(e){
15060 var k = e.getKey();
15064 this.execCmd('InsertHTML','    ');
15067 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15068 this.cleanUpPaste.defer(100, this);
15073 }else if(Roo.isSafari){
15074 return function(e){
15075 var k = e.getKey();
15079 this.execCmd('InsertText','\t');
15083 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15084 this.cleanUpPaste.defer(100, this);
15092 getAllAncestors: function()
15094 var p = this.getSelectedNode();
15097 a.push(p); // push blank onto stack..
15098 p = this.getParentElement();
15102 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15106 a.push(this.doc.body);
15110 lastSelNode : false,
15113 getSelection : function()
15115 this.assignDocWin();
15116 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15119 getSelectedNode: function()
15121 // this may only work on Gecko!!!
15123 // should we cache this!!!!
15128 var range = this.createRange(this.getSelection()).cloneRange();
15131 var parent = range.parentElement();
15133 var testRange = range.duplicate();
15134 testRange.moveToElementText(parent);
15135 if (testRange.inRange(range)) {
15138 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15141 parent = parent.parentElement;
15146 // is ancestor a text element.
15147 var ac = range.commonAncestorContainer;
15148 if (ac.nodeType == 3) {
15149 ac = ac.parentNode;
15152 var ar = ac.childNodes;
15155 var other_nodes = [];
15156 var has_other_nodes = false;
15157 for (var i=0;i<ar.length;i++) {
15158 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15161 // fullly contained node.
15163 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15168 // probably selected..
15169 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15170 other_nodes.push(ar[i]);
15174 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15179 has_other_nodes = true;
15181 if (!nodes.length && other_nodes.length) {
15182 nodes= other_nodes;
15184 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15190 createRange: function(sel)
15192 // this has strange effects when using with
15193 // top toolbar - not sure if it's a great idea.
15194 //this.editor.contentWindow.focus();
15195 if (typeof sel != "undefined") {
15197 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15199 return this.doc.createRange();
15202 return this.doc.createRange();
15205 getParentElement: function()
15208 this.assignDocWin();
15209 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15211 var range = this.createRange(sel);
15214 var p = range.commonAncestorContainer;
15215 while (p.nodeType == 3) { // text node
15226 * Range intersection.. the hard stuff...
15230 * [ -- selected range --- ]
15234 * if end is before start or hits it. fail.
15235 * if start is after end or hits it fail.
15237 * if either hits (but other is outside. - then it's not
15243 // @see http://www.thismuchiknow.co.uk/?p=64.
15244 rangeIntersectsNode : function(range, node)
15246 var nodeRange = node.ownerDocument.createRange();
15248 nodeRange.selectNode(node);
15250 nodeRange.selectNodeContents(node);
15253 var rangeStartRange = range.cloneRange();
15254 rangeStartRange.collapse(true);
15256 var rangeEndRange = range.cloneRange();
15257 rangeEndRange.collapse(false);
15259 var nodeStartRange = nodeRange.cloneRange();
15260 nodeStartRange.collapse(true);
15262 var nodeEndRange = nodeRange.cloneRange();
15263 nodeEndRange.collapse(false);
15265 return rangeStartRange.compareBoundaryPoints(
15266 Range.START_TO_START, nodeEndRange) == -1 &&
15267 rangeEndRange.compareBoundaryPoints(
15268 Range.START_TO_START, nodeStartRange) == 1;
15272 rangeCompareNode : function(range, node)
15274 var nodeRange = node.ownerDocument.createRange();
15276 nodeRange.selectNode(node);
15278 nodeRange.selectNodeContents(node);
15282 range.collapse(true);
15284 nodeRange.collapse(true);
15286 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15287 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15289 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15291 var nodeIsBefore = ss == 1;
15292 var nodeIsAfter = ee == -1;
15294 if (nodeIsBefore && nodeIsAfter)
15296 if (!nodeIsBefore && nodeIsAfter)
15297 return 1; //right trailed.
15299 if (nodeIsBefore && !nodeIsAfter)
15300 return 2; // left trailed.
15305 // private? - in a new class?
15306 cleanUpPaste : function()
15308 // cleans up the whole document..
15309 Roo.log('cleanuppaste');
15311 this.cleanUpChildren(this.doc.body);
15312 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15313 if (clean != this.doc.body.innerHTML) {
15314 this.doc.body.innerHTML = clean;
15319 cleanWordChars : function(input) {// change the chars to hex code
15320 var he = Roo.HtmlEditorCore;
15322 var output = input;
15323 Roo.each(he.swapCodes, function(sw) {
15324 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15326 output = output.replace(swapper, sw[1]);
15333 cleanUpChildren : function (n)
15335 if (!n.childNodes.length) {
15338 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15339 this.cleanUpChild(n.childNodes[i]);
15346 cleanUpChild : function (node)
15349 //console.log(node);
15350 if (node.nodeName == "#text") {
15351 // clean up silly Windows -- stuff?
15354 if (node.nodeName == "#comment") {
15355 node.parentNode.removeChild(node);
15356 // clean up silly Windows -- stuff?
15360 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15362 node.parentNode.removeChild(node);
15367 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15369 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15370 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15372 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15373 // remove_keep_children = true;
15376 if (remove_keep_children) {
15377 this.cleanUpChildren(node);
15378 // inserts everything just before this node...
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);
15388 if (!node.attributes || !node.attributes.length) {
15389 this.cleanUpChildren(node);
15393 function cleanAttr(n,v)
15396 if (v.match(/^\./) || v.match(/^\//)) {
15399 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15402 if (v.match(/^#/)) {
15405 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15406 node.removeAttribute(n);
15410 function cleanStyle(n,v)
15412 if (v.match(/expression/)) { //XSS?? should we even bother..
15413 node.removeAttribute(n);
15416 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15417 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15420 var parts = v.split(/;/);
15423 Roo.each(parts, function(p) {
15424 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15428 var l = p.split(':').shift().replace(/\s+/g,'');
15429 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15431 if ( cblack.indexOf(l) > -1) {
15432 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15433 //node.removeAttribute(n);
15437 // only allow 'c whitelisted system attributes'
15438 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15439 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15440 //node.removeAttribute(n);
15450 if (clean.length) {
15451 node.setAttribute(n, clean.join(';'));
15453 node.removeAttribute(n);
15459 for (var i = node.attributes.length-1; i > -1 ; i--) {
15460 var a = node.attributes[i];
15463 if (a.name.toLowerCase().substr(0,2)=='on') {
15464 node.removeAttribute(a.name);
15467 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15468 node.removeAttribute(a.name);
15471 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15472 cleanAttr(a.name,a.value); // fixme..
15475 if (a.name == 'style') {
15476 cleanStyle(a.name,a.value);
15479 /// clean up MS crap..
15480 // tecnically this should be a list of valid class'es..
15483 if (a.name == 'class') {
15484 if (a.value.match(/^Mso/)) {
15485 node.className = '';
15488 if (a.value.match(/body/)) {
15489 node.className = '';
15500 this.cleanUpChildren(node);
15505 * Clean up MS wordisms...
15507 cleanWord : function(node)
15510 var cleanWordChildren = function()
15512 if (!node.childNodes.length) {
15515 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15516 _t.cleanWord(node.childNodes[i]);
15522 this.cleanWord(this.doc.body);
15525 if (node.nodeName == "#text") {
15526 // clean up silly Windows -- stuff?
15529 if (node.nodeName == "#comment") {
15530 node.parentNode.removeChild(node);
15531 // clean up silly Windows -- stuff?
15535 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15536 node.parentNode.removeChild(node);
15540 // remove - but keep children..
15541 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15542 while (node.childNodes.length) {
15543 var cn = node.childNodes[0];
15544 node.removeChild(cn);
15545 node.parentNode.insertBefore(cn, node);
15547 node.parentNode.removeChild(node);
15548 cleanWordChildren();
15552 if (node.className.length) {
15554 var cn = node.className.split(/\W+/);
15556 Roo.each(cn, function(cls) {
15557 if (cls.match(/Mso[a-zA-Z]+/)) {
15562 node.className = cna.length ? cna.join(' ') : '';
15564 node.removeAttribute("class");
15568 if (node.hasAttribute("lang")) {
15569 node.removeAttribute("lang");
15572 if (node.hasAttribute("style")) {
15574 var styles = node.getAttribute("style").split(";");
15576 Roo.each(styles, function(s) {
15577 if (!s.match(/:/)) {
15580 var kv = s.split(":");
15581 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15584 // what ever is left... we allow.
15587 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15588 if (!nstyle.length) {
15589 node.removeAttribute('style');
15593 cleanWordChildren();
15597 domToHTML : function(currentElement, depth, nopadtext) {
15599 depth = depth || 0;
15600 nopadtext = nopadtext || false;
15602 if (!currentElement) {
15603 return this.domToHTML(this.doc.body);
15606 //Roo.log(currentElement);
15608 var allText = false;
15609 var nodeName = currentElement.nodeName;
15610 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15612 if (nodeName == '#text') {
15613 return currentElement.nodeValue;
15618 if (nodeName != 'BODY') {
15621 // Prints the node tagName, such as <A>, <IMG>, etc
15624 for(i = 0; i < currentElement.attributes.length;i++) {
15626 var aname = currentElement.attributes.item(i).name;
15627 if (!currentElement.attributes.item(i).value.length) {
15630 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15633 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15642 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15645 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15650 // Traverse the tree
15652 var currentElementChild = currentElement.childNodes.item(i);
15653 var allText = true;
15654 var innerHTML = '';
15656 while (currentElementChild) {
15657 // Formatting code (indent the tree so it looks nice on the screen)
15658 var nopad = nopadtext;
15659 if (lastnode == 'SPAN') {
15663 if (currentElementChild.nodeName == '#text') {
15664 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15665 if (!nopad && toadd.length > 80) {
15666 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15668 innerHTML += toadd;
15671 currentElementChild = currentElement.childNodes.item(i);
15677 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15679 // Recursively traverse the tree structure of the child node
15680 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15681 lastnode = currentElementChild.nodeName;
15683 currentElementChild=currentElement.childNodes.item(i);
15689 // The remaining code is mostly for formatting the tree
15690 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15695 ret+= "</"+tagName+">";
15701 // hide stuff that is not compatible
15715 * @event specialkey
15719 * @cfg {String} fieldClass @hide
15722 * @cfg {String} focusClass @hide
15725 * @cfg {String} autoCreate @hide
15728 * @cfg {String} inputType @hide
15731 * @cfg {String} invalidClass @hide
15734 * @cfg {String} invalidText @hide
15737 * @cfg {String} msgFx @hide
15740 * @cfg {String} validateOnBlur @hide
15744 Roo.HtmlEditorCore.white = [
15745 'area', 'br', 'img', 'input', 'hr', 'wbr',
15747 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15748 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15749 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15750 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15751 'table', 'ul', 'xmp',
15753 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15756 'dir', 'menu', 'ol', 'ul', 'dl',
15762 Roo.HtmlEditorCore.black = [
15763 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15765 'base', 'basefont', 'bgsound', 'blink', 'body',
15766 'frame', 'frameset', 'head', 'html', 'ilayer',
15767 'iframe', 'layer', 'link', 'meta', 'object',
15768 'script', 'style' ,'title', 'xml' // clean later..
15770 Roo.HtmlEditorCore.clean = [
15771 'script', 'style', 'title', 'xml'
15773 Roo.HtmlEditorCore.remove = [
15778 Roo.HtmlEditorCore.ablack = [
15782 Roo.HtmlEditorCore.aclean = [
15783 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15787 Roo.HtmlEditorCore.pwhite= [
15788 'http', 'https', 'mailto'
15791 // white listed style attributes.
15792 Roo.HtmlEditorCore.cwhite= [
15793 // 'text-align', /// default is to allow most things..
15799 // black listed style attributes.
15800 Roo.HtmlEditorCore.cblack= [
15801 // 'font-size' -- this can be set by the project
15805 Roo.HtmlEditorCore.swapCodes =[
15824 * @class Roo.bootstrap.HtmlEditor
15825 * @extends Roo.bootstrap.TextArea
15826 * Bootstrap HtmlEditor class
15829 * Create a new HtmlEditor
15830 * @param {Object} config The config object
15833 Roo.bootstrap.HtmlEditor = function(config){
15834 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15835 if (!this.toolbars) {
15836 this.toolbars = [];
15838 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15841 * @event initialize
15842 * Fires when the editor is fully initialized (including the iframe)
15843 * @param {HtmlEditor} this
15848 * Fires when the editor is first receives the focus. Any insertion must wait
15849 * until after this event.
15850 * @param {HtmlEditor} this
15854 * @event beforesync
15855 * Fires before the textarea is updated with content from the editor iframe. Return false
15856 * to cancel the sync.
15857 * @param {HtmlEditor} this
15858 * @param {String} html
15862 * @event beforepush
15863 * Fires before the iframe editor is updated with content from the textarea. Return false
15864 * to cancel the push.
15865 * @param {HtmlEditor} this
15866 * @param {String} html
15871 * Fires when the textarea is updated with content from the editor iframe.
15872 * @param {HtmlEditor} this
15873 * @param {String} html
15878 * Fires when the iframe editor is updated with content from the textarea.
15879 * @param {HtmlEditor} this
15880 * @param {String} html
15884 * @event editmodechange
15885 * Fires when the editor switches edit modes
15886 * @param {HtmlEditor} this
15887 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15889 editmodechange: true,
15891 * @event editorevent
15892 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15893 * @param {HtmlEditor} this
15897 * @event firstfocus
15898 * Fires when on first focus - needed by toolbars..
15899 * @param {HtmlEditor} this
15904 * Auto save the htmlEditor value as a file into Events
15905 * @param {HtmlEditor} this
15909 * @event savedpreview
15910 * preview the saved version of htmlEditor
15911 * @param {HtmlEditor} this
15918 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15922 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15927 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15932 * @cfg {Number} height (in pixels)
15936 * @cfg {Number} width (in pixels)
15941 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15944 stylesheets: false,
15949 // private properties
15950 validationEvent : false,
15952 initialized : false,
15955 onFocus : Roo.emptyFn,
15957 hideMode:'offsets',
15960 tbContainer : false,
15962 toolbarContainer :function() {
15963 return this.wrap.select('.x-html-editor-tb',true).first();
15967 * Protected method that will not generally be called directly. It
15968 * is called when the editor creates its toolbar. Override this method if you need to
15969 * add custom toolbar buttons.
15970 * @param {HtmlEditor} editor
15972 createToolbar : function(){
15974 Roo.log("create toolbars");
15976 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15977 this.toolbars[0].render(this.toolbarContainer());
15981 // if (!editor.toolbars || !editor.toolbars.length) {
15982 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15985 // for (var i =0 ; i < editor.toolbars.length;i++) {
15986 // editor.toolbars[i] = Roo.factory(
15987 // typeof(editor.toolbars[i]) == 'string' ?
15988 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15989 // Roo.bootstrap.HtmlEditor);
15990 // editor.toolbars[i].init(editor);
15996 onRender : function(ct, position)
15998 // Roo.log("Call onRender: " + this.xtype);
16000 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
16002 this.wrap = this.inputEl().wrap({
16003 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16006 this.editorcore.onRender(ct, position);
16008 if (this.resizable) {
16009 this.resizeEl = new Roo.Resizable(this.wrap, {
16013 minHeight : this.height,
16014 height: this.height,
16015 handles : this.resizable,
16018 resize : function(r, w, h) {
16019 _t.onResize(w,h); // -something
16025 this.createToolbar(this);
16028 if(!this.width && this.resizable){
16029 this.setSize(this.wrap.getSize());
16031 if (this.resizeEl) {
16032 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16033 // should trigger onReize..
16039 onResize : function(w, h)
16041 Roo.log('resize: ' +w + ',' + h );
16042 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16046 if(this.inputEl() ){
16047 if(typeof w == 'number'){
16048 var aw = w - this.wrap.getFrameWidth('lr');
16049 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16052 if(typeof h == 'number'){
16053 var tbh = -11; // fixme it needs to tool bar size!
16054 for (var i =0; i < this.toolbars.length;i++) {
16055 // fixme - ask toolbars for heights?
16056 tbh += this.toolbars[i].el.getHeight();
16057 //if (this.toolbars[i].footer) {
16058 // tbh += this.toolbars[i].footer.el.getHeight();
16066 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16067 ah -= 5; // knock a few pixes off for look..
16068 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16072 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16073 this.editorcore.onResize(ew,eh);
16078 * Toggles the editor between standard and source edit mode.
16079 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16081 toggleSourceEdit : function(sourceEditMode)
16083 this.editorcore.toggleSourceEdit(sourceEditMode);
16085 if(this.editorcore.sourceEditMode){
16086 Roo.log('editor - showing textarea');
16089 // Roo.log(this.syncValue());
16091 this.inputEl().removeClass('hide');
16092 this.inputEl().dom.removeAttribute('tabIndex');
16093 this.inputEl().focus();
16095 Roo.log('editor - hiding textarea');
16097 // Roo.log(this.pushValue());
16100 this.inputEl().addClass('hide');
16101 this.inputEl().dom.setAttribute('tabIndex', -1);
16102 //this.deferFocus();
16105 if(this.resizable){
16106 this.setSize(this.wrap.getSize());
16109 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16112 // private (for BoxComponent)
16113 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16115 // private (for BoxComponent)
16116 getResizeEl : function(){
16120 // private (for BoxComponent)
16121 getPositionEl : function(){
16126 initEvents : function(){
16127 this.originalValue = this.getValue();
16131 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16134 // markInvalid : Roo.emptyFn,
16136 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16139 // clearInvalid : Roo.emptyFn,
16141 setValue : function(v){
16142 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16143 this.editorcore.pushValue();
16148 deferFocus : function(){
16149 this.focus.defer(10, this);
16153 focus : function(){
16154 this.editorcore.focus();
16160 onDestroy : function(){
16166 for (var i =0; i < this.toolbars.length;i++) {
16167 // fixme - ask toolbars for heights?
16168 this.toolbars[i].onDestroy();
16171 this.wrap.dom.innerHTML = '';
16172 this.wrap.remove();
16177 onFirstFocus : function(){
16178 //Roo.log("onFirstFocus");
16179 this.editorcore.onFirstFocus();
16180 for (var i =0; i < this.toolbars.length;i++) {
16181 this.toolbars[i].onFirstFocus();
16187 syncValue : function()
16189 this.editorcore.syncValue();
16192 pushValue : function()
16194 this.editorcore.pushValue();
16198 // hide stuff that is not compatible
16212 * @event specialkey
16216 * @cfg {String} fieldClass @hide
16219 * @cfg {String} focusClass @hide
16222 * @cfg {String} autoCreate @hide
16225 * @cfg {String} inputType @hide
16228 * @cfg {String} invalidClass @hide
16231 * @cfg {String} invalidText @hide
16234 * @cfg {String} msgFx @hide
16237 * @cfg {String} validateOnBlur @hide
16248 * @class Roo.bootstrap.HtmlEditorToolbar1
16253 new Roo.bootstrap.HtmlEditor({
16256 new Roo.bootstrap.HtmlEditorToolbar1({
16257 disable : { fonts: 1 , format: 1, ..., ... , ...],
16263 * @cfg {Object} disable List of elements to disable..
16264 * @cfg {Array} btns List of additional buttons.
16268 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16271 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
16274 Roo.apply(this, config);
16276 // default disabled, based on 'good practice'..
16277 this.disable = this.disable || {};
16278 Roo.applyIf(this.disable, {
16281 specialElements : true
16283 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
16285 this.editor = config.editor;
16286 this.editorcore = config.editor.editorcore;
16288 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16290 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16291 // dont call parent... till later.
16293 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16299 editorcore : false,
16304 "h1","h2","h3","h4","h5","h6",
16306 "abbr", "acronym", "address", "cite", "samp", "var",
16310 onRender : function(ct, position)
16312 // Roo.log("Call onRender: " + this.xtype);
16314 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16316 this.el.dom.style.marginBottom = '0';
16318 var editorcore = this.editorcore;
16319 var editor= this.editor;
16322 var btn = function(id,cmd , toggle, handler){
16324 var event = toggle ? 'toggle' : 'click';
16329 xns: Roo.bootstrap,
16332 enableToggle:toggle !== false,
16334 pressed : toggle ? false : null,
16337 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16338 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16347 xns: Roo.bootstrap,
16348 glyphicon : 'font',
16352 xns: Roo.bootstrap,
16356 Roo.each(this.formats, function(f) {
16357 style.menu.items.push({
16359 xns: Roo.bootstrap,
16360 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16365 editorcore.insertTag(this.tagname);
16372 children.push(style);
16375 btn('bold',false,true);
16376 btn('italic',false,true);
16377 btn('align-left', 'justifyleft',true);
16378 btn('align-center', 'justifycenter',true);
16379 btn('align-right' , 'justifyright',true);
16380 btn('link', false, false, function(btn) {
16381 //Roo.log("create link?");
16382 var url = prompt(this.createLinkText, this.defaultLinkValue);
16383 if(url && url != 'http:/'+'/'){
16384 this.editorcore.relayCmd('createlink', url);
16387 btn('list','insertunorderedlist',true);
16388 btn('pencil', false,true, function(btn){
16391 this.toggleSourceEdit(btn.pressed);
16397 xns: Roo.bootstrap,
16402 xns: Roo.bootstrap,
16407 cog.menu.items.push({
16409 xns: Roo.bootstrap,
16410 html : Clean styles,
16415 editorcore.insertTag(this.tagname);
16424 this.xtype = 'NavSimplebar';
16426 for(var i=0;i< children.length;i++) {
16428 this.buttons.add(this.addxtypeChild(children[i]));
16432 editor.on('editorevent', this.updateToolbar, this);
16434 onBtnClick : function(id)
16436 this.editorcore.relayCmd(id);
16437 this.editorcore.focus();
16441 * Protected method that will not generally be called directly. It triggers
16442 * a toolbar update by reading the markup state of the current selection in the editor.
16444 updateToolbar: function(){
16446 if(!this.editorcore.activated){
16447 this.editor.onFirstFocus(); // is this neeed?
16451 var btns = this.buttons;
16452 var doc = this.editorcore.doc;
16453 btns.get('bold').setActive(doc.queryCommandState('bold'));
16454 btns.get('italic').setActive(doc.queryCommandState('italic'));
16455 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16457 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16458 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16459 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16461 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16462 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16465 var ans = this.editorcore.getAllAncestors();
16466 if (this.formatCombo) {
16469 var store = this.formatCombo.store;
16470 this.formatCombo.setValue("");
16471 for (var i =0; i < ans.length;i++) {
16472 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16474 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16482 // hides menus... - so this cant be on a menu...
16483 Roo.bootstrap.MenuMgr.hideAll();
16485 Roo.bootstrap.MenuMgr.hideAll();
16486 //this.editorsyncValue();
16488 onFirstFocus: function() {
16489 this.buttons.each(function(item){
16493 toggleSourceEdit : function(sourceEditMode){
16496 if(sourceEditMode){
16497 Roo.log("disabling buttons");
16498 this.buttons.each( function(item){
16499 if(item.cmd != 'pencil'){
16505 Roo.log("enabling buttons");
16506 if(this.editorcore.initialized){
16507 this.buttons.each( function(item){
16513 Roo.log("calling toggole on editor");
16514 // tell the editor that it's been pressed..
16515 this.editor.toggleSourceEdit(sourceEditMode);
16525 * @class Roo.bootstrap.Table.AbstractSelectionModel
16526 * @extends Roo.util.Observable
16527 * Abstract base class for grid SelectionModels. It provides the interface that should be
16528 * implemented by descendant classes. This class should not be directly instantiated.
16531 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16532 this.locked = false;
16533 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16537 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16538 /** @ignore Called by the grid automatically. Do not call directly. */
16539 init : function(grid){
16545 * Locks the selections.
16548 this.locked = true;
16552 * Unlocks the selections.
16554 unlock : function(){
16555 this.locked = false;
16559 * Returns true if the selections are locked.
16560 * @return {Boolean}
16562 isLocked : function(){
16563 return this.locked;
16567 * @class Roo.bootstrap.Table.ColumnModel
16568 * @extends Roo.util.Observable
16569 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16570 * the columns in the table.
16573 * @param {Object} config An Array of column config objects. See this class's
16574 * config objects for details.
16576 Roo.bootstrap.Table.ColumnModel = function(config){
16578 * The config passed into the constructor
16580 this.config = config;
16583 // if no id, create one
16584 // if the column does not have a dataIndex mapping,
16585 // map it to the order it is in the config
16586 for(var i = 0, len = config.length; i < len; i++){
16588 if(typeof c.dataIndex == "undefined"){
16591 if(typeof c.renderer == "string"){
16592 c.renderer = Roo.util.Format[c.renderer];
16594 if(typeof c.id == "undefined"){
16597 // if(c.editor && c.editor.xtype){
16598 // c.editor = Roo.factory(c.editor, Roo.grid);
16600 // if(c.editor && c.editor.isFormField){
16601 // c.editor = new Roo.grid.GridEditor(c.editor);
16604 this.lookup[c.id] = c;
16608 * The width of columns which have no width specified (defaults to 100)
16611 this.defaultWidth = 100;
16614 * Default sortable of columns which have no sortable specified (defaults to false)
16617 this.defaultSortable = false;
16621 * @event widthchange
16622 * Fires when the width of a column changes.
16623 * @param {ColumnModel} this
16624 * @param {Number} columnIndex The column index
16625 * @param {Number} newWidth The new width
16627 "widthchange": true,
16629 * @event headerchange
16630 * Fires when the text of a header changes.
16631 * @param {ColumnModel} this
16632 * @param {Number} columnIndex The column index
16633 * @param {Number} newText The new header text
16635 "headerchange": true,
16637 * @event hiddenchange
16638 * Fires when a column is hidden or "unhidden".
16639 * @param {ColumnModel} this
16640 * @param {Number} columnIndex The column index
16641 * @param {Boolean} hidden true if hidden, false otherwise
16643 "hiddenchange": true,
16645 * @event columnmoved
16646 * Fires when a column is moved.
16647 * @param {ColumnModel} this
16648 * @param {Number} oldIndex
16649 * @param {Number} newIndex
16651 "columnmoved" : true,
16653 * @event columlockchange
16654 * Fires when a column's locked state is changed
16655 * @param {ColumnModel} this
16656 * @param {Number} colIndex
16657 * @param {Boolean} locked true if locked
16659 "columnlockchange" : true
16661 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16663 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16665 * @cfg {String} header The header text to display in the Grid view.
16668 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16669 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16670 * specified, the column's index is used as an index into the Record's data Array.
16673 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16674 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16677 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16678 * Defaults to the value of the {@link #defaultSortable} property.
16679 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16682 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16685 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16688 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16691 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16694 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16695 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16696 * default renderer uses the raw data value.
16699 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16703 * Returns the id of the column at the specified index.
16704 * @param {Number} index The column index
16705 * @return {String} the id
16707 getColumnId : function(index){
16708 return this.config[index].id;
16712 * Returns the column for a specified id.
16713 * @param {String} id The column id
16714 * @return {Object} the column
16716 getColumnById : function(id){
16717 return this.lookup[id];
16722 * Returns the column for a specified dataIndex.
16723 * @param {String} dataIndex The column dataIndex
16724 * @return {Object|Boolean} the column or false if not found
16726 getColumnByDataIndex: function(dataIndex){
16727 var index = this.findColumnIndex(dataIndex);
16728 return index > -1 ? this.config[index] : false;
16732 * Returns the index for a specified column id.
16733 * @param {String} id The column id
16734 * @return {Number} the index, or -1 if not found
16736 getIndexById : function(id){
16737 for(var i = 0, len = this.config.length; i < len; i++){
16738 if(this.config[i].id == id){
16746 * Returns the index for a specified column dataIndex.
16747 * @param {String} dataIndex The column dataIndex
16748 * @return {Number} the index, or -1 if not found
16751 findColumnIndex : function(dataIndex){
16752 for(var i = 0, len = this.config.length; i < len; i++){
16753 if(this.config[i].dataIndex == dataIndex){
16761 moveColumn : function(oldIndex, newIndex){
16762 var c = this.config[oldIndex];
16763 this.config.splice(oldIndex, 1);
16764 this.config.splice(newIndex, 0, c);
16765 this.dataMap = null;
16766 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16769 isLocked : function(colIndex){
16770 return this.config[colIndex].locked === true;
16773 setLocked : function(colIndex, value, suppressEvent){
16774 if(this.isLocked(colIndex) == value){
16777 this.config[colIndex].locked = value;
16778 if(!suppressEvent){
16779 this.fireEvent("columnlockchange", this, colIndex, value);
16783 getTotalLockedWidth : function(){
16784 var totalWidth = 0;
16785 for(var i = 0; i < this.config.length; i++){
16786 if(this.isLocked(i) && !this.isHidden(i)){
16787 this.totalWidth += this.getColumnWidth(i);
16793 getLockedCount : function(){
16794 for(var i = 0, len = this.config.length; i < len; i++){
16795 if(!this.isLocked(i)){
16802 * Returns the number of columns.
16805 getColumnCount : function(visibleOnly){
16806 if(visibleOnly === true){
16808 for(var i = 0, len = this.config.length; i < len; i++){
16809 if(!this.isHidden(i)){
16815 return this.config.length;
16819 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16820 * @param {Function} fn
16821 * @param {Object} scope (optional)
16822 * @return {Array} result
16824 getColumnsBy : function(fn, scope){
16826 for(var i = 0, len = this.config.length; i < len; i++){
16827 var c = this.config[i];
16828 if(fn.call(scope||this, c, i) === true){
16836 * Returns true if the specified column is sortable.
16837 * @param {Number} col The column index
16838 * @return {Boolean}
16840 isSortable : function(col){
16841 if(typeof this.config[col].sortable == "undefined"){
16842 return this.defaultSortable;
16844 return this.config[col].sortable;
16848 * Returns the rendering (formatting) function defined for the column.
16849 * @param {Number} col The column index.
16850 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16852 getRenderer : function(col){
16853 if(!this.config[col].renderer){
16854 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16856 return this.config[col].renderer;
16860 * Sets the rendering (formatting) function for a column.
16861 * @param {Number} col The column index
16862 * @param {Function} fn The function to use to process the cell's raw data
16863 * to return HTML markup for the grid view. The render function is called with
16864 * the following parameters:<ul>
16865 * <li>Data value.</li>
16866 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16867 * <li>css A CSS style string to apply to the table cell.</li>
16868 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16869 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16870 * <li>Row index</li>
16871 * <li>Column index</li>
16872 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16874 setRenderer : function(col, fn){
16875 this.config[col].renderer = fn;
16879 * Returns the width for the specified column.
16880 * @param {Number} col The column index
16883 getColumnWidth : function(col){
16884 return this.config[col].width * 1 || this.defaultWidth;
16888 * Sets the width for a column.
16889 * @param {Number} col The column index
16890 * @param {Number} width The new width
16892 setColumnWidth : function(col, width, suppressEvent){
16893 this.config[col].width = width;
16894 this.totalWidth = null;
16895 if(!suppressEvent){
16896 this.fireEvent("widthchange", this, col, width);
16901 * Returns the total width of all columns.
16902 * @param {Boolean} includeHidden True to include hidden column widths
16905 getTotalWidth : function(includeHidden){
16906 if(!this.totalWidth){
16907 this.totalWidth = 0;
16908 for(var i = 0, len = this.config.length; i < len; i++){
16909 if(includeHidden || !this.isHidden(i)){
16910 this.totalWidth += this.getColumnWidth(i);
16914 return this.totalWidth;
16918 * Returns the header for the specified column.
16919 * @param {Number} col The column index
16922 getColumnHeader : function(col){
16923 return this.config[col].header;
16927 * Sets the header for a column.
16928 * @param {Number} col The column index
16929 * @param {String} header The new header
16931 setColumnHeader : function(col, header){
16932 this.config[col].header = header;
16933 this.fireEvent("headerchange", this, col, header);
16937 * Returns the tooltip for the specified column.
16938 * @param {Number} col The column index
16941 getColumnTooltip : function(col){
16942 return this.config[col].tooltip;
16945 * Sets the tooltip for a column.
16946 * @param {Number} col The column index
16947 * @param {String} tooltip The new tooltip
16949 setColumnTooltip : function(col, tooltip){
16950 this.config[col].tooltip = tooltip;
16954 * Returns the dataIndex for the specified column.
16955 * @param {Number} col The column index
16958 getDataIndex : function(col){
16959 return this.config[col].dataIndex;
16963 * Sets the dataIndex for a column.
16964 * @param {Number} col The column index
16965 * @param {Number} dataIndex The new dataIndex
16967 setDataIndex : function(col, dataIndex){
16968 this.config[col].dataIndex = dataIndex;
16974 * Returns true if the cell is editable.
16975 * @param {Number} colIndex The column index
16976 * @param {Number} rowIndex The row index
16977 * @return {Boolean}
16979 isCellEditable : function(colIndex, rowIndex){
16980 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16984 * Returns the editor defined for the cell/column.
16985 * return false or null to disable editing.
16986 * @param {Number} colIndex The column index
16987 * @param {Number} rowIndex The row index
16990 getCellEditor : function(colIndex, rowIndex){
16991 return this.config[colIndex].editor;
16995 * Sets if a column is editable.
16996 * @param {Number} col The column index
16997 * @param {Boolean} editable True if the column is editable
16999 setEditable : function(col, editable){
17000 this.config[col].editable = editable;
17005 * Returns true if the column is hidden.
17006 * @param {Number} colIndex The column index
17007 * @return {Boolean}
17009 isHidden : function(colIndex){
17010 return this.config[colIndex].hidden;
17015 * Returns true if the column width cannot be changed
17017 isFixed : function(colIndex){
17018 return this.config[colIndex].fixed;
17022 * Returns true if the column can be resized
17023 * @return {Boolean}
17025 isResizable : function(colIndex){
17026 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
17029 * Sets if a column is hidden.
17030 * @param {Number} colIndex The column index
17031 * @param {Boolean} hidden True if the column is hidden
17033 setHidden : function(colIndex, hidden){
17034 this.config[colIndex].hidden = hidden;
17035 this.totalWidth = null;
17036 this.fireEvent("hiddenchange", this, colIndex, hidden);
17040 * Sets the editor for a column.
17041 * @param {Number} col The column index
17042 * @param {Object} editor The editor object
17044 setEditor : function(col, editor){
17045 this.config[col].editor = editor;
17049 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
17050 if(typeof value == "string" && value.length < 1){
17056 // Alias for backwards compatibility
17057 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
17060 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17061 * @class Roo.bootstrap.Table.RowSelectionModel
17062 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17063 * It supports multiple selections and keyboard selection/navigation.
17065 * @param {Object} config
17068 Roo.bootstrap.Table.RowSelectionModel = function(config){
17069 Roo.apply(this, config);
17070 this.selections = new Roo.util.MixedCollection(false, function(o){
17075 this.lastActive = false;
17079 * @event selectionchange
17080 * Fires when the selection changes
17081 * @param {SelectionModel} this
17083 "selectionchange" : true,
17085 * @event afterselectionchange
17086 * Fires after the selection changes (eg. by key press or clicking)
17087 * @param {SelectionModel} this
17089 "afterselectionchange" : true,
17091 * @event beforerowselect
17092 * Fires when a row is selected being selected, return false to cancel.
17093 * @param {SelectionModel} this
17094 * @param {Number} rowIndex The selected index
17095 * @param {Boolean} keepExisting False if other selections will be cleared
17097 "beforerowselect" : true,
17100 * Fires when a row is selected.
17101 * @param {SelectionModel} this
17102 * @param {Number} rowIndex The selected index
17103 * @param {Roo.data.Record} r The record
17105 "rowselect" : true,
17107 * @event rowdeselect
17108 * Fires when a row is deselected.
17109 * @param {SelectionModel} this
17110 * @param {Number} rowIndex The selected index
17112 "rowdeselect" : true
17114 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17115 this.locked = false;
17118 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17120 * @cfg {Boolean} singleSelect
17121 * True to allow selection of only one row at a time (defaults to false)
17123 singleSelect : false,
17126 initEvents : function(){
17128 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17129 this.grid.on("mousedown", this.handleMouseDown, this);
17130 }else{ // allow click to work like normal
17131 this.grid.on("rowclick", this.handleDragableRowClick, this);
17134 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17135 "up" : function(e){
17137 this.selectPrevious(e.shiftKey);
17138 }else if(this.last !== false && this.lastActive !== false){
17139 var last = this.last;
17140 this.selectRange(this.last, this.lastActive-1);
17141 this.grid.getView().focusRow(this.lastActive);
17142 if(last !== false){
17146 this.selectFirstRow();
17148 this.fireEvent("afterselectionchange", this);
17150 "down" : function(e){
17152 this.selectNext(e.shiftKey);
17153 }else if(this.last !== false && this.lastActive !== false){
17154 var last = this.last;
17155 this.selectRange(this.last, this.lastActive+1);
17156 this.grid.getView().focusRow(this.lastActive);
17157 if(last !== false){
17161 this.selectFirstRow();
17163 this.fireEvent("afterselectionchange", this);
17168 var view = this.grid.view;
17169 view.on("refresh", this.onRefresh, this);
17170 view.on("rowupdated", this.onRowUpdated, this);
17171 view.on("rowremoved", this.onRemove, this);
17175 onRefresh : function(){
17176 var ds = this.grid.dataSource, i, v = this.grid.view;
17177 var s = this.selections;
17178 s.each(function(r){
17179 if((i = ds.indexOfId(r.id)) != -1){
17188 onRemove : function(v, index, r){
17189 this.selections.remove(r);
17193 onRowUpdated : function(v, index, r){
17194 if(this.isSelected(r)){
17195 v.onRowSelect(index);
17201 * @param {Array} records The records to select
17202 * @param {Boolean} keepExisting (optional) True to keep existing selections
17204 selectRecords : function(records, keepExisting){
17206 this.clearSelections();
17208 var ds = this.grid.dataSource;
17209 for(var i = 0, len = records.length; i < len; i++){
17210 this.selectRow(ds.indexOf(records[i]), true);
17215 * Gets the number of selected rows.
17218 getCount : function(){
17219 return this.selections.length;
17223 * Selects the first row in the grid.
17225 selectFirstRow : function(){
17230 * Select the last row.
17231 * @param {Boolean} keepExisting (optional) True to keep existing selections
17233 selectLastRow : function(keepExisting){
17234 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17238 * Selects the row immediately following the last selected row.
17239 * @param {Boolean} keepExisting (optional) True to keep existing selections
17241 selectNext : function(keepExisting){
17242 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17243 this.selectRow(this.last+1, keepExisting);
17244 this.grid.getView().focusRow(this.last);
17249 * Selects the row that precedes the last selected row.
17250 * @param {Boolean} keepExisting (optional) True to keep existing selections
17252 selectPrevious : function(keepExisting){
17254 this.selectRow(this.last-1, keepExisting);
17255 this.grid.getView().focusRow(this.last);
17260 * Returns the selected records
17261 * @return {Array} Array of selected records
17263 getSelections : function(){
17264 return [].concat(this.selections.items);
17268 * Returns the first selected record.
17271 getSelected : function(){
17272 return this.selections.itemAt(0);
17277 * Clears all selections.
17279 clearSelections : function(fast){
17280 if(this.locked) return;
17282 var ds = this.grid.dataSource;
17283 var s = this.selections;
17284 s.each(function(r){
17285 this.deselectRow(ds.indexOfId(r.id));
17289 this.selections.clear();
17296 * Selects all rows.
17298 selectAll : function(){
17299 if(this.locked) return;
17300 this.selections.clear();
17301 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17302 this.selectRow(i, true);
17307 * Returns True if there is a selection.
17308 * @return {Boolean}
17310 hasSelection : function(){
17311 return this.selections.length > 0;
17315 * Returns True if the specified row is selected.
17316 * @param {Number/Record} record The record or index of the record to check
17317 * @return {Boolean}
17319 isSelected : function(index){
17320 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17321 return (r && this.selections.key(r.id) ? true : false);
17325 * Returns True if the specified record id is selected.
17326 * @param {String} id The id of record to check
17327 * @return {Boolean}
17329 isIdSelected : function(id){
17330 return (this.selections.key(id) ? true : false);
17334 handleMouseDown : function(e, t){
17335 var view = this.grid.getView(), rowIndex;
17336 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17339 if(e.shiftKey && this.last !== false){
17340 var last = this.last;
17341 this.selectRange(last, rowIndex, e.ctrlKey);
17342 this.last = last; // reset the last
17343 view.focusRow(rowIndex);
17345 var isSelected = this.isSelected(rowIndex);
17346 if(e.button !== 0 && isSelected){
17347 view.focusRow(rowIndex);
17348 }else if(e.ctrlKey && isSelected){
17349 this.deselectRow(rowIndex);
17350 }else if(!isSelected){
17351 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17352 view.focusRow(rowIndex);
17355 this.fireEvent("afterselectionchange", this);
17358 handleDragableRowClick : function(grid, rowIndex, e)
17360 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17361 this.selectRow(rowIndex, false);
17362 grid.view.focusRow(rowIndex);
17363 this.fireEvent("afterselectionchange", this);
17368 * Selects multiple rows.
17369 * @param {Array} rows Array of the indexes of the row to select
17370 * @param {Boolean} keepExisting (optional) True to keep existing selections
17372 selectRows : function(rows, keepExisting){
17374 this.clearSelections();
17376 for(var i = 0, len = rows.length; i < len; i++){
17377 this.selectRow(rows[i], true);
17382 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17383 * @param {Number} startRow The index of the first row in the range
17384 * @param {Number} endRow The index of the last row in the range
17385 * @param {Boolean} keepExisting (optional) True to retain existing selections
17387 selectRange : function(startRow, endRow, keepExisting){
17388 if(this.locked) return;
17390 this.clearSelections();
17392 if(startRow <= endRow){
17393 for(var i = startRow; i <= endRow; i++){
17394 this.selectRow(i, true);
17397 for(var i = startRow; i >= endRow; i--){
17398 this.selectRow(i, true);
17404 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17405 * @param {Number} startRow The index of the first row in the range
17406 * @param {Number} endRow The index of the last row in the range
17408 deselectRange : function(startRow, endRow, preventViewNotify){
17409 if(this.locked) return;
17410 for(var i = startRow; i <= endRow; i++){
17411 this.deselectRow(i, preventViewNotify);
17417 * @param {Number} row The index of the row to select
17418 * @param {Boolean} keepExisting (optional) True to keep existing selections
17420 selectRow : function(index, keepExisting, preventViewNotify){
17421 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17422 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17423 if(!keepExisting || this.singleSelect){
17424 this.clearSelections();
17426 var r = this.grid.dataSource.getAt(index);
17427 this.selections.add(r);
17428 this.last = this.lastActive = index;
17429 if(!preventViewNotify){
17430 this.grid.getView().onRowSelect(index);
17432 this.fireEvent("rowselect", this, index, r);
17433 this.fireEvent("selectionchange", this);
17439 * @param {Number} row The index of the row to deselect
17441 deselectRow : function(index, preventViewNotify){
17442 if(this.locked) return;
17443 if(this.last == index){
17446 if(this.lastActive == index){
17447 this.lastActive = false;
17449 var r = this.grid.dataSource.getAt(index);
17450 this.selections.remove(r);
17451 if(!preventViewNotify){
17452 this.grid.getView().onRowDeselect(index);
17454 this.fireEvent("rowdeselect", this, index);
17455 this.fireEvent("selectionchange", this);
17459 restoreLast : function(){
17461 this.last = this._last;
17466 acceptsNav : function(row, col, cm){
17467 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17471 onEditorKey : function(field, e){
17472 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17477 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17479 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17481 }else if(k == e.ENTER && !e.ctrlKey){
17485 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17487 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17489 }else if(k == e.ESC){
17493 g.startEditing(newCell[0], newCell[1]);
17504 * @class Roo.bootstrap.MessageBar
17505 * @extends Roo.bootstrap.Component
17506 * Bootstrap MessageBar class
17507 * @cfg {String} html contents of the MessageBar
17508 * @cfg {String} weight (info | success | warning | danger) default info
17509 * @cfg {String} beforeClass insert the bar before the given class
17510 * @cfg {Boolean} closable (true | false) default false
17511 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17514 * Create a new Element
17515 * @param {Object} config The config object
17518 Roo.bootstrap.MessageBar = function(config){
17519 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17522 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17528 beforeClass: 'bootstrap-sticky-wrap',
17530 getAutoCreate : function(){
17534 cls: 'alert alert-dismissable alert-' + this.weight,
17539 html: this.html || ''
17545 cfg.cls += ' alert-messages-fixed';
17559 onRender : function(ct, position)
17561 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17564 var cfg = Roo.apply({}, this.getAutoCreate());
17568 cfg.cls += ' ' + this.cls;
17571 cfg.style = this.style;
17573 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17575 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17578 this.el.select('>button.close').on('click', this.hide, this);
17584 if (!this.rendered) {
17590 this.fireEvent('show', this);
17596 if (!this.rendered) {
17602 this.fireEvent('hide', this);
17605 update : function()
17607 // var e = this.el.dom.firstChild;
17609 // if(this.closable){
17610 // e = e.nextSibling;
17613 // e.data = this.html || '';
17615 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';