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
4045 * Create a new Table
4046 * @param {Object} config The config object
4049 Roo.bootstrap.Table = function(config){
4050 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4053 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4054 this.sm = this.selModel;
4055 this.sm.xmodule = this.xmodule || false;
4057 if (this.cm && typeof(this.cm.config) == 'undefined') {
4058 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
4059 this.cm = this.colModel;
4060 this.cm.xmodule = this.xmodule || false;
4063 this.store= Roo.factory(this.store, Roo.data);
4064 this.ds = this.store;
4065 this.ds.xmodule = this.xmodule || false;
4070 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4092 getAutoCreate : function(){
4093 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4102 cfg.cls += ' table-striped';
4105 cfg.cls += ' table-hover';
4107 if (this.bordered) {
4108 cfg.cls += ' table-bordered';
4110 if (this.condensed) {
4111 cfg.cls += ' table-condensed';
4113 if (this.responsive) {
4114 cfg.cls += ' table-responsive';
4121 cfg.cls+= ' ' +this.cls;
4124 // this lot should be simplifed...
4127 cfg.align=this.align;
4130 cfg.bgcolor=this.bgcolor;
4133 cfg.border=this.border;
4135 if (this.cellpadding) {
4136 cfg.cellpadding=this.cellpadding;
4138 if (this.cellspacing) {
4139 cfg.cellspacing=this.cellspacing;
4142 cfg.frame=this.frame;
4145 cfg.rules=this.rules;
4147 if (this.sortable) {
4148 cfg.sortable=this.sortable;
4151 cfg.summary=this.summary;
4154 cfg.width=this.width;
4157 if(this.store || this.cm){
4158 cfg.cn.push(this.renderHeader());
4159 cfg.cn.push(this.renderBody());
4160 cfg.cn.push(this.renderFooter());
4162 cfg.cls+= ' TableGrid';
4168 // initTableGrid : function()
4177 // var cm = this.cm;
4179 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4182 // html: cm.getColumnHeader(i)
4186 // cfg.push(header);
4193 initEvents : function()
4195 if(!this.store || !this.cm){
4199 Roo.log('initEvents with ds!!!!');
4203 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4204 e.on('click', _this.sort, _this);
4206 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4207 // this.maskEl.enableDisplayMode("block");
4208 // this.maskEl.show();
4210 this.store.on('load', this.onLoad, this);
4211 this.store.on('beforeload', this.onBeforeLoad, this);
4219 sort : function(e,el)
4221 var col = Roo.get(el)
4223 if(!col.hasClass('sortable')){
4227 var sort = col.attr('sort');
4230 if(col.hasClass('glyphicon-arrow-up')){
4234 this.store.sortInfo = {field : sort, direction : dir};
4239 renderHeader : function()
4248 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4250 var config = cm.config[i];
4254 html: cm.getColumnHeader(i)
4257 if(typeof(config.dataIndex) != 'undefined'){
4258 c.sort = config.dataIndex;
4261 if(typeof(config.sortable) != 'undefined' && config.sortable){
4265 if(typeof(config.width) != 'undefined'){
4266 c.style = 'width:' + config.width + 'px';
4275 renderBody : function()
4285 renderFooter : function()
4297 Roo.log('ds onload');
4302 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4303 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4305 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4306 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4309 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4310 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4314 var tbody = this.el.select('tbody', true).first();
4318 if(this.store.getCount() > 0){
4319 this.store.data.each(function(d){
4325 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4326 var renderer = cm.getRenderer(i);
4327 var config = cm.config[i];
4331 if(typeof(renderer) !== 'undefined'){
4332 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4335 if(typeof(value) === 'object'){
4345 html: (typeof(value) === 'object') ? '' : value
4348 if(typeof(config.width) != 'undefined'){
4349 td.style = 'width:' + config.width + 'px';
4356 tbody.createChild(row);
4364 Roo.each(renders, function(r){
4365 _this.renderColumn(r);
4369 // if(this.loadMask){
4370 // this.maskEl.hide();
4374 onBeforeLoad : function()
4376 Roo.log('ds onBeforeLoad');
4380 // if(this.loadMask){
4381 // this.maskEl.show();
4387 this.el.select('tbody', true).first().dom.innerHTML = '';
4390 getSelectionModel : function(){
4392 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4394 return this.selModel;
4397 renderColumn : function(r)
4400 r.cfg.render(Roo.get(r.id));
4403 Roo.each(r.cfg.cn, function(c){
4408 _this.renderColumn(child);
4425 * @class Roo.bootstrap.TableCell
4426 * @extends Roo.bootstrap.Component
4427 * Bootstrap TableCell class
4428 * @cfg {String} html cell contain text
4429 * @cfg {String} cls cell class
4430 * @cfg {String} tag cell tag (td|th) default td
4431 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4432 * @cfg {String} align Aligns the content in a cell
4433 * @cfg {String} axis Categorizes cells
4434 * @cfg {String} bgcolor Specifies the background color of a cell
4435 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4436 * @cfg {Number} colspan Specifies the number of columns a cell should span
4437 * @cfg {String} headers Specifies one or more header cells a cell is related to
4438 * @cfg {Number} height Sets the height of a cell
4439 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4440 * @cfg {Number} rowspan Sets the number of rows a cell should span
4441 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4442 * @cfg {String} valign Vertical aligns the content in a cell
4443 * @cfg {Number} width Specifies the width of a cell
4446 * Create a new TableCell
4447 * @param {Object} config The config object
4450 Roo.bootstrap.TableCell = function(config){
4451 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4454 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4474 getAutoCreate : function(){
4475 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4495 cfg.align=this.align
4501 cfg.bgcolor=this.bgcolor
4504 cfg.charoff=this.charoff
4507 cfg.colspan=this.colspan
4510 cfg.headers=this.headers
4513 cfg.height=this.height
4516 cfg.nowrap=this.nowrap
4519 cfg.rowspan=this.rowspan
4522 cfg.scope=this.scope
4525 cfg.valign=this.valign
4528 cfg.width=this.width
4547 * @class Roo.bootstrap.TableRow
4548 * @extends Roo.bootstrap.Component
4549 * Bootstrap TableRow class
4550 * @cfg {String} cls row class
4551 * @cfg {String} align Aligns the content in a table row
4552 * @cfg {String} bgcolor Specifies a background color for a table row
4553 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4554 * @cfg {String} valign Vertical aligns the content in a table row
4557 * Create a new TableRow
4558 * @param {Object} config The config object
4561 Roo.bootstrap.TableRow = function(config){
4562 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4565 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4573 getAutoCreate : function(){
4574 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4584 cfg.align = this.align;
4587 cfg.bgcolor = this.bgcolor;
4590 cfg.charoff = this.charoff;
4593 cfg.valign = this.valign;
4611 * @class Roo.bootstrap.TableBody
4612 * @extends Roo.bootstrap.Component
4613 * Bootstrap TableBody class
4614 * @cfg {String} cls element class
4615 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4616 * @cfg {String} align Aligns the content inside the element
4617 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4618 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4621 * Create a new TableBody
4622 * @param {Object} config The config object
4625 Roo.bootstrap.TableBody = function(config){
4626 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4629 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4637 getAutoCreate : function(){
4638 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4652 cfg.align = this.align;
4655 cfg.charoff = this.charoff;
4658 cfg.valign = this.valign;
4665 // initEvents : function()
4672 // this.store = Roo.factory(this.store, Roo.data);
4673 // this.store.on('load', this.onLoad, this);
4675 // this.store.load();
4679 // onLoad: function ()
4681 // this.fireEvent('load', this);
4691 * Ext JS Library 1.1.1
4692 * Copyright(c) 2006-2007, Ext JS, LLC.
4694 * Originally Released Under LGPL - original licence link has changed is not relivant.
4697 * <script type="text/javascript">
4700 // as we use this in bootstrap.
4701 Roo.namespace('Roo.form');
4703 * @class Roo.form.Action
4704 * Internal Class used to handle form actions
4706 * @param {Roo.form.BasicForm} el The form element or its id
4707 * @param {Object} config Configuration options
4712 // define the action interface
4713 Roo.form.Action = function(form, options){
4715 this.options = options || {};
4718 * Client Validation Failed
4721 Roo.form.Action.CLIENT_INVALID = 'client';
4723 * Server Validation Failed
4726 Roo.form.Action.SERVER_INVALID = 'server';
4728 * Connect to Server Failed
4731 Roo.form.Action.CONNECT_FAILURE = 'connect';
4733 * Reading Data from Server Failed
4736 Roo.form.Action.LOAD_FAILURE = 'load';
4738 Roo.form.Action.prototype = {
4740 failureType : undefined,
4741 response : undefined,
4745 run : function(options){
4750 success : function(response){
4755 handleResponse : function(response){
4759 // default connection failure
4760 failure : function(response){
4762 this.response = response;
4763 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4764 this.form.afterAction(this, false);
4767 processResponse : function(response){
4768 this.response = response;
4769 if(!response.responseText){
4772 this.result = this.handleResponse(response);
4776 // utility functions used internally
4777 getUrl : function(appendParams){
4778 var url = this.options.url || this.form.url || this.form.el.dom.action;
4780 var p = this.getParams();
4782 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4788 getMethod : function(){
4789 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4792 getParams : function(){
4793 var bp = this.form.baseParams;
4794 var p = this.options.params;
4796 if(typeof p == "object"){
4797 p = Roo.urlEncode(Roo.applyIf(p, bp));
4798 }else if(typeof p == 'string' && bp){
4799 p += '&' + Roo.urlEncode(bp);
4802 p = Roo.urlEncode(bp);
4807 createCallback : function(){
4809 success: this.success,
4810 failure: this.failure,
4812 timeout: (this.form.timeout*1000),
4813 upload: this.form.fileUpload ? this.success : undefined
4818 Roo.form.Action.Submit = function(form, options){
4819 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4822 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4825 haveProgress : false,
4826 uploadComplete : false,
4828 // uploadProgress indicator.
4829 uploadProgress : function()
4831 if (!this.form.progressUrl) {
4835 if (!this.haveProgress) {
4836 Roo.MessageBox.progress("Uploading", "Uploading");
4838 if (this.uploadComplete) {
4839 Roo.MessageBox.hide();
4843 this.haveProgress = true;
4845 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4847 var c = new Roo.data.Connection();
4849 url : this.form.progressUrl,
4854 success : function(req){
4855 //console.log(data);
4859 rdata = Roo.decode(req.responseText)
4861 Roo.log("Invalid data from server..");
4865 if (!rdata || !rdata.success) {
4867 Roo.MessageBox.alert(Roo.encode(rdata));
4870 var data = rdata.data;
4872 if (this.uploadComplete) {
4873 Roo.MessageBox.hide();
4878 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4879 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4882 this.uploadProgress.defer(2000,this);
4885 failure: function(data) {
4886 Roo.log('progress url failed ');
4897 // run get Values on the form, so it syncs any secondary forms.
4898 this.form.getValues();
4900 var o = this.options;
4901 var method = this.getMethod();
4902 var isPost = method == 'POST';
4903 if(o.clientValidation === false || this.form.isValid()){
4905 if (this.form.progressUrl) {
4906 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4907 (new Date() * 1) + '' + Math.random());
4912 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4913 form:this.form.el.dom,
4914 url:this.getUrl(!isPost),
4916 params:isPost ? this.getParams() : null,
4917 isUpload: this.form.fileUpload
4920 this.uploadProgress();
4922 }else if (o.clientValidation !== false){ // client validation failed
4923 this.failureType = Roo.form.Action.CLIENT_INVALID;
4924 this.form.afterAction(this, false);
4928 success : function(response)
4930 this.uploadComplete= true;
4931 if (this.haveProgress) {
4932 Roo.MessageBox.hide();
4936 var result = this.processResponse(response);
4937 if(result === true || result.success){
4938 this.form.afterAction(this, true);
4942 this.form.markInvalid(result.errors);
4943 this.failureType = Roo.form.Action.SERVER_INVALID;
4945 this.form.afterAction(this, false);
4947 failure : function(response)
4949 this.uploadComplete= true;
4950 if (this.haveProgress) {
4951 Roo.MessageBox.hide();
4954 this.response = response;
4955 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4956 this.form.afterAction(this, false);
4959 handleResponse : function(response){
4960 if(this.form.errorReader){
4961 var rs = this.form.errorReader.read(response);
4964 for(var i = 0, len = rs.records.length; i < len; i++) {
4965 var r = rs.records[i];
4969 if(errors.length < 1){
4973 success : rs.success,
4979 ret = Roo.decode(response.responseText);
4983 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4993 Roo.form.Action.Load = function(form, options){
4994 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4995 this.reader = this.form.reader;
4998 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5003 Roo.Ajax.request(Roo.apply(
5004 this.createCallback(), {
5005 method:this.getMethod(),
5006 url:this.getUrl(false),
5007 params:this.getParams()
5011 success : function(response){
5013 var result = this.processResponse(response);
5014 if(result === true || !result.success || !result.data){
5015 this.failureType = Roo.form.Action.LOAD_FAILURE;
5016 this.form.afterAction(this, false);
5019 this.form.clearInvalid();
5020 this.form.setValues(result.data);
5021 this.form.afterAction(this, true);
5024 handleResponse : function(response){
5025 if(this.form.reader){
5026 var rs = this.form.reader.read(response);
5027 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5029 success : rs.success,
5033 return Roo.decode(response.responseText);
5037 Roo.form.Action.ACTION_TYPES = {
5038 'load' : Roo.form.Action.Load,
5039 'submit' : Roo.form.Action.Submit
5048 * @class Roo.bootstrap.Form
5049 * @extends Roo.bootstrap.Component
5050 * Bootstrap Form class
5051 * @cfg {String} method GET | POST (default POST)
5052 * @cfg {String} labelAlign top | left (default top)
5053 * @cfg {String} align left | right - for navbars
5058 * @param {Object} config The config object
5062 Roo.bootstrap.Form = function(config){
5063 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5066 * @event clientvalidation
5067 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5068 * @param {Form} this
5069 * @param {Boolean} valid true if the form has passed client-side validation
5071 clientvalidation: true,
5073 * @event beforeaction
5074 * Fires before any action is performed. Return false to cancel the action.
5075 * @param {Form} this
5076 * @param {Action} action The action to be performed
5080 * @event actionfailed
5081 * Fires when an action fails.
5082 * @param {Form} this
5083 * @param {Action} action The action that failed
5085 actionfailed : true,
5087 * @event actioncomplete
5088 * Fires when an action is completed.
5089 * @param {Form} this
5090 * @param {Action} action The action that completed
5092 actioncomplete : true
5097 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5100 * @cfg {String} method
5101 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5106 * The URL to use for form actions if one isn't supplied in the action options.
5109 * @cfg {Boolean} fileUpload
5110 * Set to true if this form is a file upload.
5114 * @cfg {Object} baseParams
5115 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5119 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5123 * @cfg {Sting} align (left|right) for navbar forms
5128 activeAction : null,
5131 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5132 * element by passing it or its id or mask the form itself by passing in true.
5135 waitMsgTarget : false,
5140 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5141 * element by passing it or its id or mask the form itself by passing in true.
5145 getAutoCreate : function(){
5149 method : this.method || 'POST',
5150 id : this.id || Roo.id(),
5153 if (this.parent().xtype.match(/^Nav/)) {
5154 cfg.cls = 'navbar-form navbar-' + this.align;
5158 if (this.labelAlign == 'left' ) {
5159 cfg.cls += ' form-horizontal';
5165 initEvents : function()
5167 this.el.on('submit', this.onSubmit, this);
5172 onSubmit : function(e){
5177 * Returns true if client-side validation on the form is successful.
5180 isValid : function(){
5181 var items = this.getItems();
5183 items.each(function(f){
5192 * Returns true if any fields in this form have changed since their original load.
5195 isDirty : function(){
5197 var items = this.getItems();
5198 items.each(function(f){
5208 * Performs a predefined action (submit or load) or custom actions you define on this form.
5209 * @param {String} actionName The name of the action type
5210 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5211 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5212 * accept other config options):
5214 Property Type Description
5215 ---------------- --------------- ----------------------------------------------------------------------------------
5216 url String The url for the action (defaults to the form's url)
5217 method String The form method to use (defaults to the form's method, or POST if not defined)
5218 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5219 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5220 validate the form on the client (defaults to false)
5222 * @return {BasicForm} this
5224 doAction : function(action, options){
5225 if(typeof action == 'string'){
5226 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5228 if(this.fireEvent('beforeaction', this, action) !== false){
5229 this.beforeAction(action);
5230 action.run.defer(100, action);
5236 beforeAction : function(action){
5237 var o = action.options;
5239 // not really supported yet.. ??
5241 //if(this.waitMsgTarget === true){
5242 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5243 //}else if(this.waitMsgTarget){
5244 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5245 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5247 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5253 afterAction : function(action, success){
5254 this.activeAction = null;
5255 var o = action.options;
5257 //if(this.waitMsgTarget === true){
5259 //}else if(this.waitMsgTarget){
5260 // this.waitMsgTarget.unmask();
5262 // Roo.MessageBox.updateProgress(1);
5263 // Roo.MessageBox.hide();
5270 Roo.callback(o.success, o.scope, [this, action]);
5271 this.fireEvent('actioncomplete', this, action);
5275 // failure condition..
5276 // we have a scenario where updates need confirming.
5277 // eg. if a locking scenario exists..
5278 // we look for { errors : { needs_confirm : true }} in the response.
5280 (typeof(action.result) != 'undefined') &&
5281 (typeof(action.result.errors) != 'undefined') &&
5282 (typeof(action.result.errors.needs_confirm) != 'undefined')
5285 Roo.log("not supported yet");
5288 Roo.MessageBox.confirm(
5289 "Change requires confirmation",
5290 action.result.errorMsg,
5295 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5305 Roo.callback(o.failure, o.scope, [this, action]);
5306 // show an error message if no failed handler is set..
5307 if (!this.hasListener('actionfailed')) {
5308 Roo.log("need to add dialog support");
5310 Roo.MessageBox.alert("Error",
5311 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5312 action.result.errorMsg :
5313 "Saving Failed, please check your entries or try again"
5318 this.fireEvent('actionfailed', this, action);
5323 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5324 * @param {String} id The value to search for
5327 findField : function(id){
5328 var items = this.getItems();
5329 var field = items.get(id);
5331 items.each(function(f){
5332 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5339 return field || null;
5342 * Mark fields in this form invalid in bulk.
5343 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5344 * @return {BasicForm} this
5346 markInvalid : function(errors){
5347 if(errors instanceof Array){
5348 for(var i = 0, len = errors.length; i < len; i++){
5349 var fieldError = errors[i];
5350 var f = this.findField(fieldError.id);
5352 f.markInvalid(fieldError.msg);
5358 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5359 field.markInvalid(errors[id]);
5363 //Roo.each(this.childForms || [], function (f) {
5364 // f.markInvalid(errors);
5371 * Set values for fields in this form in bulk.
5372 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5373 * @return {BasicForm} this
5375 setValues : function(values){
5376 if(values instanceof Array){ // array of objects
5377 for(var i = 0, len = values.length; i < len; i++){
5379 var f = this.findField(v.id);
5381 f.setValue(v.value);
5382 if(this.trackResetOnLoad){
5383 f.originalValue = f.getValue();
5387 }else{ // object hash
5390 if(typeof values[id] != 'function' && (field = this.findField(id))){
5392 if (field.setFromData &&
5394 field.displayField &&
5395 // combos' with local stores can
5396 // be queried via setValue()
5397 // to set their value..
5398 (field.store && !field.store.isLocal)
5402 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5403 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5404 field.setFromData(sd);
5407 field.setValue(values[id]);
5411 if(this.trackResetOnLoad){
5412 field.originalValue = field.getValue();
5418 //Roo.each(this.childForms || [], function (f) {
5419 // f.setValues(values);
5426 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5427 * they are returned as an array.
5428 * @param {Boolean} asString
5431 getValues : function(asString){
5432 //if (this.childForms) {
5433 // copy values from the child forms
5434 // Roo.each(this.childForms, function (f) {
5435 // this.setValues(f.getValues());
5441 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5442 if(asString === true){
5445 return Roo.urlDecode(fs);
5449 * Returns the fields in this form as an object with key/value pairs.
5450 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5453 getFieldValues : function(with_hidden)
5455 var items = this.getItems();
5457 items.each(function(f){
5461 var v = f.getValue();
5462 if (f.inputType =='radio') {
5463 if (typeof(ret[f.getName()]) == 'undefined') {
5464 ret[f.getName()] = ''; // empty..
5467 if (!f.el.dom.checked) {
5475 // not sure if this supported any more..
5476 if ((typeof(v) == 'object') && f.getRawValue) {
5477 v = f.getRawValue() ; // dates..
5479 // combo boxes where name != hiddenName...
5480 if (f.name != f.getName()) {
5481 ret[f.name] = f.getRawValue();
5483 ret[f.getName()] = v;
5490 * Clears all invalid messages in this form.
5491 * @return {BasicForm} this
5493 clearInvalid : function(){
5494 var items = this.getItems();
5496 items.each(function(f){
5507 * @return {BasicForm} this
5510 var items = this.getItems();
5511 items.each(function(f){
5515 Roo.each(this.childForms || [], function (f) {
5522 getItems : function()
5524 var r=new Roo.util.MixedCollection(false, function(o){
5525 return o.id || (o.id = Roo.id());
5527 var iter = function(el) {
5534 Roo.each(el.items,function(e) {
5553 * Ext JS Library 1.1.1
5554 * Copyright(c) 2006-2007, Ext JS, LLC.
5556 * Originally Released Under LGPL - original licence link has changed is not relivant.
5559 * <script type="text/javascript">
5562 * @class Roo.form.VTypes
5563 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5566 Roo.form.VTypes = function(){
5567 // closure these in so they are only created once.
5568 var alpha = /^[a-zA-Z_]+$/;
5569 var alphanum = /^[a-zA-Z0-9_]+$/;
5570 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5571 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5573 // All these messages and functions are configurable
5576 * The function used to validate email addresses
5577 * @param {String} value The email address
5579 'email' : function(v){
5580 return email.test(v);
5583 * The error text to display when the email validation function returns false
5586 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5588 * The keystroke filter mask to be applied on email input
5591 'emailMask' : /[a-z0-9_\.\-@]/i,
5594 * The function used to validate URLs
5595 * @param {String} value The URL
5597 'url' : function(v){
5601 * The error text to display when the url validation function returns false
5604 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5607 * The function used to validate alpha values
5608 * @param {String} value The value
5610 'alpha' : function(v){
5611 return alpha.test(v);
5614 * The error text to display when the alpha validation function returns false
5617 'alphaText' : 'This field should only contain letters and _',
5619 * The keystroke filter mask to be applied on alpha input
5622 'alphaMask' : /[a-z_]/i,
5625 * The function used to validate alphanumeric values
5626 * @param {String} value The value
5628 'alphanum' : function(v){
5629 return alphanum.test(v);
5632 * The error text to display when the alphanumeric validation function returns false
5635 'alphanumText' : 'This field should only contain letters, numbers and _',
5637 * The keystroke filter mask to be applied on alphanumeric input
5640 'alphanumMask' : /[a-z0-9_]/i
5650 * @class Roo.bootstrap.Input
5651 * @extends Roo.bootstrap.Component
5652 * Bootstrap Input class
5653 * @cfg {Boolean} disabled is it disabled
5654 * @cfg {String} fieldLabel - the label associated
5655 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5656 * @cfg {String} name name of the input
5657 * @cfg {string} fieldLabel - the label associated
5658 * @cfg {string} inputType - input / file submit ...
5659 * @cfg {string} placeholder - placeholder to put in text.
5660 * @cfg {string} before - input group add on before
5661 * @cfg {string} after - input group add on after
5662 * @cfg {string} size - (lg|sm) or leave empty..
5663 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5664 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5665 * @cfg {Number} md colspan out of 12 for computer-sized screens
5666 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5667 * @cfg {string} value default value of the input
5668 * @cfg {Number} labelWidth set the width of label (0-12)
5669 * @cfg {String} labelAlign (top|left)
5670 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5674 * Create a new Input
5675 * @param {Object} config The config object
5678 Roo.bootstrap.Input = function(config){
5679 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5684 * Fires when this field receives input focus.
5685 * @param {Roo.form.Field} this
5690 * Fires when this field loses input focus.
5691 * @param {Roo.form.Field} this
5696 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5697 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5698 * @param {Roo.form.Field} this
5699 * @param {Roo.EventObject} e The event object
5704 * Fires just before the field blurs if the field value has changed.
5705 * @param {Roo.form.Field} this
5706 * @param {Mixed} newValue The new value
5707 * @param {Mixed} oldValue The original value
5712 * Fires after the field has been marked as invalid.
5713 * @param {Roo.form.Field} this
5714 * @param {String} msg The validation message
5719 * Fires after the field has been validated with no errors.
5720 * @param {Roo.form.Field} this
5725 * Fires after the key up
5726 * @param {Roo.form.Field} this
5727 * @param {Roo.EventObject} e The event Object
5733 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5735 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5736 automatic validation (defaults to "keyup").
5738 validationEvent : "keyup",
5740 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5742 validateOnBlur : true,
5744 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5746 validationDelay : 250,
5748 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5750 focusClass : "x-form-focus", // not needed???
5754 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5756 invalidClass : "has-error",
5759 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5761 selectOnFocus : false,
5764 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5768 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5773 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5775 disableKeyFilter : false,
5778 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5782 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5786 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5788 blankText : "This field is required",
5791 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5795 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5797 maxLength : Number.MAX_VALUE,
5799 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5801 minLengthText : "The minimum length for this field is {0}",
5803 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5805 maxLengthText : "The maximum length for this field is {0}",
5809 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5810 * If available, this function will be called only after the basic validators all return true, and will be passed the
5811 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5815 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5816 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5817 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5821 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5844 parentLabelAlign : function()
5847 while (parent.parent()) {
5848 parent = parent.parent();
5849 if (typeof(parent.labelAlign) !='undefined') {
5850 return parent.labelAlign;
5857 getAutoCreate : function(){
5859 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5865 if(this.inputType != 'hidden'){
5866 cfg.cls = 'form-group' //input-group
5872 type : this.inputType,
5874 cls : 'form-control',
5875 placeholder : this.placeholder || ''
5879 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5880 input.maxLength = this.maxLength;
5883 if (this.disabled) {
5884 input.disabled=true;
5887 if (this.readOnly) {
5888 input.readonly=true;
5892 input.name = this.name;
5895 input.cls += ' input-' + this.size;
5898 ['xs','sm','md','lg'].map(function(size){
5899 if (settings[size]) {
5900 cfg.cls += ' col-' + size + '-' + settings[size];
5904 var inputblock = input;
5906 if (this.before || this.after) {
5909 cls : 'input-group',
5912 if (this.before && typeof(this.before) == 'string') {
5914 inputblock.cn.push({
5916 cls : 'roo-input-before input-group-addon',
5920 if (this.before && typeof(this.before) == 'object') {
5921 this.before = Roo.factory(this.before);
5922 Roo.log(this.before);
5923 inputblock.cn.push({
5925 cls : 'roo-input-before input-group-' +
5926 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5930 inputblock.cn.push(input);
5932 if (this.after && typeof(this.after) == 'string') {
5933 inputblock.cn.push({
5935 cls : 'roo-input-after input-group-addon',
5939 if (this.after && typeof(this.after) == 'object') {
5940 this.after = Roo.factory(this.after);
5941 Roo.log(this.after);
5942 inputblock.cn.push({
5944 cls : 'roo-input-after input-group-' +
5945 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5950 if (align ==='left' && this.fieldLabel.length) {
5951 Roo.log("left and has label");
5957 cls : 'control-label col-sm-' + this.labelWidth,
5958 html : this.fieldLabel
5962 cls : "col-sm-" + (12 - this.labelWidth),
5969 } else if ( this.fieldLabel.length) {
5975 //cls : 'input-group-addon',
5976 html : this.fieldLabel
5986 Roo.log(" no label && no align");
5995 Roo.log('input-parentType: ' + this.parentType);
5997 if (this.parentType === 'Navbar' && this.parent().bar) {
5998 cfg.cls += ' navbar-form';
6006 * return the real input element.
6008 inputEl: function ()
6010 return this.el.select('input.form-control',true).first();
6012 setDisabled : function(v)
6014 var i = this.inputEl().dom;
6016 i.removeAttribute('disabled');
6020 i.setAttribute('disabled','true');
6022 initEvents : function()
6025 this.inputEl().on("keydown" , this.fireKey, this);
6026 this.inputEl().on("focus", this.onFocus, this);
6027 this.inputEl().on("blur", this.onBlur, this);
6029 this.inputEl().relayEvent('keyup', this);
6031 // reference to original value for reset
6032 this.originalValue = this.getValue();
6033 //Roo.form.TextField.superclass.initEvents.call(this);
6034 if(this.validationEvent == 'keyup'){
6035 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6036 this.inputEl().on('keyup', this.filterValidation, this);
6038 else if(this.validationEvent !== false){
6039 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6042 if(this.selectOnFocus){
6043 this.on("focus", this.preFocus, this);
6046 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6047 this.inputEl().on("keypress", this.filterKeys, this);
6050 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6051 this.el.on("click", this.autoSize, this);
6054 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6055 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6058 if (typeof(this.before) == 'object') {
6059 this.before.render(this.el.select('.roo-input-before',true).first());
6061 if (typeof(this.after) == 'object') {
6062 this.after.render(this.el.select('.roo-input-after',true).first());
6067 filterValidation : function(e){
6068 if(!e.isNavKeyPress()){
6069 this.validationTask.delay(this.validationDelay);
6073 * Validates the field value
6074 * @return {Boolean} True if the value is valid, else false
6076 validate : function(){
6077 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6078 if(this.disabled || this.validateValue(this.getRawValue())){
6079 this.clearInvalid();
6087 * Validates a value according to the field's validation rules and marks the field as invalid
6088 * if the validation fails
6089 * @param {Mixed} value The value to validate
6090 * @return {Boolean} True if the value is valid, else false
6092 validateValue : function(value){
6093 if(value.length < 1) { // if it's blank
6094 if(this.allowBlank){
6095 this.clearInvalid();
6098 this.markInvalid(this.blankText);
6102 if(value.length < this.minLength){
6103 this.markInvalid(String.format(this.minLengthText, this.minLength));
6106 if(value.length > this.maxLength){
6107 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6111 var vt = Roo.form.VTypes;
6112 if(!vt[this.vtype](value, this)){
6113 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6117 if(typeof this.validator == "function"){
6118 var msg = this.validator(value);
6120 this.markInvalid(msg);
6124 if(this.regex && !this.regex.test(value)){
6125 this.markInvalid(this.regexText);
6134 fireKey : function(e){
6135 //Roo.log('field ' + e.getKey());
6136 if(e.isNavKeyPress()){
6137 this.fireEvent("specialkey", this, e);
6140 focus : function (selectText){
6142 this.inputEl().focus();
6143 if(selectText === true){
6144 this.inputEl().dom.select();
6150 onFocus : function(){
6151 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6152 // this.el.addClass(this.focusClass);
6155 this.hasFocus = true;
6156 this.startValue = this.getValue();
6157 this.fireEvent("focus", this);
6161 beforeBlur : Roo.emptyFn,
6165 onBlur : function(){
6167 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6168 //this.el.removeClass(this.focusClass);
6170 this.hasFocus = false;
6171 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6174 var v = this.getValue();
6175 if(String(v) !== String(this.startValue)){
6176 this.fireEvent('change', this, v, this.startValue);
6178 this.fireEvent("blur", this);
6182 * Resets the current field value to the originally loaded value and clears any validation messages
6185 this.setValue(this.originalValue);
6186 this.clearInvalid();
6189 * Returns the name of the field
6190 * @return {Mixed} name The name field
6192 getName: function(){
6196 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6197 * @return {Mixed} value The field value
6199 getValue : function(){
6200 return this.inputEl().getValue();
6203 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6204 * @return {Mixed} value The field value
6206 getRawValue : function(){
6207 var v = this.inputEl().getValue();
6213 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6214 * @param {Mixed} value The value to set
6216 setRawValue : function(v){
6217 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6220 selectText : function(start, end){
6221 var v = this.getRawValue();
6223 start = start === undefined ? 0 : start;
6224 end = end === undefined ? v.length : end;
6225 var d = this.inputEl().dom;
6226 if(d.setSelectionRange){
6227 d.setSelectionRange(start, end);
6228 }else if(d.createTextRange){
6229 var range = d.createTextRange();
6230 range.moveStart("character", start);
6231 range.moveEnd("character", v.length-end);
6238 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6239 * @param {Mixed} value The value to set
6241 setValue : function(v){
6244 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6250 processValue : function(value){
6251 if(this.stripCharsRe){
6252 var newValue = value.replace(this.stripCharsRe, '');
6253 if(newValue !== value){
6254 this.setRawValue(newValue);
6261 preFocus : function(){
6263 if(this.selectOnFocus){
6264 this.inputEl().dom.select();
6267 filterKeys : function(e){
6269 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6272 var c = e.getCharCode(), cc = String.fromCharCode(c);
6273 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6276 if(!this.maskRe.test(cc)){
6281 * Clear any invalid styles/messages for this field
6283 clearInvalid : function(){
6285 if(!this.el || this.preventMark){ // not rendered
6288 this.el.removeClass(this.invalidClass);
6290 switch(this.msgTarget){
6292 this.el.dom.qtip = '';
6295 this.el.dom.title = '';
6299 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6304 this.errorIcon.dom.qtip = '';
6305 this.errorIcon.hide();
6306 this.un('resize', this.alignErrorIcon, this);
6310 var t = Roo.getDom(this.msgTarget);
6312 t.style.display = 'none';
6316 this.fireEvent('valid', this);
6319 * Mark this field as invalid
6320 * @param {String} msg The validation message
6322 markInvalid : function(msg){
6323 if(!this.el || this.preventMark){ // not rendered
6326 this.el.addClass(this.invalidClass);
6328 msg = msg || this.invalidText;
6329 switch(this.msgTarget){
6331 this.el.dom.qtip = msg;
6332 this.el.dom.qclass = 'x-form-invalid-tip';
6333 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6334 Roo.QuickTips.enable();
6338 this.el.dom.title = msg;
6342 var elp = this.el.findParent('.x-form-element', 5, true);
6343 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6344 this.errorEl.setWidth(elp.getWidth(true)-20);
6346 this.errorEl.update(msg);
6347 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6350 if(!this.errorIcon){
6351 var elp = this.el.findParent('.x-form-element', 5, true);
6352 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6354 this.alignErrorIcon();
6355 this.errorIcon.dom.qtip = msg;
6356 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6357 this.errorIcon.show();
6358 this.on('resize', this.alignErrorIcon, this);
6361 var t = Roo.getDom(this.msgTarget);
6363 t.style.display = this.msgDisplay;
6367 this.fireEvent('invalid', this, msg);
6370 SafariOnKeyDown : function(event)
6372 // this is a workaround for a password hang bug on chrome/ webkit.
6374 var isSelectAll = false;
6376 if(this.inputEl().dom.selectionEnd > 0){
6377 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6379 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6380 event.preventDefault();
6385 if(isSelectAll){ // backspace and delete key
6387 event.preventDefault();
6388 // this is very hacky as keydown always get's upper case.
6390 var cc = String.fromCharCode(event.getCharCode());
6391 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6395 adjustWidth : function(tag, w){
6396 tag = tag.toLowerCase();
6397 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6398 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6402 if(tag == 'textarea'){
6405 }else if(Roo.isOpera){
6409 if(tag == 'textarea'){
6428 * @class Roo.bootstrap.TextArea
6429 * @extends Roo.bootstrap.Input
6430 * Bootstrap TextArea class
6431 * @cfg {Number} cols Specifies the visible width of a text area
6432 * @cfg {Number} rows Specifies the visible number of lines in a text area
6433 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6434 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6435 * @cfg {string} html text
6438 * Create a new TextArea
6439 * @param {Object} config The config object
6442 Roo.bootstrap.TextArea = function(config){
6443 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6447 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6457 getAutoCreate : function(){
6459 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6470 value : this.value || '',
6471 html: this.html || '',
6472 cls : 'form-control',
6473 placeholder : this.placeholder || ''
6477 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6478 input.maxLength = this.maxLength;
6482 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6486 input.cols = this.cols;
6489 if (this.readOnly) {
6490 input.readonly = true;
6494 input.name = this.name;
6498 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6502 ['xs','sm','md','lg'].map(function(size){
6503 if (settings[size]) {
6504 cfg.cls += ' col-' + size + '-' + settings[size];
6508 var inputblock = input;
6510 if (this.before || this.after) {
6513 cls : 'input-group',
6517 inputblock.cn.push({
6519 cls : 'input-group-addon',
6523 inputblock.cn.push(input);
6525 inputblock.cn.push({
6527 cls : 'input-group-addon',
6534 if (align ==='left' && this.fieldLabel.length) {
6535 Roo.log("left and has label");
6541 cls : 'control-label col-sm-' + this.labelWidth,
6542 html : this.fieldLabel
6546 cls : "col-sm-" + (12 - this.labelWidth),
6553 } else if ( this.fieldLabel.length) {
6559 //cls : 'input-group-addon',
6560 html : this.fieldLabel
6570 Roo.log(" no label && no align");
6580 if (this.disabled) {
6581 input.disabled=true;
6588 * return the real textarea element.
6590 inputEl: function ()
6592 return this.el.select('textarea.form-control',true).first();
6600 * trigger field - base class for combo..
6605 * @class Roo.bootstrap.TriggerField
6606 * @extends Roo.bootstrap.Input
6607 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6608 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6609 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6610 * for which you can provide a custom implementation. For example:
6612 var trigger = new Roo.bootstrap.TriggerField();
6613 trigger.onTriggerClick = myTriggerFn;
6614 trigger.applyTo('my-field');
6617 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6618 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6619 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6620 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6622 * Create a new TriggerField.
6623 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6624 * to the base TextField)
6626 Roo.bootstrap.TriggerField = function(config){
6627 this.mimicing = false;
6628 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6631 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6633 * @cfg {String} triggerClass A CSS class to apply to the trigger
6636 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6640 /** @cfg {Boolean} grow @hide */
6641 /** @cfg {Number} growMin @hide */
6642 /** @cfg {Number} growMax @hide */
6648 autoSize: Roo.emptyFn,
6655 actionMode : 'wrap',
6659 getAutoCreate : function(){
6661 var parent = this.parent();
6663 var align = this.labelAlign || this.parentLabelAlign();
6668 cls: 'form-group' //input-group
6675 type : this.inputType,
6676 cls : 'form-control',
6677 autocomplete: 'off',
6678 placeholder : this.placeholder || ''
6682 input.name = this.name;
6685 input.cls += ' input-' + this.size;
6688 if (this.disabled) {
6689 input.disabled=true;
6692 var inputblock = input;
6694 if (this.before || this.after) {
6697 cls : 'input-group',
6701 inputblock.cn.push({
6703 cls : 'input-group-addon',
6707 inputblock.cn.push(input);
6709 inputblock.cn.push({
6711 cls : 'input-group-addon',
6724 cls: 'form-hidden-field'
6732 Roo.log('multiple');
6740 cls: 'form-hidden-field'
6744 cls: 'select2-choices',
6748 cls: 'select2-search-field',
6761 cls: 'select2-container input-group',
6766 cls: 'typeahead typeahead-long dropdown-menu',
6767 style: 'display:none'
6775 cls : 'input-group-addon btn dropdown-toggle',
6783 cls: 'combobox-clear',
6797 combobox.cls += ' select2-container-multi';
6800 if (align ==='left' && this.fieldLabel.length) {
6802 Roo.log("left and has label");
6808 cls : 'control-label col-sm-' + this.labelWidth,
6809 html : this.fieldLabel
6813 cls : "col-sm-" + (12 - this.labelWidth),
6820 } else if ( this.fieldLabel.length) {
6826 //cls : 'input-group-addon',
6827 html : this.fieldLabel
6837 Roo.log(" no label && no align");
6844 ['xs','sm','md','lg'].map(function(size){
6845 if (settings[size]) {
6846 cfg.cls += ' col-' + size + '-' + settings[size];
6857 onResize : function(w, h){
6858 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6859 // if(typeof w == 'number'){
6860 // var x = w - this.trigger.getWidth();
6861 // this.inputEl().setWidth(this.adjustWidth('input', x));
6862 // this.trigger.setStyle('left', x+'px');
6867 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6870 getResizeEl : function(){
6871 return this.inputEl();
6875 getPositionEl : function(){
6876 return this.inputEl();
6880 alignErrorIcon : function(){
6881 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6885 initEvents : function(){
6887 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6888 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6890 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6891 if(this.hideTrigger){
6892 this.trigger.setDisplayed(false);
6894 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6898 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6901 //this.trigger.addClassOnOver('x-form-trigger-over');
6902 //this.trigger.addClassOnClick('x-form-trigger-click');
6905 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6910 initTrigger : function(){
6915 onDestroy : function(){
6917 this.trigger.removeAllListeners();
6918 // this.trigger.remove();
6921 // this.wrap.remove();
6923 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6927 onFocus : function(){
6928 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6931 this.wrap.addClass('x-trigger-wrap-focus');
6932 this.mimicing = true;
6933 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6934 if(this.monitorTab){
6935 this.el.on("keydown", this.checkTab, this);
6942 checkTab : function(e){
6943 if(e.getKey() == e.TAB){
6949 onBlur : function(){
6954 mimicBlur : function(e, t){
6956 if(!this.wrap.contains(t) && this.validateBlur()){
6963 triggerBlur : function(){
6964 this.mimicing = false;
6965 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6966 if(this.monitorTab){
6967 this.el.un("keydown", this.checkTab, this);
6969 //this.wrap.removeClass('x-trigger-wrap-focus');
6970 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6974 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6975 validateBlur : function(e, t){
6980 onDisable : function(){
6981 this.inputEl().dom.disabled = true;
6982 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6984 // this.wrap.addClass('x-item-disabled');
6989 onEnable : function(){
6990 this.inputEl().dom.disabled = false;
6991 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6993 // this.el.removeClass('x-item-disabled');
6998 onShow : function(){
6999 var ae = this.getActionEl();
7002 ae.dom.style.display = '';
7003 ae.dom.style.visibility = 'visible';
7009 onHide : function(){
7010 var ae = this.getActionEl();
7011 ae.dom.style.display = 'none';
7015 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7016 * by an implementing function.
7018 * @param {EventObject} e
7020 onTriggerClick : Roo.emptyFn
7024 * Ext JS Library 1.1.1
7025 * Copyright(c) 2006-2007, Ext JS, LLC.
7027 * Originally Released Under LGPL - original licence link has changed is not relivant.
7030 * <script type="text/javascript">
7035 * @class Roo.data.SortTypes
7037 * Defines the default sorting (casting?) comparison functions used when sorting data.
7039 Roo.data.SortTypes = {
7041 * Default sort that does nothing
7042 * @param {Mixed} s The value being converted
7043 * @return {Mixed} The comparison value
7050 * The regular expression used to strip tags
7054 stripTagsRE : /<\/?[^>]+>/gi,
7057 * Strips all HTML tags to sort on text only
7058 * @param {Mixed} s The value being converted
7059 * @return {String} The comparison value
7061 asText : function(s){
7062 return String(s).replace(this.stripTagsRE, "");
7066 * Strips all HTML tags to sort on text only - Case insensitive
7067 * @param {Mixed} s The value being converted
7068 * @return {String} The comparison value
7070 asUCText : function(s){
7071 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7075 * Case insensitive string
7076 * @param {Mixed} s The value being converted
7077 * @return {String} The comparison value
7079 asUCString : function(s) {
7080 return String(s).toUpperCase();
7085 * @param {Mixed} s The value being converted
7086 * @return {Number} The comparison value
7088 asDate : function(s) {
7092 if(s instanceof Date){
7095 return Date.parse(String(s));
7100 * @param {Mixed} s The value being converted
7101 * @return {Float} The comparison value
7103 asFloat : function(s) {
7104 var val = parseFloat(String(s).replace(/,/g, ""));
7105 if(isNaN(val)) val = 0;
7111 * @param {Mixed} s The value being converted
7112 * @return {Number} The comparison value
7114 asInt : function(s) {
7115 var val = parseInt(String(s).replace(/,/g, ""));
7116 if(isNaN(val)) val = 0;
7121 * Ext JS Library 1.1.1
7122 * Copyright(c) 2006-2007, Ext JS, LLC.
7124 * Originally Released Under LGPL - original licence link has changed is not relivant.
7127 * <script type="text/javascript">
7131 * @class Roo.data.Record
7132 * Instances of this class encapsulate both record <em>definition</em> information, and record
7133 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7134 * to access Records cached in an {@link Roo.data.Store} object.<br>
7136 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7137 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7140 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7142 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7143 * {@link #create}. The parameters are the same.
7144 * @param {Array} data An associative Array of data values keyed by the field name.
7145 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7146 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7147 * not specified an integer id is generated.
7149 Roo.data.Record = function(data, id){
7150 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7155 * Generate a constructor for a specific record layout.
7156 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7157 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7158 * Each field definition object may contain the following properties: <ul>
7159 * <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,
7160 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7161 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7162 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7163 * is being used, then this is a string containing the javascript expression to reference the data relative to
7164 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7165 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7166 * this may be omitted.</p></li>
7167 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7168 * <ul><li>auto (Default, implies no conversion)</li>
7173 * <li>date</li></ul></p></li>
7174 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7175 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7176 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7177 * by the Reader into an object that will be stored in the Record. It is passed the
7178 * following parameters:<ul>
7179 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7181 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7183 * <br>usage:<br><pre><code>
7184 var TopicRecord = Roo.data.Record.create(
7185 {name: 'title', mapping: 'topic_title'},
7186 {name: 'author', mapping: 'username'},
7187 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7188 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7189 {name: 'lastPoster', mapping: 'user2'},
7190 {name: 'excerpt', mapping: 'post_text'}
7193 var myNewRecord = new TopicRecord({
7194 title: 'Do my job please',
7197 lastPost: new Date(),
7198 lastPoster: 'Animal',
7199 excerpt: 'No way dude!'
7201 myStore.add(myNewRecord);
7206 Roo.data.Record.create = function(o){
7208 f.superclass.constructor.apply(this, arguments);
7210 Roo.extend(f, Roo.data.Record);
7211 var p = f.prototype;
7212 p.fields = new Roo.util.MixedCollection(false, function(field){
7215 for(var i = 0, len = o.length; i < len; i++){
7216 p.fields.add(new Roo.data.Field(o[i]));
7218 f.getField = function(name){
7219 return p.fields.get(name);
7224 Roo.data.Record.AUTO_ID = 1000;
7225 Roo.data.Record.EDIT = 'edit';
7226 Roo.data.Record.REJECT = 'reject';
7227 Roo.data.Record.COMMIT = 'commit';
7229 Roo.data.Record.prototype = {
7231 * Readonly flag - true if this record has been modified.
7240 join : function(store){
7245 * Set the named field to the specified value.
7246 * @param {String} name The name of the field to set.
7247 * @param {Object} value The value to set the field to.
7249 set : function(name, value){
7250 if(this.data[name] == value){
7257 if(typeof this.modified[name] == 'undefined'){
7258 this.modified[name] = this.data[name];
7260 this.data[name] = value;
7261 if(!this.editing && this.store){
7262 this.store.afterEdit(this);
7267 * Get the value of the named field.
7268 * @param {String} name The name of the field to get the value of.
7269 * @return {Object} The value of the field.
7271 get : function(name){
7272 return this.data[name];
7276 beginEdit : function(){
7277 this.editing = true;
7282 cancelEdit : function(){
7283 this.editing = false;
7284 delete this.modified;
7288 endEdit : function(){
7289 this.editing = false;
7290 if(this.dirty && this.store){
7291 this.store.afterEdit(this);
7296 * Usually called by the {@link Roo.data.Store} which owns the Record.
7297 * Rejects all changes made to the Record since either creation, or the last commit operation.
7298 * Modified fields are reverted to their original values.
7300 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7301 * of reject operations.
7303 reject : function(){
7304 var m = this.modified;
7306 if(typeof m[n] != "function"){
7307 this.data[n] = m[n];
7311 delete this.modified;
7312 this.editing = false;
7314 this.store.afterReject(this);
7319 * Usually called by the {@link Roo.data.Store} which owns the Record.
7320 * Commits all changes made to the Record since either creation, or the last commit operation.
7322 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7323 * of commit operations.
7325 commit : function(){
7327 delete this.modified;
7328 this.editing = false;
7330 this.store.afterCommit(this);
7335 hasError : function(){
7336 return this.error != null;
7340 clearError : function(){
7345 * Creates a copy of this record.
7346 * @param {String} id (optional) A new record id if you don't want to use this record's id
7349 copy : function(newId) {
7350 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7354 * Ext JS Library 1.1.1
7355 * Copyright(c) 2006-2007, Ext JS, LLC.
7357 * Originally Released Under LGPL - original licence link has changed is not relivant.
7360 * <script type="text/javascript">
7366 * @class Roo.data.Store
7367 * @extends Roo.util.Observable
7368 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7369 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7371 * 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
7372 * has no knowledge of the format of the data returned by the Proxy.<br>
7374 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7375 * instances from the data object. These records are cached and made available through accessor functions.
7377 * Creates a new Store.
7378 * @param {Object} config A config object containing the objects needed for the Store to access data,
7379 * and read the data into Records.
7381 Roo.data.Store = function(config){
7382 this.data = new Roo.util.MixedCollection(false);
7383 this.data.getKey = function(o){
7386 this.baseParams = {};
7393 "multisort" : "_multisort"
7396 if(config && config.data){
7397 this.inlineData = config.data;
7401 Roo.apply(this, config);
7403 if(this.reader){ // reader passed
7404 this.reader = Roo.factory(this.reader, Roo.data);
7405 this.reader.xmodule = this.xmodule || false;
7406 if(!this.recordType){
7407 this.recordType = this.reader.recordType;
7409 if(this.reader.onMetaChange){
7410 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7414 if(this.recordType){
7415 this.fields = this.recordType.prototype.fields;
7421 * @event datachanged
7422 * Fires when the data cache has changed, and a widget which is using this Store
7423 * as a Record cache should refresh its view.
7424 * @param {Store} this
7429 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7430 * @param {Store} this
7431 * @param {Object} meta The JSON metadata
7436 * Fires when Records have been added to the Store
7437 * @param {Store} this
7438 * @param {Roo.data.Record[]} records The array of Records added
7439 * @param {Number} index The index at which the record(s) were added
7444 * Fires when a Record has been removed from the Store
7445 * @param {Store} this
7446 * @param {Roo.data.Record} record The Record that was removed
7447 * @param {Number} index The index at which the record was removed
7452 * Fires when a Record has been updated
7453 * @param {Store} this
7454 * @param {Roo.data.Record} record The Record that was updated
7455 * @param {String} operation The update operation being performed. Value may be one of:
7457 Roo.data.Record.EDIT
7458 Roo.data.Record.REJECT
7459 Roo.data.Record.COMMIT
7465 * Fires when the data cache has been cleared.
7466 * @param {Store} this
7471 * Fires before a request is made for a new data object. If the beforeload handler returns false
7472 * the load action will be canceled.
7473 * @param {Store} this
7474 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7478 * @event beforeloadadd
7479 * Fires after a new set of Records has been loaded.
7480 * @param {Store} this
7481 * @param {Roo.data.Record[]} records The Records that were loaded
7482 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7484 beforeloadadd : true,
7487 * Fires after a new set of Records has been loaded, before they are added to the store.
7488 * @param {Store} this
7489 * @param {Roo.data.Record[]} records The Records that were loaded
7490 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7491 * @params {Object} return from reader
7495 * @event loadexception
7496 * Fires if an exception occurs in the Proxy during loading.
7497 * Called with the signature of the Proxy's "loadexception" event.
7498 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7501 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7502 * @param {Object} load options
7503 * @param {Object} jsonData from your request (normally this contains the Exception)
7505 loadexception : true
7509 this.proxy = Roo.factory(this.proxy, Roo.data);
7510 this.proxy.xmodule = this.xmodule || false;
7511 this.relayEvents(this.proxy, ["loadexception"]);
7513 this.sortToggle = {};
7514 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7516 Roo.data.Store.superclass.constructor.call(this);
7518 if(this.inlineData){
7519 this.loadData(this.inlineData);
7520 delete this.inlineData;
7524 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7526 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7527 * without a remote query - used by combo/forms at present.
7531 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7534 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7537 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7538 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7541 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7542 * on any HTTP request
7545 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7548 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7552 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7553 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7558 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7559 * loaded or when a record is removed. (defaults to false).
7561 pruneModifiedRecords : false,
7567 * Add Records to the Store and fires the add event.
7568 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7570 add : function(records){
7571 records = [].concat(records);
7572 for(var i = 0, len = records.length; i < len; i++){
7573 records[i].join(this);
7575 var index = this.data.length;
7576 this.data.addAll(records);
7577 this.fireEvent("add", this, records, index);
7581 * Remove a Record from the Store and fires the remove event.
7582 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7584 remove : function(record){
7585 var index = this.data.indexOf(record);
7586 this.data.removeAt(index);
7587 if(this.pruneModifiedRecords){
7588 this.modified.remove(record);
7590 this.fireEvent("remove", this, record, index);
7594 * Remove all Records from the Store and fires the clear event.
7596 removeAll : function(){
7598 if(this.pruneModifiedRecords){
7601 this.fireEvent("clear", this);
7605 * Inserts Records to the Store at the given index and fires the add event.
7606 * @param {Number} index The start index at which to insert the passed Records.
7607 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7609 insert : function(index, records){
7610 records = [].concat(records);
7611 for(var i = 0, len = records.length; i < len; i++){
7612 this.data.insert(index, records[i]);
7613 records[i].join(this);
7615 this.fireEvent("add", this, records, index);
7619 * Get the index within the cache of the passed Record.
7620 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7621 * @return {Number} The index of the passed Record. Returns -1 if not found.
7623 indexOf : function(record){
7624 return this.data.indexOf(record);
7628 * Get the index within the cache of the Record with the passed id.
7629 * @param {String} id The id of the Record to find.
7630 * @return {Number} The index of the Record. Returns -1 if not found.
7632 indexOfId : function(id){
7633 return this.data.indexOfKey(id);
7637 * Get the Record with the specified id.
7638 * @param {String} id The id of the Record to find.
7639 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7641 getById : function(id){
7642 return this.data.key(id);
7646 * Get the Record at the specified index.
7647 * @param {Number} index The index of the Record to find.
7648 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7650 getAt : function(index){
7651 return this.data.itemAt(index);
7655 * Returns a range of Records between specified indices.
7656 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7657 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7658 * @return {Roo.data.Record[]} An array of Records
7660 getRange : function(start, end){
7661 return this.data.getRange(start, end);
7665 storeOptions : function(o){
7666 o = Roo.apply({}, o);
7669 this.lastOptions = o;
7673 * Loads the Record cache from the configured Proxy using the configured Reader.
7675 * If using remote paging, then the first load call must specify the <em>start</em>
7676 * and <em>limit</em> properties in the options.params property to establish the initial
7677 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7679 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7680 * and this call will return before the new data has been loaded. Perform any post-processing
7681 * in a callback function, or in a "load" event handler.</strong>
7683 * @param {Object} options An object containing properties which control loading options:<ul>
7684 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7685 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7686 * passed the following arguments:<ul>
7687 * <li>r : Roo.data.Record[]</li>
7688 * <li>options: Options object from the load call</li>
7689 * <li>success: Boolean success indicator</li></ul></li>
7690 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7691 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7694 load : function(options){
7695 options = options || {};
7696 if(this.fireEvent("beforeload", this, options) !== false){
7697 this.storeOptions(options);
7698 var p = Roo.apply(options.params || {}, this.baseParams);
7699 // if meta was not loaded from remote source.. try requesting it.
7700 if (!this.reader.metaFromRemote) {
7703 if(this.sortInfo && this.remoteSort){
7704 var pn = this.paramNames;
7705 p[pn["sort"]] = this.sortInfo.field;
7706 p[pn["dir"]] = this.sortInfo.direction;
7708 if (this.multiSort) {
7709 var pn = this.paramNames;
7710 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7713 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7718 * Reloads the Record cache from the configured Proxy using the configured Reader and
7719 * the options from the last load operation performed.
7720 * @param {Object} options (optional) An object containing properties which may override the options
7721 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7722 * the most recently used options are reused).
7724 reload : function(options){
7725 this.load(Roo.applyIf(options||{}, this.lastOptions));
7729 // Called as a callback by the Reader during a load operation.
7730 loadRecords : function(o, options, success){
7731 if(!o || success === false){
7732 if(success !== false){
7733 this.fireEvent("load", this, [], options, o);
7735 if(options.callback){
7736 options.callback.call(options.scope || this, [], options, false);
7740 // if data returned failure - throw an exception.
7741 if (o.success === false) {
7742 // show a message if no listener is registered.
7743 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7744 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7746 // loadmask wil be hooked into this..
7747 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7750 var r = o.records, t = o.totalRecords || r.length;
7752 this.fireEvent("beforeloadadd", this, r, options, o);
7754 if(!options || options.add !== true){
7755 if(this.pruneModifiedRecords){
7758 for(var i = 0, len = r.length; i < len; i++){
7762 this.data = this.snapshot;
7763 delete this.snapshot;
7766 this.data.addAll(r);
7767 this.totalLength = t;
7769 this.fireEvent("datachanged", this);
7771 this.totalLength = Math.max(t, this.data.length+r.length);
7774 this.fireEvent("load", this, r, options, o);
7775 if(options.callback){
7776 options.callback.call(options.scope || this, r, options, true);
7782 * Loads data from a passed data block. A Reader which understands the format of the data
7783 * must have been configured in the constructor.
7784 * @param {Object} data The data block from which to read the Records. The format of the data expected
7785 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7786 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7788 loadData : function(o, append){
7789 var r = this.reader.readRecords(o);
7790 this.loadRecords(r, {add: append}, true);
7794 * Gets the number of cached records.
7796 * <em>If using paging, this may not be the total size of the dataset. If the data object
7797 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7798 * the data set size</em>
7800 getCount : function(){
7801 return this.data.length || 0;
7805 * Gets the total number of records in the dataset as returned by the server.
7807 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7808 * the dataset size</em>
7810 getTotalCount : function(){
7811 return this.totalLength || 0;
7815 * Returns the sort state of the Store as an object with two properties:
7817 field {String} The name of the field by which the Records are sorted
7818 direction {String} The sort order, "ASC" or "DESC"
7821 getSortState : function(){
7822 return this.sortInfo;
7826 applySort : function(){
7827 if(this.sortInfo && !this.remoteSort){
7828 var s = this.sortInfo, f = s.field;
7829 var st = this.fields.get(f).sortType;
7830 var fn = function(r1, r2){
7831 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7832 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7834 this.data.sort(s.direction, fn);
7835 if(this.snapshot && this.snapshot != this.data){
7836 this.snapshot.sort(s.direction, fn);
7842 * Sets the default sort column and order to be used by the next load operation.
7843 * @param {String} fieldName The name of the field to sort by.
7844 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7846 setDefaultSort : function(field, dir){
7847 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7852 * If remote sorting is used, the sort is performed on the server, and the cache is
7853 * reloaded. If local sorting is used, the cache is sorted internally.
7854 * @param {String} fieldName The name of the field to sort by.
7855 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7857 sort : function(fieldName, dir){
7858 var f = this.fields.get(fieldName);
7860 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7862 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7863 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7868 this.sortToggle[f.name] = dir;
7869 this.sortInfo = {field: f.name, direction: dir};
7870 if(!this.remoteSort){
7872 this.fireEvent("datachanged", this);
7874 this.load(this.lastOptions);
7879 * Calls the specified function for each of the Records in the cache.
7880 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7881 * Returning <em>false</em> aborts and exits the iteration.
7882 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7884 each : function(fn, scope){
7885 this.data.each(fn, scope);
7889 * Gets all records modified since the last commit. Modified records are persisted across load operations
7890 * (e.g., during paging).
7891 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7893 getModifiedRecords : function(){
7894 return this.modified;
7898 createFilterFn : function(property, value, anyMatch){
7899 if(!value.exec){ // not a regex
7900 value = String(value);
7901 if(value.length == 0){
7904 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7907 return value.test(r.data[property]);
7912 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7913 * @param {String} property A field on your records
7914 * @param {Number} start The record index to start at (defaults to 0)
7915 * @param {Number} end The last record index to include (defaults to length - 1)
7916 * @return {Number} The sum
7918 sum : function(property, start, end){
7919 var rs = this.data.items, v = 0;
7921 end = (end || end === 0) ? end : rs.length-1;
7923 for(var i = start; i <= end; i++){
7924 v += (rs[i].data[property] || 0);
7930 * Filter the records by a specified property.
7931 * @param {String} field A field on your records
7932 * @param {String/RegExp} value Either a string that the field
7933 * should start with or a RegExp to test against the field
7934 * @param {Boolean} anyMatch True to match any part not just the beginning
7936 filter : function(property, value, anyMatch){
7937 var fn = this.createFilterFn(property, value, anyMatch);
7938 return fn ? this.filterBy(fn) : this.clearFilter();
7942 * Filter by a function. The specified function will be called with each
7943 * record in this data source. If the function returns true the record is included,
7944 * otherwise it is filtered.
7945 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7946 * @param {Object} scope (optional) The scope of the function (defaults to this)
7948 filterBy : function(fn, scope){
7949 this.snapshot = this.snapshot || this.data;
7950 this.data = this.queryBy(fn, scope||this);
7951 this.fireEvent("datachanged", this);
7955 * Query the records by a specified property.
7956 * @param {String} field A field on your records
7957 * @param {String/RegExp} value Either a string that the field
7958 * should start with or a RegExp to test against the field
7959 * @param {Boolean} anyMatch True to match any part not just the beginning
7960 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7962 query : function(property, value, anyMatch){
7963 var fn = this.createFilterFn(property, value, anyMatch);
7964 return fn ? this.queryBy(fn) : this.data.clone();
7968 * Query by a function. The specified function will be called with each
7969 * record in this data source. If the function returns true the record is included
7971 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7972 * @param {Object} scope (optional) The scope of the function (defaults to this)
7973 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7975 queryBy : function(fn, scope){
7976 var data = this.snapshot || this.data;
7977 return data.filterBy(fn, scope||this);
7981 * Collects unique values for a particular dataIndex from this store.
7982 * @param {String} dataIndex The property to collect
7983 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7984 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7985 * @return {Array} An array of the unique values
7987 collect : function(dataIndex, allowNull, bypassFilter){
7988 var d = (bypassFilter === true && this.snapshot) ?
7989 this.snapshot.items : this.data.items;
7990 var v, sv, r = [], l = {};
7991 for(var i = 0, len = d.length; i < len; i++){
7992 v = d[i].data[dataIndex];
7994 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8003 * Revert to a view of the Record cache with no filtering applied.
8004 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8006 clearFilter : function(suppressEvent){
8007 if(this.snapshot && this.snapshot != this.data){
8008 this.data = this.snapshot;
8009 delete this.snapshot;
8010 if(suppressEvent !== true){
8011 this.fireEvent("datachanged", this);
8017 afterEdit : function(record){
8018 if(this.modified.indexOf(record) == -1){
8019 this.modified.push(record);
8021 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8025 afterReject : function(record){
8026 this.modified.remove(record);
8027 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8031 afterCommit : function(record){
8032 this.modified.remove(record);
8033 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8037 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8038 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8040 commitChanges : function(){
8041 var m = this.modified.slice(0);
8043 for(var i = 0, len = m.length; i < len; i++){
8049 * Cancel outstanding changes on all changed records.
8051 rejectChanges : function(){
8052 var m = this.modified.slice(0);
8054 for(var i = 0, len = m.length; i < len; i++){
8059 onMetaChange : function(meta, rtype, o){
8060 this.recordType = rtype;
8061 this.fields = rtype.prototype.fields;
8062 delete this.snapshot;
8063 this.sortInfo = meta.sortInfo || this.sortInfo;
8065 this.fireEvent('metachange', this, this.reader.meta);
8068 moveIndex : function(data, type)
8070 var index = this.indexOf(data);
8072 var newIndex = index + type;
8076 this.insert(newIndex, data);
8081 * Ext JS Library 1.1.1
8082 * Copyright(c) 2006-2007, Ext JS, LLC.
8084 * Originally Released Under LGPL - original licence link has changed is not relivant.
8087 * <script type="text/javascript">
8091 * @class Roo.data.SimpleStore
8092 * @extends Roo.data.Store
8093 * Small helper class to make creating Stores from Array data easier.
8094 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8095 * @cfg {Array} fields An array of field definition objects, or field name strings.
8096 * @cfg {Array} data The multi-dimensional array of data
8098 * @param {Object} config
8100 Roo.data.SimpleStore = function(config){
8101 Roo.data.SimpleStore.superclass.constructor.call(this, {
8103 reader: new Roo.data.ArrayReader({
8106 Roo.data.Record.create(config.fields)
8108 proxy : new Roo.data.MemoryProxy(config.data)
8112 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8114 * Ext JS Library 1.1.1
8115 * Copyright(c) 2006-2007, Ext JS, LLC.
8117 * Originally Released Under LGPL - original licence link has changed is not relivant.
8120 * <script type="text/javascript">
8125 * @extends Roo.data.Store
8126 * @class Roo.data.JsonStore
8127 * Small helper class to make creating Stores for JSON data easier. <br/>
8129 var store = new Roo.data.JsonStore({
8130 url: 'get-images.php',
8132 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8135 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8136 * JsonReader and HttpProxy (unless inline data is provided).</b>
8137 * @cfg {Array} fields An array of field definition objects, or field name strings.
8139 * @param {Object} config
8141 Roo.data.JsonStore = function(c){
8142 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8143 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8144 reader: new Roo.data.JsonReader(c, c.fields)
8147 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8149 * Ext JS Library 1.1.1
8150 * Copyright(c) 2006-2007, Ext JS, LLC.
8152 * Originally Released Under LGPL - original licence link has changed is not relivant.
8155 * <script type="text/javascript">
8159 Roo.data.Field = function(config){
8160 if(typeof config == "string"){
8161 config = {name: config};
8163 Roo.apply(this, config);
8169 var st = Roo.data.SortTypes;
8170 // named sortTypes are supported, here we look them up
8171 if(typeof this.sortType == "string"){
8172 this.sortType = st[this.sortType];
8175 // set default sortType for strings and dates
8179 this.sortType = st.asUCString;
8182 this.sortType = st.asDate;
8185 this.sortType = st.none;
8190 var stripRe = /[\$,%]/g;
8192 // prebuilt conversion function for this field, instead of
8193 // switching every time we're reading a value
8195 var cv, dateFormat = this.dateFormat;
8200 cv = function(v){ return v; };
8203 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8207 return v !== undefined && v !== null && v !== '' ?
8208 parseInt(String(v).replace(stripRe, ""), 10) : '';
8213 return v !== undefined && v !== null && v !== '' ?
8214 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8219 cv = function(v){ return v === true || v === "true" || v == 1; };
8226 if(v instanceof Date){
8230 if(dateFormat == "timestamp"){
8231 return new Date(v*1000);
8233 return Date.parseDate(v, dateFormat);
8235 var parsed = Date.parse(v);
8236 return parsed ? new Date(parsed) : null;
8245 Roo.data.Field.prototype = {
8253 * Ext JS Library 1.1.1
8254 * Copyright(c) 2006-2007, Ext JS, LLC.
8256 * Originally Released Under LGPL - original licence link has changed is not relivant.
8259 * <script type="text/javascript">
8262 // Base class for reading structured data from a data source. This class is intended to be
8263 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8266 * @class Roo.data.DataReader
8267 * Base class for reading structured data from a data source. This class is intended to be
8268 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8271 Roo.data.DataReader = function(meta, recordType){
8275 this.recordType = recordType instanceof Array ?
8276 Roo.data.Record.create(recordType) : recordType;
8279 Roo.data.DataReader.prototype = {
8281 * Create an empty record
8282 * @param {Object} data (optional) - overlay some values
8283 * @return {Roo.data.Record} record created.
8285 newRow : function(d) {
8287 this.recordType.prototype.fields.each(function(c) {
8289 case 'int' : da[c.name] = 0; break;
8290 case 'date' : da[c.name] = new Date(); break;
8291 case 'float' : da[c.name] = 0.0; break;
8292 case 'boolean' : da[c.name] = false; break;
8293 default : da[c.name] = ""; break;
8297 return new this.recordType(Roo.apply(da, d));
8302 * Ext JS Library 1.1.1
8303 * Copyright(c) 2006-2007, Ext JS, LLC.
8305 * Originally Released Under LGPL - original licence link has changed is not relivant.
8308 * <script type="text/javascript">
8312 * @class Roo.data.DataProxy
8313 * @extends Roo.data.Observable
8314 * This class is an abstract base class for implementations which provide retrieval of
8315 * unformatted data objects.<br>
8317 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8318 * (of the appropriate type which knows how to parse the data object) to provide a block of
8319 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8321 * Custom implementations must implement the load method as described in
8322 * {@link Roo.data.HttpProxy#load}.
8324 Roo.data.DataProxy = function(){
8328 * Fires before a network request is made to retrieve a data object.
8329 * @param {Object} This DataProxy object.
8330 * @param {Object} params The params parameter to the load function.
8335 * Fires before the load method's callback is called.
8336 * @param {Object} This DataProxy object.
8337 * @param {Object} o The data object.
8338 * @param {Object} arg The callback argument object passed to the load function.
8342 * @event loadexception
8343 * Fires if an Exception occurs during data retrieval.
8344 * @param {Object} This DataProxy object.
8345 * @param {Object} o The data object.
8346 * @param {Object} arg The callback argument object passed to the load function.
8347 * @param {Object} e The Exception.
8349 loadexception : true
8351 Roo.data.DataProxy.superclass.constructor.call(this);
8354 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8357 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8361 * Ext JS Library 1.1.1
8362 * Copyright(c) 2006-2007, Ext JS, LLC.
8364 * Originally Released Under LGPL - original licence link has changed is not relivant.
8367 * <script type="text/javascript">
8370 * @class Roo.data.MemoryProxy
8371 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8372 * to the Reader when its load method is called.
8374 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8376 Roo.data.MemoryProxy = function(data){
8380 Roo.data.MemoryProxy.superclass.constructor.call(this);
8384 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8386 * Load data from the requested source (in this case an in-memory
8387 * data object passed to the constructor), read the data object into
8388 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8389 * process that block using the passed callback.
8390 * @param {Object} params This parameter is not used by the MemoryProxy class.
8391 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8392 * object into a block of Roo.data.Records.
8393 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8394 * The function must be passed <ul>
8395 * <li>The Record block object</li>
8396 * <li>The "arg" argument from the load function</li>
8397 * <li>A boolean success indicator</li>
8399 * @param {Object} scope The scope in which to call the callback
8400 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8402 load : function(params, reader, callback, scope, arg){
8403 params = params || {};
8406 result = reader.readRecords(this.data);
8408 this.fireEvent("loadexception", this, arg, null, e);
8409 callback.call(scope, null, arg, false);
8412 callback.call(scope, result, arg, true);
8416 update : function(params, records){
8421 * Ext JS Library 1.1.1
8422 * Copyright(c) 2006-2007, Ext JS, LLC.
8424 * Originally Released Under LGPL - original licence link has changed is not relivant.
8427 * <script type="text/javascript">
8430 * @class Roo.data.HttpProxy
8431 * @extends Roo.data.DataProxy
8432 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8433 * configured to reference a certain URL.<br><br>
8435 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8436 * from which the running page was served.<br><br>
8438 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8440 * Be aware that to enable the browser to parse an XML document, the server must set
8441 * the Content-Type header in the HTTP response to "text/xml".
8443 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8444 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8445 * will be used to make the request.
8447 Roo.data.HttpProxy = function(conn){
8448 Roo.data.HttpProxy.superclass.constructor.call(this);
8449 // is conn a conn config or a real conn?
8451 this.useAjax = !conn || !conn.events;
8455 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8456 // thse are take from connection...
8459 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8462 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8463 * extra parameters to each request made by this object. (defaults to undefined)
8466 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8467 * to each request made by this object. (defaults to undefined)
8470 * @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)
8473 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8476 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8482 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8486 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8487 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8488 * a finer-grained basis than the DataProxy events.
8490 getConnection : function(){
8491 return this.useAjax ? Roo.Ajax : this.conn;
8495 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8496 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8497 * process that block using the passed callback.
8498 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8499 * for the request to the remote server.
8500 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8501 * object into a block of Roo.data.Records.
8502 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8503 * The function must be passed <ul>
8504 * <li>The Record block object</li>
8505 * <li>The "arg" argument from the load function</li>
8506 * <li>A boolean success indicator</li>
8508 * @param {Object} scope The scope in which to call the callback
8509 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8511 load : function(params, reader, callback, scope, arg){
8512 if(this.fireEvent("beforeload", this, params) !== false){
8514 params : params || {},
8516 callback : callback,
8521 callback : this.loadResponse,
8525 Roo.applyIf(o, this.conn);
8526 if(this.activeRequest){
8527 Roo.Ajax.abort(this.activeRequest);
8529 this.activeRequest = Roo.Ajax.request(o);
8531 this.conn.request(o);
8534 callback.call(scope||this, null, arg, false);
8539 loadResponse : function(o, success, response){
8540 delete this.activeRequest;
8542 this.fireEvent("loadexception", this, o, response);
8543 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8548 result = o.reader.read(response);
8550 this.fireEvent("loadexception", this, o, response, e);
8551 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8555 this.fireEvent("load", this, o, o.request.arg);
8556 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8560 update : function(dataSet){
8565 updateResponse : function(dataSet){
8570 * Ext JS Library 1.1.1
8571 * Copyright(c) 2006-2007, Ext JS, LLC.
8573 * Originally Released Under LGPL - original licence link has changed is not relivant.
8576 * <script type="text/javascript">
8580 * @class Roo.data.ScriptTagProxy
8581 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8582 * other than the originating domain of the running page.<br><br>
8584 * <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
8585 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8587 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8588 * source code that is used as the source inside a <script> tag.<br><br>
8590 * In order for the browser to process the returned data, the server must wrap the data object
8591 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8592 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8593 * depending on whether the callback name was passed:
8596 boolean scriptTag = false;
8597 String cb = request.getParameter("callback");
8600 response.setContentType("text/javascript");
8602 response.setContentType("application/x-json");
8604 Writer out = response.getWriter();
8606 out.write(cb + "(");
8608 out.print(dataBlock.toJsonString());
8615 * @param {Object} config A configuration object.
8617 Roo.data.ScriptTagProxy = function(config){
8618 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8619 Roo.apply(this, config);
8620 this.head = document.getElementsByTagName("head")[0];
8623 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8625 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8627 * @cfg {String} url The URL from which to request the data object.
8630 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8634 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8635 * the server the name of the callback function set up by the load call to process the returned data object.
8636 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8637 * javascript output which calls this named function passing the data object as its only parameter.
8639 callbackParam : "callback",
8641 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8642 * name to the request.
8647 * Load data from the configured URL, read the data object into
8648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8649 * process that block using the passed callback.
8650 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8651 * for the request to the remote server.
8652 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8653 * object into a block of Roo.data.Records.
8654 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8655 * The function must be passed <ul>
8656 * <li>The Record block object</li>
8657 * <li>The "arg" argument from the load function</li>
8658 * <li>A boolean success indicator</li>
8660 * @param {Object} scope The scope in which to call the callback
8661 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8663 load : function(params, reader, callback, scope, arg){
8664 if(this.fireEvent("beforeload", this, params) !== false){
8666 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8669 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8671 url += "&_dc=" + (new Date().getTime());
8673 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8676 cb : "stcCallback"+transId,
8677 scriptId : "stcScript"+transId,
8681 callback : callback,
8687 window[trans.cb] = function(o){
8688 conn.handleResponse(o, trans);
8691 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8693 if(this.autoAbort !== false){
8697 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8699 var script = document.createElement("script");
8700 script.setAttribute("src", url);
8701 script.setAttribute("type", "text/javascript");
8702 script.setAttribute("id", trans.scriptId);
8703 this.head.appendChild(script);
8707 callback.call(scope||this, null, arg, false);
8712 isLoading : function(){
8713 return this.trans ? true : false;
8717 * Abort the current server request.
8720 if(this.isLoading()){
8721 this.destroyTrans(this.trans);
8726 destroyTrans : function(trans, isLoaded){
8727 this.head.removeChild(document.getElementById(trans.scriptId));
8728 clearTimeout(trans.timeoutId);
8730 window[trans.cb] = undefined;
8732 delete window[trans.cb];
8735 // if hasn't been loaded, wait for load to remove it to prevent script error
8736 window[trans.cb] = function(){
8737 window[trans.cb] = undefined;
8739 delete window[trans.cb];
8746 handleResponse : function(o, trans){
8748 this.destroyTrans(trans, true);
8751 result = trans.reader.readRecords(o);
8753 this.fireEvent("loadexception", this, o, trans.arg, e);
8754 trans.callback.call(trans.scope||window, null, trans.arg, false);
8757 this.fireEvent("load", this, o, trans.arg);
8758 trans.callback.call(trans.scope||window, result, trans.arg, true);
8762 handleFailure : function(trans){
8764 this.destroyTrans(trans, false);
8765 this.fireEvent("loadexception", this, null, trans.arg);
8766 trans.callback.call(trans.scope||window, null, trans.arg, false);
8770 * Ext JS Library 1.1.1
8771 * Copyright(c) 2006-2007, Ext JS, LLC.
8773 * Originally Released Under LGPL - original licence link has changed is not relivant.
8776 * <script type="text/javascript">
8780 * @class Roo.data.JsonReader
8781 * @extends Roo.data.DataReader
8782 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8783 * based on mappings in a provided Roo.data.Record constructor.
8785 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8786 * in the reply previously.
8791 var RecordDef = Roo.data.Record.create([
8792 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8793 {name: 'occupation'} // This field will use "occupation" as the mapping.
8795 var myReader = new Roo.data.JsonReader({
8796 totalProperty: "results", // The property which contains the total dataset size (optional)
8797 root: "rows", // The property which contains an Array of row objects
8798 id: "id" // The property within each row object that provides an ID for the record (optional)
8802 * This would consume a JSON file like this:
8804 { 'results': 2, 'rows': [
8805 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8806 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8809 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8810 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8811 * paged from the remote server.
8812 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8813 * @cfg {String} root name of the property which contains the Array of row objects.
8814 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8816 * Create a new JsonReader
8817 * @param {Object} meta Metadata configuration options
8818 * @param {Object} recordType Either an Array of field definition objects,
8819 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8821 Roo.data.JsonReader = function(meta, recordType){
8824 // set some defaults:
8826 totalProperty: 'total',
8827 successProperty : 'success',
8832 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8834 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8837 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8838 * Used by Store query builder to append _requestMeta to params.
8841 metaFromRemote : false,
8843 * This method is only used by a DataProxy which has retrieved data from a remote server.
8844 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8845 * @return {Object} data A data block which is used by an Roo.data.Store object as
8846 * a cache of Roo.data.Records.
8848 read : function(response){
8849 var json = response.responseText;
8851 var o = /* eval:var:o */ eval("("+json+")");
8853 throw {message: "JsonReader.read: Json object not found"};
8859 this.metaFromRemote = true;
8860 this.meta = o.metaData;
8861 this.recordType = Roo.data.Record.create(o.metaData.fields);
8862 this.onMetaChange(this.meta, this.recordType, o);
8864 return this.readRecords(o);
8867 // private function a store will implement
8868 onMetaChange : function(meta, recordType, o){
8875 simpleAccess: function(obj, subsc) {
8882 getJsonAccessor: function(){
8884 return function(expr) {
8886 return(re.test(expr))
8887 ? new Function("obj", "return obj." + expr)
8897 * Create a data block containing Roo.data.Records from an XML document.
8898 * @param {Object} o An object which contains an Array of row objects in the property specified
8899 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8900 * which contains the total size of the dataset.
8901 * @return {Object} data A data block which is used by an Roo.data.Store object as
8902 * a cache of Roo.data.Records.
8904 readRecords : function(o){
8906 * After any data loads, the raw JSON data is available for further custom processing.
8910 var s = this.meta, Record = this.recordType,
8911 f = Record.prototype.fields, fi = f.items, fl = f.length;
8913 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8915 if(s.totalProperty) {
8916 this.getTotal = this.getJsonAccessor(s.totalProperty);
8918 if(s.successProperty) {
8919 this.getSuccess = this.getJsonAccessor(s.successProperty);
8921 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8923 var g = this.getJsonAccessor(s.id);
8924 this.getId = function(rec) {
8926 return (r === undefined || r === "") ? null : r;
8929 this.getId = function(){return null;};
8932 for(var jj = 0; jj < fl; jj++){
8934 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8935 this.ef[jj] = this.getJsonAccessor(map);
8939 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8940 if(s.totalProperty){
8941 var vt = parseInt(this.getTotal(o), 10);
8946 if(s.successProperty){
8947 var vs = this.getSuccess(o);
8948 if(vs === false || vs === 'false'){
8953 for(var i = 0; i < c; i++){
8956 var id = this.getId(n);
8957 for(var j = 0; j < fl; j++){
8959 var v = this.ef[j](n);
8961 Roo.log('missing convert for ' + f.name);
8965 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8967 var record = new Record(values, id);
8969 records[i] = record;
8975 totalRecords : totalRecords
8980 * Ext JS Library 1.1.1
8981 * Copyright(c) 2006-2007, Ext JS, LLC.
8983 * Originally Released Under LGPL - original licence link has changed is not relivant.
8986 * <script type="text/javascript">
8990 * @class Roo.data.ArrayReader
8991 * @extends Roo.data.DataReader
8992 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8993 * Each element of that Array represents a row of data fields. The
8994 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8995 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8999 var RecordDef = Roo.data.Record.create([
9000 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9001 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9003 var myReader = new Roo.data.ArrayReader({
9004 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9008 * This would consume an Array like this:
9010 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9012 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9014 * Create a new JsonReader
9015 * @param {Object} meta Metadata configuration options.
9016 * @param {Object} recordType Either an Array of field definition objects
9017 * as specified to {@link Roo.data.Record#create},
9018 * or an {@link Roo.data.Record} object
9019 * created using {@link Roo.data.Record#create}.
9021 Roo.data.ArrayReader = function(meta, recordType){
9022 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9025 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9027 * Create a data block containing Roo.data.Records from an XML document.
9028 * @param {Object} o An Array of row objects which represents the dataset.
9029 * @return {Object} data A data block which is used by an Roo.data.Store object as
9030 * a cache of Roo.data.Records.
9032 readRecords : function(o){
9033 var sid = this.meta ? this.meta.id : null;
9034 var recordType = this.recordType, fields = recordType.prototype.fields;
9037 for(var i = 0; i < root.length; i++){
9040 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9041 for(var j = 0, jlen = fields.length; j < jlen; j++){
9042 var f = fields.items[j];
9043 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9044 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9048 var record = new recordType(values, id);
9050 records[records.length] = record;
9054 totalRecords : records.length
9063 * @class Roo.bootstrap.ComboBox
9064 * @extends Roo.bootstrap.TriggerField
9065 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9066 * @cfg {Boolean} append (true|false) default false
9068 * Create a new ComboBox.
9069 * @param {Object} config Configuration options
9071 Roo.bootstrap.ComboBox = function(config){
9072 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9076 * Fires when the dropdown list is expanded
9077 * @param {Roo.bootstrap.ComboBox} combo This combo box
9082 * Fires when the dropdown list is collapsed
9083 * @param {Roo.bootstrap.ComboBox} combo This combo box
9087 * @event beforeselect
9088 * Fires before a list item is selected. Return false to cancel the selection.
9089 * @param {Roo.bootstrap.ComboBox} combo This combo box
9090 * @param {Roo.data.Record} record The data record returned from the underlying store
9091 * @param {Number} index The index of the selected item in the dropdown list
9093 'beforeselect' : true,
9096 * Fires when a list item is selected
9097 * @param {Roo.bootstrap.ComboBox} combo This combo box
9098 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9099 * @param {Number} index The index of the selected item in the dropdown list
9103 * @event beforequery
9104 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9105 * The event object passed has these properties:
9106 * @param {Roo.bootstrap.ComboBox} combo This combo box
9107 * @param {String} query The query
9108 * @param {Boolean} forceAll true to force "all" query
9109 * @param {Boolean} cancel true to cancel the query
9110 * @param {Object} e The query event object
9112 'beforequery': true,
9115 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9116 * @param {Roo.bootstrap.ComboBox} combo This combo box
9121 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9122 * @param {Roo.bootstrap.ComboBox} combo This combo box
9123 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9128 * Fires when the remove value from the combobox array
9129 * @param {Roo.bootstrap.ComboBox} combo This combo box
9136 this.selectedIndex = -1;
9137 if(this.mode == 'local'){
9138 if(config.queryDelay === undefined){
9139 this.queryDelay = 10;
9141 if(config.minChars === undefined){
9147 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9150 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9151 * rendering into an Roo.Editor, defaults to false)
9154 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9155 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9158 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9161 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9162 * the dropdown list (defaults to undefined, with no header element)
9166 * @cfg {String/Roo.Template} tpl The template to use to render the output
9170 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9172 listWidth: undefined,
9174 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9175 * mode = 'remote' or 'text' if mode = 'local')
9177 displayField: undefined,
9179 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9180 * mode = 'remote' or 'value' if mode = 'local').
9181 * Note: use of a valueField requires the user make a selection
9182 * in order for a value to be mapped.
9184 valueField: undefined,
9188 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9189 * field's data value (defaults to the underlying DOM element's name)
9191 hiddenName: undefined,
9193 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9197 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9199 selectedClass: 'active',
9202 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9206 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9207 * anchor positions (defaults to 'tl-bl')
9209 listAlign: 'tl-bl?',
9211 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9215 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9216 * query specified by the allQuery config option (defaults to 'query')
9218 triggerAction: 'query',
9220 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9221 * (defaults to 4, does not apply if editable = false)
9225 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9226 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9230 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9231 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9235 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9236 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9240 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9241 * when editable = true (defaults to false)
9243 selectOnFocus:false,
9245 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9247 queryParam: 'query',
9249 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9250 * when mode = 'remote' (defaults to 'Loading...')
9252 loadingText: 'Loading...',
9254 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9258 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9262 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9263 * traditional select (defaults to true)
9267 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9271 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9275 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9276 * listWidth has a higher value)
9280 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9281 * allow the user to set arbitrary text into the field (defaults to false)
9283 forceSelection:false,
9285 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9286 * if typeAhead = true (defaults to 250)
9288 typeAheadDelay : 250,
9290 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9291 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9293 valueNotFoundText : undefined,
9295 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9300 * @cfg {Boolean} disableClear Disable showing of clear button.
9302 disableClear : false,
9304 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9306 alwaysQuery : false,
9309 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9323 // element that contains real text value.. (when hidden is used..)
9326 initEvents: function(){
9329 throw "can not find store for combo";
9331 this.store = Roo.factory(this.store, Roo.data);
9335 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9338 if(this.hiddenName){
9340 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9342 this.hiddenField.dom.value =
9343 this.hiddenValue !== undefined ? this.hiddenValue :
9344 this.value !== undefined ? this.value : '';
9346 // prevent input submission
9347 this.el.dom.removeAttribute('name');
9348 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9353 // this.el.dom.setAttribute('autocomplete', 'off');
9356 var cls = 'x-combo-list';
9357 this.list = this.el.select('ul.dropdown-menu',true).first();
9359 //this.list = new Roo.Layer({
9360 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9363 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9364 this.list.setWidth(lw);
9366 this.list.on('mouseover', this.onViewOver, this);
9367 this.list.on('mousemove', this.onViewMove, this);
9369 this.list.on('scroll', this.onViewScroll, this);
9372 this.list.swallowEvent('mousewheel');
9373 this.assetHeight = 0;
9376 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9377 this.assetHeight += this.header.getHeight();
9380 this.innerList = this.list.createChild({cls:cls+'-inner'});
9381 this.innerList.on('mouseover', this.onViewOver, this);
9382 this.innerList.on('mousemove', this.onViewMove, this);
9383 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9385 if(this.allowBlank && !this.pageSize && !this.disableClear){
9386 this.footer = this.list.createChild({cls:cls+'-ft'});
9387 this.pageTb = new Roo.Toolbar(this.footer);
9391 this.footer = this.list.createChild({cls:cls+'-ft'});
9392 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9393 {pageSize: this.pageSize});
9397 if (this.pageTb && this.allowBlank && !this.disableClear) {
9399 this.pageTb.add(new Roo.Toolbar.Fill(), {
9400 cls: 'x-btn-icon x-btn-clear',
9406 _this.onSelect(false, -1);
9411 this.assetHeight += this.footer.getHeight();
9416 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9419 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9420 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9422 //this.view.wrapEl.setDisplayed(false);
9423 this.view.on('click', this.onViewClick, this);
9427 this.store.on('beforeload', this.onBeforeLoad, this);
9428 this.store.on('load', this.onLoad, this);
9429 this.store.on('loadexception', this.onLoadException, this);
9432 this.resizer = new Roo.Resizable(this.list, {
9433 pinned:true, handles:'se'
9435 this.resizer.on('resize', function(r, w, h){
9436 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9438 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9439 this.restrictHeight();
9441 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9445 this.editable = true;
9446 this.setEditable(false);
9451 if (typeof(this.events.add.listeners) != 'undefined') {
9453 this.addicon = this.wrap.createChild(
9454 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9456 this.addicon.on('click', function(e) {
9457 this.fireEvent('add', this);
9460 if (typeof(this.events.edit.listeners) != 'undefined') {
9462 this.editicon = this.wrap.createChild(
9463 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9465 this.editicon.setStyle('margin-left', '40px');
9467 this.editicon.on('click', function(e) {
9469 // we fire even if inothing is selected..
9470 this.fireEvent('edit', this, this.lastData );
9476 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9478 this.inKeyMode = true;
9482 "down" : function(e){
9483 if(!this.isExpanded()){
9484 this.onTriggerClick();
9486 this.inKeyMode = true;
9491 "enter" : function(e){
9496 "esc" : function(e){
9500 "tab" : function(e){
9503 if(this.fireEvent("specialkey", this, e)){
9504 this.onViewClick(false);
9512 doRelay : function(foo, bar, hname){
9513 if(hname == 'down' || this.scope.isExpanded()){
9514 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9523 this.queryDelay = Math.max(this.queryDelay || 10,
9524 this.mode == 'local' ? 10 : 250);
9527 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9530 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9532 if(this.editable !== false){
9533 this.inputEl().on("keyup", this.onKeyUp, this);
9535 if(this.forceSelection){
9536 this.inputEl().on('blur', this.doForce, this);
9540 this.choices = this.el.select('ul.select2-choices', true).first();
9541 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9545 onDestroy : function(){
9547 this.view.setStore(null);
9548 this.view.el.removeAllListeners();
9549 this.view.el.remove();
9550 this.view.purgeListeners();
9553 this.list.dom.innerHTML = '';
9556 this.store.un('beforeload', this.onBeforeLoad, this);
9557 this.store.un('load', this.onLoad, this);
9558 this.store.un('loadexception', this.onLoadException, this);
9560 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9564 fireKey : function(e){
9565 if(e.isNavKeyPress() && !this.list.isVisible()){
9566 this.fireEvent("specialkey", this, e);
9571 onResize: function(w, h){
9572 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9574 // if(typeof w != 'number'){
9575 // // we do not handle it!?!?
9578 // var tw = this.trigger.getWidth();
9579 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9580 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9582 // this.inputEl().setWidth( this.adjustWidth('input', x));
9584 // //this.trigger.setStyle('left', x+'px');
9586 // if(this.list && this.listWidth === undefined){
9587 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9588 // this.list.setWidth(lw);
9589 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9597 * Allow or prevent the user from directly editing the field text. If false is passed,
9598 * the user will only be able to select from the items defined in the dropdown list. This method
9599 * is the runtime equivalent of setting the 'editable' config option at config time.
9600 * @param {Boolean} value True to allow the user to directly edit the field text
9602 setEditable : function(value){
9603 if(value == this.editable){
9606 this.editable = value;
9608 this.inputEl().dom.setAttribute('readOnly', true);
9609 this.inputEl().on('mousedown', this.onTriggerClick, this);
9610 this.inputEl().addClass('x-combo-noedit');
9612 this.inputEl().dom.setAttribute('readOnly', false);
9613 this.inputEl().un('mousedown', this.onTriggerClick, this);
9614 this.inputEl().removeClass('x-combo-noedit');
9620 onBeforeLoad : function(combo,opts){
9625 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9627 this.restrictHeight();
9628 this.selectedIndex = -1;
9632 onLoad : function(){
9634 this.hasQuery = false;
9640 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9641 this.loading.hide();
9644 if(this.store.getCount() > 0){
9646 this.restrictHeight();
9647 if(this.lastQuery == this.allQuery){
9649 this.inputEl().dom.select();
9651 if(!this.selectByValue(this.value, true)){
9652 this.select(0, true);
9656 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9657 this.taTask.delay(this.typeAheadDelay);
9661 this.onEmptyResults();
9667 onLoadException : function()
9669 this.hasQuery = false;
9671 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9672 this.loading.hide();
9676 Roo.log(this.store.reader.jsonData);
9677 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9679 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9685 onTypeAhead : function(){
9686 if(this.store.getCount() > 0){
9687 var r = this.store.getAt(0);
9688 var newValue = r.data[this.displayField];
9689 var len = newValue.length;
9690 var selStart = this.getRawValue().length;
9692 if(selStart != len){
9693 this.setRawValue(newValue);
9694 this.selectText(selStart, newValue.length);
9700 onSelect : function(record, index){
9702 if(this.fireEvent('beforeselect', this, record, index) !== false){
9704 this.setFromData(index > -1 ? record.data : false);
9707 this.fireEvent('select', this, record, index);
9712 * Returns the currently selected field value or empty string if no value is set.
9713 * @return {String} value The selected value
9715 getValue : function(){
9718 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9721 if(this.valueField){
9722 return typeof this.value != 'undefined' ? this.value : '';
9724 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9729 * Clears any text/value currently set in the field
9731 clearValue : function(){
9732 if(this.hiddenField){
9733 this.hiddenField.dom.value = '';
9736 this.setRawValue('');
9737 this.lastSelectionText = '';
9742 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9743 * will be displayed in the field. If the value does not match the data value of an existing item,
9744 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9745 * Otherwise the field will be blank (although the value will still be set).
9746 * @param {String} value The value to match
9748 setValue : function(v){
9755 if(this.valueField){
9756 var r = this.findRecord(this.valueField, v);
9758 text = r.data[this.displayField];
9759 }else if(this.valueNotFoundText !== undefined){
9760 text = this.valueNotFoundText;
9763 this.lastSelectionText = text;
9764 if(this.hiddenField){
9765 this.hiddenField.dom.value = v;
9767 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9771 * @property {Object} the last set data for the element
9776 * Sets the value of the field based on a object which is related to the record format for the store.
9777 * @param {Object} value the value to set as. or false on reset?
9779 setFromData : function(o){
9786 var dv = ''; // display value
9787 var vv = ''; // value value..
9789 if (this.displayField) {
9790 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9792 // this is an error condition!!!
9793 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9796 if(this.valueField){
9797 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9800 if(this.hiddenField){
9801 this.hiddenField.dom.value = vv;
9803 this.lastSelectionText = dv;
9804 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9808 // no hidden field.. - we store the value in 'value', but still display
9809 // display field!!!!
9810 this.lastSelectionText = dv;
9811 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9818 // overridden so that last data is reset..
9819 this.setValue(this.originalValue);
9820 this.clearInvalid();
9821 this.lastData = false;
9823 this.view.clearSelections();
9827 findRecord : function(prop, value){
9829 if(this.store.getCount() > 0){
9830 this.store.each(function(r){
9831 if(r.data[prop] == value){
9843 // returns hidden if it's set..
9844 if (!this.rendered) {return ''};
9845 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9849 onViewMove : function(e, t){
9850 this.inKeyMode = false;
9854 onViewOver : function(e, t){
9855 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9858 var item = this.view.findItemFromChild(t);
9860 var index = this.view.indexOf(item);
9861 this.select(index, false);
9866 onViewClick : function(doFocus)
9868 var index = this.view.getSelectedIndexes()[0];
9869 var r = this.store.getAt(index);
9871 this.onSelect(r, index);
9873 if(doFocus !== false && !this.blockFocus){
9874 this.inputEl().focus();
9879 restrictHeight : function(){
9880 //this.innerList.dom.style.height = '';
9881 //var inner = this.innerList.dom;
9882 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9883 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9884 //this.list.beginUpdate();
9885 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9886 this.list.alignTo(this.inputEl(), this.listAlign);
9887 //this.list.endUpdate();
9891 onEmptyResults : function(){
9896 * Returns true if the dropdown list is expanded, else false.
9898 isExpanded : function(){
9899 return this.list.isVisible();
9903 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9904 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9905 * @param {String} value The data value of the item to select
9906 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9907 * selected item if it is not currently in view (defaults to true)
9908 * @return {Boolean} True if the value matched an item in the list, else false
9910 selectByValue : function(v, scrollIntoView){
9911 if(v !== undefined && v !== null){
9912 var r = this.findRecord(this.valueField || this.displayField, v);
9914 this.select(this.store.indexOf(r), scrollIntoView);
9922 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9923 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9924 * @param {Number} index The zero-based index of the list item to select
9925 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9926 * selected item if it is not currently in view (defaults to true)
9928 select : function(index, scrollIntoView){
9929 this.selectedIndex = index;
9930 this.view.select(index);
9931 if(scrollIntoView !== false){
9932 var el = this.view.getNode(index);
9934 //this.innerList.scrollChildIntoView(el, false);
9941 selectNext : function(){
9942 var ct = this.store.getCount();
9944 if(this.selectedIndex == -1){
9946 }else if(this.selectedIndex < ct-1){
9947 this.select(this.selectedIndex+1);
9953 selectPrev : function(){
9954 var ct = this.store.getCount();
9956 if(this.selectedIndex == -1){
9958 }else if(this.selectedIndex != 0){
9959 this.select(this.selectedIndex-1);
9965 onKeyUp : function(e){
9966 if(this.editable !== false && !e.isSpecialKey()){
9967 this.lastKey = e.getKey();
9968 this.dqTask.delay(this.queryDelay);
9973 validateBlur : function(){
9974 return !this.list || !this.list.isVisible();
9978 initQuery : function(){
9979 this.doQuery(this.getRawValue());
9983 doForce : function(){
9984 if(this.inputEl().dom.value.length > 0){
9985 this.inputEl().dom.value =
9986 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9992 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9993 * query allowing the query action to be canceled if needed.
9994 * @param {String} query The SQL query to execute
9995 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9996 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9997 * saved in the current store (defaults to false)
9999 doQuery : function(q, forceAll){
10001 if(q === undefined || q === null){
10006 forceAll: forceAll,
10010 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10015 forceAll = qe.forceAll;
10016 if(forceAll === true || (q.length >= this.minChars)){
10018 this.hasQuery = true;
10020 if(this.lastQuery != q || this.alwaysQuery){
10021 this.lastQuery = q;
10022 if(this.mode == 'local'){
10023 this.selectedIndex = -1;
10025 this.store.clearFilter();
10027 this.store.filter(this.displayField, q);
10031 this.store.baseParams[this.queryParam] = q;
10033 var options = {params : this.getParams(q)};
10036 options.add = true;
10037 options.params.start = this.page * this.pageSize;
10040 this.store.load(options);
10044 this.selectedIndex = -1;
10049 this.loadNext = false;
10053 getParams : function(q){
10055 //p[this.queryParam] = q;
10059 p.limit = this.pageSize;
10065 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10067 collapse : function(){
10068 if(!this.isExpanded()){
10073 Roo.get(document).un('mousedown', this.collapseIf, this);
10074 Roo.get(document).un('mousewheel', this.collapseIf, this);
10075 if (!this.editable) {
10076 Roo.get(document).un('keydown', this.listKeyPress, this);
10078 this.fireEvent('collapse', this);
10082 collapseIf : function(e){
10083 var in_combo = e.within(this.el);
10084 var in_list = e.within(this.list);
10086 if (in_combo || in_list) {
10087 //e.stopPropagation();
10096 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10098 expand : function(){
10100 if(this.isExpanded() || !this.hasFocus){
10104 this.list.alignTo(this.inputEl(), this.listAlign);
10106 Roo.get(document).on('mousedown', this.collapseIf, this);
10107 Roo.get(document).on('mousewheel', this.collapseIf, this);
10108 if (!this.editable) {
10109 Roo.get(document).on('keydown', this.listKeyPress, this);
10112 this.fireEvent('expand', this);
10116 // Implements the default empty TriggerField.onTriggerClick function
10117 onTriggerClick : function()
10119 Roo.log('trigger click');
10126 this.loadNext = false;
10128 if(this.isExpanded()){
10130 if (!this.blockFocus) {
10131 this.inputEl().focus();
10135 this.hasFocus = true;
10136 if(this.triggerAction == 'all') {
10137 this.doQuery(this.allQuery, true);
10139 this.doQuery(this.getRawValue());
10141 if (!this.blockFocus) {
10142 this.inputEl().focus();
10146 listKeyPress : function(e)
10148 //Roo.log('listkeypress');
10149 // scroll to first matching element based on key pres..
10150 if (e.isSpecialKey()) {
10153 var k = String.fromCharCode(e.getKey()).toUpperCase();
10156 var csel = this.view.getSelectedNodes();
10157 var cselitem = false;
10159 var ix = this.view.indexOf(csel[0]);
10160 cselitem = this.store.getAt(ix);
10161 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10167 this.store.each(function(v) {
10169 // start at existing selection.
10170 if (cselitem.id == v.id) {
10176 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10177 match = this.store.indexOf(v);
10183 if (match === false) {
10184 return true; // no more action?
10187 this.view.select(match);
10188 var sn = Roo.get(this.view.getSelectedNodes()[0])
10189 //sn.scrollIntoView(sn.dom.parentNode, false);
10192 onViewScroll : function(e, t){
10194 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10198 this.hasQuery = true;
10200 this.loading = this.list.select('.loading', true).first();
10202 if(this.loading === null){
10203 this.list.createChild({
10205 cls: 'loading select2-more-results select2-active',
10206 html: 'Loading more results...'
10209 this.loading = this.list.select('.loading', true).first();
10211 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10213 this.loading.hide();
10216 this.loading.show();
10221 this.loadNext = true;
10223 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10228 addItem : function(o)
10230 var dv = ''; // display value
10232 if (this.displayField) {
10233 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10235 // this is an error condition!!!
10236 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10243 var choice = this.choices.createChild({
10245 cls: 'select2-search-choice',
10254 cls: 'select2-search-choice-close',
10259 }, this.searchField);
10261 var close = choice.select('a.select2-search-choice-close', true).first()
10263 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10270 this.inputEl().dom.value = '';
10274 onRemoveItem : function(e, _self, o)
10276 e.preventDefault();
10277 var index = this.item.indexOf(o.data) * 1;
10280 Roo.log('not this item?!');
10284 this.item.splice(index, 1);
10289 this.fireEvent('remove', this, e);
10293 syncValue : function()
10295 if(!this.item.length){
10302 Roo.each(this.item, function(i){
10303 if(_this.valueField){
10304 value.push(i[_this.valueField]);
10311 this.value = value.join(',');
10313 if(this.hiddenField){
10314 this.hiddenField.dom.value = this.value;
10318 clearItem : function()
10320 if(!this.multiple){
10326 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10336 * @cfg {Boolean} grow
10340 * @cfg {Number} growMin
10344 * @cfg {Number} growMax
10354 * Ext JS Library 1.1.1
10355 * Copyright(c) 2006-2007, Ext JS, LLC.
10357 * Originally Released Under LGPL - original licence link has changed is not relivant.
10360 * <script type="text/javascript">
10365 * @extends Roo.util.Observable
10366 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10367 * This class also supports single and multi selection modes. <br>
10368 * Create a data model bound view:
10370 var store = new Roo.data.Store(...);
10372 var view = new Roo.View({
10374 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10376 singleSelect: true,
10377 selectedClass: "ydataview-selected",
10381 // listen for node click?
10382 view.on("click", function(vw, index, node, e){
10383 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10387 dataModel.load("foobar.xml");
10389 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10391 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10392 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10394 * Note: old style constructor is still suported (container, template, config)
10397 * Create a new View
10398 * @param {Object} config The config object
10401 Roo.View = function(config, depreciated_tpl, depreciated_config){
10403 if (typeof(depreciated_tpl) == 'undefined') {
10404 // new way.. - universal constructor.
10405 Roo.apply(this, config);
10406 this.el = Roo.get(this.el);
10409 this.el = Roo.get(config);
10410 this.tpl = depreciated_tpl;
10411 Roo.apply(this, depreciated_config);
10413 this.wrapEl = this.el.wrap().wrap();
10414 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10417 if(typeof(this.tpl) == "string"){
10418 this.tpl = new Roo.Template(this.tpl);
10420 // support xtype ctors..
10421 this.tpl = new Roo.factory(this.tpl, Roo);
10425 this.tpl.compile();
10433 * @event beforeclick
10434 * Fires before a click is processed. Returns false to cancel the default action.
10435 * @param {Roo.View} this
10436 * @param {Number} index The index of the target node
10437 * @param {HTMLElement} node The target node
10438 * @param {Roo.EventObject} e The raw event object
10440 "beforeclick" : true,
10443 * Fires when a template node is clicked.
10444 * @param {Roo.View} this
10445 * @param {Number} index The index of the target node
10446 * @param {HTMLElement} node The target node
10447 * @param {Roo.EventObject} e The raw event object
10452 * Fires when a template node is double clicked.
10453 * @param {Roo.View} this
10454 * @param {Number} index The index of the target node
10455 * @param {HTMLElement} node The target node
10456 * @param {Roo.EventObject} e The raw event object
10460 * @event contextmenu
10461 * Fires when a template node is right clicked.
10462 * @param {Roo.View} this
10463 * @param {Number} index The index of the target node
10464 * @param {HTMLElement} node The target node
10465 * @param {Roo.EventObject} e The raw event object
10467 "contextmenu" : true,
10469 * @event selectionchange
10470 * Fires when the selected nodes change.
10471 * @param {Roo.View} this
10472 * @param {Array} selections Array of the selected nodes
10474 "selectionchange" : true,
10477 * @event beforeselect
10478 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10479 * @param {Roo.View} this
10480 * @param {HTMLElement} node The node to be selected
10481 * @param {Array} selections Array of currently selected nodes
10483 "beforeselect" : true,
10485 * @event preparedata
10486 * Fires on every row to render, to allow you to change the data.
10487 * @param {Roo.View} this
10488 * @param {Object} data to be rendered (change this)
10490 "preparedata" : true
10498 "click": this.onClick,
10499 "dblclick": this.onDblClick,
10500 "contextmenu": this.onContextMenu,
10504 this.selections = [];
10506 this.cmp = new Roo.CompositeElementLite([]);
10508 this.store = Roo.factory(this.store, Roo.data);
10509 this.setStore(this.store, true);
10512 if ( this.footer && this.footer.xtype) {
10514 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10516 this.footer.dataSource = this.store
10517 this.footer.container = fctr;
10518 this.footer = Roo.factory(this.footer, Roo);
10519 fctr.insertFirst(this.el);
10521 // this is a bit insane - as the paging toolbar seems to detach the el..
10522 // dom.parentNode.parentNode.parentNode
10523 // they get detached?
10527 Roo.View.superclass.constructor.call(this);
10532 Roo.extend(Roo.View, Roo.util.Observable, {
10535 * @cfg {Roo.data.Store} store Data store to load data from.
10540 * @cfg {String|Roo.Element} el The container element.
10545 * @cfg {String|Roo.Template} tpl The template used by this View
10549 * @cfg {String} dataName the named area of the template to use as the data area
10550 * Works with domtemplates roo-name="name"
10554 * @cfg {String} selectedClass The css class to add to selected nodes
10556 selectedClass : "x-view-selected",
10558 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10563 * @cfg {String} text to display on mask (default Loading)
10567 * @cfg {Boolean} multiSelect Allow multiple selection
10569 multiSelect : false,
10571 * @cfg {Boolean} singleSelect Allow single selection
10573 singleSelect: false,
10576 * @cfg {Boolean} toggleSelect - selecting
10578 toggleSelect : false,
10581 * Returns the element this view is bound to.
10582 * @return {Roo.Element}
10584 getEl : function(){
10585 return this.wrapEl;
10591 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10593 refresh : function(){
10594 Roo.log('refresh');
10597 // if we are using something like 'domtemplate', then
10598 // the what gets used is:
10599 // t.applySubtemplate(NAME, data, wrapping data..)
10600 // the outer template then get' applied with
10601 // the store 'extra data'
10602 // and the body get's added to the
10603 // roo-name="data" node?
10604 // <span class='roo-tpl-{name}'></span> ?????
10608 this.clearSelections();
10609 this.el.update("");
10611 var records = this.store.getRange();
10612 if(records.length < 1) {
10614 // is this valid?? = should it render a template??
10616 this.el.update(this.emptyText);
10620 if (this.dataName) {
10621 this.el.update(t.apply(this.store.meta)); //????
10622 el = this.el.child('.roo-tpl-' + this.dataName);
10625 for(var i = 0, len = records.length; i < len; i++){
10626 var data = this.prepareData(records[i].data, i, records[i]);
10627 this.fireEvent("preparedata", this, data, i, records[i]);
10628 html[html.length] = Roo.util.Format.trim(
10630 t.applySubtemplate(this.dataName, data, this.store.meta) :
10637 el.update(html.join(""));
10638 this.nodes = el.dom.childNodes;
10639 this.updateIndexes(0);
10644 * Function to override to reformat the data that is sent to
10645 * the template for each node.
10646 * DEPRICATED - use the preparedata event handler.
10647 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10648 * a JSON object for an UpdateManager bound view).
10650 prepareData : function(data, index, record)
10652 this.fireEvent("preparedata", this, data, index, record);
10656 onUpdate : function(ds, record){
10657 Roo.log('on update');
10658 this.clearSelections();
10659 var index = this.store.indexOf(record);
10660 var n = this.nodes[index];
10661 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10662 n.parentNode.removeChild(n);
10663 this.updateIndexes(index, index);
10669 onAdd : function(ds, records, index)
10671 Roo.log(['on Add', ds, records, index] );
10672 this.clearSelections();
10673 if(this.nodes.length == 0){
10677 var n = this.nodes[index];
10678 for(var i = 0, len = records.length; i < len; i++){
10679 var d = this.prepareData(records[i].data, i, records[i]);
10681 this.tpl.insertBefore(n, d);
10684 this.tpl.append(this.el, d);
10687 this.updateIndexes(index);
10690 onRemove : function(ds, record, index){
10691 Roo.log('onRemove');
10692 this.clearSelections();
10693 var el = this.dataName ?
10694 this.el.child('.roo-tpl-' + this.dataName) :
10697 el.dom.removeChild(this.nodes[index]);
10698 this.updateIndexes(index);
10702 * Refresh an individual node.
10703 * @param {Number} index
10705 refreshNode : function(index){
10706 this.onUpdate(this.store, this.store.getAt(index));
10709 updateIndexes : function(startIndex, endIndex){
10710 var ns = this.nodes;
10711 startIndex = startIndex || 0;
10712 endIndex = endIndex || ns.length - 1;
10713 for(var i = startIndex; i <= endIndex; i++){
10714 ns[i].nodeIndex = i;
10719 * Changes the data store this view uses and refresh the view.
10720 * @param {Store} store
10722 setStore : function(store, initial){
10723 if(!initial && this.store){
10724 this.store.un("datachanged", this.refresh);
10725 this.store.un("add", this.onAdd);
10726 this.store.un("remove", this.onRemove);
10727 this.store.un("update", this.onUpdate);
10728 this.store.un("clear", this.refresh);
10729 this.store.un("beforeload", this.onBeforeLoad);
10730 this.store.un("load", this.onLoad);
10731 this.store.un("loadexception", this.onLoad);
10735 store.on("datachanged", this.refresh, this);
10736 store.on("add", this.onAdd, this);
10737 store.on("remove", this.onRemove, this);
10738 store.on("update", this.onUpdate, this);
10739 store.on("clear", this.refresh, this);
10740 store.on("beforeload", this.onBeforeLoad, this);
10741 store.on("load", this.onLoad, this);
10742 store.on("loadexception", this.onLoad, this);
10750 * onbeforeLoad - masks the loading area.
10753 onBeforeLoad : function(store,opts)
10755 Roo.log('onBeforeLoad');
10757 this.el.update("");
10759 this.el.mask(this.mask ? this.mask : "Loading" );
10761 onLoad : function ()
10768 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10769 * @param {HTMLElement} node
10770 * @return {HTMLElement} The template node
10772 findItemFromChild : function(node){
10773 var el = this.dataName ?
10774 this.el.child('.roo-tpl-' + this.dataName,true) :
10777 if(!node || node.parentNode == el){
10780 var p = node.parentNode;
10781 while(p && p != el){
10782 if(p.parentNode == el){
10791 onClick : function(e){
10792 var item = this.findItemFromChild(e.getTarget());
10794 var index = this.indexOf(item);
10795 if(this.onItemClick(item, index, e) !== false){
10796 this.fireEvent("click", this, index, item, e);
10799 this.clearSelections();
10804 onContextMenu : function(e){
10805 var item = this.findItemFromChild(e.getTarget());
10807 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10812 onDblClick : function(e){
10813 var item = this.findItemFromChild(e.getTarget());
10815 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10819 onItemClick : function(item, index, e)
10821 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10824 if (this.toggleSelect) {
10825 var m = this.isSelected(item) ? 'unselect' : 'select';
10828 _t[m](item, true, false);
10831 if(this.multiSelect || this.singleSelect){
10832 if(this.multiSelect && e.shiftKey && this.lastSelection){
10833 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10835 this.select(item, this.multiSelect && e.ctrlKey);
10836 this.lastSelection = item;
10838 e.preventDefault();
10844 * Get the number of selected nodes.
10847 getSelectionCount : function(){
10848 return this.selections.length;
10852 * Get the currently selected nodes.
10853 * @return {Array} An array of HTMLElements
10855 getSelectedNodes : function(){
10856 return this.selections;
10860 * Get the indexes of the selected nodes.
10863 getSelectedIndexes : function(){
10864 var indexes = [], s = this.selections;
10865 for(var i = 0, len = s.length; i < len; i++){
10866 indexes.push(s[i].nodeIndex);
10872 * Clear all selections
10873 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10875 clearSelections : function(suppressEvent){
10876 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10877 this.cmp.elements = this.selections;
10878 this.cmp.removeClass(this.selectedClass);
10879 this.selections = [];
10880 if(!suppressEvent){
10881 this.fireEvent("selectionchange", this, this.selections);
10887 * Returns true if the passed node is selected
10888 * @param {HTMLElement/Number} node The node or node index
10889 * @return {Boolean}
10891 isSelected : function(node){
10892 var s = this.selections;
10896 node = this.getNode(node);
10897 return s.indexOf(node) !== -1;
10902 * @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
10903 * @param {Boolean} keepExisting (optional) true to keep existing selections
10904 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10906 select : function(nodeInfo, keepExisting, suppressEvent){
10907 if(nodeInfo instanceof Array){
10909 this.clearSelections(true);
10911 for(var i = 0, len = nodeInfo.length; i < len; i++){
10912 this.select(nodeInfo[i], true, true);
10916 var node = this.getNode(nodeInfo);
10917 if(!node || this.isSelected(node)){
10918 return; // already selected.
10921 this.clearSelections(true);
10923 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10924 Roo.fly(node).addClass(this.selectedClass);
10925 this.selections.push(node);
10926 if(!suppressEvent){
10927 this.fireEvent("selectionchange", this, this.selections);
10935 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
10936 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10937 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10939 unselect : function(nodeInfo, keepExisting, suppressEvent)
10941 if(nodeInfo instanceof Array){
10942 Roo.each(this.selections, function(s) {
10943 this.unselect(s, nodeInfo);
10947 var node = this.getNode(nodeInfo);
10948 if(!node || !this.isSelected(node)){
10949 Roo.log("not selected");
10950 return; // not selected.
10954 Roo.each(this.selections, function(s) {
10956 Roo.fly(node).removeClass(this.selectedClass);
10963 this.selections= ns;
10964 this.fireEvent("selectionchange", this, this.selections);
10968 * Gets a template node.
10969 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10970 * @return {HTMLElement} The node or null if it wasn't found
10972 getNode : function(nodeInfo){
10973 if(typeof nodeInfo == "string"){
10974 return document.getElementById(nodeInfo);
10975 }else if(typeof nodeInfo == "number"){
10976 return this.nodes[nodeInfo];
10982 * Gets a range template nodes.
10983 * @param {Number} startIndex
10984 * @param {Number} endIndex
10985 * @return {Array} An array of nodes
10987 getNodes : function(start, end){
10988 var ns = this.nodes;
10989 start = start || 0;
10990 end = typeof end == "undefined" ? ns.length - 1 : end;
10993 for(var i = start; i <= end; i++){
10997 for(var i = start; i >= end; i--){
11005 * Finds the index of the passed 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 {Number} The index of the node or -1
11009 indexOf : function(node){
11010 node = this.getNode(node);
11011 if(typeof node.nodeIndex == "number"){
11012 return node.nodeIndex;
11014 var ns = this.nodes;
11015 for(var i = 0, len = ns.length; i < len; i++){
11026 * based on jquery fullcalendar
11030 Roo.bootstrap = Roo.bootstrap || {};
11032 * @class Roo.bootstrap.Calendar
11033 * @extends Roo.bootstrap.Component
11034 * Bootstrap Calendar class
11035 * @cfg {Boolean} loadMask (true|false) default false
11036 * @cfg {Object} header generate the user specific header of the calendar, default false
11039 * Create a new Container
11040 * @param {Object} config The config object
11045 Roo.bootstrap.Calendar = function(config){
11046 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11050 * Fires when a date is selected
11051 * @param {DatePicker} this
11052 * @param {Date} date The selected date
11056 * @event monthchange
11057 * Fires when the displayed month changes
11058 * @param {DatePicker} this
11059 * @param {Date} date The selected month
11061 'monthchange': true,
11063 * @event evententer
11064 * Fires when mouse over an event
11065 * @param {Calendar} this
11066 * @param {event} Event
11068 'evententer': true,
11070 * @event eventleave
11071 * Fires when the mouse leaves an
11072 * @param {Calendar} this
11075 'eventleave': true,
11077 * @event eventclick
11078 * Fires when the mouse click an
11079 * @param {Calendar} this
11088 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11091 * @cfg {Number} startDay
11092 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11100 getAutoCreate : function(){
11103 var fc_button = function(name, corner, style, content ) {
11104 return Roo.apply({},{
11106 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11108 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11111 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11122 style : 'width:100%',
11129 cls : 'fc-header-left',
11131 fc_button('prev', 'left', 'arrow', '‹' ),
11132 fc_button('next', 'right', 'arrow', '›' ),
11133 { tag: 'span', cls: 'fc-header-space' },
11134 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11142 cls : 'fc-header-center',
11146 cls: 'fc-header-title',
11149 html : 'month / year'
11157 cls : 'fc-header-right',
11159 /* fc_button('month', 'left', '', 'month' ),
11160 fc_button('week', '', '', 'week' ),
11161 fc_button('day', 'right', '', 'day' )
11173 header = this.header;
11176 var cal_heads = function() {
11178 // fixme - handle this.
11180 for (var i =0; i < Date.dayNames.length; i++) {
11181 var d = Date.dayNames[i];
11184 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11185 html : d.substring(0,3)
11189 ret[0].cls += ' fc-first';
11190 ret[6].cls += ' fc-last';
11193 var cal_cell = function(n) {
11196 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11201 cls: 'fc-day-number',
11205 cls: 'fc-day-content',
11209 style: 'position: relative;' // height: 17px;
11221 var cal_rows = function() {
11224 for (var r = 0; r < 6; r++) {
11231 for (var i =0; i < Date.dayNames.length; i++) {
11232 var d = Date.dayNames[i];
11233 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11236 row.cn[0].cls+=' fc-first';
11237 row.cn[0].cn[0].style = 'min-height:90px';
11238 row.cn[6].cls+=' fc-last';
11242 ret[0].cls += ' fc-first';
11243 ret[4].cls += ' fc-prev-last';
11244 ret[5].cls += ' fc-last';
11251 cls: 'fc-border-separate',
11252 style : 'width:100%',
11260 cls : 'fc-first fc-last',
11278 cls : 'fc-content',
11279 style : "position: relative;",
11282 cls : 'fc-view fc-view-month fc-grid',
11283 style : 'position: relative',
11284 unselectable : 'on',
11287 cls : 'fc-event-container',
11288 style : 'position:absolute;z-index:8;top:0;left:0;'
11306 initEvents : function()
11309 throw "can not find store for calendar";
11315 style: "text-align:center",
11319 style: "background-color:white;width:50%;margin:250 auto",
11323 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11334 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11336 var size = this.el.select('.fc-content', true).first().getSize();
11337 this.maskEl.setSize(size.width, size.height);
11338 this.maskEl.enableDisplayMode("block");
11339 if(!this.loadMask){
11340 this.maskEl.hide();
11343 this.store = Roo.factory(this.store, Roo.data);
11344 this.store.on('load', this.onLoad, this);
11345 this.store.on('beforeload', this.onBeforeLoad, this);
11349 this.cells = this.el.select('.fc-day',true);
11350 //Roo.log(this.cells);
11351 this.textNodes = this.el.query('.fc-day-number');
11352 this.cells.addClassOnOver('fc-state-hover');
11354 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11355 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11356 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11357 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11359 this.on('monthchange', this.onMonthChange, this);
11361 this.update(new Date().clearTime());
11364 resize : function() {
11365 var sz = this.el.getSize();
11367 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11368 this.el.select('.fc-day-content div',true).setHeight(34);
11373 showPrevMonth : function(e){
11374 this.update(this.activeDate.add("mo", -1));
11376 showToday : function(e){
11377 this.update(new Date().clearTime());
11380 showNextMonth : function(e){
11381 this.update(this.activeDate.add("mo", 1));
11385 showPrevYear : function(){
11386 this.update(this.activeDate.add("y", -1));
11390 showNextYear : function(){
11391 this.update(this.activeDate.add("y", 1));
11396 update : function(date)
11398 var vd = this.activeDate;
11399 this.activeDate = date;
11400 // if(vd && this.el){
11401 // var t = date.getTime();
11402 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11403 // Roo.log('using add remove');
11405 // this.fireEvent('monthchange', this, date);
11407 // this.cells.removeClass("fc-state-highlight");
11408 // this.cells.each(function(c){
11409 // if(c.dateValue == t){
11410 // c.addClass("fc-state-highlight");
11411 // setTimeout(function(){
11412 // try{c.dom.firstChild.focus();}catch(e){}
11422 var days = date.getDaysInMonth();
11424 var firstOfMonth = date.getFirstDateOfMonth();
11425 var startingPos = firstOfMonth.getDay()-this.startDay;
11427 if(startingPos < this.startDay){
11431 var pm = date.add(Date.MONTH, -1);
11432 var prevStart = pm.getDaysInMonth()-startingPos;
11434 this.cells = this.el.select('.fc-day',true);
11435 this.textNodes = this.el.query('.fc-day-number');
11436 this.cells.addClassOnOver('fc-state-hover');
11438 var cells = this.cells.elements;
11439 var textEls = this.textNodes;
11441 Roo.each(cells, function(cell){
11442 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11445 days += startingPos;
11447 // convert everything to numbers so it's fast
11448 var day = 86400000;
11449 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11452 //Roo.log(prevStart);
11454 var today = new Date().clearTime().getTime();
11455 var sel = date.clearTime().getTime();
11456 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11457 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11458 var ddMatch = this.disabledDatesRE;
11459 var ddText = this.disabledDatesText;
11460 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11461 var ddaysText = this.disabledDaysText;
11462 var format = this.format;
11464 var setCellClass = function(cal, cell){
11466 //Roo.log('set Cell Class');
11468 var t = d.getTime();
11472 cell.dateValue = t;
11474 cell.className += " fc-today";
11475 cell.className += " fc-state-highlight";
11476 cell.title = cal.todayText;
11479 // disable highlight in other month..
11480 //cell.className += " fc-state-highlight";
11485 cell.className = " fc-state-disabled";
11486 cell.title = cal.minText;
11490 cell.className = " fc-state-disabled";
11491 cell.title = cal.maxText;
11495 if(ddays.indexOf(d.getDay()) != -1){
11496 cell.title = ddaysText;
11497 cell.className = " fc-state-disabled";
11500 if(ddMatch && format){
11501 var fvalue = d.dateFormat(format);
11502 if(ddMatch.test(fvalue)){
11503 cell.title = ddText.replace("%0", fvalue);
11504 cell.className = " fc-state-disabled";
11508 if (!cell.initialClassName) {
11509 cell.initialClassName = cell.dom.className;
11512 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11517 for(; i < startingPos; i++) {
11518 textEls[i].innerHTML = (++prevStart);
11519 d.setDate(d.getDate()+1);
11521 cells[i].className = "fc-past fc-other-month";
11522 setCellClass(this, cells[i]);
11527 for(; i < days; i++){
11528 intDay = i - startingPos + 1;
11529 textEls[i].innerHTML = (intDay);
11530 d.setDate(d.getDate()+1);
11532 cells[i].className = ''; // "x-date-active";
11533 setCellClass(this, cells[i]);
11537 for(; i < 42; i++) {
11538 textEls[i].innerHTML = (++extraDays);
11539 d.setDate(d.getDate()+1);
11541 cells[i].className = "fc-future fc-other-month";
11542 setCellClass(this, cells[i]);
11545 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11547 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11549 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11550 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11552 if(totalRows != 6){
11553 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11554 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11557 this.fireEvent('monthchange', this, date);
11561 if(!this.internalRender){
11562 var main = this.el.dom.firstChild;
11563 var w = main.offsetWidth;
11564 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11565 Roo.fly(main).setWidth(w);
11566 this.internalRender = true;
11567 // opera does not respect the auto grow header center column
11568 // then, after it gets a width opera refuses to recalculate
11569 // without a second pass
11570 if(Roo.isOpera && !this.secondPass){
11571 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11572 this.secondPass = true;
11573 this.update.defer(10, this, [date]);
11580 findCell : function(dt) {
11581 dt = dt.clearTime().getTime();
11583 this.cells.each(function(c){
11584 //Roo.log("check " +c.dateValue + '?=' + dt);
11585 if(c.dateValue == dt){
11595 findCells : function(ev) {
11596 var s = ev.start.clone().clearTime().getTime();
11598 var e= ev.end.clone().clearTime().getTime();
11601 this.cells.each(function(c){
11602 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11604 if(c.dateValue > e){
11607 if(c.dateValue < s){
11616 // findBestRow: function(cells)
11620 // for (var i =0 ; i < cells.length;i++) {
11621 // ret = Math.max(cells[i].rows || 0,ret);
11628 addItem : function(ev)
11630 // look for vertical location slot in
11631 var cells = this.findCells(ev);
11633 // ev.row = this.findBestRow(cells);
11635 // work out the location.
11639 for(var i =0; i < cells.length; i++) {
11647 if (crow.start.getY() == cells[i].getY()) {
11649 crow.end = cells[i];
11665 ev.rendered = false;
11666 // for (var i = 0; i < cells.length;i++) {
11667 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11671 this.calevents.push(ev);
11674 clearEvents: function() {
11676 if(!this.calevents){
11680 Roo.each(this.cells.elements, function(c){
11685 Roo.each(this.calevents, function(e) {
11686 Roo.each(e.els, function(el) {
11687 el.un('mouseenter' ,this.onEventEnter, this);
11688 el.un('mouseleave' ,this.onEventLeave, this);
11693 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11699 renderEvents: function()
11701 // first make sure there is enough space..
11702 this.cells.each(function(c) {
11707 for (var e = 0; e < this.calevents.length; e++) {
11709 var ev = this.calevents[e];
11710 var cells = ev.cells;
11711 var rows = ev.rows;
11713 for(var i = 0; i < cells.length; i++){
11715 var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11717 if(cells.length < 2 && cbox.rows.length > 3){
11718 cbox.more.push(ev);
11722 cbox.rows.push(ev);
11728 this.cells.each(function(c) {
11729 if(c.more.length && c.more.length == 1){
11730 c.rows.push(c.more.pop());
11733 var r = (c.more.length) ? c.rows.length + 1 : c.rows.length;
11734 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, r * 20));
11737 for (var e = 0; e < c.rows.length; e++){
11738 var ev = c.rows[e];
11744 var cells = ev.cells;
11745 var rows = ev.rows;
11747 for(var i = 0; i < rows.length; i++) {
11749 // how many rows should it span..
11752 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11753 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11755 unselectable : "on",
11758 cls: 'fc-event-inner',
11762 // cls: 'fc-event-time',
11763 // html : cells.length > 1 ? '' : ev.time
11767 cls: 'fc-event-title',
11768 html : String.format('{0}', ev.title)
11775 cls: 'ui-resizable-handle ui-resizable-e',
11776 html : '  '
11783 cfg.cls += ' fc-event-start';
11785 if ((i+1) == rows.length) {
11786 cfg.cls += ' fc-event-end';
11789 var ctr = _this.el.select('.fc-event-container',true).first();
11790 var cg = ctr.createChild(cfg);
11792 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11793 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11795 cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11796 cg.setWidth(ebox.right - sbox.x -2);
11798 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11799 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11800 cg.on('click', _this.onEventClick, _this, ev);
11804 ev.rendered = true;
11812 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11813 style : 'position: absolute',
11814 unselectable : "on",
11817 cls: 'fc-event-inner',
11821 cls: 'fc-event-title',
11829 cls: 'ui-resizable-handle ui-resizable-e',
11830 html : '  '
11836 var ctr = _this.el.select('.fc-event-container',true).first();
11837 var cg = ctr.createChild(cfg);
11839 var sbox = c.select('.fc-day-content',true).first().getBox();
11840 var ebox = c.select('.fc-day-content',true).first().getBox();
11842 cg.setXY([sbox.x +2, sbox.y +(c.rows.length * 20)]);
11843 cg.setWidth(ebox.right - sbox.x -2);
11845 cg.on('click', _this.onMoreEventClick, _this, c.more);
11855 onEventEnter: function (e, el,event,d) {
11856 this.fireEvent('evententer', this, el, event);
11859 onEventLeave: function (e, el,event,d) {
11860 this.fireEvent('eventleave', this, el, event);
11863 onEventClick: function (e, el,event,d) {
11864 this.fireEvent('eventclick', this, el, event);
11867 onMonthChange: function () {
11871 onMoreEventClick: function(e, el, more)
11875 this.calpopover.placement = 'right';
11876 this.calpopover.setTitle('More');
11878 this.calpopover.setContent('');
11880 var ctr = this.calpopover.el.select('.popover-content', true).first();
11882 Roo.each(more, function(m){
11884 cls : 'fc-event-hori fc-event-draggable',
11887 var cg = ctr.createChild(cfg);
11889 cg.on('click', _this.onEventClick, _this, m);
11892 this.calpopover.show(el);
11897 onLoad: function ()
11899 this.calevents = [];
11902 if(this.store.getCount() > 0){
11903 this.store.data.each(function(d){
11906 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11907 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11908 time : d.data.start_time,
11909 title : d.data.title,
11910 description : d.data.description,
11911 venue : d.data.venue
11916 this.renderEvents();
11918 if(this.calevents.length && this.loadMask){
11919 this.maskEl.hide();
11923 onBeforeLoad: function()
11925 this.clearEvents();
11927 this.maskEl.show();
11941 * @class Roo.bootstrap.Popover
11942 * @extends Roo.bootstrap.Component
11943 * Bootstrap Popover class
11944 * @cfg {String} html contents of the popover (or false to use children..)
11945 * @cfg {String} title of popover (or false to hide)
11946 * @cfg {String} placement how it is placed
11947 * @cfg {String} trigger click || hover (or false to trigger manually)
11948 * @cfg {String} over what (parent or false to trigger manually.)
11951 * Create a new Popover
11952 * @param {Object} config The config object
11955 Roo.bootstrap.Popover = function(config){
11956 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11959 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11961 title: 'Fill in a title',
11964 placement : 'right',
11965 trigger : 'hover', // hover
11969 can_build_overlaid : false,
11971 getChildContainer : function()
11973 return this.el.select('.popover-content',true).first();
11976 getAutoCreate : function(){
11977 Roo.log('make popover?');
11979 cls : 'popover roo-dynamic',
11980 style: 'display:block',
11986 cls : 'popover-inner',
11990 cls: 'popover-title',
11994 cls : 'popover-content',
12005 setTitle: function(str)
12007 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12009 setContent: function(str)
12011 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12013 // as it get's added to the bottom of the page.
12014 onRender : function(ct, position)
12016 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12018 var cfg = Roo.apply({}, this.getAutoCreate());
12022 cfg.cls += ' ' + this.cls;
12025 cfg.style = this.style;
12027 Roo.log("adding to ")
12028 this.el = Roo.get(document.body).createChild(cfg, position);
12034 initEvents : function()
12036 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12037 this.el.enableDisplayMode('block');
12039 if (this.over === false) {
12042 if (this.triggers === false) {
12045 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12046 var triggers = this.trigger ? this.trigger.split(' ') : [];
12047 Roo.each(triggers, function(trigger) {
12049 if (trigger == 'click') {
12050 on_el.on('click', this.toggle, this);
12051 } else if (trigger != 'manual') {
12052 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12053 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12055 on_el.on(eventIn ,this.enter, this);
12056 on_el.on(eventOut, this.leave, this);
12067 toggle : function () {
12068 this.hoverState == 'in' ? this.leave() : this.enter();
12071 enter : function () {
12074 clearTimeout(this.timeout);
12076 this.hoverState = 'in'
12078 if (!this.delay || !this.delay.show) {
12083 this.timeout = setTimeout(function () {
12084 if (_t.hoverState == 'in') {
12087 }, this.delay.show)
12089 leave : function() {
12090 clearTimeout(this.timeout);
12092 this.hoverState = 'out'
12094 if (!this.delay || !this.delay.hide) {
12099 this.timeout = setTimeout(function () {
12100 if (_t.hoverState == 'out') {
12103 }, this.delay.hide)
12106 show : function (on_el)
12109 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12112 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12113 if (this.html !== false) {
12114 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12116 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12117 if (!this.title.length) {
12118 this.el.select('.popover-title',true).hide();
12121 var placement = typeof this.placement == 'function' ?
12122 this.placement.call(this, this.el, on_el) :
12125 var autoToken = /\s?auto?\s?/i;
12126 var autoPlace = autoToken.test(placement);
12128 placement = placement.replace(autoToken, '') || 'top';
12132 //this.el.setXY([0,0]);
12134 this.el.dom.style.display='block';
12135 this.el.addClass(placement);
12137 //this.el.appendTo(on_el);
12139 var p = this.getPosition();
12140 var box = this.el.getBox();
12145 var align = Roo.bootstrap.Popover.alignment[placement]
12146 this.el.alignTo(on_el, align[0],align[1]);
12147 //var arrow = this.el.select('.arrow',true).first();
12148 //arrow.set(align[2],
12150 this.el.addClass('in');
12151 this.hoverState = null;
12153 if (this.el.hasClass('fade')) {
12160 this.el.setXY([0,0]);
12161 this.el.removeClass('in');
12168 Roo.bootstrap.Popover.alignment = {
12169 'left' : ['r-l', [-10,0], 'right'],
12170 'right' : ['l-r', [10,0], 'left'],
12171 'bottom' : ['t-b', [0,10], 'top'],
12172 'top' : [ 'b-t', [0,-10], 'bottom']
12183 * @class Roo.bootstrap.Progress
12184 * @extends Roo.bootstrap.Component
12185 * Bootstrap Progress class
12186 * @cfg {Boolean} striped striped of the progress bar
12187 * @cfg {Boolean} active animated of the progress bar
12191 * Create a new Progress
12192 * @param {Object} config The config object
12195 Roo.bootstrap.Progress = function(config){
12196 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12199 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12204 getAutoCreate : function(){
12212 cfg.cls += ' progress-striped';
12216 cfg.cls += ' active';
12235 * @class Roo.bootstrap.ProgressBar
12236 * @extends Roo.bootstrap.Component
12237 * Bootstrap ProgressBar class
12238 * @cfg {Number} aria_valuenow aria-value now
12239 * @cfg {Number} aria_valuemin aria-value min
12240 * @cfg {Number} aria_valuemax aria-value max
12241 * @cfg {String} label label for the progress bar
12242 * @cfg {String} panel (success | info | warning | danger )
12243 * @cfg {String} role role of the progress bar
12244 * @cfg {String} sr_only text
12248 * Create a new ProgressBar
12249 * @param {Object} config The config object
12252 Roo.bootstrap.ProgressBar = function(config){
12253 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12256 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12260 aria_valuemax : 100,
12266 getAutoCreate : function()
12271 cls: 'progress-bar',
12272 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12284 cfg.role = this.role;
12287 if(this.aria_valuenow){
12288 cfg['aria-valuenow'] = this.aria_valuenow;
12291 if(this.aria_valuemin){
12292 cfg['aria-valuemin'] = this.aria_valuemin;
12295 if(this.aria_valuemax){
12296 cfg['aria-valuemax'] = this.aria_valuemax;
12299 if(this.label && !this.sr_only){
12300 cfg.html = this.label;
12304 cfg.cls += ' progress-bar-' + this.panel;
12310 update : function(aria_valuenow)
12312 this.aria_valuenow = aria_valuenow;
12314 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12329 * @class Roo.bootstrap.TabPanel
12330 * @extends Roo.bootstrap.Component
12331 * Bootstrap TabPanel class
12332 * @cfg {Boolean} active panel active
12333 * @cfg {String} html panel content
12334 * @cfg {String} tabId tab relate id
12335 * @cfg {String} navId The navbar which triggers show hide
12339 * Create a new TabPanel
12340 * @param {Object} config The config object
12343 Roo.bootstrap.TabPanel = function(config){
12344 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12348 * Fires when the active status changes
12349 * @param {Roo.bootstrap.TabPanel} this
12350 * @param {Boolean} state the new state
12357 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12364 getAutoCreate : function(){
12368 html: this.html || ''
12372 cfg.cls += ' active';
12376 cfg.tabId = this.tabId;
12381 onRender : function(ct, position)
12383 // Roo.log("Call onRender: " + this.xtype);
12385 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12387 if (this.navId && this.tabId) {
12388 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12390 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12392 item.on('changed', function(item, state) {
12393 this.setActive(state);
12399 setActive: function(state)
12401 Roo.log("panel - set active " + this.tabId + "=" + state);
12403 this.active = state;
12405 this.el.removeClass('active');
12407 } else if (!this.el.hasClass('active')) {
12408 this.el.addClass('active');
12410 this.fireEvent('changed', this, state);
12427 * @class Roo.bootstrap.DateField
12428 * @extends Roo.bootstrap.Input
12429 * Bootstrap DateField class
12430 * @cfg {Number} weekStart default 0
12431 * @cfg {Number} weekStart default 0
12432 * @cfg {Number} viewMode default empty, (months|years)
12433 * @cfg {Number} minViewMode default empty, (months|years)
12434 * @cfg {Number} startDate default -Infinity
12435 * @cfg {Number} endDate default Infinity
12436 * @cfg {Boolean} todayHighlight default false
12437 * @cfg {Boolean} todayBtn default false
12438 * @cfg {Boolean} calendarWeeks default false
12439 * @cfg {Object} daysOfWeekDisabled default empty
12441 * @cfg {Boolean} keyboardNavigation default true
12442 * @cfg {String} language default en
12445 * Create a new DateField
12446 * @param {Object} config The config object
12449 Roo.bootstrap.DateField = function(config){
12450 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12454 * Fires when this field show.
12455 * @param {Roo.bootstrap.DateField} this
12456 * @param {Mixed} date The date value
12461 * Fires when this field hide.
12462 * @param {Roo.bootstrap.DateField} this
12463 * @param {Mixed} date The date value
12468 * Fires when select a date.
12469 * @param {Roo.bootstrap.DateField} this
12470 * @param {Mixed} date The date value
12476 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12479 * @cfg {String} format
12480 * The default date format string which can be overriden for localization support. The format must be
12481 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12485 * @cfg {String} altFormats
12486 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12487 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12489 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12497 todayHighlight : false,
12503 keyboardNavigation: true,
12505 calendarWeeks: false,
12507 startDate: -Infinity,
12511 daysOfWeekDisabled: [],
12515 UTCDate: function()
12517 return new Date(Date.UTC.apply(Date, arguments));
12520 UTCToday: function()
12522 var today = new Date();
12523 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12526 getDate: function() {
12527 var d = this.getUTCDate();
12528 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12531 getUTCDate: function() {
12535 setDate: function(d) {
12536 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12539 setUTCDate: function(d) {
12541 this.setValue(this.formatDate(this.date));
12544 onRender: function(ct, position)
12547 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12549 this.language = this.language || 'en';
12550 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12551 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12553 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12554 this.format = this.format || 'm/d/y';
12555 this.isInline = false;
12556 this.isInput = true;
12557 this.component = this.el.select('.add-on', true).first() || false;
12558 this.component = (this.component && this.component.length === 0) ? false : this.component;
12559 this.hasInput = this.component && this.inputEL().length;
12561 if (typeof(this.minViewMode === 'string')) {
12562 switch (this.minViewMode) {
12564 this.minViewMode = 1;
12567 this.minViewMode = 2;
12570 this.minViewMode = 0;
12575 if (typeof(this.viewMode === 'string')) {
12576 switch (this.viewMode) {
12589 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12591 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12593 this.picker().on('mousedown', this.onMousedown, this);
12594 this.picker().on('click', this.onClick, this);
12596 this.picker().addClass('datepicker-dropdown');
12598 this.startViewMode = this.viewMode;
12601 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12602 if(!this.calendarWeeks){
12607 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12608 v.attr('colspan', function(i, val){
12609 return parseInt(val) + 1;
12614 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12616 this.setStartDate(this.startDate);
12617 this.setEndDate(this.endDate);
12619 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12626 if(this.isInline) {
12631 picker : function()
12633 return this.el.select('.datepicker', true).first();
12636 fillDow: function()
12638 var dowCnt = this.weekStart;
12647 if(this.calendarWeeks){
12655 while (dowCnt < this.weekStart + 7) {
12659 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12663 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12666 fillMonths: function()
12669 var months = this.picker().select('>.datepicker-months td', true).first();
12671 months.dom.innerHTML = '';
12677 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12680 months.createChild(month);
12685 update: function(){
12687 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12689 if (this.date < this.startDate) {
12690 this.viewDate = new Date(this.startDate);
12691 } else if (this.date > this.endDate) {
12692 this.viewDate = new Date(this.endDate);
12694 this.viewDate = new Date(this.date);
12701 var d = new Date(this.viewDate),
12702 year = d.getUTCFullYear(),
12703 month = d.getUTCMonth(),
12704 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12705 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12706 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12707 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12708 currentDate = this.date && this.date.valueOf(),
12709 today = this.UTCToday();
12711 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12713 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12715 // this.picker.select('>tfoot th.today').
12716 // .text(dates[this.language].today)
12717 // .toggle(this.todayBtn !== false);
12719 this.updateNavArrows();
12722 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12724 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12726 prevMonth.setUTCDate(day);
12728 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12730 var nextMonth = new Date(prevMonth);
12732 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12734 nextMonth = nextMonth.valueOf();
12736 var fillMonths = false;
12738 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12740 while(prevMonth.valueOf() < nextMonth) {
12743 if (prevMonth.getUTCDay() === this.weekStart) {
12745 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12753 if(this.calendarWeeks){
12754 // ISO 8601: First week contains first thursday.
12755 // ISO also states week starts on Monday, but we can be more abstract here.
12757 // Start of current week: based on weekstart/current date
12758 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12759 // Thursday of this week
12760 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12761 // First Thursday of year, year from thursday
12762 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12763 // Calendar week: ms between thursdays, div ms per day, div 7 days
12764 calWeek = (th - yth) / 864e5 / 7 + 1;
12766 fillMonths.cn.push({
12774 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12776 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12779 if (this.todayHighlight &&
12780 prevMonth.getUTCFullYear() == today.getFullYear() &&
12781 prevMonth.getUTCMonth() == today.getMonth() &&
12782 prevMonth.getUTCDate() == today.getDate()) {
12783 clsName += ' today';
12786 if (currentDate && prevMonth.valueOf() === currentDate) {
12787 clsName += ' active';
12790 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12791 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12792 clsName += ' disabled';
12795 fillMonths.cn.push({
12797 cls: 'day ' + clsName,
12798 html: prevMonth.getDate()
12801 prevMonth.setDate(prevMonth.getDate()+1);
12804 var currentYear = this.date && this.date.getUTCFullYear();
12805 var currentMonth = this.date && this.date.getUTCMonth();
12807 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12809 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12810 v.removeClass('active');
12812 if(currentYear === year && k === currentMonth){
12813 v.addClass('active');
12816 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12817 v.addClass('disabled');
12823 year = parseInt(year/10, 10) * 10;
12825 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12827 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12830 for (var i = -1; i < 11; i++) {
12831 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12833 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12841 showMode: function(dir) {
12843 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12845 Roo.each(this.picker().select('>div',true).elements, function(v){
12846 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12849 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12854 if(this.isInline) return;
12856 this.picker().removeClass(['bottom', 'top']);
12858 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12860 * place to the top of element!
12864 this.picker().addClass('top');
12865 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12870 this.picker().addClass('bottom');
12872 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12875 parseDate : function(value){
12876 if(!value || value instanceof Date){
12879 var v = Date.parseDate(value, this.format);
12880 if (!v && this.useIso) {
12881 v = Date.parseDate(value, 'Y-m-d');
12883 if(!v && this.altFormats){
12884 if(!this.altFormatsArray){
12885 this.altFormatsArray = this.altFormats.split("|");
12887 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12888 v = Date.parseDate(value, this.altFormatsArray[i]);
12894 formatDate : function(date, fmt){
12895 return (!date || !(date instanceof Date)) ?
12896 date : date.dateFormat(fmt || this.format);
12899 onFocus : function()
12901 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12905 onBlur : function()
12907 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12913 this.picker().show();
12917 this.fireEvent('show', this, this.date);
12922 if(this.isInline) return;
12923 this.picker().hide();
12924 this.viewMode = this.startViewMode;
12927 this.fireEvent('hide', this, this.date);
12931 onMousedown: function(e){
12932 e.stopPropagation();
12933 e.preventDefault();
12936 keyup: function(e){
12937 Roo.bootstrap.DateField.superclass.keyup.call(this);
12942 setValue: function(v){
12943 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12945 this.fireEvent('select', this, this.date);
12949 fireKey: function(e){
12950 if (!this.picker().isVisible()){
12951 if (e.keyCode == 27) // allow escape to hide and re-show picker
12955 var dateChanged = false,
12957 newDate, newViewDate;
12961 e.preventDefault();
12965 if (!this.keyboardNavigation) break;
12966 dir = e.keyCode == 37 ? -1 : 1;
12969 newDate = this.moveYear(this.date, dir);
12970 newViewDate = this.moveYear(this.viewDate, dir);
12971 } else if (e.shiftKey){
12972 newDate = this.moveMonth(this.date, dir);
12973 newViewDate = this.moveMonth(this.viewDate, dir);
12975 newDate = new Date(this.date);
12976 newDate.setUTCDate(this.date.getUTCDate() + dir);
12977 newViewDate = new Date(this.viewDate);
12978 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12980 if (this.dateWithinRange(newDate)){
12981 this.date = newDate;
12982 this.viewDate = newViewDate;
12983 this.setValue(this.formatDate(this.date));
12985 e.preventDefault();
12986 dateChanged = true;
12991 if (!this.keyboardNavigation) break;
12992 dir = e.keyCode == 38 ? -1 : 1;
12994 newDate = this.moveYear(this.date, dir);
12995 newViewDate = this.moveYear(this.viewDate, dir);
12996 } else if (e.shiftKey){
12997 newDate = this.moveMonth(this.date, dir);
12998 newViewDate = this.moveMonth(this.viewDate, dir);
13000 newDate = new Date(this.date);
13001 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13002 newViewDate = new Date(this.viewDate);
13003 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13005 if (this.dateWithinRange(newDate)){
13006 this.date = newDate;
13007 this.viewDate = newViewDate;
13008 this.setValue(this.formatDate(this.date));
13010 e.preventDefault();
13011 dateChanged = true;
13015 this.setValue(this.formatDate(this.date));
13017 e.preventDefault();
13020 this.setValue(this.formatDate(this.date));
13027 onClick: function(e) {
13028 e.stopPropagation();
13029 e.preventDefault();
13031 var target = e.getTarget();
13033 if(target.nodeName.toLowerCase() === 'i'){
13034 target = Roo.get(target).dom.parentNode;
13037 var nodeName = target.nodeName;
13038 var className = target.className;
13039 var html = target.innerHTML;
13041 switch(nodeName.toLowerCase()) {
13043 switch(className) {
13049 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13050 switch(this.viewMode){
13052 this.viewDate = this.moveMonth(this.viewDate, dir);
13056 this.viewDate = this.moveYear(this.viewDate, dir);
13062 var date = new Date();
13063 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13065 this.setValue(this.formatDate(this.date));
13071 if (className.indexOf('disabled') === -1) {
13072 this.viewDate.setUTCDate(1);
13073 if (className.indexOf('month') !== -1) {
13074 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13076 var year = parseInt(html, 10) || 0;
13077 this.viewDate.setUTCFullYear(year);
13086 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13087 var day = parseInt(html, 10) || 1;
13088 var year = this.viewDate.getUTCFullYear(),
13089 month = this.viewDate.getUTCMonth();
13091 if (className.indexOf('old') !== -1) {
13098 } else if (className.indexOf('new') !== -1) {
13106 this.date = this.UTCDate(year, month, day,0,0,0,0);
13107 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13109 this.setValue(this.formatDate(this.date));
13116 setStartDate: function(startDate){
13117 this.startDate = startDate || -Infinity;
13118 if (this.startDate !== -Infinity) {
13119 this.startDate = this.parseDate(this.startDate);
13122 this.updateNavArrows();
13125 setEndDate: function(endDate){
13126 this.endDate = endDate || Infinity;
13127 if (this.endDate !== Infinity) {
13128 this.endDate = this.parseDate(this.endDate);
13131 this.updateNavArrows();
13134 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13135 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13136 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13137 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13139 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13140 return parseInt(d, 10);
13143 this.updateNavArrows();
13146 updateNavArrows: function() {
13147 var d = new Date(this.viewDate),
13148 year = d.getUTCFullYear(),
13149 month = d.getUTCMonth();
13151 Roo.each(this.picker().select('.prev', true).elements, function(v){
13153 switch (this.viewMode) {
13156 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13162 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13169 Roo.each(this.picker().select('.next', true).elements, function(v){
13171 switch (this.viewMode) {
13174 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13180 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13188 moveMonth: function(date, dir){
13189 if (!dir) return date;
13190 var new_date = new Date(date.valueOf()),
13191 day = new_date.getUTCDate(),
13192 month = new_date.getUTCMonth(),
13193 mag = Math.abs(dir),
13195 dir = dir > 0 ? 1 : -1;
13198 // If going back one month, make sure month is not current month
13199 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13201 return new_date.getUTCMonth() == month;
13203 // If going forward one month, make sure month is as expected
13204 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13206 return new_date.getUTCMonth() != new_month;
13208 new_month = month + dir;
13209 new_date.setUTCMonth(new_month);
13210 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13211 if (new_month < 0 || new_month > 11)
13212 new_month = (new_month + 12) % 12;
13214 // For magnitudes >1, move one month at a time...
13215 for (var i=0; i<mag; i++)
13216 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13217 new_date = this.moveMonth(new_date, dir);
13218 // ...then reset the day, keeping it in the new month
13219 new_month = new_date.getUTCMonth();
13220 new_date.setUTCDate(day);
13222 return new_month != new_date.getUTCMonth();
13225 // Common date-resetting loop -- if date is beyond end of month, make it
13228 new_date.setUTCDate(--day);
13229 new_date.setUTCMonth(new_month);
13234 moveYear: function(date, dir){
13235 return this.moveMonth(date, dir*12);
13238 dateWithinRange: function(date){
13239 return date >= this.startDate && date <= this.endDate;
13243 remove: function() {
13244 this.picker().remove();
13249 Roo.apply(Roo.bootstrap.DateField, {
13260 html: '<i class="icon-arrow-left"/>'
13270 html: '<i class="icon-arrow-right"/>'
13312 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13313 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13314 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13315 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13316 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13329 navFnc: 'FullYear',
13334 navFnc: 'FullYear',
13339 Roo.apply(Roo.bootstrap.DateField, {
13343 cls: 'datepicker dropdown-menu',
13347 cls: 'datepicker-days',
13351 cls: 'table-condensed',
13353 Roo.bootstrap.DateField.head,
13357 Roo.bootstrap.DateField.footer
13364 cls: 'datepicker-months',
13368 cls: 'table-condensed',
13370 Roo.bootstrap.DateField.head,
13371 Roo.bootstrap.DateField.content,
13372 Roo.bootstrap.DateField.footer
13379 cls: 'datepicker-years',
13383 cls: 'table-condensed',
13385 Roo.bootstrap.DateField.head,
13386 Roo.bootstrap.DateField.content,
13387 Roo.bootstrap.DateField.footer
13406 * @class Roo.bootstrap.TimeField
13407 * @extends Roo.bootstrap.Input
13408 * Bootstrap DateField class
13412 * Create a new TimeField
13413 * @param {Object} config The config object
13416 Roo.bootstrap.TimeField = function(config){
13417 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13421 * Fires when this field show.
13422 * @param {Roo.bootstrap.DateField} this
13423 * @param {Mixed} date The date value
13428 * Fires when this field hide.
13429 * @param {Roo.bootstrap.DateField} this
13430 * @param {Mixed} date The date value
13435 * Fires when select a date.
13436 * @param {Roo.bootstrap.DateField} this
13437 * @param {Mixed} date The date value
13443 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13446 * @cfg {String} format
13447 * The default time format string which can be overriden for localization support. The format must be
13448 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13452 onRender: function(ct, position)
13455 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13457 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13459 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13461 this.pop = this.picker().select('>.datepicker-time',true).first();
13462 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13464 this.picker().on('mousedown', this.onMousedown, this);
13465 this.picker().on('click', this.onClick, this);
13467 this.picker().addClass('datepicker-dropdown');
13472 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13473 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13474 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13475 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13476 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13477 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13481 fireKey: function(e){
13482 if (!this.picker().isVisible()){
13483 if (e.keyCode == 27) // allow escape to hide and re-show picker
13488 e.preventDefault();
13496 this.onTogglePeriod();
13499 this.onIncrementMinutes();
13502 this.onDecrementMinutes();
13511 onClick: function(e) {
13512 e.stopPropagation();
13513 e.preventDefault();
13516 picker : function()
13518 return this.el.select('.datepicker', true).first();
13521 fillTime: function()
13523 var time = this.pop.select('tbody', true).first();
13525 time.dom.innerHTML = '';
13540 cls: 'hours-up glyphicon glyphicon-chevron-up'
13560 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13581 cls: 'timepicker-hour',
13596 cls: 'timepicker-minute',
13611 cls: 'btn btn-primary period',
13633 cls: 'hours-down glyphicon glyphicon-chevron-down'
13653 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13671 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13678 var hours = this.time.getHours();
13679 var minutes = this.time.getMinutes();
13692 hours = hours - 12;
13696 hours = '0' + hours;
13700 minutes = '0' + minutes;
13703 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13704 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13705 this.pop.select('button', true).first().dom.innerHTML = period;
13711 this.picker().removeClass(['bottom', 'top']);
13713 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13715 * place to the top of element!
13719 this.picker().addClass('top');
13720 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13725 this.picker().addClass('bottom');
13727 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13730 onFocus : function()
13732 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13736 onBlur : function()
13738 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13744 this.picker().show();
13749 this.fireEvent('show', this, this.date);
13754 this.picker().hide();
13757 this.fireEvent('hide', this, this.date);
13760 setTime : function()
13763 this.setValue(this.time.format(this.format));
13765 this.fireEvent('select', this, this.date);
13770 onMousedown: function(e){
13771 e.stopPropagation();
13772 e.preventDefault();
13775 onIncrementHours: function()
13777 Roo.log('onIncrementHours');
13778 this.time = this.time.add(Date.HOUR, 1);
13783 onDecrementHours: function()
13785 Roo.log('onDecrementHours');
13786 this.time = this.time.add(Date.HOUR, -1);
13790 onIncrementMinutes: function()
13792 Roo.log('onIncrementMinutes');
13793 this.time = this.time.add(Date.MINUTE, 1);
13797 onDecrementMinutes: function()
13799 Roo.log('onDecrementMinutes');
13800 this.time = this.time.add(Date.MINUTE, -1);
13804 onTogglePeriod: function()
13806 Roo.log('onTogglePeriod');
13807 this.time = this.time.add(Date.HOUR, 12);
13814 Roo.apply(Roo.bootstrap.TimeField, {
13844 cls: 'btn btn-info ok',
13856 Roo.apply(Roo.bootstrap.TimeField, {
13860 cls: 'datepicker dropdown-menu',
13864 cls: 'datepicker-time',
13868 cls: 'table-condensed',
13870 Roo.bootstrap.TimeField.content,
13871 Roo.bootstrap.TimeField.footer
13890 * @class Roo.bootstrap.CheckBox
13891 * @extends Roo.bootstrap.Input
13892 * Bootstrap CheckBox class
13894 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13895 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13896 * @cfg {String} boxLabel The text that appears beside the checkbox
13897 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13898 * @cfg {Boolean} checked initnal the element
13902 * Create a new CheckBox
13903 * @param {Object} config The config object
13906 Roo.bootstrap.CheckBox = function(config){
13907 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13912 * Fires when the element is checked or unchecked.
13913 * @param {Roo.bootstrap.CheckBox} this This input
13914 * @param {Boolean} checked The new checked value
13920 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13922 inputType: 'checkbox',
13929 getAutoCreate : function()
13931 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13937 cfg.cls = 'form-group checkbox' //input-group
13945 type : this.inputType,
13946 value : (!this.checked) ? this.valueOff : this.inputValue,
13947 cls : 'roo-checkbox', //'form-box',
13948 placeholder : this.placeholder || ''
13952 if (this.weight) { // Validity check?
13953 cfg.cls += " checkbox-" + this.weight;
13956 if (this.disabled) {
13957 input.disabled=true;
13961 input.checked = this.checked;
13965 input.name = this.name;
13969 input.cls += ' input-' + this.size;
13973 ['xs','sm','md','lg'].map(function(size){
13974 if (settings[size]) {
13975 cfg.cls += ' col-' + size + '-' + settings[size];
13981 var inputblock = input;
13986 if (this.before || this.after) {
13989 cls : 'input-group',
13993 inputblock.cn.push({
13995 cls : 'input-group-addon',
13999 inputblock.cn.push(input);
14001 inputblock.cn.push({
14003 cls : 'input-group-addon',
14010 if (align ==='left' && this.fieldLabel.length) {
14011 Roo.log("left and has label");
14017 cls : 'control-label col-md-' + this.labelWidth,
14018 html : this.fieldLabel
14022 cls : "col-md-" + (12 - this.labelWidth),
14029 } else if ( this.fieldLabel.length) {
14034 tag: this.boxLabel ? 'span' : 'label',
14036 cls: 'control-label box-input-label',
14037 //cls : 'input-group-addon',
14038 html : this.fieldLabel
14048 Roo.log(" no label && no align");
14049 cfg.cn = [ inputblock ] ;
14058 html: this.boxLabel
14070 * return the real input element.
14072 inputEl: function ()
14074 return this.el.select('input.roo-checkbox',true).first();
14079 return this.el.select('label.control-label',true).first();
14082 initEvents : function()
14084 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14086 this.inputEl().on('click', this.onClick, this);
14090 onClick : function()
14092 this.setChecked(!this.checked);
14095 setChecked : function(state,suppressEvent)
14097 this.checked = state;
14099 this.inputEl().dom.checked = state;
14101 if(suppressEvent !== true){
14102 this.fireEvent('check', this, state);
14105 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14109 setValue : function(v,suppressEvent)
14111 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14125 * @class Roo.bootstrap.Radio
14126 * @extends Roo.bootstrap.CheckBox
14127 * Bootstrap Radio class
14130 * Create a new Radio
14131 * @param {Object} config The config object
14134 Roo.bootstrap.Radio = function(config){
14135 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14139 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14141 inputType: 'radio',
14145 getAutoCreate : function()
14147 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14153 cfg.cls = 'form-group radio' //input-group
14158 type : this.inputType,
14159 value : (!this.checked) ? this.valueOff : this.inputValue,
14161 placeholder : this.placeholder || ''
14164 if (this.weight) { // Validity check?
14165 cfg.cls += " radio-" + this.weight;
14167 if (this.disabled) {
14168 input.disabled=true;
14172 input.checked = this.checked;
14176 input.name = this.name;
14180 input.cls += ' input-' + this.size;
14184 ['xs','sm','md','lg'].map(function(size){
14185 if (settings[size]) {
14186 cfg.cls += ' col-' + size + '-' + settings[size];
14190 var inputblock = input;
14192 if (this.before || this.after) {
14195 cls : 'input-group',
14199 inputblock.cn.push({
14201 cls : 'input-group-addon',
14205 inputblock.cn.push(input);
14207 inputblock.cn.push({
14209 cls : 'input-group-addon',
14216 if (align ==='left' && this.fieldLabel.length) {
14217 Roo.log("left and has label");
14223 cls : 'control-label col-md-' + this.labelWidth,
14224 html : this.fieldLabel
14228 cls : "col-md-" + (12 - this.labelWidth),
14235 } else if ( this.fieldLabel.length) {
14242 cls: 'control-label box-input-label',
14243 //cls : 'input-group-addon',
14244 html : this.fieldLabel
14254 Roo.log(" no label && no align");
14269 html: this.boxLabel
14276 inputEl: function ()
14278 return this.el.select('input.roo-radio',true).first();
14280 onClick : function()
14282 this.setChecked(true);
14285 setChecked : function(state,suppressEvent)
14288 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14289 v.dom.checked = false;
14293 this.checked = state;
14294 this.inputEl().dom.checked = state;
14296 if(suppressEvent !== true){
14297 this.fireEvent('check', this, state);
14300 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14304 getGroupValue : function()
14307 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14308 if(v.dom.checked == true){
14309 value = v.dom.value;
14317 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14318 * @return {Mixed} value The field value
14320 getValue : function(){
14321 return this.getGroupValue();
14327 //<script type="text/javascript">
14330 * Based Ext JS Library 1.1.1
14331 * Copyright(c) 2006-2007, Ext JS, LLC.
14337 * @class Roo.HtmlEditorCore
14338 * @extends Roo.Component
14339 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14341 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14344 Roo.HtmlEditorCore = function(config){
14347 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14350 * @event initialize
14351 * Fires when the editor is fully initialized (including the iframe)
14352 * @param {Roo.HtmlEditorCore} this
14357 * Fires when the editor is first receives the focus. Any insertion must wait
14358 * until after this event.
14359 * @param {Roo.HtmlEditorCore} this
14363 * @event beforesync
14364 * Fires before the textarea is updated with content from the editor iframe. Return false
14365 * to cancel the sync.
14366 * @param {Roo.HtmlEditorCore} this
14367 * @param {String} html
14371 * @event beforepush
14372 * Fires before the iframe editor is updated with content from the textarea. Return false
14373 * to cancel the push.
14374 * @param {Roo.HtmlEditorCore} this
14375 * @param {String} html
14380 * Fires when the textarea is updated with content from the editor iframe.
14381 * @param {Roo.HtmlEditorCore} this
14382 * @param {String} html
14387 * Fires when the iframe editor is updated with content from the textarea.
14388 * @param {Roo.HtmlEditorCore} this
14389 * @param {String} html
14394 * @event editorevent
14395 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14396 * @param {Roo.HtmlEditorCore} this
14404 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14408 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14414 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14419 * @cfg {Number} height (in pixels)
14423 * @cfg {Number} width (in pixels)
14428 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14431 stylesheets: false,
14436 // private properties
14437 validationEvent : false,
14439 initialized : false,
14441 sourceEditMode : false,
14442 onFocus : Roo.emptyFn,
14444 hideMode:'offsets',
14452 * Protected method that will not generally be called directly. It
14453 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14454 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14456 getDocMarkup : function(){
14459 Roo.log(this.stylesheets);
14461 // inherit styels from page...??
14462 if (this.stylesheets === false) {
14464 Roo.get(document.head).select('style').each(function(node) {
14465 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14468 Roo.get(document.head).select('link').each(function(node) {
14469 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14472 } else if (!this.stylesheets.length) {
14474 st = '<style type="text/css">' +
14475 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14478 Roo.each(this.stylesheets, function(s) {
14479 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14484 st += '<style type="text/css">' +
14485 'IMG { cursor: pointer } ' +
14489 return '<html><head>' + st +
14490 //<style type="text/css">' +
14491 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14493 ' </head><body class="roo-htmleditor-body"></body></html>';
14497 onRender : function(ct, position)
14500 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14501 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14504 this.el.dom.style.border = '0 none';
14505 this.el.dom.setAttribute('tabIndex', -1);
14506 this.el.addClass('x-hidden hide');
14510 if(Roo.isIE){ // fix IE 1px bogus margin
14511 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14515 this.frameId = Roo.id();
14519 var iframe = this.owner.wrap.createChild({
14521 cls: 'form-control', // bootstrap..
14523 name: this.frameId,
14524 frameBorder : 'no',
14525 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14530 this.iframe = iframe.dom;
14532 this.assignDocWin();
14534 this.doc.designMode = 'on';
14537 this.doc.write(this.getDocMarkup());
14541 var task = { // must defer to wait for browser to be ready
14543 //console.log("run task?" + this.doc.readyState);
14544 this.assignDocWin();
14545 if(this.doc.body || this.doc.readyState == 'complete'){
14547 this.doc.designMode="on";
14551 Roo.TaskMgr.stop(task);
14552 this.initEditor.defer(10, this);
14559 Roo.TaskMgr.start(task);
14566 onResize : function(w, h)
14568 Roo.log('resize: ' +w + ',' + h );
14569 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14573 if(typeof w == 'number'){
14575 this.iframe.style.width = w + 'px';
14577 if(typeof h == 'number'){
14579 this.iframe.style.height = h + 'px';
14581 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14588 * Toggles the editor between standard and source edit mode.
14589 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14591 toggleSourceEdit : function(sourceEditMode){
14593 this.sourceEditMode = sourceEditMode === true;
14595 if(this.sourceEditMode){
14597 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14600 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14601 //this.iframe.className = '';
14604 //this.setSize(this.owner.wrap.getSize());
14605 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14612 * Protected method that will not generally be called directly. If you need/want
14613 * custom HTML cleanup, this is the method you should override.
14614 * @param {String} html The HTML to be cleaned
14615 * return {String} The cleaned HTML
14617 cleanHtml : function(html){
14618 html = String(html);
14619 if(html.length > 5){
14620 if(Roo.isSafari){ // strip safari nonsense
14621 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14624 if(html == ' '){
14631 * HTML Editor -> Textarea
14632 * Protected method that will not generally be called directly. Syncs the contents
14633 * of the editor iframe with the textarea.
14635 syncValue : function(){
14636 if(this.initialized){
14637 var bd = (this.doc.body || this.doc.documentElement);
14638 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14639 var html = bd.innerHTML;
14641 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14642 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14644 html = '<div style="'+m[0]+'">' + html + '</div>';
14647 html = this.cleanHtml(html);
14648 // fix up the special chars.. normaly like back quotes in word...
14649 // however we do not want to do this with chinese..
14650 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14651 var cc = b.charCodeAt();
14653 (cc >= 0x4E00 && cc < 0xA000 ) ||
14654 (cc >= 0x3400 && cc < 0x4E00 ) ||
14655 (cc >= 0xf900 && cc < 0xfb00 )
14661 if(this.owner.fireEvent('beforesync', this, html) !== false){
14662 this.el.dom.value = html;
14663 this.owner.fireEvent('sync', this, html);
14669 * Protected method that will not generally be called directly. Pushes the value of the textarea
14670 * into the iframe editor.
14672 pushValue : function(){
14673 if(this.initialized){
14674 var v = this.el.dom.value.trim();
14676 // if(v.length < 1){
14680 if(this.owner.fireEvent('beforepush', this, v) !== false){
14681 var d = (this.doc.body || this.doc.documentElement);
14683 this.cleanUpPaste();
14684 this.el.dom.value = d.innerHTML;
14685 this.owner.fireEvent('push', this, v);
14691 deferFocus : function(){
14692 this.focus.defer(10, this);
14696 focus : function(){
14697 if(this.win && !this.sourceEditMode){
14704 assignDocWin: function()
14706 var iframe = this.iframe;
14709 this.doc = iframe.contentWindow.document;
14710 this.win = iframe.contentWindow;
14712 if (!Roo.get(this.frameId)) {
14715 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14716 this.win = Roo.get(this.frameId).dom.contentWindow;
14721 initEditor : function(){
14722 //console.log("INIT EDITOR");
14723 this.assignDocWin();
14727 this.doc.designMode="on";
14729 this.doc.write(this.getDocMarkup());
14732 var dbody = (this.doc.body || this.doc.documentElement);
14733 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14734 // this copies styles from the containing element into thsi one..
14735 // not sure why we need all of this..
14736 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14737 ss['background-attachment'] = 'fixed'; // w3c
14738 dbody.bgProperties = 'fixed'; // ie
14739 Roo.DomHelper.applyStyles(dbody, ss);
14740 Roo.EventManager.on(this.doc, {
14741 //'mousedown': this.onEditorEvent,
14742 'mouseup': this.onEditorEvent,
14743 'dblclick': this.onEditorEvent,
14744 'click': this.onEditorEvent,
14745 'keyup': this.onEditorEvent,
14750 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14752 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14753 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14755 this.initialized = true;
14757 this.owner.fireEvent('initialize', this);
14762 onDestroy : function(){
14768 //for (var i =0; i < this.toolbars.length;i++) {
14769 // // fixme - ask toolbars for heights?
14770 // this.toolbars[i].onDestroy();
14773 //this.wrap.dom.innerHTML = '';
14774 //this.wrap.remove();
14779 onFirstFocus : function(){
14781 this.assignDocWin();
14784 this.activated = true;
14787 if(Roo.isGecko){ // prevent silly gecko errors
14789 var s = this.win.getSelection();
14790 if(!s.focusNode || s.focusNode.nodeType != 3){
14791 var r = s.getRangeAt(0);
14792 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14797 this.execCmd('useCSS', true);
14798 this.execCmd('styleWithCSS', false);
14801 this.owner.fireEvent('activate', this);
14805 adjustFont: function(btn){
14806 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14807 //if(Roo.isSafari){ // safari
14810 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14811 if(Roo.isSafari){ // safari
14812 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14813 v = (v < 10) ? 10 : v;
14814 v = (v > 48) ? 48 : v;
14815 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14820 v = Math.max(1, v+adjust);
14822 this.execCmd('FontSize', v );
14825 onEditorEvent : function(e){
14826 this.owner.fireEvent('editorevent', this, e);
14827 // this.updateToolbar();
14828 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14831 insertTag : function(tg)
14833 // could be a bit smarter... -> wrap the current selected tRoo..
14834 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14836 range = this.createRange(this.getSelection());
14837 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14838 wrappingNode.appendChild(range.extractContents());
14839 range.insertNode(wrappingNode);
14846 this.execCmd("formatblock", tg);
14850 insertText : function(txt)
14854 var range = this.createRange();
14855 range.deleteContents();
14856 //alert(Sender.getAttribute('label'));
14858 range.insertNode(this.doc.createTextNode(txt));
14864 * Executes a Midas editor command on the editor document and performs necessary focus and
14865 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14866 * @param {String} cmd The Midas command
14867 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14869 relayCmd : function(cmd, value){
14871 this.execCmd(cmd, value);
14872 this.owner.fireEvent('editorevent', this);
14873 //this.updateToolbar();
14874 this.owner.deferFocus();
14878 * Executes a Midas editor command directly on the editor document.
14879 * For visual commands, you should use {@link #relayCmd} instead.
14880 * <b>This should only be called after the editor is initialized.</b>
14881 * @param {String} cmd The Midas command
14882 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14884 execCmd : function(cmd, value){
14885 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14892 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14894 * @param {String} text | dom node..
14896 insertAtCursor : function(text)
14901 if(!this.activated){
14907 var r = this.doc.selection.createRange();
14918 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14922 // from jquery ui (MIT licenced)
14924 var win = this.win;
14926 if (win.getSelection && win.getSelection().getRangeAt) {
14927 range = win.getSelection().getRangeAt(0);
14928 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14929 range.insertNode(node);
14930 } else if (win.document.selection && win.document.selection.createRange) {
14931 // no firefox support
14932 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14933 win.document.selection.createRange().pasteHTML(txt);
14935 // no firefox support
14936 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14937 this.execCmd('InsertHTML', txt);
14946 mozKeyPress : function(e){
14948 var c = e.getCharCode(), cmd;
14951 c = String.fromCharCode(c).toLowerCase();
14965 this.cleanUpPaste.defer(100, this);
14973 e.preventDefault();
14981 fixKeys : function(){ // load time branching for fastest keydown performance
14983 return function(e){
14984 var k = e.getKey(), r;
14987 r = this.doc.selection.createRange();
14990 r.pasteHTML('    ');
14997 r = this.doc.selection.createRange();
14999 var target = r.parentElement();
15000 if(!target || target.tagName.toLowerCase() != 'li'){
15002 r.pasteHTML('<br />');
15008 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15009 this.cleanUpPaste.defer(100, this);
15015 }else if(Roo.isOpera){
15016 return function(e){
15017 var k = e.getKey();
15021 this.execCmd('InsertHTML','    ');
15024 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15025 this.cleanUpPaste.defer(100, this);
15030 }else if(Roo.isSafari){
15031 return function(e){
15032 var k = e.getKey();
15036 this.execCmd('InsertText','\t');
15040 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15041 this.cleanUpPaste.defer(100, this);
15049 getAllAncestors: function()
15051 var p = this.getSelectedNode();
15054 a.push(p); // push blank onto stack..
15055 p = this.getParentElement();
15059 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15063 a.push(this.doc.body);
15067 lastSelNode : false,
15070 getSelection : function()
15072 this.assignDocWin();
15073 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15076 getSelectedNode: function()
15078 // this may only work on Gecko!!!
15080 // should we cache this!!!!
15085 var range = this.createRange(this.getSelection()).cloneRange();
15088 var parent = range.parentElement();
15090 var testRange = range.duplicate();
15091 testRange.moveToElementText(parent);
15092 if (testRange.inRange(range)) {
15095 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15098 parent = parent.parentElement;
15103 // is ancestor a text element.
15104 var ac = range.commonAncestorContainer;
15105 if (ac.nodeType == 3) {
15106 ac = ac.parentNode;
15109 var ar = ac.childNodes;
15112 var other_nodes = [];
15113 var has_other_nodes = false;
15114 for (var i=0;i<ar.length;i++) {
15115 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15118 // fullly contained node.
15120 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15125 // probably selected..
15126 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15127 other_nodes.push(ar[i]);
15131 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15136 has_other_nodes = true;
15138 if (!nodes.length && other_nodes.length) {
15139 nodes= other_nodes;
15141 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15147 createRange: function(sel)
15149 // this has strange effects when using with
15150 // top toolbar - not sure if it's a great idea.
15151 //this.editor.contentWindow.focus();
15152 if (typeof sel != "undefined") {
15154 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15156 return this.doc.createRange();
15159 return this.doc.createRange();
15162 getParentElement: function()
15165 this.assignDocWin();
15166 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15168 var range = this.createRange(sel);
15171 var p = range.commonAncestorContainer;
15172 while (p.nodeType == 3) { // text node
15183 * Range intersection.. the hard stuff...
15187 * [ -- selected range --- ]
15191 * if end is before start or hits it. fail.
15192 * if start is after end or hits it fail.
15194 * if either hits (but other is outside. - then it's not
15200 // @see http://www.thismuchiknow.co.uk/?p=64.
15201 rangeIntersectsNode : function(range, node)
15203 var nodeRange = node.ownerDocument.createRange();
15205 nodeRange.selectNode(node);
15207 nodeRange.selectNodeContents(node);
15210 var rangeStartRange = range.cloneRange();
15211 rangeStartRange.collapse(true);
15213 var rangeEndRange = range.cloneRange();
15214 rangeEndRange.collapse(false);
15216 var nodeStartRange = nodeRange.cloneRange();
15217 nodeStartRange.collapse(true);
15219 var nodeEndRange = nodeRange.cloneRange();
15220 nodeEndRange.collapse(false);
15222 return rangeStartRange.compareBoundaryPoints(
15223 Range.START_TO_START, nodeEndRange) == -1 &&
15224 rangeEndRange.compareBoundaryPoints(
15225 Range.START_TO_START, nodeStartRange) == 1;
15229 rangeCompareNode : function(range, node)
15231 var nodeRange = node.ownerDocument.createRange();
15233 nodeRange.selectNode(node);
15235 nodeRange.selectNodeContents(node);
15239 range.collapse(true);
15241 nodeRange.collapse(true);
15243 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15244 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15246 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15248 var nodeIsBefore = ss == 1;
15249 var nodeIsAfter = ee == -1;
15251 if (nodeIsBefore && nodeIsAfter)
15253 if (!nodeIsBefore && nodeIsAfter)
15254 return 1; //right trailed.
15256 if (nodeIsBefore && !nodeIsAfter)
15257 return 2; // left trailed.
15262 // private? - in a new class?
15263 cleanUpPaste : function()
15265 // cleans up the whole document..
15266 Roo.log('cleanuppaste');
15268 this.cleanUpChildren(this.doc.body);
15269 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15270 if (clean != this.doc.body.innerHTML) {
15271 this.doc.body.innerHTML = clean;
15276 cleanWordChars : function(input) {// change the chars to hex code
15277 var he = Roo.HtmlEditorCore;
15279 var output = input;
15280 Roo.each(he.swapCodes, function(sw) {
15281 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15283 output = output.replace(swapper, sw[1]);
15290 cleanUpChildren : function (n)
15292 if (!n.childNodes.length) {
15295 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15296 this.cleanUpChild(n.childNodes[i]);
15303 cleanUpChild : function (node)
15306 //console.log(node);
15307 if (node.nodeName == "#text") {
15308 // clean up silly Windows -- stuff?
15311 if (node.nodeName == "#comment") {
15312 node.parentNode.removeChild(node);
15313 // clean up silly Windows -- stuff?
15317 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15319 node.parentNode.removeChild(node);
15324 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15326 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15327 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15329 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15330 // remove_keep_children = true;
15333 if (remove_keep_children) {
15334 this.cleanUpChildren(node);
15335 // inserts everything just before this node...
15336 while (node.childNodes.length) {
15337 var cn = node.childNodes[0];
15338 node.removeChild(cn);
15339 node.parentNode.insertBefore(cn, node);
15341 node.parentNode.removeChild(node);
15345 if (!node.attributes || !node.attributes.length) {
15346 this.cleanUpChildren(node);
15350 function cleanAttr(n,v)
15353 if (v.match(/^\./) || v.match(/^\//)) {
15356 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15359 if (v.match(/^#/)) {
15362 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15363 node.removeAttribute(n);
15367 function cleanStyle(n,v)
15369 if (v.match(/expression/)) { //XSS?? should we even bother..
15370 node.removeAttribute(n);
15373 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15374 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15377 var parts = v.split(/;/);
15380 Roo.each(parts, function(p) {
15381 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15385 var l = p.split(':').shift().replace(/\s+/g,'');
15386 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15388 if ( cblack.indexOf(l) > -1) {
15389 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15390 //node.removeAttribute(n);
15394 // only allow 'c whitelisted system attributes'
15395 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15396 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15397 //node.removeAttribute(n);
15407 if (clean.length) {
15408 node.setAttribute(n, clean.join(';'));
15410 node.removeAttribute(n);
15416 for (var i = node.attributes.length-1; i > -1 ; i--) {
15417 var a = node.attributes[i];
15420 if (a.name.toLowerCase().substr(0,2)=='on') {
15421 node.removeAttribute(a.name);
15424 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15425 node.removeAttribute(a.name);
15428 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15429 cleanAttr(a.name,a.value); // fixme..
15432 if (a.name == 'style') {
15433 cleanStyle(a.name,a.value);
15436 /// clean up MS crap..
15437 // tecnically this should be a list of valid class'es..
15440 if (a.name == 'class') {
15441 if (a.value.match(/^Mso/)) {
15442 node.className = '';
15445 if (a.value.match(/body/)) {
15446 node.className = '';
15457 this.cleanUpChildren(node);
15462 * Clean up MS wordisms...
15464 cleanWord : function(node)
15467 var cleanWordChildren = function()
15469 if (!node.childNodes.length) {
15472 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15473 _t.cleanWord(node.childNodes[i]);
15479 this.cleanWord(this.doc.body);
15482 if (node.nodeName == "#text") {
15483 // clean up silly Windows -- stuff?
15486 if (node.nodeName == "#comment") {
15487 node.parentNode.removeChild(node);
15488 // clean up silly Windows -- stuff?
15492 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15493 node.parentNode.removeChild(node);
15497 // remove - but keep children..
15498 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15499 while (node.childNodes.length) {
15500 var cn = node.childNodes[0];
15501 node.removeChild(cn);
15502 node.parentNode.insertBefore(cn, node);
15504 node.parentNode.removeChild(node);
15505 cleanWordChildren();
15509 if (node.className.length) {
15511 var cn = node.className.split(/\W+/);
15513 Roo.each(cn, function(cls) {
15514 if (cls.match(/Mso[a-zA-Z]+/)) {
15519 node.className = cna.length ? cna.join(' ') : '';
15521 node.removeAttribute("class");
15525 if (node.hasAttribute("lang")) {
15526 node.removeAttribute("lang");
15529 if (node.hasAttribute("style")) {
15531 var styles = node.getAttribute("style").split(";");
15533 Roo.each(styles, function(s) {
15534 if (!s.match(/:/)) {
15537 var kv = s.split(":");
15538 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15541 // what ever is left... we allow.
15544 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15545 if (!nstyle.length) {
15546 node.removeAttribute('style');
15550 cleanWordChildren();
15554 domToHTML : function(currentElement, depth, nopadtext) {
15556 depth = depth || 0;
15557 nopadtext = nopadtext || false;
15559 if (!currentElement) {
15560 return this.domToHTML(this.doc.body);
15563 //Roo.log(currentElement);
15565 var allText = false;
15566 var nodeName = currentElement.nodeName;
15567 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15569 if (nodeName == '#text') {
15570 return currentElement.nodeValue;
15575 if (nodeName != 'BODY') {
15578 // Prints the node tagName, such as <A>, <IMG>, etc
15581 for(i = 0; i < currentElement.attributes.length;i++) {
15583 var aname = currentElement.attributes.item(i).name;
15584 if (!currentElement.attributes.item(i).value.length) {
15587 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15590 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15599 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15602 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15607 // Traverse the tree
15609 var currentElementChild = currentElement.childNodes.item(i);
15610 var allText = true;
15611 var innerHTML = '';
15613 while (currentElementChild) {
15614 // Formatting code (indent the tree so it looks nice on the screen)
15615 var nopad = nopadtext;
15616 if (lastnode == 'SPAN') {
15620 if (currentElementChild.nodeName == '#text') {
15621 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15622 if (!nopad && toadd.length > 80) {
15623 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15625 innerHTML += toadd;
15628 currentElementChild = currentElement.childNodes.item(i);
15634 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15636 // Recursively traverse the tree structure of the child node
15637 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15638 lastnode = currentElementChild.nodeName;
15640 currentElementChild=currentElement.childNodes.item(i);
15646 // The remaining code is mostly for formatting the tree
15647 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15652 ret+= "</"+tagName+">";
15658 // hide stuff that is not compatible
15672 * @event specialkey
15676 * @cfg {String} fieldClass @hide
15679 * @cfg {String} focusClass @hide
15682 * @cfg {String} autoCreate @hide
15685 * @cfg {String} inputType @hide
15688 * @cfg {String} invalidClass @hide
15691 * @cfg {String} invalidText @hide
15694 * @cfg {String} msgFx @hide
15697 * @cfg {String} validateOnBlur @hide
15701 Roo.HtmlEditorCore.white = [
15702 'area', 'br', 'img', 'input', 'hr', 'wbr',
15704 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15705 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15706 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15707 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15708 'table', 'ul', 'xmp',
15710 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15713 'dir', 'menu', 'ol', 'ul', 'dl',
15719 Roo.HtmlEditorCore.black = [
15720 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15722 'base', 'basefont', 'bgsound', 'blink', 'body',
15723 'frame', 'frameset', 'head', 'html', 'ilayer',
15724 'iframe', 'layer', 'link', 'meta', 'object',
15725 'script', 'style' ,'title', 'xml' // clean later..
15727 Roo.HtmlEditorCore.clean = [
15728 'script', 'style', 'title', 'xml'
15730 Roo.HtmlEditorCore.remove = [
15735 Roo.HtmlEditorCore.ablack = [
15739 Roo.HtmlEditorCore.aclean = [
15740 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15744 Roo.HtmlEditorCore.pwhite= [
15745 'http', 'https', 'mailto'
15748 // white listed style attributes.
15749 Roo.HtmlEditorCore.cwhite= [
15750 // 'text-align', /// default is to allow most things..
15756 // black listed style attributes.
15757 Roo.HtmlEditorCore.cblack= [
15758 // 'font-size' -- this can be set by the project
15762 Roo.HtmlEditorCore.swapCodes =[
15781 * @class Roo.bootstrap.HtmlEditor
15782 * @extends Roo.bootstrap.TextArea
15783 * Bootstrap HtmlEditor class
15786 * Create a new HtmlEditor
15787 * @param {Object} config The config object
15790 Roo.bootstrap.HtmlEditor = function(config){
15791 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15792 if (!this.toolbars) {
15793 this.toolbars = [];
15795 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15798 * @event initialize
15799 * Fires when the editor is fully initialized (including the iframe)
15800 * @param {HtmlEditor} this
15805 * Fires when the editor is first receives the focus. Any insertion must wait
15806 * until after this event.
15807 * @param {HtmlEditor} this
15811 * @event beforesync
15812 * Fires before the textarea is updated with content from the editor iframe. Return false
15813 * to cancel the sync.
15814 * @param {HtmlEditor} this
15815 * @param {String} html
15819 * @event beforepush
15820 * Fires before the iframe editor is updated with content from the textarea. Return false
15821 * to cancel the push.
15822 * @param {HtmlEditor} this
15823 * @param {String} html
15828 * Fires when the textarea is updated with content from the editor iframe.
15829 * @param {HtmlEditor} this
15830 * @param {String} html
15835 * Fires when the iframe editor is updated with content from the textarea.
15836 * @param {HtmlEditor} this
15837 * @param {String} html
15841 * @event editmodechange
15842 * Fires when the editor switches edit modes
15843 * @param {HtmlEditor} this
15844 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15846 editmodechange: true,
15848 * @event editorevent
15849 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15850 * @param {HtmlEditor} this
15854 * @event firstfocus
15855 * Fires when on first focus - needed by toolbars..
15856 * @param {HtmlEditor} this
15861 * Auto save the htmlEditor value as a file into Events
15862 * @param {HtmlEditor} this
15866 * @event savedpreview
15867 * preview the saved version of htmlEditor
15868 * @param {HtmlEditor} this
15875 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15879 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15884 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15889 * @cfg {Number} height (in pixels)
15893 * @cfg {Number} width (in pixels)
15898 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15901 stylesheets: false,
15906 // private properties
15907 validationEvent : false,
15909 initialized : false,
15912 onFocus : Roo.emptyFn,
15914 hideMode:'offsets',
15917 tbContainer : false,
15919 toolbarContainer :function() {
15920 return this.wrap.select('.x-html-editor-tb',true).first();
15924 * Protected method that will not generally be called directly. It
15925 * is called when the editor creates its toolbar. Override this method if you need to
15926 * add custom toolbar buttons.
15927 * @param {HtmlEditor} editor
15929 createToolbar : function(){
15931 Roo.log("create toolbars");
15933 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15934 this.toolbars[0].render(this.toolbarContainer());
15938 // if (!editor.toolbars || !editor.toolbars.length) {
15939 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15942 // for (var i =0 ; i < editor.toolbars.length;i++) {
15943 // editor.toolbars[i] = Roo.factory(
15944 // typeof(editor.toolbars[i]) == 'string' ?
15945 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15946 // Roo.bootstrap.HtmlEditor);
15947 // editor.toolbars[i].init(editor);
15953 onRender : function(ct, position)
15955 // Roo.log("Call onRender: " + this.xtype);
15957 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15959 this.wrap = this.inputEl().wrap({
15960 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15963 this.editorcore.onRender(ct, position);
15965 if (this.resizable) {
15966 this.resizeEl = new Roo.Resizable(this.wrap, {
15970 minHeight : this.height,
15971 height: this.height,
15972 handles : this.resizable,
15975 resize : function(r, w, h) {
15976 _t.onResize(w,h); // -something
15982 this.createToolbar(this);
15985 if(!this.width && this.resizable){
15986 this.setSize(this.wrap.getSize());
15988 if (this.resizeEl) {
15989 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15990 // should trigger onReize..
15996 onResize : function(w, h)
15998 Roo.log('resize: ' +w + ',' + h );
15999 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16003 if(this.inputEl() ){
16004 if(typeof w == 'number'){
16005 var aw = w - this.wrap.getFrameWidth('lr');
16006 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16009 if(typeof h == 'number'){
16010 var tbh = -11; // fixme it needs to tool bar size!
16011 for (var i =0; i < this.toolbars.length;i++) {
16012 // fixme - ask toolbars for heights?
16013 tbh += this.toolbars[i].el.getHeight();
16014 //if (this.toolbars[i].footer) {
16015 // tbh += this.toolbars[i].footer.el.getHeight();
16023 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16024 ah -= 5; // knock a few pixes off for look..
16025 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16029 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16030 this.editorcore.onResize(ew,eh);
16035 * Toggles the editor between standard and source edit mode.
16036 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16038 toggleSourceEdit : function(sourceEditMode)
16040 this.editorcore.toggleSourceEdit(sourceEditMode);
16042 if(this.editorcore.sourceEditMode){
16043 Roo.log('editor - showing textarea');
16046 // Roo.log(this.syncValue());
16048 this.inputEl().removeClass('hide');
16049 this.inputEl().dom.removeAttribute('tabIndex');
16050 this.inputEl().focus();
16052 Roo.log('editor - hiding textarea');
16054 // Roo.log(this.pushValue());
16057 this.inputEl().addClass('hide');
16058 this.inputEl().dom.setAttribute('tabIndex', -1);
16059 //this.deferFocus();
16062 if(this.resizable){
16063 this.setSize(this.wrap.getSize());
16066 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16069 // private (for BoxComponent)
16070 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16072 // private (for BoxComponent)
16073 getResizeEl : function(){
16077 // private (for BoxComponent)
16078 getPositionEl : function(){
16083 initEvents : function(){
16084 this.originalValue = this.getValue();
16088 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16091 // markInvalid : Roo.emptyFn,
16093 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16096 // clearInvalid : Roo.emptyFn,
16098 setValue : function(v){
16099 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16100 this.editorcore.pushValue();
16105 deferFocus : function(){
16106 this.focus.defer(10, this);
16110 focus : function(){
16111 this.editorcore.focus();
16117 onDestroy : function(){
16123 for (var i =0; i < this.toolbars.length;i++) {
16124 // fixme - ask toolbars for heights?
16125 this.toolbars[i].onDestroy();
16128 this.wrap.dom.innerHTML = '';
16129 this.wrap.remove();
16134 onFirstFocus : function(){
16135 //Roo.log("onFirstFocus");
16136 this.editorcore.onFirstFocus();
16137 for (var i =0; i < this.toolbars.length;i++) {
16138 this.toolbars[i].onFirstFocus();
16144 syncValue : function()
16146 this.editorcore.syncValue();
16149 pushValue : function()
16151 this.editorcore.pushValue();
16155 // hide stuff that is not compatible
16169 * @event specialkey
16173 * @cfg {String} fieldClass @hide
16176 * @cfg {String} focusClass @hide
16179 * @cfg {String} autoCreate @hide
16182 * @cfg {String} inputType @hide
16185 * @cfg {String} invalidClass @hide
16188 * @cfg {String} invalidText @hide
16191 * @cfg {String} msgFx @hide
16194 * @cfg {String} validateOnBlur @hide
16205 * @class Roo.bootstrap.HtmlEditorToolbar1
16210 new Roo.bootstrap.HtmlEditor({
16213 new Roo.bootstrap.HtmlEditorToolbar1({
16214 disable : { fonts: 1 , format: 1, ..., ... , ...],
16220 * @cfg {Object} disable List of elements to disable..
16221 * @cfg {Array} btns List of additional buttons.
16225 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16228 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
16231 Roo.apply(this, config);
16233 // default disabled, based on 'good practice'..
16234 this.disable = this.disable || {};
16235 Roo.applyIf(this.disable, {
16238 specialElements : true
16240 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
16242 this.editor = config.editor;
16243 this.editorcore = config.editor.editorcore;
16245 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16247 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16248 // dont call parent... till later.
16250 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16256 editorcore : false,
16261 "h1","h2","h3","h4","h5","h6",
16263 "abbr", "acronym", "address", "cite", "samp", "var",
16267 onRender : function(ct, position)
16269 // Roo.log("Call onRender: " + this.xtype);
16271 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16273 this.el.dom.style.marginBottom = '0';
16275 var editorcore = this.editorcore;
16276 var editor= this.editor;
16279 var btn = function(id,cmd , toggle, handler){
16281 var event = toggle ? 'toggle' : 'click';
16286 xns: Roo.bootstrap,
16289 enableToggle:toggle !== false,
16291 pressed : toggle ? false : null,
16294 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16295 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16304 xns: Roo.bootstrap,
16305 glyphicon : 'font',
16309 xns: Roo.bootstrap,
16313 Roo.each(this.formats, function(f) {
16314 style.menu.items.push({
16316 xns: Roo.bootstrap,
16317 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16322 editorcore.insertTag(this.tagname);
16329 children.push(style);
16332 btn('bold',false,true);
16333 btn('italic',false,true);
16334 btn('align-left', 'justifyleft',true);
16335 btn('align-center', 'justifycenter',true);
16336 btn('align-right' , 'justifyright',true);
16337 btn('link', false, false, function(btn) {
16338 //Roo.log("create link?");
16339 var url = prompt(this.createLinkText, this.defaultLinkValue);
16340 if(url && url != 'http:/'+'/'){
16341 this.editorcore.relayCmd('createlink', url);
16344 btn('list','insertunorderedlist',true);
16345 btn('pencil', false,true, function(btn){
16348 this.toggleSourceEdit(btn.pressed);
16354 xns: Roo.bootstrap,
16359 xns: Roo.bootstrap,
16364 cog.menu.items.push({
16366 xns: Roo.bootstrap,
16367 html : Clean styles,
16372 editorcore.insertTag(this.tagname);
16381 this.xtype = 'NavSimplebar';
16383 for(var i=0;i< children.length;i++) {
16385 this.buttons.add(this.addxtypeChild(children[i]));
16389 editor.on('editorevent', this.updateToolbar, this);
16391 onBtnClick : function(id)
16393 this.editorcore.relayCmd(id);
16394 this.editorcore.focus();
16398 * Protected method that will not generally be called directly. It triggers
16399 * a toolbar update by reading the markup state of the current selection in the editor.
16401 updateToolbar: function(){
16403 if(!this.editorcore.activated){
16404 this.editor.onFirstFocus(); // is this neeed?
16408 var btns = this.buttons;
16409 var doc = this.editorcore.doc;
16410 btns.get('bold').setActive(doc.queryCommandState('bold'));
16411 btns.get('italic').setActive(doc.queryCommandState('italic'));
16412 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16414 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16415 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16416 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16418 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16419 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16422 var ans = this.editorcore.getAllAncestors();
16423 if (this.formatCombo) {
16426 var store = this.formatCombo.store;
16427 this.formatCombo.setValue("");
16428 for (var i =0; i < ans.length;i++) {
16429 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16431 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16439 // hides menus... - so this cant be on a menu...
16440 Roo.bootstrap.MenuMgr.hideAll();
16442 Roo.bootstrap.MenuMgr.hideAll();
16443 //this.editorsyncValue();
16445 onFirstFocus: function() {
16446 this.buttons.each(function(item){
16450 toggleSourceEdit : function(sourceEditMode){
16453 if(sourceEditMode){
16454 Roo.log("disabling buttons");
16455 this.buttons.each( function(item){
16456 if(item.cmd != 'pencil'){
16462 Roo.log("enabling buttons");
16463 if(this.editorcore.initialized){
16464 this.buttons.each( function(item){
16470 Roo.log("calling toggole on editor");
16471 // tell the editor that it's been pressed..
16472 this.editor.toggleSourceEdit(sourceEditMode);
16482 * @class Roo.bootstrap.Table.AbstractSelectionModel
16483 * @extends Roo.util.Observable
16484 * Abstract base class for grid SelectionModels. It provides the interface that should be
16485 * implemented by descendant classes. This class should not be directly instantiated.
16488 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16489 this.locked = false;
16490 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16494 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16495 /** @ignore Called by the grid automatically. Do not call directly. */
16496 init : function(grid){
16502 * Locks the selections.
16505 this.locked = true;
16509 * Unlocks the selections.
16511 unlock : function(){
16512 this.locked = false;
16516 * Returns true if the selections are locked.
16517 * @return {Boolean}
16519 isLocked : function(){
16520 return this.locked;
16524 * @class Roo.bootstrap.Table.ColumnModel
16525 * @extends Roo.util.Observable
16526 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16527 * the columns in the table.
16530 * @param {Object} config An Array of column config objects. See this class's
16531 * config objects for details.
16533 Roo.bootstrap.Table.ColumnModel = function(config){
16535 * The config passed into the constructor
16537 this.config = config;
16540 // if no id, create one
16541 // if the column does not have a dataIndex mapping,
16542 // map it to the order it is in the config
16543 for(var i = 0, len = config.length; i < len; i++){
16545 if(typeof c.dataIndex == "undefined"){
16548 if(typeof c.renderer == "string"){
16549 c.renderer = Roo.util.Format[c.renderer];
16551 if(typeof c.id == "undefined"){
16554 // if(c.editor && c.editor.xtype){
16555 // c.editor = Roo.factory(c.editor, Roo.grid);
16557 // if(c.editor && c.editor.isFormField){
16558 // c.editor = new Roo.grid.GridEditor(c.editor);
16561 this.lookup[c.id] = c;
16565 * The width of columns which have no width specified (defaults to 100)
16568 this.defaultWidth = 100;
16571 * Default sortable of columns which have no sortable specified (defaults to false)
16574 this.defaultSortable = false;
16578 * @event widthchange
16579 * Fires when the width of a column changes.
16580 * @param {ColumnModel} this
16581 * @param {Number} columnIndex The column index
16582 * @param {Number} newWidth The new width
16584 "widthchange": true,
16586 * @event headerchange
16587 * Fires when the text of a header changes.
16588 * @param {ColumnModel} this
16589 * @param {Number} columnIndex The column index
16590 * @param {Number} newText The new header text
16592 "headerchange": true,
16594 * @event hiddenchange
16595 * Fires when a column is hidden or "unhidden".
16596 * @param {ColumnModel} this
16597 * @param {Number} columnIndex The column index
16598 * @param {Boolean} hidden true if hidden, false otherwise
16600 "hiddenchange": true,
16602 * @event columnmoved
16603 * Fires when a column is moved.
16604 * @param {ColumnModel} this
16605 * @param {Number} oldIndex
16606 * @param {Number} newIndex
16608 "columnmoved" : true,
16610 * @event columlockchange
16611 * Fires when a column's locked state is changed
16612 * @param {ColumnModel} this
16613 * @param {Number} colIndex
16614 * @param {Boolean} locked true if locked
16616 "columnlockchange" : true
16618 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16620 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16622 * @cfg {String} header The header text to display in the Grid view.
16625 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16626 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16627 * specified, the column's index is used as an index into the Record's data Array.
16630 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16631 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16634 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16635 * Defaults to the value of the {@link #defaultSortable} property.
16636 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16639 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16642 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16645 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16648 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16651 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16652 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16653 * default renderer uses the raw data value.
16656 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16660 * Returns the id of the column at the specified index.
16661 * @param {Number} index The column index
16662 * @return {String} the id
16664 getColumnId : function(index){
16665 return this.config[index].id;
16669 * Returns the column for a specified id.
16670 * @param {String} id The column id
16671 * @return {Object} the column
16673 getColumnById : function(id){
16674 return this.lookup[id];
16679 * Returns the column for a specified dataIndex.
16680 * @param {String} dataIndex The column dataIndex
16681 * @return {Object|Boolean} the column or false if not found
16683 getColumnByDataIndex: function(dataIndex){
16684 var index = this.findColumnIndex(dataIndex);
16685 return index > -1 ? this.config[index] : false;
16689 * Returns the index for a specified column id.
16690 * @param {String} id The column id
16691 * @return {Number} the index, or -1 if not found
16693 getIndexById : function(id){
16694 for(var i = 0, len = this.config.length; i < len; i++){
16695 if(this.config[i].id == id){
16703 * Returns the index for a specified column dataIndex.
16704 * @param {String} dataIndex The column dataIndex
16705 * @return {Number} the index, or -1 if not found
16708 findColumnIndex : function(dataIndex){
16709 for(var i = 0, len = this.config.length; i < len; i++){
16710 if(this.config[i].dataIndex == dataIndex){
16718 moveColumn : function(oldIndex, newIndex){
16719 var c = this.config[oldIndex];
16720 this.config.splice(oldIndex, 1);
16721 this.config.splice(newIndex, 0, c);
16722 this.dataMap = null;
16723 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16726 isLocked : function(colIndex){
16727 return this.config[colIndex].locked === true;
16730 setLocked : function(colIndex, value, suppressEvent){
16731 if(this.isLocked(colIndex) == value){
16734 this.config[colIndex].locked = value;
16735 if(!suppressEvent){
16736 this.fireEvent("columnlockchange", this, colIndex, value);
16740 getTotalLockedWidth : function(){
16741 var totalWidth = 0;
16742 for(var i = 0; i < this.config.length; i++){
16743 if(this.isLocked(i) && !this.isHidden(i)){
16744 this.totalWidth += this.getColumnWidth(i);
16750 getLockedCount : function(){
16751 for(var i = 0, len = this.config.length; i < len; i++){
16752 if(!this.isLocked(i)){
16759 * Returns the number of columns.
16762 getColumnCount : function(visibleOnly){
16763 if(visibleOnly === true){
16765 for(var i = 0, len = this.config.length; i < len; i++){
16766 if(!this.isHidden(i)){
16772 return this.config.length;
16776 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16777 * @param {Function} fn
16778 * @param {Object} scope (optional)
16779 * @return {Array} result
16781 getColumnsBy : function(fn, scope){
16783 for(var i = 0, len = this.config.length; i < len; i++){
16784 var c = this.config[i];
16785 if(fn.call(scope||this, c, i) === true){
16793 * Returns true if the specified column is sortable.
16794 * @param {Number} col The column index
16795 * @return {Boolean}
16797 isSortable : function(col){
16798 if(typeof this.config[col].sortable == "undefined"){
16799 return this.defaultSortable;
16801 return this.config[col].sortable;
16805 * Returns the rendering (formatting) function defined for the column.
16806 * @param {Number} col The column index.
16807 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16809 getRenderer : function(col){
16810 if(!this.config[col].renderer){
16811 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16813 return this.config[col].renderer;
16817 * Sets the rendering (formatting) function for a column.
16818 * @param {Number} col The column index
16819 * @param {Function} fn The function to use to process the cell's raw data
16820 * to return HTML markup for the grid view. The render function is called with
16821 * the following parameters:<ul>
16822 * <li>Data value.</li>
16823 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16824 * <li>css A CSS style string to apply to the table cell.</li>
16825 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16826 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16827 * <li>Row index</li>
16828 * <li>Column index</li>
16829 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16831 setRenderer : function(col, fn){
16832 this.config[col].renderer = fn;
16836 * Returns the width for the specified column.
16837 * @param {Number} col The column index
16840 getColumnWidth : function(col){
16841 return this.config[col].width * 1 || this.defaultWidth;
16845 * Sets the width for a column.
16846 * @param {Number} col The column index
16847 * @param {Number} width The new width
16849 setColumnWidth : function(col, width, suppressEvent){
16850 this.config[col].width = width;
16851 this.totalWidth = null;
16852 if(!suppressEvent){
16853 this.fireEvent("widthchange", this, col, width);
16858 * Returns the total width of all columns.
16859 * @param {Boolean} includeHidden True to include hidden column widths
16862 getTotalWidth : function(includeHidden){
16863 if(!this.totalWidth){
16864 this.totalWidth = 0;
16865 for(var i = 0, len = this.config.length; i < len; i++){
16866 if(includeHidden || !this.isHidden(i)){
16867 this.totalWidth += this.getColumnWidth(i);
16871 return this.totalWidth;
16875 * Returns the header for the specified column.
16876 * @param {Number} col The column index
16879 getColumnHeader : function(col){
16880 return this.config[col].header;
16884 * Sets the header for a column.
16885 * @param {Number} col The column index
16886 * @param {String} header The new header
16888 setColumnHeader : function(col, header){
16889 this.config[col].header = header;
16890 this.fireEvent("headerchange", this, col, header);
16894 * Returns the tooltip for the specified column.
16895 * @param {Number} col The column index
16898 getColumnTooltip : function(col){
16899 return this.config[col].tooltip;
16902 * Sets the tooltip for a column.
16903 * @param {Number} col The column index
16904 * @param {String} tooltip The new tooltip
16906 setColumnTooltip : function(col, tooltip){
16907 this.config[col].tooltip = tooltip;
16911 * Returns the dataIndex for the specified column.
16912 * @param {Number} col The column index
16915 getDataIndex : function(col){
16916 return this.config[col].dataIndex;
16920 * Sets the dataIndex for a column.
16921 * @param {Number} col The column index
16922 * @param {Number} dataIndex The new dataIndex
16924 setDataIndex : function(col, dataIndex){
16925 this.config[col].dataIndex = dataIndex;
16931 * Returns true if the cell is editable.
16932 * @param {Number} colIndex The column index
16933 * @param {Number} rowIndex The row index
16934 * @return {Boolean}
16936 isCellEditable : function(colIndex, rowIndex){
16937 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16941 * Returns the editor defined for the cell/column.
16942 * return false or null to disable editing.
16943 * @param {Number} colIndex The column index
16944 * @param {Number} rowIndex The row index
16947 getCellEditor : function(colIndex, rowIndex){
16948 return this.config[colIndex].editor;
16952 * Sets if a column is editable.
16953 * @param {Number} col The column index
16954 * @param {Boolean} editable True if the column is editable
16956 setEditable : function(col, editable){
16957 this.config[col].editable = editable;
16962 * Returns true if the column is hidden.
16963 * @param {Number} colIndex The column index
16964 * @return {Boolean}
16966 isHidden : function(colIndex){
16967 return this.config[colIndex].hidden;
16972 * Returns true if the column width cannot be changed
16974 isFixed : function(colIndex){
16975 return this.config[colIndex].fixed;
16979 * Returns true if the column can be resized
16980 * @return {Boolean}
16982 isResizable : function(colIndex){
16983 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16986 * Sets if a column is hidden.
16987 * @param {Number} colIndex The column index
16988 * @param {Boolean} hidden True if the column is hidden
16990 setHidden : function(colIndex, hidden){
16991 this.config[colIndex].hidden = hidden;
16992 this.totalWidth = null;
16993 this.fireEvent("hiddenchange", this, colIndex, hidden);
16997 * Sets the editor for a column.
16998 * @param {Number} col The column index
16999 * @param {Object} editor The editor object
17001 setEditor : function(col, editor){
17002 this.config[col].editor = editor;
17006 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
17007 if(typeof value == "string" && value.length < 1){
17013 // Alias for backwards compatibility
17014 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
17017 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17018 * @class Roo.bootstrap.Table.RowSelectionModel
17019 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17020 * It supports multiple selections and keyboard selection/navigation.
17022 * @param {Object} config
17025 Roo.bootstrap.Table.RowSelectionModel = function(config){
17026 Roo.apply(this, config);
17027 this.selections = new Roo.util.MixedCollection(false, function(o){
17032 this.lastActive = false;
17036 * @event selectionchange
17037 * Fires when the selection changes
17038 * @param {SelectionModel} this
17040 "selectionchange" : true,
17042 * @event afterselectionchange
17043 * Fires after the selection changes (eg. by key press or clicking)
17044 * @param {SelectionModel} this
17046 "afterselectionchange" : true,
17048 * @event beforerowselect
17049 * Fires when a row is selected being selected, return false to cancel.
17050 * @param {SelectionModel} this
17051 * @param {Number} rowIndex The selected index
17052 * @param {Boolean} keepExisting False if other selections will be cleared
17054 "beforerowselect" : true,
17057 * Fires when a row is selected.
17058 * @param {SelectionModel} this
17059 * @param {Number} rowIndex The selected index
17060 * @param {Roo.data.Record} r The record
17062 "rowselect" : true,
17064 * @event rowdeselect
17065 * Fires when a row is deselected.
17066 * @param {SelectionModel} this
17067 * @param {Number} rowIndex The selected index
17069 "rowdeselect" : true
17071 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17072 this.locked = false;
17075 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17077 * @cfg {Boolean} singleSelect
17078 * True to allow selection of only one row at a time (defaults to false)
17080 singleSelect : false,
17083 initEvents : function(){
17085 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17086 this.grid.on("mousedown", this.handleMouseDown, this);
17087 }else{ // allow click to work like normal
17088 this.grid.on("rowclick", this.handleDragableRowClick, this);
17091 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17092 "up" : function(e){
17094 this.selectPrevious(e.shiftKey);
17095 }else if(this.last !== false && this.lastActive !== false){
17096 var last = this.last;
17097 this.selectRange(this.last, this.lastActive-1);
17098 this.grid.getView().focusRow(this.lastActive);
17099 if(last !== false){
17103 this.selectFirstRow();
17105 this.fireEvent("afterselectionchange", this);
17107 "down" : function(e){
17109 this.selectNext(e.shiftKey);
17110 }else if(this.last !== false && this.lastActive !== false){
17111 var last = this.last;
17112 this.selectRange(this.last, this.lastActive+1);
17113 this.grid.getView().focusRow(this.lastActive);
17114 if(last !== false){
17118 this.selectFirstRow();
17120 this.fireEvent("afterselectionchange", this);
17125 var view = this.grid.view;
17126 view.on("refresh", this.onRefresh, this);
17127 view.on("rowupdated", this.onRowUpdated, this);
17128 view.on("rowremoved", this.onRemove, this);
17132 onRefresh : function(){
17133 var ds = this.grid.dataSource, i, v = this.grid.view;
17134 var s = this.selections;
17135 s.each(function(r){
17136 if((i = ds.indexOfId(r.id)) != -1){
17145 onRemove : function(v, index, r){
17146 this.selections.remove(r);
17150 onRowUpdated : function(v, index, r){
17151 if(this.isSelected(r)){
17152 v.onRowSelect(index);
17158 * @param {Array} records The records to select
17159 * @param {Boolean} keepExisting (optional) True to keep existing selections
17161 selectRecords : function(records, keepExisting){
17163 this.clearSelections();
17165 var ds = this.grid.dataSource;
17166 for(var i = 0, len = records.length; i < len; i++){
17167 this.selectRow(ds.indexOf(records[i]), true);
17172 * Gets the number of selected rows.
17175 getCount : function(){
17176 return this.selections.length;
17180 * Selects the first row in the grid.
17182 selectFirstRow : function(){
17187 * Select the last row.
17188 * @param {Boolean} keepExisting (optional) True to keep existing selections
17190 selectLastRow : function(keepExisting){
17191 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17195 * Selects the row immediately following the last selected row.
17196 * @param {Boolean} keepExisting (optional) True to keep existing selections
17198 selectNext : function(keepExisting){
17199 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17200 this.selectRow(this.last+1, keepExisting);
17201 this.grid.getView().focusRow(this.last);
17206 * Selects the row that precedes the last selected row.
17207 * @param {Boolean} keepExisting (optional) True to keep existing selections
17209 selectPrevious : function(keepExisting){
17211 this.selectRow(this.last-1, keepExisting);
17212 this.grid.getView().focusRow(this.last);
17217 * Returns the selected records
17218 * @return {Array} Array of selected records
17220 getSelections : function(){
17221 return [].concat(this.selections.items);
17225 * Returns the first selected record.
17228 getSelected : function(){
17229 return this.selections.itemAt(0);
17234 * Clears all selections.
17236 clearSelections : function(fast){
17237 if(this.locked) return;
17239 var ds = this.grid.dataSource;
17240 var s = this.selections;
17241 s.each(function(r){
17242 this.deselectRow(ds.indexOfId(r.id));
17246 this.selections.clear();
17253 * Selects all rows.
17255 selectAll : function(){
17256 if(this.locked) return;
17257 this.selections.clear();
17258 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17259 this.selectRow(i, true);
17264 * Returns True if there is a selection.
17265 * @return {Boolean}
17267 hasSelection : function(){
17268 return this.selections.length > 0;
17272 * Returns True if the specified row is selected.
17273 * @param {Number/Record} record The record or index of the record to check
17274 * @return {Boolean}
17276 isSelected : function(index){
17277 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17278 return (r && this.selections.key(r.id) ? true : false);
17282 * Returns True if the specified record id is selected.
17283 * @param {String} id The id of record to check
17284 * @return {Boolean}
17286 isIdSelected : function(id){
17287 return (this.selections.key(id) ? true : false);
17291 handleMouseDown : function(e, t){
17292 var view = this.grid.getView(), rowIndex;
17293 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17296 if(e.shiftKey && this.last !== false){
17297 var last = this.last;
17298 this.selectRange(last, rowIndex, e.ctrlKey);
17299 this.last = last; // reset the last
17300 view.focusRow(rowIndex);
17302 var isSelected = this.isSelected(rowIndex);
17303 if(e.button !== 0 && isSelected){
17304 view.focusRow(rowIndex);
17305 }else if(e.ctrlKey && isSelected){
17306 this.deselectRow(rowIndex);
17307 }else if(!isSelected){
17308 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17309 view.focusRow(rowIndex);
17312 this.fireEvent("afterselectionchange", this);
17315 handleDragableRowClick : function(grid, rowIndex, e)
17317 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17318 this.selectRow(rowIndex, false);
17319 grid.view.focusRow(rowIndex);
17320 this.fireEvent("afterselectionchange", this);
17325 * Selects multiple rows.
17326 * @param {Array} rows Array of the indexes of the row to select
17327 * @param {Boolean} keepExisting (optional) True to keep existing selections
17329 selectRows : function(rows, keepExisting){
17331 this.clearSelections();
17333 for(var i = 0, len = rows.length; i < len; i++){
17334 this.selectRow(rows[i], true);
17339 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17340 * @param {Number} startRow The index of the first row in the range
17341 * @param {Number} endRow The index of the last row in the range
17342 * @param {Boolean} keepExisting (optional) True to retain existing selections
17344 selectRange : function(startRow, endRow, keepExisting){
17345 if(this.locked) return;
17347 this.clearSelections();
17349 if(startRow <= endRow){
17350 for(var i = startRow; i <= endRow; i++){
17351 this.selectRow(i, true);
17354 for(var i = startRow; i >= endRow; i--){
17355 this.selectRow(i, true);
17361 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17362 * @param {Number} startRow The index of the first row in the range
17363 * @param {Number} endRow The index of the last row in the range
17365 deselectRange : function(startRow, endRow, preventViewNotify){
17366 if(this.locked) return;
17367 for(var i = startRow; i <= endRow; i++){
17368 this.deselectRow(i, preventViewNotify);
17374 * @param {Number} row The index of the row to select
17375 * @param {Boolean} keepExisting (optional) True to keep existing selections
17377 selectRow : function(index, keepExisting, preventViewNotify){
17378 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17379 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17380 if(!keepExisting || this.singleSelect){
17381 this.clearSelections();
17383 var r = this.grid.dataSource.getAt(index);
17384 this.selections.add(r);
17385 this.last = this.lastActive = index;
17386 if(!preventViewNotify){
17387 this.grid.getView().onRowSelect(index);
17389 this.fireEvent("rowselect", this, index, r);
17390 this.fireEvent("selectionchange", this);
17396 * @param {Number} row The index of the row to deselect
17398 deselectRow : function(index, preventViewNotify){
17399 if(this.locked) return;
17400 if(this.last == index){
17403 if(this.lastActive == index){
17404 this.lastActive = false;
17406 var r = this.grid.dataSource.getAt(index);
17407 this.selections.remove(r);
17408 if(!preventViewNotify){
17409 this.grid.getView().onRowDeselect(index);
17411 this.fireEvent("rowdeselect", this, index);
17412 this.fireEvent("selectionchange", this);
17416 restoreLast : function(){
17418 this.last = this._last;
17423 acceptsNav : function(row, col, cm){
17424 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17428 onEditorKey : function(field, e){
17429 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17434 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17436 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17438 }else if(k == e.ENTER && !e.ctrlKey){
17442 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17444 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17446 }else if(k == e.ESC){
17450 g.startEditing(newCell[0], newCell[1]);
17461 * @class Roo.bootstrap.MessageBar
17462 * @extends Roo.bootstrap.Component
17463 * Bootstrap MessageBar class
17464 * @cfg {String} html contents of the MessageBar
17465 * @cfg {String} weight (info | success | warning | danger) default info
17466 * @cfg {String} beforeClass insert the bar before the given class
17467 * @cfg {Boolean} closable (true | false) default false
17468 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17471 * Create a new Element
17472 * @param {Object} config The config object
17475 Roo.bootstrap.MessageBar = function(config){
17476 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17479 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17485 beforeClass: 'bootstrap-sticky-wrap',
17487 getAutoCreate : function(){
17491 cls: 'alert alert-dismissable alert-' + this.weight,
17496 html: this.html || ''
17502 cfg.cls += ' alert-messages-fixed';
17516 onRender : function(ct, position)
17518 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17521 var cfg = Roo.apply({}, this.getAutoCreate());
17525 cfg.cls += ' ' + this.cls;
17528 cfg.style = this.style;
17530 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17532 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17535 this.el.select('>button.close').on('click', this.hide, this);
17541 if (!this.rendered) {
17547 this.fireEvent('show', this);
17553 if (!this.rendered) {
17559 this.fireEvent('hide', this);
17562 update : function()
17564 // var e = this.el.dom.firstChild;
17566 // if(this.closable){
17567 // e = e.nextSibling;
17570 // e.data = this.html || '';
17572 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';