4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
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%;",
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, size.height);
4241 this.maskEl.enableDisplayMode("block");
4243 this.store.on('load', this.onLoad, this);
4244 this.store.on('beforeload', this.onBeforeLoad, this);
4252 sort : function(e,el)
4254 var col = Roo.get(el)
4256 if(!col.hasClass('sortable')){
4260 var sort = col.attr('sort');
4263 if(col.hasClass('glyphicon-arrow-up')){
4267 this.store.sortInfo = {field : sort, direction : dir};
4272 renderHeader : function()
4281 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4283 var config = cm.config[i];
4287 html: cm.getColumnHeader(i)
4290 if(typeof(config.dataIndex) != 'undefined'){
4291 c.sort = config.dataIndex;
4294 if(typeof(config.sortable) != 'undefined' && config.sortable){
4298 if(typeof(config.width) != 'undefined'){
4299 c.style = 'width:' + config.width + 'px';
4308 renderBody : function()
4318 renderFooter : function()
4330 Roo.log('ds onload');
4335 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4336 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4338 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4339 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4342 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4343 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4347 var tbody = this.el.select('tbody', true).first();
4351 if(this.store.getCount() > 0){
4352 this.store.data.each(function(d){
4358 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4359 var renderer = cm.getRenderer(i);
4360 var config = cm.config[i];
4364 if(typeof(renderer) !== 'undefined'){
4365 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4368 if(typeof(value) === 'object'){
4378 html: (typeof(value) === 'object') ? '' : value
4381 if(typeof(config.width) != 'undefined'){
4382 td.style = 'width:' + config.width + 'px';
4389 tbody.createChild(row);
4397 Roo.each(renders, function(r){
4398 _this.renderColumn(r);
4402 // if(this.loadMask){
4403 // this.maskEl.hide();
4407 onBeforeLoad : function()
4409 Roo.log('ds onBeforeLoad');
4413 // if(this.loadMask){
4414 // this.maskEl.show();
4420 this.el.select('tbody', true).first().dom.innerHTML = '';
4423 getSelectionModel : function(){
4425 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4427 return this.selModel;
4430 renderColumn : function(r)
4433 r.cfg.render(Roo.get(r.id));
4436 Roo.each(r.cfg.cn, function(c){
4441 _this.renderColumn(child);
4458 * @class Roo.bootstrap.TableCell
4459 * @extends Roo.bootstrap.Component
4460 * Bootstrap TableCell class
4461 * @cfg {String} html cell contain text
4462 * @cfg {String} cls cell class
4463 * @cfg {String} tag cell tag (td|th) default td
4464 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4465 * @cfg {String} align Aligns the content in a cell
4466 * @cfg {String} axis Categorizes cells
4467 * @cfg {String} bgcolor Specifies the background color of a cell
4468 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4469 * @cfg {Number} colspan Specifies the number of columns a cell should span
4470 * @cfg {String} headers Specifies one or more header cells a cell is related to
4471 * @cfg {Number} height Sets the height of a cell
4472 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4473 * @cfg {Number} rowspan Sets the number of rows a cell should span
4474 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4475 * @cfg {String} valign Vertical aligns the content in a cell
4476 * @cfg {Number} width Specifies the width of a cell
4479 * Create a new TableCell
4480 * @param {Object} config The config object
4483 Roo.bootstrap.TableCell = function(config){
4484 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4487 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4507 getAutoCreate : function(){
4508 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4528 cfg.align=this.align
4534 cfg.bgcolor=this.bgcolor
4537 cfg.charoff=this.charoff
4540 cfg.colspan=this.colspan
4543 cfg.headers=this.headers
4546 cfg.height=this.height
4549 cfg.nowrap=this.nowrap
4552 cfg.rowspan=this.rowspan
4555 cfg.scope=this.scope
4558 cfg.valign=this.valign
4561 cfg.width=this.width
4580 * @class Roo.bootstrap.TableRow
4581 * @extends Roo.bootstrap.Component
4582 * Bootstrap TableRow class
4583 * @cfg {String} cls row class
4584 * @cfg {String} align Aligns the content in a table row
4585 * @cfg {String} bgcolor Specifies a background color for a table row
4586 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4587 * @cfg {String} valign Vertical aligns the content in a table row
4590 * Create a new TableRow
4591 * @param {Object} config The config object
4594 Roo.bootstrap.TableRow = function(config){
4595 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4598 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4606 getAutoCreate : function(){
4607 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4617 cfg.align = this.align;
4620 cfg.bgcolor = this.bgcolor;
4623 cfg.charoff = this.charoff;
4626 cfg.valign = this.valign;
4644 * @class Roo.bootstrap.TableBody
4645 * @extends Roo.bootstrap.Component
4646 * Bootstrap TableBody class
4647 * @cfg {String} cls element class
4648 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4649 * @cfg {String} align Aligns the content inside the element
4650 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4651 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4654 * Create a new TableBody
4655 * @param {Object} config The config object
4658 Roo.bootstrap.TableBody = function(config){
4659 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4662 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4670 getAutoCreate : function(){
4671 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4685 cfg.align = this.align;
4688 cfg.charoff = this.charoff;
4691 cfg.valign = this.valign;
4698 // initEvents : function()
4705 // this.store = Roo.factory(this.store, Roo.data);
4706 // this.store.on('load', this.onLoad, this);
4708 // this.store.load();
4712 // onLoad: function ()
4714 // this.fireEvent('load', this);
4724 * Ext JS Library 1.1.1
4725 * Copyright(c) 2006-2007, Ext JS, LLC.
4727 * Originally Released Under LGPL - original licence link has changed is not relivant.
4730 * <script type="text/javascript">
4733 // as we use this in bootstrap.
4734 Roo.namespace('Roo.form');
4736 * @class Roo.form.Action
4737 * Internal Class used to handle form actions
4739 * @param {Roo.form.BasicForm} el The form element or its id
4740 * @param {Object} config Configuration options
4745 // define the action interface
4746 Roo.form.Action = function(form, options){
4748 this.options = options || {};
4751 * Client Validation Failed
4754 Roo.form.Action.CLIENT_INVALID = 'client';
4756 * Server Validation Failed
4759 Roo.form.Action.SERVER_INVALID = 'server';
4761 * Connect to Server Failed
4764 Roo.form.Action.CONNECT_FAILURE = 'connect';
4766 * Reading Data from Server Failed
4769 Roo.form.Action.LOAD_FAILURE = 'load';
4771 Roo.form.Action.prototype = {
4773 failureType : undefined,
4774 response : undefined,
4778 run : function(options){
4783 success : function(response){
4788 handleResponse : function(response){
4792 // default connection failure
4793 failure : function(response){
4795 this.response = response;
4796 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4797 this.form.afterAction(this, false);
4800 processResponse : function(response){
4801 this.response = response;
4802 if(!response.responseText){
4805 this.result = this.handleResponse(response);
4809 // utility functions used internally
4810 getUrl : function(appendParams){
4811 var url = this.options.url || this.form.url || this.form.el.dom.action;
4813 var p = this.getParams();
4815 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4821 getMethod : function(){
4822 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4825 getParams : function(){
4826 var bp = this.form.baseParams;
4827 var p = this.options.params;
4829 if(typeof p == "object"){
4830 p = Roo.urlEncode(Roo.applyIf(p, bp));
4831 }else if(typeof p == 'string' && bp){
4832 p += '&' + Roo.urlEncode(bp);
4835 p = Roo.urlEncode(bp);
4840 createCallback : function(){
4842 success: this.success,
4843 failure: this.failure,
4845 timeout: (this.form.timeout*1000),
4846 upload: this.form.fileUpload ? this.success : undefined
4851 Roo.form.Action.Submit = function(form, options){
4852 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4855 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4858 haveProgress : false,
4859 uploadComplete : false,
4861 // uploadProgress indicator.
4862 uploadProgress : function()
4864 if (!this.form.progressUrl) {
4868 if (!this.haveProgress) {
4869 Roo.MessageBox.progress("Uploading", "Uploading");
4871 if (this.uploadComplete) {
4872 Roo.MessageBox.hide();
4876 this.haveProgress = true;
4878 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4880 var c = new Roo.data.Connection();
4882 url : this.form.progressUrl,
4887 success : function(req){
4888 //console.log(data);
4892 rdata = Roo.decode(req.responseText)
4894 Roo.log("Invalid data from server..");
4898 if (!rdata || !rdata.success) {
4900 Roo.MessageBox.alert(Roo.encode(rdata));
4903 var data = rdata.data;
4905 if (this.uploadComplete) {
4906 Roo.MessageBox.hide();
4911 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4912 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4915 this.uploadProgress.defer(2000,this);
4918 failure: function(data) {
4919 Roo.log('progress url failed ');
4930 // run get Values on the form, so it syncs any secondary forms.
4931 this.form.getValues();
4933 var o = this.options;
4934 var method = this.getMethod();
4935 var isPost = method == 'POST';
4936 if(o.clientValidation === false || this.form.isValid()){
4938 if (this.form.progressUrl) {
4939 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4940 (new Date() * 1) + '' + Math.random());
4945 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4946 form:this.form.el.dom,
4947 url:this.getUrl(!isPost),
4949 params:isPost ? this.getParams() : null,
4950 isUpload: this.form.fileUpload
4953 this.uploadProgress();
4955 }else if (o.clientValidation !== false){ // client validation failed
4956 this.failureType = Roo.form.Action.CLIENT_INVALID;
4957 this.form.afterAction(this, false);
4961 success : function(response)
4963 this.uploadComplete= true;
4964 if (this.haveProgress) {
4965 Roo.MessageBox.hide();
4969 var result = this.processResponse(response);
4970 if(result === true || result.success){
4971 this.form.afterAction(this, true);
4975 this.form.markInvalid(result.errors);
4976 this.failureType = Roo.form.Action.SERVER_INVALID;
4978 this.form.afterAction(this, false);
4980 failure : function(response)
4982 this.uploadComplete= true;
4983 if (this.haveProgress) {
4984 Roo.MessageBox.hide();
4987 this.response = response;
4988 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4989 this.form.afterAction(this, false);
4992 handleResponse : function(response){
4993 if(this.form.errorReader){
4994 var rs = this.form.errorReader.read(response);
4997 for(var i = 0, len = rs.records.length; i < len; i++) {
4998 var r = rs.records[i];
5002 if(errors.length < 1){
5006 success : rs.success,
5012 ret = Roo.decode(response.responseText);
5016 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5026 Roo.form.Action.Load = function(form, options){
5027 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5028 this.reader = this.form.reader;
5031 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5036 Roo.Ajax.request(Roo.apply(
5037 this.createCallback(), {
5038 method:this.getMethod(),
5039 url:this.getUrl(false),
5040 params:this.getParams()
5044 success : function(response){
5046 var result = this.processResponse(response);
5047 if(result === true || !result.success || !result.data){
5048 this.failureType = Roo.form.Action.LOAD_FAILURE;
5049 this.form.afterAction(this, false);
5052 this.form.clearInvalid();
5053 this.form.setValues(result.data);
5054 this.form.afterAction(this, true);
5057 handleResponse : function(response){
5058 if(this.form.reader){
5059 var rs = this.form.reader.read(response);
5060 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5062 success : rs.success,
5066 return Roo.decode(response.responseText);
5070 Roo.form.Action.ACTION_TYPES = {
5071 'load' : Roo.form.Action.Load,
5072 'submit' : Roo.form.Action.Submit
5081 * @class Roo.bootstrap.Form
5082 * @extends Roo.bootstrap.Component
5083 * Bootstrap Form class
5084 * @cfg {String} method GET | POST (default POST)
5085 * @cfg {String} labelAlign top | left (default top)
5086 * @cfg {String} align left | right - for navbars
5091 * @param {Object} config The config object
5095 Roo.bootstrap.Form = function(config){
5096 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5099 * @event clientvalidation
5100 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5101 * @param {Form} this
5102 * @param {Boolean} valid true if the form has passed client-side validation
5104 clientvalidation: true,
5106 * @event beforeaction
5107 * Fires before any action is performed. Return false to cancel the action.
5108 * @param {Form} this
5109 * @param {Action} action The action to be performed
5113 * @event actionfailed
5114 * Fires when an action fails.
5115 * @param {Form} this
5116 * @param {Action} action The action that failed
5118 actionfailed : true,
5120 * @event actioncomplete
5121 * Fires when an action is completed.
5122 * @param {Form} this
5123 * @param {Action} action The action that completed
5125 actioncomplete : true
5130 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5133 * @cfg {String} method
5134 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5139 * The URL to use for form actions if one isn't supplied in the action options.
5142 * @cfg {Boolean} fileUpload
5143 * Set to true if this form is a file upload.
5147 * @cfg {Object} baseParams
5148 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5152 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5156 * @cfg {Sting} align (left|right) for navbar forms
5161 activeAction : null,
5164 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5165 * element by passing it or its id or mask the form itself by passing in true.
5168 waitMsgTarget : false,
5173 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5174 * element by passing it or its id or mask the form itself by passing in true.
5178 getAutoCreate : function(){
5182 method : this.method || 'POST',
5183 id : this.id || Roo.id(),
5186 if (this.parent().xtype.match(/^Nav/)) {
5187 cfg.cls = 'navbar-form navbar-' + this.align;
5191 if (this.labelAlign == 'left' ) {
5192 cfg.cls += ' form-horizontal';
5198 initEvents : function()
5200 this.el.on('submit', this.onSubmit, this);
5205 onSubmit : function(e){
5210 * Returns true if client-side validation on the form is successful.
5213 isValid : function(){
5214 var items = this.getItems();
5216 items.each(function(f){
5225 * Returns true if any fields in this form have changed since their original load.
5228 isDirty : function(){
5230 var items = this.getItems();
5231 items.each(function(f){
5241 * Performs a predefined action (submit or load) or custom actions you define on this form.
5242 * @param {String} actionName The name of the action type
5243 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5244 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5245 * accept other config options):
5247 Property Type Description
5248 ---------------- --------------- ----------------------------------------------------------------------------------
5249 url String The url for the action (defaults to the form's url)
5250 method String The form method to use (defaults to the form's method, or POST if not defined)
5251 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5252 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5253 validate the form on the client (defaults to false)
5255 * @return {BasicForm} this
5257 doAction : function(action, options){
5258 if(typeof action == 'string'){
5259 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5261 if(this.fireEvent('beforeaction', this, action) !== false){
5262 this.beforeAction(action);
5263 action.run.defer(100, action);
5269 beforeAction : function(action){
5270 var o = action.options;
5272 // not really supported yet.. ??
5274 //if(this.waitMsgTarget === true){
5275 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5276 //}else if(this.waitMsgTarget){
5277 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5278 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5280 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5286 afterAction : function(action, success){
5287 this.activeAction = null;
5288 var o = action.options;
5290 //if(this.waitMsgTarget === true){
5292 //}else if(this.waitMsgTarget){
5293 // this.waitMsgTarget.unmask();
5295 // Roo.MessageBox.updateProgress(1);
5296 // Roo.MessageBox.hide();
5303 Roo.callback(o.success, o.scope, [this, action]);
5304 this.fireEvent('actioncomplete', this, action);
5308 // failure condition..
5309 // we have a scenario where updates need confirming.
5310 // eg. if a locking scenario exists..
5311 // we look for { errors : { needs_confirm : true }} in the response.
5313 (typeof(action.result) != 'undefined') &&
5314 (typeof(action.result.errors) != 'undefined') &&
5315 (typeof(action.result.errors.needs_confirm) != 'undefined')
5318 Roo.log("not supported yet");
5321 Roo.MessageBox.confirm(
5322 "Change requires confirmation",
5323 action.result.errorMsg,
5328 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5338 Roo.callback(o.failure, o.scope, [this, action]);
5339 // show an error message if no failed handler is set..
5340 if (!this.hasListener('actionfailed')) {
5341 Roo.log("need to add dialog support");
5343 Roo.MessageBox.alert("Error",
5344 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5345 action.result.errorMsg :
5346 "Saving Failed, please check your entries or try again"
5351 this.fireEvent('actionfailed', this, action);
5356 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5357 * @param {String} id The value to search for
5360 findField : function(id){
5361 var items = this.getItems();
5362 var field = items.get(id);
5364 items.each(function(f){
5365 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5372 return field || null;
5375 * Mark fields in this form invalid in bulk.
5376 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5377 * @return {BasicForm} this
5379 markInvalid : function(errors){
5380 if(errors instanceof Array){
5381 for(var i = 0, len = errors.length; i < len; i++){
5382 var fieldError = errors[i];
5383 var f = this.findField(fieldError.id);
5385 f.markInvalid(fieldError.msg);
5391 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5392 field.markInvalid(errors[id]);
5396 //Roo.each(this.childForms || [], function (f) {
5397 // f.markInvalid(errors);
5404 * Set values for fields in this form in bulk.
5405 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5406 * @return {BasicForm} this
5408 setValues : function(values){
5409 if(values instanceof Array){ // array of objects
5410 for(var i = 0, len = values.length; i < len; i++){
5412 var f = this.findField(v.id);
5414 f.setValue(v.value);
5415 if(this.trackResetOnLoad){
5416 f.originalValue = f.getValue();
5420 }else{ // object hash
5423 if(typeof values[id] != 'function' && (field = this.findField(id))){
5425 if (field.setFromData &&
5427 field.displayField &&
5428 // combos' with local stores can
5429 // be queried via setValue()
5430 // to set their value..
5431 (field.store && !field.store.isLocal)
5435 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5436 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5437 field.setFromData(sd);
5440 field.setValue(values[id]);
5444 if(this.trackResetOnLoad){
5445 field.originalValue = field.getValue();
5451 //Roo.each(this.childForms || [], function (f) {
5452 // f.setValues(values);
5459 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5460 * they are returned as an array.
5461 * @param {Boolean} asString
5464 getValues : function(asString){
5465 //if (this.childForms) {
5466 // copy values from the child forms
5467 // Roo.each(this.childForms, function (f) {
5468 // this.setValues(f.getValues());
5474 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5475 if(asString === true){
5478 return Roo.urlDecode(fs);
5482 * Returns the fields in this form as an object with key/value pairs.
5483 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5486 getFieldValues : function(with_hidden)
5488 var items = this.getItems();
5490 items.each(function(f){
5494 var v = f.getValue();
5495 if (f.inputType =='radio') {
5496 if (typeof(ret[f.getName()]) == 'undefined') {
5497 ret[f.getName()] = ''; // empty..
5500 if (!f.el.dom.checked) {
5508 // not sure if this supported any more..
5509 if ((typeof(v) == 'object') && f.getRawValue) {
5510 v = f.getRawValue() ; // dates..
5512 // combo boxes where name != hiddenName...
5513 if (f.name != f.getName()) {
5514 ret[f.name] = f.getRawValue();
5516 ret[f.getName()] = v;
5523 * Clears all invalid messages in this form.
5524 * @return {BasicForm} this
5526 clearInvalid : function(){
5527 var items = this.getItems();
5529 items.each(function(f){
5540 * @return {BasicForm} this
5543 var items = this.getItems();
5544 items.each(function(f){
5548 Roo.each(this.childForms || [], function (f) {
5555 getItems : function()
5557 var r=new Roo.util.MixedCollection(false, function(o){
5558 return o.id || (o.id = Roo.id());
5560 var iter = function(el) {
5567 Roo.each(el.items,function(e) {
5586 * Ext JS Library 1.1.1
5587 * Copyright(c) 2006-2007, Ext JS, LLC.
5589 * Originally Released Under LGPL - original licence link has changed is not relivant.
5592 * <script type="text/javascript">
5595 * @class Roo.form.VTypes
5596 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5599 Roo.form.VTypes = function(){
5600 // closure these in so they are only created once.
5601 var alpha = /^[a-zA-Z_]+$/;
5602 var alphanum = /^[a-zA-Z0-9_]+$/;
5603 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5604 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5606 // All these messages and functions are configurable
5609 * The function used to validate email addresses
5610 * @param {String} value The email address
5612 'email' : function(v){
5613 return email.test(v);
5616 * The error text to display when the email validation function returns false
5619 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5621 * The keystroke filter mask to be applied on email input
5624 'emailMask' : /[a-z0-9_\.\-@]/i,
5627 * The function used to validate URLs
5628 * @param {String} value The URL
5630 'url' : function(v){
5634 * The error text to display when the url validation function returns false
5637 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5640 * The function used to validate alpha values
5641 * @param {String} value The value
5643 'alpha' : function(v){
5644 return alpha.test(v);
5647 * The error text to display when the alpha validation function returns false
5650 'alphaText' : 'This field should only contain letters and _',
5652 * The keystroke filter mask to be applied on alpha input
5655 'alphaMask' : /[a-z_]/i,
5658 * The function used to validate alphanumeric values
5659 * @param {String} value The value
5661 'alphanum' : function(v){
5662 return alphanum.test(v);
5665 * The error text to display when the alphanumeric validation function returns false
5668 'alphanumText' : 'This field should only contain letters, numbers and _',
5670 * The keystroke filter mask to be applied on alphanumeric input
5673 'alphanumMask' : /[a-z0-9_]/i
5683 * @class Roo.bootstrap.Input
5684 * @extends Roo.bootstrap.Component
5685 * Bootstrap Input class
5686 * @cfg {Boolean} disabled is it disabled
5687 * @cfg {String} fieldLabel - the label associated
5688 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5689 * @cfg {String} name name of the input
5690 * @cfg {string} fieldLabel - the label associated
5691 * @cfg {string} inputType - input / file submit ...
5692 * @cfg {string} placeholder - placeholder to put in text.
5693 * @cfg {string} before - input group add on before
5694 * @cfg {string} after - input group add on after
5695 * @cfg {string} size - (lg|sm) or leave empty..
5696 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5697 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5698 * @cfg {Number} md colspan out of 12 for computer-sized screens
5699 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5700 * @cfg {string} value default value of the input
5701 * @cfg {Number} labelWidth set the width of label (0-12)
5702 * @cfg {String} labelAlign (top|left)
5703 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5707 * Create a new Input
5708 * @param {Object} config The config object
5711 Roo.bootstrap.Input = function(config){
5712 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5717 * Fires when this field receives input focus.
5718 * @param {Roo.form.Field} this
5723 * Fires when this field loses input focus.
5724 * @param {Roo.form.Field} this
5729 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5730 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5731 * @param {Roo.form.Field} this
5732 * @param {Roo.EventObject} e The event object
5737 * Fires just before the field blurs if the field value has changed.
5738 * @param {Roo.form.Field} this
5739 * @param {Mixed} newValue The new value
5740 * @param {Mixed} oldValue The original value
5745 * Fires after the field has been marked as invalid.
5746 * @param {Roo.form.Field} this
5747 * @param {String} msg The validation message
5752 * Fires after the field has been validated with no errors.
5753 * @param {Roo.form.Field} this
5758 * Fires after the key up
5759 * @param {Roo.form.Field} this
5760 * @param {Roo.EventObject} e The event Object
5766 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5768 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5769 automatic validation (defaults to "keyup").
5771 validationEvent : "keyup",
5773 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5775 validateOnBlur : true,
5777 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5779 validationDelay : 250,
5781 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5783 focusClass : "x-form-focus", // not needed???
5787 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5789 invalidClass : "has-error",
5792 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5794 selectOnFocus : false,
5797 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5801 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5806 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5808 disableKeyFilter : false,
5811 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5815 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5819 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5821 blankText : "This field is required",
5824 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5828 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5830 maxLength : Number.MAX_VALUE,
5832 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5834 minLengthText : "The minimum length for this field is {0}",
5836 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5838 maxLengthText : "The maximum length for this field is {0}",
5842 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5843 * If available, this function will be called only after the basic validators all return true, and will be passed the
5844 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5848 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5849 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5850 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5854 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5877 parentLabelAlign : function()
5880 while (parent.parent()) {
5881 parent = parent.parent();
5882 if (typeof(parent.labelAlign) !='undefined') {
5883 return parent.labelAlign;
5890 getAutoCreate : function(){
5892 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5898 if(this.inputType != 'hidden'){
5899 cfg.cls = 'form-group' //input-group
5905 type : this.inputType,
5907 cls : 'form-control',
5908 placeholder : this.placeholder || ''
5912 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5913 input.maxLength = this.maxLength;
5916 if (this.disabled) {
5917 input.disabled=true;
5920 if (this.readOnly) {
5921 input.readonly=true;
5925 input.name = this.name;
5928 input.cls += ' input-' + this.size;
5931 ['xs','sm','md','lg'].map(function(size){
5932 if (settings[size]) {
5933 cfg.cls += ' col-' + size + '-' + settings[size];
5937 var inputblock = input;
5939 if (this.before || this.after) {
5942 cls : 'input-group',
5945 if (this.before && typeof(this.before) == 'string') {
5947 inputblock.cn.push({
5949 cls : 'roo-input-before input-group-addon',
5953 if (this.before && typeof(this.before) == 'object') {
5954 this.before = Roo.factory(this.before);
5955 Roo.log(this.before);
5956 inputblock.cn.push({
5958 cls : 'roo-input-before input-group-' +
5959 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5963 inputblock.cn.push(input);
5965 if (this.after && typeof(this.after) == 'string') {
5966 inputblock.cn.push({
5968 cls : 'roo-input-after input-group-addon',
5972 if (this.after && typeof(this.after) == 'object') {
5973 this.after = Roo.factory(this.after);
5974 Roo.log(this.after);
5975 inputblock.cn.push({
5977 cls : 'roo-input-after input-group-' +
5978 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5983 if (align ==='left' && this.fieldLabel.length) {
5984 Roo.log("left and has label");
5990 cls : 'control-label col-sm-' + this.labelWidth,
5991 html : this.fieldLabel
5995 cls : "col-sm-" + (12 - this.labelWidth),
6002 } else if ( this.fieldLabel.length) {
6008 //cls : 'input-group-addon',
6009 html : this.fieldLabel
6019 Roo.log(" no label && no align");
6028 Roo.log('input-parentType: ' + this.parentType);
6030 if (this.parentType === 'Navbar' && this.parent().bar) {
6031 cfg.cls += ' navbar-form';
6039 * return the real input element.
6041 inputEl: function ()
6043 return this.el.select('input.form-control',true).first();
6045 setDisabled : function(v)
6047 var i = this.inputEl().dom;
6049 i.removeAttribute('disabled');
6053 i.setAttribute('disabled','true');
6055 initEvents : function()
6058 this.inputEl().on("keydown" , this.fireKey, this);
6059 this.inputEl().on("focus", this.onFocus, this);
6060 this.inputEl().on("blur", this.onBlur, this);
6062 this.inputEl().relayEvent('keyup', this);
6064 // reference to original value for reset
6065 this.originalValue = this.getValue();
6066 //Roo.form.TextField.superclass.initEvents.call(this);
6067 if(this.validationEvent == 'keyup'){
6068 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6069 this.inputEl().on('keyup', this.filterValidation, this);
6071 else if(this.validationEvent !== false){
6072 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6075 if(this.selectOnFocus){
6076 this.on("focus", this.preFocus, this);
6079 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6080 this.inputEl().on("keypress", this.filterKeys, this);
6083 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6084 this.el.on("click", this.autoSize, this);
6087 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6088 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6091 if (typeof(this.before) == 'object') {
6092 this.before.render(this.el.select('.roo-input-before',true).first());
6094 if (typeof(this.after) == 'object') {
6095 this.after.render(this.el.select('.roo-input-after',true).first());
6100 filterValidation : function(e){
6101 if(!e.isNavKeyPress()){
6102 this.validationTask.delay(this.validationDelay);
6106 * Validates the field value
6107 * @return {Boolean} True if the value is valid, else false
6109 validate : function(){
6110 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6111 if(this.disabled || this.validateValue(this.getRawValue())){
6112 this.clearInvalid();
6120 * Validates a value according to the field's validation rules and marks the field as invalid
6121 * if the validation fails
6122 * @param {Mixed} value The value to validate
6123 * @return {Boolean} True if the value is valid, else false
6125 validateValue : function(value){
6126 if(value.length < 1) { // if it's blank
6127 if(this.allowBlank){
6128 this.clearInvalid();
6131 this.markInvalid(this.blankText);
6135 if(value.length < this.minLength){
6136 this.markInvalid(String.format(this.minLengthText, this.minLength));
6139 if(value.length > this.maxLength){
6140 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6144 var vt = Roo.form.VTypes;
6145 if(!vt[this.vtype](value, this)){
6146 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6150 if(typeof this.validator == "function"){
6151 var msg = this.validator(value);
6153 this.markInvalid(msg);
6157 if(this.regex && !this.regex.test(value)){
6158 this.markInvalid(this.regexText);
6167 fireKey : function(e){
6168 //Roo.log('field ' + e.getKey());
6169 if(e.isNavKeyPress()){
6170 this.fireEvent("specialkey", this, e);
6173 focus : function (selectText){
6175 this.inputEl().focus();
6176 if(selectText === true){
6177 this.inputEl().dom.select();
6183 onFocus : function(){
6184 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6185 // this.el.addClass(this.focusClass);
6188 this.hasFocus = true;
6189 this.startValue = this.getValue();
6190 this.fireEvent("focus", this);
6194 beforeBlur : Roo.emptyFn,
6198 onBlur : function(){
6200 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6201 //this.el.removeClass(this.focusClass);
6203 this.hasFocus = false;
6204 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6207 var v = this.getValue();
6208 if(String(v) !== String(this.startValue)){
6209 this.fireEvent('change', this, v, this.startValue);
6211 this.fireEvent("blur", this);
6215 * Resets the current field value to the originally loaded value and clears any validation messages
6218 this.setValue(this.originalValue);
6219 this.clearInvalid();
6222 * Returns the name of the field
6223 * @return {Mixed} name The name field
6225 getName: function(){
6229 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6230 * @return {Mixed} value The field value
6232 getValue : function(){
6233 return this.inputEl().getValue();
6236 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6237 * @return {Mixed} value The field value
6239 getRawValue : function(){
6240 var v = this.inputEl().getValue();
6246 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6247 * @param {Mixed} value The value to set
6249 setRawValue : function(v){
6250 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6253 selectText : function(start, end){
6254 var v = this.getRawValue();
6256 start = start === undefined ? 0 : start;
6257 end = end === undefined ? v.length : end;
6258 var d = this.inputEl().dom;
6259 if(d.setSelectionRange){
6260 d.setSelectionRange(start, end);
6261 }else if(d.createTextRange){
6262 var range = d.createTextRange();
6263 range.moveStart("character", start);
6264 range.moveEnd("character", v.length-end);
6271 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6272 * @param {Mixed} value The value to set
6274 setValue : function(v){
6277 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6283 processValue : function(value){
6284 if(this.stripCharsRe){
6285 var newValue = value.replace(this.stripCharsRe, '');
6286 if(newValue !== value){
6287 this.setRawValue(newValue);
6294 preFocus : function(){
6296 if(this.selectOnFocus){
6297 this.inputEl().dom.select();
6300 filterKeys : function(e){
6302 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6305 var c = e.getCharCode(), cc = String.fromCharCode(c);
6306 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6309 if(!this.maskRe.test(cc)){
6314 * Clear any invalid styles/messages for this field
6316 clearInvalid : function(){
6318 if(!this.el || this.preventMark){ // not rendered
6321 this.el.removeClass(this.invalidClass);
6323 switch(this.msgTarget){
6325 this.el.dom.qtip = '';
6328 this.el.dom.title = '';
6332 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6337 this.errorIcon.dom.qtip = '';
6338 this.errorIcon.hide();
6339 this.un('resize', this.alignErrorIcon, this);
6343 var t = Roo.getDom(this.msgTarget);
6345 t.style.display = 'none';
6349 this.fireEvent('valid', this);
6352 * Mark this field as invalid
6353 * @param {String} msg The validation message
6355 markInvalid : function(msg){
6356 if(!this.el || this.preventMark){ // not rendered
6359 this.el.addClass(this.invalidClass);
6361 msg = msg || this.invalidText;
6362 switch(this.msgTarget){
6364 this.el.dom.qtip = msg;
6365 this.el.dom.qclass = 'x-form-invalid-tip';
6366 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6367 Roo.QuickTips.enable();
6371 this.el.dom.title = msg;
6375 var elp = this.el.findParent('.x-form-element', 5, true);
6376 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6377 this.errorEl.setWidth(elp.getWidth(true)-20);
6379 this.errorEl.update(msg);
6380 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6383 if(!this.errorIcon){
6384 var elp = this.el.findParent('.x-form-element', 5, true);
6385 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6387 this.alignErrorIcon();
6388 this.errorIcon.dom.qtip = msg;
6389 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6390 this.errorIcon.show();
6391 this.on('resize', this.alignErrorIcon, this);
6394 var t = Roo.getDom(this.msgTarget);
6396 t.style.display = this.msgDisplay;
6400 this.fireEvent('invalid', this, msg);
6403 SafariOnKeyDown : function(event)
6405 // this is a workaround for a password hang bug on chrome/ webkit.
6407 var isSelectAll = false;
6409 if(this.inputEl().dom.selectionEnd > 0){
6410 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6412 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6413 event.preventDefault();
6418 if(isSelectAll){ // backspace and delete key
6420 event.preventDefault();
6421 // this is very hacky as keydown always get's upper case.
6423 var cc = String.fromCharCode(event.getCharCode());
6424 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6428 adjustWidth : function(tag, w){
6429 tag = tag.toLowerCase();
6430 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6431 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6435 if(tag == 'textarea'){
6438 }else if(Roo.isOpera){
6442 if(tag == 'textarea'){
6461 * @class Roo.bootstrap.TextArea
6462 * @extends Roo.bootstrap.Input
6463 * Bootstrap TextArea class
6464 * @cfg {Number} cols Specifies the visible width of a text area
6465 * @cfg {Number} rows Specifies the visible number of lines in a text area
6466 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6467 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6468 * @cfg {string} html text
6471 * Create a new TextArea
6472 * @param {Object} config The config object
6475 Roo.bootstrap.TextArea = function(config){
6476 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6480 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6490 getAutoCreate : function(){
6492 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6503 value : this.value || '',
6504 html: this.html || '',
6505 cls : 'form-control',
6506 placeholder : this.placeholder || ''
6510 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6511 input.maxLength = this.maxLength;
6515 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6519 input.cols = this.cols;
6522 if (this.readOnly) {
6523 input.readonly = true;
6527 input.name = this.name;
6531 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6535 ['xs','sm','md','lg'].map(function(size){
6536 if (settings[size]) {
6537 cfg.cls += ' col-' + size + '-' + settings[size];
6541 var inputblock = input;
6543 if (this.before || this.after) {
6546 cls : 'input-group',
6550 inputblock.cn.push({
6552 cls : 'input-group-addon',
6556 inputblock.cn.push(input);
6558 inputblock.cn.push({
6560 cls : 'input-group-addon',
6567 if (align ==='left' && this.fieldLabel.length) {
6568 Roo.log("left and has label");
6574 cls : 'control-label col-sm-' + this.labelWidth,
6575 html : this.fieldLabel
6579 cls : "col-sm-" + (12 - this.labelWidth),
6586 } else if ( this.fieldLabel.length) {
6592 //cls : 'input-group-addon',
6593 html : this.fieldLabel
6603 Roo.log(" no label && no align");
6613 if (this.disabled) {
6614 input.disabled=true;
6621 * return the real textarea element.
6623 inputEl: function ()
6625 return this.el.select('textarea.form-control',true).first();
6633 * trigger field - base class for combo..
6638 * @class Roo.bootstrap.TriggerField
6639 * @extends Roo.bootstrap.Input
6640 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6641 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6642 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6643 * for which you can provide a custom implementation. For example:
6645 var trigger = new Roo.bootstrap.TriggerField();
6646 trigger.onTriggerClick = myTriggerFn;
6647 trigger.applyTo('my-field');
6650 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6651 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6652 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6653 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6655 * Create a new TriggerField.
6656 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6657 * to the base TextField)
6659 Roo.bootstrap.TriggerField = function(config){
6660 this.mimicing = false;
6661 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6664 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6666 * @cfg {String} triggerClass A CSS class to apply to the trigger
6669 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6673 /** @cfg {Boolean} grow @hide */
6674 /** @cfg {Number} growMin @hide */
6675 /** @cfg {Number} growMax @hide */
6681 autoSize: Roo.emptyFn,
6688 actionMode : 'wrap',
6692 getAutoCreate : function(){
6694 var parent = this.parent();
6696 var align = this.labelAlign || this.parentLabelAlign();
6701 cls: 'form-group' //input-group
6708 type : this.inputType,
6709 cls : 'form-control',
6710 autocomplete: 'off',
6711 placeholder : this.placeholder || ''
6715 input.name = this.name;
6718 input.cls += ' input-' + this.size;
6721 if (this.disabled) {
6722 input.disabled=true;
6725 var inputblock = input;
6727 if (this.before || this.after) {
6730 cls : 'input-group',
6734 inputblock.cn.push({
6736 cls : 'input-group-addon',
6740 inputblock.cn.push(input);
6742 inputblock.cn.push({
6744 cls : 'input-group-addon',
6757 cls: 'form-hidden-field'
6765 Roo.log('multiple');
6773 cls: 'form-hidden-field'
6777 cls: 'select2-choices',
6781 cls: 'select2-search-field',
6794 cls: 'select2-container input-group',
6799 cls: 'typeahead typeahead-long dropdown-menu',
6800 style: 'display:none'
6808 cls : 'input-group-addon btn dropdown-toggle',
6816 cls: 'combobox-clear',
6830 combobox.cls += ' select2-container-multi';
6833 if (align ==='left' && this.fieldLabel.length) {
6835 Roo.log("left and has label");
6841 cls : 'control-label col-sm-' + this.labelWidth,
6842 html : this.fieldLabel
6846 cls : "col-sm-" + (12 - this.labelWidth),
6853 } else if ( this.fieldLabel.length) {
6859 //cls : 'input-group-addon',
6860 html : this.fieldLabel
6870 Roo.log(" no label && no align");
6877 ['xs','sm','md','lg'].map(function(size){
6878 if (settings[size]) {
6879 cfg.cls += ' col-' + size + '-' + settings[size];
6890 onResize : function(w, h){
6891 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6892 // if(typeof w == 'number'){
6893 // var x = w - this.trigger.getWidth();
6894 // this.inputEl().setWidth(this.adjustWidth('input', x));
6895 // this.trigger.setStyle('left', x+'px');
6900 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6903 getResizeEl : function(){
6904 return this.inputEl();
6908 getPositionEl : function(){
6909 return this.inputEl();
6913 alignErrorIcon : function(){
6914 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6918 initEvents : function(){
6920 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6921 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6923 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6924 if(this.hideTrigger){
6925 this.trigger.setDisplayed(false);
6927 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6931 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6934 //this.trigger.addClassOnOver('x-form-trigger-over');
6935 //this.trigger.addClassOnClick('x-form-trigger-click');
6938 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6943 initTrigger : function(){
6948 onDestroy : function(){
6950 this.trigger.removeAllListeners();
6951 // this.trigger.remove();
6954 // this.wrap.remove();
6956 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6960 onFocus : function(){
6961 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6964 this.wrap.addClass('x-trigger-wrap-focus');
6965 this.mimicing = true;
6966 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6967 if(this.monitorTab){
6968 this.el.on("keydown", this.checkTab, this);
6975 checkTab : function(e){
6976 if(e.getKey() == e.TAB){
6982 onBlur : function(){
6987 mimicBlur : function(e, t){
6989 if(!this.wrap.contains(t) && this.validateBlur()){
6996 triggerBlur : function(){
6997 this.mimicing = false;
6998 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6999 if(this.monitorTab){
7000 this.el.un("keydown", this.checkTab, this);
7002 //this.wrap.removeClass('x-trigger-wrap-focus');
7003 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7007 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7008 validateBlur : function(e, t){
7013 onDisable : function(){
7014 this.inputEl().dom.disabled = true;
7015 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7017 // this.wrap.addClass('x-item-disabled');
7022 onEnable : function(){
7023 this.inputEl().dom.disabled = false;
7024 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7026 // this.el.removeClass('x-item-disabled');
7031 onShow : function(){
7032 var ae = this.getActionEl();
7035 ae.dom.style.display = '';
7036 ae.dom.style.visibility = 'visible';
7042 onHide : function(){
7043 var ae = this.getActionEl();
7044 ae.dom.style.display = 'none';
7048 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7049 * by an implementing function.
7051 * @param {EventObject} e
7053 onTriggerClick : Roo.emptyFn
7057 * Ext JS Library 1.1.1
7058 * Copyright(c) 2006-2007, Ext JS, LLC.
7060 * Originally Released Under LGPL - original licence link has changed is not relivant.
7063 * <script type="text/javascript">
7068 * @class Roo.data.SortTypes
7070 * Defines the default sorting (casting?) comparison functions used when sorting data.
7072 Roo.data.SortTypes = {
7074 * Default sort that does nothing
7075 * @param {Mixed} s The value being converted
7076 * @return {Mixed} The comparison value
7083 * The regular expression used to strip tags
7087 stripTagsRE : /<\/?[^>]+>/gi,
7090 * Strips all HTML tags to sort on text only
7091 * @param {Mixed} s The value being converted
7092 * @return {String} The comparison value
7094 asText : function(s){
7095 return String(s).replace(this.stripTagsRE, "");
7099 * Strips all HTML tags to sort on text only - Case insensitive
7100 * @param {Mixed} s The value being converted
7101 * @return {String} The comparison value
7103 asUCText : function(s){
7104 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7108 * Case insensitive string
7109 * @param {Mixed} s The value being converted
7110 * @return {String} The comparison value
7112 asUCString : function(s) {
7113 return String(s).toUpperCase();
7118 * @param {Mixed} s The value being converted
7119 * @return {Number} The comparison value
7121 asDate : function(s) {
7125 if(s instanceof Date){
7128 return Date.parse(String(s));
7133 * @param {Mixed} s The value being converted
7134 * @return {Float} The comparison value
7136 asFloat : function(s) {
7137 var val = parseFloat(String(s).replace(/,/g, ""));
7138 if(isNaN(val)) val = 0;
7144 * @param {Mixed} s The value being converted
7145 * @return {Number} The comparison value
7147 asInt : function(s) {
7148 var val = parseInt(String(s).replace(/,/g, ""));
7149 if(isNaN(val)) val = 0;
7154 * Ext JS Library 1.1.1
7155 * Copyright(c) 2006-2007, Ext JS, LLC.
7157 * Originally Released Under LGPL - original licence link has changed is not relivant.
7160 * <script type="text/javascript">
7164 * @class Roo.data.Record
7165 * Instances of this class encapsulate both record <em>definition</em> information, and record
7166 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7167 * to access Records cached in an {@link Roo.data.Store} object.<br>
7169 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7170 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7173 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7175 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7176 * {@link #create}. The parameters are the same.
7177 * @param {Array} data An associative Array of data values keyed by the field name.
7178 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7179 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7180 * not specified an integer id is generated.
7182 Roo.data.Record = function(data, id){
7183 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7188 * Generate a constructor for a specific record layout.
7189 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7190 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7191 * Each field definition object may contain the following properties: <ul>
7192 * <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,
7193 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7194 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7195 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7196 * is being used, then this is a string containing the javascript expression to reference the data relative to
7197 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7198 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7199 * this may be omitted.</p></li>
7200 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7201 * <ul><li>auto (Default, implies no conversion)</li>
7206 * <li>date</li></ul></p></li>
7207 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7208 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7209 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7210 * by the Reader into an object that will be stored in the Record. It is passed the
7211 * following parameters:<ul>
7212 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7214 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7216 * <br>usage:<br><pre><code>
7217 var TopicRecord = Roo.data.Record.create(
7218 {name: 'title', mapping: 'topic_title'},
7219 {name: 'author', mapping: 'username'},
7220 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7221 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7222 {name: 'lastPoster', mapping: 'user2'},
7223 {name: 'excerpt', mapping: 'post_text'}
7226 var myNewRecord = new TopicRecord({
7227 title: 'Do my job please',
7230 lastPost: new Date(),
7231 lastPoster: 'Animal',
7232 excerpt: 'No way dude!'
7234 myStore.add(myNewRecord);
7239 Roo.data.Record.create = function(o){
7241 f.superclass.constructor.apply(this, arguments);
7243 Roo.extend(f, Roo.data.Record);
7244 var p = f.prototype;
7245 p.fields = new Roo.util.MixedCollection(false, function(field){
7248 for(var i = 0, len = o.length; i < len; i++){
7249 p.fields.add(new Roo.data.Field(o[i]));
7251 f.getField = function(name){
7252 return p.fields.get(name);
7257 Roo.data.Record.AUTO_ID = 1000;
7258 Roo.data.Record.EDIT = 'edit';
7259 Roo.data.Record.REJECT = 'reject';
7260 Roo.data.Record.COMMIT = 'commit';
7262 Roo.data.Record.prototype = {
7264 * Readonly flag - true if this record has been modified.
7273 join : function(store){
7278 * Set the named field to the specified value.
7279 * @param {String} name The name of the field to set.
7280 * @param {Object} value The value to set the field to.
7282 set : function(name, value){
7283 if(this.data[name] == value){
7290 if(typeof this.modified[name] == 'undefined'){
7291 this.modified[name] = this.data[name];
7293 this.data[name] = value;
7294 if(!this.editing && this.store){
7295 this.store.afterEdit(this);
7300 * Get the value of the named field.
7301 * @param {String} name The name of the field to get the value of.
7302 * @return {Object} The value of the field.
7304 get : function(name){
7305 return this.data[name];
7309 beginEdit : function(){
7310 this.editing = true;
7315 cancelEdit : function(){
7316 this.editing = false;
7317 delete this.modified;
7321 endEdit : function(){
7322 this.editing = false;
7323 if(this.dirty && this.store){
7324 this.store.afterEdit(this);
7329 * Usually called by the {@link Roo.data.Store} which owns the Record.
7330 * Rejects all changes made to the Record since either creation, or the last commit operation.
7331 * Modified fields are reverted to their original values.
7333 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7334 * of reject operations.
7336 reject : function(){
7337 var m = this.modified;
7339 if(typeof m[n] != "function"){
7340 this.data[n] = m[n];
7344 delete this.modified;
7345 this.editing = false;
7347 this.store.afterReject(this);
7352 * Usually called by the {@link Roo.data.Store} which owns the Record.
7353 * Commits all changes made to the Record since either creation, or the last commit operation.
7355 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7356 * of commit operations.
7358 commit : function(){
7360 delete this.modified;
7361 this.editing = false;
7363 this.store.afterCommit(this);
7368 hasError : function(){
7369 return this.error != null;
7373 clearError : function(){
7378 * Creates a copy of this record.
7379 * @param {String} id (optional) A new record id if you don't want to use this record's id
7382 copy : function(newId) {
7383 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7387 * Ext JS Library 1.1.1
7388 * Copyright(c) 2006-2007, Ext JS, LLC.
7390 * Originally Released Under LGPL - original licence link has changed is not relivant.
7393 * <script type="text/javascript">
7399 * @class Roo.data.Store
7400 * @extends Roo.util.Observable
7401 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7402 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7404 * 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
7405 * has no knowledge of the format of the data returned by the Proxy.<br>
7407 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7408 * instances from the data object. These records are cached and made available through accessor functions.
7410 * Creates a new Store.
7411 * @param {Object} config A config object containing the objects needed for the Store to access data,
7412 * and read the data into Records.
7414 Roo.data.Store = function(config){
7415 this.data = new Roo.util.MixedCollection(false);
7416 this.data.getKey = function(o){
7419 this.baseParams = {};
7426 "multisort" : "_multisort"
7429 if(config && config.data){
7430 this.inlineData = config.data;
7434 Roo.apply(this, config);
7436 if(this.reader){ // reader passed
7437 this.reader = Roo.factory(this.reader, Roo.data);
7438 this.reader.xmodule = this.xmodule || false;
7439 if(!this.recordType){
7440 this.recordType = this.reader.recordType;
7442 if(this.reader.onMetaChange){
7443 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7447 if(this.recordType){
7448 this.fields = this.recordType.prototype.fields;
7454 * @event datachanged
7455 * Fires when the data cache has changed, and a widget which is using this Store
7456 * as a Record cache should refresh its view.
7457 * @param {Store} this
7462 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7463 * @param {Store} this
7464 * @param {Object} meta The JSON metadata
7469 * Fires when Records have been added to the Store
7470 * @param {Store} this
7471 * @param {Roo.data.Record[]} records The array of Records added
7472 * @param {Number} index The index at which the record(s) were added
7477 * Fires when a Record has been removed from the Store
7478 * @param {Store} this
7479 * @param {Roo.data.Record} record The Record that was removed
7480 * @param {Number} index The index at which the record was removed
7485 * Fires when a Record has been updated
7486 * @param {Store} this
7487 * @param {Roo.data.Record} record The Record that was updated
7488 * @param {String} operation The update operation being performed. Value may be one of:
7490 Roo.data.Record.EDIT
7491 Roo.data.Record.REJECT
7492 Roo.data.Record.COMMIT
7498 * Fires when the data cache has been cleared.
7499 * @param {Store} this
7504 * Fires before a request is made for a new data object. If the beforeload handler returns false
7505 * the load action will be canceled.
7506 * @param {Store} this
7507 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7511 * @event beforeloadadd
7512 * Fires after a new set of Records has been loaded.
7513 * @param {Store} this
7514 * @param {Roo.data.Record[]} records The Records that were loaded
7515 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7517 beforeloadadd : true,
7520 * Fires after a new set of Records has been loaded, before they are added to the store.
7521 * @param {Store} this
7522 * @param {Roo.data.Record[]} records The Records that were loaded
7523 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7524 * @params {Object} return from reader
7528 * @event loadexception
7529 * Fires if an exception occurs in the Proxy during loading.
7530 * Called with the signature of the Proxy's "loadexception" event.
7531 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7534 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7535 * @param {Object} load options
7536 * @param {Object} jsonData from your request (normally this contains the Exception)
7538 loadexception : true
7542 this.proxy = Roo.factory(this.proxy, Roo.data);
7543 this.proxy.xmodule = this.xmodule || false;
7544 this.relayEvents(this.proxy, ["loadexception"]);
7546 this.sortToggle = {};
7547 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7549 Roo.data.Store.superclass.constructor.call(this);
7551 if(this.inlineData){
7552 this.loadData(this.inlineData);
7553 delete this.inlineData;
7557 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7559 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7560 * without a remote query - used by combo/forms at present.
7564 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7567 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7570 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7571 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7574 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7575 * on any HTTP request
7578 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7581 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7585 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7586 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7591 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7592 * loaded or when a record is removed. (defaults to false).
7594 pruneModifiedRecords : false,
7600 * Add Records to the Store and fires the add event.
7601 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7603 add : function(records){
7604 records = [].concat(records);
7605 for(var i = 0, len = records.length; i < len; i++){
7606 records[i].join(this);
7608 var index = this.data.length;
7609 this.data.addAll(records);
7610 this.fireEvent("add", this, records, index);
7614 * Remove a Record from the Store and fires the remove event.
7615 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7617 remove : function(record){
7618 var index = this.data.indexOf(record);
7619 this.data.removeAt(index);
7620 if(this.pruneModifiedRecords){
7621 this.modified.remove(record);
7623 this.fireEvent("remove", this, record, index);
7627 * Remove all Records from the Store and fires the clear event.
7629 removeAll : function(){
7631 if(this.pruneModifiedRecords){
7634 this.fireEvent("clear", this);
7638 * Inserts Records to the Store at the given index and fires the add event.
7639 * @param {Number} index The start index at which to insert the passed Records.
7640 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7642 insert : function(index, records){
7643 records = [].concat(records);
7644 for(var i = 0, len = records.length; i < len; i++){
7645 this.data.insert(index, records[i]);
7646 records[i].join(this);
7648 this.fireEvent("add", this, records, index);
7652 * Get the index within the cache of the passed Record.
7653 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7654 * @return {Number} The index of the passed Record. Returns -1 if not found.
7656 indexOf : function(record){
7657 return this.data.indexOf(record);
7661 * Get the index within the cache of the Record with the passed id.
7662 * @param {String} id The id of the Record to find.
7663 * @return {Number} The index of the Record. Returns -1 if not found.
7665 indexOfId : function(id){
7666 return this.data.indexOfKey(id);
7670 * Get the Record with the specified id.
7671 * @param {String} id The id of the Record to find.
7672 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7674 getById : function(id){
7675 return this.data.key(id);
7679 * Get the Record at the specified index.
7680 * @param {Number} index The index of the Record to find.
7681 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7683 getAt : function(index){
7684 return this.data.itemAt(index);
7688 * Returns a range of Records between specified indices.
7689 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7690 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7691 * @return {Roo.data.Record[]} An array of Records
7693 getRange : function(start, end){
7694 return this.data.getRange(start, end);
7698 storeOptions : function(o){
7699 o = Roo.apply({}, o);
7702 this.lastOptions = o;
7706 * Loads the Record cache from the configured Proxy using the configured Reader.
7708 * If using remote paging, then the first load call must specify the <em>start</em>
7709 * and <em>limit</em> properties in the options.params property to establish the initial
7710 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7712 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7713 * and this call will return before the new data has been loaded. Perform any post-processing
7714 * in a callback function, or in a "load" event handler.</strong>
7716 * @param {Object} options An object containing properties which control loading options:<ul>
7717 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7718 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7719 * passed the following arguments:<ul>
7720 * <li>r : Roo.data.Record[]</li>
7721 * <li>options: Options object from the load call</li>
7722 * <li>success: Boolean success indicator</li></ul></li>
7723 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7724 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7727 load : function(options){
7728 options = options || {};
7729 if(this.fireEvent("beforeload", this, options) !== false){
7730 this.storeOptions(options);
7731 var p = Roo.apply(options.params || {}, this.baseParams);
7732 // if meta was not loaded from remote source.. try requesting it.
7733 if (!this.reader.metaFromRemote) {
7736 if(this.sortInfo && this.remoteSort){
7737 var pn = this.paramNames;
7738 p[pn["sort"]] = this.sortInfo.field;
7739 p[pn["dir"]] = this.sortInfo.direction;
7741 if (this.multiSort) {
7742 var pn = this.paramNames;
7743 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7746 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7751 * Reloads the Record cache from the configured Proxy using the configured Reader and
7752 * the options from the last load operation performed.
7753 * @param {Object} options (optional) An object containing properties which may override the options
7754 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7755 * the most recently used options are reused).
7757 reload : function(options){
7758 this.load(Roo.applyIf(options||{}, this.lastOptions));
7762 // Called as a callback by the Reader during a load operation.
7763 loadRecords : function(o, options, success){
7764 if(!o || success === false){
7765 if(success !== false){
7766 this.fireEvent("load", this, [], options, o);
7768 if(options.callback){
7769 options.callback.call(options.scope || this, [], options, false);
7773 // if data returned failure - throw an exception.
7774 if (o.success === false) {
7775 // show a message if no listener is registered.
7776 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7777 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7779 // loadmask wil be hooked into this..
7780 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7783 var r = o.records, t = o.totalRecords || r.length;
7785 this.fireEvent("beforeloadadd", this, r, options, o);
7787 if(!options || options.add !== true){
7788 if(this.pruneModifiedRecords){
7791 for(var i = 0, len = r.length; i < len; i++){
7795 this.data = this.snapshot;
7796 delete this.snapshot;
7799 this.data.addAll(r);
7800 this.totalLength = t;
7802 this.fireEvent("datachanged", this);
7804 this.totalLength = Math.max(t, this.data.length+r.length);
7807 this.fireEvent("load", this, r, options, o);
7808 if(options.callback){
7809 options.callback.call(options.scope || this, r, options, true);
7815 * Loads data from a passed data block. A Reader which understands the format of the data
7816 * must have been configured in the constructor.
7817 * @param {Object} data The data block from which to read the Records. The format of the data expected
7818 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7819 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7821 loadData : function(o, append){
7822 var r = this.reader.readRecords(o);
7823 this.loadRecords(r, {add: append}, true);
7827 * Gets the number of cached records.
7829 * <em>If using paging, this may not be the total size of the dataset. If the data object
7830 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7831 * the data set size</em>
7833 getCount : function(){
7834 return this.data.length || 0;
7838 * Gets the total number of records in the dataset as returned by the server.
7840 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7841 * the dataset size</em>
7843 getTotalCount : function(){
7844 return this.totalLength || 0;
7848 * Returns the sort state of the Store as an object with two properties:
7850 field {String} The name of the field by which the Records are sorted
7851 direction {String} The sort order, "ASC" or "DESC"
7854 getSortState : function(){
7855 return this.sortInfo;
7859 applySort : function(){
7860 if(this.sortInfo && !this.remoteSort){
7861 var s = this.sortInfo, f = s.field;
7862 var st = this.fields.get(f).sortType;
7863 var fn = function(r1, r2){
7864 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7865 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7867 this.data.sort(s.direction, fn);
7868 if(this.snapshot && this.snapshot != this.data){
7869 this.snapshot.sort(s.direction, fn);
7875 * Sets the default sort column and order to be used by the next load operation.
7876 * @param {String} fieldName The name of the field to sort by.
7877 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7879 setDefaultSort : function(field, dir){
7880 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7885 * If remote sorting is used, the sort is performed on the server, and the cache is
7886 * reloaded. If local sorting is used, the cache is sorted internally.
7887 * @param {String} fieldName The name of the field to sort by.
7888 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7890 sort : function(fieldName, dir){
7891 var f = this.fields.get(fieldName);
7893 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7895 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7896 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7901 this.sortToggle[f.name] = dir;
7902 this.sortInfo = {field: f.name, direction: dir};
7903 if(!this.remoteSort){
7905 this.fireEvent("datachanged", this);
7907 this.load(this.lastOptions);
7912 * Calls the specified function for each of the Records in the cache.
7913 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7914 * Returning <em>false</em> aborts and exits the iteration.
7915 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7917 each : function(fn, scope){
7918 this.data.each(fn, scope);
7922 * Gets all records modified since the last commit. Modified records are persisted across load operations
7923 * (e.g., during paging).
7924 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7926 getModifiedRecords : function(){
7927 return this.modified;
7931 createFilterFn : function(property, value, anyMatch){
7932 if(!value.exec){ // not a regex
7933 value = String(value);
7934 if(value.length == 0){
7937 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7940 return value.test(r.data[property]);
7945 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7946 * @param {String} property A field on your records
7947 * @param {Number} start The record index to start at (defaults to 0)
7948 * @param {Number} end The last record index to include (defaults to length - 1)
7949 * @return {Number} The sum
7951 sum : function(property, start, end){
7952 var rs = this.data.items, v = 0;
7954 end = (end || end === 0) ? end : rs.length-1;
7956 for(var i = start; i <= end; i++){
7957 v += (rs[i].data[property] || 0);
7963 * Filter the records by a specified property.
7964 * @param {String} field A field on your records
7965 * @param {String/RegExp} value Either a string that the field
7966 * should start with or a RegExp to test against the field
7967 * @param {Boolean} anyMatch True to match any part not just the beginning
7969 filter : function(property, value, anyMatch){
7970 var fn = this.createFilterFn(property, value, anyMatch);
7971 return fn ? this.filterBy(fn) : this.clearFilter();
7975 * Filter by a function. The specified function will be called with each
7976 * record in this data source. If the function returns true the record is included,
7977 * otherwise it is filtered.
7978 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7979 * @param {Object} scope (optional) The scope of the function (defaults to this)
7981 filterBy : function(fn, scope){
7982 this.snapshot = this.snapshot || this.data;
7983 this.data = this.queryBy(fn, scope||this);
7984 this.fireEvent("datachanged", this);
7988 * Query the records by a specified property.
7989 * @param {String} field A field on your records
7990 * @param {String/RegExp} value Either a string that the field
7991 * should start with or a RegExp to test against the field
7992 * @param {Boolean} anyMatch True to match any part not just the beginning
7993 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7995 query : function(property, value, anyMatch){
7996 var fn = this.createFilterFn(property, value, anyMatch);
7997 return fn ? this.queryBy(fn) : this.data.clone();
8001 * Query by a function. The specified function will be called with each
8002 * record in this data source. If the function returns true the record is included
8004 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8005 * @param {Object} scope (optional) The scope of the function (defaults to this)
8006 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8008 queryBy : function(fn, scope){
8009 var data = this.snapshot || this.data;
8010 return data.filterBy(fn, scope||this);
8014 * Collects unique values for a particular dataIndex from this store.
8015 * @param {String} dataIndex The property to collect
8016 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8017 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8018 * @return {Array} An array of the unique values
8020 collect : function(dataIndex, allowNull, bypassFilter){
8021 var d = (bypassFilter === true && this.snapshot) ?
8022 this.snapshot.items : this.data.items;
8023 var v, sv, r = [], l = {};
8024 for(var i = 0, len = d.length; i < len; i++){
8025 v = d[i].data[dataIndex];
8027 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8036 * Revert to a view of the Record cache with no filtering applied.
8037 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8039 clearFilter : function(suppressEvent){
8040 if(this.snapshot && this.snapshot != this.data){
8041 this.data = this.snapshot;
8042 delete this.snapshot;
8043 if(suppressEvent !== true){
8044 this.fireEvent("datachanged", this);
8050 afterEdit : function(record){
8051 if(this.modified.indexOf(record) == -1){
8052 this.modified.push(record);
8054 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8058 afterReject : function(record){
8059 this.modified.remove(record);
8060 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8064 afterCommit : function(record){
8065 this.modified.remove(record);
8066 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8070 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8071 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8073 commitChanges : function(){
8074 var m = this.modified.slice(0);
8076 for(var i = 0, len = m.length; i < len; i++){
8082 * Cancel outstanding changes on all changed records.
8084 rejectChanges : function(){
8085 var m = this.modified.slice(0);
8087 for(var i = 0, len = m.length; i < len; i++){
8092 onMetaChange : function(meta, rtype, o){
8093 this.recordType = rtype;
8094 this.fields = rtype.prototype.fields;
8095 delete this.snapshot;
8096 this.sortInfo = meta.sortInfo || this.sortInfo;
8098 this.fireEvent('metachange', this, this.reader.meta);
8101 moveIndex : function(data, type)
8103 var index = this.indexOf(data);
8105 var newIndex = index + type;
8109 this.insert(newIndex, data);
8114 * Ext JS Library 1.1.1
8115 * Copyright(c) 2006-2007, Ext JS, LLC.
8117 * Originally Released Under LGPL - original licence link has changed is not relivant.
8120 * <script type="text/javascript">
8124 * @class Roo.data.SimpleStore
8125 * @extends Roo.data.Store
8126 * Small helper class to make creating Stores from Array data easier.
8127 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8128 * @cfg {Array} fields An array of field definition objects, or field name strings.
8129 * @cfg {Array} data The multi-dimensional array of data
8131 * @param {Object} config
8133 Roo.data.SimpleStore = function(config){
8134 Roo.data.SimpleStore.superclass.constructor.call(this, {
8136 reader: new Roo.data.ArrayReader({
8139 Roo.data.Record.create(config.fields)
8141 proxy : new Roo.data.MemoryProxy(config.data)
8145 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8147 * Ext JS Library 1.1.1
8148 * Copyright(c) 2006-2007, Ext JS, LLC.
8150 * Originally Released Under LGPL - original licence link has changed is not relivant.
8153 * <script type="text/javascript">
8158 * @extends Roo.data.Store
8159 * @class Roo.data.JsonStore
8160 * Small helper class to make creating Stores for JSON data easier. <br/>
8162 var store = new Roo.data.JsonStore({
8163 url: 'get-images.php',
8165 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8168 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8169 * JsonReader and HttpProxy (unless inline data is provided).</b>
8170 * @cfg {Array} fields An array of field definition objects, or field name strings.
8172 * @param {Object} config
8174 Roo.data.JsonStore = function(c){
8175 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8176 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8177 reader: new Roo.data.JsonReader(c, c.fields)
8180 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8182 * Ext JS Library 1.1.1
8183 * Copyright(c) 2006-2007, Ext JS, LLC.
8185 * Originally Released Under LGPL - original licence link has changed is not relivant.
8188 * <script type="text/javascript">
8192 Roo.data.Field = function(config){
8193 if(typeof config == "string"){
8194 config = {name: config};
8196 Roo.apply(this, config);
8202 var st = Roo.data.SortTypes;
8203 // named sortTypes are supported, here we look them up
8204 if(typeof this.sortType == "string"){
8205 this.sortType = st[this.sortType];
8208 // set default sortType for strings and dates
8212 this.sortType = st.asUCString;
8215 this.sortType = st.asDate;
8218 this.sortType = st.none;
8223 var stripRe = /[\$,%]/g;
8225 // prebuilt conversion function for this field, instead of
8226 // switching every time we're reading a value
8228 var cv, dateFormat = this.dateFormat;
8233 cv = function(v){ return v; };
8236 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8240 return v !== undefined && v !== null && v !== '' ?
8241 parseInt(String(v).replace(stripRe, ""), 10) : '';
8246 return v !== undefined && v !== null && v !== '' ?
8247 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8252 cv = function(v){ return v === true || v === "true" || v == 1; };
8259 if(v instanceof Date){
8263 if(dateFormat == "timestamp"){
8264 return new Date(v*1000);
8266 return Date.parseDate(v, dateFormat);
8268 var parsed = Date.parse(v);
8269 return parsed ? new Date(parsed) : null;
8278 Roo.data.Field.prototype = {
8286 * Ext JS Library 1.1.1
8287 * Copyright(c) 2006-2007, Ext JS, LLC.
8289 * Originally Released Under LGPL - original licence link has changed is not relivant.
8292 * <script type="text/javascript">
8295 // Base class for reading structured data from a data source. This class is intended to be
8296 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8299 * @class Roo.data.DataReader
8300 * Base class for reading structured data from a data source. This class is intended to be
8301 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8304 Roo.data.DataReader = function(meta, recordType){
8308 this.recordType = recordType instanceof Array ?
8309 Roo.data.Record.create(recordType) : recordType;
8312 Roo.data.DataReader.prototype = {
8314 * Create an empty record
8315 * @param {Object} data (optional) - overlay some values
8316 * @return {Roo.data.Record} record created.
8318 newRow : function(d) {
8320 this.recordType.prototype.fields.each(function(c) {
8322 case 'int' : da[c.name] = 0; break;
8323 case 'date' : da[c.name] = new Date(); break;
8324 case 'float' : da[c.name] = 0.0; break;
8325 case 'boolean' : da[c.name] = false; break;
8326 default : da[c.name] = ""; break;
8330 return new this.recordType(Roo.apply(da, d));
8335 * Ext JS Library 1.1.1
8336 * Copyright(c) 2006-2007, Ext JS, LLC.
8338 * Originally Released Under LGPL - original licence link has changed is not relivant.
8341 * <script type="text/javascript">
8345 * @class Roo.data.DataProxy
8346 * @extends Roo.data.Observable
8347 * This class is an abstract base class for implementations which provide retrieval of
8348 * unformatted data objects.<br>
8350 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8351 * (of the appropriate type which knows how to parse the data object) to provide a block of
8352 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8354 * Custom implementations must implement the load method as described in
8355 * {@link Roo.data.HttpProxy#load}.
8357 Roo.data.DataProxy = function(){
8361 * Fires before a network request is made to retrieve a data object.
8362 * @param {Object} This DataProxy object.
8363 * @param {Object} params The params parameter to the load function.
8368 * Fires before the load method's callback is called.
8369 * @param {Object} This DataProxy object.
8370 * @param {Object} o The data object.
8371 * @param {Object} arg The callback argument object passed to the load function.
8375 * @event loadexception
8376 * Fires if an Exception occurs during data retrieval.
8377 * @param {Object} This DataProxy object.
8378 * @param {Object} o The data object.
8379 * @param {Object} arg The callback argument object passed to the load function.
8380 * @param {Object} e The Exception.
8382 loadexception : true
8384 Roo.data.DataProxy.superclass.constructor.call(this);
8387 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8390 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8394 * Ext JS Library 1.1.1
8395 * Copyright(c) 2006-2007, Ext JS, LLC.
8397 * Originally Released Under LGPL - original licence link has changed is not relivant.
8400 * <script type="text/javascript">
8403 * @class Roo.data.MemoryProxy
8404 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8405 * to the Reader when its load method is called.
8407 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8409 Roo.data.MemoryProxy = function(data){
8413 Roo.data.MemoryProxy.superclass.constructor.call(this);
8417 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8419 * Load data from the requested source (in this case an in-memory
8420 * data object passed to the constructor), read the data object into
8421 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8422 * process that block using the passed callback.
8423 * @param {Object} params This parameter is not used by the MemoryProxy class.
8424 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8425 * object into a block of Roo.data.Records.
8426 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8427 * The function must be passed <ul>
8428 * <li>The Record block object</li>
8429 * <li>The "arg" argument from the load function</li>
8430 * <li>A boolean success indicator</li>
8432 * @param {Object} scope The scope in which to call the callback
8433 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8435 load : function(params, reader, callback, scope, arg){
8436 params = params || {};
8439 result = reader.readRecords(this.data);
8441 this.fireEvent("loadexception", this, arg, null, e);
8442 callback.call(scope, null, arg, false);
8445 callback.call(scope, result, arg, true);
8449 update : function(params, records){
8454 * Ext JS Library 1.1.1
8455 * Copyright(c) 2006-2007, Ext JS, LLC.
8457 * Originally Released Under LGPL - original licence link has changed is not relivant.
8460 * <script type="text/javascript">
8463 * @class Roo.data.HttpProxy
8464 * @extends Roo.data.DataProxy
8465 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8466 * configured to reference a certain URL.<br><br>
8468 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8469 * from which the running page was served.<br><br>
8471 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8473 * Be aware that to enable the browser to parse an XML document, the server must set
8474 * the Content-Type header in the HTTP response to "text/xml".
8476 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8477 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8478 * will be used to make the request.
8480 Roo.data.HttpProxy = function(conn){
8481 Roo.data.HttpProxy.superclass.constructor.call(this);
8482 // is conn a conn config or a real conn?
8484 this.useAjax = !conn || !conn.events;
8488 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8489 // thse are take from connection...
8492 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8495 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8496 * extra parameters to each request made by this object. (defaults to undefined)
8499 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8500 * to each request made by this object. (defaults to undefined)
8503 * @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)
8506 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8509 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8515 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8519 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8520 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8521 * a finer-grained basis than the DataProxy events.
8523 getConnection : function(){
8524 return this.useAjax ? Roo.Ajax : this.conn;
8528 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8529 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8530 * process that block using the passed callback.
8531 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8532 * for the request to the remote server.
8533 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8534 * object into a block of Roo.data.Records.
8535 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8536 * The function must be passed <ul>
8537 * <li>The Record block object</li>
8538 * <li>The "arg" argument from the load function</li>
8539 * <li>A boolean success indicator</li>
8541 * @param {Object} scope The scope in which to call the callback
8542 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8544 load : function(params, reader, callback, scope, arg){
8545 if(this.fireEvent("beforeload", this, params) !== false){
8547 params : params || {},
8549 callback : callback,
8554 callback : this.loadResponse,
8558 Roo.applyIf(o, this.conn);
8559 if(this.activeRequest){
8560 Roo.Ajax.abort(this.activeRequest);
8562 this.activeRequest = Roo.Ajax.request(o);
8564 this.conn.request(o);
8567 callback.call(scope||this, null, arg, false);
8572 loadResponse : function(o, success, response){
8573 delete this.activeRequest;
8575 this.fireEvent("loadexception", this, o, response);
8576 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8581 result = o.reader.read(response);
8583 this.fireEvent("loadexception", this, o, response, e);
8584 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8588 this.fireEvent("load", this, o, o.request.arg);
8589 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8593 update : function(dataSet){
8598 updateResponse : function(dataSet){
8603 * Ext JS Library 1.1.1
8604 * Copyright(c) 2006-2007, Ext JS, LLC.
8606 * Originally Released Under LGPL - original licence link has changed is not relivant.
8609 * <script type="text/javascript">
8613 * @class Roo.data.ScriptTagProxy
8614 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8615 * other than the originating domain of the running page.<br><br>
8617 * <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
8618 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8620 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8621 * source code that is used as the source inside a <script> tag.<br><br>
8623 * In order for the browser to process the returned data, the server must wrap the data object
8624 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8625 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8626 * depending on whether the callback name was passed:
8629 boolean scriptTag = false;
8630 String cb = request.getParameter("callback");
8633 response.setContentType("text/javascript");
8635 response.setContentType("application/x-json");
8637 Writer out = response.getWriter();
8639 out.write(cb + "(");
8641 out.print(dataBlock.toJsonString());
8648 * @param {Object} config A configuration object.
8650 Roo.data.ScriptTagProxy = function(config){
8651 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8652 Roo.apply(this, config);
8653 this.head = document.getElementsByTagName("head")[0];
8656 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8658 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8660 * @cfg {String} url The URL from which to request the data object.
8663 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8667 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8668 * the server the name of the callback function set up by the load call to process the returned data object.
8669 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8670 * javascript output which calls this named function passing the data object as its only parameter.
8672 callbackParam : "callback",
8674 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8675 * name to the request.
8680 * Load data from the configured URL, read the data object into
8681 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8682 * process that block using the passed callback.
8683 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8684 * for the request to the remote server.
8685 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8686 * object into a block of Roo.data.Records.
8687 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8688 * The function must be passed <ul>
8689 * <li>The Record block object</li>
8690 * <li>The "arg" argument from the load function</li>
8691 * <li>A boolean success indicator</li>
8693 * @param {Object} scope The scope in which to call the callback
8694 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8696 load : function(params, reader, callback, scope, arg){
8697 if(this.fireEvent("beforeload", this, params) !== false){
8699 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8702 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8704 url += "&_dc=" + (new Date().getTime());
8706 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8709 cb : "stcCallback"+transId,
8710 scriptId : "stcScript"+transId,
8714 callback : callback,
8720 window[trans.cb] = function(o){
8721 conn.handleResponse(o, trans);
8724 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8726 if(this.autoAbort !== false){
8730 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8732 var script = document.createElement("script");
8733 script.setAttribute("src", url);
8734 script.setAttribute("type", "text/javascript");
8735 script.setAttribute("id", trans.scriptId);
8736 this.head.appendChild(script);
8740 callback.call(scope||this, null, arg, false);
8745 isLoading : function(){
8746 return this.trans ? true : false;
8750 * Abort the current server request.
8753 if(this.isLoading()){
8754 this.destroyTrans(this.trans);
8759 destroyTrans : function(trans, isLoaded){
8760 this.head.removeChild(document.getElementById(trans.scriptId));
8761 clearTimeout(trans.timeoutId);
8763 window[trans.cb] = undefined;
8765 delete window[trans.cb];
8768 // if hasn't been loaded, wait for load to remove it to prevent script error
8769 window[trans.cb] = function(){
8770 window[trans.cb] = undefined;
8772 delete window[trans.cb];
8779 handleResponse : function(o, trans){
8781 this.destroyTrans(trans, true);
8784 result = trans.reader.readRecords(o);
8786 this.fireEvent("loadexception", this, o, trans.arg, e);
8787 trans.callback.call(trans.scope||window, null, trans.arg, false);
8790 this.fireEvent("load", this, o, trans.arg);
8791 trans.callback.call(trans.scope||window, result, trans.arg, true);
8795 handleFailure : function(trans){
8797 this.destroyTrans(trans, false);
8798 this.fireEvent("loadexception", this, null, trans.arg);
8799 trans.callback.call(trans.scope||window, null, trans.arg, false);
8803 * Ext JS Library 1.1.1
8804 * Copyright(c) 2006-2007, Ext JS, LLC.
8806 * Originally Released Under LGPL - original licence link has changed is not relivant.
8809 * <script type="text/javascript">
8813 * @class Roo.data.JsonReader
8814 * @extends Roo.data.DataReader
8815 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8816 * based on mappings in a provided Roo.data.Record constructor.
8818 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8819 * in the reply previously.
8824 var RecordDef = Roo.data.Record.create([
8825 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8826 {name: 'occupation'} // This field will use "occupation" as the mapping.
8828 var myReader = new Roo.data.JsonReader({
8829 totalProperty: "results", // The property which contains the total dataset size (optional)
8830 root: "rows", // The property which contains an Array of row objects
8831 id: "id" // The property within each row object that provides an ID for the record (optional)
8835 * This would consume a JSON file like this:
8837 { 'results': 2, 'rows': [
8838 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8839 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8842 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8843 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8844 * paged from the remote server.
8845 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8846 * @cfg {String} root name of the property which contains the Array of row objects.
8847 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8849 * Create a new JsonReader
8850 * @param {Object} meta Metadata configuration options
8851 * @param {Object} recordType Either an Array of field definition objects,
8852 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8854 Roo.data.JsonReader = function(meta, recordType){
8857 // set some defaults:
8859 totalProperty: 'total',
8860 successProperty : 'success',
8865 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8867 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8870 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8871 * Used by Store query builder to append _requestMeta to params.
8874 metaFromRemote : false,
8876 * This method is only used by a DataProxy which has retrieved data from a remote server.
8877 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8878 * @return {Object} data A data block which is used by an Roo.data.Store object as
8879 * a cache of Roo.data.Records.
8881 read : function(response){
8882 var json = response.responseText;
8884 var o = /* eval:var:o */ eval("("+json+")");
8886 throw {message: "JsonReader.read: Json object not found"};
8892 this.metaFromRemote = true;
8893 this.meta = o.metaData;
8894 this.recordType = Roo.data.Record.create(o.metaData.fields);
8895 this.onMetaChange(this.meta, this.recordType, o);
8897 return this.readRecords(o);
8900 // private function a store will implement
8901 onMetaChange : function(meta, recordType, o){
8908 simpleAccess: function(obj, subsc) {
8915 getJsonAccessor: function(){
8917 return function(expr) {
8919 return(re.test(expr))
8920 ? new Function("obj", "return obj." + expr)
8930 * Create a data block containing Roo.data.Records from an XML document.
8931 * @param {Object} o An object which contains an Array of row objects in the property specified
8932 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8933 * which contains the total size of the dataset.
8934 * @return {Object} data A data block which is used by an Roo.data.Store object as
8935 * a cache of Roo.data.Records.
8937 readRecords : function(o){
8939 * After any data loads, the raw JSON data is available for further custom processing.
8943 var s = this.meta, Record = this.recordType,
8944 f = Record.prototype.fields, fi = f.items, fl = f.length;
8946 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8948 if(s.totalProperty) {
8949 this.getTotal = this.getJsonAccessor(s.totalProperty);
8951 if(s.successProperty) {
8952 this.getSuccess = this.getJsonAccessor(s.successProperty);
8954 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8956 var g = this.getJsonAccessor(s.id);
8957 this.getId = function(rec) {
8959 return (r === undefined || r === "") ? null : r;
8962 this.getId = function(){return null;};
8965 for(var jj = 0; jj < fl; jj++){
8967 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8968 this.ef[jj] = this.getJsonAccessor(map);
8972 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8973 if(s.totalProperty){
8974 var vt = parseInt(this.getTotal(o), 10);
8979 if(s.successProperty){
8980 var vs = this.getSuccess(o);
8981 if(vs === false || vs === 'false'){
8986 for(var i = 0; i < c; i++){
8989 var id = this.getId(n);
8990 for(var j = 0; j < fl; j++){
8992 var v = this.ef[j](n);
8994 Roo.log('missing convert for ' + f.name);
8998 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9000 var record = new Record(values, id);
9002 records[i] = record;
9008 totalRecords : totalRecords
9013 * Ext JS Library 1.1.1
9014 * Copyright(c) 2006-2007, Ext JS, LLC.
9016 * Originally Released Under LGPL - original licence link has changed is not relivant.
9019 * <script type="text/javascript">
9023 * @class Roo.data.ArrayReader
9024 * @extends Roo.data.DataReader
9025 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9026 * Each element of that Array represents a row of data fields. The
9027 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9028 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9032 var RecordDef = Roo.data.Record.create([
9033 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9034 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9036 var myReader = new Roo.data.ArrayReader({
9037 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9041 * This would consume an Array like this:
9043 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9045 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9047 * Create a new JsonReader
9048 * @param {Object} meta Metadata configuration options.
9049 * @param {Object} recordType Either an Array of field definition objects
9050 * as specified to {@link Roo.data.Record#create},
9051 * or an {@link Roo.data.Record} object
9052 * created using {@link Roo.data.Record#create}.
9054 Roo.data.ArrayReader = function(meta, recordType){
9055 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9058 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9060 * Create a data block containing Roo.data.Records from an XML document.
9061 * @param {Object} o An Array of row objects which represents the dataset.
9062 * @return {Object} data A data block which is used by an Roo.data.Store object as
9063 * a cache of Roo.data.Records.
9065 readRecords : function(o){
9066 var sid = this.meta ? this.meta.id : null;
9067 var recordType = this.recordType, fields = recordType.prototype.fields;
9070 for(var i = 0; i < root.length; i++){
9073 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9074 for(var j = 0, jlen = fields.length; j < jlen; j++){
9075 var f = fields.items[j];
9076 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9077 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9081 var record = new recordType(values, id);
9083 records[records.length] = record;
9087 totalRecords : records.length
9096 * @class Roo.bootstrap.ComboBox
9097 * @extends Roo.bootstrap.TriggerField
9098 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9099 * @cfg {Boolean} append (true|false) default false
9101 * Create a new ComboBox.
9102 * @param {Object} config Configuration options
9104 Roo.bootstrap.ComboBox = function(config){
9105 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9109 * Fires when the dropdown list is expanded
9110 * @param {Roo.bootstrap.ComboBox} combo This combo box
9115 * Fires when the dropdown list is collapsed
9116 * @param {Roo.bootstrap.ComboBox} combo This combo box
9120 * @event beforeselect
9121 * Fires before a list item is selected. Return false to cancel the selection.
9122 * @param {Roo.bootstrap.ComboBox} combo This combo box
9123 * @param {Roo.data.Record} record The data record returned from the underlying store
9124 * @param {Number} index The index of the selected item in the dropdown list
9126 'beforeselect' : true,
9129 * Fires when a list item is selected
9130 * @param {Roo.bootstrap.ComboBox} combo This combo box
9131 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9132 * @param {Number} index The index of the selected item in the dropdown list
9136 * @event beforequery
9137 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9138 * The event object passed has these properties:
9139 * @param {Roo.bootstrap.ComboBox} combo This combo box
9140 * @param {String} query The query
9141 * @param {Boolean} forceAll true to force "all" query
9142 * @param {Boolean} cancel true to cancel the query
9143 * @param {Object} e The query event object
9145 'beforequery': true,
9148 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9149 * @param {Roo.bootstrap.ComboBox} combo This combo box
9154 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9155 * @param {Roo.bootstrap.ComboBox} combo This combo box
9156 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9161 * Fires when the remove value from the combobox array
9162 * @param {Roo.bootstrap.ComboBox} combo This combo box
9169 this.selectedIndex = -1;
9170 if(this.mode == 'local'){
9171 if(config.queryDelay === undefined){
9172 this.queryDelay = 10;
9174 if(config.minChars === undefined){
9180 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9183 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9184 * rendering into an Roo.Editor, defaults to false)
9187 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9188 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9191 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9194 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9195 * the dropdown list (defaults to undefined, with no header element)
9199 * @cfg {String/Roo.Template} tpl The template to use to render the output
9203 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9205 listWidth: undefined,
9207 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9208 * mode = 'remote' or 'text' if mode = 'local')
9210 displayField: undefined,
9212 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9213 * mode = 'remote' or 'value' if mode = 'local').
9214 * Note: use of a valueField requires the user make a selection
9215 * in order for a value to be mapped.
9217 valueField: undefined,
9221 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9222 * field's data value (defaults to the underlying DOM element's name)
9224 hiddenName: undefined,
9226 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9230 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9232 selectedClass: 'active',
9235 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9239 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9240 * anchor positions (defaults to 'tl-bl')
9242 listAlign: 'tl-bl?',
9244 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9248 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9249 * query specified by the allQuery config option (defaults to 'query')
9251 triggerAction: 'query',
9253 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9254 * (defaults to 4, does not apply if editable = false)
9258 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9259 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9263 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9264 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9268 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9269 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9273 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9274 * when editable = true (defaults to false)
9276 selectOnFocus:false,
9278 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9280 queryParam: 'query',
9282 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9283 * when mode = 'remote' (defaults to 'Loading...')
9285 loadingText: 'Loading...',
9287 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9291 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9295 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9296 * traditional select (defaults to true)
9300 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9304 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9308 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9309 * listWidth has a higher value)
9313 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9314 * allow the user to set arbitrary text into the field (defaults to false)
9316 forceSelection:false,
9318 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9319 * if typeAhead = true (defaults to 250)
9321 typeAheadDelay : 250,
9323 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9324 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9326 valueNotFoundText : undefined,
9328 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9333 * @cfg {Boolean} disableClear Disable showing of clear button.
9335 disableClear : false,
9337 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9339 alwaysQuery : false,
9342 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9356 // element that contains real text value.. (when hidden is used..)
9359 initEvents: function(){
9362 throw "can not find store for combo";
9364 this.store = Roo.factory(this.store, Roo.data);
9368 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9371 if(this.hiddenName){
9373 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9375 this.hiddenField.dom.value =
9376 this.hiddenValue !== undefined ? this.hiddenValue :
9377 this.value !== undefined ? this.value : '';
9379 // prevent input submission
9380 this.el.dom.removeAttribute('name');
9381 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9386 // this.el.dom.setAttribute('autocomplete', 'off');
9389 var cls = 'x-combo-list';
9390 this.list = this.el.select('ul.dropdown-menu',true).first();
9392 //this.list = new Roo.Layer({
9393 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9396 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9397 this.list.setWidth(lw);
9399 this.list.on('mouseover', this.onViewOver, this);
9400 this.list.on('mousemove', this.onViewMove, this);
9402 this.list.on('scroll', this.onViewScroll, this);
9405 this.list.swallowEvent('mousewheel');
9406 this.assetHeight = 0;
9409 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9410 this.assetHeight += this.header.getHeight();
9413 this.innerList = this.list.createChild({cls:cls+'-inner'});
9414 this.innerList.on('mouseover', this.onViewOver, this);
9415 this.innerList.on('mousemove', this.onViewMove, this);
9416 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9418 if(this.allowBlank && !this.pageSize && !this.disableClear){
9419 this.footer = this.list.createChild({cls:cls+'-ft'});
9420 this.pageTb = new Roo.Toolbar(this.footer);
9424 this.footer = this.list.createChild({cls:cls+'-ft'});
9425 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9426 {pageSize: this.pageSize});
9430 if (this.pageTb && this.allowBlank && !this.disableClear) {
9432 this.pageTb.add(new Roo.Toolbar.Fill(), {
9433 cls: 'x-btn-icon x-btn-clear',
9439 _this.onSelect(false, -1);
9444 this.assetHeight += this.footer.getHeight();
9449 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9452 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9453 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9455 //this.view.wrapEl.setDisplayed(false);
9456 this.view.on('click', this.onViewClick, this);
9460 this.store.on('beforeload', this.onBeforeLoad, this);
9461 this.store.on('load', this.onLoad, this);
9462 this.store.on('loadexception', this.onLoadException, this);
9465 this.resizer = new Roo.Resizable(this.list, {
9466 pinned:true, handles:'se'
9468 this.resizer.on('resize', function(r, w, h){
9469 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9471 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9472 this.restrictHeight();
9474 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9478 this.editable = true;
9479 this.setEditable(false);
9484 if (typeof(this.events.add.listeners) != 'undefined') {
9486 this.addicon = this.wrap.createChild(
9487 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9489 this.addicon.on('click', function(e) {
9490 this.fireEvent('add', this);
9493 if (typeof(this.events.edit.listeners) != 'undefined') {
9495 this.editicon = this.wrap.createChild(
9496 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9498 this.editicon.setStyle('margin-left', '40px');
9500 this.editicon.on('click', function(e) {
9502 // we fire even if inothing is selected..
9503 this.fireEvent('edit', this, this.lastData );
9509 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9511 this.inKeyMode = true;
9515 "down" : function(e){
9516 if(!this.isExpanded()){
9517 this.onTriggerClick();
9519 this.inKeyMode = true;
9524 "enter" : function(e){
9529 "esc" : function(e){
9533 "tab" : function(e){
9536 if(this.fireEvent("specialkey", this, e)){
9537 this.onViewClick(false);
9545 doRelay : function(foo, bar, hname){
9546 if(hname == 'down' || this.scope.isExpanded()){
9547 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9556 this.queryDelay = Math.max(this.queryDelay || 10,
9557 this.mode == 'local' ? 10 : 250);
9560 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9563 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9565 if(this.editable !== false){
9566 this.inputEl().on("keyup", this.onKeyUp, this);
9568 if(this.forceSelection){
9569 this.inputEl().on('blur', this.doForce, this);
9573 this.choices = this.el.select('ul.select2-choices', true).first();
9574 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9578 onDestroy : function(){
9580 this.view.setStore(null);
9581 this.view.el.removeAllListeners();
9582 this.view.el.remove();
9583 this.view.purgeListeners();
9586 this.list.dom.innerHTML = '';
9589 this.store.un('beforeload', this.onBeforeLoad, this);
9590 this.store.un('load', this.onLoad, this);
9591 this.store.un('loadexception', this.onLoadException, this);
9593 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9597 fireKey : function(e){
9598 if(e.isNavKeyPress() && !this.list.isVisible()){
9599 this.fireEvent("specialkey", this, e);
9604 onResize: function(w, h){
9605 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9607 // if(typeof w != 'number'){
9608 // // we do not handle it!?!?
9611 // var tw = this.trigger.getWidth();
9612 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9613 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9615 // this.inputEl().setWidth( this.adjustWidth('input', x));
9617 // //this.trigger.setStyle('left', x+'px');
9619 // if(this.list && this.listWidth === undefined){
9620 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9621 // this.list.setWidth(lw);
9622 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9630 * Allow or prevent the user from directly editing the field text. If false is passed,
9631 * the user will only be able to select from the items defined in the dropdown list. This method
9632 * is the runtime equivalent of setting the 'editable' config option at config time.
9633 * @param {Boolean} value True to allow the user to directly edit the field text
9635 setEditable : function(value){
9636 if(value == this.editable){
9639 this.editable = value;
9641 this.inputEl().dom.setAttribute('readOnly', true);
9642 this.inputEl().on('mousedown', this.onTriggerClick, this);
9643 this.inputEl().addClass('x-combo-noedit');
9645 this.inputEl().dom.setAttribute('readOnly', false);
9646 this.inputEl().un('mousedown', this.onTriggerClick, this);
9647 this.inputEl().removeClass('x-combo-noedit');
9653 onBeforeLoad : function(combo,opts){
9658 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9660 this.restrictHeight();
9661 this.selectedIndex = -1;
9665 onLoad : function(){
9667 this.hasQuery = false;
9673 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9674 this.loading.hide();
9677 if(this.store.getCount() > 0){
9679 this.restrictHeight();
9680 if(this.lastQuery == this.allQuery){
9682 this.inputEl().dom.select();
9684 if(!this.selectByValue(this.value, true)){
9685 this.select(0, true);
9689 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9690 this.taTask.delay(this.typeAheadDelay);
9694 this.onEmptyResults();
9700 onLoadException : function()
9702 this.hasQuery = false;
9704 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9705 this.loading.hide();
9709 Roo.log(this.store.reader.jsonData);
9710 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9712 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9718 onTypeAhead : function(){
9719 if(this.store.getCount() > 0){
9720 var r = this.store.getAt(0);
9721 var newValue = r.data[this.displayField];
9722 var len = newValue.length;
9723 var selStart = this.getRawValue().length;
9725 if(selStart != len){
9726 this.setRawValue(newValue);
9727 this.selectText(selStart, newValue.length);
9733 onSelect : function(record, index){
9735 if(this.fireEvent('beforeselect', this, record, index) !== false){
9737 this.setFromData(index > -1 ? record.data : false);
9740 this.fireEvent('select', this, record, index);
9745 * Returns the currently selected field value or empty string if no value is set.
9746 * @return {String} value The selected value
9748 getValue : function(){
9751 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9754 if(this.valueField){
9755 return typeof this.value != 'undefined' ? this.value : '';
9757 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9762 * Clears any text/value currently set in the field
9764 clearValue : function(){
9765 if(this.hiddenField){
9766 this.hiddenField.dom.value = '';
9769 this.setRawValue('');
9770 this.lastSelectionText = '';
9775 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9776 * will be displayed in the field. If the value does not match the data value of an existing item,
9777 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9778 * Otherwise the field will be blank (although the value will still be set).
9779 * @param {String} value The value to match
9781 setValue : function(v){
9788 if(this.valueField){
9789 var r = this.findRecord(this.valueField, v);
9791 text = r.data[this.displayField];
9792 }else if(this.valueNotFoundText !== undefined){
9793 text = this.valueNotFoundText;
9796 this.lastSelectionText = text;
9797 if(this.hiddenField){
9798 this.hiddenField.dom.value = v;
9800 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9804 * @property {Object} the last set data for the element
9809 * Sets the value of the field based on a object which is related to the record format for the store.
9810 * @param {Object} value the value to set as. or false on reset?
9812 setFromData : function(o){
9819 var dv = ''; // display value
9820 var vv = ''; // value value..
9822 if (this.displayField) {
9823 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9825 // this is an error condition!!!
9826 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9829 if(this.valueField){
9830 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9833 if(this.hiddenField){
9834 this.hiddenField.dom.value = vv;
9836 this.lastSelectionText = dv;
9837 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9841 // no hidden field.. - we store the value in 'value', but still display
9842 // display field!!!!
9843 this.lastSelectionText = dv;
9844 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9851 // overridden so that last data is reset..
9852 this.setValue(this.originalValue);
9853 this.clearInvalid();
9854 this.lastData = false;
9856 this.view.clearSelections();
9860 findRecord : function(prop, value){
9862 if(this.store.getCount() > 0){
9863 this.store.each(function(r){
9864 if(r.data[prop] == value){
9876 // returns hidden if it's set..
9877 if (!this.rendered) {return ''};
9878 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9882 onViewMove : function(e, t){
9883 this.inKeyMode = false;
9887 onViewOver : function(e, t){
9888 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9891 var item = this.view.findItemFromChild(t);
9893 var index = this.view.indexOf(item);
9894 this.select(index, false);
9899 onViewClick : function(doFocus)
9901 var index = this.view.getSelectedIndexes()[0];
9902 var r = this.store.getAt(index);
9904 this.onSelect(r, index);
9906 if(doFocus !== false && !this.blockFocus){
9907 this.inputEl().focus();
9912 restrictHeight : function(){
9913 //this.innerList.dom.style.height = '';
9914 //var inner = this.innerList.dom;
9915 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9916 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9917 //this.list.beginUpdate();
9918 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9919 this.list.alignTo(this.inputEl(), this.listAlign);
9920 //this.list.endUpdate();
9924 onEmptyResults : function(){
9929 * Returns true if the dropdown list is expanded, else false.
9931 isExpanded : function(){
9932 return this.list.isVisible();
9936 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9937 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9938 * @param {String} value The data value of the item to select
9939 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9940 * selected item if it is not currently in view (defaults to true)
9941 * @return {Boolean} True if the value matched an item in the list, else false
9943 selectByValue : function(v, scrollIntoView){
9944 if(v !== undefined && v !== null){
9945 var r = this.findRecord(this.valueField || this.displayField, v);
9947 this.select(this.store.indexOf(r), scrollIntoView);
9955 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9956 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9957 * @param {Number} index The zero-based index of the list item to select
9958 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9959 * selected item if it is not currently in view (defaults to true)
9961 select : function(index, scrollIntoView){
9962 this.selectedIndex = index;
9963 this.view.select(index);
9964 if(scrollIntoView !== false){
9965 var el = this.view.getNode(index);
9967 //this.innerList.scrollChildIntoView(el, false);
9974 selectNext : function(){
9975 var ct = this.store.getCount();
9977 if(this.selectedIndex == -1){
9979 }else if(this.selectedIndex < ct-1){
9980 this.select(this.selectedIndex+1);
9986 selectPrev : function(){
9987 var ct = this.store.getCount();
9989 if(this.selectedIndex == -1){
9991 }else if(this.selectedIndex != 0){
9992 this.select(this.selectedIndex-1);
9998 onKeyUp : function(e){
9999 if(this.editable !== false && !e.isSpecialKey()){
10000 this.lastKey = e.getKey();
10001 this.dqTask.delay(this.queryDelay);
10006 validateBlur : function(){
10007 return !this.list || !this.list.isVisible();
10011 initQuery : function(){
10012 this.doQuery(this.getRawValue());
10016 doForce : function(){
10017 if(this.inputEl().dom.value.length > 0){
10018 this.inputEl().dom.value =
10019 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10025 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10026 * query allowing the query action to be canceled if needed.
10027 * @param {String} query The SQL query to execute
10028 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10029 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10030 * saved in the current store (defaults to false)
10032 doQuery : function(q, forceAll){
10034 if(q === undefined || q === null){
10039 forceAll: forceAll,
10043 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10048 forceAll = qe.forceAll;
10049 if(forceAll === true || (q.length >= this.minChars)){
10051 this.hasQuery = true;
10053 if(this.lastQuery != q || this.alwaysQuery){
10054 this.lastQuery = q;
10055 if(this.mode == 'local'){
10056 this.selectedIndex = -1;
10058 this.store.clearFilter();
10060 this.store.filter(this.displayField, q);
10064 this.store.baseParams[this.queryParam] = q;
10066 var options = {params : this.getParams(q)};
10069 options.add = true;
10070 options.params.start = this.page * this.pageSize;
10073 this.store.load(options);
10077 this.selectedIndex = -1;
10082 this.loadNext = false;
10086 getParams : function(q){
10088 //p[this.queryParam] = q;
10092 p.limit = this.pageSize;
10098 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10100 collapse : function(){
10101 if(!this.isExpanded()){
10106 Roo.get(document).un('mousedown', this.collapseIf, this);
10107 Roo.get(document).un('mousewheel', this.collapseIf, this);
10108 if (!this.editable) {
10109 Roo.get(document).un('keydown', this.listKeyPress, this);
10111 this.fireEvent('collapse', this);
10115 collapseIf : function(e){
10116 var in_combo = e.within(this.el);
10117 var in_list = e.within(this.list);
10119 if (in_combo || in_list) {
10120 //e.stopPropagation();
10129 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10131 expand : function(){
10133 if(this.isExpanded() || !this.hasFocus){
10137 this.list.alignTo(this.inputEl(), this.listAlign);
10139 Roo.get(document).on('mousedown', this.collapseIf, this);
10140 Roo.get(document).on('mousewheel', this.collapseIf, this);
10141 if (!this.editable) {
10142 Roo.get(document).on('keydown', this.listKeyPress, this);
10145 this.fireEvent('expand', this);
10149 // Implements the default empty TriggerField.onTriggerClick function
10150 onTriggerClick : function()
10152 Roo.log('trigger click');
10159 this.loadNext = false;
10161 if(this.isExpanded()){
10163 if (!this.blockFocus) {
10164 this.inputEl().focus();
10168 this.hasFocus = true;
10169 if(this.triggerAction == 'all') {
10170 this.doQuery(this.allQuery, true);
10172 this.doQuery(this.getRawValue());
10174 if (!this.blockFocus) {
10175 this.inputEl().focus();
10179 listKeyPress : function(e)
10181 //Roo.log('listkeypress');
10182 // scroll to first matching element based on key pres..
10183 if (e.isSpecialKey()) {
10186 var k = String.fromCharCode(e.getKey()).toUpperCase();
10189 var csel = this.view.getSelectedNodes();
10190 var cselitem = false;
10192 var ix = this.view.indexOf(csel[0]);
10193 cselitem = this.store.getAt(ix);
10194 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10200 this.store.each(function(v) {
10202 // start at existing selection.
10203 if (cselitem.id == v.id) {
10209 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10210 match = this.store.indexOf(v);
10216 if (match === false) {
10217 return true; // no more action?
10220 this.view.select(match);
10221 var sn = Roo.get(this.view.getSelectedNodes()[0])
10222 //sn.scrollIntoView(sn.dom.parentNode, false);
10225 onViewScroll : function(e, t){
10227 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10231 this.hasQuery = true;
10233 this.loading = this.list.select('.loading', true).first();
10235 if(this.loading === null){
10236 this.list.createChild({
10238 cls: 'loading select2-more-results select2-active',
10239 html: 'Loading more results...'
10242 this.loading = this.list.select('.loading', true).first();
10244 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10246 this.loading.hide();
10249 this.loading.show();
10254 this.loadNext = true;
10256 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10261 addItem : function(o)
10263 var dv = ''; // display value
10265 if (this.displayField) {
10266 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10268 // this is an error condition!!!
10269 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10276 var choice = this.choices.createChild({
10278 cls: 'select2-search-choice',
10287 cls: 'select2-search-choice-close',
10292 }, this.searchField);
10294 var close = choice.select('a.select2-search-choice-close', true).first()
10296 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10303 this.inputEl().dom.value = '';
10307 onRemoveItem : function(e, _self, o)
10309 e.preventDefault();
10310 var index = this.item.indexOf(o.data) * 1;
10313 Roo.log('not this item?!');
10317 this.item.splice(index, 1);
10322 this.fireEvent('remove', this, e);
10326 syncValue : function()
10328 if(!this.item.length){
10335 Roo.each(this.item, function(i){
10336 if(_this.valueField){
10337 value.push(i[_this.valueField]);
10344 this.value = value.join(',');
10346 if(this.hiddenField){
10347 this.hiddenField.dom.value = this.value;
10351 clearItem : function()
10353 if(!this.multiple){
10359 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10369 * @cfg {Boolean} grow
10373 * @cfg {Number} growMin
10377 * @cfg {Number} growMax
10387 * Ext JS Library 1.1.1
10388 * Copyright(c) 2006-2007, Ext JS, LLC.
10390 * Originally Released Under LGPL - original licence link has changed is not relivant.
10393 * <script type="text/javascript">
10398 * @extends Roo.util.Observable
10399 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10400 * This class also supports single and multi selection modes. <br>
10401 * Create a data model bound view:
10403 var store = new Roo.data.Store(...);
10405 var view = new Roo.View({
10407 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10409 singleSelect: true,
10410 selectedClass: "ydataview-selected",
10414 // listen for node click?
10415 view.on("click", function(vw, index, node, e){
10416 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10420 dataModel.load("foobar.xml");
10422 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10424 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10425 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10427 * Note: old style constructor is still suported (container, template, config)
10430 * Create a new View
10431 * @param {Object} config The config object
10434 Roo.View = function(config, depreciated_tpl, depreciated_config){
10436 if (typeof(depreciated_tpl) == 'undefined') {
10437 // new way.. - universal constructor.
10438 Roo.apply(this, config);
10439 this.el = Roo.get(this.el);
10442 this.el = Roo.get(config);
10443 this.tpl = depreciated_tpl;
10444 Roo.apply(this, depreciated_config);
10446 this.wrapEl = this.el.wrap().wrap();
10447 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10450 if(typeof(this.tpl) == "string"){
10451 this.tpl = new Roo.Template(this.tpl);
10453 // support xtype ctors..
10454 this.tpl = new Roo.factory(this.tpl, Roo);
10458 this.tpl.compile();
10466 * @event beforeclick
10467 * Fires before a click is processed. Returns false to cancel the default action.
10468 * @param {Roo.View} this
10469 * @param {Number} index The index of the target node
10470 * @param {HTMLElement} node The target node
10471 * @param {Roo.EventObject} e The raw event object
10473 "beforeclick" : true,
10476 * Fires when a template node is clicked.
10477 * @param {Roo.View} this
10478 * @param {Number} index The index of the target node
10479 * @param {HTMLElement} node The target node
10480 * @param {Roo.EventObject} e The raw event object
10485 * Fires when a template node is double clicked.
10486 * @param {Roo.View} this
10487 * @param {Number} index The index of the target node
10488 * @param {HTMLElement} node The target node
10489 * @param {Roo.EventObject} e The raw event object
10493 * @event contextmenu
10494 * Fires when a template node is right clicked.
10495 * @param {Roo.View} this
10496 * @param {Number} index The index of the target node
10497 * @param {HTMLElement} node The target node
10498 * @param {Roo.EventObject} e The raw event object
10500 "contextmenu" : true,
10502 * @event selectionchange
10503 * Fires when the selected nodes change.
10504 * @param {Roo.View} this
10505 * @param {Array} selections Array of the selected nodes
10507 "selectionchange" : true,
10510 * @event beforeselect
10511 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10512 * @param {Roo.View} this
10513 * @param {HTMLElement} node The node to be selected
10514 * @param {Array} selections Array of currently selected nodes
10516 "beforeselect" : true,
10518 * @event preparedata
10519 * Fires on every row to render, to allow you to change the data.
10520 * @param {Roo.View} this
10521 * @param {Object} data to be rendered (change this)
10523 "preparedata" : true
10531 "click": this.onClick,
10532 "dblclick": this.onDblClick,
10533 "contextmenu": this.onContextMenu,
10537 this.selections = [];
10539 this.cmp = new Roo.CompositeElementLite([]);
10541 this.store = Roo.factory(this.store, Roo.data);
10542 this.setStore(this.store, true);
10545 if ( this.footer && this.footer.xtype) {
10547 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10549 this.footer.dataSource = this.store
10550 this.footer.container = fctr;
10551 this.footer = Roo.factory(this.footer, Roo);
10552 fctr.insertFirst(this.el);
10554 // this is a bit insane - as the paging toolbar seems to detach the el..
10555 // dom.parentNode.parentNode.parentNode
10556 // they get detached?
10560 Roo.View.superclass.constructor.call(this);
10565 Roo.extend(Roo.View, Roo.util.Observable, {
10568 * @cfg {Roo.data.Store} store Data store to load data from.
10573 * @cfg {String|Roo.Element} el The container element.
10578 * @cfg {String|Roo.Template} tpl The template used by this View
10582 * @cfg {String} dataName the named area of the template to use as the data area
10583 * Works with domtemplates roo-name="name"
10587 * @cfg {String} selectedClass The css class to add to selected nodes
10589 selectedClass : "x-view-selected",
10591 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10596 * @cfg {String} text to display on mask (default Loading)
10600 * @cfg {Boolean} multiSelect Allow multiple selection
10602 multiSelect : false,
10604 * @cfg {Boolean} singleSelect Allow single selection
10606 singleSelect: false,
10609 * @cfg {Boolean} toggleSelect - selecting
10611 toggleSelect : false,
10614 * Returns the element this view is bound to.
10615 * @return {Roo.Element}
10617 getEl : function(){
10618 return this.wrapEl;
10624 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10626 refresh : function(){
10627 Roo.log('refresh');
10630 // if we are using something like 'domtemplate', then
10631 // the what gets used is:
10632 // t.applySubtemplate(NAME, data, wrapping data..)
10633 // the outer template then get' applied with
10634 // the store 'extra data'
10635 // and the body get's added to the
10636 // roo-name="data" node?
10637 // <span class='roo-tpl-{name}'></span> ?????
10641 this.clearSelections();
10642 this.el.update("");
10644 var records = this.store.getRange();
10645 if(records.length < 1) {
10647 // is this valid?? = should it render a template??
10649 this.el.update(this.emptyText);
10653 if (this.dataName) {
10654 this.el.update(t.apply(this.store.meta)); //????
10655 el = this.el.child('.roo-tpl-' + this.dataName);
10658 for(var i = 0, len = records.length; i < len; i++){
10659 var data = this.prepareData(records[i].data, i, records[i]);
10660 this.fireEvent("preparedata", this, data, i, records[i]);
10661 html[html.length] = Roo.util.Format.trim(
10663 t.applySubtemplate(this.dataName, data, this.store.meta) :
10670 el.update(html.join(""));
10671 this.nodes = el.dom.childNodes;
10672 this.updateIndexes(0);
10677 * Function to override to reformat the data that is sent to
10678 * the template for each node.
10679 * DEPRICATED - use the preparedata event handler.
10680 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10681 * a JSON object for an UpdateManager bound view).
10683 prepareData : function(data, index, record)
10685 this.fireEvent("preparedata", this, data, index, record);
10689 onUpdate : function(ds, record){
10690 Roo.log('on update');
10691 this.clearSelections();
10692 var index = this.store.indexOf(record);
10693 var n = this.nodes[index];
10694 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10695 n.parentNode.removeChild(n);
10696 this.updateIndexes(index, index);
10702 onAdd : function(ds, records, index)
10704 Roo.log(['on Add', ds, records, index] );
10705 this.clearSelections();
10706 if(this.nodes.length == 0){
10710 var n = this.nodes[index];
10711 for(var i = 0, len = records.length; i < len; i++){
10712 var d = this.prepareData(records[i].data, i, records[i]);
10714 this.tpl.insertBefore(n, d);
10717 this.tpl.append(this.el, d);
10720 this.updateIndexes(index);
10723 onRemove : function(ds, record, index){
10724 Roo.log('onRemove');
10725 this.clearSelections();
10726 var el = this.dataName ?
10727 this.el.child('.roo-tpl-' + this.dataName) :
10730 el.dom.removeChild(this.nodes[index]);
10731 this.updateIndexes(index);
10735 * Refresh an individual node.
10736 * @param {Number} index
10738 refreshNode : function(index){
10739 this.onUpdate(this.store, this.store.getAt(index));
10742 updateIndexes : function(startIndex, endIndex){
10743 var ns = this.nodes;
10744 startIndex = startIndex || 0;
10745 endIndex = endIndex || ns.length - 1;
10746 for(var i = startIndex; i <= endIndex; i++){
10747 ns[i].nodeIndex = i;
10752 * Changes the data store this view uses and refresh the view.
10753 * @param {Store} store
10755 setStore : function(store, initial){
10756 if(!initial && this.store){
10757 this.store.un("datachanged", this.refresh);
10758 this.store.un("add", this.onAdd);
10759 this.store.un("remove", this.onRemove);
10760 this.store.un("update", this.onUpdate);
10761 this.store.un("clear", this.refresh);
10762 this.store.un("beforeload", this.onBeforeLoad);
10763 this.store.un("load", this.onLoad);
10764 this.store.un("loadexception", this.onLoad);
10768 store.on("datachanged", this.refresh, this);
10769 store.on("add", this.onAdd, this);
10770 store.on("remove", this.onRemove, this);
10771 store.on("update", this.onUpdate, this);
10772 store.on("clear", this.refresh, this);
10773 store.on("beforeload", this.onBeforeLoad, this);
10774 store.on("load", this.onLoad, this);
10775 store.on("loadexception", this.onLoad, this);
10783 * onbeforeLoad - masks the loading area.
10786 onBeforeLoad : function(store,opts)
10788 Roo.log('onBeforeLoad');
10790 this.el.update("");
10792 this.el.mask(this.mask ? this.mask : "Loading" );
10794 onLoad : function ()
10801 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10802 * @param {HTMLElement} node
10803 * @return {HTMLElement} The template node
10805 findItemFromChild : function(node){
10806 var el = this.dataName ?
10807 this.el.child('.roo-tpl-' + this.dataName,true) :
10810 if(!node || node.parentNode == el){
10813 var p = node.parentNode;
10814 while(p && p != el){
10815 if(p.parentNode == el){
10824 onClick : function(e){
10825 var item = this.findItemFromChild(e.getTarget());
10827 var index = this.indexOf(item);
10828 if(this.onItemClick(item, index, e) !== false){
10829 this.fireEvent("click", this, index, item, e);
10832 this.clearSelections();
10837 onContextMenu : function(e){
10838 var item = this.findItemFromChild(e.getTarget());
10840 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10845 onDblClick : function(e){
10846 var item = this.findItemFromChild(e.getTarget());
10848 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10852 onItemClick : function(item, index, e)
10854 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10857 if (this.toggleSelect) {
10858 var m = this.isSelected(item) ? 'unselect' : 'select';
10861 _t[m](item, true, false);
10864 if(this.multiSelect || this.singleSelect){
10865 if(this.multiSelect && e.shiftKey && this.lastSelection){
10866 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10868 this.select(item, this.multiSelect && e.ctrlKey);
10869 this.lastSelection = item;
10871 e.preventDefault();
10877 * Get the number of selected nodes.
10880 getSelectionCount : function(){
10881 return this.selections.length;
10885 * Get the currently selected nodes.
10886 * @return {Array} An array of HTMLElements
10888 getSelectedNodes : function(){
10889 return this.selections;
10893 * Get the indexes of the selected nodes.
10896 getSelectedIndexes : function(){
10897 var indexes = [], s = this.selections;
10898 for(var i = 0, len = s.length; i < len; i++){
10899 indexes.push(s[i].nodeIndex);
10905 * Clear all selections
10906 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10908 clearSelections : function(suppressEvent){
10909 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10910 this.cmp.elements = this.selections;
10911 this.cmp.removeClass(this.selectedClass);
10912 this.selections = [];
10913 if(!suppressEvent){
10914 this.fireEvent("selectionchange", this, this.selections);
10920 * Returns true if the passed node is selected
10921 * @param {HTMLElement/Number} node The node or node index
10922 * @return {Boolean}
10924 isSelected : function(node){
10925 var s = this.selections;
10929 node = this.getNode(node);
10930 return s.indexOf(node) !== -1;
10935 * @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
10936 * @param {Boolean} keepExisting (optional) true to keep existing selections
10937 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10939 select : function(nodeInfo, keepExisting, suppressEvent){
10940 if(nodeInfo instanceof Array){
10942 this.clearSelections(true);
10944 for(var i = 0, len = nodeInfo.length; i < len; i++){
10945 this.select(nodeInfo[i], true, true);
10949 var node = this.getNode(nodeInfo);
10950 if(!node || this.isSelected(node)){
10951 return; // already selected.
10954 this.clearSelections(true);
10956 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10957 Roo.fly(node).addClass(this.selectedClass);
10958 this.selections.push(node);
10959 if(!suppressEvent){
10960 this.fireEvent("selectionchange", this, this.selections);
10968 * @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
10969 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10970 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10972 unselect : function(nodeInfo, keepExisting, suppressEvent)
10974 if(nodeInfo instanceof Array){
10975 Roo.each(this.selections, function(s) {
10976 this.unselect(s, nodeInfo);
10980 var node = this.getNode(nodeInfo);
10981 if(!node || !this.isSelected(node)){
10982 Roo.log("not selected");
10983 return; // not selected.
10987 Roo.each(this.selections, function(s) {
10989 Roo.fly(node).removeClass(this.selectedClass);
10996 this.selections= ns;
10997 this.fireEvent("selectionchange", this, this.selections);
11001 * Gets a template node.
11002 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11003 * @return {HTMLElement} The node or null if it wasn't found
11005 getNode : function(nodeInfo){
11006 if(typeof nodeInfo == "string"){
11007 return document.getElementById(nodeInfo);
11008 }else if(typeof nodeInfo == "number"){
11009 return this.nodes[nodeInfo];
11015 * Gets a range template nodes.
11016 * @param {Number} startIndex
11017 * @param {Number} endIndex
11018 * @return {Array} An array of nodes
11020 getNodes : function(start, end){
11021 var ns = this.nodes;
11022 start = start || 0;
11023 end = typeof end == "undefined" ? ns.length - 1 : end;
11026 for(var i = start; i <= end; i++){
11030 for(var i = start; i >= end; i--){
11038 * Finds the index of the passed node
11039 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11040 * @return {Number} The index of the node or -1
11042 indexOf : function(node){
11043 node = this.getNode(node);
11044 if(typeof node.nodeIndex == "number"){
11045 return node.nodeIndex;
11047 var ns = this.nodes;
11048 for(var i = 0, len = ns.length; i < len; i++){
11059 * based on jquery fullcalendar
11063 Roo.bootstrap = Roo.bootstrap || {};
11065 * @class Roo.bootstrap.Calendar
11066 * @extends Roo.bootstrap.Component
11067 * Bootstrap Calendar class
11068 * @cfg {Boolean} loadMask (true|false) default false
11069 * @cfg {Object} header generate the user specific header of the calendar, default false
11072 * Create a new Container
11073 * @param {Object} config The config object
11078 Roo.bootstrap.Calendar = function(config){
11079 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11083 * Fires when a date is selected
11084 * @param {DatePicker} this
11085 * @param {Date} date The selected date
11089 * @event monthchange
11090 * Fires when the displayed month changes
11091 * @param {DatePicker} this
11092 * @param {Date} date The selected month
11094 'monthchange': true,
11096 * @event evententer
11097 * Fires when mouse over an event
11098 * @param {Calendar} this
11099 * @param {event} Event
11101 'evententer': true,
11103 * @event eventleave
11104 * Fires when the mouse leaves an
11105 * @param {Calendar} this
11108 'eventleave': true,
11110 * @event eventclick
11111 * Fires when the mouse click an
11112 * @param {Calendar} this
11121 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11124 * @cfg {Number} startDay
11125 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11133 getAutoCreate : function(){
11136 var fc_button = function(name, corner, style, content ) {
11137 return Roo.apply({},{
11139 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11141 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11144 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11155 style : 'width:100%',
11162 cls : 'fc-header-left',
11164 fc_button('prev', 'left', 'arrow', '‹' ),
11165 fc_button('next', 'right', 'arrow', '›' ),
11166 { tag: 'span', cls: 'fc-header-space' },
11167 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11175 cls : 'fc-header-center',
11179 cls: 'fc-header-title',
11182 html : 'month / year'
11190 cls : 'fc-header-right',
11192 /* fc_button('month', 'left', '', 'month' ),
11193 fc_button('week', '', '', 'week' ),
11194 fc_button('day', 'right', '', 'day' )
11206 header = this.header;
11209 var cal_heads = function() {
11211 // fixme - handle this.
11213 for (var i =0; i < Date.dayNames.length; i++) {
11214 var d = Date.dayNames[i];
11217 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11218 html : d.substring(0,3)
11222 ret[0].cls += ' fc-first';
11223 ret[6].cls += ' fc-last';
11226 var cal_cell = function(n) {
11229 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11234 cls: 'fc-day-number',
11238 cls: 'fc-day-content',
11242 style: 'position: relative;' // height: 17px;
11254 var cal_rows = function() {
11257 for (var r = 0; r < 6; r++) {
11264 for (var i =0; i < Date.dayNames.length; i++) {
11265 var d = Date.dayNames[i];
11266 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11269 row.cn[0].cls+=' fc-first';
11270 row.cn[0].cn[0].style = 'min-height:90px';
11271 row.cn[6].cls+=' fc-last';
11275 ret[0].cls += ' fc-first';
11276 ret[4].cls += ' fc-prev-last';
11277 ret[5].cls += ' fc-last';
11284 cls: 'fc-border-separate',
11285 style : 'width:100%',
11293 cls : 'fc-first fc-last',
11311 cls : 'fc-content',
11312 style : "position: relative;",
11315 cls : 'fc-view fc-view-month fc-grid',
11316 style : 'position: relative',
11317 unselectable : 'on',
11320 cls : 'fc-event-container',
11321 style : 'position:absolute;z-index:8;top:0;left:0;'
11339 initEvents : function()
11342 throw "can not find store for calendar";
11348 style: "text-align:center",
11352 style: "background-color:white;width:50%;margin:250 auto",
11356 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11367 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11369 var size = this.el.select('.fc-content', true).first().getSize();
11370 this.maskEl.setSize(size.width, size.height);
11371 this.maskEl.enableDisplayMode("block");
11372 if(!this.loadMask){
11373 this.maskEl.hide();
11376 this.store = Roo.factory(this.store, Roo.data);
11377 this.store.on('load', this.onLoad, this);
11378 this.store.on('beforeload', this.onBeforeLoad, this);
11382 this.cells = this.el.select('.fc-day',true);
11383 //Roo.log(this.cells);
11384 this.textNodes = this.el.query('.fc-day-number');
11385 this.cells.addClassOnOver('fc-state-hover');
11387 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11388 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11389 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11390 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11392 this.on('monthchange', this.onMonthChange, this);
11394 this.update(new Date().clearTime());
11397 resize : function() {
11398 var sz = this.el.getSize();
11400 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11401 this.el.select('.fc-day-content div',true).setHeight(34);
11406 showPrevMonth : function(e){
11407 this.update(this.activeDate.add("mo", -1));
11409 showToday : function(e){
11410 this.update(new Date().clearTime());
11413 showNextMonth : function(e){
11414 this.update(this.activeDate.add("mo", 1));
11418 showPrevYear : function(){
11419 this.update(this.activeDate.add("y", -1));
11423 showNextYear : function(){
11424 this.update(this.activeDate.add("y", 1));
11429 update : function(date)
11431 var vd = this.activeDate;
11432 this.activeDate = date;
11433 // if(vd && this.el){
11434 // var t = date.getTime();
11435 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11436 // Roo.log('using add remove');
11438 // this.fireEvent('monthchange', this, date);
11440 // this.cells.removeClass("fc-state-highlight");
11441 // this.cells.each(function(c){
11442 // if(c.dateValue == t){
11443 // c.addClass("fc-state-highlight");
11444 // setTimeout(function(){
11445 // try{c.dom.firstChild.focus();}catch(e){}
11455 var days = date.getDaysInMonth();
11457 var firstOfMonth = date.getFirstDateOfMonth();
11458 var startingPos = firstOfMonth.getDay()-this.startDay;
11460 if(startingPos < this.startDay){
11464 var pm = date.add(Date.MONTH, -1);
11465 var prevStart = pm.getDaysInMonth()-startingPos;
11467 this.cells = this.el.select('.fc-day',true);
11468 this.textNodes = this.el.query('.fc-day-number');
11469 this.cells.addClassOnOver('fc-state-hover');
11471 var cells = this.cells.elements;
11472 var textEls = this.textNodes;
11474 Roo.each(cells, function(cell){
11475 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11478 days += startingPos;
11480 // convert everything to numbers so it's fast
11481 var day = 86400000;
11482 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11485 //Roo.log(prevStart);
11487 var today = new Date().clearTime().getTime();
11488 var sel = date.clearTime().getTime();
11489 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11490 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11491 var ddMatch = this.disabledDatesRE;
11492 var ddText = this.disabledDatesText;
11493 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11494 var ddaysText = this.disabledDaysText;
11495 var format = this.format;
11497 var setCellClass = function(cal, cell){
11499 //Roo.log('set Cell Class');
11501 var t = d.getTime();
11505 cell.dateValue = t;
11507 cell.className += " fc-today";
11508 cell.className += " fc-state-highlight";
11509 cell.title = cal.todayText;
11512 // disable highlight in other month..
11513 //cell.className += " fc-state-highlight";
11518 cell.className = " fc-state-disabled";
11519 cell.title = cal.minText;
11523 cell.className = " fc-state-disabled";
11524 cell.title = cal.maxText;
11528 if(ddays.indexOf(d.getDay()) != -1){
11529 cell.title = ddaysText;
11530 cell.className = " fc-state-disabled";
11533 if(ddMatch && format){
11534 var fvalue = d.dateFormat(format);
11535 if(ddMatch.test(fvalue)){
11536 cell.title = ddText.replace("%0", fvalue);
11537 cell.className = " fc-state-disabled";
11541 if (!cell.initialClassName) {
11542 cell.initialClassName = cell.dom.className;
11545 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11550 for(; i < startingPos; i++) {
11551 textEls[i].innerHTML = (++prevStart);
11552 d.setDate(d.getDate()+1);
11554 cells[i].className = "fc-past fc-other-month";
11555 setCellClass(this, cells[i]);
11560 for(; i < days; i++){
11561 intDay = i - startingPos + 1;
11562 textEls[i].innerHTML = (intDay);
11563 d.setDate(d.getDate()+1);
11565 cells[i].className = ''; // "x-date-active";
11566 setCellClass(this, cells[i]);
11570 for(; i < 42; i++) {
11571 textEls[i].innerHTML = (++extraDays);
11572 d.setDate(d.getDate()+1);
11574 cells[i].className = "fc-future fc-other-month";
11575 setCellClass(this, cells[i]);
11578 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11580 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11582 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11583 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11585 if(totalRows != 6){
11586 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11587 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11590 this.fireEvent('monthchange', this, date);
11594 if(!this.internalRender){
11595 var main = this.el.dom.firstChild;
11596 var w = main.offsetWidth;
11597 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11598 Roo.fly(main).setWidth(w);
11599 this.internalRender = true;
11600 // opera does not respect the auto grow header center column
11601 // then, after it gets a width opera refuses to recalculate
11602 // without a second pass
11603 if(Roo.isOpera && !this.secondPass){
11604 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11605 this.secondPass = true;
11606 this.update.defer(10, this, [date]);
11613 findCell : function(dt) {
11614 dt = dt.clearTime().getTime();
11616 this.cells.each(function(c){
11617 //Roo.log("check " +c.dateValue + '?=' + dt);
11618 if(c.dateValue == dt){
11628 findCells : function(ev) {
11629 var s = ev.start.clone().clearTime().getTime();
11631 var e= ev.end.clone().clearTime().getTime();
11634 this.cells.each(function(c){
11635 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11637 if(c.dateValue > e){
11640 if(c.dateValue < s){
11649 // findBestRow: function(cells)
11653 // for (var i =0 ; i < cells.length;i++) {
11654 // ret = Math.max(cells[i].rows || 0,ret);
11661 addItem : function(ev)
11663 // look for vertical location slot in
11664 var cells = this.findCells(ev);
11666 // ev.row = this.findBestRow(cells);
11668 // work out the location.
11672 for(var i =0; i < cells.length; i++) {
11680 if (crow.start.getY() == cells[i].getY()) {
11682 crow.end = cells[i];
11698 ev.rendered = false;
11699 // for (var i = 0; i < cells.length;i++) {
11700 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11704 this.calevents.push(ev);
11707 clearEvents: function() {
11709 if(!this.calevents){
11713 Roo.each(this.cells.elements, function(c){
11718 Roo.each(this.calevents, function(e) {
11719 Roo.each(e.els, function(el) {
11720 el.un('mouseenter' ,this.onEventEnter, this);
11721 el.un('mouseleave' ,this.onEventLeave, this);
11726 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11732 renderEvents: function()
11734 // first make sure there is enough space..
11735 this.cells.each(function(c) {
11740 for (var e = 0; e < this.calevents.length; e++) {
11742 var ev = this.calevents[e];
11743 var cells = ev.cells;
11744 var rows = ev.rows;
11746 for(var i = 0; i < cells.length; i++){
11748 var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11750 if(cells.length < 2 && cbox.rows.length > 3){
11751 cbox.more.push(ev);
11755 cbox.rows.push(ev);
11761 this.cells.each(function(c) {
11762 if(c.more.length && c.more.length == 1){
11763 c.rows.push(c.more.pop());
11766 var r = (c.more.length) ? c.rows.length + 1 : c.rows.length;
11767 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, r * 20));
11770 for (var e = 0; e < c.rows.length; e++){
11771 var ev = c.rows[e];
11777 var cells = ev.cells;
11778 var rows = ev.rows;
11780 for(var i = 0; i < rows.length; i++) {
11782 // how many rows should it span..
11785 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11786 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11788 unselectable : "on",
11791 cls: 'fc-event-inner',
11795 // cls: 'fc-event-time',
11796 // html : cells.length > 1 ? '' : ev.time
11800 cls: 'fc-event-title',
11801 html : String.format('{0}', ev.title)
11808 cls: 'ui-resizable-handle ui-resizable-e',
11809 html : '  '
11816 cfg.cls += ' fc-event-start';
11818 if ((i+1) == rows.length) {
11819 cfg.cls += ' fc-event-end';
11822 var ctr = _this.el.select('.fc-event-container',true).first();
11823 var cg = ctr.createChild(cfg);
11825 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11826 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11828 cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11829 cg.setWidth(ebox.right - sbox.x -2);
11831 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11832 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11833 cg.on('click', _this.onEventClick, _this, ev);
11837 ev.rendered = true;
11845 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11846 style : 'position: absolute',
11847 unselectable : "on",
11850 cls: 'fc-event-inner',
11854 cls: 'fc-event-title',
11862 cls: 'ui-resizable-handle ui-resizable-e',
11863 html : '  '
11869 var ctr = _this.el.select('.fc-event-container',true).first();
11870 var cg = ctr.createChild(cfg);
11872 var sbox = c.select('.fc-day-content',true).first().getBox();
11873 var ebox = c.select('.fc-day-content',true).first().getBox();
11875 cg.setXY([sbox.x +2, sbox.y +(c.rows.length * 20)]);
11876 cg.setWidth(ebox.right - sbox.x -2);
11878 cg.on('click', _this.onMoreEventClick, _this, c.more);
11888 onEventEnter: function (e, el,event,d) {
11889 this.fireEvent('evententer', this, el, event);
11892 onEventLeave: function (e, el,event,d) {
11893 this.fireEvent('eventleave', this, el, event);
11896 onEventClick: function (e, el,event,d) {
11897 this.fireEvent('eventclick', this, el, event);
11900 onMonthChange: function () {
11904 onMoreEventClick: function(e, el, more)
11908 this.calpopover.placement = 'right';
11909 this.calpopover.setTitle('More');
11911 this.calpopover.setContent('');
11913 var ctr = this.calpopover.el.select('.popover-content', true).first();
11915 Roo.each(more, function(m){
11917 cls : 'fc-event-hori fc-event-draggable',
11920 var cg = ctr.createChild(cfg);
11922 cg.on('click', _this.onEventClick, _this, m);
11925 this.calpopover.show(el);
11930 onLoad: function ()
11932 this.calevents = [];
11935 if(this.store.getCount() > 0){
11936 this.store.data.each(function(d){
11939 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11940 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11941 time : d.data.start_time,
11942 title : d.data.title,
11943 description : d.data.description,
11944 venue : d.data.venue
11949 this.renderEvents();
11951 if(this.calevents.length && this.loadMask){
11952 this.maskEl.hide();
11956 onBeforeLoad: function()
11958 this.clearEvents();
11960 this.maskEl.show();
11974 * @class Roo.bootstrap.Popover
11975 * @extends Roo.bootstrap.Component
11976 * Bootstrap Popover class
11977 * @cfg {String} html contents of the popover (or false to use children..)
11978 * @cfg {String} title of popover (or false to hide)
11979 * @cfg {String} placement how it is placed
11980 * @cfg {String} trigger click || hover (or false to trigger manually)
11981 * @cfg {String} over what (parent or false to trigger manually.)
11984 * Create a new Popover
11985 * @param {Object} config The config object
11988 Roo.bootstrap.Popover = function(config){
11989 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11992 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11994 title: 'Fill in a title',
11997 placement : 'right',
11998 trigger : 'hover', // hover
12002 can_build_overlaid : false,
12004 getChildContainer : function()
12006 return this.el.select('.popover-content',true).first();
12009 getAutoCreate : function(){
12010 Roo.log('make popover?');
12012 cls : 'popover roo-dynamic',
12013 style: 'display:block',
12019 cls : 'popover-inner',
12023 cls: 'popover-title',
12027 cls : 'popover-content',
12038 setTitle: function(str)
12040 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12042 setContent: function(str)
12044 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12046 // as it get's added to the bottom of the page.
12047 onRender : function(ct, position)
12049 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12051 var cfg = Roo.apply({}, this.getAutoCreate());
12055 cfg.cls += ' ' + this.cls;
12058 cfg.style = this.style;
12060 Roo.log("adding to ")
12061 this.el = Roo.get(document.body).createChild(cfg, position);
12067 initEvents : function()
12069 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12070 this.el.enableDisplayMode('block');
12072 if (this.over === false) {
12075 if (this.triggers === false) {
12078 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12079 var triggers = this.trigger ? this.trigger.split(' ') : [];
12080 Roo.each(triggers, function(trigger) {
12082 if (trigger == 'click') {
12083 on_el.on('click', this.toggle, this);
12084 } else if (trigger != 'manual') {
12085 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12086 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12088 on_el.on(eventIn ,this.enter, this);
12089 on_el.on(eventOut, this.leave, this);
12100 toggle : function () {
12101 this.hoverState == 'in' ? this.leave() : this.enter();
12104 enter : function () {
12107 clearTimeout(this.timeout);
12109 this.hoverState = 'in'
12111 if (!this.delay || !this.delay.show) {
12116 this.timeout = setTimeout(function () {
12117 if (_t.hoverState == 'in') {
12120 }, this.delay.show)
12122 leave : function() {
12123 clearTimeout(this.timeout);
12125 this.hoverState = 'out'
12127 if (!this.delay || !this.delay.hide) {
12132 this.timeout = setTimeout(function () {
12133 if (_t.hoverState == 'out') {
12136 }, this.delay.hide)
12139 show : function (on_el)
12142 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12145 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12146 if (this.html !== false) {
12147 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12149 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12150 if (!this.title.length) {
12151 this.el.select('.popover-title',true).hide();
12154 var placement = typeof this.placement == 'function' ?
12155 this.placement.call(this, this.el, on_el) :
12158 var autoToken = /\s?auto?\s?/i;
12159 var autoPlace = autoToken.test(placement);
12161 placement = placement.replace(autoToken, '') || 'top';
12165 //this.el.setXY([0,0]);
12167 this.el.dom.style.display='block';
12168 this.el.addClass(placement);
12170 //this.el.appendTo(on_el);
12172 var p = this.getPosition();
12173 var box = this.el.getBox();
12178 var align = Roo.bootstrap.Popover.alignment[placement]
12179 this.el.alignTo(on_el, align[0],align[1]);
12180 //var arrow = this.el.select('.arrow',true).first();
12181 //arrow.set(align[2],
12183 this.el.addClass('in');
12184 this.hoverState = null;
12186 if (this.el.hasClass('fade')) {
12193 this.el.setXY([0,0]);
12194 this.el.removeClass('in');
12201 Roo.bootstrap.Popover.alignment = {
12202 'left' : ['r-l', [-10,0], 'right'],
12203 'right' : ['l-r', [10,0], 'left'],
12204 'bottom' : ['t-b', [0,10], 'top'],
12205 'top' : [ 'b-t', [0,-10], 'bottom']
12216 * @class Roo.bootstrap.Progress
12217 * @extends Roo.bootstrap.Component
12218 * Bootstrap Progress class
12219 * @cfg {Boolean} striped striped of the progress bar
12220 * @cfg {Boolean} active animated of the progress bar
12224 * Create a new Progress
12225 * @param {Object} config The config object
12228 Roo.bootstrap.Progress = function(config){
12229 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12232 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12237 getAutoCreate : function(){
12245 cfg.cls += ' progress-striped';
12249 cfg.cls += ' active';
12268 * @class Roo.bootstrap.ProgressBar
12269 * @extends Roo.bootstrap.Component
12270 * Bootstrap ProgressBar class
12271 * @cfg {Number} aria_valuenow aria-value now
12272 * @cfg {Number} aria_valuemin aria-value min
12273 * @cfg {Number} aria_valuemax aria-value max
12274 * @cfg {String} label label for the progress bar
12275 * @cfg {String} panel (success | info | warning | danger )
12276 * @cfg {String} role role of the progress bar
12277 * @cfg {String} sr_only text
12281 * Create a new ProgressBar
12282 * @param {Object} config The config object
12285 Roo.bootstrap.ProgressBar = function(config){
12286 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12289 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12293 aria_valuemax : 100,
12299 getAutoCreate : function()
12304 cls: 'progress-bar',
12305 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12317 cfg.role = this.role;
12320 if(this.aria_valuenow){
12321 cfg['aria-valuenow'] = this.aria_valuenow;
12324 if(this.aria_valuemin){
12325 cfg['aria-valuemin'] = this.aria_valuemin;
12328 if(this.aria_valuemax){
12329 cfg['aria-valuemax'] = this.aria_valuemax;
12332 if(this.label && !this.sr_only){
12333 cfg.html = this.label;
12337 cfg.cls += ' progress-bar-' + this.panel;
12343 update : function(aria_valuenow)
12345 this.aria_valuenow = aria_valuenow;
12347 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12362 * @class Roo.bootstrap.TabPanel
12363 * @extends Roo.bootstrap.Component
12364 * Bootstrap TabPanel class
12365 * @cfg {Boolean} active panel active
12366 * @cfg {String} html panel content
12367 * @cfg {String} tabId tab relate id
12368 * @cfg {String} navId The navbar which triggers show hide
12372 * Create a new TabPanel
12373 * @param {Object} config The config object
12376 Roo.bootstrap.TabPanel = function(config){
12377 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12381 * Fires when the active status changes
12382 * @param {Roo.bootstrap.TabPanel} this
12383 * @param {Boolean} state the new state
12390 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12397 getAutoCreate : function(){
12401 html: this.html || ''
12405 cfg.cls += ' active';
12409 cfg.tabId = this.tabId;
12414 onRender : function(ct, position)
12416 // Roo.log("Call onRender: " + this.xtype);
12418 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12420 if (this.navId && this.tabId) {
12421 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12423 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12425 item.on('changed', function(item, state) {
12426 this.setActive(state);
12432 setActive: function(state)
12434 Roo.log("panel - set active " + this.tabId + "=" + state);
12436 this.active = state;
12438 this.el.removeClass('active');
12440 } else if (!this.el.hasClass('active')) {
12441 this.el.addClass('active');
12443 this.fireEvent('changed', this, state);
12460 * @class Roo.bootstrap.DateField
12461 * @extends Roo.bootstrap.Input
12462 * Bootstrap DateField class
12463 * @cfg {Number} weekStart default 0
12464 * @cfg {Number} weekStart default 0
12465 * @cfg {Number} viewMode default empty, (months|years)
12466 * @cfg {Number} minViewMode default empty, (months|years)
12467 * @cfg {Number} startDate default -Infinity
12468 * @cfg {Number} endDate default Infinity
12469 * @cfg {Boolean} todayHighlight default false
12470 * @cfg {Boolean} todayBtn default false
12471 * @cfg {Boolean} calendarWeeks default false
12472 * @cfg {Object} daysOfWeekDisabled default empty
12474 * @cfg {Boolean} keyboardNavigation default true
12475 * @cfg {String} language default en
12478 * Create a new DateField
12479 * @param {Object} config The config object
12482 Roo.bootstrap.DateField = function(config){
12483 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12487 * Fires when this field show.
12488 * @param {Roo.bootstrap.DateField} this
12489 * @param {Mixed} date The date value
12494 * Fires when this field hide.
12495 * @param {Roo.bootstrap.DateField} this
12496 * @param {Mixed} date The date value
12501 * Fires when select a date.
12502 * @param {Roo.bootstrap.DateField} this
12503 * @param {Mixed} date The date value
12509 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12512 * @cfg {String} format
12513 * The default date format string which can be overriden for localization support. The format must be
12514 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12518 * @cfg {String} altFormats
12519 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12520 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12522 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12530 todayHighlight : false,
12536 keyboardNavigation: true,
12538 calendarWeeks: false,
12540 startDate: -Infinity,
12544 daysOfWeekDisabled: [],
12548 UTCDate: function()
12550 return new Date(Date.UTC.apply(Date, arguments));
12553 UTCToday: function()
12555 var today = new Date();
12556 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12559 getDate: function() {
12560 var d = this.getUTCDate();
12561 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12564 getUTCDate: function() {
12568 setDate: function(d) {
12569 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12572 setUTCDate: function(d) {
12574 this.setValue(this.formatDate(this.date));
12577 onRender: function(ct, position)
12580 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12582 this.language = this.language || 'en';
12583 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12584 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12586 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12587 this.format = this.format || 'm/d/y';
12588 this.isInline = false;
12589 this.isInput = true;
12590 this.component = this.el.select('.add-on', true).first() || false;
12591 this.component = (this.component && this.component.length === 0) ? false : this.component;
12592 this.hasInput = this.component && this.inputEL().length;
12594 if (typeof(this.minViewMode === 'string')) {
12595 switch (this.minViewMode) {
12597 this.minViewMode = 1;
12600 this.minViewMode = 2;
12603 this.minViewMode = 0;
12608 if (typeof(this.viewMode === 'string')) {
12609 switch (this.viewMode) {
12622 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12624 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12626 this.picker().on('mousedown', this.onMousedown, this);
12627 this.picker().on('click', this.onClick, this);
12629 this.picker().addClass('datepicker-dropdown');
12631 this.startViewMode = this.viewMode;
12634 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12635 if(!this.calendarWeeks){
12640 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12641 v.attr('colspan', function(i, val){
12642 return parseInt(val) + 1;
12647 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12649 this.setStartDate(this.startDate);
12650 this.setEndDate(this.endDate);
12652 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12659 if(this.isInline) {
12664 picker : function()
12666 return this.el.select('.datepicker', true).first();
12669 fillDow: function()
12671 var dowCnt = this.weekStart;
12680 if(this.calendarWeeks){
12688 while (dowCnt < this.weekStart + 7) {
12692 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12696 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12699 fillMonths: function()
12702 var months = this.picker().select('>.datepicker-months td', true).first();
12704 months.dom.innerHTML = '';
12710 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12713 months.createChild(month);
12718 update: function(){
12720 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12722 if (this.date < this.startDate) {
12723 this.viewDate = new Date(this.startDate);
12724 } else if (this.date > this.endDate) {
12725 this.viewDate = new Date(this.endDate);
12727 this.viewDate = new Date(this.date);
12734 var d = new Date(this.viewDate),
12735 year = d.getUTCFullYear(),
12736 month = d.getUTCMonth(),
12737 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12738 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12739 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12740 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12741 currentDate = this.date && this.date.valueOf(),
12742 today = this.UTCToday();
12744 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12746 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12748 // this.picker.select('>tfoot th.today').
12749 // .text(dates[this.language].today)
12750 // .toggle(this.todayBtn !== false);
12752 this.updateNavArrows();
12755 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12757 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12759 prevMonth.setUTCDate(day);
12761 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12763 var nextMonth = new Date(prevMonth);
12765 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12767 nextMonth = nextMonth.valueOf();
12769 var fillMonths = false;
12771 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12773 while(prevMonth.valueOf() < nextMonth) {
12776 if (prevMonth.getUTCDay() === this.weekStart) {
12778 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12786 if(this.calendarWeeks){
12787 // ISO 8601: First week contains first thursday.
12788 // ISO also states week starts on Monday, but we can be more abstract here.
12790 // Start of current week: based on weekstart/current date
12791 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12792 // Thursday of this week
12793 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12794 // First Thursday of year, year from thursday
12795 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12796 // Calendar week: ms between thursdays, div ms per day, div 7 days
12797 calWeek = (th - yth) / 864e5 / 7 + 1;
12799 fillMonths.cn.push({
12807 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12809 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12812 if (this.todayHighlight &&
12813 prevMonth.getUTCFullYear() == today.getFullYear() &&
12814 prevMonth.getUTCMonth() == today.getMonth() &&
12815 prevMonth.getUTCDate() == today.getDate()) {
12816 clsName += ' today';
12819 if (currentDate && prevMonth.valueOf() === currentDate) {
12820 clsName += ' active';
12823 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12824 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12825 clsName += ' disabled';
12828 fillMonths.cn.push({
12830 cls: 'day ' + clsName,
12831 html: prevMonth.getDate()
12834 prevMonth.setDate(prevMonth.getDate()+1);
12837 var currentYear = this.date && this.date.getUTCFullYear();
12838 var currentMonth = this.date && this.date.getUTCMonth();
12840 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12842 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12843 v.removeClass('active');
12845 if(currentYear === year && k === currentMonth){
12846 v.addClass('active');
12849 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12850 v.addClass('disabled');
12856 year = parseInt(year/10, 10) * 10;
12858 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12860 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12863 for (var i = -1; i < 11; i++) {
12864 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12866 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12874 showMode: function(dir) {
12876 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12878 Roo.each(this.picker().select('>div',true).elements, function(v){
12879 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12882 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12887 if(this.isInline) return;
12889 this.picker().removeClass(['bottom', 'top']);
12891 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12893 * place to the top of element!
12897 this.picker().addClass('top');
12898 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12903 this.picker().addClass('bottom');
12905 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12908 parseDate : function(value){
12909 if(!value || value instanceof Date){
12912 var v = Date.parseDate(value, this.format);
12913 if (!v && this.useIso) {
12914 v = Date.parseDate(value, 'Y-m-d');
12916 if(!v && this.altFormats){
12917 if(!this.altFormatsArray){
12918 this.altFormatsArray = this.altFormats.split("|");
12920 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12921 v = Date.parseDate(value, this.altFormatsArray[i]);
12927 formatDate : function(date, fmt){
12928 return (!date || !(date instanceof Date)) ?
12929 date : date.dateFormat(fmt || this.format);
12932 onFocus : function()
12934 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12938 onBlur : function()
12940 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12946 this.picker().show();
12950 this.fireEvent('show', this, this.date);
12955 if(this.isInline) return;
12956 this.picker().hide();
12957 this.viewMode = this.startViewMode;
12960 this.fireEvent('hide', this, this.date);
12964 onMousedown: function(e){
12965 e.stopPropagation();
12966 e.preventDefault();
12969 keyup: function(e){
12970 Roo.bootstrap.DateField.superclass.keyup.call(this);
12975 setValue: function(v){
12976 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12978 this.fireEvent('select', this, this.date);
12982 fireKey: function(e){
12983 if (!this.picker().isVisible()){
12984 if (e.keyCode == 27) // allow escape to hide and re-show picker
12988 var dateChanged = false,
12990 newDate, newViewDate;
12994 e.preventDefault();
12998 if (!this.keyboardNavigation) break;
12999 dir = e.keyCode == 37 ? -1 : 1;
13002 newDate = this.moveYear(this.date, dir);
13003 newViewDate = this.moveYear(this.viewDate, dir);
13004 } else if (e.shiftKey){
13005 newDate = this.moveMonth(this.date, dir);
13006 newViewDate = this.moveMonth(this.viewDate, dir);
13008 newDate = new Date(this.date);
13009 newDate.setUTCDate(this.date.getUTCDate() + dir);
13010 newViewDate = new Date(this.viewDate);
13011 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13013 if (this.dateWithinRange(newDate)){
13014 this.date = newDate;
13015 this.viewDate = newViewDate;
13016 this.setValue(this.formatDate(this.date));
13018 e.preventDefault();
13019 dateChanged = true;
13024 if (!this.keyboardNavigation) break;
13025 dir = e.keyCode == 38 ? -1 : 1;
13027 newDate = this.moveYear(this.date, dir);
13028 newViewDate = this.moveYear(this.viewDate, dir);
13029 } else if (e.shiftKey){
13030 newDate = this.moveMonth(this.date, dir);
13031 newViewDate = this.moveMonth(this.viewDate, dir);
13033 newDate = new Date(this.date);
13034 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13035 newViewDate = new Date(this.viewDate);
13036 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13038 if (this.dateWithinRange(newDate)){
13039 this.date = newDate;
13040 this.viewDate = newViewDate;
13041 this.setValue(this.formatDate(this.date));
13043 e.preventDefault();
13044 dateChanged = true;
13048 this.setValue(this.formatDate(this.date));
13050 e.preventDefault();
13053 this.setValue(this.formatDate(this.date));
13060 onClick: function(e) {
13061 e.stopPropagation();
13062 e.preventDefault();
13064 var target = e.getTarget();
13066 if(target.nodeName.toLowerCase() === 'i'){
13067 target = Roo.get(target).dom.parentNode;
13070 var nodeName = target.nodeName;
13071 var className = target.className;
13072 var html = target.innerHTML;
13074 switch(nodeName.toLowerCase()) {
13076 switch(className) {
13082 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13083 switch(this.viewMode){
13085 this.viewDate = this.moveMonth(this.viewDate, dir);
13089 this.viewDate = this.moveYear(this.viewDate, dir);
13095 var date = new Date();
13096 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13098 this.setValue(this.formatDate(this.date));
13104 if (className.indexOf('disabled') === -1) {
13105 this.viewDate.setUTCDate(1);
13106 if (className.indexOf('month') !== -1) {
13107 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13109 var year = parseInt(html, 10) || 0;
13110 this.viewDate.setUTCFullYear(year);
13119 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13120 var day = parseInt(html, 10) || 1;
13121 var year = this.viewDate.getUTCFullYear(),
13122 month = this.viewDate.getUTCMonth();
13124 if (className.indexOf('old') !== -1) {
13131 } else if (className.indexOf('new') !== -1) {
13139 this.date = this.UTCDate(year, month, day,0,0,0,0);
13140 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13142 this.setValue(this.formatDate(this.date));
13149 setStartDate: function(startDate){
13150 this.startDate = startDate || -Infinity;
13151 if (this.startDate !== -Infinity) {
13152 this.startDate = this.parseDate(this.startDate);
13155 this.updateNavArrows();
13158 setEndDate: function(endDate){
13159 this.endDate = endDate || Infinity;
13160 if (this.endDate !== Infinity) {
13161 this.endDate = this.parseDate(this.endDate);
13164 this.updateNavArrows();
13167 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13168 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13169 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13170 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13172 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13173 return parseInt(d, 10);
13176 this.updateNavArrows();
13179 updateNavArrows: function() {
13180 var d = new Date(this.viewDate),
13181 year = d.getUTCFullYear(),
13182 month = d.getUTCMonth();
13184 Roo.each(this.picker().select('.prev', true).elements, function(v){
13186 switch (this.viewMode) {
13189 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13195 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13202 Roo.each(this.picker().select('.next', true).elements, function(v){
13204 switch (this.viewMode) {
13207 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13213 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13221 moveMonth: function(date, dir){
13222 if (!dir) return date;
13223 var new_date = new Date(date.valueOf()),
13224 day = new_date.getUTCDate(),
13225 month = new_date.getUTCMonth(),
13226 mag = Math.abs(dir),
13228 dir = dir > 0 ? 1 : -1;
13231 // If going back one month, make sure month is not current month
13232 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13234 return new_date.getUTCMonth() == month;
13236 // If going forward one month, make sure month is as expected
13237 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13239 return new_date.getUTCMonth() != new_month;
13241 new_month = month + dir;
13242 new_date.setUTCMonth(new_month);
13243 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13244 if (new_month < 0 || new_month > 11)
13245 new_month = (new_month + 12) % 12;
13247 // For magnitudes >1, move one month at a time...
13248 for (var i=0; i<mag; i++)
13249 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13250 new_date = this.moveMonth(new_date, dir);
13251 // ...then reset the day, keeping it in the new month
13252 new_month = new_date.getUTCMonth();
13253 new_date.setUTCDate(day);
13255 return new_month != new_date.getUTCMonth();
13258 // Common date-resetting loop -- if date is beyond end of month, make it
13261 new_date.setUTCDate(--day);
13262 new_date.setUTCMonth(new_month);
13267 moveYear: function(date, dir){
13268 return this.moveMonth(date, dir*12);
13271 dateWithinRange: function(date){
13272 return date >= this.startDate && date <= this.endDate;
13276 remove: function() {
13277 this.picker().remove();
13282 Roo.apply(Roo.bootstrap.DateField, {
13293 html: '<i class="icon-arrow-left"/>'
13303 html: '<i class="icon-arrow-right"/>'
13345 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13346 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13347 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13348 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13349 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13362 navFnc: 'FullYear',
13367 navFnc: 'FullYear',
13372 Roo.apply(Roo.bootstrap.DateField, {
13376 cls: 'datepicker dropdown-menu',
13380 cls: 'datepicker-days',
13384 cls: 'table-condensed',
13386 Roo.bootstrap.DateField.head,
13390 Roo.bootstrap.DateField.footer
13397 cls: 'datepicker-months',
13401 cls: 'table-condensed',
13403 Roo.bootstrap.DateField.head,
13404 Roo.bootstrap.DateField.content,
13405 Roo.bootstrap.DateField.footer
13412 cls: 'datepicker-years',
13416 cls: 'table-condensed',
13418 Roo.bootstrap.DateField.head,
13419 Roo.bootstrap.DateField.content,
13420 Roo.bootstrap.DateField.footer
13439 * @class Roo.bootstrap.TimeField
13440 * @extends Roo.bootstrap.Input
13441 * Bootstrap DateField class
13445 * Create a new TimeField
13446 * @param {Object} config The config object
13449 Roo.bootstrap.TimeField = function(config){
13450 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13454 * Fires when this field show.
13455 * @param {Roo.bootstrap.DateField} this
13456 * @param {Mixed} date The date value
13461 * Fires when this field hide.
13462 * @param {Roo.bootstrap.DateField} this
13463 * @param {Mixed} date The date value
13468 * Fires when select a date.
13469 * @param {Roo.bootstrap.DateField} this
13470 * @param {Mixed} date The date value
13476 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13479 * @cfg {String} format
13480 * The default time format string which can be overriden for localization support. The format must be
13481 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13485 onRender: function(ct, position)
13488 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13490 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13492 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13494 this.pop = this.picker().select('>.datepicker-time',true).first();
13495 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13497 this.picker().on('mousedown', this.onMousedown, this);
13498 this.picker().on('click', this.onClick, this);
13500 this.picker().addClass('datepicker-dropdown');
13505 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13506 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13507 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13508 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13509 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13510 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13514 fireKey: function(e){
13515 if (!this.picker().isVisible()){
13516 if (e.keyCode == 27) // allow escape to hide and re-show picker
13521 e.preventDefault();
13529 this.onTogglePeriod();
13532 this.onIncrementMinutes();
13535 this.onDecrementMinutes();
13544 onClick: function(e) {
13545 e.stopPropagation();
13546 e.preventDefault();
13549 picker : function()
13551 return this.el.select('.datepicker', true).first();
13554 fillTime: function()
13556 var time = this.pop.select('tbody', true).first();
13558 time.dom.innerHTML = '';
13573 cls: 'hours-up glyphicon glyphicon-chevron-up'
13593 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13614 cls: 'timepicker-hour',
13629 cls: 'timepicker-minute',
13644 cls: 'btn btn-primary period',
13666 cls: 'hours-down glyphicon glyphicon-chevron-down'
13686 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13704 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13711 var hours = this.time.getHours();
13712 var minutes = this.time.getMinutes();
13725 hours = hours - 12;
13729 hours = '0' + hours;
13733 minutes = '0' + minutes;
13736 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13737 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13738 this.pop.select('button', true).first().dom.innerHTML = period;
13744 this.picker().removeClass(['bottom', 'top']);
13746 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13748 * place to the top of element!
13752 this.picker().addClass('top');
13753 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13758 this.picker().addClass('bottom');
13760 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13763 onFocus : function()
13765 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13769 onBlur : function()
13771 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13777 this.picker().show();
13782 this.fireEvent('show', this, this.date);
13787 this.picker().hide();
13790 this.fireEvent('hide', this, this.date);
13793 setTime : function()
13796 this.setValue(this.time.format(this.format));
13798 this.fireEvent('select', this, this.date);
13803 onMousedown: function(e){
13804 e.stopPropagation();
13805 e.preventDefault();
13808 onIncrementHours: function()
13810 Roo.log('onIncrementHours');
13811 this.time = this.time.add(Date.HOUR, 1);
13816 onDecrementHours: function()
13818 Roo.log('onDecrementHours');
13819 this.time = this.time.add(Date.HOUR, -1);
13823 onIncrementMinutes: function()
13825 Roo.log('onIncrementMinutes');
13826 this.time = this.time.add(Date.MINUTE, 1);
13830 onDecrementMinutes: function()
13832 Roo.log('onDecrementMinutes');
13833 this.time = this.time.add(Date.MINUTE, -1);
13837 onTogglePeriod: function()
13839 Roo.log('onTogglePeriod');
13840 this.time = this.time.add(Date.HOUR, 12);
13847 Roo.apply(Roo.bootstrap.TimeField, {
13877 cls: 'btn btn-info ok',
13889 Roo.apply(Roo.bootstrap.TimeField, {
13893 cls: 'datepicker dropdown-menu',
13897 cls: 'datepicker-time',
13901 cls: 'table-condensed',
13903 Roo.bootstrap.TimeField.content,
13904 Roo.bootstrap.TimeField.footer
13923 * @class Roo.bootstrap.CheckBox
13924 * @extends Roo.bootstrap.Input
13925 * Bootstrap CheckBox class
13927 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13928 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13929 * @cfg {String} boxLabel The text that appears beside the checkbox
13930 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13931 * @cfg {Boolean} checked initnal the element
13935 * Create a new CheckBox
13936 * @param {Object} config The config object
13939 Roo.bootstrap.CheckBox = function(config){
13940 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13945 * Fires when the element is checked or unchecked.
13946 * @param {Roo.bootstrap.CheckBox} this This input
13947 * @param {Boolean} checked The new checked value
13953 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13955 inputType: 'checkbox',
13962 getAutoCreate : function()
13964 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13970 cfg.cls = 'form-group checkbox' //input-group
13978 type : this.inputType,
13979 value : (!this.checked) ? this.valueOff : this.inputValue,
13980 cls : 'roo-checkbox', //'form-box',
13981 placeholder : this.placeholder || ''
13985 if (this.weight) { // Validity check?
13986 cfg.cls += " checkbox-" + this.weight;
13989 if (this.disabled) {
13990 input.disabled=true;
13994 input.checked = this.checked;
13998 input.name = this.name;
14002 input.cls += ' input-' + this.size;
14006 ['xs','sm','md','lg'].map(function(size){
14007 if (settings[size]) {
14008 cfg.cls += ' col-' + size + '-' + settings[size];
14014 var inputblock = input;
14019 if (this.before || this.after) {
14022 cls : 'input-group',
14026 inputblock.cn.push({
14028 cls : 'input-group-addon',
14032 inputblock.cn.push(input);
14034 inputblock.cn.push({
14036 cls : 'input-group-addon',
14043 if (align ==='left' && this.fieldLabel.length) {
14044 Roo.log("left and has label");
14050 cls : 'control-label col-md-' + this.labelWidth,
14051 html : this.fieldLabel
14055 cls : "col-md-" + (12 - this.labelWidth),
14062 } else if ( this.fieldLabel.length) {
14067 tag: this.boxLabel ? 'span' : 'label',
14069 cls: 'control-label box-input-label',
14070 //cls : 'input-group-addon',
14071 html : this.fieldLabel
14081 Roo.log(" no label && no align");
14082 cfg.cn = [ inputblock ] ;
14091 html: this.boxLabel
14103 * return the real input element.
14105 inputEl: function ()
14107 return this.el.select('input.roo-checkbox',true).first();
14112 return this.el.select('label.control-label',true).first();
14115 initEvents : function()
14117 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14119 this.inputEl().on('click', this.onClick, this);
14123 onClick : function()
14125 this.setChecked(!this.checked);
14128 setChecked : function(state,suppressEvent)
14130 this.checked = state;
14132 this.inputEl().dom.checked = state;
14134 if(suppressEvent !== true){
14135 this.fireEvent('check', this, state);
14138 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14142 setValue : function(v,suppressEvent)
14144 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14158 * @class Roo.bootstrap.Radio
14159 * @extends Roo.bootstrap.CheckBox
14160 * Bootstrap Radio class
14163 * Create a new Radio
14164 * @param {Object} config The config object
14167 Roo.bootstrap.Radio = function(config){
14168 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14172 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14174 inputType: 'radio',
14178 getAutoCreate : function()
14180 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14186 cfg.cls = 'form-group radio' //input-group
14191 type : this.inputType,
14192 value : (!this.checked) ? this.valueOff : this.inputValue,
14194 placeholder : this.placeholder || ''
14197 if (this.weight) { // Validity check?
14198 cfg.cls += " radio-" + this.weight;
14200 if (this.disabled) {
14201 input.disabled=true;
14205 input.checked = this.checked;
14209 input.name = this.name;
14213 input.cls += ' input-' + this.size;
14217 ['xs','sm','md','lg'].map(function(size){
14218 if (settings[size]) {
14219 cfg.cls += ' col-' + size + '-' + settings[size];
14223 var inputblock = input;
14225 if (this.before || this.after) {
14228 cls : 'input-group',
14232 inputblock.cn.push({
14234 cls : 'input-group-addon',
14238 inputblock.cn.push(input);
14240 inputblock.cn.push({
14242 cls : 'input-group-addon',
14249 if (align ==='left' && this.fieldLabel.length) {
14250 Roo.log("left and has label");
14256 cls : 'control-label col-md-' + this.labelWidth,
14257 html : this.fieldLabel
14261 cls : "col-md-" + (12 - this.labelWidth),
14268 } else if ( this.fieldLabel.length) {
14275 cls: 'control-label box-input-label',
14276 //cls : 'input-group-addon',
14277 html : this.fieldLabel
14287 Roo.log(" no label && no align");
14302 html: this.boxLabel
14309 inputEl: function ()
14311 return this.el.select('input.roo-radio',true).first();
14313 onClick : function()
14315 this.setChecked(true);
14318 setChecked : function(state,suppressEvent)
14321 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14322 v.dom.checked = false;
14326 this.checked = state;
14327 this.inputEl().dom.checked = state;
14329 if(suppressEvent !== true){
14330 this.fireEvent('check', this, state);
14333 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14337 getGroupValue : function()
14340 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14341 if(v.dom.checked == true){
14342 value = v.dom.value;
14350 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14351 * @return {Mixed} value The field value
14353 getValue : function(){
14354 return this.getGroupValue();
14360 //<script type="text/javascript">
14363 * Based Ext JS Library 1.1.1
14364 * Copyright(c) 2006-2007, Ext JS, LLC.
14370 * @class Roo.HtmlEditorCore
14371 * @extends Roo.Component
14372 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14374 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14377 Roo.HtmlEditorCore = function(config){
14380 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14383 * @event initialize
14384 * Fires when the editor is fully initialized (including the iframe)
14385 * @param {Roo.HtmlEditorCore} this
14390 * Fires when the editor is first receives the focus. Any insertion must wait
14391 * until after this event.
14392 * @param {Roo.HtmlEditorCore} this
14396 * @event beforesync
14397 * Fires before the textarea is updated with content from the editor iframe. Return false
14398 * to cancel the sync.
14399 * @param {Roo.HtmlEditorCore} this
14400 * @param {String} html
14404 * @event beforepush
14405 * Fires before the iframe editor is updated with content from the textarea. Return false
14406 * to cancel the push.
14407 * @param {Roo.HtmlEditorCore} this
14408 * @param {String} html
14413 * Fires when the textarea is updated with content from the editor iframe.
14414 * @param {Roo.HtmlEditorCore} this
14415 * @param {String} html
14420 * Fires when the iframe editor is updated with content from the textarea.
14421 * @param {Roo.HtmlEditorCore} this
14422 * @param {String} html
14427 * @event editorevent
14428 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14429 * @param {Roo.HtmlEditorCore} this
14437 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14441 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14447 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14452 * @cfg {Number} height (in pixels)
14456 * @cfg {Number} width (in pixels)
14461 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14464 stylesheets: false,
14469 // private properties
14470 validationEvent : false,
14472 initialized : false,
14474 sourceEditMode : false,
14475 onFocus : Roo.emptyFn,
14477 hideMode:'offsets',
14485 * Protected method that will not generally be called directly. It
14486 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14487 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14489 getDocMarkup : function(){
14492 Roo.log(this.stylesheets);
14494 // inherit styels from page...??
14495 if (this.stylesheets === false) {
14497 Roo.get(document.head).select('style').each(function(node) {
14498 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14501 Roo.get(document.head).select('link').each(function(node) {
14502 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14505 } else if (!this.stylesheets.length) {
14507 st = '<style type="text/css">' +
14508 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14511 Roo.each(this.stylesheets, function(s) {
14512 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14517 st += '<style type="text/css">' +
14518 'IMG { cursor: pointer } ' +
14522 return '<html><head>' + st +
14523 //<style type="text/css">' +
14524 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14526 ' </head><body class="roo-htmleditor-body"></body></html>';
14530 onRender : function(ct, position)
14533 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14534 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14537 this.el.dom.style.border = '0 none';
14538 this.el.dom.setAttribute('tabIndex', -1);
14539 this.el.addClass('x-hidden hide');
14543 if(Roo.isIE){ // fix IE 1px bogus margin
14544 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14548 this.frameId = Roo.id();
14552 var iframe = this.owner.wrap.createChild({
14554 cls: 'form-control', // bootstrap..
14556 name: this.frameId,
14557 frameBorder : 'no',
14558 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14563 this.iframe = iframe.dom;
14565 this.assignDocWin();
14567 this.doc.designMode = 'on';
14570 this.doc.write(this.getDocMarkup());
14574 var task = { // must defer to wait for browser to be ready
14576 //console.log("run task?" + this.doc.readyState);
14577 this.assignDocWin();
14578 if(this.doc.body || this.doc.readyState == 'complete'){
14580 this.doc.designMode="on";
14584 Roo.TaskMgr.stop(task);
14585 this.initEditor.defer(10, this);
14592 Roo.TaskMgr.start(task);
14599 onResize : function(w, h)
14601 Roo.log('resize: ' +w + ',' + h );
14602 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14606 if(typeof w == 'number'){
14608 this.iframe.style.width = w + 'px';
14610 if(typeof h == 'number'){
14612 this.iframe.style.height = h + 'px';
14614 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14621 * Toggles the editor between standard and source edit mode.
14622 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14624 toggleSourceEdit : function(sourceEditMode){
14626 this.sourceEditMode = sourceEditMode === true;
14628 if(this.sourceEditMode){
14630 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14633 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14634 //this.iframe.className = '';
14637 //this.setSize(this.owner.wrap.getSize());
14638 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14645 * Protected method that will not generally be called directly. If you need/want
14646 * custom HTML cleanup, this is the method you should override.
14647 * @param {String} html The HTML to be cleaned
14648 * return {String} The cleaned HTML
14650 cleanHtml : function(html){
14651 html = String(html);
14652 if(html.length > 5){
14653 if(Roo.isSafari){ // strip safari nonsense
14654 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14657 if(html == ' '){
14664 * HTML Editor -> Textarea
14665 * Protected method that will not generally be called directly. Syncs the contents
14666 * of the editor iframe with the textarea.
14668 syncValue : function(){
14669 if(this.initialized){
14670 var bd = (this.doc.body || this.doc.documentElement);
14671 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14672 var html = bd.innerHTML;
14674 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14675 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14677 html = '<div style="'+m[0]+'">' + html + '</div>';
14680 html = this.cleanHtml(html);
14681 // fix up the special chars.. normaly like back quotes in word...
14682 // however we do not want to do this with chinese..
14683 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14684 var cc = b.charCodeAt();
14686 (cc >= 0x4E00 && cc < 0xA000 ) ||
14687 (cc >= 0x3400 && cc < 0x4E00 ) ||
14688 (cc >= 0xf900 && cc < 0xfb00 )
14694 if(this.owner.fireEvent('beforesync', this, html) !== false){
14695 this.el.dom.value = html;
14696 this.owner.fireEvent('sync', this, html);
14702 * Protected method that will not generally be called directly. Pushes the value of the textarea
14703 * into the iframe editor.
14705 pushValue : function(){
14706 if(this.initialized){
14707 var v = this.el.dom.value.trim();
14709 // if(v.length < 1){
14713 if(this.owner.fireEvent('beforepush', this, v) !== false){
14714 var d = (this.doc.body || this.doc.documentElement);
14716 this.cleanUpPaste();
14717 this.el.dom.value = d.innerHTML;
14718 this.owner.fireEvent('push', this, v);
14724 deferFocus : function(){
14725 this.focus.defer(10, this);
14729 focus : function(){
14730 if(this.win && !this.sourceEditMode){
14737 assignDocWin: function()
14739 var iframe = this.iframe;
14742 this.doc = iframe.contentWindow.document;
14743 this.win = iframe.contentWindow;
14745 if (!Roo.get(this.frameId)) {
14748 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14749 this.win = Roo.get(this.frameId).dom.contentWindow;
14754 initEditor : function(){
14755 //console.log("INIT EDITOR");
14756 this.assignDocWin();
14760 this.doc.designMode="on";
14762 this.doc.write(this.getDocMarkup());
14765 var dbody = (this.doc.body || this.doc.documentElement);
14766 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14767 // this copies styles from the containing element into thsi one..
14768 // not sure why we need all of this..
14769 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14770 ss['background-attachment'] = 'fixed'; // w3c
14771 dbody.bgProperties = 'fixed'; // ie
14772 Roo.DomHelper.applyStyles(dbody, ss);
14773 Roo.EventManager.on(this.doc, {
14774 //'mousedown': this.onEditorEvent,
14775 'mouseup': this.onEditorEvent,
14776 'dblclick': this.onEditorEvent,
14777 'click': this.onEditorEvent,
14778 'keyup': this.onEditorEvent,
14783 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14785 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14786 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14788 this.initialized = true;
14790 this.owner.fireEvent('initialize', this);
14795 onDestroy : function(){
14801 //for (var i =0; i < this.toolbars.length;i++) {
14802 // // fixme - ask toolbars for heights?
14803 // this.toolbars[i].onDestroy();
14806 //this.wrap.dom.innerHTML = '';
14807 //this.wrap.remove();
14812 onFirstFocus : function(){
14814 this.assignDocWin();
14817 this.activated = true;
14820 if(Roo.isGecko){ // prevent silly gecko errors
14822 var s = this.win.getSelection();
14823 if(!s.focusNode || s.focusNode.nodeType != 3){
14824 var r = s.getRangeAt(0);
14825 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14830 this.execCmd('useCSS', true);
14831 this.execCmd('styleWithCSS', false);
14834 this.owner.fireEvent('activate', this);
14838 adjustFont: function(btn){
14839 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14840 //if(Roo.isSafari){ // safari
14843 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14844 if(Roo.isSafari){ // safari
14845 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14846 v = (v < 10) ? 10 : v;
14847 v = (v > 48) ? 48 : v;
14848 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14853 v = Math.max(1, v+adjust);
14855 this.execCmd('FontSize', v );
14858 onEditorEvent : function(e){
14859 this.owner.fireEvent('editorevent', this, e);
14860 // this.updateToolbar();
14861 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14864 insertTag : function(tg)
14866 // could be a bit smarter... -> wrap the current selected tRoo..
14867 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14869 range = this.createRange(this.getSelection());
14870 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14871 wrappingNode.appendChild(range.extractContents());
14872 range.insertNode(wrappingNode);
14879 this.execCmd("formatblock", tg);
14883 insertText : function(txt)
14887 var range = this.createRange();
14888 range.deleteContents();
14889 //alert(Sender.getAttribute('label'));
14891 range.insertNode(this.doc.createTextNode(txt));
14897 * Executes a Midas editor command on the editor document and performs necessary focus and
14898 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14899 * @param {String} cmd The Midas command
14900 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14902 relayCmd : function(cmd, value){
14904 this.execCmd(cmd, value);
14905 this.owner.fireEvent('editorevent', this);
14906 //this.updateToolbar();
14907 this.owner.deferFocus();
14911 * Executes a Midas editor command directly on the editor document.
14912 * For visual commands, you should use {@link #relayCmd} instead.
14913 * <b>This should only be called after the editor is initialized.</b>
14914 * @param {String} cmd The Midas command
14915 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14917 execCmd : function(cmd, value){
14918 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14925 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14927 * @param {String} text | dom node..
14929 insertAtCursor : function(text)
14934 if(!this.activated){
14940 var r = this.doc.selection.createRange();
14951 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14955 // from jquery ui (MIT licenced)
14957 var win = this.win;
14959 if (win.getSelection && win.getSelection().getRangeAt) {
14960 range = win.getSelection().getRangeAt(0);
14961 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14962 range.insertNode(node);
14963 } else if (win.document.selection && win.document.selection.createRange) {
14964 // no firefox support
14965 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14966 win.document.selection.createRange().pasteHTML(txt);
14968 // no firefox support
14969 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14970 this.execCmd('InsertHTML', txt);
14979 mozKeyPress : function(e){
14981 var c = e.getCharCode(), cmd;
14984 c = String.fromCharCode(c).toLowerCase();
14998 this.cleanUpPaste.defer(100, this);
15006 e.preventDefault();
15014 fixKeys : function(){ // load time branching for fastest keydown performance
15016 return function(e){
15017 var k = e.getKey(), r;
15020 r = this.doc.selection.createRange();
15023 r.pasteHTML('    ');
15030 r = this.doc.selection.createRange();
15032 var target = r.parentElement();
15033 if(!target || target.tagName.toLowerCase() != 'li'){
15035 r.pasteHTML('<br />');
15041 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15042 this.cleanUpPaste.defer(100, this);
15048 }else if(Roo.isOpera){
15049 return function(e){
15050 var k = e.getKey();
15054 this.execCmd('InsertHTML','    ');
15057 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15058 this.cleanUpPaste.defer(100, this);
15063 }else if(Roo.isSafari){
15064 return function(e){
15065 var k = e.getKey();
15069 this.execCmd('InsertText','\t');
15073 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15074 this.cleanUpPaste.defer(100, this);
15082 getAllAncestors: function()
15084 var p = this.getSelectedNode();
15087 a.push(p); // push blank onto stack..
15088 p = this.getParentElement();
15092 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15096 a.push(this.doc.body);
15100 lastSelNode : false,
15103 getSelection : function()
15105 this.assignDocWin();
15106 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15109 getSelectedNode: function()
15111 // this may only work on Gecko!!!
15113 // should we cache this!!!!
15118 var range = this.createRange(this.getSelection()).cloneRange();
15121 var parent = range.parentElement();
15123 var testRange = range.duplicate();
15124 testRange.moveToElementText(parent);
15125 if (testRange.inRange(range)) {
15128 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15131 parent = parent.parentElement;
15136 // is ancestor a text element.
15137 var ac = range.commonAncestorContainer;
15138 if (ac.nodeType == 3) {
15139 ac = ac.parentNode;
15142 var ar = ac.childNodes;
15145 var other_nodes = [];
15146 var has_other_nodes = false;
15147 for (var i=0;i<ar.length;i++) {
15148 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15151 // fullly contained node.
15153 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15158 // probably selected..
15159 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15160 other_nodes.push(ar[i]);
15164 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15169 has_other_nodes = true;
15171 if (!nodes.length && other_nodes.length) {
15172 nodes= other_nodes;
15174 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15180 createRange: function(sel)
15182 // this has strange effects when using with
15183 // top toolbar - not sure if it's a great idea.
15184 //this.editor.contentWindow.focus();
15185 if (typeof sel != "undefined") {
15187 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15189 return this.doc.createRange();
15192 return this.doc.createRange();
15195 getParentElement: function()
15198 this.assignDocWin();
15199 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15201 var range = this.createRange(sel);
15204 var p = range.commonAncestorContainer;
15205 while (p.nodeType == 3) { // text node
15216 * Range intersection.. the hard stuff...
15220 * [ -- selected range --- ]
15224 * if end is before start or hits it. fail.
15225 * if start is after end or hits it fail.
15227 * if either hits (but other is outside. - then it's not
15233 // @see http://www.thismuchiknow.co.uk/?p=64.
15234 rangeIntersectsNode : function(range, node)
15236 var nodeRange = node.ownerDocument.createRange();
15238 nodeRange.selectNode(node);
15240 nodeRange.selectNodeContents(node);
15243 var rangeStartRange = range.cloneRange();
15244 rangeStartRange.collapse(true);
15246 var rangeEndRange = range.cloneRange();
15247 rangeEndRange.collapse(false);
15249 var nodeStartRange = nodeRange.cloneRange();
15250 nodeStartRange.collapse(true);
15252 var nodeEndRange = nodeRange.cloneRange();
15253 nodeEndRange.collapse(false);
15255 return rangeStartRange.compareBoundaryPoints(
15256 Range.START_TO_START, nodeEndRange) == -1 &&
15257 rangeEndRange.compareBoundaryPoints(
15258 Range.START_TO_START, nodeStartRange) == 1;
15262 rangeCompareNode : function(range, node)
15264 var nodeRange = node.ownerDocument.createRange();
15266 nodeRange.selectNode(node);
15268 nodeRange.selectNodeContents(node);
15272 range.collapse(true);
15274 nodeRange.collapse(true);
15276 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15277 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15279 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15281 var nodeIsBefore = ss == 1;
15282 var nodeIsAfter = ee == -1;
15284 if (nodeIsBefore && nodeIsAfter)
15286 if (!nodeIsBefore && nodeIsAfter)
15287 return 1; //right trailed.
15289 if (nodeIsBefore && !nodeIsAfter)
15290 return 2; // left trailed.
15295 // private? - in a new class?
15296 cleanUpPaste : function()
15298 // cleans up the whole document..
15299 Roo.log('cleanuppaste');
15301 this.cleanUpChildren(this.doc.body);
15302 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15303 if (clean != this.doc.body.innerHTML) {
15304 this.doc.body.innerHTML = clean;
15309 cleanWordChars : function(input) {// change the chars to hex code
15310 var he = Roo.HtmlEditorCore;
15312 var output = input;
15313 Roo.each(he.swapCodes, function(sw) {
15314 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15316 output = output.replace(swapper, sw[1]);
15323 cleanUpChildren : function (n)
15325 if (!n.childNodes.length) {
15328 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15329 this.cleanUpChild(n.childNodes[i]);
15336 cleanUpChild : function (node)
15339 //console.log(node);
15340 if (node.nodeName == "#text") {
15341 // clean up silly Windows -- stuff?
15344 if (node.nodeName == "#comment") {
15345 node.parentNode.removeChild(node);
15346 // clean up silly Windows -- stuff?
15350 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15352 node.parentNode.removeChild(node);
15357 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15359 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15360 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15362 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15363 // remove_keep_children = true;
15366 if (remove_keep_children) {
15367 this.cleanUpChildren(node);
15368 // inserts everything just before this node...
15369 while (node.childNodes.length) {
15370 var cn = node.childNodes[0];
15371 node.removeChild(cn);
15372 node.parentNode.insertBefore(cn, node);
15374 node.parentNode.removeChild(node);
15378 if (!node.attributes || !node.attributes.length) {
15379 this.cleanUpChildren(node);
15383 function cleanAttr(n,v)
15386 if (v.match(/^\./) || v.match(/^\//)) {
15389 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15392 if (v.match(/^#/)) {
15395 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15396 node.removeAttribute(n);
15400 function cleanStyle(n,v)
15402 if (v.match(/expression/)) { //XSS?? should we even bother..
15403 node.removeAttribute(n);
15406 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15407 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15410 var parts = v.split(/;/);
15413 Roo.each(parts, function(p) {
15414 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15418 var l = p.split(':').shift().replace(/\s+/g,'');
15419 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15421 if ( cblack.indexOf(l) > -1) {
15422 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15423 //node.removeAttribute(n);
15427 // only allow 'c whitelisted system attributes'
15428 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15429 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15430 //node.removeAttribute(n);
15440 if (clean.length) {
15441 node.setAttribute(n, clean.join(';'));
15443 node.removeAttribute(n);
15449 for (var i = node.attributes.length-1; i > -1 ; i--) {
15450 var a = node.attributes[i];
15453 if (a.name.toLowerCase().substr(0,2)=='on') {
15454 node.removeAttribute(a.name);
15457 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15458 node.removeAttribute(a.name);
15461 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15462 cleanAttr(a.name,a.value); // fixme..
15465 if (a.name == 'style') {
15466 cleanStyle(a.name,a.value);
15469 /// clean up MS crap..
15470 // tecnically this should be a list of valid class'es..
15473 if (a.name == 'class') {
15474 if (a.value.match(/^Mso/)) {
15475 node.className = '';
15478 if (a.value.match(/body/)) {
15479 node.className = '';
15490 this.cleanUpChildren(node);
15495 * Clean up MS wordisms...
15497 cleanWord : function(node)
15500 var cleanWordChildren = function()
15502 if (!node.childNodes.length) {
15505 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15506 _t.cleanWord(node.childNodes[i]);
15512 this.cleanWord(this.doc.body);
15515 if (node.nodeName == "#text") {
15516 // clean up silly Windows -- stuff?
15519 if (node.nodeName == "#comment") {
15520 node.parentNode.removeChild(node);
15521 // clean up silly Windows -- stuff?
15525 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15526 node.parentNode.removeChild(node);
15530 // remove - but keep children..
15531 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15532 while (node.childNodes.length) {
15533 var cn = node.childNodes[0];
15534 node.removeChild(cn);
15535 node.parentNode.insertBefore(cn, node);
15537 node.parentNode.removeChild(node);
15538 cleanWordChildren();
15542 if (node.className.length) {
15544 var cn = node.className.split(/\W+/);
15546 Roo.each(cn, function(cls) {
15547 if (cls.match(/Mso[a-zA-Z]+/)) {
15552 node.className = cna.length ? cna.join(' ') : '';
15554 node.removeAttribute("class");
15558 if (node.hasAttribute("lang")) {
15559 node.removeAttribute("lang");
15562 if (node.hasAttribute("style")) {
15564 var styles = node.getAttribute("style").split(";");
15566 Roo.each(styles, function(s) {
15567 if (!s.match(/:/)) {
15570 var kv = s.split(":");
15571 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15574 // what ever is left... we allow.
15577 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15578 if (!nstyle.length) {
15579 node.removeAttribute('style');
15583 cleanWordChildren();
15587 domToHTML : function(currentElement, depth, nopadtext) {
15589 depth = depth || 0;
15590 nopadtext = nopadtext || false;
15592 if (!currentElement) {
15593 return this.domToHTML(this.doc.body);
15596 //Roo.log(currentElement);
15598 var allText = false;
15599 var nodeName = currentElement.nodeName;
15600 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15602 if (nodeName == '#text') {
15603 return currentElement.nodeValue;
15608 if (nodeName != 'BODY') {
15611 // Prints the node tagName, such as <A>, <IMG>, etc
15614 for(i = 0; i < currentElement.attributes.length;i++) {
15616 var aname = currentElement.attributes.item(i).name;
15617 if (!currentElement.attributes.item(i).value.length) {
15620 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15623 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15632 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15635 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15640 // Traverse the tree
15642 var currentElementChild = currentElement.childNodes.item(i);
15643 var allText = true;
15644 var innerHTML = '';
15646 while (currentElementChild) {
15647 // Formatting code (indent the tree so it looks nice on the screen)
15648 var nopad = nopadtext;
15649 if (lastnode == 'SPAN') {
15653 if (currentElementChild.nodeName == '#text') {
15654 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15655 if (!nopad && toadd.length > 80) {
15656 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15658 innerHTML += toadd;
15661 currentElementChild = currentElement.childNodes.item(i);
15667 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15669 // Recursively traverse the tree structure of the child node
15670 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15671 lastnode = currentElementChild.nodeName;
15673 currentElementChild=currentElement.childNodes.item(i);
15679 // The remaining code is mostly for formatting the tree
15680 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15685 ret+= "</"+tagName+">";
15691 // hide stuff that is not compatible
15705 * @event specialkey
15709 * @cfg {String} fieldClass @hide
15712 * @cfg {String} focusClass @hide
15715 * @cfg {String} autoCreate @hide
15718 * @cfg {String} inputType @hide
15721 * @cfg {String} invalidClass @hide
15724 * @cfg {String} invalidText @hide
15727 * @cfg {String} msgFx @hide
15730 * @cfg {String} validateOnBlur @hide
15734 Roo.HtmlEditorCore.white = [
15735 'area', 'br', 'img', 'input', 'hr', 'wbr',
15737 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15738 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15739 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15740 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15741 'table', 'ul', 'xmp',
15743 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15746 'dir', 'menu', 'ol', 'ul', 'dl',
15752 Roo.HtmlEditorCore.black = [
15753 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15755 'base', 'basefont', 'bgsound', 'blink', 'body',
15756 'frame', 'frameset', 'head', 'html', 'ilayer',
15757 'iframe', 'layer', 'link', 'meta', 'object',
15758 'script', 'style' ,'title', 'xml' // clean later..
15760 Roo.HtmlEditorCore.clean = [
15761 'script', 'style', 'title', 'xml'
15763 Roo.HtmlEditorCore.remove = [
15768 Roo.HtmlEditorCore.ablack = [
15772 Roo.HtmlEditorCore.aclean = [
15773 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15777 Roo.HtmlEditorCore.pwhite= [
15778 'http', 'https', 'mailto'
15781 // white listed style attributes.
15782 Roo.HtmlEditorCore.cwhite= [
15783 // 'text-align', /// default is to allow most things..
15789 // black listed style attributes.
15790 Roo.HtmlEditorCore.cblack= [
15791 // 'font-size' -- this can be set by the project
15795 Roo.HtmlEditorCore.swapCodes =[
15814 * @class Roo.bootstrap.HtmlEditor
15815 * @extends Roo.bootstrap.TextArea
15816 * Bootstrap HtmlEditor class
15819 * Create a new HtmlEditor
15820 * @param {Object} config The config object
15823 Roo.bootstrap.HtmlEditor = function(config){
15824 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15825 if (!this.toolbars) {
15826 this.toolbars = [];
15828 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15831 * @event initialize
15832 * Fires when the editor is fully initialized (including the iframe)
15833 * @param {HtmlEditor} this
15838 * Fires when the editor is first receives the focus. Any insertion must wait
15839 * until after this event.
15840 * @param {HtmlEditor} this
15844 * @event beforesync
15845 * Fires before the textarea is updated with content from the editor iframe. Return false
15846 * to cancel the sync.
15847 * @param {HtmlEditor} this
15848 * @param {String} html
15852 * @event beforepush
15853 * Fires before the iframe editor is updated with content from the textarea. Return false
15854 * to cancel the push.
15855 * @param {HtmlEditor} this
15856 * @param {String} html
15861 * Fires when the textarea is updated with content from the editor iframe.
15862 * @param {HtmlEditor} this
15863 * @param {String} html
15868 * Fires when the iframe editor is updated with content from the textarea.
15869 * @param {HtmlEditor} this
15870 * @param {String} html
15874 * @event editmodechange
15875 * Fires when the editor switches edit modes
15876 * @param {HtmlEditor} this
15877 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15879 editmodechange: true,
15881 * @event editorevent
15882 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15883 * @param {HtmlEditor} this
15887 * @event firstfocus
15888 * Fires when on first focus - needed by toolbars..
15889 * @param {HtmlEditor} this
15894 * Auto save the htmlEditor value as a file into Events
15895 * @param {HtmlEditor} this
15899 * @event savedpreview
15900 * preview the saved version of htmlEditor
15901 * @param {HtmlEditor} this
15908 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15912 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15917 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15922 * @cfg {Number} height (in pixels)
15926 * @cfg {Number} width (in pixels)
15931 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15934 stylesheets: false,
15939 // private properties
15940 validationEvent : false,
15942 initialized : false,
15945 onFocus : Roo.emptyFn,
15947 hideMode:'offsets',
15950 tbContainer : false,
15952 toolbarContainer :function() {
15953 return this.wrap.select('.x-html-editor-tb',true).first();
15957 * Protected method that will not generally be called directly. It
15958 * is called when the editor creates its toolbar. Override this method if you need to
15959 * add custom toolbar buttons.
15960 * @param {HtmlEditor} editor
15962 createToolbar : function(){
15964 Roo.log("create toolbars");
15966 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15967 this.toolbars[0].render(this.toolbarContainer());
15971 // if (!editor.toolbars || !editor.toolbars.length) {
15972 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15975 // for (var i =0 ; i < editor.toolbars.length;i++) {
15976 // editor.toolbars[i] = Roo.factory(
15977 // typeof(editor.toolbars[i]) == 'string' ?
15978 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15979 // Roo.bootstrap.HtmlEditor);
15980 // editor.toolbars[i].init(editor);
15986 onRender : function(ct, position)
15988 // Roo.log("Call onRender: " + this.xtype);
15990 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15992 this.wrap = this.inputEl().wrap({
15993 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15996 this.editorcore.onRender(ct, position);
15998 if (this.resizable) {
15999 this.resizeEl = new Roo.Resizable(this.wrap, {
16003 minHeight : this.height,
16004 height: this.height,
16005 handles : this.resizable,
16008 resize : function(r, w, h) {
16009 _t.onResize(w,h); // -something
16015 this.createToolbar(this);
16018 if(!this.width && this.resizable){
16019 this.setSize(this.wrap.getSize());
16021 if (this.resizeEl) {
16022 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16023 // should trigger onReize..
16029 onResize : function(w, h)
16031 Roo.log('resize: ' +w + ',' + h );
16032 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16036 if(this.inputEl() ){
16037 if(typeof w == 'number'){
16038 var aw = w - this.wrap.getFrameWidth('lr');
16039 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16042 if(typeof h == 'number'){
16043 var tbh = -11; // fixme it needs to tool bar size!
16044 for (var i =0; i < this.toolbars.length;i++) {
16045 // fixme - ask toolbars for heights?
16046 tbh += this.toolbars[i].el.getHeight();
16047 //if (this.toolbars[i].footer) {
16048 // tbh += this.toolbars[i].footer.el.getHeight();
16056 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16057 ah -= 5; // knock a few pixes off for look..
16058 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16062 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16063 this.editorcore.onResize(ew,eh);
16068 * Toggles the editor between standard and source edit mode.
16069 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16071 toggleSourceEdit : function(sourceEditMode)
16073 this.editorcore.toggleSourceEdit(sourceEditMode);
16075 if(this.editorcore.sourceEditMode){
16076 Roo.log('editor - showing textarea');
16079 // Roo.log(this.syncValue());
16081 this.inputEl().removeClass('hide');
16082 this.inputEl().dom.removeAttribute('tabIndex');
16083 this.inputEl().focus();
16085 Roo.log('editor - hiding textarea');
16087 // Roo.log(this.pushValue());
16090 this.inputEl().addClass('hide');
16091 this.inputEl().dom.setAttribute('tabIndex', -1);
16092 //this.deferFocus();
16095 if(this.resizable){
16096 this.setSize(this.wrap.getSize());
16099 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16102 // private (for BoxComponent)
16103 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16105 // private (for BoxComponent)
16106 getResizeEl : function(){
16110 // private (for BoxComponent)
16111 getPositionEl : function(){
16116 initEvents : function(){
16117 this.originalValue = this.getValue();
16121 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16124 // markInvalid : Roo.emptyFn,
16126 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16129 // clearInvalid : Roo.emptyFn,
16131 setValue : function(v){
16132 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16133 this.editorcore.pushValue();
16138 deferFocus : function(){
16139 this.focus.defer(10, this);
16143 focus : function(){
16144 this.editorcore.focus();
16150 onDestroy : function(){
16156 for (var i =0; i < this.toolbars.length;i++) {
16157 // fixme - ask toolbars for heights?
16158 this.toolbars[i].onDestroy();
16161 this.wrap.dom.innerHTML = '';
16162 this.wrap.remove();
16167 onFirstFocus : function(){
16168 //Roo.log("onFirstFocus");
16169 this.editorcore.onFirstFocus();
16170 for (var i =0; i < this.toolbars.length;i++) {
16171 this.toolbars[i].onFirstFocus();
16177 syncValue : function()
16179 this.editorcore.syncValue();
16182 pushValue : function()
16184 this.editorcore.pushValue();
16188 // hide stuff that is not compatible
16202 * @event specialkey
16206 * @cfg {String} fieldClass @hide
16209 * @cfg {String} focusClass @hide
16212 * @cfg {String} autoCreate @hide
16215 * @cfg {String} inputType @hide
16218 * @cfg {String} invalidClass @hide
16221 * @cfg {String} invalidText @hide
16224 * @cfg {String} msgFx @hide
16227 * @cfg {String} validateOnBlur @hide
16238 * @class Roo.bootstrap.HtmlEditorToolbar1
16243 new Roo.bootstrap.HtmlEditor({
16246 new Roo.bootstrap.HtmlEditorToolbar1({
16247 disable : { fonts: 1 , format: 1, ..., ... , ...],
16253 * @cfg {Object} disable List of elements to disable..
16254 * @cfg {Array} btns List of additional buttons.
16258 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16261 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
16264 Roo.apply(this, config);
16266 // default disabled, based on 'good practice'..
16267 this.disable = this.disable || {};
16268 Roo.applyIf(this.disable, {
16271 specialElements : true
16273 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
16275 this.editor = config.editor;
16276 this.editorcore = config.editor.editorcore;
16278 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16280 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16281 // dont call parent... till later.
16283 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16289 editorcore : false,
16294 "h1","h2","h3","h4","h5","h6",
16296 "abbr", "acronym", "address", "cite", "samp", "var",
16300 onRender : function(ct, position)
16302 // Roo.log("Call onRender: " + this.xtype);
16304 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16306 this.el.dom.style.marginBottom = '0';
16308 var editorcore = this.editorcore;
16309 var editor= this.editor;
16312 var btn = function(id,cmd , toggle, handler){
16314 var event = toggle ? 'toggle' : 'click';
16319 xns: Roo.bootstrap,
16322 enableToggle:toggle !== false,
16324 pressed : toggle ? false : null,
16327 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16328 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16337 xns: Roo.bootstrap,
16338 glyphicon : 'font',
16342 xns: Roo.bootstrap,
16346 Roo.each(this.formats, function(f) {
16347 style.menu.items.push({
16349 xns: Roo.bootstrap,
16350 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16355 editorcore.insertTag(this.tagname);
16362 children.push(style);
16365 btn('bold',false,true);
16366 btn('italic',false,true);
16367 btn('align-left', 'justifyleft',true);
16368 btn('align-center', 'justifycenter',true);
16369 btn('align-right' , 'justifyright',true);
16370 btn('link', false, false, function(btn) {
16371 //Roo.log("create link?");
16372 var url = prompt(this.createLinkText, this.defaultLinkValue);
16373 if(url && url != 'http:/'+'/'){
16374 this.editorcore.relayCmd('createlink', url);
16377 btn('list','insertunorderedlist',true);
16378 btn('pencil', false,true, function(btn){
16381 this.toggleSourceEdit(btn.pressed);
16387 xns: Roo.bootstrap,
16392 xns: Roo.bootstrap,
16397 cog.menu.items.push({
16399 xns: Roo.bootstrap,
16400 html : Clean styles,
16405 editorcore.insertTag(this.tagname);
16414 this.xtype = 'NavSimplebar';
16416 for(var i=0;i< children.length;i++) {
16418 this.buttons.add(this.addxtypeChild(children[i]));
16422 editor.on('editorevent', this.updateToolbar, this);
16424 onBtnClick : function(id)
16426 this.editorcore.relayCmd(id);
16427 this.editorcore.focus();
16431 * Protected method that will not generally be called directly. It triggers
16432 * a toolbar update by reading the markup state of the current selection in the editor.
16434 updateToolbar: function(){
16436 if(!this.editorcore.activated){
16437 this.editor.onFirstFocus(); // is this neeed?
16441 var btns = this.buttons;
16442 var doc = this.editorcore.doc;
16443 btns.get('bold').setActive(doc.queryCommandState('bold'));
16444 btns.get('italic').setActive(doc.queryCommandState('italic'));
16445 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16447 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16448 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16449 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16451 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16452 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16455 var ans = this.editorcore.getAllAncestors();
16456 if (this.formatCombo) {
16459 var store = this.formatCombo.store;
16460 this.formatCombo.setValue("");
16461 for (var i =0; i < ans.length;i++) {
16462 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16464 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16472 // hides menus... - so this cant be on a menu...
16473 Roo.bootstrap.MenuMgr.hideAll();
16475 Roo.bootstrap.MenuMgr.hideAll();
16476 //this.editorsyncValue();
16478 onFirstFocus: function() {
16479 this.buttons.each(function(item){
16483 toggleSourceEdit : function(sourceEditMode){
16486 if(sourceEditMode){
16487 Roo.log("disabling buttons");
16488 this.buttons.each( function(item){
16489 if(item.cmd != 'pencil'){
16495 Roo.log("enabling buttons");
16496 if(this.editorcore.initialized){
16497 this.buttons.each( function(item){
16503 Roo.log("calling toggole on editor");
16504 // tell the editor that it's been pressed..
16505 this.editor.toggleSourceEdit(sourceEditMode);
16515 * @class Roo.bootstrap.Table.AbstractSelectionModel
16516 * @extends Roo.util.Observable
16517 * Abstract base class for grid SelectionModels. It provides the interface that should be
16518 * implemented by descendant classes. This class should not be directly instantiated.
16521 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16522 this.locked = false;
16523 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16527 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16528 /** @ignore Called by the grid automatically. Do not call directly. */
16529 init : function(grid){
16535 * Locks the selections.
16538 this.locked = true;
16542 * Unlocks the selections.
16544 unlock : function(){
16545 this.locked = false;
16549 * Returns true if the selections are locked.
16550 * @return {Boolean}
16552 isLocked : function(){
16553 return this.locked;
16557 * @class Roo.bootstrap.Table.ColumnModel
16558 * @extends Roo.util.Observable
16559 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16560 * the columns in the table.
16563 * @param {Object} config An Array of column config objects. See this class's
16564 * config objects for details.
16566 Roo.bootstrap.Table.ColumnModel = function(config){
16568 * The config passed into the constructor
16570 this.config = config;
16573 // if no id, create one
16574 // if the column does not have a dataIndex mapping,
16575 // map it to the order it is in the config
16576 for(var i = 0, len = config.length; i < len; i++){
16578 if(typeof c.dataIndex == "undefined"){
16581 if(typeof c.renderer == "string"){
16582 c.renderer = Roo.util.Format[c.renderer];
16584 if(typeof c.id == "undefined"){
16587 // if(c.editor && c.editor.xtype){
16588 // c.editor = Roo.factory(c.editor, Roo.grid);
16590 // if(c.editor && c.editor.isFormField){
16591 // c.editor = new Roo.grid.GridEditor(c.editor);
16594 this.lookup[c.id] = c;
16598 * The width of columns which have no width specified (defaults to 100)
16601 this.defaultWidth = 100;
16604 * Default sortable of columns which have no sortable specified (defaults to false)
16607 this.defaultSortable = false;
16611 * @event widthchange
16612 * Fires when the width of a column changes.
16613 * @param {ColumnModel} this
16614 * @param {Number} columnIndex The column index
16615 * @param {Number} newWidth The new width
16617 "widthchange": true,
16619 * @event headerchange
16620 * Fires when the text of a header changes.
16621 * @param {ColumnModel} this
16622 * @param {Number} columnIndex The column index
16623 * @param {Number} newText The new header text
16625 "headerchange": true,
16627 * @event hiddenchange
16628 * Fires when a column is hidden or "unhidden".
16629 * @param {ColumnModel} this
16630 * @param {Number} columnIndex The column index
16631 * @param {Boolean} hidden true if hidden, false otherwise
16633 "hiddenchange": true,
16635 * @event columnmoved
16636 * Fires when a column is moved.
16637 * @param {ColumnModel} this
16638 * @param {Number} oldIndex
16639 * @param {Number} newIndex
16641 "columnmoved" : true,
16643 * @event columlockchange
16644 * Fires when a column's locked state is changed
16645 * @param {ColumnModel} this
16646 * @param {Number} colIndex
16647 * @param {Boolean} locked true if locked
16649 "columnlockchange" : true
16651 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16653 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16655 * @cfg {String} header The header text to display in the Grid view.
16658 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16659 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16660 * specified, the column's index is used as an index into the Record's data Array.
16663 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16664 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16667 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16668 * Defaults to the value of the {@link #defaultSortable} property.
16669 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16672 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16675 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16678 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16681 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16684 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16685 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16686 * default renderer uses the raw data value.
16689 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16693 * Returns the id of the column at the specified index.
16694 * @param {Number} index The column index
16695 * @return {String} the id
16697 getColumnId : function(index){
16698 return this.config[index].id;
16702 * Returns the column for a specified id.
16703 * @param {String} id The column id
16704 * @return {Object} the column
16706 getColumnById : function(id){
16707 return this.lookup[id];
16712 * Returns the column for a specified dataIndex.
16713 * @param {String} dataIndex The column dataIndex
16714 * @return {Object|Boolean} the column or false if not found
16716 getColumnByDataIndex: function(dataIndex){
16717 var index = this.findColumnIndex(dataIndex);
16718 return index > -1 ? this.config[index] : false;
16722 * Returns the index for a specified column id.
16723 * @param {String} id The column id
16724 * @return {Number} the index, or -1 if not found
16726 getIndexById : function(id){
16727 for(var i = 0, len = this.config.length; i < len; i++){
16728 if(this.config[i].id == id){
16736 * Returns the index for a specified column dataIndex.
16737 * @param {String} dataIndex The column dataIndex
16738 * @return {Number} the index, or -1 if not found
16741 findColumnIndex : function(dataIndex){
16742 for(var i = 0, len = this.config.length; i < len; i++){
16743 if(this.config[i].dataIndex == dataIndex){
16751 moveColumn : function(oldIndex, newIndex){
16752 var c = this.config[oldIndex];
16753 this.config.splice(oldIndex, 1);
16754 this.config.splice(newIndex, 0, c);
16755 this.dataMap = null;
16756 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16759 isLocked : function(colIndex){
16760 return this.config[colIndex].locked === true;
16763 setLocked : function(colIndex, value, suppressEvent){
16764 if(this.isLocked(colIndex) == value){
16767 this.config[colIndex].locked = value;
16768 if(!suppressEvent){
16769 this.fireEvent("columnlockchange", this, colIndex, value);
16773 getTotalLockedWidth : function(){
16774 var totalWidth = 0;
16775 for(var i = 0; i < this.config.length; i++){
16776 if(this.isLocked(i) && !this.isHidden(i)){
16777 this.totalWidth += this.getColumnWidth(i);
16783 getLockedCount : function(){
16784 for(var i = 0, len = this.config.length; i < len; i++){
16785 if(!this.isLocked(i)){
16792 * Returns the number of columns.
16795 getColumnCount : function(visibleOnly){
16796 if(visibleOnly === true){
16798 for(var i = 0, len = this.config.length; i < len; i++){
16799 if(!this.isHidden(i)){
16805 return this.config.length;
16809 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16810 * @param {Function} fn
16811 * @param {Object} scope (optional)
16812 * @return {Array} result
16814 getColumnsBy : function(fn, scope){
16816 for(var i = 0, len = this.config.length; i < len; i++){
16817 var c = this.config[i];
16818 if(fn.call(scope||this, c, i) === true){
16826 * Returns true if the specified column is sortable.
16827 * @param {Number} col The column index
16828 * @return {Boolean}
16830 isSortable : function(col){
16831 if(typeof this.config[col].sortable == "undefined"){
16832 return this.defaultSortable;
16834 return this.config[col].sortable;
16838 * Returns the rendering (formatting) function defined for the column.
16839 * @param {Number} col The column index.
16840 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16842 getRenderer : function(col){
16843 if(!this.config[col].renderer){
16844 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16846 return this.config[col].renderer;
16850 * Sets the rendering (formatting) function for a column.
16851 * @param {Number} col The column index
16852 * @param {Function} fn The function to use to process the cell's raw data
16853 * to return HTML markup for the grid view. The render function is called with
16854 * the following parameters:<ul>
16855 * <li>Data value.</li>
16856 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16857 * <li>css A CSS style string to apply to the table cell.</li>
16858 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16859 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16860 * <li>Row index</li>
16861 * <li>Column index</li>
16862 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16864 setRenderer : function(col, fn){
16865 this.config[col].renderer = fn;
16869 * Returns the width for the specified column.
16870 * @param {Number} col The column index
16873 getColumnWidth : function(col){
16874 return this.config[col].width * 1 || this.defaultWidth;
16878 * Sets the width for a column.
16879 * @param {Number} col The column index
16880 * @param {Number} width The new width
16882 setColumnWidth : function(col, width, suppressEvent){
16883 this.config[col].width = width;
16884 this.totalWidth = null;
16885 if(!suppressEvent){
16886 this.fireEvent("widthchange", this, col, width);
16891 * Returns the total width of all columns.
16892 * @param {Boolean} includeHidden True to include hidden column widths
16895 getTotalWidth : function(includeHidden){
16896 if(!this.totalWidth){
16897 this.totalWidth = 0;
16898 for(var i = 0, len = this.config.length; i < len; i++){
16899 if(includeHidden || !this.isHidden(i)){
16900 this.totalWidth += this.getColumnWidth(i);
16904 return this.totalWidth;
16908 * Returns the header for the specified column.
16909 * @param {Number} col The column index
16912 getColumnHeader : function(col){
16913 return this.config[col].header;
16917 * Sets the header for a column.
16918 * @param {Number} col The column index
16919 * @param {String} header The new header
16921 setColumnHeader : function(col, header){
16922 this.config[col].header = header;
16923 this.fireEvent("headerchange", this, col, header);
16927 * Returns the tooltip for the specified column.
16928 * @param {Number} col The column index
16931 getColumnTooltip : function(col){
16932 return this.config[col].tooltip;
16935 * Sets the tooltip for a column.
16936 * @param {Number} col The column index
16937 * @param {String} tooltip The new tooltip
16939 setColumnTooltip : function(col, tooltip){
16940 this.config[col].tooltip = tooltip;
16944 * Returns the dataIndex for the specified column.
16945 * @param {Number} col The column index
16948 getDataIndex : function(col){
16949 return this.config[col].dataIndex;
16953 * Sets the dataIndex for a column.
16954 * @param {Number} col The column index
16955 * @param {Number} dataIndex The new dataIndex
16957 setDataIndex : function(col, dataIndex){
16958 this.config[col].dataIndex = dataIndex;
16964 * Returns true if the cell is editable.
16965 * @param {Number} colIndex The column index
16966 * @param {Number} rowIndex The row index
16967 * @return {Boolean}
16969 isCellEditable : function(colIndex, rowIndex){
16970 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16974 * Returns the editor defined for the cell/column.
16975 * return false or null to disable editing.
16976 * @param {Number} colIndex The column index
16977 * @param {Number} rowIndex The row index
16980 getCellEditor : function(colIndex, rowIndex){
16981 return this.config[colIndex].editor;
16985 * Sets if a column is editable.
16986 * @param {Number} col The column index
16987 * @param {Boolean} editable True if the column is editable
16989 setEditable : function(col, editable){
16990 this.config[col].editable = editable;
16995 * Returns true if the column is hidden.
16996 * @param {Number} colIndex The column index
16997 * @return {Boolean}
16999 isHidden : function(colIndex){
17000 return this.config[colIndex].hidden;
17005 * Returns true if the column width cannot be changed
17007 isFixed : function(colIndex){
17008 return this.config[colIndex].fixed;
17012 * Returns true if the column can be resized
17013 * @return {Boolean}
17015 isResizable : function(colIndex){
17016 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
17019 * Sets if a column is hidden.
17020 * @param {Number} colIndex The column index
17021 * @param {Boolean} hidden True if the column is hidden
17023 setHidden : function(colIndex, hidden){
17024 this.config[colIndex].hidden = hidden;
17025 this.totalWidth = null;
17026 this.fireEvent("hiddenchange", this, colIndex, hidden);
17030 * Sets the editor for a column.
17031 * @param {Number} col The column index
17032 * @param {Object} editor The editor object
17034 setEditor : function(col, editor){
17035 this.config[col].editor = editor;
17039 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
17040 if(typeof value == "string" && value.length < 1){
17046 // Alias for backwards compatibility
17047 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
17050 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17051 * @class Roo.bootstrap.Table.RowSelectionModel
17052 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17053 * It supports multiple selections and keyboard selection/navigation.
17055 * @param {Object} config
17058 Roo.bootstrap.Table.RowSelectionModel = function(config){
17059 Roo.apply(this, config);
17060 this.selections = new Roo.util.MixedCollection(false, function(o){
17065 this.lastActive = false;
17069 * @event selectionchange
17070 * Fires when the selection changes
17071 * @param {SelectionModel} this
17073 "selectionchange" : true,
17075 * @event afterselectionchange
17076 * Fires after the selection changes (eg. by key press or clicking)
17077 * @param {SelectionModel} this
17079 "afterselectionchange" : true,
17081 * @event beforerowselect
17082 * Fires when a row is selected being selected, return false to cancel.
17083 * @param {SelectionModel} this
17084 * @param {Number} rowIndex The selected index
17085 * @param {Boolean} keepExisting False if other selections will be cleared
17087 "beforerowselect" : true,
17090 * Fires when a row is selected.
17091 * @param {SelectionModel} this
17092 * @param {Number} rowIndex The selected index
17093 * @param {Roo.data.Record} r The record
17095 "rowselect" : true,
17097 * @event rowdeselect
17098 * Fires when a row is deselected.
17099 * @param {SelectionModel} this
17100 * @param {Number} rowIndex The selected index
17102 "rowdeselect" : true
17104 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17105 this.locked = false;
17108 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17110 * @cfg {Boolean} singleSelect
17111 * True to allow selection of only one row at a time (defaults to false)
17113 singleSelect : false,
17116 initEvents : function(){
17118 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17119 this.grid.on("mousedown", this.handleMouseDown, this);
17120 }else{ // allow click to work like normal
17121 this.grid.on("rowclick", this.handleDragableRowClick, this);
17124 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17125 "up" : function(e){
17127 this.selectPrevious(e.shiftKey);
17128 }else if(this.last !== false && this.lastActive !== false){
17129 var last = this.last;
17130 this.selectRange(this.last, this.lastActive-1);
17131 this.grid.getView().focusRow(this.lastActive);
17132 if(last !== false){
17136 this.selectFirstRow();
17138 this.fireEvent("afterselectionchange", this);
17140 "down" : function(e){
17142 this.selectNext(e.shiftKey);
17143 }else if(this.last !== false && this.lastActive !== false){
17144 var last = this.last;
17145 this.selectRange(this.last, this.lastActive+1);
17146 this.grid.getView().focusRow(this.lastActive);
17147 if(last !== false){
17151 this.selectFirstRow();
17153 this.fireEvent("afterselectionchange", this);
17158 var view = this.grid.view;
17159 view.on("refresh", this.onRefresh, this);
17160 view.on("rowupdated", this.onRowUpdated, this);
17161 view.on("rowremoved", this.onRemove, this);
17165 onRefresh : function(){
17166 var ds = this.grid.dataSource, i, v = this.grid.view;
17167 var s = this.selections;
17168 s.each(function(r){
17169 if((i = ds.indexOfId(r.id)) != -1){
17178 onRemove : function(v, index, r){
17179 this.selections.remove(r);
17183 onRowUpdated : function(v, index, r){
17184 if(this.isSelected(r)){
17185 v.onRowSelect(index);
17191 * @param {Array} records The records to select
17192 * @param {Boolean} keepExisting (optional) True to keep existing selections
17194 selectRecords : function(records, keepExisting){
17196 this.clearSelections();
17198 var ds = this.grid.dataSource;
17199 for(var i = 0, len = records.length; i < len; i++){
17200 this.selectRow(ds.indexOf(records[i]), true);
17205 * Gets the number of selected rows.
17208 getCount : function(){
17209 return this.selections.length;
17213 * Selects the first row in the grid.
17215 selectFirstRow : function(){
17220 * Select the last row.
17221 * @param {Boolean} keepExisting (optional) True to keep existing selections
17223 selectLastRow : function(keepExisting){
17224 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17228 * Selects the row immediately following the last selected row.
17229 * @param {Boolean} keepExisting (optional) True to keep existing selections
17231 selectNext : function(keepExisting){
17232 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17233 this.selectRow(this.last+1, keepExisting);
17234 this.grid.getView().focusRow(this.last);
17239 * Selects the row that precedes the last selected row.
17240 * @param {Boolean} keepExisting (optional) True to keep existing selections
17242 selectPrevious : function(keepExisting){
17244 this.selectRow(this.last-1, keepExisting);
17245 this.grid.getView().focusRow(this.last);
17250 * Returns the selected records
17251 * @return {Array} Array of selected records
17253 getSelections : function(){
17254 return [].concat(this.selections.items);
17258 * Returns the first selected record.
17261 getSelected : function(){
17262 return this.selections.itemAt(0);
17267 * Clears all selections.
17269 clearSelections : function(fast){
17270 if(this.locked) return;
17272 var ds = this.grid.dataSource;
17273 var s = this.selections;
17274 s.each(function(r){
17275 this.deselectRow(ds.indexOfId(r.id));
17279 this.selections.clear();
17286 * Selects all rows.
17288 selectAll : function(){
17289 if(this.locked) return;
17290 this.selections.clear();
17291 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17292 this.selectRow(i, true);
17297 * Returns True if there is a selection.
17298 * @return {Boolean}
17300 hasSelection : function(){
17301 return this.selections.length > 0;
17305 * Returns True if the specified row is selected.
17306 * @param {Number/Record} record The record or index of the record to check
17307 * @return {Boolean}
17309 isSelected : function(index){
17310 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17311 return (r && this.selections.key(r.id) ? true : false);
17315 * Returns True if the specified record id is selected.
17316 * @param {String} id The id of record to check
17317 * @return {Boolean}
17319 isIdSelected : function(id){
17320 return (this.selections.key(id) ? true : false);
17324 handleMouseDown : function(e, t){
17325 var view = this.grid.getView(), rowIndex;
17326 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17329 if(e.shiftKey && this.last !== false){
17330 var last = this.last;
17331 this.selectRange(last, rowIndex, e.ctrlKey);
17332 this.last = last; // reset the last
17333 view.focusRow(rowIndex);
17335 var isSelected = this.isSelected(rowIndex);
17336 if(e.button !== 0 && isSelected){
17337 view.focusRow(rowIndex);
17338 }else if(e.ctrlKey && isSelected){
17339 this.deselectRow(rowIndex);
17340 }else if(!isSelected){
17341 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17342 view.focusRow(rowIndex);
17345 this.fireEvent("afterselectionchange", this);
17348 handleDragableRowClick : function(grid, rowIndex, e)
17350 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17351 this.selectRow(rowIndex, false);
17352 grid.view.focusRow(rowIndex);
17353 this.fireEvent("afterselectionchange", this);
17358 * Selects multiple rows.
17359 * @param {Array} rows Array of the indexes of the row to select
17360 * @param {Boolean} keepExisting (optional) True to keep existing selections
17362 selectRows : function(rows, keepExisting){
17364 this.clearSelections();
17366 for(var i = 0, len = rows.length; i < len; i++){
17367 this.selectRow(rows[i], true);
17372 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17373 * @param {Number} startRow The index of the first row in the range
17374 * @param {Number} endRow The index of the last row in the range
17375 * @param {Boolean} keepExisting (optional) True to retain existing selections
17377 selectRange : function(startRow, endRow, keepExisting){
17378 if(this.locked) return;
17380 this.clearSelections();
17382 if(startRow <= endRow){
17383 for(var i = startRow; i <= endRow; i++){
17384 this.selectRow(i, true);
17387 for(var i = startRow; i >= endRow; i--){
17388 this.selectRow(i, true);
17394 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17395 * @param {Number} startRow The index of the first row in the range
17396 * @param {Number} endRow The index of the last row in the range
17398 deselectRange : function(startRow, endRow, preventViewNotify){
17399 if(this.locked) return;
17400 for(var i = startRow; i <= endRow; i++){
17401 this.deselectRow(i, preventViewNotify);
17407 * @param {Number} row The index of the row to select
17408 * @param {Boolean} keepExisting (optional) True to keep existing selections
17410 selectRow : function(index, keepExisting, preventViewNotify){
17411 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17412 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17413 if(!keepExisting || this.singleSelect){
17414 this.clearSelections();
17416 var r = this.grid.dataSource.getAt(index);
17417 this.selections.add(r);
17418 this.last = this.lastActive = index;
17419 if(!preventViewNotify){
17420 this.grid.getView().onRowSelect(index);
17422 this.fireEvent("rowselect", this, index, r);
17423 this.fireEvent("selectionchange", this);
17429 * @param {Number} row The index of the row to deselect
17431 deselectRow : function(index, preventViewNotify){
17432 if(this.locked) return;
17433 if(this.last == index){
17436 if(this.lastActive == index){
17437 this.lastActive = false;
17439 var r = this.grid.dataSource.getAt(index);
17440 this.selections.remove(r);
17441 if(!preventViewNotify){
17442 this.grid.getView().onRowDeselect(index);
17444 this.fireEvent("rowdeselect", this, index);
17445 this.fireEvent("selectionchange", this);
17449 restoreLast : function(){
17451 this.last = this._last;
17456 acceptsNav : function(row, col, cm){
17457 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17461 onEditorKey : function(field, e){
17462 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17467 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17469 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17471 }else if(k == e.ENTER && !e.ctrlKey){
17475 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17477 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17479 }else if(k == e.ESC){
17483 g.startEditing(newCell[0], newCell[1]);
17494 * @class Roo.bootstrap.MessageBar
17495 * @extends Roo.bootstrap.Component
17496 * Bootstrap MessageBar class
17497 * @cfg {String} html contents of the MessageBar
17498 * @cfg {String} weight (info | success | warning | danger) default info
17499 * @cfg {String} beforeClass insert the bar before the given class
17500 * @cfg {Boolean} closable (true | false) default false
17501 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17504 * Create a new Element
17505 * @param {Object} config The config object
17508 Roo.bootstrap.MessageBar = function(config){
17509 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17512 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17518 beforeClass: 'bootstrap-sticky-wrap',
17520 getAutoCreate : function(){
17524 cls: 'alert alert-dismissable alert-' + this.weight,
17529 html: this.html || ''
17535 cfg.cls += ' alert-messages-fixed';
17549 onRender : function(ct, position)
17551 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17554 var cfg = Roo.apply({}, this.getAutoCreate());
17558 cfg.cls += ' ' + this.cls;
17561 cfg.style = this.style;
17563 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17565 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17568 this.el.select('>button.close').on('click', this.hide, this);
17574 if (!this.rendered) {
17580 this.fireEvent('show', this);
17586 if (!this.rendered) {
17592 this.fireEvent('hide', this);
17595 update : function()
17597 // var e = this.el.dom.firstChild;
17599 // if(this.closable){
17600 // e = e.nextSibling;
17603 // e.data = this.html || '';
17605 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';