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");
4247 this.store.on('load', this.onLoad, this);
4248 this.store.on('beforeload', this.onBeforeLoad, this);
4256 sort : function(e,el)
4258 var col = Roo.get(el)
4260 if(!col.hasClass('sortable')){
4264 var sort = col.attr('sort');
4267 if(col.hasClass('glyphicon-arrow-up')){
4271 this.store.sortInfo = {field : sort, direction : dir};
4276 renderHeader : function()
4285 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4287 var config = cm.config[i];
4291 html: cm.getColumnHeader(i)
4294 if(typeof(config.dataIndex) != 'undefined'){
4295 c.sort = config.dataIndex;
4298 if(typeof(config.sortable) != 'undefined' && config.sortable){
4302 if(typeof(config.width) != 'undefined'){
4303 c.style = 'width:' + config.width + 'px';
4312 renderBody : function()
4322 renderFooter : function()
4334 Roo.log('ds onload');
4339 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4340 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4342 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4343 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4346 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4347 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4351 var tbody = this.el.select('tbody', true).first();
4355 if(this.store.getCount() > 0){
4356 this.store.data.each(function(d){
4362 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4363 var renderer = cm.getRenderer(i);
4364 var config = cm.config[i];
4368 if(typeof(renderer) !== 'undefined'){
4369 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4372 if(typeof(value) === 'object'){
4382 html: (typeof(value) === 'object') ? '' : value
4385 if(typeof(config.width) != 'undefined'){
4386 td.style = 'width:' + config.width + 'px';
4393 tbody.createChild(row);
4401 Roo.each(renders, function(r){
4402 _this.renderColumn(r);
4406 // if(this.loadMask){
4407 // this.maskEl.hide();
4411 onBeforeLoad : function()
4413 Roo.log('ds onBeforeLoad');
4417 // if(this.loadMask){
4418 // this.maskEl.show();
4424 this.el.select('tbody', true).first().dom.innerHTML = '';
4427 getSelectionModel : function(){
4429 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4431 return this.selModel;
4434 renderColumn : function(r)
4437 r.cfg.render(Roo.get(r.id));
4440 Roo.each(r.cfg.cn, function(c){
4445 _this.renderColumn(child);
4462 * @class Roo.bootstrap.TableCell
4463 * @extends Roo.bootstrap.Component
4464 * Bootstrap TableCell class
4465 * @cfg {String} html cell contain text
4466 * @cfg {String} cls cell class
4467 * @cfg {String} tag cell tag (td|th) default td
4468 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4469 * @cfg {String} align Aligns the content in a cell
4470 * @cfg {String} axis Categorizes cells
4471 * @cfg {String} bgcolor Specifies the background color of a cell
4472 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4473 * @cfg {Number} colspan Specifies the number of columns a cell should span
4474 * @cfg {String} headers Specifies one or more header cells a cell is related to
4475 * @cfg {Number} height Sets the height of a cell
4476 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4477 * @cfg {Number} rowspan Sets the number of rows a cell should span
4478 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4479 * @cfg {String} valign Vertical aligns the content in a cell
4480 * @cfg {Number} width Specifies the width of a cell
4483 * Create a new TableCell
4484 * @param {Object} config The config object
4487 Roo.bootstrap.TableCell = function(config){
4488 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4491 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4511 getAutoCreate : function(){
4512 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4532 cfg.align=this.align
4538 cfg.bgcolor=this.bgcolor
4541 cfg.charoff=this.charoff
4544 cfg.colspan=this.colspan
4547 cfg.headers=this.headers
4550 cfg.height=this.height
4553 cfg.nowrap=this.nowrap
4556 cfg.rowspan=this.rowspan
4559 cfg.scope=this.scope
4562 cfg.valign=this.valign
4565 cfg.width=this.width
4584 * @class Roo.bootstrap.TableRow
4585 * @extends Roo.bootstrap.Component
4586 * Bootstrap TableRow class
4587 * @cfg {String} cls row class
4588 * @cfg {String} align Aligns the content in a table row
4589 * @cfg {String} bgcolor Specifies a background color for a table row
4590 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4591 * @cfg {String} valign Vertical aligns the content in a table row
4594 * Create a new TableRow
4595 * @param {Object} config The config object
4598 Roo.bootstrap.TableRow = function(config){
4599 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4602 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4610 getAutoCreate : function(){
4611 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4621 cfg.align = this.align;
4624 cfg.bgcolor = this.bgcolor;
4627 cfg.charoff = this.charoff;
4630 cfg.valign = this.valign;
4648 * @class Roo.bootstrap.TableBody
4649 * @extends Roo.bootstrap.Component
4650 * Bootstrap TableBody class
4651 * @cfg {String} cls element class
4652 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4653 * @cfg {String} align Aligns the content inside the element
4654 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4655 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4658 * Create a new TableBody
4659 * @param {Object} config The config object
4662 Roo.bootstrap.TableBody = function(config){
4663 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4666 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4674 getAutoCreate : function(){
4675 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4689 cfg.align = this.align;
4692 cfg.charoff = this.charoff;
4695 cfg.valign = this.valign;
4702 // initEvents : function()
4709 // this.store = Roo.factory(this.store, Roo.data);
4710 // this.store.on('load', this.onLoad, this);
4712 // this.store.load();
4716 // onLoad: function ()
4718 // this.fireEvent('load', this);
4728 * Ext JS Library 1.1.1
4729 * Copyright(c) 2006-2007, Ext JS, LLC.
4731 * Originally Released Under LGPL - original licence link has changed is not relivant.
4734 * <script type="text/javascript">
4737 // as we use this in bootstrap.
4738 Roo.namespace('Roo.form');
4740 * @class Roo.form.Action
4741 * Internal Class used to handle form actions
4743 * @param {Roo.form.BasicForm} el The form element or its id
4744 * @param {Object} config Configuration options
4749 // define the action interface
4750 Roo.form.Action = function(form, options){
4752 this.options = options || {};
4755 * Client Validation Failed
4758 Roo.form.Action.CLIENT_INVALID = 'client';
4760 * Server Validation Failed
4763 Roo.form.Action.SERVER_INVALID = 'server';
4765 * Connect to Server Failed
4768 Roo.form.Action.CONNECT_FAILURE = 'connect';
4770 * Reading Data from Server Failed
4773 Roo.form.Action.LOAD_FAILURE = 'load';
4775 Roo.form.Action.prototype = {
4777 failureType : undefined,
4778 response : undefined,
4782 run : function(options){
4787 success : function(response){
4792 handleResponse : function(response){
4796 // default connection failure
4797 failure : function(response){
4799 this.response = response;
4800 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4801 this.form.afterAction(this, false);
4804 processResponse : function(response){
4805 this.response = response;
4806 if(!response.responseText){
4809 this.result = this.handleResponse(response);
4813 // utility functions used internally
4814 getUrl : function(appendParams){
4815 var url = this.options.url || this.form.url || this.form.el.dom.action;
4817 var p = this.getParams();
4819 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4825 getMethod : function(){
4826 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4829 getParams : function(){
4830 var bp = this.form.baseParams;
4831 var p = this.options.params;
4833 if(typeof p == "object"){
4834 p = Roo.urlEncode(Roo.applyIf(p, bp));
4835 }else if(typeof p == 'string' && bp){
4836 p += '&' + Roo.urlEncode(bp);
4839 p = Roo.urlEncode(bp);
4844 createCallback : function(){
4846 success: this.success,
4847 failure: this.failure,
4849 timeout: (this.form.timeout*1000),
4850 upload: this.form.fileUpload ? this.success : undefined
4855 Roo.form.Action.Submit = function(form, options){
4856 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4859 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4862 haveProgress : false,
4863 uploadComplete : false,
4865 // uploadProgress indicator.
4866 uploadProgress : function()
4868 if (!this.form.progressUrl) {
4872 if (!this.haveProgress) {
4873 Roo.MessageBox.progress("Uploading", "Uploading");
4875 if (this.uploadComplete) {
4876 Roo.MessageBox.hide();
4880 this.haveProgress = true;
4882 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4884 var c = new Roo.data.Connection();
4886 url : this.form.progressUrl,
4891 success : function(req){
4892 //console.log(data);
4896 rdata = Roo.decode(req.responseText)
4898 Roo.log("Invalid data from server..");
4902 if (!rdata || !rdata.success) {
4904 Roo.MessageBox.alert(Roo.encode(rdata));
4907 var data = rdata.data;
4909 if (this.uploadComplete) {
4910 Roo.MessageBox.hide();
4915 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4916 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4919 this.uploadProgress.defer(2000,this);
4922 failure: function(data) {
4923 Roo.log('progress url failed ');
4934 // run get Values on the form, so it syncs any secondary forms.
4935 this.form.getValues();
4937 var o = this.options;
4938 var method = this.getMethod();
4939 var isPost = method == 'POST';
4940 if(o.clientValidation === false || this.form.isValid()){
4942 if (this.form.progressUrl) {
4943 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4944 (new Date() * 1) + '' + Math.random());
4949 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4950 form:this.form.el.dom,
4951 url:this.getUrl(!isPost),
4953 params:isPost ? this.getParams() : null,
4954 isUpload: this.form.fileUpload
4957 this.uploadProgress();
4959 }else if (o.clientValidation !== false){ // client validation failed
4960 this.failureType = Roo.form.Action.CLIENT_INVALID;
4961 this.form.afterAction(this, false);
4965 success : function(response)
4967 this.uploadComplete= true;
4968 if (this.haveProgress) {
4969 Roo.MessageBox.hide();
4973 var result = this.processResponse(response);
4974 if(result === true || result.success){
4975 this.form.afterAction(this, true);
4979 this.form.markInvalid(result.errors);
4980 this.failureType = Roo.form.Action.SERVER_INVALID;
4982 this.form.afterAction(this, false);
4984 failure : function(response)
4986 this.uploadComplete= true;
4987 if (this.haveProgress) {
4988 Roo.MessageBox.hide();
4991 this.response = response;
4992 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4993 this.form.afterAction(this, false);
4996 handleResponse : function(response){
4997 if(this.form.errorReader){
4998 var rs = this.form.errorReader.read(response);
5001 for(var i = 0, len = rs.records.length; i < len; i++) {
5002 var r = rs.records[i];
5006 if(errors.length < 1){
5010 success : rs.success,
5016 ret = Roo.decode(response.responseText);
5020 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5030 Roo.form.Action.Load = function(form, options){
5031 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5032 this.reader = this.form.reader;
5035 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5040 Roo.Ajax.request(Roo.apply(
5041 this.createCallback(), {
5042 method:this.getMethod(),
5043 url:this.getUrl(false),
5044 params:this.getParams()
5048 success : function(response){
5050 var result = this.processResponse(response);
5051 if(result === true || !result.success || !result.data){
5052 this.failureType = Roo.form.Action.LOAD_FAILURE;
5053 this.form.afterAction(this, false);
5056 this.form.clearInvalid();
5057 this.form.setValues(result.data);
5058 this.form.afterAction(this, true);
5061 handleResponse : function(response){
5062 if(this.form.reader){
5063 var rs = this.form.reader.read(response);
5064 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5066 success : rs.success,
5070 return Roo.decode(response.responseText);
5074 Roo.form.Action.ACTION_TYPES = {
5075 'load' : Roo.form.Action.Load,
5076 'submit' : Roo.form.Action.Submit
5085 * @class Roo.bootstrap.Form
5086 * @extends Roo.bootstrap.Component
5087 * Bootstrap Form class
5088 * @cfg {String} method GET | POST (default POST)
5089 * @cfg {String} labelAlign top | left (default top)
5090 * @cfg {String} align left | right - for navbars
5095 * @param {Object} config The config object
5099 Roo.bootstrap.Form = function(config){
5100 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5103 * @event clientvalidation
5104 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5105 * @param {Form} this
5106 * @param {Boolean} valid true if the form has passed client-side validation
5108 clientvalidation: true,
5110 * @event beforeaction
5111 * Fires before any action is performed. Return false to cancel the action.
5112 * @param {Form} this
5113 * @param {Action} action The action to be performed
5117 * @event actionfailed
5118 * Fires when an action fails.
5119 * @param {Form} this
5120 * @param {Action} action The action that failed
5122 actionfailed : true,
5124 * @event actioncomplete
5125 * Fires when an action is completed.
5126 * @param {Form} this
5127 * @param {Action} action The action that completed
5129 actioncomplete : true
5134 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5137 * @cfg {String} method
5138 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5143 * The URL to use for form actions if one isn't supplied in the action options.
5146 * @cfg {Boolean} fileUpload
5147 * Set to true if this form is a file upload.
5151 * @cfg {Object} baseParams
5152 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5156 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5160 * @cfg {Sting} align (left|right) for navbar forms
5165 activeAction : null,
5168 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5169 * element by passing it or its id or mask the form itself by passing in true.
5172 waitMsgTarget : false,
5177 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5178 * element by passing it or its id or mask the form itself by passing in true.
5182 getAutoCreate : function(){
5186 method : this.method || 'POST',
5187 id : this.id || Roo.id(),
5190 if (this.parent().xtype.match(/^Nav/)) {
5191 cfg.cls = 'navbar-form navbar-' + this.align;
5195 if (this.labelAlign == 'left' ) {
5196 cfg.cls += ' form-horizontal';
5202 initEvents : function()
5204 this.el.on('submit', this.onSubmit, this);
5209 onSubmit : function(e){
5214 * Returns true if client-side validation on the form is successful.
5217 isValid : function(){
5218 var items = this.getItems();
5220 items.each(function(f){
5229 * Returns true if any fields in this form have changed since their original load.
5232 isDirty : function(){
5234 var items = this.getItems();
5235 items.each(function(f){
5245 * Performs a predefined action (submit or load) or custom actions you define on this form.
5246 * @param {String} actionName The name of the action type
5247 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5248 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5249 * accept other config options):
5251 Property Type Description
5252 ---------------- --------------- ----------------------------------------------------------------------------------
5253 url String The url for the action (defaults to the form's url)
5254 method String The form method to use (defaults to the form's method, or POST if not defined)
5255 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5256 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5257 validate the form on the client (defaults to false)
5259 * @return {BasicForm} this
5261 doAction : function(action, options){
5262 if(typeof action == 'string'){
5263 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5265 if(this.fireEvent('beforeaction', this, action) !== false){
5266 this.beforeAction(action);
5267 action.run.defer(100, action);
5273 beforeAction : function(action){
5274 var o = action.options;
5276 // not really supported yet.. ??
5278 //if(this.waitMsgTarget === true){
5279 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5280 //}else if(this.waitMsgTarget){
5281 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5282 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5284 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5290 afterAction : function(action, success){
5291 this.activeAction = null;
5292 var o = action.options;
5294 //if(this.waitMsgTarget === true){
5296 //}else if(this.waitMsgTarget){
5297 // this.waitMsgTarget.unmask();
5299 // Roo.MessageBox.updateProgress(1);
5300 // Roo.MessageBox.hide();
5307 Roo.callback(o.success, o.scope, [this, action]);
5308 this.fireEvent('actioncomplete', this, action);
5312 // failure condition..
5313 // we have a scenario where updates need confirming.
5314 // eg. if a locking scenario exists..
5315 // we look for { errors : { needs_confirm : true }} in the response.
5317 (typeof(action.result) != 'undefined') &&
5318 (typeof(action.result.errors) != 'undefined') &&
5319 (typeof(action.result.errors.needs_confirm) != 'undefined')
5322 Roo.log("not supported yet");
5325 Roo.MessageBox.confirm(
5326 "Change requires confirmation",
5327 action.result.errorMsg,
5332 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5342 Roo.callback(o.failure, o.scope, [this, action]);
5343 // show an error message if no failed handler is set..
5344 if (!this.hasListener('actionfailed')) {
5345 Roo.log("need to add dialog support");
5347 Roo.MessageBox.alert("Error",
5348 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5349 action.result.errorMsg :
5350 "Saving Failed, please check your entries or try again"
5355 this.fireEvent('actionfailed', this, action);
5360 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5361 * @param {String} id The value to search for
5364 findField : function(id){
5365 var items = this.getItems();
5366 var field = items.get(id);
5368 items.each(function(f){
5369 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5376 return field || null;
5379 * Mark fields in this form invalid in bulk.
5380 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5381 * @return {BasicForm} this
5383 markInvalid : function(errors){
5384 if(errors instanceof Array){
5385 for(var i = 0, len = errors.length; i < len; i++){
5386 var fieldError = errors[i];
5387 var f = this.findField(fieldError.id);
5389 f.markInvalid(fieldError.msg);
5395 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5396 field.markInvalid(errors[id]);
5400 //Roo.each(this.childForms || [], function (f) {
5401 // f.markInvalid(errors);
5408 * Set values for fields in this form in bulk.
5409 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5410 * @return {BasicForm} this
5412 setValues : function(values){
5413 if(values instanceof Array){ // array of objects
5414 for(var i = 0, len = values.length; i < len; i++){
5416 var f = this.findField(v.id);
5418 f.setValue(v.value);
5419 if(this.trackResetOnLoad){
5420 f.originalValue = f.getValue();
5424 }else{ // object hash
5427 if(typeof values[id] != 'function' && (field = this.findField(id))){
5429 if (field.setFromData &&
5431 field.displayField &&
5432 // combos' with local stores can
5433 // be queried via setValue()
5434 // to set their value..
5435 (field.store && !field.store.isLocal)
5439 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5440 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5441 field.setFromData(sd);
5444 field.setValue(values[id]);
5448 if(this.trackResetOnLoad){
5449 field.originalValue = field.getValue();
5455 //Roo.each(this.childForms || [], function (f) {
5456 // f.setValues(values);
5463 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5464 * they are returned as an array.
5465 * @param {Boolean} asString
5468 getValues : function(asString){
5469 //if (this.childForms) {
5470 // copy values from the child forms
5471 // Roo.each(this.childForms, function (f) {
5472 // this.setValues(f.getValues());
5478 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5479 if(asString === true){
5482 return Roo.urlDecode(fs);
5486 * Returns the fields in this form as an object with key/value pairs.
5487 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5490 getFieldValues : function(with_hidden)
5492 var items = this.getItems();
5494 items.each(function(f){
5498 var v = f.getValue();
5499 if (f.inputType =='radio') {
5500 if (typeof(ret[f.getName()]) == 'undefined') {
5501 ret[f.getName()] = ''; // empty..
5504 if (!f.el.dom.checked) {
5512 // not sure if this supported any more..
5513 if ((typeof(v) == 'object') && f.getRawValue) {
5514 v = f.getRawValue() ; // dates..
5516 // combo boxes where name != hiddenName...
5517 if (f.name != f.getName()) {
5518 ret[f.name] = f.getRawValue();
5520 ret[f.getName()] = v;
5527 * Clears all invalid messages in this form.
5528 * @return {BasicForm} this
5530 clearInvalid : function(){
5531 var items = this.getItems();
5533 items.each(function(f){
5544 * @return {BasicForm} this
5547 var items = this.getItems();
5548 items.each(function(f){
5552 Roo.each(this.childForms || [], function (f) {
5559 getItems : function()
5561 var r=new Roo.util.MixedCollection(false, function(o){
5562 return o.id || (o.id = Roo.id());
5564 var iter = function(el) {
5571 Roo.each(el.items,function(e) {
5590 * Ext JS Library 1.1.1
5591 * Copyright(c) 2006-2007, Ext JS, LLC.
5593 * Originally Released Under LGPL - original licence link has changed is not relivant.
5596 * <script type="text/javascript">
5599 * @class Roo.form.VTypes
5600 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5603 Roo.form.VTypes = function(){
5604 // closure these in so they are only created once.
5605 var alpha = /^[a-zA-Z_]+$/;
5606 var alphanum = /^[a-zA-Z0-9_]+$/;
5607 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5608 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5610 // All these messages and functions are configurable
5613 * The function used to validate email addresses
5614 * @param {String} value The email address
5616 'email' : function(v){
5617 return email.test(v);
5620 * The error text to display when the email validation function returns false
5623 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5625 * The keystroke filter mask to be applied on email input
5628 'emailMask' : /[a-z0-9_\.\-@]/i,
5631 * The function used to validate URLs
5632 * @param {String} value The URL
5634 'url' : function(v){
5638 * The error text to display when the url validation function returns false
5641 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5644 * The function used to validate alpha values
5645 * @param {String} value The value
5647 'alpha' : function(v){
5648 return alpha.test(v);
5651 * The error text to display when the alpha validation function returns false
5654 'alphaText' : 'This field should only contain letters and _',
5656 * The keystroke filter mask to be applied on alpha input
5659 'alphaMask' : /[a-z_]/i,
5662 * The function used to validate alphanumeric values
5663 * @param {String} value The value
5665 'alphanum' : function(v){
5666 return alphanum.test(v);
5669 * The error text to display when the alphanumeric validation function returns false
5672 'alphanumText' : 'This field should only contain letters, numbers and _',
5674 * The keystroke filter mask to be applied on alphanumeric input
5677 'alphanumMask' : /[a-z0-9_]/i
5687 * @class Roo.bootstrap.Input
5688 * @extends Roo.bootstrap.Component
5689 * Bootstrap Input class
5690 * @cfg {Boolean} disabled is it disabled
5691 * @cfg {String} fieldLabel - the label associated
5692 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5693 * @cfg {String} name name of the input
5694 * @cfg {string} fieldLabel - the label associated
5695 * @cfg {string} inputType - input / file submit ...
5696 * @cfg {string} placeholder - placeholder to put in text.
5697 * @cfg {string} before - input group add on before
5698 * @cfg {string} after - input group add on after
5699 * @cfg {string} size - (lg|sm) or leave empty..
5700 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5701 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5702 * @cfg {Number} md colspan out of 12 for computer-sized screens
5703 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5704 * @cfg {string} value default value of the input
5705 * @cfg {Number} labelWidth set the width of label (0-12)
5706 * @cfg {String} labelAlign (top|left)
5707 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5711 * Create a new Input
5712 * @param {Object} config The config object
5715 Roo.bootstrap.Input = function(config){
5716 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5721 * Fires when this field receives input focus.
5722 * @param {Roo.form.Field} this
5727 * Fires when this field loses input focus.
5728 * @param {Roo.form.Field} this
5733 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5734 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5735 * @param {Roo.form.Field} this
5736 * @param {Roo.EventObject} e The event object
5741 * Fires just before the field blurs if the field value has changed.
5742 * @param {Roo.form.Field} this
5743 * @param {Mixed} newValue The new value
5744 * @param {Mixed} oldValue The original value
5749 * Fires after the field has been marked as invalid.
5750 * @param {Roo.form.Field} this
5751 * @param {String} msg The validation message
5756 * Fires after the field has been validated with no errors.
5757 * @param {Roo.form.Field} this
5762 * Fires after the key up
5763 * @param {Roo.form.Field} this
5764 * @param {Roo.EventObject} e The event Object
5770 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5772 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5773 automatic validation (defaults to "keyup").
5775 validationEvent : "keyup",
5777 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5779 validateOnBlur : true,
5781 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5783 validationDelay : 250,
5785 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5787 focusClass : "x-form-focus", // not needed???
5791 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5793 invalidClass : "has-error",
5796 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5798 selectOnFocus : false,
5801 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5805 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5810 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5812 disableKeyFilter : false,
5815 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5819 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5823 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5825 blankText : "This field is required",
5828 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5832 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5834 maxLength : Number.MAX_VALUE,
5836 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5838 minLengthText : "The minimum length for this field is {0}",
5840 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5842 maxLengthText : "The maximum length for this field is {0}",
5846 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5847 * If available, this function will be called only after the basic validators all return true, and will be passed the
5848 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5852 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5853 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5854 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5858 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5881 parentLabelAlign : function()
5884 while (parent.parent()) {
5885 parent = parent.parent();
5886 if (typeof(parent.labelAlign) !='undefined') {
5887 return parent.labelAlign;
5894 getAutoCreate : function(){
5896 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5902 if(this.inputType != 'hidden'){
5903 cfg.cls = 'form-group' //input-group
5909 type : this.inputType,
5911 cls : 'form-control',
5912 placeholder : this.placeholder || ''
5916 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5917 input.maxLength = this.maxLength;
5920 if (this.disabled) {
5921 input.disabled=true;
5924 if (this.readOnly) {
5925 input.readonly=true;
5929 input.name = this.name;
5932 input.cls += ' input-' + this.size;
5935 ['xs','sm','md','lg'].map(function(size){
5936 if (settings[size]) {
5937 cfg.cls += ' col-' + size + '-' + settings[size];
5941 var inputblock = input;
5943 if (this.before || this.after) {
5946 cls : 'input-group',
5949 if (this.before && typeof(this.before) == 'string') {
5951 inputblock.cn.push({
5953 cls : 'roo-input-before input-group-addon',
5957 if (this.before && typeof(this.before) == 'object') {
5958 this.before = Roo.factory(this.before);
5959 Roo.log(this.before);
5960 inputblock.cn.push({
5962 cls : 'roo-input-before input-group-' +
5963 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5967 inputblock.cn.push(input);
5969 if (this.after && typeof(this.after) == 'string') {
5970 inputblock.cn.push({
5972 cls : 'roo-input-after input-group-addon',
5976 if (this.after && typeof(this.after) == 'object') {
5977 this.after = Roo.factory(this.after);
5978 Roo.log(this.after);
5979 inputblock.cn.push({
5981 cls : 'roo-input-after input-group-' +
5982 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5987 if (align ==='left' && this.fieldLabel.length) {
5988 Roo.log("left and has label");
5994 cls : 'control-label col-sm-' + this.labelWidth,
5995 html : this.fieldLabel
5999 cls : "col-sm-" + (12 - this.labelWidth),
6006 } else if ( this.fieldLabel.length) {
6012 //cls : 'input-group-addon',
6013 html : this.fieldLabel
6023 Roo.log(" no label && no align");
6032 Roo.log('input-parentType: ' + this.parentType);
6034 if (this.parentType === 'Navbar' && this.parent().bar) {
6035 cfg.cls += ' navbar-form';
6043 * return the real input element.
6045 inputEl: function ()
6047 return this.el.select('input.form-control',true).first();
6049 setDisabled : function(v)
6051 var i = this.inputEl().dom;
6053 i.removeAttribute('disabled');
6057 i.setAttribute('disabled','true');
6059 initEvents : function()
6062 this.inputEl().on("keydown" , this.fireKey, this);
6063 this.inputEl().on("focus", this.onFocus, this);
6064 this.inputEl().on("blur", this.onBlur, this);
6066 this.inputEl().relayEvent('keyup', this);
6068 // reference to original value for reset
6069 this.originalValue = this.getValue();
6070 //Roo.form.TextField.superclass.initEvents.call(this);
6071 if(this.validationEvent == 'keyup'){
6072 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6073 this.inputEl().on('keyup', this.filterValidation, this);
6075 else if(this.validationEvent !== false){
6076 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6079 if(this.selectOnFocus){
6080 this.on("focus", this.preFocus, this);
6083 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6084 this.inputEl().on("keypress", this.filterKeys, this);
6087 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6088 this.el.on("click", this.autoSize, this);
6091 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6092 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6095 if (typeof(this.before) == 'object') {
6096 this.before.render(this.el.select('.roo-input-before',true).first());
6098 if (typeof(this.after) == 'object') {
6099 this.after.render(this.el.select('.roo-input-after',true).first());
6104 filterValidation : function(e){
6105 if(!e.isNavKeyPress()){
6106 this.validationTask.delay(this.validationDelay);
6110 * Validates the field value
6111 * @return {Boolean} True if the value is valid, else false
6113 validate : function(){
6114 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6115 if(this.disabled || this.validateValue(this.getRawValue())){
6116 this.clearInvalid();
6124 * Validates a value according to the field's validation rules and marks the field as invalid
6125 * if the validation fails
6126 * @param {Mixed} value The value to validate
6127 * @return {Boolean} True if the value is valid, else false
6129 validateValue : function(value){
6130 if(value.length < 1) { // if it's blank
6131 if(this.allowBlank){
6132 this.clearInvalid();
6135 this.markInvalid(this.blankText);
6139 if(value.length < this.minLength){
6140 this.markInvalid(String.format(this.minLengthText, this.minLength));
6143 if(value.length > this.maxLength){
6144 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6148 var vt = Roo.form.VTypes;
6149 if(!vt[this.vtype](value, this)){
6150 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6154 if(typeof this.validator == "function"){
6155 var msg = this.validator(value);
6157 this.markInvalid(msg);
6161 if(this.regex && !this.regex.test(value)){
6162 this.markInvalid(this.regexText);
6171 fireKey : function(e){
6172 //Roo.log('field ' + e.getKey());
6173 if(e.isNavKeyPress()){
6174 this.fireEvent("specialkey", this, e);
6177 focus : function (selectText){
6179 this.inputEl().focus();
6180 if(selectText === true){
6181 this.inputEl().dom.select();
6187 onFocus : function(){
6188 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6189 // this.el.addClass(this.focusClass);
6192 this.hasFocus = true;
6193 this.startValue = this.getValue();
6194 this.fireEvent("focus", this);
6198 beforeBlur : Roo.emptyFn,
6202 onBlur : function(){
6204 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6205 //this.el.removeClass(this.focusClass);
6207 this.hasFocus = false;
6208 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6211 var v = this.getValue();
6212 if(String(v) !== String(this.startValue)){
6213 this.fireEvent('change', this, v, this.startValue);
6215 this.fireEvent("blur", this);
6219 * Resets the current field value to the originally loaded value and clears any validation messages
6222 this.setValue(this.originalValue);
6223 this.clearInvalid();
6226 * Returns the name of the field
6227 * @return {Mixed} name The name field
6229 getName: function(){
6233 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6234 * @return {Mixed} value The field value
6236 getValue : function(){
6237 return this.inputEl().getValue();
6240 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6241 * @return {Mixed} value The field value
6243 getRawValue : function(){
6244 var v = this.inputEl().getValue();
6250 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6251 * @param {Mixed} value The value to set
6253 setRawValue : function(v){
6254 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6257 selectText : function(start, end){
6258 var v = this.getRawValue();
6260 start = start === undefined ? 0 : start;
6261 end = end === undefined ? v.length : end;
6262 var d = this.inputEl().dom;
6263 if(d.setSelectionRange){
6264 d.setSelectionRange(start, end);
6265 }else if(d.createTextRange){
6266 var range = d.createTextRange();
6267 range.moveStart("character", start);
6268 range.moveEnd("character", v.length-end);
6275 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6276 * @param {Mixed} value The value to set
6278 setValue : function(v){
6281 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6287 processValue : function(value){
6288 if(this.stripCharsRe){
6289 var newValue = value.replace(this.stripCharsRe, '');
6290 if(newValue !== value){
6291 this.setRawValue(newValue);
6298 preFocus : function(){
6300 if(this.selectOnFocus){
6301 this.inputEl().dom.select();
6304 filterKeys : function(e){
6306 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6309 var c = e.getCharCode(), cc = String.fromCharCode(c);
6310 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6313 if(!this.maskRe.test(cc)){
6318 * Clear any invalid styles/messages for this field
6320 clearInvalid : function(){
6322 if(!this.el || this.preventMark){ // not rendered
6325 this.el.removeClass(this.invalidClass);
6327 switch(this.msgTarget){
6329 this.el.dom.qtip = '';
6332 this.el.dom.title = '';
6336 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6341 this.errorIcon.dom.qtip = '';
6342 this.errorIcon.hide();
6343 this.un('resize', this.alignErrorIcon, this);
6347 var t = Roo.getDom(this.msgTarget);
6349 t.style.display = 'none';
6353 this.fireEvent('valid', this);
6356 * Mark this field as invalid
6357 * @param {String} msg The validation message
6359 markInvalid : function(msg){
6360 if(!this.el || this.preventMark){ // not rendered
6363 this.el.addClass(this.invalidClass);
6365 msg = msg || this.invalidText;
6366 switch(this.msgTarget){
6368 this.el.dom.qtip = msg;
6369 this.el.dom.qclass = 'x-form-invalid-tip';
6370 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6371 Roo.QuickTips.enable();
6375 this.el.dom.title = msg;
6379 var elp = this.el.findParent('.x-form-element', 5, true);
6380 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6381 this.errorEl.setWidth(elp.getWidth(true)-20);
6383 this.errorEl.update(msg);
6384 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6387 if(!this.errorIcon){
6388 var elp = this.el.findParent('.x-form-element', 5, true);
6389 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6391 this.alignErrorIcon();
6392 this.errorIcon.dom.qtip = msg;
6393 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6394 this.errorIcon.show();
6395 this.on('resize', this.alignErrorIcon, this);
6398 var t = Roo.getDom(this.msgTarget);
6400 t.style.display = this.msgDisplay;
6404 this.fireEvent('invalid', this, msg);
6407 SafariOnKeyDown : function(event)
6409 // this is a workaround for a password hang bug on chrome/ webkit.
6411 var isSelectAll = false;
6413 if(this.inputEl().dom.selectionEnd > 0){
6414 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6416 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6417 event.preventDefault();
6422 if(isSelectAll){ // backspace and delete key
6424 event.preventDefault();
6425 // this is very hacky as keydown always get's upper case.
6427 var cc = String.fromCharCode(event.getCharCode());
6428 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6432 adjustWidth : function(tag, w){
6433 tag = tag.toLowerCase();
6434 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6435 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6439 if(tag == 'textarea'){
6442 }else if(Roo.isOpera){
6446 if(tag == 'textarea'){
6465 * @class Roo.bootstrap.TextArea
6466 * @extends Roo.bootstrap.Input
6467 * Bootstrap TextArea class
6468 * @cfg {Number} cols Specifies the visible width of a text area
6469 * @cfg {Number} rows Specifies the visible number of lines in a text area
6470 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6471 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6472 * @cfg {string} html text
6475 * Create a new TextArea
6476 * @param {Object} config The config object
6479 Roo.bootstrap.TextArea = function(config){
6480 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6484 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6494 getAutoCreate : function(){
6496 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6507 value : this.value || '',
6508 html: this.html || '',
6509 cls : 'form-control',
6510 placeholder : this.placeholder || ''
6514 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6515 input.maxLength = this.maxLength;
6519 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6523 input.cols = this.cols;
6526 if (this.readOnly) {
6527 input.readonly = true;
6531 input.name = this.name;
6535 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6539 ['xs','sm','md','lg'].map(function(size){
6540 if (settings[size]) {
6541 cfg.cls += ' col-' + size + '-' + settings[size];
6545 var inputblock = input;
6547 if (this.before || this.after) {
6550 cls : 'input-group',
6554 inputblock.cn.push({
6556 cls : 'input-group-addon',
6560 inputblock.cn.push(input);
6562 inputblock.cn.push({
6564 cls : 'input-group-addon',
6571 if (align ==='left' && this.fieldLabel.length) {
6572 Roo.log("left and has label");
6578 cls : 'control-label col-sm-' + this.labelWidth,
6579 html : this.fieldLabel
6583 cls : "col-sm-" + (12 - this.labelWidth),
6590 } else if ( this.fieldLabel.length) {
6596 //cls : 'input-group-addon',
6597 html : this.fieldLabel
6607 Roo.log(" no label && no align");
6617 if (this.disabled) {
6618 input.disabled=true;
6625 * return the real textarea element.
6627 inputEl: function ()
6629 return this.el.select('textarea.form-control',true).first();
6637 * trigger field - base class for combo..
6642 * @class Roo.bootstrap.TriggerField
6643 * @extends Roo.bootstrap.Input
6644 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6645 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6646 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6647 * for which you can provide a custom implementation. For example:
6649 var trigger = new Roo.bootstrap.TriggerField();
6650 trigger.onTriggerClick = myTriggerFn;
6651 trigger.applyTo('my-field');
6654 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6655 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6656 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6657 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6659 * Create a new TriggerField.
6660 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6661 * to the base TextField)
6663 Roo.bootstrap.TriggerField = function(config){
6664 this.mimicing = false;
6665 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6668 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6670 * @cfg {String} triggerClass A CSS class to apply to the trigger
6673 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6677 /** @cfg {Boolean} grow @hide */
6678 /** @cfg {Number} growMin @hide */
6679 /** @cfg {Number} growMax @hide */
6685 autoSize: Roo.emptyFn,
6692 actionMode : 'wrap',
6696 getAutoCreate : function(){
6698 var parent = this.parent();
6700 var align = this.labelAlign || this.parentLabelAlign();
6705 cls: 'form-group' //input-group
6712 type : this.inputType,
6713 cls : 'form-control',
6714 autocomplete: 'off',
6715 placeholder : this.placeholder || ''
6719 input.name = this.name;
6722 input.cls += ' input-' + this.size;
6725 if (this.disabled) {
6726 input.disabled=true;
6729 var inputblock = input;
6731 if (this.before || this.after) {
6734 cls : 'input-group',
6738 inputblock.cn.push({
6740 cls : 'input-group-addon',
6744 inputblock.cn.push(input);
6746 inputblock.cn.push({
6748 cls : 'input-group-addon',
6761 cls: 'form-hidden-field'
6769 Roo.log('multiple');
6777 cls: 'form-hidden-field'
6781 cls: 'select2-choices',
6785 cls: 'select2-search-field',
6798 cls: 'select2-container input-group',
6803 cls: 'typeahead typeahead-long dropdown-menu',
6804 style: 'display:none'
6812 cls : 'input-group-addon btn dropdown-toggle',
6820 cls: 'combobox-clear',
6834 combobox.cls += ' select2-container-multi';
6837 if (align ==='left' && this.fieldLabel.length) {
6839 Roo.log("left and has label");
6845 cls : 'control-label col-sm-' + this.labelWidth,
6846 html : this.fieldLabel
6850 cls : "col-sm-" + (12 - this.labelWidth),
6857 } else if ( this.fieldLabel.length) {
6863 //cls : 'input-group-addon',
6864 html : this.fieldLabel
6874 Roo.log(" no label && no align");
6881 ['xs','sm','md','lg'].map(function(size){
6882 if (settings[size]) {
6883 cfg.cls += ' col-' + size + '-' + settings[size];
6894 onResize : function(w, h){
6895 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6896 // if(typeof w == 'number'){
6897 // var x = w - this.trigger.getWidth();
6898 // this.inputEl().setWidth(this.adjustWidth('input', x));
6899 // this.trigger.setStyle('left', x+'px');
6904 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6907 getResizeEl : function(){
6908 return this.inputEl();
6912 getPositionEl : function(){
6913 return this.inputEl();
6917 alignErrorIcon : function(){
6918 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6922 initEvents : function(){
6924 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6925 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6927 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6928 if(this.hideTrigger){
6929 this.trigger.setDisplayed(false);
6931 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6935 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6938 //this.trigger.addClassOnOver('x-form-trigger-over');
6939 //this.trigger.addClassOnClick('x-form-trigger-click');
6942 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6947 initTrigger : function(){
6952 onDestroy : function(){
6954 this.trigger.removeAllListeners();
6955 // this.trigger.remove();
6958 // this.wrap.remove();
6960 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6964 onFocus : function(){
6965 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6968 this.wrap.addClass('x-trigger-wrap-focus');
6969 this.mimicing = true;
6970 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6971 if(this.monitorTab){
6972 this.el.on("keydown", this.checkTab, this);
6979 checkTab : function(e){
6980 if(e.getKey() == e.TAB){
6986 onBlur : function(){
6991 mimicBlur : function(e, t){
6993 if(!this.wrap.contains(t) && this.validateBlur()){
7000 triggerBlur : function(){
7001 this.mimicing = false;
7002 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7003 if(this.monitorTab){
7004 this.el.un("keydown", this.checkTab, this);
7006 //this.wrap.removeClass('x-trigger-wrap-focus');
7007 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7011 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7012 validateBlur : function(e, t){
7017 onDisable : function(){
7018 this.inputEl().dom.disabled = true;
7019 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7021 // this.wrap.addClass('x-item-disabled');
7026 onEnable : function(){
7027 this.inputEl().dom.disabled = false;
7028 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7030 // this.el.removeClass('x-item-disabled');
7035 onShow : function(){
7036 var ae = this.getActionEl();
7039 ae.dom.style.display = '';
7040 ae.dom.style.visibility = 'visible';
7046 onHide : function(){
7047 var ae = this.getActionEl();
7048 ae.dom.style.display = 'none';
7052 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7053 * by an implementing function.
7055 * @param {EventObject} e
7057 onTriggerClick : Roo.emptyFn
7061 * Ext JS Library 1.1.1
7062 * Copyright(c) 2006-2007, Ext JS, LLC.
7064 * Originally Released Under LGPL - original licence link has changed is not relivant.
7067 * <script type="text/javascript">
7072 * @class Roo.data.SortTypes
7074 * Defines the default sorting (casting?) comparison functions used when sorting data.
7076 Roo.data.SortTypes = {
7078 * Default sort that does nothing
7079 * @param {Mixed} s The value being converted
7080 * @return {Mixed} The comparison value
7087 * The regular expression used to strip tags
7091 stripTagsRE : /<\/?[^>]+>/gi,
7094 * Strips all HTML tags to sort on text only
7095 * @param {Mixed} s The value being converted
7096 * @return {String} The comparison value
7098 asText : function(s){
7099 return String(s).replace(this.stripTagsRE, "");
7103 * Strips all HTML tags to sort on text only - Case insensitive
7104 * @param {Mixed} s The value being converted
7105 * @return {String} The comparison value
7107 asUCText : function(s){
7108 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7112 * Case insensitive string
7113 * @param {Mixed} s The value being converted
7114 * @return {String} The comparison value
7116 asUCString : function(s) {
7117 return String(s).toUpperCase();
7122 * @param {Mixed} s The value being converted
7123 * @return {Number} The comparison value
7125 asDate : function(s) {
7129 if(s instanceof Date){
7132 return Date.parse(String(s));
7137 * @param {Mixed} s The value being converted
7138 * @return {Float} The comparison value
7140 asFloat : function(s) {
7141 var val = parseFloat(String(s).replace(/,/g, ""));
7142 if(isNaN(val)) val = 0;
7148 * @param {Mixed} s The value being converted
7149 * @return {Number} The comparison value
7151 asInt : function(s) {
7152 var val = parseInt(String(s).replace(/,/g, ""));
7153 if(isNaN(val)) val = 0;
7158 * Ext JS Library 1.1.1
7159 * Copyright(c) 2006-2007, Ext JS, LLC.
7161 * Originally Released Under LGPL - original licence link has changed is not relivant.
7164 * <script type="text/javascript">
7168 * @class Roo.data.Record
7169 * Instances of this class encapsulate both record <em>definition</em> information, and record
7170 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7171 * to access Records cached in an {@link Roo.data.Store} object.<br>
7173 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7174 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7177 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7179 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7180 * {@link #create}. The parameters are the same.
7181 * @param {Array} data An associative Array of data values keyed by the field name.
7182 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7183 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7184 * not specified an integer id is generated.
7186 Roo.data.Record = function(data, id){
7187 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7192 * Generate a constructor for a specific record layout.
7193 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7194 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7195 * Each field definition object may contain the following properties: <ul>
7196 * <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,
7197 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7198 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7199 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7200 * is being used, then this is a string containing the javascript expression to reference the data relative to
7201 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7202 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7203 * this may be omitted.</p></li>
7204 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7205 * <ul><li>auto (Default, implies no conversion)</li>
7210 * <li>date</li></ul></p></li>
7211 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7212 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7213 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7214 * by the Reader into an object that will be stored in the Record. It is passed the
7215 * following parameters:<ul>
7216 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7218 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7220 * <br>usage:<br><pre><code>
7221 var TopicRecord = Roo.data.Record.create(
7222 {name: 'title', mapping: 'topic_title'},
7223 {name: 'author', mapping: 'username'},
7224 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7225 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7226 {name: 'lastPoster', mapping: 'user2'},
7227 {name: 'excerpt', mapping: 'post_text'}
7230 var myNewRecord = new TopicRecord({
7231 title: 'Do my job please',
7234 lastPost: new Date(),
7235 lastPoster: 'Animal',
7236 excerpt: 'No way dude!'
7238 myStore.add(myNewRecord);
7243 Roo.data.Record.create = function(o){
7245 f.superclass.constructor.apply(this, arguments);
7247 Roo.extend(f, Roo.data.Record);
7248 var p = f.prototype;
7249 p.fields = new Roo.util.MixedCollection(false, function(field){
7252 for(var i = 0, len = o.length; i < len; i++){
7253 p.fields.add(new Roo.data.Field(o[i]));
7255 f.getField = function(name){
7256 return p.fields.get(name);
7261 Roo.data.Record.AUTO_ID = 1000;
7262 Roo.data.Record.EDIT = 'edit';
7263 Roo.data.Record.REJECT = 'reject';
7264 Roo.data.Record.COMMIT = 'commit';
7266 Roo.data.Record.prototype = {
7268 * Readonly flag - true if this record has been modified.
7277 join : function(store){
7282 * Set the named field to the specified value.
7283 * @param {String} name The name of the field to set.
7284 * @param {Object} value The value to set the field to.
7286 set : function(name, value){
7287 if(this.data[name] == value){
7294 if(typeof this.modified[name] == 'undefined'){
7295 this.modified[name] = this.data[name];
7297 this.data[name] = value;
7298 if(!this.editing && this.store){
7299 this.store.afterEdit(this);
7304 * Get the value of the named field.
7305 * @param {String} name The name of the field to get the value of.
7306 * @return {Object} The value of the field.
7308 get : function(name){
7309 return this.data[name];
7313 beginEdit : function(){
7314 this.editing = true;
7319 cancelEdit : function(){
7320 this.editing = false;
7321 delete this.modified;
7325 endEdit : function(){
7326 this.editing = false;
7327 if(this.dirty && this.store){
7328 this.store.afterEdit(this);
7333 * Usually called by the {@link Roo.data.Store} which owns the Record.
7334 * Rejects all changes made to the Record since either creation, or the last commit operation.
7335 * Modified fields are reverted to their original values.
7337 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7338 * of reject operations.
7340 reject : function(){
7341 var m = this.modified;
7343 if(typeof m[n] != "function"){
7344 this.data[n] = m[n];
7348 delete this.modified;
7349 this.editing = false;
7351 this.store.afterReject(this);
7356 * Usually called by the {@link Roo.data.Store} which owns the Record.
7357 * Commits all changes made to the Record since either creation, or the last commit operation.
7359 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7360 * of commit operations.
7362 commit : function(){
7364 delete this.modified;
7365 this.editing = false;
7367 this.store.afterCommit(this);
7372 hasError : function(){
7373 return this.error != null;
7377 clearError : function(){
7382 * Creates a copy of this record.
7383 * @param {String} id (optional) A new record id if you don't want to use this record's id
7386 copy : function(newId) {
7387 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7391 * Ext JS Library 1.1.1
7392 * Copyright(c) 2006-2007, Ext JS, LLC.
7394 * Originally Released Under LGPL - original licence link has changed is not relivant.
7397 * <script type="text/javascript">
7403 * @class Roo.data.Store
7404 * @extends Roo.util.Observable
7405 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7406 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7408 * 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
7409 * has no knowledge of the format of the data returned by the Proxy.<br>
7411 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7412 * instances from the data object. These records are cached and made available through accessor functions.
7414 * Creates a new Store.
7415 * @param {Object} config A config object containing the objects needed for the Store to access data,
7416 * and read the data into Records.
7418 Roo.data.Store = function(config){
7419 this.data = new Roo.util.MixedCollection(false);
7420 this.data.getKey = function(o){
7423 this.baseParams = {};
7430 "multisort" : "_multisort"
7433 if(config && config.data){
7434 this.inlineData = config.data;
7438 Roo.apply(this, config);
7440 if(this.reader){ // reader passed
7441 this.reader = Roo.factory(this.reader, Roo.data);
7442 this.reader.xmodule = this.xmodule || false;
7443 if(!this.recordType){
7444 this.recordType = this.reader.recordType;
7446 if(this.reader.onMetaChange){
7447 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7451 if(this.recordType){
7452 this.fields = this.recordType.prototype.fields;
7458 * @event datachanged
7459 * Fires when the data cache has changed, and a widget which is using this Store
7460 * as a Record cache should refresh its view.
7461 * @param {Store} this
7466 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7467 * @param {Store} this
7468 * @param {Object} meta The JSON metadata
7473 * Fires when Records have been added to the Store
7474 * @param {Store} this
7475 * @param {Roo.data.Record[]} records The array of Records added
7476 * @param {Number} index The index at which the record(s) were added
7481 * Fires when a Record has been removed from the Store
7482 * @param {Store} this
7483 * @param {Roo.data.Record} record The Record that was removed
7484 * @param {Number} index The index at which the record was removed
7489 * Fires when a Record has been updated
7490 * @param {Store} this
7491 * @param {Roo.data.Record} record The Record that was updated
7492 * @param {String} operation The update operation being performed. Value may be one of:
7494 Roo.data.Record.EDIT
7495 Roo.data.Record.REJECT
7496 Roo.data.Record.COMMIT
7502 * Fires when the data cache has been cleared.
7503 * @param {Store} this
7508 * Fires before a request is made for a new data object. If the beforeload handler returns false
7509 * the load action will be canceled.
7510 * @param {Store} this
7511 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7515 * @event beforeloadadd
7516 * Fires after a new set of Records has been loaded.
7517 * @param {Store} this
7518 * @param {Roo.data.Record[]} records The Records that were loaded
7519 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7521 beforeloadadd : true,
7524 * Fires after a new set of Records has been loaded, before they are added to the store.
7525 * @param {Store} this
7526 * @param {Roo.data.Record[]} records The Records that were loaded
7527 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7528 * @params {Object} return from reader
7532 * @event loadexception
7533 * Fires if an exception occurs in the Proxy during loading.
7534 * Called with the signature of the Proxy's "loadexception" event.
7535 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7538 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7539 * @param {Object} load options
7540 * @param {Object} jsonData from your request (normally this contains the Exception)
7542 loadexception : true
7546 this.proxy = Roo.factory(this.proxy, Roo.data);
7547 this.proxy.xmodule = this.xmodule || false;
7548 this.relayEvents(this.proxy, ["loadexception"]);
7550 this.sortToggle = {};
7551 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7553 Roo.data.Store.superclass.constructor.call(this);
7555 if(this.inlineData){
7556 this.loadData(this.inlineData);
7557 delete this.inlineData;
7561 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7563 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7564 * without a remote query - used by combo/forms at present.
7568 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7571 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7574 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7575 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7578 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7579 * on any HTTP request
7582 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7585 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7589 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7590 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7595 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7596 * loaded or when a record is removed. (defaults to false).
7598 pruneModifiedRecords : false,
7604 * Add Records to the Store and fires the add event.
7605 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7607 add : function(records){
7608 records = [].concat(records);
7609 for(var i = 0, len = records.length; i < len; i++){
7610 records[i].join(this);
7612 var index = this.data.length;
7613 this.data.addAll(records);
7614 this.fireEvent("add", this, records, index);
7618 * Remove a Record from the Store and fires the remove event.
7619 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7621 remove : function(record){
7622 var index = this.data.indexOf(record);
7623 this.data.removeAt(index);
7624 if(this.pruneModifiedRecords){
7625 this.modified.remove(record);
7627 this.fireEvent("remove", this, record, index);
7631 * Remove all Records from the Store and fires the clear event.
7633 removeAll : function(){
7635 if(this.pruneModifiedRecords){
7638 this.fireEvent("clear", this);
7642 * Inserts Records to the Store at the given index and fires the add event.
7643 * @param {Number} index The start index at which to insert the passed Records.
7644 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7646 insert : function(index, records){
7647 records = [].concat(records);
7648 for(var i = 0, len = records.length; i < len; i++){
7649 this.data.insert(index, records[i]);
7650 records[i].join(this);
7652 this.fireEvent("add", this, records, index);
7656 * Get the index within the cache of the passed Record.
7657 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7658 * @return {Number} The index of the passed Record. Returns -1 if not found.
7660 indexOf : function(record){
7661 return this.data.indexOf(record);
7665 * Get the index within the cache of the Record with the passed id.
7666 * @param {String} id The id of the Record to find.
7667 * @return {Number} The index of the Record. Returns -1 if not found.
7669 indexOfId : function(id){
7670 return this.data.indexOfKey(id);
7674 * Get the Record with the specified id.
7675 * @param {String} id The id of the Record to find.
7676 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7678 getById : function(id){
7679 return this.data.key(id);
7683 * Get the Record at the specified index.
7684 * @param {Number} index The index of the Record to find.
7685 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7687 getAt : function(index){
7688 return this.data.itemAt(index);
7692 * Returns a range of Records between specified indices.
7693 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7694 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7695 * @return {Roo.data.Record[]} An array of Records
7697 getRange : function(start, end){
7698 return this.data.getRange(start, end);
7702 storeOptions : function(o){
7703 o = Roo.apply({}, o);
7706 this.lastOptions = o;
7710 * Loads the Record cache from the configured Proxy using the configured Reader.
7712 * If using remote paging, then the first load call must specify the <em>start</em>
7713 * and <em>limit</em> properties in the options.params property to establish the initial
7714 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7716 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7717 * and this call will return before the new data has been loaded. Perform any post-processing
7718 * in a callback function, or in a "load" event handler.</strong>
7720 * @param {Object} options An object containing properties which control loading options:<ul>
7721 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7722 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7723 * passed the following arguments:<ul>
7724 * <li>r : Roo.data.Record[]</li>
7725 * <li>options: Options object from the load call</li>
7726 * <li>success: Boolean success indicator</li></ul></li>
7727 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7728 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7731 load : function(options){
7732 options = options || {};
7733 if(this.fireEvent("beforeload", this, options) !== false){
7734 this.storeOptions(options);
7735 var p = Roo.apply(options.params || {}, this.baseParams);
7736 // if meta was not loaded from remote source.. try requesting it.
7737 if (!this.reader.metaFromRemote) {
7740 if(this.sortInfo && this.remoteSort){
7741 var pn = this.paramNames;
7742 p[pn["sort"]] = this.sortInfo.field;
7743 p[pn["dir"]] = this.sortInfo.direction;
7745 if (this.multiSort) {
7746 var pn = this.paramNames;
7747 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7750 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7755 * Reloads the Record cache from the configured Proxy using the configured Reader and
7756 * the options from the last load operation performed.
7757 * @param {Object} options (optional) An object containing properties which may override the options
7758 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7759 * the most recently used options are reused).
7761 reload : function(options){
7762 this.load(Roo.applyIf(options||{}, this.lastOptions));
7766 // Called as a callback by the Reader during a load operation.
7767 loadRecords : function(o, options, success){
7768 if(!o || success === false){
7769 if(success !== false){
7770 this.fireEvent("load", this, [], options, o);
7772 if(options.callback){
7773 options.callback.call(options.scope || this, [], options, false);
7777 // if data returned failure - throw an exception.
7778 if (o.success === false) {
7779 // show a message if no listener is registered.
7780 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7781 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7783 // loadmask wil be hooked into this..
7784 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7787 var r = o.records, t = o.totalRecords || r.length;
7789 this.fireEvent("beforeloadadd", this, r, options, o);
7791 if(!options || options.add !== true){
7792 if(this.pruneModifiedRecords){
7795 for(var i = 0, len = r.length; i < len; i++){
7799 this.data = this.snapshot;
7800 delete this.snapshot;
7803 this.data.addAll(r);
7804 this.totalLength = t;
7806 this.fireEvent("datachanged", this);
7808 this.totalLength = Math.max(t, this.data.length+r.length);
7811 this.fireEvent("load", this, r, options, o);
7812 if(options.callback){
7813 options.callback.call(options.scope || this, r, options, true);
7819 * Loads data from a passed data block. A Reader which understands the format of the data
7820 * must have been configured in the constructor.
7821 * @param {Object} data The data block from which to read the Records. The format of the data expected
7822 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7823 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7825 loadData : function(o, append){
7826 var r = this.reader.readRecords(o);
7827 this.loadRecords(r, {add: append}, true);
7831 * Gets the number of cached records.
7833 * <em>If using paging, this may not be the total size of the dataset. If the data object
7834 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7835 * the data set size</em>
7837 getCount : function(){
7838 return this.data.length || 0;
7842 * Gets the total number of records in the dataset as returned by the server.
7844 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7845 * the dataset size</em>
7847 getTotalCount : function(){
7848 return this.totalLength || 0;
7852 * Returns the sort state of the Store as an object with two properties:
7854 field {String} The name of the field by which the Records are sorted
7855 direction {String} The sort order, "ASC" or "DESC"
7858 getSortState : function(){
7859 return this.sortInfo;
7863 applySort : function(){
7864 if(this.sortInfo && !this.remoteSort){
7865 var s = this.sortInfo, f = s.field;
7866 var st = this.fields.get(f).sortType;
7867 var fn = function(r1, r2){
7868 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7869 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7871 this.data.sort(s.direction, fn);
7872 if(this.snapshot && this.snapshot != this.data){
7873 this.snapshot.sort(s.direction, fn);
7879 * Sets the default sort column and order to be used by the next load operation.
7880 * @param {String} fieldName The name of the field to sort by.
7881 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7883 setDefaultSort : function(field, dir){
7884 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7889 * If remote sorting is used, the sort is performed on the server, and the cache is
7890 * reloaded. If local sorting is used, the cache is sorted internally.
7891 * @param {String} fieldName The name of the field to sort by.
7892 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7894 sort : function(fieldName, dir){
7895 var f = this.fields.get(fieldName);
7897 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7899 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7900 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7905 this.sortToggle[f.name] = dir;
7906 this.sortInfo = {field: f.name, direction: dir};
7907 if(!this.remoteSort){
7909 this.fireEvent("datachanged", this);
7911 this.load(this.lastOptions);
7916 * Calls the specified function for each of the Records in the cache.
7917 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7918 * Returning <em>false</em> aborts and exits the iteration.
7919 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7921 each : function(fn, scope){
7922 this.data.each(fn, scope);
7926 * Gets all records modified since the last commit. Modified records are persisted across load operations
7927 * (e.g., during paging).
7928 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7930 getModifiedRecords : function(){
7931 return this.modified;
7935 createFilterFn : function(property, value, anyMatch){
7936 if(!value.exec){ // not a regex
7937 value = String(value);
7938 if(value.length == 0){
7941 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7944 return value.test(r.data[property]);
7949 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7950 * @param {String} property A field on your records
7951 * @param {Number} start The record index to start at (defaults to 0)
7952 * @param {Number} end The last record index to include (defaults to length - 1)
7953 * @return {Number} The sum
7955 sum : function(property, start, end){
7956 var rs = this.data.items, v = 0;
7958 end = (end || end === 0) ? end : rs.length-1;
7960 for(var i = start; i <= end; i++){
7961 v += (rs[i].data[property] || 0);
7967 * Filter the records by a specified property.
7968 * @param {String} field A field on your records
7969 * @param {String/RegExp} value Either a string that the field
7970 * should start with or a RegExp to test against the field
7971 * @param {Boolean} anyMatch True to match any part not just the beginning
7973 filter : function(property, value, anyMatch){
7974 var fn = this.createFilterFn(property, value, anyMatch);
7975 return fn ? this.filterBy(fn) : this.clearFilter();
7979 * Filter by a function. The specified function will be called with each
7980 * record in this data source. If the function returns true the record is included,
7981 * otherwise it is filtered.
7982 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7983 * @param {Object} scope (optional) The scope of the function (defaults to this)
7985 filterBy : function(fn, scope){
7986 this.snapshot = this.snapshot || this.data;
7987 this.data = this.queryBy(fn, scope||this);
7988 this.fireEvent("datachanged", this);
7992 * Query the records by a specified property.
7993 * @param {String} field A field on your records
7994 * @param {String/RegExp} value Either a string that the field
7995 * should start with or a RegExp to test against the field
7996 * @param {Boolean} anyMatch True to match any part not just the beginning
7997 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7999 query : function(property, value, anyMatch){
8000 var fn = this.createFilterFn(property, value, anyMatch);
8001 return fn ? this.queryBy(fn) : this.data.clone();
8005 * Query by a function. The specified function will be called with each
8006 * record in this data source. If the function returns true the record is included
8008 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8009 * @param {Object} scope (optional) The scope of the function (defaults to this)
8010 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8012 queryBy : function(fn, scope){
8013 var data = this.snapshot || this.data;
8014 return data.filterBy(fn, scope||this);
8018 * Collects unique values for a particular dataIndex from this store.
8019 * @param {String} dataIndex The property to collect
8020 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8021 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8022 * @return {Array} An array of the unique values
8024 collect : function(dataIndex, allowNull, bypassFilter){
8025 var d = (bypassFilter === true && this.snapshot) ?
8026 this.snapshot.items : this.data.items;
8027 var v, sv, r = [], l = {};
8028 for(var i = 0, len = d.length; i < len; i++){
8029 v = d[i].data[dataIndex];
8031 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8040 * Revert to a view of the Record cache with no filtering applied.
8041 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8043 clearFilter : function(suppressEvent){
8044 if(this.snapshot && this.snapshot != this.data){
8045 this.data = this.snapshot;
8046 delete this.snapshot;
8047 if(suppressEvent !== true){
8048 this.fireEvent("datachanged", this);
8054 afterEdit : function(record){
8055 if(this.modified.indexOf(record) == -1){
8056 this.modified.push(record);
8058 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8062 afterReject : function(record){
8063 this.modified.remove(record);
8064 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8068 afterCommit : function(record){
8069 this.modified.remove(record);
8070 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8074 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8075 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8077 commitChanges : function(){
8078 var m = this.modified.slice(0);
8080 for(var i = 0, len = m.length; i < len; i++){
8086 * Cancel outstanding changes on all changed records.
8088 rejectChanges : function(){
8089 var m = this.modified.slice(0);
8091 for(var i = 0, len = m.length; i < len; i++){
8096 onMetaChange : function(meta, rtype, o){
8097 this.recordType = rtype;
8098 this.fields = rtype.prototype.fields;
8099 delete this.snapshot;
8100 this.sortInfo = meta.sortInfo || this.sortInfo;
8102 this.fireEvent('metachange', this, this.reader.meta);
8105 moveIndex : function(data, type)
8107 var index = this.indexOf(data);
8109 var newIndex = index + type;
8113 this.insert(newIndex, data);
8118 * Ext JS Library 1.1.1
8119 * Copyright(c) 2006-2007, Ext JS, LLC.
8121 * Originally Released Under LGPL - original licence link has changed is not relivant.
8124 * <script type="text/javascript">
8128 * @class Roo.data.SimpleStore
8129 * @extends Roo.data.Store
8130 * Small helper class to make creating Stores from Array data easier.
8131 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8132 * @cfg {Array} fields An array of field definition objects, or field name strings.
8133 * @cfg {Array} data The multi-dimensional array of data
8135 * @param {Object} config
8137 Roo.data.SimpleStore = function(config){
8138 Roo.data.SimpleStore.superclass.constructor.call(this, {
8140 reader: new Roo.data.ArrayReader({
8143 Roo.data.Record.create(config.fields)
8145 proxy : new Roo.data.MemoryProxy(config.data)
8149 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8151 * Ext JS Library 1.1.1
8152 * Copyright(c) 2006-2007, Ext JS, LLC.
8154 * Originally Released Under LGPL - original licence link has changed is not relivant.
8157 * <script type="text/javascript">
8162 * @extends Roo.data.Store
8163 * @class Roo.data.JsonStore
8164 * Small helper class to make creating Stores for JSON data easier. <br/>
8166 var store = new Roo.data.JsonStore({
8167 url: 'get-images.php',
8169 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8172 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8173 * JsonReader and HttpProxy (unless inline data is provided).</b>
8174 * @cfg {Array} fields An array of field definition objects, or field name strings.
8176 * @param {Object} config
8178 Roo.data.JsonStore = function(c){
8179 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8180 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8181 reader: new Roo.data.JsonReader(c, c.fields)
8184 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8186 * Ext JS Library 1.1.1
8187 * Copyright(c) 2006-2007, Ext JS, LLC.
8189 * Originally Released Under LGPL - original licence link has changed is not relivant.
8192 * <script type="text/javascript">
8196 Roo.data.Field = function(config){
8197 if(typeof config == "string"){
8198 config = {name: config};
8200 Roo.apply(this, config);
8206 var st = Roo.data.SortTypes;
8207 // named sortTypes are supported, here we look them up
8208 if(typeof this.sortType == "string"){
8209 this.sortType = st[this.sortType];
8212 // set default sortType for strings and dates
8216 this.sortType = st.asUCString;
8219 this.sortType = st.asDate;
8222 this.sortType = st.none;
8227 var stripRe = /[\$,%]/g;
8229 // prebuilt conversion function for this field, instead of
8230 // switching every time we're reading a value
8232 var cv, dateFormat = this.dateFormat;
8237 cv = function(v){ return v; };
8240 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8244 return v !== undefined && v !== null && v !== '' ?
8245 parseInt(String(v).replace(stripRe, ""), 10) : '';
8250 return v !== undefined && v !== null && v !== '' ?
8251 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8256 cv = function(v){ return v === true || v === "true" || v == 1; };
8263 if(v instanceof Date){
8267 if(dateFormat == "timestamp"){
8268 return new Date(v*1000);
8270 return Date.parseDate(v, dateFormat);
8272 var parsed = Date.parse(v);
8273 return parsed ? new Date(parsed) : null;
8282 Roo.data.Field.prototype = {
8290 * Ext JS Library 1.1.1
8291 * Copyright(c) 2006-2007, Ext JS, LLC.
8293 * Originally Released Under LGPL - original licence link has changed is not relivant.
8296 * <script type="text/javascript">
8299 // Base class for reading structured data from a data source. This class is intended to be
8300 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8303 * @class Roo.data.DataReader
8304 * Base class for reading structured data from a data source. This class is intended to be
8305 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8308 Roo.data.DataReader = function(meta, recordType){
8312 this.recordType = recordType instanceof Array ?
8313 Roo.data.Record.create(recordType) : recordType;
8316 Roo.data.DataReader.prototype = {
8318 * Create an empty record
8319 * @param {Object} data (optional) - overlay some values
8320 * @return {Roo.data.Record} record created.
8322 newRow : function(d) {
8324 this.recordType.prototype.fields.each(function(c) {
8326 case 'int' : da[c.name] = 0; break;
8327 case 'date' : da[c.name] = new Date(); break;
8328 case 'float' : da[c.name] = 0.0; break;
8329 case 'boolean' : da[c.name] = false; break;
8330 default : da[c.name] = ""; break;
8334 return new this.recordType(Roo.apply(da, d));
8339 * Ext JS Library 1.1.1
8340 * Copyright(c) 2006-2007, Ext JS, LLC.
8342 * Originally Released Under LGPL - original licence link has changed is not relivant.
8345 * <script type="text/javascript">
8349 * @class Roo.data.DataProxy
8350 * @extends Roo.data.Observable
8351 * This class is an abstract base class for implementations which provide retrieval of
8352 * unformatted data objects.<br>
8354 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8355 * (of the appropriate type which knows how to parse the data object) to provide a block of
8356 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8358 * Custom implementations must implement the load method as described in
8359 * {@link Roo.data.HttpProxy#load}.
8361 Roo.data.DataProxy = function(){
8365 * Fires before a network request is made to retrieve a data object.
8366 * @param {Object} This DataProxy object.
8367 * @param {Object} params The params parameter to the load function.
8372 * Fires before the load method's callback is called.
8373 * @param {Object} This DataProxy object.
8374 * @param {Object} o The data object.
8375 * @param {Object} arg The callback argument object passed to the load function.
8379 * @event loadexception
8380 * Fires if an Exception occurs during data retrieval.
8381 * @param {Object} This DataProxy object.
8382 * @param {Object} o The data object.
8383 * @param {Object} arg The callback argument object passed to the load function.
8384 * @param {Object} e The Exception.
8386 loadexception : true
8388 Roo.data.DataProxy.superclass.constructor.call(this);
8391 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8394 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8398 * Ext JS Library 1.1.1
8399 * Copyright(c) 2006-2007, Ext JS, LLC.
8401 * Originally Released Under LGPL - original licence link has changed is not relivant.
8404 * <script type="text/javascript">
8407 * @class Roo.data.MemoryProxy
8408 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8409 * to the Reader when its load method is called.
8411 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8413 Roo.data.MemoryProxy = function(data){
8417 Roo.data.MemoryProxy.superclass.constructor.call(this);
8421 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8423 * Load data from the requested source (in this case an in-memory
8424 * data object passed to the constructor), read the data object into
8425 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8426 * process that block using the passed callback.
8427 * @param {Object} params This parameter is not used by the MemoryProxy class.
8428 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8429 * object into a block of Roo.data.Records.
8430 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8431 * The function must be passed <ul>
8432 * <li>The Record block object</li>
8433 * <li>The "arg" argument from the load function</li>
8434 * <li>A boolean success indicator</li>
8436 * @param {Object} scope The scope in which to call the callback
8437 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8439 load : function(params, reader, callback, scope, arg){
8440 params = params || {};
8443 result = reader.readRecords(this.data);
8445 this.fireEvent("loadexception", this, arg, null, e);
8446 callback.call(scope, null, arg, false);
8449 callback.call(scope, result, arg, true);
8453 update : function(params, records){
8458 * Ext JS Library 1.1.1
8459 * Copyright(c) 2006-2007, Ext JS, LLC.
8461 * Originally Released Under LGPL - original licence link has changed is not relivant.
8464 * <script type="text/javascript">
8467 * @class Roo.data.HttpProxy
8468 * @extends Roo.data.DataProxy
8469 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8470 * configured to reference a certain URL.<br><br>
8472 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8473 * from which the running page was served.<br><br>
8475 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8477 * Be aware that to enable the browser to parse an XML document, the server must set
8478 * the Content-Type header in the HTTP response to "text/xml".
8480 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8481 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8482 * will be used to make the request.
8484 Roo.data.HttpProxy = function(conn){
8485 Roo.data.HttpProxy.superclass.constructor.call(this);
8486 // is conn a conn config or a real conn?
8488 this.useAjax = !conn || !conn.events;
8492 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8493 // thse are take from connection...
8496 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8499 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8500 * extra parameters to each request made by this object. (defaults to undefined)
8503 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8504 * to each request made by this object. (defaults to undefined)
8507 * @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)
8510 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8513 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8519 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8523 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8524 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8525 * a finer-grained basis than the DataProxy events.
8527 getConnection : function(){
8528 return this.useAjax ? Roo.Ajax : this.conn;
8532 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8533 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8534 * process that block using the passed callback.
8535 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8536 * for the request to the remote server.
8537 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8538 * object into a block of Roo.data.Records.
8539 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8540 * The function must be passed <ul>
8541 * <li>The Record block object</li>
8542 * <li>The "arg" argument from the load function</li>
8543 * <li>A boolean success indicator</li>
8545 * @param {Object} scope The scope in which to call the callback
8546 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8548 load : function(params, reader, callback, scope, arg){
8549 if(this.fireEvent("beforeload", this, params) !== false){
8551 params : params || {},
8553 callback : callback,
8558 callback : this.loadResponse,
8562 Roo.applyIf(o, this.conn);
8563 if(this.activeRequest){
8564 Roo.Ajax.abort(this.activeRequest);
8566 this.activeRequest = Roo.Ajax.request(o);
8568 this.conn.request(o);
8571 callback.call(scope||this, null, arg, false);
8576 loadResponse : function(o, success, response){
8577 delete this.activeRequest;
8579 this.fireEvent("loadexception", this, o, response);
8580 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8585 result = o.reader.read(response);
8587 this.fireEvent("loadexception", this, o, response, e);
8588 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8592 this.fireEvent("load", this, o, o.request.arg);
8593 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8597 update : function(dataSet){
8602 updateResponse : function(dataSet){
8607 * Ext JS Library 1.1.1
8608 * Copyright(c) 2006-2007, Ext JS, LLC.
8610 * Originally Released Under LGPL - original licence link has changed is not relivant.
8613 * <script type="text/javascript">
8617 * @class Roo.data.ScriptTagProxy
8618 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8619 * other than the originating domain of the running page.<br><br>
8621 * <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
8622 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8624 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8625 * source code that is used as the source inside a <script> tag.<br><br>
8627 * In order for the browser to process the returned data, the server must wrap the data object
8628 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8629 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8630 * depending on whether the callback name was passed:
8633 boolean scriptTag = false;
8634 String cb = request.getParameter("callback");
8637 response.setContentType("text/javascript");
8639 response.setContentType("application/x-json");
8641 Writer out = response.getWriter();
8643 out.write(cb + "(");
8645 out.print(dataBlock.toJsonString());
8652 * @param {Object} config A configuration object.
8654 Roo.data.ScriptTagProxy = function(config){
8655 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8656 Roo.apply(this, config);
8657 this.head = document.getElementsByTagName("head")[0];
8660 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8662 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8664 * @cfg {String} url The URL from which to request the data object.
8667 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8671 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8672 * the server the name of the callback function set up by the load call to process the returned data object.
8673 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8674 * javascript output which calls this named function passing the data object as its only parameter.
8676 callbackParam : "callback",
8678 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8679 * name to the request.
8684 * Load data from the configured URL, read the data object into
8685 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8686 * process that block using the passed callback.
8687 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8688 * for the request to the remote server.
8689 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8690 * object into a block of Roo.data.Records.
8691 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8692 * The function must be passed <ul>
8693 * <li>The Record block object</li>
8694 * <li>The "arg" argument from the load function</li>
8695 * <li>A boolean success indicator</li>
8697 * @param {Object} scope The scope in which to call the callback
8698 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8700 load : function(params, reader, callback, scope, arg){
8701 if(this.fireEvent("beforeload", this, params) !== false){
8703 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8706 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8708 url += "&_dc=" + (new Date().getTime());
8710 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8713 cb : "stcCallback"+transId,
8714 scriptId : "stcScript"+transId,
8718 callback : callback,
8724 window[trans.cb] = function(o){
8725 conn.handleResponse(o, trans);
8728 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8730 if(this.autoAbort !== false){
8734 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8736 var script = document.createElement("script");
8737 script.setAttribute("src", url);
8738 script.setAttribute("type", "text/javascript");
8739 script.setAttribute("id", trans.scriptId);
8740 this.head.appendChild(script);
8744 callback.call(scope||this, null, arg, false);
8749 isLoading : function(){
8750 return this.trans ? true : false;
8754 * Abort the current server request.
8757 if(this.isLoading()){
8758 this.destroyTrans(this.trans);
8763 destroyTrans : function(trans, isLoaded){
8764 this.head.removeChild(document.getElementById(trans.scriptId));
8765 clearTimeout(trans.timeoutId);
8767 window[trans.cb] = undefined;
8769 delete window[trans.cb];
8772 // if hasn't been loaded, wait for load to remove it to prevent script error
8773 window[trans.cb] = function(){
8774 window[trans.cb] = undefined;
8776 delete window[trans.cb];
8783 handleResponse : function(o, trans){
8785 this.destroyTrans(trans, true);
8788 result = trans.reader.readRecords(o);
8790 this.fireEvent("loadexception", this, o, trans.arg, e);
8791 trans.callback.call(trans.scope||window, null, trans.arg, false);
8794 this.fireEvent("load", this, o, trans.arg);
8795 trans.callback.call(trans.scope||window, result, trans.arg, true);
8799 handleFailure : function(trans){
8801 this.destroyTrans(trans, false);
8802 this.fireEvent("loadexception", this, null, trans.arg);
8803 trans.callback.call(trans.scope||window, null, trans.arg, false);
8807 * Ext JS Library 1.1.1
8808 * Copyright(c) 2006-2007, Ext JS, LLC.
8810 * Originally Released Under LGPL - original licence link has changed is not relivant.
8813 * <script type="text/javascript">
8817 * @class Roo.data.JsonReader
8818 * @extends Roo.data.DataReader
8819 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8820 * based on mappings in a provided Roo.data.Record constructor.
8822 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8823 * in the reply previously.
8828 var RecordDef = Roo.data.Record.create([
8829 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8830 {name: 'occupation'} // This field will use "occupation" as the mapping.
8832 var myReader = new Roo.data.JsonReader({
8833 totalProperty: "results", // The property which contains the total dataset size (optional)
8834 root: "rows", // The property which contains an Array of row objects
8835 id: "id" // The property within each row object that provides an ID for the record (optional)
8839 * This would consume a JSON file like this:
8841 { 'results': 2, 'rows': [
8842 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8843 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8846 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8847 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8848 * paged from the remote server.
8849 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8850 * @cfg {String} root name of the property which contains the Array of row objects.
8851 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8853 * Create a new JsonReader
8854 * @param {Object} meta Metadata configuration options
8855 * @param {Object} recordType Either an Array of field definition objects,
8856 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8858 Roo.data.JsonReader = function(meta, recordType){
8861 // set some defaults:
8863 totalProperty: 'total',
8864 successProperty : 'success',
8869 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8871 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8874 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8875 * Used by Store query builder to append _requestMeta to params.
8878 metaFromRemote : false,
8880 * This method is only used by a DataProxy which has retrieved data from a remote server.
8881 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8882 * @return {Object} data A data block which is used by an Roo.data.Store object as
8883 * a cache of Roo.data.Records.
8885 read : function(response){
8886 var json = response.responseText;
8888 var o = /* eval:var:o */ eval("("+json+")");
8890 throw {message: "JsonReader.read: Json object not found"};
8896 this.metaFromRemote = true;
8897 this.meta = o.metaData;
8898 this.recordType = Roo.data.Record.create(o.metaData.fields);
8899 this.onMetaChange(this.meta, this.recordType, o);
8901 return this.readRecords(o);
8904 // private function a store will implement
8905 onMetaChange : function(meta, recordType, o){
8912 simpleAccess: function(obj, subsc) {
8919 getJsonAccessor: function(){
8921 return function(expr) {
8923 return(re.test(expr))
8924 ? new Function("obj", "return obj." + expr)
8934 * Create a data block containing Roo.data.Records from an XML document.
8935 * @param {Object} o An object which contains an Array of row objects in the property specified
8936 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8937 * which contains the total size of the dataset.
8938 * @return {Object} data A data block which is used by an Roo.data.Store object as
8939 * a cache of Roo.data.Records.
8941 readRecords : function(o){
8943 * After any data loads, the raw JSON data is available for further custom processing.
8947 var s = this.meta, Record = this.recordType,
8948 f = Record.prototype.fields, fi = f.items, fl = f.length;
8950 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8952 if(s.totalProperty) {
8953 this.getTotal = this.getJsonAccessor(s.totalProperty);
8955 if(s.successProperty) {
8956 this.getSuccess = this.getJsonAccessor(s.successProperty);
8958 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8960 var g = this.getJsonAccessor(s.id);
8961 this.getId = function(rec) {
8963 return (r === undefined || r === "") ? null : r;
8966 this.getId = function(){return null;};
8969 for(var jj = 0; jj < fl; jj++){
8971 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8972 this.ef[jj] = this.getJsonAccessor(map);
8976 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8977 if(s.totalProperty){
8978 var vt = parseInt(this.getTotal(o), 10);
8983 if(s.successProperty){
8984 var vs = this.getSuccess(o);
8985 if(vs === false || vs === 'false'){
8990 for(var i = 0; i < c; i++){
8993 var id = this.getId(n);
8994 for(var j = 0; j < fl; j++){
8996 var v = this.ef[j](n);
8998 Roo.log('missing convert for ' + f.name);
9002 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9004 var record = new Record(values, id);
9006 records[i] = record;
9012 totalRecords : totalRecords
9017 * Ext JS Library 1.1.1
9018 * Copyright(c) 2006-2007, Ext JS, LLC.
9020 * Originally Released Under LGPL - original licence link has changed is not relivant.
9023 * <script type="text/javascript">
9027 * @class Roo.data.ArrayReader
9028 * @extends Roo.data.DataReader
9029 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9030 * Each element of that Array represents a row of data fields. The
9031 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9032 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9036 var RecordDef = Roo.data.Record.create([
9037 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9038 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9040 var myReader = new Roo.data.ArrayReader({
9041 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9045 * This would consume an Array like this:
9047 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9049 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9051 * Create a new JsonReader
9052 * @param {Object} meta Metadata configuration options.
9053 * @param {Object} recordType Either an Array of field definition objects
9054 * as specified to {@link Roo.data.Record#create},
9055 * or an {@link Roo.data.Record} object
9056 * created using {@link Roo.data.Record#create}.
9058 Roo.data.ArrayReader = function(meta, recordType){
9059 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9062 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9064 * Create a data block containing Roo.data.Records from an XML document.
9065 * @param {Object} o An Array of row objects which represents the dataset.
9066 * @return {Object} data A data block which is used by an Roo.data.Store object as
9067 * a cache of Roo.data.Records.
9069 readRecords : function(o){
9070 var sid = this.meta ? this.meta.id : null;
9071 var recordType = this.recordType, fields = recordType.prototype.fields;
9074 for(var i = 0; i < root.length; i++){
9077 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9078 for(var j = 0, jlen = fields.length; j < jlen; j++){
9079 var f = fields.items[j];
9080 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9081 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9085 var record = new recordType(values, id);
9087 records[records.length] = record;
9091 totalRecords : records.length
9100 * @class Roo.bootstrap.ComboBox
9101 * @extends Roo.bootstrap.TriggerField
9102 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9103 * @cfg {Boolean} append (true|false) default false
9105 * Create a new ComboBox.
9106 * @param {Object} config Configuration options
9108 Roo.bootstrap.ComboBox = function(config){
9109 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9113 * Fires when the dropdown list is expanded
9114 * @param {Roo.bootstrap.ComboBox} combo This combo box
9119 * Fires when the dropdown list is collapsed
9120 * @param {Roo.bootstrap.ComboBox} combo This combo box
9124 * @event beforeselect
9125 * Fires before a list item is selected. Return false to cancel the selection.
9126 * @param {Roo.bootstrap.ComboBox} combo This combo box
9127 * @param {Roo.data.Record} record The data record returned from the underlying store
9128 * @param {Number} index The index of the selected item in the dropdown list
9130 'beforeselect' : true,
9133 * Fires when a list item is selected
9134 * @param {Roo.bootstrap.ComboBox} combo This combo box
9135 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9136 * @param {Number} index The index of the selected item in the dropdown list
9140 * @event beforequery
9141 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9142 * The event object passed has these properties:
9143 * @param {Roo.bootstrap.ComboBox} combo This combo box
9144 * @param {String} query The query
9145 * @param {Boolean} forceAll true to force "all" query
9146 * @param {Boolean} cancel true to cancel the query
9147 * @param {Object} e The query event object
9149 'beforequery': true,
9152 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9153 * @param {Roo.bootstrap.ComboBox} combo This combo box
9158 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9159 * @param {Roo.bootstrap.ComboBox} combo This combo box
9160 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9165 * Fires when the remove value from the combobox array
9166 * @param {Roo.bootstrap.ComboBox} combo This combo box
9173 this.selectedIndex = -1;
9174 if(this.mode == 'local'){
9175 if(config.queryDelay === undefined){
9176 this.queryDelay = 10;
9178 if(config.minChars === undefined){
9184 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9187 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9188 * rendering into an Roo.Editor, defaults to false)
9191 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9192 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9195 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9198 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9199 * the dropdown list (defaults to undefined, with no header element)
9203 * @cfg {String/Roo.Template} tpl The template to use to render the output
9207 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9209 listWidth: undefined,
9211 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9212 * mode = 'remote' or 'text' if mode = 'local')
9214 displayField: undefined,
9216 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9217 * mode = 'remote' or 'value' if mode = 'local').
9218 * Note: use of a valueField requires the user make a selection
9219 * in order for a value to be mapped.
9221 valueField: undefined,
9225 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9226 * field's data value (defaults to the underlying DOM element's name)
9228 hiddenName: undefined,
9230 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9234 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9236 selectedClass: 'active',
9239 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9243 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9244 * anchor positions (defaults to 'tl-bl')
9246 listAlign: 'tl-bl?',
9248 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9252 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9253 * query specified by the allQuery config option (defaults to 'query')
9255 triggerAction: 'query',
9257 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9258 * (defaults to 4, does not apply if editable = false)
9262 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9263 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9267 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9268 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9272 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9273 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9277 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9278 * when editable = true (defaults to false)
9280 selectOnFocus:false,
9282 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9284 queryParam: 'query',
9286 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9287 * when mode = 'remote' (defaults to 'Loading...')
9289 loadingText: 'Loading...',
9291 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9295 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9299 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9300 * traditional select (defaults to true)
9304 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9308 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9312 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9313 * listWidth has a higher value)
9317 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9318 * allow the user to set arbitrary text into the field (defaults to false)
9320 forceSelection:false,
9322 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9323 * if typeAhead = true (defaults to 250)
9325 typeAheadDelay : 250,
9327 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9328 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9330 valueNotFoundText : undefined,
9332 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9337 * @cfg {Boolean} disableClear Disable showing of clear button.
9339 disableClear : false,
9341 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9343 alwaysQuery : false,
9346 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9360 // element that contains real text value.. (when hidden is used..)
9363 initEvents: function(){
9366 throw "can not find store for combo";
9368 this.store = Roo.factory(this.store, Roo.data);
9372 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9375 if(this.hiddenName){
9377 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9379 this.hiddenField.dom.value =
9380 this.hiddenValue !== undefined ? this.hiddenValue :
9381 this.value !== undefined ? this.value : '';
9383 // prevent input submission
9384 this.el.dom.removeAttribute('name');
9385 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9390 // this.el.dom.setAttribute('autocomplete', 'off');
9393 var cls = 'x-combo-list';
9394 this.list = this.el.select('ul.dropdown-menu',true).first();
9396 //this.list = new Roo.Layer({
9397 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9400 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9401 this.list.setWidth(lw);
9403 this.list.on('mouseover', this.onViewOver, this);
9404 this.list.on('mousemove', this.onViewMove, this);
9406 this.list.on('scroll', this.onViewScroll, this);
9409 this.list.swallowEvent('mousewheel');
9410 this.assetHeight = 0;
9413 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9414 this.assetHeight += this.header.getHeight();
9417 this.innerList = this.list.createChild({cls:cls+'-inner'});
9418 this.innerList.on('mouseover', this.onViewOver, this);
9419 this.innerList.on('mousemove', this.onViewMove, this);
9420 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9422 if(this.allowBlank && !this.pageSize && !this.disableClear){
9423 this.footer = this.list.createChild({cls:cls+'-ft'});
9424 this.pageTb = new Roo.Toolbar(this.footer);
9428 this.footer = this.list.createChild({cls:cls+'-ft'});
9429 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9430 {pageSize: this.pageSize});
9434 if (this.pageTb && this.allowBlank && !this.disableClear) {
9436 this.pageTb.add(new Roo.Toolbar.Fill(), {
9437 cls: 'x-btn-icon x-btn-clear',
9443 _this.onSelect(false, -1);
9448 this.assetHeight += this.footer.getHeight();
9453 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9456 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9457 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9459 //this.view.wrapEl.setDisplayed(false);
9460 this.view.on('click', this.onViewClick, this);
9464 this.store.on('beforeload', this.onBeforeLoad, this);
9465 this.store.on('load', this.onLoad, this);
9466 this.store.on('loadexception', this.onLoadException, this);
9469 this.resizer = new Roo.Resizable(this.list, {
9470 pinned:true, handles:'se'
9472 this.resizer.on('resize', function(r, w, h){
9473 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9475 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9476 this.restrictHeight();
9478 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9482 this.editable = true;
9483 this.setEditable(false);
9488 if (typeof(this.events.add.listeners) != 'undefined') {
9490 this.addicon = this.wrap.createChild(
9491 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9493 this.addicon.on('click', function(e) {
9494 this.fireEvent('add', this);
9497 if (typeof(this.events.edit.listeners) != 'undefined') {
9499 this.editicon = this.wrap.createChild(
9500 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9502 this.editicon.setStyle('margin-left', '40px');
9504 this.editicon.on('click', function(e) {
9506 // we fire even if inothing is selected..
9507 this.fireEvent('edit', this, this.lastData );
9513 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9515 this.inKeyMode = true;
9519 "down" : function(e){
9520 if(!this.isExpanded()){
9521 this.onTriggerClick();
9523 this.inKeyMode = true;
9528 "enter" : function(e){
9533 "esc" : function(e){
9537 "tab" : function(e){
9540 if(this.fireEvent("specialkey", this, e)){
9541 this.onViewClick(false);
9549 doRelay : function(foo, bar, hname){
9550 if(hname == 'down' || this.scope.isExpanded()){
9551 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9560 this.queryDelay = Math.max(this.queryDelay || 10,
9561 this.mode == 'local' ? 10 : 250);
9564 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9567 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9569 if(this.editable !== false){
9570 this.inputEl().on("keyup", this.onKeyUp, this);
9572 if(this.forceSelection){
9573 this.inputEl().on('blur', this.doForce, this);
9577 this.choices = this.el.select('ul.select2-choices', true).first();
9578 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9582 onDestroy : function(){
9584 this.view.setStore(null);
9585 this.view.el.removeAllListeners();
9586 this.view.el.remove();
9587 this.view.purgeListeners();
9590 this.list.dom.innerHTML = '';
9593 this.store.un('beforeload', this.onBeforeLoad, this);
9594 this.store.un('load', this.onLoad, this);
9595 this.store.un('loadexception', this.onLoadException, this);
9597 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9601 fireKey : function(e){
9602 if(e.isNavKeyPress() && !this.list.isVisible()){
9603 this.fireEvent("specialkey", this, e);
9608 onResize: function(w, h){
9609 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9611 // if(typeof w != 'number'){
9612 // // we do not handle it!?!?
9615 // var tw = this.trigger.getWidth();
9616 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9617 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9619 // this.inputEl().setWidth( this.adjustWidth('input', x));
9621 // //this.trigger.setStyle('left', x+'px');
9623 // if(this.list && this.listWidth === undefined){
9624 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9625 // this.list.setWidth(lw);
9626 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9634 * Allow or prevent the user from directly editing the field text. If false is passed,
9635 * the user will only be able to select from the items defined in the dropdown list. This method
9636 * is the runtime equivalent of setting the 'editable' config option at config time.
9637 * @param {Boolean} value True to allow the user to directly edit the field text
9639 setEditable : function(value){
9640 if(value == this.editable){
9643 this.editable = value;
9645 this.inputEl().dom.setAttribute('readOnly', true);
9646 this.inputEl().on('mousedown', this.onTriggerClick, this);
9647 this.inputEl().addClass('x-combo-noedit');
9649 this.inputEl().dom.setAttribute('readOnly', false);
9650 this.inputEl().un('mousedown', this.onTriggerClick, this);
9651 this.inputEl().removeClass('x-combo-noedit');
9657 onBeforeLoad : function(combo,opts){
9662 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9664 this.restrictHeight();
9665 this.selectedIndex = -1;
9669 onLoad : function(){
9671 this.hasQuery = false;
9677 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9678 this.loading.hide();
9681 if(this.store.getCount() > 0){
9683 this.restrictHeight();
9684 if(this.lastQuery == this.allQuery){
9686 this.inputEl().dom.select();
9688 if(!this.selectByValue(this.value, true)){
9689 this.select(0, true);
9693 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9694 this.taTask.delay(this.typeAheadDelay);
9698 this.onEmptyResults();
9704 onLoadException : function()
9706 this.hasQuery = false;
9708 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9709 this.loading.hide();
9713 Roo.log(this.store.reader.jsonData);
9714 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9716 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9722 onTypeAhead : function(){
9723 if(this.store.getCount() > 0){
9724 var r = this.store.getAt(0);
9725 var newValue = r.data[this.displayField];
9726 var len = newValue.length;
9727 var selStart = this.getRawValue().length;
9729 if(selStart != len){
9730 this.setRawValue(newValue);
9731 this.selectText(selStart, newValue.length);
9737 onSelect : function(record, index){
9739 if(this.fireEvent('beforeselect', this, record, index) !== false){
9741 this.setFromData(index > -1 ? record.data : false);
9744 this.fireEvent('select', this, record, index);
9749 * Returns the currently selected field value or empty string if no value is set.
9750 * @return {String} value The selected value
9752 getValue : function(){
9755 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9758 if(this.valueField){
9759 return typeof this.value != 'undefined' ? this.value : '';
9761 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9766 * Clears any text/value currently set in the field
9768 clearValue : function(){
9769 if(this.hiddenField){
9770 this.hiddenField.dom.value = '';
9773 this.setRawValue('');
9774 this.lastSelectionText = '';
9779 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9780 * will be displayed in the field. If the value does not match the data value of an existing item,
9781 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9782 * Otherwise the field will be blank (although the value will still be set).
9783 * @param {String} value The value to match
9785 setValue : function(v){
9792 if(this.valueField){
9793 var r = this.findRecord(this.valueField, v);
9795 text = r.data[this.displayField];
9796 }else if(this.valueNotFoundText !== undefined){
9797 text = this.valueNotFoundText;
9800 this.lastSelectionText = text;
9801 if(this.hiddenField){
9802 this.hiddenField.dom.value = v;
9804 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9808 * @property {Object} the last set data for the element
9813 * Sets the value of the field based on a object which is related to the record format for the store.
9814 * @param {Object} value the value to set as. or false on reset?
9816 setFromData : function(o){
9823 var dv = ''; // display value
9824 var vv = ''; // value value..
9826 if (this.displayField) {
9827 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9829 // this is an error condition!!!
9830 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9833 if(this.valueField){
9834 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9837 if(this.hiddenField){
9838 this.hiddenField.dom.value = vv;
9840 this.lastSelectionText = dv;
9841 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9845 // no hidden field.. - we store the value in 'value', but still display
9846 // display field!!!!
9847 this.lastSelectionText = dv;
9848 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9855 // overridden so that last data is reset..
9856 this.setValue(this.originalValue);
9857 this.clearInvalid();
9858 this.lastData = false;
9860 this.view.clearSelections();
9864 findRecord : function(prop, value){
9866 if(this.store.getCount() > 0){
9867 this.store.each(function(r){
9868 if(r.data[prop] == value){
9880 // returns hidden if it's set..
9881 if (!this.rendered) {return ''};
9882 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9886 onViewMove : function(e, t){
9887 this.inKeyMode = false;
9891 onViewOver : function(e, t){
9892 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9895 var item = this.view.findItemFromChild(t);
9897 var index = this.view.indexOf(item);
9898 this.select(index, false);
9903 onViewClick : function(doFocus)
9905 var index = this.view.getSelectedIndexes()[0];
9906 var r = this.store.getAt(index);
9908 this.onSelect(r, index);
9910 if(doFocus !== false && !this.blockFocus){
9911 this.inputEl().focus();
9916 restrictHeight : function(){
9917 //this.innerList.dom.style.height = '';
9918 //var inner = this.innerList.dom;
9919 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9920 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9921 //this.list.beginUpdate();
9922 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9923 this.list.alignTo(this.inputEl(), this.listAlign);
9924 //this.list.endUpdate();
9928 onEmptyResults : function(){
9933 * Returns true if the dropdown list is expanded, else false.
9935 isExpanded : function(){
9936 return this.list.isVisible();
9940 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9941 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9942 * @param {String} value The data value of the item to select
9943 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9944 * selected item if it is not currently in view (defaults to true)
9945 * @return {Boolean} True if the value matched an item in the list, else false
9947 selectByValue : function(v, scrollIntoView){
9948 if(v !== undefined && v !== null){
9949 var r = this.findRecord(this.valueField || this.displayField, v);
9951 this.select(this.store.indexOf(r), scrollIntoView);
9959 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9960 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9961 * @param {Number} index The zero-based index of the list item to select
9962 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9963 * selected item if it is not currently in view (defaults to true)
9965 select : function(index, scrollIntoView){
9966 this.selectedIndex = index;
9967 this.view.select(index);
9968 if(scrollIntoView !== false){
9969 var el = this.view.getNode(index);
9971 //this.innerList.scrollChildIntoView(el, false);
9978 selectNext : function(){
9979 var ct = this.store.getCount();
9981 if(this.selectedIndex == -1){
9983 }else if(this.selectedIndex < ct-1){
9984 this.select(this.selectedIndex+1);
9990 selectPrev : function(){
9991 var ct = this.store.getCount();
9993 if(this.selectedIndex == -1){
9995 }else if(this.selectedIndex != 0){
9996 this.select(this.selectedIndex-1);
10002 onKeyUp : function(e){
10003 if(this.editable !== false && !e.isSpecialKey()){
10004 this.lastKey = e.getKey();
10005 this.dqTask.delay(this.queryDelay);
10010 validateBlur : function(){
10011 return !this.list || !this.list.isVisible();
10015 initQuery : function(){
10016 this.doQuery(this.getRawValue());
10020 doForce : function(){
10021 if(this.inputEl().dom.value.length > 0){
10022 this.inputEl().dom.value =
10023 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10029 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10030 * query allowing the query action to be canceled if needed.
10031 * @param {String} query The SQL query to execute
10032 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10033 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10034 * saved in the current store (defaults to false)
10036 doQuery : function(q, forceAll){
10038 if(q === undefined || q === null){
10043 forceAll: forceAll,
10047 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10052 forceAll = qe.forceAll;
10053 if(forceAll === true || (q.length >= this.minChars)){
10055 this.hasQuery = true;
10057 if(this.lastQuery != q || this.alwaysQuery){
10058 this.lastQuery = q;
10059 if(this.mode == 'local'){
10060 this.selectedIndex = -1;
10062 this.store.clearFilter();
10064 this.store.filter(this.displayField, q);
10068 this.store.baseParams[this.queryParam] = q;
10070 var options = {params : this.getParams(q)};
10073 options.add = true;
10074 options.params.start = this.page * this.pageSize;
10077 this.store.load(options);
10081 this.selectedIndex = -1;
10086 this.loadNext = false;
10090 getParams : function(q){
10092 //p[this.queryParam] = q;
10096 p.limit = this.pageSize;
10102 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10104 collapse : function(){
10105 if(!this.isExpanded()){
10110 Roo.get(document).un('mousedown', this.collapseIf, this);
10111 Roo.get(document).un('mousewheel', this.collapseIf, this);
10112 if (!this.editable) {
10113 Roo.get(document).un('keydown', this.listKeyPress, this);
10115 this.fireEvent('collapse', this);
10119 collapseIf : function(e){
10120 var in_combo = e.within(this.el);
10121 var in_list = e.within(this.list);
10123 if (in_combo || in_list) {
10124 //e.stopPropagation();
10133 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10135 expand : function(){
10137 if(this.isExpanded() || !this.hasFocus){
10141 this.list.alignTo(this.inputEl(), this.listAlign);
10143 Roo.get(document).on('mousedown', this.collapseIf, this);
10144 Roo.get(document).on('mousewheel', this.collapseIf, this);
10145 if (!this.editable) {
10146 Roo.get(document).on('keydown', this.listKeyPress, this);
10149 this.fireEvent('expand', this);
10153 // Implements the default empty TriggerField.onTriggerClick function
10154 onTriggerClick : function()
10156 Roo.log('trigger click');
10163 this.loadNext = false;
10165 if(this.isExpanded()){
10167 if (!this.blockFocus) {
10168 this.inputEl().focus();
10172 this.hasFocus = true;
10173 if(this.triggerAction == 'all') {
10174 this.doQuery(this.allQuery, true);
10176 this.doQuery(this.getRawValue());
10178 if (!this.blockFocus) {
10179 this.inputEl().focus();
10183 listKeyPress : function(e)
10185 //Roo.log('listkeypress');
10186 // scroll to first matching element based on key pres..
10187 if (e.isSpecialKey()) {
10190 var k = String.fromCharCode(e.getKey()).toUpperCase();
10193 var csel = this.view.getSelectedNodes();
10194 var cselitem = false;
10196 var ix = this.view.indexOf(csel[0]);
10197 cselitem = this.store.getAt(ix);
10198 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10204 this.store.each(function(v) {
10206 // start at existing selection.
10207 if (cselitem.id == v.id) {
10213 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10214 match = this.store.indexOf(v);
10220 if (match === false) {
10221 return true; // no more action?
10224 this.view.select(match);
10225 var sn = Roo.get(this.view.getSelectedNodes()[0])
10226 //sn.scrollIntoView(sn.dom.parentNode, false);
10229 onViewScroll : function(e, t){
10231 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10235 this.hasQuery = true;
10237 this.loading = this.list.select('.loading', true).first();
10239 if(this.loading === null){
10240 this.list.createChild({
10242 cls: 'loading select2-more-results select2-active',
10243 html: 'Loading more results...'
10246 this.loading = this.list.select('.loading', true).first();
10248 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10250 this.loading.hide();
10253 this.loading.show();
10258 this.loadNext = true;
10260 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10265 addItem : function(o)
10267 var dv = ''; // display value
10269 if (this.displayField) {
10270 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10272 // this is an error condition!!!
10273 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10280 var choice = this.choices.createChild({
10282 cls: 'select2-search-choice',
10291 cls: 'select2-search-choice-close',
10296 }, this.searchField);
10298 var close = choice.select('a.select2-search-choice-close', true).first()
10300 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10307 this.inputEl().dom.value = '';
10311 onRemoveItem : function(e, _self, o)
10313 e.preventDefault();
10314 var index = this.item.indexOf(o.data) * 1;
10317 Roo.log('not this item?!');
10321 this.item.splice(index, 1);
10326 this.fireEvent('remove', this, e);
10330 syncValue : function()
10332 if(!this.item.length){
10339 Roo.each(this.item, function(i){
10340 if(_this.valueField){
10341 value.push(i[_this.valueField]);
10348 this.value = value.join(',');
10350 if(this.hiddenField){
10351 this.hiddenField.dom.value = this.value;
10355 clearItem : function()
10357 if(!this.multiple){
10363 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10373 * @cfg {Boolean} grow
10377 * @cfg {Number} growMin
10381 * @cfg {Number} growMax
10391 * Ext JS Library 1.1.1
10392 * Copyright(c) 2006-2007, Ext JS, LLC.
10394 * Originally Released Under LGPL - original licence link has changed is not relivant.
10397 * <script type="text/javascript">
10402 * @extends Roo.util.Observable
10403 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10404 * This class also supports single and multi selection modes. <br>
10405 * Create a data model bound view:
10407 var store = new Roo.data.Store(...);
10409 var view = new Roo.View({
10411 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10413 singleSelect: true,
10414 selectedClass: "ydataview-selected",
10418 // listen for node click?
10419 view.on("click", function(vw, index, node, e){
10420 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10424 dataModel.load("foobar.xml");
10426 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10428 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10429 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10431 * Note: old style constructor is still suported (container, template, config)
10434 * Create a new View
10435 * @param {Object} config The config object
10438 Roo.View = function(config, depreciated_tpl, depreciated_config){
10440 if (typeof(depreciated_tpl) == 'undefined') {
10441 // new way.. - universal constructor.
10442 Roo.apply(this, config);
10443 this.el = Roo.get(this.el);
10446 this.el = Roo.get(config);
10447 this.tpl = depreciated_tpl;
10448 Roo.apply(this, depreciated_config);
10450 this.wrapEl = this.el.wrap().wrap();
10451 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10454 if(typeof(this.tpl) == "string"){
10455 this.tpl = new Roo.Template(this.tpl);
10457 // support xtype ctors..
10458 this.tpl = new Roo.factory(this.tpl, Roo);
10462 this.tpl.compile();
10470 * @event beforeclick
10471 * Fires before a click is processed. Returns false to cancel the default action.
10472 * @param {Roo.View} this
10473 * @param {Number} index The index of the target node
10474 * @param {HTMLElement} node The target node
10475 * @param {Roo.EventObject} e The raw event object
10477 "beforeclick" : true,
10480 * Fires when a template node is clicked.
10481 * @param {Roo.View} this
10482 * @param {Number} index The index of the target node
10483 * @param {HTMLElement} node The target node
10484 * @param {Roo.EventObject} e The raw event object
10489 * Fires when a template node is double clicked.
10490 * @param {Roo.View} this
10491 * @param {Number} index The index of the target node
10492 * @param {HTMLElement} node The target node
10493 * @param {Roo.EventObject} e The raw event object
10497 * @event contextmenu
10498 * Fires when a template node is right clicked.
10499 * @param {Roo.View} this
10500 * @param {Number} index The index of the target node
10501 * @param {HTMLElement} node The target node
10502 * @param {Roo.EventObject} e The raw event object
10504 "contextmenu" : true,
10506 * @event selectionchange
10507 * Fires when the selected nodes change.
10508 * @param {Roo.View} this
10509 * @param {Array} selections Array of the selected nodes
10511 "selectionchange" : true,
10514 * @event beforeselect
10515 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10516 * @param {Roo.View} this
10517 * @param {HTMLElement} node The node to be selected
10518 * @param {Array} selections Array of currently selected nodes
10520 "beforeselect" : true,
10522 * @event preparedata
10523 * Fires on every row to render, to allow you to change the data.
10524 * @param {Roo.View} this
10525 * @param {Object} data to be rendered (change this)
10527 "preparedata" : true
10535 "click": this.onClick,
10536 "dblclick": this.onDblClick,
10537 "contextmenu": this.onContextMenu,
10541 this.selections = [];
10543 this.cmp = new Roo.CompositeElementLite([]);
10545 this.store = Roo.factory(this.store, Roo.data);
10546 this.setStore(this.store, true);
10549 if ( this.footer && this.footer.xtype) {
10551 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10553 this.footer.dataSource = this.store
10554 this.footer.container = fctr;
10555 this.footer = Roo.factory(this.footer, Roo);
10556 fctr.insertFirst(this.el);
10558 // this is a bit insane - as the paging toolbar seems to detach the el..
10559 // dom.parentNode.parentNode.parentNode
10560 // they get detached?
10564 Roo.View.superclass.constructor.call(this);
10569 Roo.extend(Roo.View, Roo.util.Observable, {
10572 * @cfg {Roo.data.Store} store Data store to load data from.
10577 * @cfg {String|Roo.Element} el The container element.
10582 * @cfg {String|Roo.Template} tpl The template used by this View
10586 * @cfg {String} dataName the named area of the template to use as the data area
10587 * Works with domtemplates roo-name="name"
10591 * @cfg {String} selectedClass The css class to add to selected nodes
10593 selectedClass : "x-view-selected",
10595 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10600 * @cfg {String} text to display on mask (default Loading)
10604 * @cfg {Boolean} multiSelect Allow multiple selection
10606 multiSelect : false,
10608 * @cfg {Boolean} singleSelect Allow single selection
10610 singleSelect: false,
10613 * @cfg {Boolean} toggleSelect - selecting
10615 toggleSelect : false,
10618 * Returns the element this view is bound to.
10619 * @return {Roo.Element}
10621 getEl : function(){
10622 return this.wrapEl;
10628 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10630 refresh : function(){
10631 Roo.log('refresh');
10634 // if we are using something like 'domtemplate', then
10635 // the what gets used is:
10636 // t.applySubtemplate(NAME, data, wrapping data..)
10637 // the outer template then get' applied with
10638 // the store 'extra data'
10639 // and the body get's added to the
10640 // roo-name="data" node?
10641 // <span class='roo-tpl-{name}'></span> ?????
10645 this.clearSelections();
10646 this.el.update("");
10648 var records = this.store.getRange();
10649 if(records.length < 1) {
10651 // is this valid?? = should it render a template??
10653 this.el.update(this.emptyText);
10657 if (this.dataName) {
10658 this.el.update(t.apply(this.store.meta)); //????
10659 el = this.el.child('.roo-tpl-' + this.dataName);
10662 for(var i = 0, len = records.length; i < len; i++){
10663 var data = this.prepareData(records[i].data, i, records[i]);
10664 this.fireEvent("preparedata", this, data, i, records[i]);
10665 html[html.length] = Roo.util.Format.trim(
10667 t.applySubtemplate(this.dataName, data, this.store.meta) :
10674 el.update(html.join(""));
10675 this.nodes = el.dom.childNodes;
10676 this.updateIndexes(0);
10681 * Function to override to reformat the data that is sent to
10682 * the template for each node.
10683 * DEPRICATED - use the preparedata event handler.
10684 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10685 * a JSON object for an UpdateManager bound view).
10687 prepareData : function(data, index, record)
10689 this.fireEvent("preparedata", this, data, index, record);
10693 onUpdate : function(ds, record){
10694 Roo.log('on update');
10695 this.clearSelections();
10696 var index = this.store.indexOf(record);
10697 var n = this.nodes[index];
10698 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10699 n.parentNode.removeChild(n);
10700 this.updateIndexes(index, index);
10706 onAdd : function(ds, records, index)
10708 Roo.log(['on Add', ds, records, index] );
10709 this.clearSelections();
10710 if(this.nodes.length == 0){
10714 var n = this.nodes[index];
10715 for(var i = 0, len = records.length; i < len; i++){
10716 var d = this.prepareData(records[i].data, i, records[i]);
10718 this.tpl.insertBefore(n, d);
10721 this.tpl.append(this.el, d);
10724 this.updateIndexes(index);
10727 onRemove : function(ds, record, index){
10728 Roo.log('onRemove');
10729 this.clearSelections();
10730 var el = this.dataName ?
10731 this.el.child('.roo-tpl-' + this.dataName) :
10734 el.dom.removeChild(this.nodes[index]);
10735 this.updateIndexes(index);
10739 * Refresh an individual node.
10740 * @param {Number} index
10742 refreshNode : function(index){
10743 this.onUpdate(this.store, this.store.getAt(index));
10746 updateIndexes : function(startIndex, endIndex){
10747 var ns = this.nodes;
10748 startIndex = startIndex || 0;
10749 endIndex = endIndex || ns.length - 1;
10750 for(var i = startIndex; i <= endIndex; i++){
10751 ns[i].nodeIndex = i;
10756 * Changes the data store this view uses and refresh the view.
10757 * @param {Store} store
10759 setStore : function(store, initial){
10760 if(!initial && this.store){
10761 this.store.un("datachanged", this.refresh);
10762 this.store.un("add", this.onAdd);
10763 this.store.un("remove", this.onRemove);
10764 this.store.un("update", this.onUpdate);
10765 this.store.un("clear", this.refresh);
10766 this.store.un("beforeload", this.onBeforeLoad);
10767 this.store.un("load", this.onLoad);
10768 this.store.un("loadexception", this.onLoad);
10772 store.on("datachanged", this.refresh, this);
10773 store.on("add", this.onAdd, this);
10774 store.on("remove", this.onRemove, this);
10775 store.on("update", this.onUpdate, this);
10776 store.on("clear", this.refresh, this);
10777 store.on("beforeload", this.onBeforeLoad, this);
10778 store.on("load", this.onLoad, this);
10779 store.on("loadexception", this.onLoad, this);
10787 * onbeforeLoad - masks the loading area.
10790 onBeforeLoad : function(store,opts)
10792 Roo.log('onBeforeLoad');
10794 this.el.update("");
10796 this.el.mask(this.mask ? this.mask : "Loading" );
10798 onLoad : function ()
10805 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10806 * @param {HTMLElement} node
10807 * @return {HTMLElement} The template node
10809 findItemFromChild : function(node){
10810 var el = this.dataName ?
10811 this.el.child('.roo-tpl-' + this.dataName,true) :
10814 if(!node || node.parentNode == el){
10817 var p = node.parentNode;
10818 while(p && p != el){
10819 if(p.parentNode == el){
10828 onClick : function(e){
10829 var item = this.findItemFromChild(e.getTarget());
10831 var index = this.indexOf(item);
10832 if(this.onItemClick(item, index, e) !== false){
10833 this.fireEvent("click", this, index, item, e);
10836 this.clearSelections();
10841 onContextMenu : function(e){
10842 var item = this.findItemFromChild(e.getTarget());
10844 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10849 onDblClick : function(e){
10850 var item = this.findItemFromChild(e.getTarget());
10852 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10856 onItemClick : function(item, index, e)
10858 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10861 if (this.toggleSelect) {
10862 var m = this.isSelected(item) ? 'unselect' : 'select';
10865 _t[m](item, true, false);
10868 if(this.multiSelect || this.singleSelect){
10869 if(this.multiSelect && e.shiftKey && this.lastSelection){
10870 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10872 this.select(item, this.multiSelect && e.ctrlKey);
10873 this.lastSelection = item;
10875 e.preventDefault();
10881 * Get the number of selected nodes.
10884 getSelectionCount : function(){
10885 return this.selections.length;
10889 * Get the currently selected nodes.
10890 * @return {Array} An array of HTMLElements
10892 getSelectedNodes : function(){
10893 return this.selections;
10897 * Get the indexes of the selected nodes.
10900 getSelectedIndexes : function(){
10901 var indexes = [], s = this.selections;
10902 for(var i = 0, len = s.length; i < len; i++){
10903 indexes.push(s[i].nodeIndex);
10909 * Clear all selections
10910 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10912 clearSelections : function(suppressEvent){
10913 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10914 this.cmp.elements = this.selections;
10915 this.cmp.removeClass(this.selectedClass);
10916 this.selections = [];
10917 if(!suppressEvent){
10918 this.fireEvent("selectionchange", this, this.selections);
10924 * Returns true if the passed node is selected
10925 * @param {HTMLElement/Number} node The node or node index
10926 * @return {Boolean}
10928 isSelected : function(node){
10929 var s = this.selections;
10933 node = this.getNode(node);
10934 return s.indexOf(node) !== -1;
10939 * @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
10940 * @param {Boolean} keepExisting (optional) true to keep existing selections
10941 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10943 select : function(nodeInfo, keepExisting, suppressEvent){
10944 if(nodeInfo instanceof Array){
10946 this.clearSelections(true);
10948 for(var i = 0, len = nodeInfo.length; i < len; i++){
10949 this.select(nodeInfo[i], true, true);
10953 var node = this.getNode(nodeInfo);
10954 if(!node || this.isSelected(node)){
10955 return; // already selected.
10958 this.clearSelections(true);
10960 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10961 Roo.fly(node).addClass(this.selectedClass);
10962 this.selections.push(node);
10963 if(!suppressEvent){
10964 this.fireEvent("selectionchange", this, this.selections);
10972 * @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
10973 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10974 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10976 unselect : function(nodeInfo, keepExisting, suppressEvent)
10978 if(nodeInfo instanceof Array){
10979 Roo.each(this.selections, function(s) {
10980 this.unselect(s, nodeInfo);
10984 var node = this.getNode(nodeInfo);
10985 if(!node || !this.isSelected(node)){
10986 Roo.log("not selected");
10987 return; // not selected.
10991 Roo.each(this.selections, function(s) {
10993 Roo.fly(node).removeClass(this.selectedClass);
11000 this.selections= ns;
11001 this.fireEvent("selectionchange", this, this.selections);
11005 * Gets a template node.
11006 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11007 * @return {HTMLElement} The node or null if it wasn't found
11009 getNode : function(nodeInfo){
11010 if(typeof nodeInfo == "string"){
11011 return document.getElementById(nodeInfo);
11012 }else if(typeof nodeInfo == "number"){
11013 return this.nodes[nodeInfo];
11019 * Gets a range template nodes.
11020 * @param {Number} startIndex
11021 * @param {Number} endIndex
11022 * @return {Array} An array of nodes
11024 getNodes : function(start, end){
11025 var ns = this.nodes;
11026 start = start || 0;
11027 end = typeof end == "undefined" ? ns.length - 1 : end;
11030 for(var i = start; i <= end; i++){
11034 for(var i = start; i >= end; i--){
11042 * Finds the index of the passed node
11043 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11044 * @return {Number} The index of the node or -1
11046 indexOf : function(node){
11047 node = this.getNode(node);
11048 if(typeof node.nodeIndex == "number"){
11049 return node.nodeIndex;
11051 var ns = this.nodes;
11052 for(var i = 0, len = ns.length; i < len; i++){
11063 * based on jquery fullcalendar
11067 Roo.bootstrap = Roo.bootstrap || {};
11069 * @class Roo.bootstrap.Calendar
11070 * @extends Roo.bootstrap.Component
11071 * Bootstrap Calendar class
11072 * @cfg {Boolean} loadMask (true|false) default false
11073 * @cfg {Object} header generate the user specific header of the calendar, default false
11076 * Create a new Container
11077 * @param {Object} config The config object
11082 Roo.bootstrap.Calendar = function(config){
11083 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11087 * Fires when a date is selected
11088 * @param {DatePicker} this
11089 * @param {Date} date The selected date
11093 * @event monthchange
11094 * Fires when the displayed month changes
11095 * @param {DatePicker} this
11096 * @param {Date} date The selected month
11098 'monthchange': true,
11100 * @event evententer
11101 * Fires when mouse over an event
11102 * @param {Calendar} this
11103 * @param {event} Event
11105 'evententer': true,
11107 * @event eventleave
11108 * Fires when the mouse leaves an
11109 * @param {Calendar} this
11112 'eventleave': true,
11114 * @event eventclick
11115 * Fires when the mouse click an
11116 * @param {Calendar} this
11125 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11128 * @cfg {Number} startDay
11129 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11137 getAutoCreate : function(){
11140 var fc_button = function(name, corner, style, content ) {
11141 return Roo.apply({},{
11143 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11145 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11148 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11159 style : 'width:100%',
11166 cls : 'fc-header-left',
11168 fc_button('prev', 'left', 'arrow', '‹' ),
11169 fc_button('next', 'right', 'arrow', '›' ),
11170 { tag: 'span', cls: 'fc-header-space' },
11171 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11179 cls : 'fc-header-center',
11183 cls: 'fc-header-title',
11186 html : 'month / year'
11194 cls : 'fc-header-right',
11196 /* fc_button('month', 'left', '', 'month' ),
11197 fc_button('week', '', '', 'week' ),
11198 fc_button('day', 'right', '', 'day' )
11210 header = this.header;
11213 var cal_heads = function() {
11215 // fixme - handle this.
11217 for (var i =0; i < Date.dayNames.length; i++) {
11218 var d = Date.dayNames[i];
11221 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11222 html : d.substring(0,3)
11226 ret[0].cls += ' fc-first';
11227 ret[6].cls += ' fc-last';
11230 var cal_cell = function(n) {
11233 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11238 cls: 'fc-day-number',
11242 cls: 'fc-day-content',
11246 style: 'position: relative;' // height: 17px;
11258 var cal_rows = function() {
11261 for (var r = 0; r < 6; r++) {
11268 for (var i =0; i < Date.dayNames.length; i++) {
11269 var d = Date.dayNames[i];
11270 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11273 row.cn[0].cls+=' fc-first';
11274 row.cn[0].cn[0].style = 'min-height:90px';
11275 row.cn[6].cls+=' fc-last';
11279 ret[0].cls += ' fc-first';
11280 ret[4].cls += ' fc-prev-last';
11281 ret[5].cls += ' fc-last';
11288 cls: 'fc-border-separate',
11289 style : 'width:100%',
11297 cls : 'fc-first fc-last',
11315 cls : 'fc-content',
11316 style : "position: relative;",
11319 cls : 'fc-view fc-view-month fc-grid',
11320 style : 'position: relative',
11321 unselectable : 'on',
11324 cls : 'fc-event-container',
11325 style : 'position:absolute;z-index:8;top:0;left:0;'
11343 initEvents : function()
11346 throw "can not find store for calendar";
11352 style: "text-align:center",
11356 style: "background-color:white;width:50%;margin:250 auto",
11360 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11371 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11373 var size = this.el.select('.fc-content', true).first().getSize();
11374 this.maskEl.setSize(size.width, size.height);
11375 this.maskEl.enableDisplayMode("block");
11376 if(!this.loadMask){
11377 this.maskEl.hide();
11380 this.store = Roo.factory(this.store, Roo.data);
11381 this.store.on('load', this.onLoad, this);
11382 this.store.on('beforeload', this.onBeforeLoad, this);
11386 this.cells = this.el.select('.fc-day',true);
11387 //Roo.log(this.cells);
11388 this.textNodes = this.el.query('.fc-day-number');
11389 this.cells.addClassOnOver('fc-state-hover');
11391 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11392 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11393 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11394 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11396 this.on('monthchange', this.onMonthChange, this);
11398 this.update(new Date().clearTime());
11401 resize : function() {
11402 var sz = this.el.getSize();
11404 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11405 this.el.select('.fc-day-content div',true).setHeight(34);
11410 showPrevMonth : function(e){
11411 this.update(this.activeDate.add("mo", -1));
11413 showToday : function(e){
11414 this.update(new Date().clearTime());
11417 showNextMonth : function(e){
11418 this.update(this.activeDate.add("mo", 1));
11422 showPrevYear : function(){
11423 this.update(this.activeDate.add("y", -1));
11427 showNextYear : function(){
11428 this.update(this.activeDate.add("y", 1));
11433 update : function(date)
11435 var vd = this.activeDate;
11436 this.activeDate = date;
11437 // if(vd && this.el){
11438 // var t = date.getTime();
11439 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11440 // Roo.log('using add remove');
11442 // this.fireEvent('monthchange', this, date);
11444 // this.cells.removeClass("fc-state-highlight");
11445 // this.cells.each(function(c){
11446 // if(c.dateValue == t){
11447 // c.addClass("fc-state-highlight");
11448 // setTimeout(function(){
11449 // try{c.dom.firstChild.focus();}catch(e){}
11459 var days = date.getDaysInMonth();
11461 var firstOfMonth = date.getFirstDateOfMonth();
11462 var startingPos = firstOfMonth.getDay()-this.startDay;
11464 if(startingPos < this.startDay){
11468 var pm = date.add(Date.MONTH, -1);
11469 var prevStart = pm.getDaysInMonth()-startingPos;
11471 this.cells = this.el.select('.fc-day',true);
11472 this.textNodes = this.el.query('.fc-day-number');
11473 this.cells.addClassOnOver('fc-state-hover');
11475 var cells = this.cells.elements;
11476 var textEls = this.textNodes;
11478 Roo.each(cells, function(cell){
11479 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11482 days += startingPos;
11484 // convert everything to numbers so it's fast
11485 var day = 86400000;
11486 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11489 //Roo.log(prevStart);
11491 var today = new Date().clearTime().getTime();
11492 var sel = date.clearTime().getTime();
11493 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11494 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11495 var ddMatch = this.disabledDatesRE;
11496 var ddText = this.disabledDatesText;
11497 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11498 var ddaysText = this.disabledDaysText;
11499 var format = this.format;
11501 var setCellClass = function(cal, cell){
11503 //Roo.log('set Cell Class');
11505 var t = d.getTime();
11509 cell.dateValue = t;
11511 cell.className += " fc-today";
11512 cell.className += " fc-state-highlight";
11513 cell.title = cal.todayText;
11516 // disable highlight in other month..
11517 //cell.className += " fc-state-highlight";
11522 cell.className = " fc-state-disabled";
11523 cell.title = cal.minText;
11527 cell.className = " fc-state-disabled";
11528 cell.title = cal.maxText;
11532 if(ddays.indexOf(d.getDay()) != -1){
11533 cell.title = ddaysText;
11534 cell.className = " fc-state-disabled";
11537 if(ddMatch && format){
11538 var fvalue = d.dateFormat(format);
11539 if(ddMatch.test(fvalue)){
11540 cell.title = ddText.replace("%0", fvalue);
11541 cell.className = " fc-state-disabled";
11545 if (!cell.initialClassName) {
11546 cell.initialClassName = cell.dom.className;
11549 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11554 for(; i < startingPos; i++) {
11555 textEls[i].innerHTML = (++prevStart);
11556 d.setDate(d.getDate()+1);
11558 cells[i].className = "fc-past fc-other-month";
11559 setCellClass(this, cells[i]);
11564 for(; i < days; i++){
11565 intDay = i - startingPos + 1;
11566 textEls[i].innerHTML = (intDay);
11567 d.setDate(d.getDate()+1);
11569 cells[i].className = ''; // "x-date-active";
11570 setCellClass(this, cells[i]);
11574 for(; i < 42; i++) {
11575 textEls[i].innerHTML = (++extraDays);
11576 d.setDate(d.getDate()+1);
11578 cells[i].className = "fc-future fc-other-month";
11579 setCellClass(this, cells[i]);
11582 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11584 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11586 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11587 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11589 if(totalRows != 6){
11590 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11591 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11594 this.fireEvent('monthchange', this, date);
11598 if(!this.internalRender){
11599 var main = this.el.dom.firstChild;
11600 var w = main.offsetWidth;
11601 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11602 Roo.fly(main).setWidth(w);
11603 this.internalRender = true;
11604 // opera does not respect the auto grow header center column
11605 // then, after it gets a width opera refuses to recalculate
11606 // without a second pass
11607 if(Roo.isOpera && !this.secondPass){
11608 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11609 this.secondPass = true;
11610 this.update.defer(10, this, [date]);
11617 findCell : function(dt) {
11618 dt = dt.clearTime().getTime();
11620 this.cells.each(function(c){
11621 //Roo.log("check " +c.dateValue + '?=' + dt);
11622 if(c.dateValue == dt){
11632 findCells : function(ev) {
11633 var s = ev.start.clone().clearTime().getTime();
11635 var e= ev.end.clone().clearTime().getTime();
11638 this.cells.each(function(c){
11639 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11641 if(c.dateValue > e){
11644 if(c.dateValue < s){
11653 // findBestRow: function(cells)
11657 // for (var i =0 ; i < cells.length;i++) {
11658 // ret = Math.max(cells[i].rows || 0,ret);
11665 addItem : function(ev)
11667 // look for vertical location slot in
11668 var cells = this.findCells(ev);
11670 // ev.row = this.findBestRow(cells);
11672 // work out the location.
11676 for(var i =0; i < cells.length; i++) {
11684 if (crow.start.getY() == cells[i].getY()) {
11686 crow.end = cells[i];
11702 ev.rendered = false;
11703 // for (var i = 0; i < cells.length;i++) {
11704 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11708 this.calevents.push(ev);
11711 clearEvents: function() {
11713 if(!this.calevents){
11717 Roo.each(this.cells.elements, function(c){
11722 Roo.each(this.calevents, function(e) {
11723 Roo.each(e.els, function(el) {
11724 el.un('mouseenter' ,this.onEventEnter, this);
11725 el.un('mouseleave' ,this.onEventLeave, this);
11730 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11736 renderEvents: function()
11738 // first make sure there is enough space..
11739 this.cells.each(function(c) {
11744 for (var e = 0; e < this.calevents.length; e++) {
11746 var ev = this.calevents[e];
11747 var cells = ev.cells;
11748 var rows = ev.rows;
11750 for(var i = 0; i < cells.length; i++){
11752 var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11754 if(cells.length < 2 && cbox.rows.length > 3){
11755 cbox.more.push(ev);
11759 cbox.rows.push(ev);
11765 this.cells.each(function(c) {
11766 if(c.more.length && c.more.length == 1){
11767 c.rows.push(c.more.pop());
11770 var r = (c.more.length) ? c.rows.length + 1 : c.rows.length;
11771 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, r * 20));
11774 for (var e = 0; e < c.rows.length; e++){
11775 var ev = c.rows[e];
11781 var cells = ev.cells;
11782 var rows = ev.rows;
11784 for(var i = 0; i < rows.length; i++) {
11786 // how many rows should it span..
11789 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11790 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11792 unselectable : "on",
11795 cls: 'fc-event-inner',
11799 // cls: 'fc-event-time',
11800 // html : cells.length > 1 ? '' : ev.time
11804 cls: 'fc-event-title',
11805 html : String.format('{0}', ev.title)
11812 cls: 'ui-resizable-handle ui-resizable-e',
11813 html : '  '
11820 cfg.cls += ' fc-event-start';
11822 if ((i+1) == rows.length) {
11823 cfg.cls += ' fc-event-end';
11826 var ctr = _this.el.select('.fc-event-container',true).first();
11827 var cg = ctr.createChild(cfg);
11829 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11830 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11832 cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11833 cg.setWidth(ebox.right - sbox.x -2);
11835 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11836 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11837 cg.on('click', _this.onEventClick, _this, ev);
11841 ev.rendered = true;
11849 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11850 style : 'position: absolute',
11851 unselectable : "on",
11854 cls: 'fc-event-inner',
11858 cls: 'fc-event-title',
11866 cls: 'ui-resizable-handle ui-resizable-e',
11867 html : '  '
11873 var ctr = _this.el.select('.fc-event-container',true).first();
11874 var cg = ctr.createChild(cfg);
11876 var sbox = c.select('.fc-day-content',true).first().getBox();
11877 var ebox = c.select('.fc-day-content',true).first().getBox();
11879 cg.setXY([sbox.x +2, sbox.y +(c.rows.length * 20)]);
11880 cg.setWidth(ebox.right - sbox.x -2);
11882 cg.on('click', _this.onMoreEventClick, _this, c.more);
11892 onEventEnter: function (e, el,event,d) {
11893 this.fireEvent('evententer', this, el, event);
11896 onEventLeave: function (e, el,event,d) {
11897 this.fireEvent('eventleave', this, el, event);
11900 onEventClick: function (e, el,event,d) {
11901 this.fireEvent('eventclick', this, el, event);
11904 onMonthChange: function () {
11908 onMoreEventClick: function(e, el, more)
11912 this.calpopover.placement = 'right';
11913 this.calpopover.setTitle('More');
11915 this.calpopover.setContent('');
11917 var ctr = this.calpopover.el.select('.popover-content', true).first();
11919 Roo.each(more, function(m){
11921 cls : 'fc-event-hori fc-event-draggable',
11924 var cg = ctr.createChild(cfg);
11926 cg.on('click', _this.onEventClick, _this, m);
11929 this.calpopover.show(el);
11934 onLoad: function ()
11936 this.calevents = [];
11939 if(this.store.getCount() > 0){
11940 this.store.data.each(function(d){
11943 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11944 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11945 time : d.data.start_time,
11946 title : d.data.title,
11947 description : d.data.description,
11948 venue : d.data.venue
11953 this.renderEvents();
11955 if(this.calevents.length && this.loadMask){
11956 this.maskEl.hide();
11960 onBeforeLoad: function()
11962 this.clearEvents();
11964 this.maskEl.show();
11978 * @class Roo.bootstrap.Popover
11979 * @extends Roo.bootstrap.Component
11980 * Bootstrap Popover class
11981 * @cfg {String} html contents of the popover (or false to use children..)
11982 * @cfg {String} title of popover (or false to hide)
11983 * @cfg {String} placement how it is placed
11984 * @cfg {String} trigger click || hover (or false to trigger manually)
11985 * @cfg {String} over what (parent or false to trigger manually.)
11988 * Create a new Popover
11989 * @param {Object} config The config object
11992 Roo.bootstrap.Popover = function(config){
11993 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11996 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11998 title: 'Fill in a title',
12001 placement : 'right',
12002 trigger : 'hover', // hover
12006 can_build_overlaid : false,
12008 getChildContainer : function()
12010 return this.el.select('.popover-content',true).first();
12013 getAutoCreate : function(){
12014 Roo.log('make popover?');
12016 cls : 'popover roo-dynamic',
12017 style: 'display:block',
12023 cls : 'popover-inner',
12027 cls: 'popover-title',
12031 cls : 'popover-content',
12042 setTitle: function(str)
12044 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12046 setContent: function(str)
12048 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12050 // as it get's added to the bottom of the page.
12051 onRender : function(ct, position)
12053 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12055 var cfg = Roo.apply({}, this.getAutoCreate());
12059 cfg.cls += ' ' + this.cls;
12062 cfg.style = this.style;
12064 Roo.log("adding to ")
12065 this.el = Roo.get(document.body).createChild(cfg, position);
12071 initEvents : function()
12073 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12074 this.el.enableDisplayMode('block');
12076 if (this.over === false) {
12079 if (this.triggers === false) {
12082 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12083 var triggers = this.trigger ? this.trigger.split(' ') : [];
12084 Roo.each(triggers, function(trigger) {
12086 if (trigger == 'click') {
12087 on_el.on('click', this.toggle, this);
12088 } else if (trigger != 'manual') {
12089 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12090 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12092 on_el.on(eventIn ,this.enter, this);
12093 on_el.on(eventOut, this.leave, this);
12104 toggle : function () {
12105 this.hoverState == 'in' ? this.leave() : this.enter();
12108 enter : function () {
12111 clearTimeout(this.timeout);
12113 this.hoverState = 'in'
12115 if (!this.delay || !this.delay.show) {
12120 this.timeout = setTimeout(function () {
12121 if (_t.hoverState == 'in') {
12124 }, this.delay.show)
12126 leave : function() {
12127 clearTimeout(this.timeout);
12129 this.hoverState = 'out'
12131 if (!this.delay || !this.delay.hide) {
12136 this.timeout = setTimeout(function () {
12137 if (_t.hoverState == 'out') {
12140 }, this.delay.hide)
12143 show : function (on_el)
12146 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12149 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12150 if (this.html !== false) {
12151 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12153 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12154 if (!this.title.length) {
12155 this.el.select('.popover-title',true).hide();
12158 var placement = typeof this.placement == 'function' ?
12159 this.placement.call(this, this.el, on_el) :
12162 var autoToken = /\s?auto?\s?/i;
12163 var autoPlace = autoToken.test(placement);
12165 placement = placement.replace(autoToken, '') || 'top';
12169 //this.el.setXY([0,0]);
12171 this.el.dom.style.display='block';
12172 this.el.addClass(placement);
12174 //this.el.appendTo(on_el);
12176 var p = this.getPosition();
12177 var box = this.el.getBox();
12182 var align = Roo.bootstrap.Popover.alignment[placement]
12183 this.el.alignTo(on_el, align[0],align[1]);
12184 //var arrow = this.el.select('.arrow',true).first();
12185 //arrow.set(align[2],
12187 this.el.addClass('in');
12188 this.hoverState = null;
12190 if (this.el.hasClass('fade')) {
12197 this.el.setXY([0,0]);
12198 this.el.removeClass('in');
12205 Roo.bootstrap.Popover.alignment = {
12206 'left' : ['r-l', [-10,0], 'right'],
12207 'right' : ['l-r', [10,0], 'left'],
12208 'bottom' : ['t-b', [0,10], 'top'],
12209 'top' : [ 'b-t', [0,-10], 'bottom']
12220 * @class Roo.bootstrap.Progress
12221 * @extends Roo.bootstrap.Component
12222 * Bootstrap Progress class
12223 * @cfg {Boolean} striped striped of the progress bar
12224 * @cfg {Boolean} active animated of the progress bar
12228 * Create a new Progress
12229 * @param {Object} config The config object
12232 Roo.bootstrap.Progress = function(config){
12233 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12236 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12241 getAutoCreate : function(){
12249 cfg.cls += ' progress-striped';
12253 cfg.cls += ' active';
12272 * @class Roo.bootstrap.ProgressBar
12273 * @extends Roo.bootstrap.Component
12274 * Bootstrap ProgressBar class
12275 * @cfg {Number} aria_valuenow aria-value now
12276 * @cfg {Number} aria_valuemin aria-value min
12277 * @cfg {Number} aria_valuemax aria-value max
12278 * @cfg {String} label label for the progress bar
12279 * @cfg {String} panel (success | info | warning | danger )
12280 * @cfg {String} role role of the progress bar
12281 * @cfg {String} sr_only text
12285 * Create a new ProgressBar
12286 * @param {Object} config The config object
12289 Roo.bootstrap.ProgressBar = function(config){
12290 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12293 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12297 aria_valuemax : 100,
12303 getAutoCreate : function()
12308 cls: 'progress-bar',
12309 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12321 cfg.role = this.role;
12324 if(this.aria_valuenow){
12325 cfg['aria-valuenow'] = this.aria_valuenow;
12328 if(this.aria_valuemin){
12329 cfg['aria-valuemin'] = this.aria_valuemin;
12332 if(this.aria_valuemax){
12333 cfg['aria-valuemax'] = this.aria_valuemax;
12336 if(this.label && !this.sr_only){
12337 cfg.html = this.label;
12341 cfg.cls += ' progress-bar-' + this.panel;
12347 update : function(aria_valuenow)
12349 this.aria_valuenow = aria_valuenow;
12351 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12366 * @class Roo.bootstrap.TabPanel
12367 * @extends Roo.bootstrap.Component
12368 * Bootstrap TabPanel class
12369 * @cfg {Boolean} active panel active
12370 * @cfg {String} html panel content
12371 * @cfg {String} tabId tab relate id
12372 * @cfg {String} navId The navbar which triggers show hide
12376 * Create a new TabPanel
12377 * @param {Object} config The config object
12380 Roo.bootstrap.TabPanel = function(config){
12381 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12385 * Fires when the active status changes
12386 * @param {Roo.bootstrap.TabPanel} this
12387 * @param {Boolean} state the new state
12394 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12401 getAutoCreate : function(){
12405 html: this.html || ''
12409 cfg.cls += ' active';
12413 cfg.tabId = this.tabId;
12418 onRender : function(ct, position)
12420 // Roo.log("Call onRender: " + this.xtype);
12422 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12424 if (this.navId && this.tabId) {
12425 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12427 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12429 item.on('changed', function(item, state) {
12430 this.setActive(state);
12436 setActive: function(state)
12438 Roo.log("panel - set active " + this.tabId + "=" + state);
12440 this.active = state;
12442 this.el.removeClass('active');
12444 } else if (!this.el.hasClass('active')) {
12445 this.el.addClass('active');
12447 this.fireEvent('changed', this, state);
12464 * @class Roo.bootstrap.DateField
12465 * @extends Roo.bootstrap.Input
12466 * Bootstrap DateField class
12467 * @cfg {Number} weekStart default 0
12468 * @cfg {Number} weekStart default 0
12469 * @cfg {Number} viewMode default empty, (months|years)
12470 * @cfg {Number} minViewMode default empty, (months|years)
12471 * @cfg {Number} startDate default -Infinity
12472 * @cfg {Number} endDate default Infinity
12473 * @cfg {Boolean} todayHighlight default false
12474 * @cfg {Boolean} todayBtn default false
12475 * @cfg {Boolean} calendarWeeks default false
12476 * @cfg {Object} daysOfWeekDisabled default empty
12478 * @cfg {Boolean} keyboardNavigation default true
12479 * @cfg {String} language default en
12482 * Create a new DateField
12483 * @param {Object} config The config object
12486 Roo.bootstrap.DateField = function(config){
12487 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12491 * Fires when this field show.
12492 * @param {Roo.bootstrap.DateField} this
12493 * @param {Mixed} date The date value
12498 * Fires when this field hide.
12499 * @param {Roo.bootstrap.DateField} this
12500 * @param {Mixed} date The date value
12505 * Fires when select a date.
12506 * @param {Roo.bootstrap.DateField} this
12507 * @param {Mixed} date The date value
12513 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12516 * @cfg {String} format
12517 * The default date format string which can be overriden for localization support. The format must be
12518 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12522 * @cfg {String} altFormats
12523 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12524 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12526 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12534 todayHighlight : false,
12540 keyboardNavigation: true,
12542 calendarWeeks: false,
12544 startDate: -Infinity,
12548 daysOfWeekDisabled: [],
12552 UTCDate: function()
12554 return new Date(Date.UTC.apply(Date, arguments));
12557 UTCToday: function()
12559 var today = new Date();
12560 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12563 getDate: function() {
12564 var d = this.getUTCDate();
12565 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12568 getUTCDate: function() {
12572 setDate: function(d) {
12573 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12576 setUTCDate: function(d) {
12578 this.setValue(this.formatDate(this.date));
12581 onRender: function(ct, position)
12584 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12586 this.language = this.language || 'en';
12587 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12588 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12590 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12591 this.format = this.format || 'm/d/y';
12592 this.isInline = false;
12593 this.isInput = true;
12594 this.component = this.el.select('.add-on', true).first() || false;
12595 this.component = (this.component && this.component.length === 0) ? false : this.component;
12596 this.hasInput = this.component && this.inputEL().length;
12598 if (typeof(this.minViewMode === 'string')) {
12599 switch (this.minViewMode) {
12601 this.minViewMode = 1;
12604 this.minViewMode = 2;
12607 this.minViewMode = 0;
12612 if (typeof(this.viewMode === 'string')) {
12613 switch (this.viewMode) {
12626 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12628 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12630 this.picker().on('mousedown', this.onMousedown, this);
12631 this.picker().on('click', this.onClick, this);
12633 this.picker().addClass('datepicker-dropdown');
12635 this.startViewMode = this.viewMode;
12638 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12639 if(!this.calendarWeeks){
12644 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12645 v.attr('colspan', function(i, val){
12646 return parseInt(val) + 1;
12651 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12653 this.setStartDate(this.startDate);
12654 this.setEndDate(this.endDate);
12656 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12663 if(this.isInline) {
12668 picker : function()
12670 return this.el.select('.datepicker', true).first();
12673 fillDow: function()
12675 var dowCnt = this.weekStart;
12684 if(this.calendarWeeks){
12692 while (dowCnt < this.weekStart + 7) {
12696 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12700 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12703 fillMonths: function()
12706 var months = this.picker().select('>.datepicker-months td', true).first();
12708 months.dom.innerHTML = '';
12714 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12717 months.createChild(month);
12722 update: function(){
12724 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12726 if (this.date < this.startDate) {
12727 this.viewDate = new Date(this.startDate);
12728 } else if (this.date > this.endDate) {
12729 this.viewDate = new Date(this.endDate);
12731 this.viewDate = new Date(this.date);
12738 var d = new Date(this.viewDate),
12739 year = d.getUTCFullYear(),
12740 month = d.getUTCMonth(),
12741 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12742 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12743 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12744 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12745 currentDate = this.date && this.date.valueOf(),
12746 today = this.UTCToday();
12748 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12750 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12752 // this.picker.select('>tfoot th.today').
12753 // .text(dates[this.language].today)
12754 // .toggle(this.todayBtn !== false);
12756 this.updateNavArrows();
12759 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12761 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12763 prevMonth.setUTCDate(day);
12765 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12767 var nextMonth = new Date(prevMonth);
12769 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12771 nextMonth = nextMonth.valueOf();
12773 var fillMonths = false;
12775 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12777 while(prevMonth.valueOf() < nextMonth) {
12780 if (prevMonth.getUTCDay() === this.weekStart) {
12782 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12790 if(this.calendarWeeks){
12791 // ISO 8601: First week contains first thursday.
12792 // ISO also states week starts on Monday, but we can be more abstract here.
12794 // Start of current week: based on weekstart/current date
12795 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12796 // Thursday of this week
12797 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12798 // First Thursday of year, year from thursday
12799 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12800 // Calendar week: ms between thursdays, div ms per day, div 7 days
12801 calWeek = (th - yth) / 864e5 / 7 + 1;
12803 fillMonths.cn.push({
12811 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12813 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12816 if (this.todayHighlight &&
12817 prevMonth.getUTCFullYear() == today.getFullYear() &&
12818 prevMonth.getUTCMonth() == today.getMonth() &&
12819 prevMonth.getUTCDate() == today.getDate()) {
12820 clsName += ' today';
12823 if (currentDate && prevMonth.valueOf() === currentDate) {
12824 clsName += ' active';
12827 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12828 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12829 clsName += ' disabled';
12832 fillMonths.cn.push({
12834 cls: 'day ' + clsName,
12835 html: prevMonth.getDate()
12838 prevMonth.setDate(prevMonth.getDate()+1);
12841 var currentYear = this.date && this.date.getUTCFullYear();
12842 var currentMonth = this.date && this.date.getUTCMonth();
12844 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12846 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12847 v.removeClass('active');
12849 if(currentYear === year && k === currentMonth){
12850 v.addClass('active');
12853 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12854 v.addClass('disabled');
12860 year = parseInt(year/10, 10) * 10;
12862 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12864 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12867 for (var i = -1; i < 11; i++) {
12868 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12870 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12878 showMode: function(dir) {
12880 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12882 Roo.each(this.picker().select('>div',true).elements, function(v){
12883 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12886 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12891 if(this.isInline) return;
12893 this.picker().removeClass(['bottom', 'top']);
12895 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12897 * place to the top of element!
12901 this.picker().addClass('top');
12902 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12907 this.picker().addClass('bottom');
12909 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12912 parseDate : function(value){
12913 if(!value || value instanceof Date){
12916 var v = Date.parseDate(value, this.format);
12917 if (!v && this.useIso) {
12918 v = Date.parseDate(value, 'Y-m-d');
12920 if(!v && this.altFormats){
12921 if(!this.altFormatsArray){
12922 this.altFormatsArray = this.altFormats.split("|");
12924 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12925 v = Date.parseDate(value, this.altFormatsArray[i]);
12931 formatDate : function(date, fmt){
12932 return (!date || !(date instanceof Date)) ?
12933 date : date.dateFormat(fmt || this.format);
12936 onFocus : function()
12938 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12942 onBlur : function()
12944 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12950 this.picker().show();
12954 this.fireEvent('show', this, this.date);
12959 if(this.isInline) return;
12960 this.picker().hide();
12961 this.viewMode = this.startViewMode;
12964 this.fireEvent('hide', this, this.date);
12968 onMousedown: function(e){
12969 e.stopPropagation();
12970 e.preventDefault();
12973 keyup: function(e){
12974 Roo.bootstrap.DateField.superclass.keyup.call(this);
12979 setValue: function(v){
12980 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12982 this.fireEvent('select', this, this.date);
12986 fireKey: function(e){
12987 if (!this.picker().isVisible()){
12988 if (e.keyCode == 27) // allow escape to hide and re-show picker
12992 var dateChanged = false,
12994 newDate, newViewDate;
12998 e.preventDefault();
13002 if (!this.keyboardNavigation) break;
13003 dir = e.keyCode == 37 ? -1 : 1;
13006 newDate = this.moveYear(this.date, dir);
13007 newViewDate = this.moveYear(this.viewDate, dir);
13008 } else if (e.shiftKey){
13009 newDate = this.moveMonth(this.date, dir);
13010 newViewDate = this.moveMonth(this.viewDate, dir);
13012 newDate = new Date(this.date);
13013 newDate.setUTCDate(this.date.getUTCDate() + dir);
13014 newViewDate = new Date(this.viewDate);
13015 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13017 if (this.dateWithinRange(newDate)){
13018 this.date = newDate;
13019 this.viewDate = newViewDate;
13020 this.setValue(this.formatDate(this.date));
13022 e.preventDefault();
13023 dateChanged = true;
13028 if (!this.keyboardNavigation) break;
13029 dir = e.keyCode == 38 ? -1 : 1;
13031 newDate = this.moveYear(this.date, dir);
13032 newViewDate = this.moveYear(this.viewDate, dir);
13033 } else if (e.shiftKey){
13034 newDate = this.moveMonth(this.date, dir);
13035 newViewDate = this.moveMonth(this.viewDate, dir);
13037 newDate = new Date(this.date);
13038 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13039 newViewDate = new Date(this.viewDate);
13040 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13042 if (this.dateWithinRange(newDate)){
13043 this.date = newDate;
13044 this.viewDate = newViewDate;
13045 this.setValue(this.formatDate(this.date));
13047 e.preventDefault();
13048 dateChanged = true;
13052 this.setValue(this.formatDate(this.date));
13054 e.preventDefault();
13057 this.setValue(this.formatDate(this.date));
13064 onClick: function(e) {
13065 e.stopPropagation();
13066 e.preventDefault();
13068 var target = e.getTarget();
13070 if(target.nodeName.toLowerCase() === 'i'){
13071 target = Roo.get(target).dom.parentNode;
13074 var nodeName = target.nodeName;
13075 var className = target.className;
13076 var html = target.innerHTML;
13078 switch(nodeName.toLowerCase()) {
13080 switch(className) {
13086 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13087 switch(this.viewMode){
13089 this.viewDate = this.moveMonth(this.viewDate, dir);
13093 this.viewDate = this.moveYear(this.viewDate, dir);
13099 var date = new Date();
13100 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13102 this.setValue(this.formatDate(this.date));
13108 if (className.indexOf('disabled') === -1) {
13109 this.viewDate.setUTCDate(1);
13110 if (className.indexOf('month') !== -1) {
13111 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13113 var year = parseInt(html, 10) || 0;
13114 this.viewDate.setUTCFullYear(year);
13123 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13124 var day = parseInt(html, 10) || 1;
13125 var year = this.viewDate.getUTCFullYear(),
13126 month = this.viewDate.getUTCMonth();
13128 if (className.indexOf('old') !== -1) {
13135 } else if (className.indexOf('new') !== -1) {
13143 this.date = this.UTCDate(year, month, day,0,0,0,0);
13144 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13146 this.setValue(this.formatDate(this.date));
13153 setStartDate: function(startDate){
13154 this.startDate = startDate || -Infinity;
13155 if (this.startDate !== -Infinity) {
13156 this.startDate = this.parseDate(this.startDate);
13159 this.updateNavArrows();
13162 setEndDate: function(endDate){
13163 this.endDate = endDate || Infinity;
13164 if (this.endDate !== Infinity) {
13165 this.endDate = this.parseDate(this.endDate);
13168 this.updateNavArrows();
13171 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13172 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13173 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13174 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13176 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13177 return parseInt(d, 10);
13180 this.updateNavArrows();
13183 updateNavArrows: function() {
13184 var d = new Date(this.viewDate),
13185 year = d.getUTCFullYear(),
13186 month = d.getUTCMonth();
13188 Roo.each(this.picker().select('.prev', true).elements, function(v){
13190 switch (this.viewMode) {
13193 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13199 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13206 Roo.each(this.picker().select('.next', true).elements, function(v){
13208 switch (this.viewMode) {
13211 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13217 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13225 moveMonth: function(date, dir){
13226 if (!dir) return date;
13227 var new_date = new Date(date.valueOf()),
13228 day = new_date.getUTCDate(),
13229 month = new_date.getUTCMonth(),
13230 mag = Math.abs(dir),
13232 dir = dir > 0 ? 1 : -1;
13235 // If going back one month, make sure month is not current month
13236 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13238 return new_date.getUTCMonth() == month;
13240 // If going forward one month, make sure month is as expected
13241 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13243 return new_date.getUTCMonth() != new_month;
13245 new_month = month + dir;
13246 new_date.setUTCMonth(new_month);
13247 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13248 if (new_month < 0 || new_month > 11)
13249 new_month = (new_month + 12) % 12;
13251 // For magnitudes >1, move one month at a time...
13252 for (var i=0; i<mag; i++)
13253 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13254 new_date = this.moveMonth(new_date, dir);
13255 // ...then reset the day, keeping it in the new month
13256 new_month = new_date.getUTCMonth();
13257 new_date.setUTCDate(day);
13259 return new_month != new_date.getUTCMonth();
13262 // Common date-resetting loop -- if date is beyond end of month, make it
13265 new_date.setUTCDate(--day);
13266 new_date.setUTCMonth(new_month);
13271 moveYear: function(date, dir){
13272 return this.moveMonth(date, dir*12);
13275 dateWithinRange: function(date){
13276 return date >= this.startDate && date <= this.endDate;
13280 remove: function() {
13281 this.picker().remove();
13286 Roo.apply(Roo.bootstrap.DateField, {
13297 html: '<i class="icon-arrow-left"/>'
13307 html: '<i class="icon-arrow-right"/>'
13349 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13350 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13351 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13352 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13353 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13366 navFnc: 'FullYear',
13371 navFnc: 'FullYear',
13376 Roo.apply(Roo.bootstrap.DateField, {
13380 cls: 'datepicker dropdown-menu',
13384 cls: 'datepicker-days',
13388 cls: 'table-condensed',
13390 Roo.bootstrap.DateField.head,
13394 Roo.bootstrap.DateField.footer
13401 cls: 'datepicker-months',
13405 cls: 'table-condensed',
13407 Roo.bootstrap.DateField.head,
13408 Roo.bootstrap.DateField.content,
13409 Roo.bootstrap.DateField.footer
13416 cls: 'datepicker-years',
13420 cls: 'table-condensed',
13422 Roo.bootstrap.DateField.head,
13423 Roo.bootstrap.DateField.content,
13424 Roo.bootstrap.DateField.footer
13443 * @class Roo.bootstrap.TimeField
13444 * @extends Roo.bootstrap.Input
13445 * Bootstrap DateField class
13449 * Create a new TimeField
13450 * @param {Object} config The config object
13453 Roo.bootstrap.TimeField = function(config){
13454 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13458 * Fires when this field show.
13459 * @param {Roo.bootstrap.DateField} this
13460 * @param {Mixed} date The date value
13465 * Fires when this field hide.
13466 * @param {Roo.bootstrap.DateField} this
13467 * @param {Mixed} date The date value
13472 * Fires when select a date.
13473 * @param {Roo.bootstrap.DateField} this
13474 * @param {Mixed} date The date value
13480 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13483 * @cfg {String} format
13484 * The default time format string which can be overriden for localization support. The format must be
13485 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13489 onRender: function(ct, position)
13492 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13494 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13496 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13498 this.pop = this.picker().select('>.datepicker-time',true).first();
13499 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13501 this.picker().on('mousedown', this.onMousedown, this);
13502 this.picker().on('click', this.onClick, this);
13504 this.picker().addClass('datepicker-dropdown');
13509 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13510 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13511 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13512 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13513 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13514 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13518 fireKey: function(e){
13519 if (!this.picker().isVisible()){
13520 if (e.keyCode == 27) // allow escape to hide and re-show picker
13525 e.preventDefault();
13533 this.onTogglePeriod();
13536 this.onIncrementMinutes();
13539 this.onDecrementMinutes();
13548 onClick: function(e) {
13549 e.stopPropagation();
13550 e.preventDefault();
13553 picker : function()
13555 return this.el.select('.datepicker', true).first();
13558 fillTime: function()
13560 var time = this.pop.select('tbody', true).first();
13562 time.dom.innerHTML = '';
13577 cls: 'hours-up glyphicon glyphicon-chevron-up'
13597 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13618 cls: 'timepicker-hour',
13633 cls: 'timepicker-minute',
13648 cls: 'btn btn-primary period',
13670 cls: 'hours-down glyphicon glyphicon-chevron-down'
13690 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13708 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13715 var hours = this.time.getHours();
13716 var minutes = this.time.getMinutes();
13729 hours = hours - 12;
13733 hours = '0' + hours;
13737 minutes = '0' + minutes;
13740 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13741 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13742 this.pop.select('button', true).first().dom.innerHTML = period;
13748 this.picker().removeClass(['bottom', 'top']);
13750 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13752 * place to the top of element!
13756 this.picker().addClass('top');
13757 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13762 this.picker().addClass('bottom');
13764 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13767 onFocus : function()
13769 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13773 onBlur : function()
13775 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13781 this.picker().show();
13786 this.fireEvent('show', this, this.date);
13791 this.picker().hide();
13794 this.fireEvent('hide', this, this.date);
13797 setTime : function()
13800 this.setValue(this.time.format(this.format));
13802 this.fireEvent('select', this, this.date);
13807 onMousedown: function(e){
13808 e.stopPropagation();
13809 e.preventDefault();
13812 onIncrementHours: function()
13814 Roo.log('onIncrementHours');
13815 this.time = this.time.add(Date.HOUR, 1);
13820 onDecrementHours: function()
13822 Roo.log('onDecrementHours');
13823 this.time = this.time.add(Date.HOUR, -1);
13827 onIncrementMinutes: function()
13829 Roo.log('onIncrementMinutes');
13830 this.time = this.time.add(Date.MINUTE, 1);
13834 onDecrementMinutes: function()
13836 Roo.log('onDecrementMinutes');
13837 this.time = this.time.add(Date.MINUTE, -1);
13841 onTogglePeriod: function()
13843 Roo.log('onTogglePeriod');
13844 this.time = this.time.add(Date.HOUR, 12);
13851 Roo.apply(Roo.bootstrap.TimeField, {
13881 cls: 'btn btn-info ok',
13893 Roo.apply(Roo.bootstrap.TimeField, {
13897 cls: 'datepicker dropdown-menu',
13901 cls: 'datepicker-time',
13905 cls: 'table-condensed',
13907 Roo.bootstrap.TimeField.content,
13908 Roo.bootstrap.TimeField.footer
13927 * @class Roo.bootstrap.CheckBox
13928 * @extends Roo.bootstrap.Input
13929 * Bootstrap CheckBox class
13931 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13932 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13933 * @cfg {String} boxLabel The text that appears beside the checkbox
13934 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13935 * @cfg {Boolean} checked initnal the element
13939 * Create a new CheckBox
13940 * @param {Object} config The config object
13943 Roo.bootstrap.CheckBox = function(config){
13944 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13949 * Fires when the element is checked or unchecked.
13950 * @param {Roo.bootstrap.CheckBox} this This input
13951 * @param {Boolean} checked The new checked value
13957 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13959 inputType: 'checkbox',
13966 getAutoCreate : function()
13968 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13974 cfg.cls = 'form-group checkbox' //input-group
13982 type : this.inputType,
13983 value : (!this.checked) ? this.valueOff : this.inputValue,
13984 cls : 'roo-checkbox', //'form-box',
13985 placeholder : this.placeholder || ''
13989 if (this.weight) { // Validity check?
13990 cfg.cls += " checkbox-" + this.weight;
13993 if (this.disabled) {
13994 input.disabled=true;
13998 input.checked = this.checked;
14002 input.name = this.name;
14006 input.cls += ' input-' + this.size;
14010 ['xs','sm','md','lg'].map(function(size){
14011 if (settings[size]) {
14012 cfg.cls += ' col-' + size + '-' + settings[size];
14018 var inputblock = input;
14023 if (this.before || this.after) {
14026 cls : 'input-group',
14030 inputblock.cn.push({
14032 cls : 'input-group-addon',
14036 inputblock.cn.push(input);
14038 inputblock.cn.push({
14040 cls : 'input-group-addon',
14047 if (align ==='left' && this.fieldLabel.length) {
14048 Roo.log("left and has label");
14054 cls : 'control-label col-md-' + this.labelWidth,
14055 html : this.fieldLabel
14059 cls : "col-md-" + (12 - this.labelWidth),
14066 } else if ( this.fieldLabel.length) {
14071 tag: this.boxLabel ? 'span' : 'label',
14073 cls: 'control-label box-input-label',
14074 //cls : 'input-group-addon',
14075 html : this.fieldLabel
14085 Roo.log(" no label && no align");
14086 cfg.cn = [ inputblock ] ;
14095 html: this.boxLabel
14107 * return the real input element.
14109 inputEl: function ()
14111 return this.el.select('input.roo-checkbox',true).first();
14116 return this.el.select('label.control-label',true).first();
14119 initEvents : function()
14121 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14123 this.inputEl().on('click', this.onClick, this);
14127 onClick : function()
14129 this.setChecked(!this.checked);
14132 setChecked : function(state,suppressEvent)
14134 this.checked = state;
14136 this.inputEl().dom.checked = state;
14138 if(suppressEvent !== true){
14139 this.fireEvent('check', this, state);
14142 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14146 setValue : function(v,suppressEvent)
14148 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14162 * @class Roo.bootstrap.Radio
14163 * @extends Roo.bootstrap.CheckBox
14164 * Bootstrap Radio class
14167 * Create a new Radio
14168 * @param {Object} config The config object
14171 Roo.bootstrap.Radio = function(config){
14172 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14176 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14178 inputType: 'radio',
14182 getAutoCreate : function()
14184 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14190 cfg.cls = 'form-group radio' //input-group
14195 type : this.inputType,
14196 value : (!this.checked) ? this.valueOff : this.inputValue,
14198 placeholder : this.placeholder || ''
14201 if (this.weight) { // Validity check?
14202 cfg.cls += " radio-" + this.weight;
14204 if (this.disabled) {
14205 input.disabled=true;
14209 input.checked = this.checked;
14213 input.name = this.name;
14217 input.cls += ' input-' + this.size;
14221 ['xs','sm','md','lg'].map(function(size){
14222 if (settings[size]) {
14223 cfg.cls += ' col-' + size + '-' + settings[size];
14227 var inputblock = input;
14229 if (this.before || this.after) {
14232 cls : 'input-group',
14236 inputblock.cn.push({
14238 cls : 'input-group-addon',
14242 inputblock.cn.push(input);
14244 inputblock.cn.push({
14246 cls : 'input-group-addon',
14253 if (align ==='left' && this.fieldLabel.length) {
14254 Roo.log("left and has label");
14260 cls : 'control-label col-md-' + this.labelWidth,
14261 html : this.fieldLabel
14265 cls : "col-md-" + (12 - this.labelWidth),
14272 } else if ( this.fieldLabel.length) {
14279 cls: 'control-label box-input-label',
14280 //cls : 'input-group-addon',
14281 html : this.fieldLabel
14291 Roo.log(" no label && no align");
14306 html: this.boxLabel
14313 inputEl: function ()
14315 return this.el.select('input.roo-radio',true).first();
14317 onClick : function()
14319 this.setChecked(true);
14322 setChecked : function(state,suppressEvent)
14325 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14326 v.dom.checked = false;
14330 this.checked = state;
14331 this.inputEl().dom.checked = state;
14333 if(suppressEvent !== true){
14334 this.fireEvent('check', this, state);
14337 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14341 getGroupValue : function()
14344 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14345 if(v.dom.checked == true){
14346 value = v.dom.value;
14354 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14355 * @return {Mixed} value The field value
14357 getValue : function(){
14358 return this.getGroupValue();
14364 //<script type="text/javascript">
14367 * Based Ext JS Library 1.1.1
14368 * Copyright(c) 2006-2007, Ext JS, LLC.
14374 * @class Roo.HtmlEditorCore
14375 * @extends Roo.Component
14376 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14378 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14381 Roo.HtmlEditorCore = function(config){
14384 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14387 * @event initialize
14388 * Fires when the editor is fully initialized (including the iframe)
14389 * @param {Roo.HtmlEditorCore} this
14394 * Fires when the editor is first receives the focus. Any insertion must wait
14395 * until after this event.
14396 * @param {Roo.HtmlEditorCore} this
14400 * @event beforesync
14401 * Fires before the textarea is updated with content from the editor iframe. Return false
14402 * to cancel the sync.
14403 * @param {Roo.HtmlEditorCore} this
14404 * @param {String} html
14408 * @event beforepush
14409 * Fires before the iframe editor is updated with content from the textarea. Return false
14410 * to cancel the push.
14411 * @param {Roo.HtmlEditorCore} this
14412 * @param {String} html
14417 * Fires when the textarea is updated with content from the editor iframe.
14418 * @param {Roo.HtmlEditorCore} this
14419 * @param {String} html
14424 * Fires when the iframe editor is updated with content from the textarea.
14425 * @param {Roo.HtmlEditorCore} this
14426 * @param {String} html
14431 * @event editorevent
14432 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14433 * @param {Roo.HtmlEditorCore} this
14441 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14445 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14451 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14456 * @cfg {Number} height (in pixels)
14460 * @cfg {Number} width (in pixels)
14465 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14468 stylesheets: false,
14473 // private properties
14474 validationEvent : false,
14476 initialized : false,
14478 sourceEditMode : false,
14479 onFocus : Roo.emptyFn,
14481 hideMode:'offsets',
14489 * Protected method that will not generally be called directly. It
14490 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14491 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14493 getDocMarkup : function(){
14496 Roo.log(this.stylesheets);
14498 // inherit styels from page...??
14499 if (this.stylesheets === false) {
14501 Roo.get(document.head).select('style').each(function(node) {
14502 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14505 Roo.get(document.head).select('link').each(function(node) {
14506 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14509 } else if (!this.stylesheets.length) {
14511 st = '<style type="text/css">' +
14512 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14515 Roo.each(this.stylesheets, function(s) {
14516 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14521 st += '<style type="text/css">' +
14522 'IMG { cursor: pointer } ' +
14526 return '<html><head>' + st +
14527 //<style type="text/css">' +
14528 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14530 ' </head><body class="roo-htmleditor-body"></body></html>';
14534 onRender : function(ct, position)
14537 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14538 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14541 this.el.dom.style.border = '0 none';
14542 this.el.dom.setAttribute('tabIndex', -1);
14543 this.el.addClass('x-hidden hide');
14547 if(Roo.isIE){ // fix IE 1px bogus margin
14548 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14552 this.frameId = Roo.id();
14556 var iframe = this.owner.wrap.createChild({
14558 cls: 'form-control', // bootstrap..
14560 name: this.frameId,
14561 frameBorder : 'no',
14562 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14567 this.iframe = iframe.dom;
14569 this.assignDocWin();
14571 this.doc.designMode = 'on';
14574 this.doc.write(this.getDocMarkup());
14578 var task = { // must defer to wait for browser to be ready
14580 //console.log("run task?" + this.doc.readyState);
14581 this.assignDocWin();
14582 if(this.doc.body || this.doc.readyState == 'complete'){
14584 this.doc.designMode="on";
14588 Roo.TaskMgr.stop(task);
14589 this.initEditor.defer(10, this);
14596 Roo.TaskMgr.start(task);
14603 onResize : function(w, h)
14605 Roo.log('resize: ' +w + ',' + h );
14606 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14610 if(typeof w == 'number'){
14612 this.iframe.style.width = w + 'px';
14614 if(typeof h == 'number'){
14616 this.iframe.style.height = h + 'px';
14618 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14625 * Toggles the editor between standard and source edit mode.
14626 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14628 toggleSourceEdit : function(sourceEditMode){
14630 this.sourceEditMode = sourceEditMode === true;
14632 if(this.sourceEditMode){
14634 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14637 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14638 //this.iframe.className = '';
14641 //this.setSize(this.owner.wrap.getSize());
14642 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14649 * Protected method that will not generally be called directly. If you need/want
14650 * custom HTML cleanup, this is the method you should override.
14651 * @param {String} html The HTML to be cleaned
14652 * return {String} The cleaned HTML
14654 cleanHtml : function(html){
14655 html = String(html);
14656 if(html.length > 5){
14657 if(Roo.isSafari){ // strip safari nonsense
14658 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14661 if(html == ' '){
14668 * HTML Editor -> Textarea
14669 * Protected method that will not generally be called directly. Syncs the contents
14670 * of the editor iframe with the textarea.
14672 syncValue : function(){
14673 if(this.initialized){
14674 var bd = (this.doc.body || this.doc.documentElement);
14675 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14676 var html = bd.innerHTML;
14678 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14679 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14681 html = '<div style="'+m[0]+'">' + html + '</div>';
14684 html = this.cleanHtml(html);
14685 // fix up the special chars.. normaly like back quotes in word...
14686 // however we do not want to do this with chinese..
14687 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14688 var cc = b.charCodeAt();
14690 (cc >= 0x4E00 && cc < 0xA000 ) ||
14691 (cc >= 0x3400 && cc < 0x4E00 ) ||
14692 (cc >= 0xf900 && cc < 0xfb00 )
14698 if(this.owner.fireEvent('beforesync', this, html) !== false){
14699 this.el.dom.value = html;
14700 this.owner.fireEvent('sync', this, html);
14706 * Protected method that will not generally be called directly. Pushes the value of the textarea
14707 * into the iframe editor.
14709 pushValue : function(){
14710 if(this.initialized){
14711 var v = this.el.dom.value.trim();
14713 // if(v.length < 1){
14717 if(this.owner.fireEvent('beforepush', this, v) !== false){
14718 var d = (this.doc.body || this.doc.documentElement);
14720 this.cleanUpPaste();
14721 this.el.dom.value = d.innerHTML;
14722 this.owner.fireEvent('push', this, v);
14728 deferFocus : function(){
14729 this.focus.defer(10, this);
14733 focus : function(){
14734 if(this.win && !this.sourceEditMode){
14741 assignDocWin: function()
14743 var iframe = this.iframe;
14746 this.doc = iframe.contentWindow.document;
14747 this.win = iframe.contentWindow;
14749 if (!Roo.get(this.frameId)) {
14752 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14753 this.win = Roo.get(this.frameId).dom.contentWindow;
14758 initEditor : function(){
14759 //console.log("INIT EDITOR");
14760 this.assignDocWin();
14764 this.doc.designMode="on";
14766 this.doc.write(this.getDocMarkup());
14769 var dbody = (this.doc.body || this.doc.documentElement);
14770 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14771 // this copies styles from the containing element into thsi one..
14772 // not sure why we need all of this..
14773 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14774 ss['background-attachment'] = 'fixed'; // w3c
14775 dbody.bgProperties = 'fixed'; // ie
14776 Roo.DomHelper.applyStyles(dbody, ss);
14777 Roo.EventManager.on(this.doc, {
14778 //'mousedown': this.onEditorEvent,
14779 'mouseup': this.onEditorEvent,
14780 'dblclick': this.onEditorEvent,
14781 'click': this.onEditorEvent,
14782 'keyup': this.onEditorEvent,
14787 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14789 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14790 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14792 this.initialized = true;
14794 this.owner.fireEvent('initialize', this);
14799 onDestroy : function(){
14805 //for (var i =0; i < this.toolbars.length;i++) {
14806 // // fixme - ask toolbars for heights?
14807 // this.toolbars[i].onDestroy();
14810 //this.wrap.dom.innerHTML = '';
14811 //this.wrap.remove();
14816 onFirstFocus : function(){
14818 this.assignDocWin();
14821 this.activated = true;
14824 if(Roo.isGecko){ // prevent silly gecko errors
14826 var s = this.win.getSelection();
14827 if(!s.focusNode || s.focusNode.nodeType != 3){
14828 var r = s.getRangeAt(0);
14829 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14834 this.execCmd('useCSS', true);
14835 this.execCmd('styleWithCSS', false);
14838 this.owner.fireEvent('activate', this);
14842 adjustFont: function(btn){
14843 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14844 //if(Roo.isSafari){ // safari
14847 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14848 if(Roo.isSafari){ // safari
14849 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14850 v = (v < 10) ? 10 : v;
14851 v = (v > 48) ? 48 : v;
14852 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14857 v = Math.max(1, v+adjust);
14859 this.execCmd('FontSize', v );
14862 onEditorEvent : function(e){
14863 this.owner.fireEvent('editorevent', this, e);
14864 // this.updateToolbar();
14865 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14868 insertTag : function(tg)
14870 // could be a bit smarter... -> wrap the current selected tRoo..
14871 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14873 range = this.createRange(this.getSelection());
14874 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14875 wrappingNode.appendChild(range.extractContents());
14876 range.insertNode(wrappingNode);
14883 this.execCmd("formatblock", tg);
14887 insertText : function(txt)
14891 var range = this.createRange();
14892 range.deleteContents();
14893 //alert(Sender.getAttribute('label'));
14895 range.insertNode(this.doc.createTextNode(txt));
14901 * Executes a Midas editor command on the editor document and performs necessary focus and
14902 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14903 * @param {String} cmd The Midas command
14904 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14906 relayCmd : function(cmd, value){
14908 this.execCmd(cmd, value);
14909 this.owner.fireEvent('editorevent', this);
14910 //this.updateToolbar();
14911 this.owner.deferFocus();
14915 * Executes a Midas editor command directly on the editor document.
14916 * For visual commands, you should use {@link #relayCmd} instead.
14917 * <b>This should only be called after the editor is initialized.</b>
14918 * @param {String} cmd The Midas command
14919 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14921 execCmd : function(cmd, value){
14922 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14929 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14931 * @param {String} text | dom node..
14933 insertAtCursor : function(text)
14938 if(!this.activated){
14944 var r = this.doc.selection.createRange();
14955 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14959 // from jquery ui (MIT licenced)
14961 var win = this.win;
14963 if (win.getSelection && win.getSelection().getRangeAt) {
14964 range = win.getSelection().getRangeAt(0);
14965 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14966 range.insertNode(node);
14967 } else if (win.document.selection && win.document.selection.createRange) {
14968 // no firefox support
14969 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14970 win.document.selection.createRange().pasteHTML(txt);
14972 // no firefox support
14973 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14974 this.execCmd('InsertHTML', txt);
14983 mozKeyPress : function(e){
14985 var c = e.getCharCode(), cmd;
14988 c = String.fromCharCode(c).toLowerCase();
15002 this.cleanUpPaste.defer(100, this);
15010 e.preventDefault();
15018 fixKeys : function(){ // load time branching for fastest keydown performance
15020 return function(e){
15021 var k = e.getKey(), r;
15024 r = this.doc.selection.createRange();
15027 r.pasteHTML('    ');
15034 r = this.doc.selection.createRange();
15036 var target = r.parentElement();
15037 if(!target || target.tagName.toLowerCase() != 'li'){
15039 r.pasteHTML('<br />');
15045 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15046 this.cleanUpPaste.defer(100, this);
15052 }else if(Roo.isOpera){
15053 return function(e){
15054 var k = e.getKey();
15058 this.execCmd('InsertHTML','    ');
15061 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15062 this.cleanUpPaste.defer(100, this);
15067 }else if(Roo.isSafari){
15068 return function(e){
15069 var k = e.getKey();
15073 this.execCmd('InsertText','\t');
15077 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15078 this.cleanUpPaste.defer(100, this);
15086 getAllAncestors: function()
15088 var p = this.getSelectedNode();
15091 a.push(p); // push blank onto stack..
15092 p = this.getParentElement();
15096 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15100 a.push(this.doc.body);
15104 lastSelNode : false,
15107 getSelection : function()
15109 this.assignDocWin();
15110 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15113 getSelectedNode: function()
15115 // this may only work on Gecko!!!
15117 // should we cache this!!!!
15122 var range = this.createRange(this.getSelection()).cloneRange();
15125 var parent = range.parentElement();
15127 var testRange = range.duplicate();
15128 testRange.moveToElementText(parent);
15129 if (testRange.inRange(range)) {
15132 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15135 parent = parent.parentElement;
15140 // is ancestor a text element.
15141 var ac = range.commonAncestorContainer;
15142 if (ac.nodeType == 3) {
15143 ac = ac.parentNode;
15146 var ar = ac.childNodes;
15149 var other_nodes = [];
15150 var has_other_nodes = false;
15151 for (var i=0;i<ar.length;i++) {
15152 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15155 // fullly contained node.
15157 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15162 // probably selected..
15163 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15164 other_nodes.push(ar[i]);
15168 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15173 has_other_nodes = true;
15175 if (!nodes.length && other_nodes.length) {
15176 nodes= other_nodes;
15178 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15184 createRange: function(sel)
15186 // this has strange effects when using with
15187 // top toolbar - not sure if it's a great idea.
15188 //this.editor.contentWindow.focus();
15189 if (typeof sel != "undefined") {
15191 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15193 return this.doc.createRange();
15196 return this.doc.createRange();
15199 getParentElement: function()
15202 this.assignDocWin();
15203 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15205 var range = this.createRange(sel);
15208 var p = range.commonAncestorContainer;
15209 while (p.nodeType == 3) { // text node
15220 * Range intersection.. the hard stuff...
15224 * [ -- selected range --- ]
15228 * if end is before start or hits it. fail.
15229 * if start is after end or hits it fail.
15231 * if either hits (but other is outside. - then it's not
15237 // @see http://www.thismuchiknow.co.uk/?p=64.
15238 rangeIntersectsNode : function(range, node)
15240 var nodeRange = node.ownerDocument.createRange();
15242 nodeRange.selectNode(node);
15244 nodeRange.selectNodeContents(node);
15247 var rangeStartRange = range.cloneRange();
15248 rangeStartRange.collapse(true);
15250 var rangeEndRange = range.cloneRange();
15251 rangeEndRange.collapse(false);
15253 var nodeStartRange = nodeRange.cloneRange();
15254 nodeStartRange.collapse(true);
15256 var nodeEndRange = nodeRange.cloneRange();
15257 nodeEndRange.collapse(false);
15259 return rangeStartRange.compareBoundaryPoints(
15260 Range.START_TO_START, nodeEndRange) == -1 &&
15261 rangeEndRange.compareBoundaryPoints(
15262 Range.START_TO_START, nodeStartRange) == 1;
15266 rangeCompareNode : function(range, node)
15268 var nodeRange = node.ownerDocument.createRange();
15270 nodeRange.selectNode(node);
15272 nodeRange.selectNodeContents(node);
15276 range.collapse(true);
15278 nodeRange.collapse(true);
15280 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15281 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15283 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15285 var nodeIsBefore = ss == 1;
15286 var nodeIsAfter = ee == -1;
15288 if (nodeIsBefore && nodeIsAfter)
15290 if (!nodeIsBefore && nodeIsAfter)
15291 return 1; //right trailed.
15293 if (nodeIsBefore && !nodeIsAfter)
15294 return 2; // left trailed.
15299 // private? - in a new class?
15300 cleanUpPaste : function()
15302 // cleans up the whole document..
15303 Roo.log('cleanuppaste');
15305 this.cleanUpChildren(this.doc.body);
15306 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15307 if (clean != this.doc.body.innerHTML) {
15308 this.doc.body.innerHTML = clean;
15313 cleanWordChars : function(input) {// change the chars to hex code
15314 var he = Roo.HtmlEditorCore;
15316 var output = input;
15317 Roo.each(he.swapCodes, function(sw) {
15318 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15320 output = output.replace(swapper, sw[1]);
15327 cleanUpChildren : function (n)
15329 if (!n.childNodes.length) {
15332 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15333 this.cleanUpChild(n.childNodes[i]);
15340 cleanUpChild : function (node)
15343 //console.log(node);
15344 if (node.nodeName == "#text") {
15345 // clean up silly Windows -- stuff?
15348 if (node.nodeName == "#comment") {
15349 node.parentNode.removeChild(node);
15350 // clean up silly Windows -- stuff?
15354 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15356 node.parentNode.removeChild(node);
15361 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15363 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15364 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15366 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15367 // remove_keep_children = true;
15370 if (remove_keep_children) {
15371 this.cleanUpChildren(node);
15372 // inserts everything just before this node...
15373 while (node.childNodes.length) {
15374 var cn = node.childNodes[0];
15375 node.removeChild(cn);
15376 node.parentNode.insertBefore(cn, node);
15378 node.parentNode.removeChild(node);
15382 if (!node.attributes || !node.attributes.length) {
15383 this.cleanUpChildren(node);
15387 function cleanAttr(n,v)
15390 if (v.match(/^\./) || v.match(/^\//)) {
15393 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15396 if (v.match(/^#/)) {
15399 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15400 node.removeAttribute(n);
15404 function cleanStyle(n,v)
15406 if (v.match(/expression/)) { //XSS?? should we even bother..
15407 node.removeAttribute(n);
15410 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15411 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15414 var parts = v.split(/;/);
15417 Roo.each(parts, function(p) {
15418 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15422 var l = p.split(':').shift().replace(/\s+/g,'');
15423 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15425 if ( cblack.indexOf(l) > -1) {
15426 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15427 //node.removeAttribute(n);
15431 // only allow 'c whitelisted system attributes'
15432 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15433 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15434 //node.removeAttribute(n);
15444 if (clean.length) {
15445 node.setAttribute(n, clean.join(';'));
15447 node.removeAttribute(n);
15453 for (var i = node.attributes.length-1; i > -1 ; i--) {
15454 var a = node.attributes[i];
15457 if (a.name.toLowerCase().substr(0,2)=='on') {
15458 node.removeAttribute(a.name);
15461 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15462 node.removeAttribute(a.name);
15465 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15466 cleanAttr(a.name,a.value); // fixme..
15469 if (a.name == 'style') {
15470 cleanStyle(a.name,a.value);
15473 /// clean up MS crap..
15474 // tecnically this should be a list of valid class'es..
15477 if (a.name == 'class') {
15478 if (a.value.match(/^Mso/)) {
15479 node.className = '';
15482 if (a.value.match(/body/)) {
15483 node.className = '';
15494 this.cleanUpChildren(node);
15499 * Clean up MS wordisms...
15501 cleanWord : function(node)
15504 var cleanWordChildren = function()
15506 if (!node.childNodes.length) {
15509 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15510 _t.cleanWord(node.childNodes[i]);
15516 this.cleanWord(this.doc.body);
15519 if (node.nodeName == "#text") {
15520 // clean up silly Windows -- stuff?
15523 if (node.nodeName == "#comment") {
15524 node.parentNode.removeChild(node);
15525 // clean up silly Windows -- stuff?
15529 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15530 node.parentNode.removeChild(node);
15534 // remove - but keep children..
15535 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15536 while (node.childNodes.length) {
15537 var cn = node.childNodes[0];
15538 node.removeChild(cn);
15539 node.parentNode.insertBefore(cn, node);
15541 node.parentNode.removeChild(node);
15542 cleanWordChildren();
15546 if (node.className.length) {
15548 var cn = node.className.split(/\W+/);
15550 Roo.each(cn, function(cls) {
15551 if (cls.match(/Mso[a-zA-Z]+/)) {
15556 node.className = cna.length ? cna.join(' ') : '';
15558 node.removeAttribute("class");
15562 if (node.hasAttribute("lang")) {
15563 node.removeAttribute("lang");
15566 if (node.hasAttribute("style")) {
15568 var styles = node.getAttribute("style").split(";");
15570 Roo.each(styles, function(s) {
15571 if (!s.match(/:/)) {
15574 var kv = s.split(":");
15575 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15578 // what ever is left... we allow.
15581 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15582 if (!nstyle.length) {
15583 node.removeAttribute('style');
15587 cleanWordChildren();
15591 domToHTML : function(currentElement, depth, nopadtext) {
15593 depth = depth || 0;
15594 nopadtext = nopadtext || false;
15596 if (!currentElement) {
15597 return this.domToHTML(this.doc.body);
15600 //Roo.log(currentElement);
15602 var allText = false;
15603 var nodeName = currentElement.nodeName;
15604 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15606 if (nodeName == '#text') {
15607 return currentElement.nodeValue;
15612 if (nodeName != 'BODY') {
15615 // Prints the node tagName, such as <A>, <IMG>, etc
15618 for(i = 0; i < currentElement.attributes.length;i++) {
15620 var aname = currentElement.attributes.item(i).name;
15621 if (!currentElement.attributes.item(i).value.length) {
15624 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15627 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15636 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15639 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15644 // Traverse the tree
15646 var currentElementChild = currentElement.childNodes.item(i);
15647 var allText = true;
15648 var innerHTML = '';
15650 while (currentElementChild) {
15651 // Formatting code (indent the tree so it looks nice on the screen)
15652 var nopad = nopadtext;
15653 if (lastnode == 'SPAN') {
15657 if (currentElementChild.nodeName == '#text') {
15658 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15659 if (!nopad && toadd.length > 80) {
15660 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15662 innerHTML += toadd;
15665 currentElementChild = currentElement.childNodes.item(i);
15671 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15673 // Recursively traverse the tree structure of the child node
15674 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15675 lastnode = currentElementChild.nodeName;
15677 currentElementChild=currentElement.childNodes.item(i);
15683 // The remaining code is mostly for formatting the tree
15684 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15689 ret+= "</"+tagName+">";
15695 // hide stuff that is not compatible
15709 * @event specialkey
15713 * @cfg {String} fieldClass @hide
15716 * @cfg {String} focusClass @hide
15719 * @cfg {String} autoCreate @hide
15722 * @cfg {String} inputType @hide
15725 * @cfg {String} invalidClass @hide
15728 * @cfg {String} invalidText @hide
15731 * @cfg {String} msgFx @hide
15734 * @cfg {String} validateOnBlur @hide
15738 Roo.HtmlEditorCore.white = [
15739 'area', 'br', 'img', 'input', 'hr', 'wbr',
15741 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15742 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15743 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15744 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15745 'table', 'ul', 'xmp',
15747 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15750 'dir', 'menu', 'ol', 'ul', 'dl',
15756 Roo.HtmlEditorCore.black = [
15757 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15759 'base', 'basefont', 'bgsound', 'blink', 'body',
15760 'frame', 'frameset', 'head', 'html', 'ilayer',
15761 'iframe', 'layer', 'link', 'meta', 'object',
15762 'script', 'style' ,'title', 'xml' // clean later..
15764 Roo.HtmlEditorCore.clean = [
15765 'script', 'style', 'title', 'xml'
15767 Roo.HtmlEditorCore.remove = [
15772 Roo.HtmlEditorCore.ablack = [
15776 Roo.HtmlEditorCore.aclean = [
15777 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15781 Roo.HtmlEditorCore.pwhite= [
15782 'http', 'https', 'mailto'
15785 // white listed style attributes.
15786 Roo.HtmlEditorCore.cwhite= [
15787 // 'text-align', /// default is to allow most things..
15793 // black listed style attributes.
15794 Roo.HtmlEditorCore.cblack= [
15795 // 'font-size' -- this can be set by the project
15799 Roo.HtmlEditorCore.swapCodes =[
15818 * @class Roo.bootstrap.HtmlEditor
15819 * @extends Roo.bootstrap.TextArea
15820 * Bootstrap HtmlEditor class
15823 * Create a new HtmlEditor
15824 * @param {Object} config The config object
15827 Roo.bootstrap.HtmlEditor = function(config){
15828 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15829 if (!this.toolbars) {
15830 this.toolbars = [];
15832 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15835 * @event initialize
15836 * Fires when the editor is fully initialized (including the iframe)
15837 * @param {HtmlEditor} this
15842 * Fires when the editor is first receives the focus. Any insertion must wait
15843 * until after this event.
15844 * @param {HtmlEditor} this
15848 * @event beforesync
15849 * Fires before the textarea is updated with content from the editor iframe. Return false
15850 * to cancel the sync.
15851 * @param {HtmlEditor} this
15852 * @param {String} html
15856 * @event beforepush
15857 * Fires before the iframe editor is updated with content from the textarea. Return false
15858 * to cancel the push.
15859 * @param {HtmlEditor} this
15860 * @param {String} html
15865 * Fires when the textarea is updated with content from the editor iframe.
15866 * @param {HtmlEditor} this
15867 * @param {String} html
15872 * Fires when the iframe editor is updated with content from the textarea.
15873 * @param {HtmlEditor} this
15874 * @param {String} html
15878 * @event editmodechange
15879 * Fires when the editor switches edit modes
15880 * @param {HtmlEditor} this
15881 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15883 editmodechange: true,
15885 * @event editorevent
15886 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15887 * @param {HtmlEditor} this
15891 * @event firstfocus
15892 * Fires when on first focus - needed by toolbars..
15893 * @param {HtmlEditor} this
15898 * Auto save the htmlEditor value as a file into Events
15899 * @param {HtmlEditor} this
15903 * @event savedpreview
15904 * preview the saved version of htmlEditor
15905 * @param {HtmlEditor} this
15912 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15916 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15921 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15926 * @cfg {Number} height (in pixels)
15930 * @cfg {Number} width (in pixels)
15935 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15938 stylesheets: false,
15943 // private properties
15944 validationEvent : false,
15946 initialized : false,
15949 onFocus : Roo.emptyFn,
15951 hideMode:'offsets',
15954 tbContainer : false,
15956 toolbarContainer :function() {
15957 return this.wrap.select('.x-html-editor-tb',true).first();
15961 * Protected method that will not generally be called directly. It
15962 * is called when the editor creates its toolbar. Override this method if you need to
15963 * add custom toolbar buttons.
15964 * @param {HtmlEditor} editor
15966 createToolbar : function(){
15968 Roo.log("create toolbars");
15970 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15971 this.toolbars[0].render(this.toolbarContainer());
15975 // if (!editor.toolbars || !editor.toolbars.length) {
15976 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15979 // for (var i =0 ; i < editor.toolbars.length;i++) {
15980 // editor.toolbars[i] = Roo.factory(
15981 // typeof(editor.toolbars[i]) == 'string' ?
15982 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15983 // Roo.bootstrap.HtmlEditor);
15984 // editor.toolbars[i].init(editor);
15990 onRender : function(ct, position)
15992 // Roo.log("Call onRender: " + this.xtype);
15994 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15996 this.wrap = this.inputEl().wrap({
15997 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16000 this.editorcore.onRender(ct, position);
16002 if (this.resizable) {
16003 this.resizeEl = new Roo.Resizable(this.wrap, {
16007 minHeight : this.height,
16008 height: this.height,
16009 handles : this.resizable,
16012 resize : function(r, w, h) {
16013 _t.onResize(w,h); // -something
16019 this.createToolbar(this);
16022 if(!this.width && this.resizable){
16023 this.setSize(this.wrap.getSize());
16025 if (this.resizeEl) {
16026 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16027 // should trigger onReize..
16033 onResize : function(w, h)
16035 Roo.log('resize: ' +w + ',' + h );
16036 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16040 if(this.inputEl() ){
16041 if(typeof w == 'number'){
16042 var aw = w - this.wrap.getFrameWidth('lr');
16043 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16046 if(typeof h == 'number'){
16047 var tbh = -11; // fixme it needs to tool bar size!
16048 for (var i =0; i < this.toolbars.length;i++) {
16049 // fixme - ask toolbars for heights?
16050 tbh += this.toolbars[i].el.getHeight();
16051 //if (this.toolbars[i].footer) {
16052 // tbh += this.toolbars[i].footer.el.getHeight();
16060 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16061 ah -= 5; // knock a few pixes off for look..
16062 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16066 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16067 this.editorcore.onResize(ew,eh);
16072 * Toggles the editor between standard and source edit mode.
16073 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16075 toggleSourceEdit : function(sourceEditMode)
16077 this.editorcore.toggleSourceEdit(sourceEditMode);
16079 if(this.editorcore.sourceEditMode){
16080 Roo.log('editor - showing textarea');
16083 // Roo.log(this.syncValue());
16085 this.inputEl().removeClass('hide');
16086 this.inputEl().dom.removeAttribute('tabIndex');
16087 this.inputEl().focus();
16089 Roo.log('editor - hiding textarea');
16091 // Roo.log(this.pushValue());
16094 this.inputEl().addClass('hide');
16095 this.inputEl().dom.setAttribute('tabIndex', -1);
16096 //this.deferFocus();
16099 if(this.resizable){
16100 this.setSize(this.wrap.getSize());
16103 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16106 // private (for BoxComponent)
16107 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16109 // private (for BoxComponent)
16110 getResizeEl : function(){
16114 // private (for BoxComponent)
16115 getPositionEl : function(){
16120 initEvents : function(){
16121 this.originalValue = this.getValue();
16125 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16128 // markInvalid : Roo.emptyFn,
16130 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16133 // clearInvalid : Roo.emptyFn,
16135 setValue : function(v){
16136 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16137 this.editorcore.pushValue();
16142 deferFocus : function(){
16143 this.focus.defer(10, this);
16147 focus : function(){
16148 this.editorcore.focus();
16154 onDestroy : function(){
16160 for (var i =0; i < this.toolbars.length;i++) {
16161 // fixme - ask toolbars for heights?
16162 this.toolbars[i].onDestroy();
16165 this.wrap.dom.innerHTML = '';
16166 this.wrap.remove();
16171 onFirstFocus : function(){
16172 //Roo.log("onFirstFocus");
16173 this.editorcore.onFirstFocus();
16174 for (var i =0; i < this.toolbars.length;i++) {
16175 this.toolbars[i].onFirstFocus();
16181 syncValue : function()
16183 this.editorcore.syncValue();
16186 pushValue : function()
16188 this.editorcore.pushValue();
16192 // hide stuff that is not compatible
16206 * @event specialkey
16210 * @cfg {String} fieldClass @hide
16213 * @cfg {String} focusClass @hide
16216 * @cfg {String} autoCreate @hide
16219 * @cfg {String} inputType @hide
16222 * @cfg {String} invalidClass @hide
16225 * @cfg {String} invalidText @hide
16228 * @cfg {String} msgFx @hide
16231 * @cfg {String} validateOnBlur @hide
16242 * @class Roo.bootstrap.HtmlEditorToolbar1
16247 new Roo.bootstrap.HtmlEditor({
16250 new Roo.bootstrap.HtmlEditorToolbar1({
16251 disable : { fonts: 1 , format: 1, ..., ... , ...],
16257 * @cfg {Object} disable List of elements to disable..
16258 * @cfg {Array} btns List of additional buttons.
16262 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16265 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
16268 Roo.apply(this, config);
16270 // default disabled, based on 'good practice'..
16271 this.disable = this.disable || {};
16272 Roo.applyIf(this.disable, {
16275 specialElements : true
16277 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
16279 this.editor = config.editor;
16280 this.editorcore = config.editor.editorcore;
16282 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16284 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16285 // dont call parent... till later.
16287 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16293 editorcore : false,
16298 "h1","h2","h3","h4","h5","h6",
16300 "abbr", "acronym", "address", "cite", "samp", "var",
16304 onRender : function(ct, position)
16306 // Roo.log("Call onRender: " + this.xtype);
16308 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16310 this.el.dom.style.marginBottom = '0';
16312 var editorcore = this.editorcore;
16313 var editor= this.editor;
16316 var btn = function(id,cmd , toggle, handler){
16318 var event = toggle ? 'toggle' : 'click';
16323 xns: Roo.bootstrap,
16326 enableToggle:toggle !== false,
16328 pressed : toggle ? false : null,
16331 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16332 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16341 xns: Roo.bootstrap,
16342 glyphicon : 'font',
16346 xns: Roo.bootstrap,
16350 Roo.each(this.formats, function(f) {
16351 style.menu.items.push({
16353 xns: Roo.bootstrap,
16354 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16359 editorcore.insertTag(this.tagname);
16366 children.push(style);
16369 btn('bold',false,true);
16370 btn('italic',false,true);
16371 btn('align-left', 'justifyleft',true);
16372 btn('align-center', 'justifycenter',true);
16373 btn('align-right' , 'justifyright',true);
16374 btn('link', false, false, function(btn) {
16375 //Roo.log("create link?");
16376 var url = prompt(this.createLinkText, this.defaultLinkValue);
16377 if(url && url != 'http:/'+'/'){
16378 this.editorcore.relayCmd('createlink', url);
16381 btn('list','insertunorderedlist',true);
16382 btn('pencil', false,true, function(btn){
16385 this.toggleSourceEdit(btn.pressed);
16391 xns: Roo.bootstrap,
16396 xns: Roo.bootstrap,
16401 cog.menu.items.push({
16403 xns: Roo.bootstrap,
16404 html : Clean styles,
16409 editorcore.insertTag(this.tagname);
16418 this.xtype = 'NavSimplebar';
16420 for(var i=0;i< children.length;i++) {
16422 this.buttons.add(this.addxtypeChild(children[i]));
16426 editor.on('editorevent', this.updateToolbar, this);
16428 onBtnClick : function(id)
16430 this.editorcore.relayCmd(id);
16431 this.editorcore.focus();
16435 * Protected method that will not generally be called directly. It triggers
16436 * a toolbar update by reading the markup state of the current selection in the editor.
16438 updateToolbar: function(){
16440 if(!this.editorcore.activated){
16441 this.editor.onFirstFocus(); // is this neeed?
16445 var btns = this.buttons;
16446 var doc = this.editorcore.doc;
16447 btns.get('bold').setActive(doc.queryCommandState('bold'));
16448 btns.get('italic').setActive(doc.queryCommandState('italic'));
16449 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16451 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16452 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16453 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16455 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16456 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16459 var ans = this.editorcore.getAllAncestors();
16460 if (this.formatCombo) {
16463 var store = this.formatCombo.store;
16464 this.formatCombo.setValue("");
16465 for (var i =0; i < ans.length;i++) {
16466 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16468 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16476 // hides menus... - so this cant be on a menu...
16477 Roo.bootstrap.MenuMgr.hideAll();
16479 Roo.bootstrap.MenuMgr.hideAll();
16480 //this.editorsyncValue();
16482 onFirstFocus: function() {
16483 this.buttons.each(function(item){
16487 toggleSourceEdit : function(sourceEditMode){
16490 if(sourceEditMode){
16491 Roo.log("disabling buttons");
16492 this.buttons.each( function(item){
16493 if(item.cmd != 'pencil'){
16499 Roo.log("enabling buttons");
16500 if(this.editorcore.initialized){
16501 this.buttons.each( function(item){
16507 Roo.log("calling toggole on editor");
16508 // tell the editor that it's been pressed..
16509 this.editor.toggleSourceEdit(sourceEditMode);
16519 * @class Roo.bootstrap.Table.AbstractSelectionModel
16520 * @extends Roo.util.Observable
16521 * Abstract base class for grid SelectionModels. It provides the interface that should be
16522 * implemented by descendant classes. This class should not be directly instantiated.
16525 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16526 this.locked = false;
16527 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16531 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16532 /** @ignore Called by the grid automatically. Do not call directly. */
16533 init : function(grid){
16539 * Locks the selections.
16542 this.locked = true;
16546 * Unlocks the selections.
16548 unlock : function(){
16549 this.locked = false;
16553 * Returns true if the selections are locked.
16554 * @return {Boolean}
16556 isLocked : function(){
16557 return this.locked;
16561 * @class Roo.bootstrap.Table.ColumnModel
16562 * @extends Roo.util.Observable
16563 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16564 * the columns in the table.
16567 * @param {Object} config An Array of column config objects. See this class's
16568 * config objects for details.
16570 Roo.bootstrap.Table.ColumnModel = function(config){
16572 * The config passed into the constructor
16574 this.config = config;
16577 // if no id, create one
16578 // if the column does not have a dataIndex mapping,
16579 // map it to the order it is in the config
16580 for(var i = 0, len = config.length; i < len; i++){
16582 if(typeof c.dataIndex == "undefined"){
16585 if(typeof c.renderer == "string"){
16586 c.renderer = Roo.util.Format[c.renderer];
16588 if(typeof c.id == "undefined"){
16591 // if(c.editor && c.editor.xtype){
16592 // c.editor = Roo.factory(c.editor, Roo.grid);
16594 // if(c.editor && c.editor.isFormField){
16595 // c.editor = new Roo.grid.GridEditor(c.editor);
16598 this.lookup[c.id] = c;
16602 * The width of columns which have no width specified (defaults to 100)
16605 this.defaultWidth = 100;
16608 * Default sortable of columns which have no sortable specified (defaults to false)
16611 this.defaultSortable = false;
16615 * @event widthchange
16616 * Fires when the width of a column changes.
16617 * @param {ColumnModel} this
16618 * @param {Number} columnIndex The column index
16619 * @param {Number} newWidth The new width
16621 "widthchange": true,
16623 * @event headerchange
16624 * Fires when the text of a header changes.
16625 * @param {ColumnModel} this
16626 * @param {Number} columnIndex The column index
16627 * @param {Number} newText The new header text
16629 "headerchange": true,
16631 * @event hiddenchange
16632 * Fires when a column is hidden or "unhidden".
16633 * @param {ColumnModel} this
16634 * @param {Number} columnIndex The column index
16635 * @param {Boolean} hidden true if hidden, false otherwise
16637 "hiddenchange": true,
16639 * @event columnmoved
16640 * Fires when a column is moved.
16641 * @param {ColumnModel} this
16642 * @param {Number} oldIndex
16643 * @param {Number} newIndex
16645 "columnmoved" : true,
16647 * @event columlockchange
16648 * Fires when a column's locked state is changed
16649 * @param {ColumnModel} this
16650 * @param {Number} colIndex
16651 * @param {Boolean} locked true if locked
16653 "columnlockchange" : true
16655 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16657 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16659 * @cfg {String} header The header text to display in the Grid view.
16662 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16663 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16664 * specified, the column's index is used as an index into the Record's data Array.
16667 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16668 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16671 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16672 * Defaults to the value of the {@link #defaultSortable} property.
16673 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16676 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16679 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16682 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16685 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16688 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16689 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16690 * default renderer uses the raw data value.
16693 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16697 * Returns the id of the column at the specified index.
16698 * @param {Number} index The column index
16699 * @return {String} the id
16701 getColumnId : function(index){
16702 return this.config[index].id;
16706 * Returns the column for a specified id.
16707 * @param {String} id The column id
16708 * @return {Object} the column
16710 getColumnById : function(id){
16711 return this.lookup[id];
16716 * Returns the column for a specified dataIndex.
16717 * @param {String} dataIndex The column dataIndex
16718 * @return {Object|Boolean} the column or false if not found
16720 getColumnByDataIndex: function(dataIndex){
16721 var index = this.findColumnIndex(dataIndex);
16722 return index > -1 ? this.config[index] : false;
16726 * Returns the index for a specified column id.
16727 * @param {String} id The column id
16728 * @return {Number} the index, or -1 if not found
16730 getIndexById : function(id){
16731 for(var i = 0, len = this.config.length; i < len; i++){
16732 if(this.config[i].id == id){
16740 * Returns the index for a specified column dataIndex.
16741 * @param {String} dataIndex The column dataIndex
16742 * @return {Number} the index, or -1 if not found
16745 findColumnIndex : function(dataIndex){
16746 for(var i = 0, len = this.config.length; i < len; i++){
16747 if(this.config[i].dataIndex == dataIndex){
16755 moveColumn : function(oldIndex, newIndex){
16756 var c = this.config[oldIndex];
16757 this.config.splice(oldIndex, 1);
16758 this.config.splice(newIndex, 0, c);
16759 this.dataMap = null;
16760 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16763 isLocked : function(colIndex){
16764 return this.config[colIndex].locked === true;
16767 setLocked : function(colIndex, value, suppressEvent){
16768 if(this.isLocked(colIndex) == value){
16771 this.config[colIndex].locked = value;
16772 if(!suppressEvent){
16773 this.fireEvent("columnlockchange", this, colIndex, value);
16777 getTotalLockedWidth : function(){
16778 var totalWidth = 0;
16779 for(var i = 0; i < this.config.length; i++){
16780 if(this.isLocked(i) && !this.isHidden(i)){
16781 this.totalWidth += this.getColumnWidth(i);
16787 getLockedCount : function(){
16788 for(var i = 0, len = this.config.length; i < len; i++){
16789 if(!this.isLocked(i)){
16796 * Returns the number of columns.
16799 getColumnCount : function(visibleOnly){
16800 if(visibleOnly === true){
16802 for(var i = 0, len = this.config.length; i < len; i++){
16803 if(!this.isHidden(i)){
16809 return this.config.length;
16813 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16814 * @param {Function} fn
16815 * @param {Object} scope (optional)
16816 * @return {Array} result
16818 getColumnsBy : function(fn, scope){
16820 for(var i = 0, len = this.config.length; i < len; i++){
16821 var c = this.config[i];
16822 if(fn.call(scope||this, c, i) === true){
16830 * Returns true if the specified column is sortable.
16831 * @param {Number} col The column index
16832 * @return {Boolean}
16834 isSortable : function(col){
16835 if(typeof this.config[col].sortable == "undefined"){
16836 return this.defaultSortable;
16838 return this.config[col].sortable;
16842 * Returns the rendering (formatting) function defined for the column.
16843 * @param {Number} col The column index.
16844 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16846 getRenderer : function(col){
16847 if(!this.config[col].renderer){
16848 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16850 return this.config[col].renderer;
16854 * Sets the rendering (formatting) function for a column.
16855 * @param {Number} col The column index
16856 * @param {Function} fn The function to use to process the cell's raw data
16857 * to return HTML markup for the grid view. The render function is called with
16858 * the following parameters:<ul>
16859 * <li>Data value.</li>
16860 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16861 * <li>css A CSS style string to apply to the table cell.</li>
16862 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16863 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16864 * <li>Row index</li>
16865 * <li>Column index</li>
16866 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16868 setRenderer : function(col, fn){
16869 this.config[col].renderer = fn;
16873 * Returns the width for the specified column.
16874 * @param {Number} col The column index
16877 getColumnWidth : function(col){
16878 return this.config[col].width * 1 || this.defaultWidth;
16882 * Sets the width for a column.
16883 * @param {Number} col The column index
16884 * @param {Number} width The new width
16886 setColumnWidth : function(col, width, suppressEvent){
16887 this.config[col].width = width;
16888 this.totalWidth = null;
16889 if(!suppressEvent){
16890 this.fireEvent("widthchange", this, col, width);
16895 * Returns the total width of all columns.
16896 * @param {Boolean} includeHidden True to include hidden column widths
16899 getTotalWidth : function(includeHidden){
16900 if(!this.totalWidth){
16901 this.totalWidth = 0;
16902 for(var i = 0, len = this.config.length; i < len; i++){
16903 if(includeHidden || !this.isHidden(i)){
16904 this.totalWidth += this.getColumnWidth(i);
16908 return this.totalWidth;
16912 * Returns the header for the specified column.
16913 * @param {Number} col The column index
16916 getColumnHeader : function(col){
16917 return this.config[col].header;
16921 * Sets the header for a column.
16922 * @param {Number} col The column index
16923 * @param {String} header The new header
16925 setColumnHeader : function(col, header){
16926 this.config[col].header = header;
16927 this.fireEvent("headerchange", this, col, header);
16931 * Returns the tooltip for the specified column.
16932 * @param {Number} col The column index
16935 getColumnTooltip : function(col){
16936 return this.config[col].tooltip;
16939 * Sets the tooltip for a column.
16940 * @param {Number} col The column index
16941 * @param {String} tooltip The new tooltip
16943 setColumnTooltip : function(col, tooltip){
16944 this.config[col].tooltip = tooltip;
16948 * Returns the dataIndex for the specified column.
16949 * @param {Number} col The column index
16952 getDataIndex : function(col){
16953 return this.config[col].dataIndex;
16957 * Sets the dataIndex for a column.
16958 * @param {Number} col The column index
16959 * @param {Number} dataIndex The new dataIndex
16961 setDataIndex : function(col, dataIndex){
16962 this.config[col].dataIndex = dataIndex;
16968 * Returns true if the cell is editable.
16969 * @param {Number} colIndex The column index
16970 * @param {Number} rowIndex The row index
16971 * @return {Boolean}
16973 isCellEditable : function(colIndex, rowIndex){
16974 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16978 * Returns the editor defined for the cell/column.
16979 * return false or null to disable editing.
16980 * @param {Number} colIndex The column index
16981 * @param {Number} rowIndex The row index
16984 getCellEditor : function(colIndex, rowIndex){
16985 return this.config[colIndex].editor;
16989 * Sets if a column is editable.
16990 * @param {Number} col The column index
16991 * @param {Boolean} editable True if the column is editable
16993 setEditable : function(col, editable){
16994 this.config[col].editable = editable;
16999 * Returns true if the column is hidden.
17000 * @param {Number} colIndex The column index
17001 * @return {Boolean}
17003 isHidden : function(colIndex){
17004 return this.config[colIndex].hidden;
17009 * Returns true if the column width cannot be changed
17011 isFixed : function(colIndex){
17012 return this.config[colIndex].fixed;
17016 * Returns true if the column can be resized
17017 * @return {Boolean}
17019 isResizable : function(colIndex){
17020 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
17023 * Sets if a column is hidden.
17024 * @param {Number} colIndex The column index
17025 * @param {Boolean} hidden True if the column is hidden
17027 setHidden : function(colIndex, hidden){
17028 this.config[colIndex].hidden = hidden;
17029 this.totalWidth = null;
17030 this.fireEvent("hiddenchange", this, colIndex, hidden);
17034 * Sets the editor for a column.
17035 * @param {Number} col The column index
17036 * @param {Object} editor The editor object
17038 setEditor : function(col, editor){
17039 this.config[col].editor = editor;
17043 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
17044 if(typeof value == "string" && value.length < 1){
17050 // Alias for backwards compatibility
17051 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
17054 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17055 * @class Roo.bootstrap.Table.RowSelectionModel
17056 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17057 * It supports multiple selections and keyboard selection/navigation.
17059 * @param {Object} config
17062 Roo.bootstrap.Table.RowSelectionModel = function(config){
17063 Roo.apply(this, config);
17064 this.selections = new Roo.util.MixedCollection(false, function(o){
17069 this.lastActive = false;
17073 * @event selectionchange
17074 * Fires when the selection changes
17075 * @param {SelectionModel} this
17077 "selectionchange" : true,
17079 * @event afterselectionchange
17080 * Fires after the selection changes (eg. by key press or clicking)
17081 * @param {SelectionModel} this
17083 "afterselectionchange" : true,
17085 * @event beforerowselect
17086 * Fires when a row is selected being selected, return false to cancel.
17087 * @param {SelectionModel} this
17088 * @param {Number} rowIndex The selected index
17089 * @param {Boolean} keepExisting False if other selections will be cleared
17091 "beforerowselect" : true,
17094 * Fires when a row is selected.
17095 * @param {SelectionModel} this
17096 * @param {Number} rowIndex The selected index
17097 * @param {Roo.data.Record} r The record
17099 "rowselect" : true,
17101 * @event rowdeselect
17102 * Fires when a row is deselected.
17103 * @param {SelectionModel} this
17104 * @param {Number} rowIndex The selected index
17106 "rowdeselect" : true
17108 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17109 this.locked = false;
17112 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17114 * @cfg {Boolean} singleSelect
17115 * True to allow selection of only one row at a time (defaults to false)
17117 singleSelect : false,
17120 initEvents : function(){
17122 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17123 this.grid.on("mousedown", this.handleMouseDown, this);
17124 }else{ // allow click to work like normal
17125 this.grid.on("rowclick", this.handleDragableRowClick, this);
17128 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17129 "up" : function(e){
17131 this.selectPrevious(e.shiftKey);
17132 }else if(this.last !== false && this.lastActive !== false){
17133 var last = this.last;
17134 this.selectRange(this.last, this.lastActive-1);
17135 this.grid.getView().focusRow(this.lastActive);
17136 if(last !== false){
17140 this.selectFirstRow();
17142 this.fireEvent("afterselectionchange", this);
17144 "down" : function(e){
17146 this.selectNext(e.shiftKey);
17147 }else if(this.last !== false && this.lastActive !== false){
17148 var last = this.last;
17149 this.selectRange(this.last, this.lastActive+1);
17150 this.grid.getView().focusRow(this.lastActive);
17151 if(last !== false){
17155 this.selectFirstRow();
17157 this.fireEvent("afterselectionchange", this);
17162 var view = this.grid.view;
17163 view.on("refresh", this.onRefresh, this);
17164 view.on("rowupdated", this.onRowUpdated, this);
17165 view.on("rowremoved", this.onRemove, this);
17169 onRefresh : function(){
17170 var ds = this.grid.dataSource, i, v = this.grid.view;
17171 var s = this.selections;
17172 s.each(function(r){
17173 if((i = ds.indexOfId(r.id)) != -1){
17182 onRemove : function(v, index, r){
17183 this.selections.remove(r);
17187 onRowUpdated : function(v, index, r){
17188 if(this.isSelected(r)){
17189 v.onRowSelect(index);
17195 * @param {Array} records The records to select
17196 * @param {Boolean} keepExisting (optional) True to keep existing selections
17198 selectRecords : function(records, keepExisting){
17200 this.clearSelections();
17202 var ds = this.grid.dataSource;
17203 for(var i = 0, len = records.length; i < len; i++){
17204 this.selectRow(ds.indexOf(records[i]), true);
17209 * Gets the number of selected rows.
17212 getCount : function(){
17213 return this.selections.length;
17217 * Selects the first row in the grid.
17219 selectFirstRow : function(){
17224 * Select the last row.
17225 * @param {Boolean} keepExisting (optional) True to keep existing selections
17227 selectLastRow : function(keepExisting){
17228 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17232 * Selects the row immediately following the last selected row.
17233 * @param {Boolean} keepExisting (optional) True to keep existing selections
17235 selectNext : function(keepExisting){
17236 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17237 this.selectRow(this.last+1, keepExisting);
17238 this.grid.getView().focusRow(this.last);
17243 * Selects the row that precedes the last selected row.
17244 * @param {Boolean} keepExisting (optional) True to keep existing selections
17246 selectPrevious : function(keepExisting){
17248 this.selectRow(this.last-1, keepExisting);
17249 this.grid.getView().focusRow(this.last);
17254 * Returns the selected records
17255 * @return {Array} Array of selected records
17257 getSelections : function(){
17258 return [].concat(this.selections.items);
17262 * Returns the first selected record.
17265 getSelected : function(){
17266 return this.selections.itemAt(0);
17271 * Clears all selections.
17273 clearSelections : function(fast){
17274 if(this.locked) return;
17276 var ds = this.grid.dataSource;
17277 var s = this.selections;
17278 s.each(function(r){
17279 this.deselectRow(ds.indexOfId(r.id));
17283 this.selections.clear();
17290 * Selects all rows.
17292 selectAll : function(){
17293 if(this.locked) return;
17294 this.selections.clear();
17295 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17296 this.selectRow(i, true);
17301 * Returns True if there is a selection.
17302 * @return {Boolean}
17304 hasSelection : function(){
17305 return this.selections.length > 0;
17309 * Returns True if the specified row is selected.
17310 * @param {Number/Record} record The record or index of the record to check
17311 * @return {Boolean}
17313 isSelected : function(index){
17314 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17315 return (r && this.selections.key(r.id) ? true : false);
17319 * Returns True if the specified record id is selected.
17320 * @param {String} id The id of record to check
17321 * @return {Boolean}
17323 isIdSelected : function(id){
17324 return (this.selections.key(id) ? true : false);
17328 handleMouseDown : function(e, t){
17329 var view = this.grid.getView(), rowIndex;
17330 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17333 if(e.shiftKey && this.last !== false){
17334 var last = this.last;
17335 this.selectRange(last, rowIndex, e.ctrlKey);
17336 this.last = last; // reset the last
17337 view.focusRow(rowIndex);
17339 var isSelected = this.isSelected(rowIndex);
17340 if(e.button !== 0 && isSelected){
17341 view.focusRow(rowIndex);
17342 }else if(e.ctrlKey && isSelected){
17343 this.deselectRow(rowIndex);
17344 }else if(!isSelected){
17345 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17346 view.focusRow(rowIndex);
17349 this.fireEvent("afterselectionchange", this);
17352 handleDragableRowClick : function(grid, rowIndex, e)
17354 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17355 this.selectRow(rowIndex, false);
17356 grid.view.focusRow(rowIndex);
17357 this.fireEvent("afterselectionchange", this);
17362 * Selects multiple rows.
17363 * @param {Array} rows Array of the indexes of the row to select
17364 * @param {Boolean} keepExisting (optional) True to keep existing selections
17366 selectRows : function(rows, keepExisting){
17368 this.clearSelections();
17370 for(var i = 0, len = rows.length; i < len; i++){
17371 this.selectRow(rows[i], true);
17376 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17377 * @param {Number} startRow The index of the first row in the range
17378 * @param {Number} endRow The index of the last row in the range
17379 * @param {Boolean} keepExisting (optional) True to retain existing selections
17381 selectRange : function(startRow, endRow, keepExisting){
17382 if(this.locked) return;
17384 this.clearSelections();
17386 if(startRow <= endRow){
17387 for(var i = startRow; i <= endRow; i++){
17388 this.selectRow(i, true);
17391 for(var i = startRow; i >= endRow; i--){
17392 this.selectRow(i, true);
17398 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17399 * @param {Number} startRow The index of the first row in the range
17400 * @param {Number} endRow The index of the last row in the range
17402 deselectRange : function(startRow, endRow, preventViewNotify){
17403 if(this.locked) return;
17404 for(var i = startRow; i <= endRow; i++){
17405 this.deselectRow(i, preventViewNotify);
17411 * @param {Number} row The index of the row to select
17412 * @param {Boolean} keepExisting (optional) True to keep existing selections
17414 selectRow : function(index, keepExisting, preventViewNotify){
17415 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17416 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17417 if(!keepExisting || this.singleSelect){
17418 this.clearSelections();
17420 var r = this.grid.dataSource.getAt(index);
17421 this.selections.add(r);
17422 this.last = this.lastActive = index;
17423 if(!preventViewNotify){
17424 this.grid.getView().onRowSelect(index);
17426 this.fireEvent("rowselect", this, index, r);
17427 this.fireEvent("selectionchange", this);
17433 * @param {Number} row The index of the row to deselect
17435 deselectRow : function(index, preventViewNotify){
17436 if(this.locked) return;
17437 if(this.last == index){
17440 if(this.lastActive == index){
17441 this.lastActive = false;
17443 var r = this.grid.dataSource.getAt(index);
17444 this.selections.remove(r);
17445 if(!preventViewNotify){
17446 this.grid.getView().onRowDeselect(index);
17448 this.fireEvent("rowdeselect", this, index);
17449 this.fireEvent("selectionchange", this);
17453 restoreLast : function(){
17455 this.last = this._last;
17460 acceptsNav : function(row, col, cm){
17461 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17465 onEditorKey : function(field, e){
17466 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17471 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17473 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17475 }else if(k == e.ENTER && !e.ctrlKey){
17479 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17481 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17483 }else if(k == e.ESC){
17487 g.startEditing(newCell[0], newCell[1]);
17498 * @class Roo.bootstrap.MessageBar
17499 * @extends Roo.bootstrap.Component
17500 * Bootstrap MessageBar class
17501 * @cfg {String} html contents of the MessageBar
17502 * @cfg {String} weight (info | success | warning | danger) default info
17503 * @cfg {String} beforeClass insert the bar before the given class
17504 * @cfg {Boolean} closable (true | false) default false
17505 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17508 * Create a new Element
17509 * @param {Object} config The config object
17512 Roo.bootstrap.MessageBar = function(config){
17513 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17516 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17522 beforeClass: 'bootstrap-sticky-wrap',
17524 getAutoCreate : function(){
17528 cls: 'alert alert-dismissable alert-' + this.weight,
17533 html: this.html || ''
17539 cfg.cls += ' alert-messages-fixed';
17553 onRender : function(ct, position)
17555 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17558 var cfg = Roo.apply({}, this.getAutoCreate());
17562 cfg.cls += ' ' + this.cls;
17565 cfg.style = this.style;
17567 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17569 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17572 this.el.select('>button.close').on('click', this.hide, this);
17578 if (!this.rendered) {
17584 this.fireEvent('show', this);
17590 if (!this.rendered) {
17596 this.fireEvent('hide', this);
17599 update : function()
17601 // var e = this.el.dom.firstChild;
17603 // if(this.closable){
17604 // e = e.nextSibling;
17607 // e.data = this.html || '';
17609 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';