4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
972 * @class Roo.bootstrap.Img
973 * @extends Roo.bootstrap.Component
974 * Bootstrap Img class
975 * @cfg {Boolean} imgResponsive false | true
976 * @cfg {String} border rounded | circle | thumbnail
977 * @cfg {String} src image source
978 * @cfg {String} alt image alternative text
979 * @cfg {String} href a tag href
980 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
984 * @param {Object} config The config object
987 Roo.bootstrap.Img = function(config){
988 Roo.bootstrap.Img.superclass.constructor.call(this, config);
994 * The img click event for the img.
995 * @param {Roo.EventObject} e
1001 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1003 imgResponsive: true,
1009 getAutoCreate : function(){
1013 cls: (this.imgResponsive) ? 'img-responsive' : '',
1017 cfg.html = this.html || cfg.html;
1019 cfg.src = this.src || cfg.src;
1021 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1022 cfg.cls += ' img-' + this.border;
1039 a.target = this.target;
1045 return (this.href) ? a : cfg;
1048 initEvents: function() {
1051 this.el.on('click', this.onClick, this);
1055 onClick : function(e)
1057 Roo.log('img onclick');
1058 this.fireEvent('click', this, e);
1072 * @class Roo.bootstrap.Link
1073 * @extends Roo.bootstrap.Component
1074 * Bootstrap Link Class
1075 * @cfg {String} alt image alternative text
1076 * @cfg {String} href a tag href
1077 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1078 * @cfg {String} html the content of the link.
1082 * Create a new Input
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Link = function(config){
1087 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1093 * The img click event for the img.
1094 * @param {Roo.EventObject} e
1100 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1105 getAutoCreate : function(){
1109 html : this.html || 'html-missing'
1116 cfg.href = this.href || '#';
1118 cfg.target = this.target;
1124 initEvents: function() {
1127 this.el.on('click', this.onClick, this);
1131 onClick : function(e)
1133 //Roo.log('img onclick');
1134 this.fireEvent('click', this, e);
1147 * @class Roo.bootstrap.Header
1148 * @extends Roo.bootstrap.Component
1149 * Bootstrap Header class
1150 * @cfg {String} html content of header
1151 * @cfg {Number} level (1|2|3|4|5|6) default 1
1154 * Create a new Header
1155 * @param {Object} config The config object
1159 Roo.bootstrap.Header = function(config){
1160 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1163 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1171 getAutoCreate : function(){
1174 tag: 'h' + (1 *this.level),
1175 html: this.html || 'fill in html'
1187 * Ext JS Library 1.1.1
1188 * Copyright(c) 2006-2007, Ext JS, LLC.
1190 * Originally Released Under LGPL - original licence link has changed is not relivant.
1193 * <script type="text/javascript">
1197 * @class Roo.bootstrap.MenuMgr
1198 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1201 Roo.bootstrap.MenuMgr = function(){
1202 var menus, active, groups = {}, attached = false, lastShow = new Date();
1204 // private - called when first menu is created
1207 active = new Roo.util.MixedCollection();
1208 Roo.get(document).addKeyListener(27, function(){
1209 if(active.length > 0){
1217 if(active && active.length > 0){
1218 var c = active.clone();
1228 if(active.length < 1){
1229 Roo.get(document).un("mouseup", onMouseDown);
1237 var last = active.last();
1238 lastShow = new Date();
1241 Roo.get(document).on("mouseup", onMouseDown);
1246 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1247 m.parentMenu.activeChild = m;
1248 }else if(last && last.isVisible()){
1249 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1254 function onBeforeHide(m){
1256 m.activeChild.hide();
1258 if(m.autoHideTimer){
1259 clearTimeout(m.autoHideTimer);
1260 delete m.autoHideTimer;
1265 function onBeforeShow(m){
1266 var pm = m.parentMenu;
1267 if(!pm && !m.allowOtherMenus){
1269 }else if(pm && pm.activeChild && active != m){
1270 pm.activeChild.hide();
1275 function onMouseDown(e){
1276 Roo.log("on MouseDown");
1277 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1285 function onBeforeCheck(mi, state){
1287 var g = groups[mi.group];
1288 for(var i = 0, l = g.length; i < l; i++){
1290 g[i].setChecked(false);
1299 * Hides all menus that are currently visible
1301 hideAll : function(){
1306 register : function(menu){
1310 menus[menu.id] = menu;
1311 menu.on("beforehide", onBeforeHide);
1312 menu.on("hide", onHide);
1313 menu.on("beforeshow", onBeforeShow);
1314 menu.on("show", onShow);
1316 if(g && menu.events["checkchange"]){
1320 groups[g].push(menu);
1321 menu.on("checkchange", onCheck);
1326 * Returns a {@link Roo.menu.Menu} object
1327 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1328 * be used to generate and return a new Menu instance.
1330 get : function(menu){
1331 if(typeof menu == "string"){ // menu id
1333 }else if(menu.events){ // menu instance
1336 /*else if(typeof menu.length == 'number'){ // array of menu items?
1337 return new Roo.bootstrap.Menu({items:menu});
1338 }else{ // otherwise, must be a config
1339 return new Roo.bootstrap.Menu(menu);
1346 unregister : function(menu){
1347 delete menus[menu.id];
1348 menu.un("beforehide", onBeforeHide);
1349 menu.un("hide", onHide);
1350 menu.un("beforeshow", onBeforeShow);
1351 menu.un("show", onShow);
1353 if(g && menu.events["checkchange"]){
1354 groups[g].remove(menu);
1355 menu.un("checkchange", onCheck);
1360 registerCheckable : function(menuItem){
1361 var g = menuItem.group;
1366 groups[g].push(menuItem);
1367 menuItem.on("beforecheckchange", onBeforeCheck);
1372 unregisterCheckable : function(menuItem){
1373 var g = menuItem.group;
1375 groups[g].remove(menuItem);
1376 menuItem.un("beforecheckchange", onBeforeCheck);
1388 * @class Roo.bootstrap.Menu
1389 * @extends Roo.bootstrap.Component
1390 * Bootstrap Menu class - container for MenuItems
1391 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1395 * @param {Object} config The config object
1399 Roo.bootstrap.Menu = function(config){
1400 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1401 if (this.registerMenu) {
1402 Roo.bootstrap.MenuMgr.register(this);
1407 * Fires before this menu is displayed
1408 * @param {Roo.menu.Menu} this
1413 * Fires before this menu is hidden
1414 * @param {Roo.menu.Menu} this
1419 * Fires after this menu is displayed
1420 * @param {Roo.menu.Menu} this
1425 * Fires after this menu is hidden
1426 * @param {Roo.menu.Menu} this
1431 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1432 * @param {Roo.menu.Menu} this
1433 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1434 * @param {Roo.EventObject} e
1439 * Fires when the mouse is hovering over this menu
1440 * @param {Roo.menu.Menu} this
1441 * @param {Roo.EventObject} e
1442 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1447 * Fires when the mouse exits this menu
1448 * @param {Roo.menu.Menu} this
1449 * @param {Roo.EventObject} e
1450 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1455 * Fires when a menu item contained in this menu is clicked
1456 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1457 * @param {Roo.EventObject} e
1461 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1464 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1468 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1471 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1473 registerMenu : true,
1475 menuItems :false, // stores the menu items..
1481 getChildContainer : function() {
1485 getAutoCreate : function(){
1487 //if (['right'].indexOf(this.align)!==-1) {
1488 // cfg.cn[1].cls += ' pull-right'
1494 cls : 'dropdown-menu' ,
1495 style : 'z-index:1000'
1499 if (this.type === 'submenu') {
1500 cfg.cls = 'submenu active';
1502 if (this.type === 'treeview') {
1503 cfg.cls = 'treeview-menu';
1508 initEvents : function() {
1510 // Roo.log("ADD event");
1511 // Roo.log(this.triggerEl.dom);
1512 this.triggerEl.on('click', this.onTriggerPress, this);
1513 this.triggerEl.addClass('dropdown-toggle');
1514 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1516 this.el.on("mouseover", this.onMouseOver, this);
1517 this.el.on("mouseout", this.onMouseOut, this);
1521 findTargetItem : function(e){
1522 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1526 //Roo.log(t); Roo.log(t.id);
1528 //Roo.log(this.menuitems);
1529 return this.menuitems.get(t.id);
1531 //return this.items.get(t.menuItemId);
1536 onClick : function(e){
1537 Roo.log("menu.onClick");
1538 var t = this.findTargetItem(e);
1544 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1545 if(t == this.activeItem && t.shouldDeactivate(e)){
1546 this.activeItem.deactivate();
1547 delete this.activeItem;
1551 this.setActiveItem(t, true);
1558 Roo.log('pass click event');
1562 this.fireEvent("click", this, t, e);
1566 onMouseOver : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t.canActivate && !t.disabled){
1571 // this.setActiveItem(t, true);
1575 this.fireEvent("mouseover", this, e, t);
1577 isVisible : function(){
1578 return !this.hidden;
1580 onMouseOut : function(e){
1581 var t = this.findTargetItem(e);
1584 // if(t == this.activeItem && t.shouldDeactivate(e)){
1585 // this.activeItem.deactivate();
1586 // delete this.activeItem;
1589 this.fireEvent("mouseout", this, e, t);
1594 * Displays this menu relative to another element
1595 * @param {String/HTMLElement/Roo.Element} element The element to align to
1596 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1597 * the element (defaults to this.defaultAlign)
1598 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1600 show : function(el, pos, parentMenu){
1601 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1606 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1609 * Displays this menu at a specific xy position
1610 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1611 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1613 showAt : function(xy, parentMenu, /* private: */_e){
1614 this.parentMenu = parentMenu;
1619 this.fireEvent("beforeshow", this);
1621 //xy = this.el.adjustForConstraints(xy);
1623 //this.el.setXY(xy);
1625 this.hideMenuItems();
1626 this.hidden = false;
1627 this.triggerEl.addClass('open');
1629 this.fireEvent("show", this);
1635 this.doFocus.defer(50, this);
1639 doFocus : function(){
1641 this.focusEl.focus();
1646 * Hides this menu and optionally all parent menus
1647 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1649 hide : function(deep){
1651 this.hideMenuItems();
1652 if(this.el && this.isVisible()){
1653 this.fireEvent("beforehide", this);
1654 if(this.activeItem){
1655 this.activeItem.deactivate();
1656 this.activeItem = null;
1658 this.triggerEl.removeClass('open');;
1660 this.fireEvent("hide", this);
1662 if(deep === true && this.parentMenu){
1663 this.parentMenu.hide(true);
1667 onTriggerPress : function(e)
1670 Roo.log('trigger press');
1671 //Roo.log(e.getTarget());
1672 // Roo.log(this.triggerEl.dom);
1673 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1676 if (this.isVisible()) {
1680 this.show(this.triggerEl, false, false);
1689 hideMenuItems : function()
1691 //$(backdrop).remove()
1692 Roo.select('.open',true).each(function(aa) {
1694 aa.removeClass('open');
1695 //var parent = getParent($(this))
1696 //var relatedTarget = { relatedTarget: this }
1698 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1699 //if (e.isDefaultPrevented()) return
1700 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1703 addxtypeChild : function (tree, cntr) {
1704 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1706 this.menuitems.add(comp);
1727 * @class Roo.bootstrap.MenuItem
1728 * @extends Roo.bootstrap.Component
1729 * Bootstrap MenuItem class
1730 * @cfg {String} html the menu label
1731 * @cfg {String} href the link
1732 * @cfg {Boolean} preventDefault (true | false) default true
1736 * Create a new MenuItem
1737 * @param {Object} config The config object
1741 Roo.bootstrap.MenuItem = function(config){
1742 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1747 * The raw click event for the entire grid.
1748 * @param {Roo.EventObject} e
1754 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1758 preventDefault: true,
1760 getAutoCreate : function(){
1763 cls: 'dropdown-menu-item',
1772 if (this.parent().type == 'treeview') {
1773 cfg.cls = 'treeview-menu';
1776 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1777 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1781 initEvents: function() {
1783 //this.el.select('a').on('click', this.onClick, this);
1786 onClick : function(e)
1788 Roo.log('item on click ');
1789 //if(this.preventDefault){
1790 // e.preventDefault();
1792 //this.parent().hideMenuItems();
1794 this.fireEvent('click', this, e);
1813 * @class Roo.bootstrap.MenuSeparator
1814 * @extends Roo.bootstrap.Component
1815 * Bootstrap MenuSeparator class
1818 * Create a new MenuItem
1819 * @param {Object} config The config object
1823 Roo.bootstrap.MenuSeparator = function(config){
1824 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1827 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1829 getAutoCreate : function(){
1844 <div class="modal fade">
1845 <div class="modal-dialog">
1846 <div class="modal-content">
1847 <div class="modal-header">
1848 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1849 <h4 class="modal-title">Modal title</h4>
1851 <div class="modal-body">
1852 <p>One fine body…</p>
1854 <div class="modal-footer">
1855 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1856 <button type="button" class="btn btn-primary">Save changes</button>
1858 </div><!-- /.modal-content -->
1859 </div><!-- /.modal-dialog -->
1860 </div><!-- /.modal -->
1870 * @class Roo.bootstrap.Modal
1871 * @extends Roo.bootstrap.Component
1872 * Bootstrap Modal class
1873 * @cfg {String} title Title of dialog
1874 * @cfg {Boolean} specificTitle (true|false) default false
1875 * @cfg {Array} buttons Array of buttons or standard button set..
1876 * @cfg {String} buttonPosition (left|right|center) default right
1879 * Create a new Modal Dialog
1880 * @param {Object} config The config object
1883 Roo.bootstrap.Modal = function(config){
1884 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1889 * The raw btnclick event for the button
1890 * @param {Roo.EventObject} e
1894 this.buttons = this.buttons || [];
1897 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1899 title : 'test dialog',
1906 specificTitle: false,
1908 buttonPosition: 'right',
1910 onRender : function(ct, position)
1912 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1915 var cfg = Roo.apply({}, this.getAutoCreate());
1918 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1920 //if (!cfg.name.length) {
1924 cfg.cls += ' ' + this.cls;
1927 cfg.style = this.style;
1929 this.el = Roo.get(document.body).createChild(cfg, position);
1931 //var type = this.el.dom.type;
1933 if(this.tabIndex !== undefined){
1934 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1939 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1940 this.maskEl.enableDisplayMode("block");
1942 //this.el.addClass("x-dlg-modal");
1944 if (this.buttons.length) {
1945 Roo.each(this.buttons, function(bb) {
1946 b = Roo.apply({}, bb);
1947 b.xns = b.xns || Roo.bootstrap;
1948 b.xtype = b.xtype || 'Button';
1949 if (typeof(b.listeners) == 'undefined') {
1950 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1953 var btn = Roo.factory(b);
1955 btn.onRender(this.el.select('.modal-footer div').first());
1959 // render the children.
1962 if(typeof(this.items) != 'undefined'){
1963 var items = this.items;
1966 for(var i =0;i < items.length;i++) {
1967 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1971 this.items = nitems;
1973 this.body = this.el.select('.modal-body',true).first();
1974 this.close = this.el.select('.modal-header .close', true).first();
1975 this.footer = this.el.select('.modal-footer',true).first();
1977 //this.el.addClass([this.fieldClass, this.cls]);
1980 getAutoCreate : function(){
1985 html : this.html || ''
1990 cls : 'modal-title',
1994 if(this.specificTitle){
2000 style : 'display: none',
2003 cls: "modal-dialog",
2006 cls : "modal-content",
2009 cls : 'modal-header',
2021 cls : 'modal-footer',
2025 cls: 'btn-' + this.buttonPosition
2044 getChildContainer : function() {
2046 return this.el.select('.modal-body',true).first();
2049 getButtonContainer : function() {
2050 return this.el.select('.modal-footer div',true).first();
2053 initEvents : function()
2055 this.el.select('.modal-header .close').on('click', this.hide, this);
2057 // this.addxtype(this);
2061 if (!this.rendered) {
2065 this.el.addClass('on');
2066 this.el.removeClass('fade');
2067 this.el.setStyle('display', 'block');
2068 Roo.get(document.body).addClass("x-body-masked");
2069 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2071 this.el.setStyle('zIndex', '10001');
2072 this.fireEvent('show', this);
2078 Roo.log('Modal hide?!');
2080 Roo.get(document.body).removeClass("x-body-masked");
2081 this.el.removeClass('on');
2082 this.el.addClass('fade');
2083 this.el.setStyle('display', 'none');
2084 this.fireEvent('hide', this);
2087 addButton : function(str, cb)
2091 var b = Roo.apply({}, { html : str } );
2092 b.xns = b.xns || Roo.bootstrap;
2093 b.xtype = b.xtype || 'Button';
2094 if (typeof(b.listeners) == 'undefined') {
2095 b.listeners = { click : cb.createDelegate(this) };
2098 var btn = Roo.factory(b);
2100 btn.onRender(this.el.select('.modal-footer div').first());
2106 setDefaultButton : function(btn)
2108 //this.el.select('.modal-footer').()
2110 resizeTo: function(w,h)
2114 setContentSize : function(w, h)
2118 onButtonClick: function(btn,e)
2121 this.fireEvent('btnclick', btn.name, e);
2123 setTitle: function(str) {
2124 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2130 Roo.apply(Roo.bootstrap.Modal, {
2132 * Button config that displays a single OK button
2141 * Button config that displays Yes and No buttons
2157 * Button config that displays OK and Cancel buttons
2172 * Button config that displays Yes, No and Cancel buttons
2194 * messagebox - can be used as a replace
2198 * @class Roo.MessageBox
2199 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2203 Roo.Msg.alert('Status', 'Changes saved successfully.');
2205 // Prompt for user data:
2206 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2208 // process text value...
2212 // Show a dialog using config options:
2214 title:'Save Changes?',
2215 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2216 buttons: Roo.Msg.YESNOCANCEL,
2223 Roo.bootstrap.MessageBox = function(){
2224 var dlg, opt, mask, waitTimer;
2225 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2226 var buttons, activeTextEl, bwidth;
2230 var handleButton = function(button){
2232 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2236 var handleHide = function(){
2238 dlg.el.removeClass(opt.cls);
2241 // Roo.TaskMgr.stop(waitTimer);
2242 // waitTimer = null;
2247 var updateButtons = function(b){
2250 buttons["ok"].hide();
2251 buttons["cancel"].hide();
2252 buttons["yes"].hide();
2253 buttons["no"].hide();
2254 //dlg.footer.dom.style.display = 'none';
2257 dlg.footer.dom.style.display = '';
2258 for(var k in buttons){
2259 if(typeof buttons[k] != "function"){
2262 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2263 width += buttons[k].el.getWidth()+15;
2273 var handleEsc = function(d, k, e){
2274 if(opt && opt.closable !== false){
2284 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2285 * @return {Roo.BasicDialog} The BasicDialog element
2287 getDialog : function(){
2289 dlg = new Roo.bootstrap.Modal( {
2292 //constraintoviewport:false,
2294 //collapsible : false,
2299 //buttonAlign:"center",
2300 closeClick : function(){
2301 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2304 handleButton("cancel");
2309 dlg.on("hide", handleHide);
2311 //dlg.addKeyListener(27, handleEsc);
2313 this.buttons = buttons;
2314 var bt = this.buttonText;
2315 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2316 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2317 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2318 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2320 bodyEl = dlg.body.createChild({
2322 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2323 '<textarea class="roo-mb-textarea"></textarea>' +
2324 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2326 msgEl = bodyEl.dom.firstChild;
2327 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2328 textboxEl.enableDisplayMode();
2329 textboxEl.addKeyListener([10,13], function(){
2330 if(dlg.isVisible() && opt && opt.buttons){
2333 }else if(opt.buttons.yes){
2334 handleButton("yes");
2338 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2339 textareaEl.enableDisplayMode();
2340 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2341 progressEl.enableDisplayMode();
2342 var pf = progressEl.dom.firstChild;
2344 pp = Roo.get(pf.firstChild);
2345 pp.setHeight(pf.offsetHeight);
2353 * Updates the message box body text
2354 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2355 * the XHTML-compliant non-breaking space character '&#160;')
2356 * @return {Roo.MessageBox} This message box
2358 updateText : function(text){
2359 if(!dlg.isVisible() && !opt.width){
2360 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2362 msgEl.innerHTML = text || ' ';
2364 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2365 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2367 Math.min(opt.width || cw , this.maxWidth),
2368 Math.max(opt.minWidth || this.minWidth, bwidth)
2371 activeTextEl.setWidth(w);
2373 if(dlg.isVisible()){
2374 dlg.fixedcenter = false;
2376 // to big, make it scroll. = But as usual stupid IE does not support
2379 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2380 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2381 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2383 bodyEl.dom.style.height = '';
2384 bodyEl.dom.style.overflowY = '';
2387 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2389 bodyEl.dom.style.overflowX = '';
2392 dlg.setContentSize(w, bodyEl.getHeight());
2393 if(dlg.isVisible()){
2394 dlg.fixedcenter = true;
2400 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2401 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2402 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2403 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2404 * @return {Roo.MessageBox} This message box
2406 updateProgress : function(value, text){
2408 this.updateText(text);
2410 if (pp) { // weird bug on my firefox - for some reason this is not defined
2411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2417 * Returns true if the message box is currently displayed
2418 * @return {Boolean} True if the message box is visible, else false
2420 isVisible : function(){
2421 return dlg && dlg.isVisible();
2425 * Hides the message box if it is displayed
2428 if(this.isVisible()){
2434 * Displays a new message box, or reinitializes an existing message box, based on the config options
2435 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2436 * The following config object properties are supported:
2438 Property Type Description
2439 ---------- --------------- ------------------------------------------------------------------------------------
2440 animEl String/Element An id or Element from which the message box should animate as it opens and
2441 closes (defaults to undefined)
2442 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2443 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2444 closable Boolean False to hide the top-right close button (defaults to true). Note that
2445 progress and wait dialogs will ignore this property and always hide the
2446 close button as they can only be closed programmatically.
2447 cls String A custom CSS class to apply to the message box element
2448 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2449 displayed (defaults to 75)
2450 fn Function A callback function to execute after closing the dialog. The arguments to the
2451 function will be btn (the name of the button that was clicked, if applicable,
2452 e.g. "ok"), and text (the value of the active text field, if applicable).
2453 Progress and wait dialogs will ignore this option since they do not respond to
2454 user actions and can only be closed programmatically, so any required function
2455 should be called by the same code after it closes the dialog.
2456 icon String A CSS class that provides a background image to be used as an icon for
2457 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2458 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2459 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2460 modal Boolean False to allow user interaction with the page while the message box is
2461 displayed (defaults to true)
2462 msg String A string that will replace the existing message box body text (defaults
2463 to the XHTML-compliant non-breaking space character ' ')
2464 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2465 progress Boolean True to display a progress bar (defaults to false)
2466 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2467 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2468 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2469 title String The title text
2470 value String The string value to set into the active textbox element if displayed
2471 wait Boolean True to display a progress bar (defaults to false)
2472 width Number The width of the dialog in pixels
2479 msg: 'Please enter your address:',
2481 buttons: Roo.MessageBox.OKCANCEL,
2484 animEl: 'addAddressBtn'
2487 * @param {Object} config Configuration options
2488 * @return {Roo.MessageBox} This message box
2490 show : function(options)
2493 // this causes nightmares if you show one dialog after another
2494 // especially on callbacks..
2496 if(this.isVisible()){
2499 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2500 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2501 Roo.log("New Dialog Message:" + options.msg )
2502 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2503 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2506 var d = this.getDialog();
2508 d.setTitle(opt.title || " ");
2509 d.close.setDisplayed(opt.closable !== false);
2510 activeTextEl = textboxEl;
2511 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2516 textareaEl.setHeight(typeof opt.multiline == "number" ?
2517 opt.multiline : this.defaultTextHeight);
2518 activeTextEl = textareaEl;
2527 progressEl.setDisplayed(opt.progress === true);
2528 this.updateProgress(0);
2529 activeTextEl.dom.value = opt.value || "";
2531 dlg.setDefaultButton(activeTextEl);
2533 var bs = opt.buttons;
2537 }else if(bs && bs.yes){
2538 db = buttons["yes"];
2540 dlg.setDefaultButton(db);
2542 bwidth = updateButtons(opt.buttons);
2543 this.updateText(opt.msg);
2545 d.el.addClass(opt.cls);
2547 d.proxyDrag = opt.proxyDrag === true;
2548 d.modal = opt.modal !== false;
2549 d.mask = opt.modal !== false ? mask : false;
2551 // force it to the end of the z-index stack so it gets a cursor in FF
2552 document.body.appendChild(dlg.el.dom);
2553 d.animateTarget = null;
2554 d.show(options.animEl);
2560 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2561 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2562 * and closing the message box when the process is complete.
2563 * @param {String} title The title bar text
2564 * @param {String} msg The message box body text
2565 * @return {Roo.MessageBox} This message box
2567 progress : function(title, msg){
2574 minWidth: this.minProgressWidth,
2581 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2582 * If a callback function is passed it will be called after the user clicks the button, and the
2583 * id of the button that was clicked will be passed as the only parameter to the callback
2584 * (could also be the top-right close button).
2585 * @param {String} title The title bar text
2586 * @param {String} msg The message box body text
2587 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2588 * @param {Object} scope (optional) The scope of the callback function
2589 * @return {Roo.MessageBox} This message box
2591 alert : function(title, msg, fn, scope){
2604 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2605 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2606 * You are responsible for closing the message box when the process is complete.
2607 * @param {String} msg The message box body text
2608 * @param {String} title (optional) The title bar text
2609 * @return {Roo.MessageBox} This message box
2611 wait : function(msg, title){
2622 waitTimer = Roo.TaskMgr.start({
2624 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2632 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2633 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2634 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2635 * @param {String} title The title bar text
2636 * @param {String} msg The message box body text
2637 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2638 * @param {Object} scope (optional) The scope of the callback function
2639 * @return {Roo.MessageBox} This message box
2641 confirm : function(title, msg, fn, scope){
2645 buttons: this.YESNO,
2654 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2655 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2656 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2657 * (could also be the top-right close button) and the text that was entered will be passed as the two
2658 * parameters to the callback.
2659 * @param {String} title The title bar text
2660 * @param {String} msg The message box body text
2661 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2662 * @param {Object} scope (optional) The scope of the callback function
2663 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2664 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2665 * @return {Roo.MessageBox} This message box
2667 prompt : function(title, msg, fn, scope, multiline){
2671 buttons: this.OKCANCEL,
2676 multiline: multiline,
2683 * Button config that displays a single OK button
2688 * Button config that displays Yes and No buttons
2691 YESNO : {yes:true, no:true},
2693 * Button config that displays OK and Cancel buttons
2696 OKCANCEL : {ok:true, cancel:true},
2698 * Button config that displays Yes, No and Cancel buttons
2701 YESNOCANCEL : {yes:true, no:true, cancel:true},
2704 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2707 defaultTextHeight : 75,
2709 * The maximum width in pixels of the message box (defaults to 600)
2714 * The minimum width in pixels of the message box (defaults to 100)
2719 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2720 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2723 minProgressWidth : 250,
2725 * An object containing the default button text strings that can be overriden for localized language support.
2726 * Supported properties are: ok, cancel, yes and no.
2727 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2740 * Shorthand for {@link Roo.MessageBox}
2742 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2743 Roo.Msg = Roo.Msg || Roo.MessageBox;
2752 * @class Roo.bootstrap.Navbar
2753 * @extends Roo.bootstrap.Component
2754 * Bootstrap Navbar class
2757 * Create a new Navbar
2758 * @param {Object} config The config object
2762 Roo.bootstrap.Navbar = function(config){
2763 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2767 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2776 getAutoCreate : function(){
2779 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2783 initEvents :function ()
2785 //Roo.log(this.el.select('.navbar-toggle',true));
2786 this.el.select('.navbar-toggle',true).on('click', function() {
2787 // Roo.log('click');
2788 this.el.select('.navbar-collapse',true).toggleClass('in');
2796 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2798 var size = this.el.getSize();
2799 this.maskEl.setSize(size.width, size.height);
2800 this.maskEl.enableDisplayMode("block");
2809 getChildContainer : function()
2811 if (this.el.select('.collapse').getCount()) {
2812 return this.el.select('.collapse',true).first();
2844 * @class Roo.bootstrap.NavSimplebar
2845 * @extends Roo.bootstrap.Navbar
2846 * Bootstrap Sidebar class
2848 * @cfg {Boolean} inverse is inverted color
2850 * @cfg {String} type (nav | pills | tabs)
2851 * @cfg {Boolean} arrangement stacked | justified
2852 * @cfg {String} align (left | right) alignment
2854 * @cfg {Boolean} main (true|false) main nav bar? default false
2855 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2857 * @cfg {String} tag (header|footer|nav|div) default is nav
2863 * Create a new Sidebar
2864 * @param {Object} config The config object
2868 Roo.bootstrap.NavSimplebar = function(config){
2869 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2872 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2888 getAutoCreate : function(){
2892 tag : this.tag || 'div',
2905 this.type = this.type || 'nav';
2906 if (['tabs','pills'].indexOf(this.type)!==-1) {
2907 cfg.cn[0].cls += ' nav-' + this.type
2911 if (this.type!=='nav') {
2912 Roo.log('nav type must be nav/tabs/pills')
2914 cfg.cn[0].cls += ' navbar-nav'
2920 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2921 cfg.cn[0].cls += ' nav-' + this.arrangement;
2925 if (this.align === 'right') {
2926 cfg.cn[0].cls += ' navbar-right';
2930 cfg.cls += ' navbar-inverse';
2957 * @class Roo.bootstrap.NavHeaderbar
2958 * @extends Roo.bootstrap.NavSimplebar
2959 * Bootstrap Sidebar class
2961 * @cfg {String} brand what is brand
2962 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2963 * @cfg {String} brand_href href of the brand
2966 * Create a new Sidebar
2967 * @param {Object} config The config object
2971 Roo.bootstrap.NavHeaderbar = function(config){
2972 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2975 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2982 getAutoCreate : function(){
2987 tag: this.nav || 'nav',
2993 cls: 'navbar-header',
2998 cls: 'navbar-toggle',
2999 'data-toggle': 'collapse',
3004 html: 'Toggle navigation'
3024 cls: 'collapse navbar-collapse'
3029 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3031 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3032 cfg.cls += ' navbar-' + this.position;
3034 // tag can override this..
3036 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3039 if (this.brand !== '') {
3042 href: this.brand_href ? this.brand_href : '#',
3043 cls: 'navbar-brand',
3051 cfg.cls += ' main-nav';
3076 * @class Roo.bootstrap.NavSidebar
3077 * @extends Roo.bootstrap.Navbar
3078 * Bootstrap Sidebar class
3081 * Create a new Sidebar
3082 * @param {Object} config The config object
3086 Roo.bootstrap.NavSidebar = function(config){
3087 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3090 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3092 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3094 getAutoCreate : function(){
3099 cls: 'sidebar sidebar-nav'
3121 * @class Roo.bootstrap.NavGroup
3122 * @extends Roo.bootstrap.Component
3123 * Bootstrap NavGroup class
3124 * @cfg {String} align left | right
3125 * @cfg {Boolean} inverse false | true
3126 * @cfg {String} type (nav|pills|tab) default nav
3127 * @cfg {String} navId - reference Id for navbar.
3131 * Create a new nav group
3132 * @param {Object} config The config object
3135 Roo.bootstrap.NavGroup = function(config){
3136 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3138 Roo.bootstrap.NavGroup.register(this);
3142 * Fires when the active item changes
3143 * @param {Roo.bootstrap.NavGroup} this
3144 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3145 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3152 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3163 getAutoCreate : function()
3165 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3172 if (['tabs','pills'].indexOf(this.type)!==-1) {
3173 cfg.cls += ' nav-' + this.type
3175 if (this.type!=='nav') {
3176 Roo.log('nav type must be nav/tabs/pills')
3178 cfg.cls += ' navbar-nav'
3181 if (this.parent().sidebar) {
3184 cls: 'dashboard-menu sidebar-menu'
3190 if (this.form === true) {
3196 if (this.align === 'right') {
3197 cfg.cls += ' navbar-right';
3199 cfg.cls += ' navbar-left';
3203 if (this.align === 'right') {
3204 cfg.cls += ' navbar-right';
3208 cfg.cls += ' navbar-inverse';
3216 setActiveItem : function(item)
3219 Roo.each(this.navItems, function(v){
3224 v.setActive(false, true);
3231 item.setActive(true, true);
3232 this.fireEvent('changed', this, item, prev);
3238 register : function(item)
3240 this.navItems.push( item);
3241 item.navId = this.navId;
3244 getNavItem: function(tabId)
3247 Roo.each(this.navItems, function(e) {
3248 if (e.tabId == tabId) {
3260 Roo.apply(Roo.bootstrap.NavGroup, {
3264 register : function(navgrp)
3266 this.groups[navgrp.navId] = navgrp;
3269 get: function(navId) {
3270 return this.groups[navId];
3285 * @class Roo.bootstrap.Navbar.Item
3286 * @extends Roo.bootstrap.Component
3287 * Bootstrap Navbar.Button class
3288 * @cfg {String} href link to
3289 * @cfg {String} html content of button
3290 * @cfg {String} badge text inside badge
3291 * @cfg {String} glyphicon name of glyphicon
3292 * @cfg {String} icon name of font awesome icon
3293 * @cfg {Boolean} active Is item active
3294 * @cfg {Boolean} preventDefault (true | false) default false
3295 * @cfg {String} tabId the tab that this item activates.
3298 * Create a new Navbar Button
3299 * @param {Object} config The config object
3301 Roo.bootstrap.Navbar.Item = function(config){
3302 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3307 * The raw click event for the entire grid.
3308 * @param {Roo.EventObject} e
3313 * Fires when the active item active state changes
3314 * @param {Roo.bootstrap.Navbar.Item} this
3315 * @param {boolean} state the new state
3323 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3331 preventDefault : false,
3334 getAutoCreate : function(){
3336 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3338 if (this.parent().parent().sidebar === true) {
3351 cfg.cn[0].html = this.html;
3355 this.cls += ' active';
3359 cfg.cn[0].cls += ' dropdown-toggle';
3360 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3364 cfg.cn[0].tag = 'a',
3365 cfg.cn[0].href = this.href;
3368 if (this.glyphicon) {
3369 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3373 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3385 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3395 if (this.glyphicon) {
3396 if(cfg.html){cfg.html = ' ' + this.html};
3400 cls: 'glyphicon glyphicon-' + this.glyphicon
3405 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3410 cfg.cn[0].html += " <span class='caret'></span>";
3411 //}else if (!this.href) {
3412 // cfg.cn[0].tag='p';
3413 // cfg.cn[0].cls='navbar-text';
3416 cfg.cn[0].href=this.href||'#';
3417 cfg.cn[0].html=this.html;
3420 if (this.badge !== '') {
3423 cfg.cn[0].html + ' ',
3434 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3439 initEvents: function() {
3440 // Roo.log('init events?');
3441 // Roo.log(this.el.dom);
3442 this.el.select('a',true).on('click', this.onClick, this);
3443 // at this point parent should be available..
3444 this.parent().register(this);
3447 onClick : function(e)
3449 if(this.preventDefault){
3453 if (typeof (this.menu) != 'undefined') {
3454 this.menu.parentType = this.xtype;
3455 this.menu.triggerEl = this.el;
3456 this.addxtype(Roo.apply({}, this.menu));
3459 if(this.fireEvent('click', this, e) === false){
3463 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3464 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3465 this.parent().setActiveItem(this);
3471 isActive: function () {
3474 setActive : function(state, fire)
3476 this.active = state;
3478 this.el.removeClass('active');
3479 } else if (!this.el.hasClass('active')) {
3480 this.el.addClass('active');
3483 this.fireEvent('changed', this, state);
3488 // this should not be here...
3501 * @class Roo.bootstrap.NavItem
3502 * @extends Roo.bootstrap.Component
3503 * Bootstrap Navbar.NavItem class
3504 * @cfg {String} href link to
3505 * @cfg {String} html content of button
3506 * @cfg {String} badge text inside badge
3507 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3508 * @cfg {String} glyphicon name of glyphicon
3509 * @cfg {String} icon name of font awesome icon
3510 * @cfg {Boolean} active Is item active
3511 * @cfg {Boolean} preventDefault (true | false) default false
3512 * @cfg {String} tabId the tab that this item activates.
3515 * Create a new Navbar Item
3516 * @param {Object} config The config object
3518 Roo.bootstrap.NavItem = function(config){
3519 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3524 * The raw click event for the entire grid.
3525 * @param {Roo.EventObject} e
3530 * Fires when the active item active state changes
3531 * @param {Roo.bootstrap.NavItem} this
3532 * @param {boolean} state the new state
3540 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3548 preventDefault : false,
3551 getAutoCreate : function(){
3559 href : this.href || "#",
3560 html: this.html || ''
3566 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3569 // glyphicon and icon go before content..
3570 if (this.glyphicon || this.icon) {
3572 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html + '</span>'
3574 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span>' + cfg.cn[0].html;
3582 cfg.cn[0].html += " <span class='caret'></span>";
3586 if (this.badge !== '') {
3588 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3595 initEvents: function() {
3596 // Roo.log('init events?');
3597 // Roo.log(this.el.dom);
3598 if (typeof (this.menu) != 'undefined') {
3599 this.menu.parentType = this.xtype;
3600 this.menu.triggerEl = this.el;
3601 this.addxtype(Roo.apply({}, this.menu));
3605 this.el.select('a',true).on('click', this.onClick, this);
3606 // at this point parent should be available..
3607 this.parent().register(this);
3610 onClick : function(e)
3612 if(this.preventDefault){
3616 if(this.fireEvent('click', this, e) === false){
3620 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3621 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3622 this.parent().setActiveItem(this);
3630 isActive: function () {
3633 setActive : function(state, fire)
3635 this.active = state;
3637 this.el.removeClass('active');
3638 } else if (!this.el.hasClass('active')) {
3639 this.el.addClass('active');
3642 this.fireEvent('changed', this, state);
3647 // this should not be here...
3658 * <span> icon </span>
3659 * <span> text </span>
3660 * <span>badge </span>
3664 * @class Roo.bootstrap.NavSidebarItem
3665 * @extends Roo.bootstrap.NavItem
3666 * Bootstrap Navbar.NavSidebarItem class
3668 * Create a new Navbar Button
3669 * @param {Object} config The config object
3671 Roo.bootstrap.NavSidebarItem = function(config){
3672 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3677 * The raw click event for the entire grid.
3678 * @param {Roo.EventObject} e
3683 * Fires when the active item active state changes
3684 * @param {Roo.bootstrap.NavSidebarItem} this
3685 * @param {boolean} state the new state
3693 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3696 getAutoCreate : function(){
3701 href : this.href || '#',
3713 html : this.html || ''
3718 cfg.cls += ' active';
3722 if (this.glyphicon || this.icon) {
3723 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3724 a.cn.push({ tag : 'i', cls : c }) ;
3729 if (this.badge !== '') {
3730 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3734 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3735 a.cls += 'dropdown-toggle treeview' ;
3759 * @class Roo.bootstrap.Row
3760 * @extends Roo.bootstrap.Component
3761 * Bootstrap Row class (contains columns...)
3765 * @param {Object} config The config object
3768 Roo.bootstrap.Row = function(config){
3769 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3772 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3774 getAutoCreate : function(){
3793 * @class Roo.bootstrap.Element
3794 * @extends Roo.bootstrap.Component
3795 * Bootstrap Element class
3796 * @cfg {String} html contents of the element
3797 * @cfg {String} tag tag of the element
3798 * @cfg {String} cls class of the element
3801 * Create a new Element
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Element = function(config){
3806 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3816 getAutoCreate : function(){
3841 * @class Roo.bootstrap.Pagination
3842 * @extends Roo.bootstrap.Component
3843 * Bootstrap Pagination class
3844 * @cfg {String} size xs | sm | md | lg
3845 * @cfg {Boolean} inverse false | true
3848 * Create a new Pagination
3849 * @param {Object} config The config object
3852 Roo.bootstrap.Pagination = function(config){
3853 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3856 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3862 getAutoCreate : function(){
3868 cfg.cls += ' inverse';
3874 cfg.cls += " " + this.cls;
3892 * @class Roo.bootstrap.PaginationItem
3893 * @extends Roo.bootstrap.Component
3894 * Bootstrap PaginationItem class
3895 * @cfg {String} html text
3896 * @cfg {String} href the link
3897 * @cfg {Boolean} preventDefault (true | false) default true
3898 * @cfg {Boolean} active (true | false) default false
3902 * Create a new PaginationItem
3903 * @param {Object} config The config object
3907 Roo.bootstrap.PaginationItem = function(config){
3908 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3913 * The raw click event for the entire grid.
3914 * @param {Roo.EventObject} e
3920 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3924 preventDefault: true,
3928 getAutoCreate : function(){
3934 href : this.href ? this.href : '#',
3935 html : this.html ? this.html : ''
3945 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3951 initEvents: function() {
3953 this.el.on('click', this.onClick, this);
3956 onClick : function(e)
3958 Roo.log('PaginationItem on click ');
3959 if(this.preventDefault){
3963 this.fireEvent('click', this, e);
3979 * @class Roo.bootstrap.Slider
3980 * @extends Roo.bootstrap.Component
3981 * Bootstrap Slider class
3984 * Create a new Slider
3985 * @param {Object} config The config object
3988 Roo.bootstrap.Slider = function(config){
3989 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3992 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3994 getAutoCreate : function(){
3998 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4002 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4020 * @class Roo.bootstrap.Table
4021 * @extends Roo.bootstrap.Component
4022 * Bootstrap Table class
4023 * @cfg {String} cls table class
4024 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4025 * @cfg {String} bgcolor Specifies the background color for a table
4026 * @cfg {Number} border Specifies whether the table cells should have borders or not
4027 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4028 * @cfg {Number} cellspacing Specifies the space between cells
4029 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4030 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4031 * @cfg {String} sortable Specifies that the table should be sortable
4032 * @cfg {String} summary Specifies a summary of the content of a table
4033 * @cfg {Number} width Specifies the width of a table
4035 * @cfg {boolean} striped Should the rows be alternative striped
4036 * @cfg {boolean} bordered Add borders to the table
4037 * @cfg {boolean} hover Add hover highlighting
4038 * @cfg {boolean} condensed Format condensed
4039 * @cfg {boolean} responsive Format condensed
4040 * @cfg {Boolean} loadMask (true|false) default false
4046 * Create a new Table
4047 * @param {Object} config The config object
4050 Roo.bootstrap.Table = function(config){
4051 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4054 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4055 this.sm = this.selModel;
4056 this.sm.xmodule = this.xmodule || false;
4058 if (this.cm && typeof(this.cm.config) == 'undefined') {
4059 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
4060 this.cm = this.colModel;
4061 this.cm.xmodule = this.xmodule || false;
4064 this.store= Roo.factory(this.store, Roo.data);
4065 this.ds = this.store;
4066 this.ds.xmodule = this.xmodule || false;
4071 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4094 getAutoCreate : function(){
4095 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4104 cfg.cls += ' table-striped';
4107 cfg.cls += ' table-hover';
4109 if (this.bordered) {
4110 cfg.cls += ' table-bordered';
4112 if (this.condensed) {
4113 cfg.cls += ' table-condensed';
4115 if (this.responsive) {
4116 cfg.cls += ' table-responsive';
4123 cfg.cls+= ' ' +this.cls;
4126 // this lot should be simplifed...
4129 cfg.align=this.align;
4132 cfg.bgcolor=this.bgcolor;
4135 cfg.border=this.border;
4137 if (this.cellpadding) {
4138 cfg.cellpadding=this.cellpadding;
4140 if (this.cellspacing) {
4141 cfg.cellspacing=this.cellspacing;
4144 cfg.frame=this.frame;
4147 cfg.rules=this.rules;
4149 if (this.sortable) {
4150 cfg.sortable=this.sortable;
4153 cfg.summary=this.summary;
4156 cfg.width=this.width;
4159 if(this.store || this.cm){
4160 cfg.cn.push(this.renderHeader());
4161 cfg.cn.push(this.renderBody());
4162 cfg.cn.push(this.renderFooter());
4164 cfg.cls+= ' TableGrid';
4170 // initTableGrid : function()
4179 // var cm = this.cm;
4181 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4184 // html: cm.getColumnHeader(i)
4188 // cfg.push(header);
4195 initEvents : function()
4197 if(!this.store || !this.cm){
4201 Roo.log('initEvents with ds!!!!');
4205 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4206 e.on('click', _this.sort, _this);
4208 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4209 // this.maskEl.enableDisplayMode("block");
4210 // this.maskEl.show();
4212 this.parent().el.setStyle('position', 'relative');
4217 style: "text-align:center",
4221 style: "background-color:white;width:50%;margin:100 auto",
4225 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
4236 this.maskEl = Roo.DomHelper.append(this.parent().el, mark, true);
4238 var size = this.parent().el.getSize();
4240 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4242 this.maskEl.enableDisplayMode("block");
4244 this.store.on('load', this.onLoad, this);
4245 this.store.on('beforeload', this.onBeforeLoad, this);
4253 sort : function(e,el)
4255 var col = Roo.get(el)
4257 if(!col.hasClass('sortable')){
4261 var sort = col.attr('sort');
4264 if(col.hasClass('glyphicon-arrow-up')){
4268 this.store.sortInfo = {field : sort, direction : dir};
4273 renderHeader : function()
4282 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4284 var config = cm.config[i];
4286 if(typeof(config.hidden) != 'undefined' && config.hidden){
4292 html: cm.getColumnHeader(i)
4295 if(typeof(config.dataIndex) != 'undefined'){
4296 c.sort = config.dataIndex;
4299 if(typeof(config.sortable) != 'undefined' && config.sortable){
4303 if(typeof(config.width) != 'undefined'){
4304 c.style = 'width:' + config.width + 'px';
4313 renderBody : function()
4323 renderFooter : function()
4335 Roo.log('ds onload');
4340 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4341 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4343 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4344 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4347 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4348 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4352 var tbody = this.el.select('tbody', true).first();
4356 if(this.store.getCount() > 0){
4357 this.store.data.each(function(d){
4363 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4364 var config = cm.config[i];
4366 if(typeof(config.hidden) != 'undefined' && config.hidden){
4370 var renderer = cm.getRenderer(i);
4374 if(typeof(renderer) !== 'undefined'){
4375 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4378 if(typeof(value) === 'object'){
4388 html: (typeof(value) === 'object') ? '' : value
4391 if(typeof(config.width) != 'undefined'){
4392 td.style = 'width:' + config.width + 'px';
4399 tbody.createChild(row);
4407 Roo.each(renders, function(r){
4408 _this.renderColumn(r);
4417 onBeforeLoad : function()
4419 Roo.log('ds onBeforeLoad');
4430 this.el.select('tbody', true).first().dom.innerHTML = '';
4433 getSelectionModel : function(){
4435 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4437 return this.selModel;
4440 renderColumn : function(r)
4443 r.cfg.render(Roo.get(r.id));
4446 Roo.each(r.cfg.cn, function(c){
4451 _this.renderColumn(child);
4468 * @class Roo.bootstrap.TableCell
4469 * @extends Roo.bootstrap.Component
4470 * Bootstrap TableCell class
4471 * @cfg {String} html cell contain text
4472 * @cfg {String} cls cell class
4473 * @cfg {String} tag cell tag (td|th) default td
4474 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4475 * @cfg {String} align Aligns the content in a cell
4476 * @cfg {String} axis Categorizes cells
4477 * @cfg {String} bgcolor Specifies the background color of a cell
4478 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4479 * @cfg {Number} colspan Specifies the number of columns a cell should span
4480 * @cfg {String} headers Specifies one or more header cells a cell is related to
4481 * @cfg {Number} height Sets the height of a cell
4482 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4483 * @cfg {Number} rowspan Sets the number of rows a cell should span
4484 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4485 * @cfg {String} valign Vertical aligns the content in a cell
4486 * @cfg {Number} width Specifies the width of a cell
4489 * Create a new TableCell
4490 * @param {Object} config The config object
4493 Roo.bootstrap.TableCell = function(config){
4494 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4497 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4517 getAutoCreate : function(){
4518 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4538 cfg.align=this.align
4544 cfg.bgcolor=this.bgcolor
4547 cfg.charoff=this.charoff
4550 cfg.colspan=this.colspan
4553 cfg.headers=this.headers
4556 cfg.height=this.height
4559 cfg.nowrap=this.nowrap
4562 cfg.rowspan=this.rowspan
4565 cfg.scope=this.scope
4568 cfg.valign=this.valign
4571 cfg.width=this.width
4590 * @class Roo.bootstrap.TableRow
4591 * @extends Roo.bootstrap.Component
4592 * Bootstrap TableRow class
4593 * @cfg {String} cls row class
4594 * @cfg {String} align Aligns the content in a table row
4595 * @cfg {String} bgcolor Specifies a background color for a table row
4596 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4597 * @cfg {String} valign Vertical aligns the content in a table row
4600 * Create a new TableRow
4601 * @param {Object} config The config object
4604 Roo.bootstrap.TableRow = function(config){
4605 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4608 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4616 getAutoCreate : function(){
4617 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4627 cfg.align = this.align;
4630 cfg.bgcolor = this.bgcolor;
4633 cfg.charoff = this.charoff;
4636 cfg.valign = this.valign;
4654 * @class Roo.bootstrap.TableBody
4655 * @extends Roo.bootstrap.Component
4656 * Bootstrap TableBody class
4657 * @cfg {String} cls element class
4658 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4659 * @cfg {String} align Aligns the content inside the element
4660 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4661 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4664 * Create a new TableBody
4665 * @param {Object} config The config object
4668 Roo.bootstrap.TableBody = function(config){
4669 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4672 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4680 getAutoCreate : function(){
4681 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4695 cfg.align = this.align;
4698 cfg.charoff = this.charoff;
4701 cfg.valign = this.valign;
4708 // initEvents : function()
4715 // this.store = Roo.factory(this.store, Roo.data);
4716 // this.store.on('load', this.onLoad, this);
4718 // this.store.load();
4722 // onLoad: function ()
4724 // this.fireEvent('load', this);
4734 * Ext JS Library 1.1.1
4735 * Copyright(c) 2006-2007, Ext JS, LLC.
4737 * Originally Released Under LGPL - original licence link has changed is not relivant.
4740 * <script type="text/javascript">
4743 // as we use this in bootstrap.
4744 Roo.namespace('Roo.form');
4746 * @class Roo.form.Action
4747 * Internal Class used to handle form actions
4749 * @param {Roo.form.BasicForm} el The form element or its id
4750 * @param {Object} config Configuration options
4755 // define the action interface
4756 Roo.form.Action = function(form, options){
4758 this.options = options || {};
4761 * Client Validation Failed
4764 Roo.form.Action.CLIENT_INVALID = 'client';
4766 * Server Validation Failed
4769 Roo.form.Action.SERVER_INVALID = 'server';
4771 * Connect to Server Failed
4774 Roo.form.Action.CONNECT_FAILURE = 'connect';
4776 * Reading Data from Server Failed
4779 Roo.form.Action.LOAD_FAILURE = 'load';
4781 Roo.form.Action.prototype = {
4783 failureType : undefined,
4784 response : undefined,
4788 run : function(options){
4793 success : function(response){
4798 handleResponse : function(response){
4802 // default connection failure
4803 failure : function(response){
4805 this.response = response;
4806 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4807 this.form.afterAction(this, false);
4810 processResponse : function(response){
4811 this.response = response;
4812 if(!response.responseText){
4815 this.result = this.handleResponse(response);
4819 // utility functions used internally
4820 getUrl : function(appendParams){
4821 var url = this.options.url || this.form.url || this.form.el.dom.action;
4823 var p = this.getParams();
4825 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4831 getMethod : function(){
4832 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4835 getParams : function(){
4836 var bp = this.form.baseParams;
4837 var p = this.options.params;
4839 if(typeof p == "object"){
4840 p = Roo.urlEncode(Roo.applyIf(p, bp));
4841 }else if(typeof p == 'string' && bp){
4842 p += '&' + Roo.urlEncode(bp);
4845 p = Roo.urlEncode(bp);
4850 createCallback : function(){
4852 success: this.success,
4853 failure: this.failure,
4855 timeout: (this.form.timeout*1000),
4856 upload: this.form.fileUpload ? this.success : undefined
4861 Roo.form.Action.Submit = function(form, options){
4862 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4865 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4868 haveProgress : false,
4869 uploadComplete : false,
4871 // uploadProgress indicator.
4872 uploadProgress : function()
4874 if (!this.form.progressUrl) {
4878 if (!this.haveProgress) {
4879 Roo.MessageBox.progress("Uploading", "Uploading");
4881 if (this.uploadComplete) {
4882 Roo.MessageBox.hide();
4886 this.haveProgress = true;
4888 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4890 var c = new Roo.data.Connection();
4892 url : this.form.progressUrl,
4897 success : function(req){
4898 //console.log(data);
4902 rdata = Roo.decode(req.responseText)
4904 Roo.log("Invalid data from server..");
4908 if (!rdata || !rdata.success) {
4910 Roo.MessageBox.alert(Roo.encode(rdata));
4913 var data = rdata.data;
4915 if (this.uploadComplete) {
4916 Roo.MessageBox.hide();
4921 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4922 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4925 this.uploadProgress.defer(2000,this);
4928 failure: function(data) {
4929 Roo.log('progress url failed ');
4940 // run get Values on the form, so it syncs any secondary forms.
4941 this.form.getValues();
4943 var o = this.options;
4944 var method = this.getMethod();
4945 var isPost = method == 'POST';
4946 if(o.clientValidation === false || this.form.isValid()){
4948 if (this.form.progressUrl) {
4949 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4950 (new Date() * 1) + '' + Math.random());
4955 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4956 form:this.form.el.dom,
4957 url:this.getUrl(!isPost),
4959 params:isPost ? this.getParams() : null,
4960 isUpload: this.form.fileUpload
4963 this.uploadProgress();
4965 }else if (o.clientValidation !== false){ // client validation failed
4966 this.failureType = Roo.form.Action.CLIENT_INVALID;
4967 this.form.afterAction(this, false);
4971 success : function(response)
4973 this.uploadComplete= true;
4974 if (this.haveProgress) {
4975 Roo.MessageBox.hide();
4979 var result = this.processResponse(response);
4980 if(result === true || result.success){
4981 this.form.afterAction(this, true);
4985 this.form.markInvalid(result.errors);
4986 this.failureType = Roo.form.Action.SERVER_INVALID;
4988 this.form.afterAction(this, false);
4990 failure : function(response)
4992 this.uploadComplete= true;
4993 if (this.haveProgress) {
4994 Roo.MessageBox.hide();
4997 this.response = response;
4998 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4999 this.form.afterAction(this, false);
5002 handleResponse : function(response){
5003 if(this.form.errorReader){
5004 var rs = this.form.errorReader.read(response);
5007 for(var i = 0, len = rs.records.length; i < len; i++) {
5008 var r = rs.records[i];
5012 if(errors.length < 1){
5016 success : rs.success,
5022 ret = Roo.decode(response.responseText);
5026 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5036 Roo.form.Action.Load = function(form, options){
5037 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5038 this.reader = this.form.reader;
5041 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5046 Roo.Ajax.request(Roo.apply(
5047 this.createCallback(), {
5048 method:this.getMethod(),
5049 url:this.getUrl(false),
5050 params:this.getParams()
5054 success : function(response){
5056 var result = this.processResponse(response);
5057 if(result === true || !result.success || !result.data){
5058 this.failureType = Roo.form.Action.LOAD_FAILURE;
5059 this.form.afterAction(this, false);
5062 this.form.clearInvalid();
5063 this.form.setValues(result.data);
5064 this.form.afterAction(this, true);
5067 handleResponse : function(response){
5068 if(this.form.reader){
5069 var rs = this.form.reader.read(response);
5070 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5072 success : rs.success,
5076 return Roo.decode(response.responseText);
5080 Roo.form.Action.ACTION_TYPES = {
5081 'load' : Roo.form.Action.Load,
5082 'submit' : Roo.form.Action.Submit
5091 * @class Roo.bootstrap.Form
5092 * @extends Roo.bootstrap.Component
5093 * Bootstrap Form class
5094 * @cfg {String} method GET | POST (default POST)
5095 * @cfg {String} labelAlign top | left (default top)
5096 * @cfg {String} align left | right - for navbars
5101 * @param {Object} config The config object
5105 Roo.bootstrap.Form = function(config){
5106 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5109 * @event clientvalidation
5110 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5111 * @param {Form} this
5112 * @param {Boolean} valid true if the form has passed client-side validation
5114 clientvalidation: true,
5116 * @event beforeaction
5117 * Fires before any action is performed. Return false to cancel the action.
5118 * @param {Form} this
5119 * @param {Action} action The action to be performed
5123 * @event actionfailed
5124 * Fires when an action fails.
5125 * @param {Form} this
5126 * @param {Action} action The action that failed
5128 actionfailed : true,
5130 * @event actioncomplete
5131 * Fires when an action is completed.
5132 * @param {Form} this
5133 * @param {Action} action The action that completed
5135 actioncomplete : true
5140 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5143 * @cfg {String} method
5144 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5149 * The URL to use for form actions if one isn't supplied in the action options.
5152 * @cfg {Boolean} fileUpload
5153 * Set to true if this form is a file upload.
5157 * @cfg {Object} baseParams
5158 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5162 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5166 * @cfg {Sting} align (left|right) for navbar forms
5171 activeAction : null,
5174 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5175 * element by passing it or its id or mask the form itself by passing in true.
5178 waitMsgTarget : false,
5183 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5184 * element by passing it or its id or mask the form itself by passing in true.
5188 getAutoCreate : function(){
5192 method : this.method || 'POST',
5193 id : this.id || Roo.id(),
5196 if (this.parent().xtype.match(/^Nav/)) {
5197 cfg.cls = 'navbar-form navbar-' + this.align;
5201 if (this.labelAlign == 'left' ) {
5202 cfg.cls += ' form-horizontal';
5208 initEvents : function()
5210 this.el.on('submit', this.onSubmit, this);
5215 onSubmit : function(e){
5220 * Returns true if client-side validation on the form is successful.
5223 isValid : function(){
5224 var items = this.getItems();
5226 items.each(function(f){
5235 * Returns true if any fields in this form have changed since their original load.
5238 isDirty : function(){
5240 var items = this.getItems();
5241 items.each(function(f){
5251 * Performs a predefined action (submit or load) or custom actions you define on this form.
5252 * @param {String} actionName The name of the action type
5253 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5254 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5255 * accept other config options):
5257 Property Type Description
5258 ---------------- --------------- ----------------------------------------------------------------------------------
5259 url String The url for the action (defaults to the form's url)
5260 method String The form method to use (defaults to the form's method, or POST if not defined)
5261 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5262 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5263 validate the form on the client (defaults to false)
5265 * @return {BasicForm} this
5267 doAction : function(action, options){
5268 if(typeof action == 'string'){
5269 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5271 if(this.fireEvent('beforeaction', this, action) !== false){
5272 this.beforeAction(action);
5273 action.run.defer(100, action);
5279 beforeAction : function(action){
5280 var o = action.options;
5282 // not really supported yet.. ??
5284 //if(this.waitMsgTarget === true){
5285 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5286 //}else if(this.waitMsgTarget){
5287 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5288 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5290 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5296 afterAction : function(action, success){
5297 this.activeAction = null;
5298 var o = action.options;
5300 //if(this.waitMsgTarget === true){
5302 //}else if(this.waitMsgTarget){
5303 // this.waitMsgTarget.unmask();
5305 // Roo.MessageBox.updateProgress(1);
5306 // Roo.MessageBox.hide();
5313 Roo.callback(o.success, o.scope, [this, action]);
5314 this.fireEvent('actioncomplete', this, action);
5318 // failure condition..
5319 // we have a scenario where updates need confirming.
5320 // eg. if a locking scenario exists..
5321 // we look for { errors : { needs_confirm : true }} in the response.
5323 (typeof(action.result) != 'undefined') &&
5324 (typeof(action.result.errors) != 'undefined') &&
5325 (typeof(action.result.errors.needs_confirm) != 'undefined')
5328 Roo.log("not supported yet");
5331 Roo.MessageBox.confirm(
5332 "Change requires confirmation",
5333 action.result.errorMsg,
5338 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5348 Roo.callback(o.failure, o.scope, [this, action]);
5349 // show an error message if no failed handler is set..
5350 if (!this.hasListener('actionfailed')) {
5351 Roo.log("need to add dialog support");
5353 Roo.MessageBox.alert("Error",
5354 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5355 action.result.errorMsg :
5356 "Saving Failed, please check your entries or try again"
5361 this.fireEvent('actionfailed', this, action);
5366 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5367 * @param {String} id The value to search for
5370 findField : function(id){
5371 var items = this.getItems();
5372 var field = items.get(id);
5374 items.each(function(f){
5375 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5382 return field || null;
5385 * Mark fields in this form invalid in bulk.
5386 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5387 * @return {BasicForm} this
5389 markInvalid : function(errors){
5390 if(errors instanceof Array){
5391 for(var i = 0, len = errors.length; i < len; i++){
5392 var fieldError = errors[i];
5393 var f = this.findField(fieldError.id);
5395 f.markInvalid(fieldError.msg);
5401 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5402 field.markInvalid(errors[id]);
5406 //Roo.each(this.childForms || [], function (f) {
5407 // f.markInvalid(errors);
5414 * Set values for fields in this form in bulk.
5415 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5416 * @return {BasicForm} this
5418 setValues : function(values){
5419 if(values instanceof Array){ // array of objects
5420 for(var i = 0, len = values.length; i < len; i++){
5422 var f = this.findField(v.id);
5424 f.setValue(v.value);
5425 if(this.trackResetOnLoad){
5426 f.originalValue = f.getValue();
5430 }else{ // object hash
5433 if(typeof values[id] != 'function' && (field = this.findField(id))){
5435 if (field.setFromData &&
5437 field.displayField &&
5438 // combos' with local stores can
5439 // be queried via setValue()
5440 // to set their value..
5441 (field.store && !field.store.isLocal)
5445 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5446 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5447 field.setFromData(sd);
5450 field.setValue(values[id]);
5454 if(this.trackResetOnLoad){
5455 field.originalValue = field.getValue();
5461 //Roo.each(this.childForms || [], function (f) {
5462 // f.setValues(values);
5469 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5470 * they are returned as an array.
5471 * @param {Boolean} asString
5474 getValues : function(asString){
5475 //if (this.childForms) {
5476 // copy values from the child forms
5477 // Roo.each(this.childForms, function (f) {
5478 // this.setValues(f.getValues());
5484 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5485 if(asString === true){
5488 return Roo.urlDecode(fs);
5492 * Returns the fields in this form as an object with key/value pairs.
5493 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5496 getFieldValues : function(with_hidden)
5498 var items = this.getItems();
5500 items.each(function(f){
5504 var v = f.getValue();
5505 if (f.inputType =='radio') {
5506 if (typeof(ret[f.getName()]) == 'undefined') {
5507 ret[f.getName()] = ''; // empty..
5510 if (!f.el.dom.checked) {
5518 // not sure if this supported any more..
5519 if ((typeof(v) == 'object') && f.getRawValue) {
5520 v = f.getRawValue() ; // dates..
5522 // combo boxes where name != hiddenName...
5523 if (f.name != f.getName()) {
5524 ret[f.name] = f.getRawValue();
5526 ret[f.getName()] = v;
5533 * Clears all invalid messages in this form.
5534 * @return {BasicForm} this
5536 clearInvalid : function(){
5537 var items = this.getItems();
5539 items.each(function(f){
5550 * @return {BasicForm} this
5553 var items = this.getItems();
5554 items.each(function(f){
5558 Roo.each(this.childForms || [], function (f) {
5565 getItems : function()
5567 var r=new Roo.util.MixedCollection(false, function(o){
5568 return o.id || (o.id = Roo.id());
5570 var iter = function(el) {
5577 Roo.each(el.items,function(e) {
5596 * Ext JS Library 1.1.1
5597 * Copyright(c) 2006-2007, Ext JS, LLC.
5599 * Originally Released Under LGPL - original licence link has changed is not relivant.
5602 * <script type="text/javascript">
5605 * @class Roo.form.VTypes
5606 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5609 Roo.form.VTypes = function(){
5610 // closure these in so they are only created once.
5611 var alpha = /^[a-zA-Z_]+$/;
5612 var alphanum = /^[a-zA-Z0-9_]+$/;
5613 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5614 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5616 // All these messages and functions are configurable
5619 * The function used to validate email addresses
5620 * @param {String} value The email address
5622 'email' : function(v){
5623 return email.test(v);
5626 * The error text to display when the email validation function returns false
5629 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5631 * The keystroke filter mask to be applied on email input
5634 'emailMask' : /[a-z0-9_\.\-@]/i,
5637 * The function used to validate URLs
5638 * @param {String} value The URL
5640 'url' : function(v){
5644 * The error text to display when the url validation function returns false
5647 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5650 * The function used to validate alpha values
5651 * @param {String} value The value
5653 'alpha' : function(v){
5654 return alpha.test(v);
5657 * The error text to display when the alpha validation function returns false
5660 'alphaText' : 'This field should only contain letters and _',
5662 * The keystroke filter mask to be applied on alpha input
5665 'alphaMask' : /[a-z_]/i,
5668 * The function used to validate alphanumeric values
5669 * @param {String} value The value
5671 'alphanum' : function(v){
5672 return alphanum.test(v);
5675 * The error text to display when the alphanumeric validation function returns false
5678 'alphanumText' : 'This field should only contain letters, numbers and _',
5680 * The keystroke filter mask to be applied on alphanumeric input
5683 'alphanumMask' : /[a-z0-9_]/i
5693 * @class Roo.bootstrap.Input
5694 * @extends Roo.bootstrap.Component
5695 * Bootstrap Input class
5696 * @cfg {Boolean} disabled is it disabled
5697 * @cfg {String} fieldLabel - the label associated
5698 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5699 * @cfg {String} name name of the input
5700 * @cfg {string} fieldLabel - the label associated
5701 * @cfg {string} inputType - input / file submit ...
5702 * @cfg {string} placeholder - placeholder to put in text.
5703 * @cfg {string} before - input group add on before
5704 * @cfg {string} after - input group add on after
5705 * @cfg {string} size - (lg|sm) or leave empty..
5706 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5707 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5708 * @cfg {Number} md colspan out of 12 for computer-sized screens
5709 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5710 * @cfg {string} value default value of the input
5711 * @cfg {Number} labelWidth set the width of label (0-12)
5712 * @cfg {String} labelAlign (top|left)
5713 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5717 * Create a new Input
5718 * @param {Object} config The config object
5721 Roo.bootstrap.Input = function(config){
5722 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5727 * Fires when this field receives input focus.
5728 * @param {Roo.form.Field} this
5733 * Fires when this field loses input focus.
5734 * @param {Roo.form.Field} this
5739 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5740 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5741 * @param {Roo.form.Field} this
5742 * @param {Roo.EventObject} e The event object
5747 * Fires just before the field blurs if the field value has changed.
5748 * @param {Roo.form.Field} this
5749 * @param {Mixed} newValue The new value
5750 * @param {Mixed} oldValue The original value
5755 * Fires after the field has been marked as invalid.
5756 * @param {Roo.form.Field} this
5757 * @param {String} msg The validation message
5762 * Fires after the field has been validated with no errors.
5763 * @param {Roo.form.Field} this
5768 * Fires after the key up
5769 * @param {Roo.form.Field} this
5770 * @param {Roo.EventObject} e The event Object
5776 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5778 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5779 automatic validation (defaults to "keyup").
5781 validationEvent : "keyup",
5783 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5785 validateOnBlur : true,
5787 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5789 validationDelay : 250,
5791 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5793 focusClass : "x-form-focus", // not needed???
5797 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5799 invalidClass : "has-error",
5802 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5804 selectOnFocus : false,
5807 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5811 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5816 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5818 disableKeyFilter : false,
5821 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5825 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5829 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5831 blankText : "This field is required",
5834 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5838 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5840 maxLength : Number.MAX_VALUE,
5842 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5844 minLengthText : "The minimum length for this field is {0}",
5846 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5848 maxLengthText : "The maximum length for this field is {0}",
5852 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5853 * If available, this function will be called only after the basic validators all return true, and will be passed the
5854 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5858 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5859 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5860 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5864 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5887 parentLabelAlign : function()
5890 while (parent.parent()) {
5891 parent = parent.parent();
5892 if (typeof(parent.labelAlign) !='undefined') {
5893 return parent.labelAlign;
5900 getAutoCreate : function(){
5902 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5908 if(this.inputType != 'hidden'){
5909 cfg.cls = 'form-group' //input-group
5915 type : this.inputType,
5917 cls : 'form-control',
5918 placeholder : this.placeholder || ''
5922 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5923 input.maxLength = this.maxLength;
5926 if (this.disabled) {
5927 input.disabled=true;
5930 if (this.readOnly) {
5931 input.readonly=true;
5935 input.name = this.name;
5938 input.cls += ' input-' + this.size;
5941 ['xs','sm','md','lg'].map(function(size){
5942 if (settings[size]) {
5943 cfg.cls += ' col-' + size + '-' + settings[size];
5947 var inputblock = input;
5949 if (this.before || this.after) {
5952 cls : 'input-group',
5955 if (this.before && typeof(this.before) == 'string') {
5957 inputblock.cn.push({
5959 cls : 'roo-input-before input-group-addon',
5963 if (this.before && typeof(this.before) == 'object') {
5964 this.before = Roo.factory(this.before);
5965 Roo.log(this.before);
5966 inputblock.cn.push({
5968 cls : 'roo-input-before input-group-' +
5969 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5973 inputblock.cn.push(input);
5975 if (this.after && typeof(this.after) == 'string') {
5976 inputblock.cn.push({
5978 cls : 'roo-input-after input-group-addon',
5982 if (this.after && typeof(this.after) == 'object') {
5983 this.after = Roo.factory(this.after);
5984 Roo.log(this.after);
5985 inputblock.cn.push({
5987 cls : 'roo-input-after input-group-' +
5988 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5993 if (align ==='left' && this.fieldLabel.length) {
5994 Roo.log("left and has label");
6000 cls : 'control-label col-sm-' + this.labelWidth,
6001 html : this.fieldLabel
6005 cls : "col-sm-" + (12 - this.labelWidth),
6012 } else if ( this.fieldLabel.length) {
6018 //cls : 'input-group-addon',
6019 html : this.fieldLabel
6029 Roo.log(" no label && no align");
6038 Roo.log('input-parentType: ' + this.parentType);
6040 if (this.parentType === 'Navbar' && this.parent().bar) {
6041 cfg.cls += ' navbar-form';
6049 * return the real input element.
6051 inputEl: function ()
6053 return this.el.select('input.form-control',true).first();
6055 setDisabled : function(v)
6057 var i = this.inputEl().dom;
6059 i.removeAttribute('disabled');
6063 i.setAttribute('disabled','true');
6065 initEvents : function()
6068 this.inputEl().on("keydown" , this.fireKey, this);
6069 this.inputEl().on("focus", this.onFocus, this);
6070 this.inputEl().on("blur", this.onBlur, this);
6072 this.inputEl().relayEvent('keyup', this);
6074 // reference to original value for reset
6075 this.originalValue = this.getValue();
6076 //Roo.form.TextField.superclass.initEvents.call(this);
6077 if(this.validationEvent == 'keyup'){
6078 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6079 this.inputEl().on('keyup', this.filterValidation, this);
6081 else if(this.validationEvent !== false){
6082 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6085 if(this.selectOnFocus){
6086 this.on("focus", this.preFocus, this);
6089 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6090 this.inputEl().on("keypress", this.filterKeys, this);
6093 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6094 this.el.on("click", this.autoSize, this);
6097 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6098 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6101 if (typeof(this.before) == 'object') {
6102 this.before.render(this.el.select('.roo-input-before',true).first());
6104 if (typeof(this.after) == 'object') {
6105 this.after.render(this.el.select('.roo-input-after',true).first());
6110 filterValidation : function(e){
6111 if(!e.isNavKeyPress()){
6112 this.validationTask.delay(this.validationDelay);
6116 * Validates the field value
6117 * @return {Boolean} True if the value is valid, else false
6119 validate : function(){
6120 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6121 if(this.disabled || this.validateValue(this.getRawValue())){
6122 this.clearInvalid();
6130 * Validates a value according to the field's validation rules and marks the field as invalid
6131 * if the validation fails
6132 * @param {Mixed} value The value to validate
6133 * @return {Boolean} True if the value is valid, else false
6135 validateValue : function(value){
6136 if(value.length < 1) { // if it's blank
6137 if(this.allowBlank){
6138 this.clearInvalid();
6141 this.markInvalid(this.blankText);
6145 if(value.length < this.minLength){
6146 this.markInvalid(String.format(this.minLengthText, this.minLength));
6149 if(value.length > this.maxLength){
6150 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6154 var vt = Roo.form.VTypes;
6155 if(!vt[this.vtype](value, this)){
6156 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6160 if(typeof this.validator == "function"){
6161 var msg = this.validator(value);
6163 this.markInvalid(msg);
6167 if(this.regex && !this.regex.test(value)){
6168 this.markInvalid(this.regexText);
6177 fireKey : function(e){
6178 //Roo.log('field ' + e.getKey());
6179 if(e.isNavKeyPress()){
6180 this.fireEvent("specialkey", this, e);
6183 focus : function (selectText){
6185 this.inputEl().focus();
6186 if(selectText === true){
6187 this.inputEl().dom.select();
6193 onFocus : function(){
6194 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6195 // this.el.addClass(this.focusClass);
6198 this.hasFocus = true;
6199 this.startValue = this.getValue();
6200 this.fireEvent("focus", this);
6204 beforeBlur : Roo.emptyFn,
6208 onBlur : function(){
6210 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6211 //this.el.removeClass(this.focusClass);
6213 this.hasFocus = false;
6214 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6217 var v = this.getValue();
6218 if(String(v) !== String(this.startValue)){
6219 this.fireEvent('change', this, v, this.startValue);
6221 this.fireEvent("blur", this);
6225 * Resets the current field value to the originally loaded value and clears any validation messages
6228 this.setValue(this.originalValue);
6229 this.clearInvalid();
6232 * Returns the name of the field
6233 * @return {Mixed} name The name field
6235 getName: function(){
6239 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6240 * @return {Mixed} value The field value
6242 getValue : function(){
6243 return this.inputEl().getValue();
6246 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6247 * @return {Mixed} value The field value
6249 getRawValue : function(){
6250 var v = this.inputEl().getValue();
6256 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6257 * @param {Mixed} value The value to set
6259 setRawValue : function(v){
6260 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6263 selectText : function(start, end){
6264 var v = this.getRawValue();
6266 start = start === undefined ? 0 : start;
6267 end = end === undefined ? v.length : end;
6268 var d = this.inputEl().dom;
6269 if(d.setSelectionRange){
6270 d.setSelectionRange(start, end);
6271 }else if(d.createTextRange){
6272 var range = d.createTextRange();
6273 range.moveStart("character", start);
6274 range.moveEnd("character", v.length-end);
6281 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6282 * @param {Mixed} value The value to set
6284 setValue : function(v){
6287 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6293 processValue : function(value){
6294 if(this.stripCharsRe){
6295 var newValue = value.replace(this.stripCharsRe, '');
6296 if(newValue !== value){
6297 this.setRawValue(newValue);
6304 preFocus : function(){
6306 if(this.selectOnFocus){
6307 this.inputEl().dom.select();
6310 filterKeys : function(e){
6312 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6315 var c = e.getCharCode(), cc = String.fromCharCode(c);
6316 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6319 if(!this.maskRe.test(cc)){
6324 * Clear any invalid styles/messages for this field
6326 clearInvalid : function(){
6328 if(!this.el || this.preventMark){ // not rendered
6331 this.el.removeClass(this.invalidClass);
6333 switch(this.msgTarget){
6335 this.el.dom.qtip = '';
6338 this.el.dom.title = '';
6342 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6347 this.errorIcon.dom.qtip = '';
6348 this.errorIcon.hide();
6349 this.un('resize', this.alignErrorIcon, this);
6353 var t = Roo.getDom(this.msgTarget);
6355 t.style.display = 'none';
6359 this.fireEvent('valid', this);
6362 * Mark this field as invalid
6363 * @param {String} msg The validation message
6365 markInvalid : function(msg){
6366 if(!this.el || this.preventMark){ // not rendered
6369 this.el.addClass(this.invalidClass);
6371 msg = msg || this.invalidText;
6372 switch(this.msgTarget){
6374 this.el.dom.qtip = msg;
6375 this.el.dom.qclass = 'x-form-invalid-tip';
6376 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6377 Roo.QuickTips.enable();
6381 this.el.dom.title = msg;
6385 var elp = this.el.findParent('.x-form-element', 5, true);
6386 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6387 this.errorEl.setWidth(elp.getWidth(true)-20);
6389 this.errorEl.update(msg);
6390 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6393 if(!this.errorIcon){
6394 var elp = this.el.findParent('.x-form-element', 5, true);
6395 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6397 this.alignErrorIcon();
6398 this.errorIcon.dom.qtip = msg;
6399 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6400 this.errorIcon.show();
6401 this.on('resize', this.alignErrorIcon, this);
6404 var t = Roo.getDom(this.msgTarget);
6406 t.style.display = this.msgDisplay;
6410 this.fireEvent('invalid', this, msg);
6413 SafariOnKeyDown : function(event)
6415 // this is a workaround for a password hang bug on chrome/ webkit.
6417 var isSelectAll = false;
6419 if(this.inputEl().dom.selectionEnd > 0){
6420 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6422 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6423 event.preventDefault();
6428 if(isSelectAll){ // backspace and delete key
6430 event.preventDefault();
6431 // this is very hacky as keydown always get's upper case.
6433 var cc = String.fromCharCode(event.getCharCode());
6434 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6438 adjustWidth : function(tag, w){
6439 tag = tag.toLowerCase();
6440 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6441 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6445 if(tag == 'textarea'){
6448 }else if(Roo.isOpera){
6452 if(tag == 'textarea'){
6471 * @class Roo.bootstrap.TextArea
6472 * @extends Roo.bootstrap.Input
6473 * Bootstrap TextArea class
6474 * @cfg {Number} cols Specifies the visible width of a text area
6475 * @cfg {Number} rows Specifies the visible number of lines in a text area
6476 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6477 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6478 * @cfg {string} html text
6481 * Create a new TextArea
6482 * @param {Object} config The config object
6485 Roo.bootstrap.TextArea = function(config){
6486 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6490 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6500 getAutoCreate : function(){
6502 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6513 value : this.value || '',
6514 html: this.html || '',
6515 cls : 'form-control',
6516 placeholder : this.placeholder || ''
6520 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6521 input.maxLength = this.maxLength;
6525 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6529 input.cols = this.cols;
6532 if (this.readOnly) {
6533 input.readonly = true;
6537 input.name = this.name;
6541 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6545 ['xs','sm','md','lg'].map(function(size){
6546 if (settings[size]) {
6547 cfg.cls += ' col-' + size + '-' + settings[size];
6551 var inputblock = input;
6553 if (this.before || this.after) {
6556 cls : 'input-group',
6560 inputblock.cn.push({
6562 cls : 'input-group-addon',
6566 inputblock.cn.push(input);
6568 inputblock.cn.push({
6570 cls : 'input-group-addon',
6577 if (align ==='left' && this.fieldLabel.length) {
6578 Roo.log("left and has label");
6584 cls : 'control-label col-sm-' + this.labelWidth,
6585 html : this.fieldLabel
6589 cls : "col-sm-" + (12 - this.labelWidth),
6596 } else if ( this.fieldLabel.length) {
6602 //cls : 'input-group-addon',
6603 html : this.fieldLabel
6613 Roo.log(" no label && no align");
6623 if (this.disabled) {
6624 input.disabled=true;
6631 * return the real textarea element.
6633 inputEl: function ()
6635 return this.el.select('textarea.form-control',true).first();
6643 * trigger field - base class for combo..
6648 * @class Roo.bootstrap.TriggerField
6649 * @extends Roo.bootstrap.Input
6650 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6651 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6652 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6653 * for which you can provide a custom implementation. For example:
6655 var trigger = new Roo.bootstrap.TriggerField();
6656 trigger.onTriggerClick = myTriggerFn;
6657 trigger.applyTo('my-field');
6660 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6661 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6662 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6663 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6665 * Create a new TriggerField.
6666 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6667 * to the base TextField)
6669 Roo.bootstrap.TriggerField = function(config){
6670 this.mimicing = false;
6671 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6674 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6676 * @cfg {String} triggerClass A CSS class to apply to the trigger
6679 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6683 /** @cfg {Boolean} grow @hide */
6684 /** @cfg {Number} growMin @hide */
6685 /** @cfg {Number} growMax @hide */
6691 autoSize: Roo.emptyFn,
6698 actionMode : 'wrap',
6702 getAutoCreate : function(){
6704 var parent = this.parent();
6706 var align = this.labelAlign || this.parentLabelAlign();
6711 cls: 'form-group' //input-group
6718 type : this.inputType,
6719 cls : 'form-control',
6720 autocomplete: 'off',
6721 placeholder : this.placeholder || ''
6725 input.name = this.name;
6728 input.cls += ' input-' + this.size;
6731 if (this.disabled) {
6732 input.disabled=true;
6735 var inputblock = input;
6737 if (this.before || this.after) {
6740 cls : 'input-group',
6744 inputblock.cn.push({
6746 cls : 'input-group-addon',
6750 inputblock.cn.push(input);
6752 inputblock.cn.push({
6754 cls : 'input-group-addon',
6767 cls: 'form-hidden-field'
6775 Roo.log('multiple');
6783 cls: 'form-hidden-field'
6787 cls: 'select2-choices',
6791 cls: 'select2-search-field',
6804 cls: 'select2-container input-group',
6809 cls: 'typeahead typeahead-long dropdown-menu',
6810 style: 'display:none'
6818 cls : 'input-group-addon btn dropdown-toggle',
6826 cls: 'combobox-clear',
6840 combobox.cls += ' select2-container-multi';
6843 if (align ==='left' && this.fieldLabel.length) {
6845 Roo.log("left and has label");
6851 cls : 'control-label col-sm-' + this.labelWidth,
6852 html : this.fieldLabel
6856 cls : "col-sm-" + (12 - this.labelWidth),
6863 } else if ( this.fieldLabel.length) {
6869 //cls : 'input-group-addon',
6870 html : this.fieldLabel
6880 Roo.log(" no label && no align");
6887 ['xs','sm','md','lg'].map(function(size){
6888 if (settings[size]) {
6889 cfg.cls += ' col-' + size + '-' + settings[size];
6900 onResize : function(w, h){
6901 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6902 // if(typeof w == 'number'){
6903 // var x = w - this.trigger.getWidth();
6904 // this.inputEl().setWidth(this.adjustWidth('input', x));
6905 // this.trigger.setStyle('left', x+'px');
6910 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6913 getResizeEl : function(){
6914 return this.inputEl();
6918 getPositionEl : function(){
6919 return this.inputEl();
6923 alignErrorIcon : function(){
6924 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6928 initEvents : function(){
6930 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6931 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6933 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6934 if(this.hideTrigger){
6935 this.trigger.setDisplayed(false);
6937 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6941 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6944 //this.trigger.addClassOnOver('x-form-trigger-over');
6945 //this.trigger.addClassOnClick('x-form-trigger-click');
6948 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6953 initTrigger : function(){
6958 onDestroy : function(){
6960 this.trigger.removeAllListeners();
6961 // this.trigger.remove();
6964 // this.wrap.remove();
6966 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6970 onFocus : function(){
6971 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6974 this.wrap.addClass('x-trigger-wrap-focus');
6975 this.mimicing = true;
6976 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6977 if(this.monitorTab){
6978 this.el.on("keydown", this.checkTab, this);
6985 checkTab : function(e){
6986 if(e.getKey() == e.TAB){
6992 onBlur : function(){
6997 mimicBlur : function(e, t){
6999 if(!this.wrap.contains(t) && this.validateBlur()){
7006 triggerBlur : function(){
7007 this.mimicing = false;
7008 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7009 if(this.monitorTab){
7010 this.el.un("keydown", this.checkTab, this);
7012 //this.wrap.removeClass('x-trigger-wrap-focus');
7013 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7017 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7018 validateBlur : function(e, t){
7023 onDisable : function(){
7024 this.inputEl().dom.disabled = true;
7025 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7027 // this.wrap.addClass('x-item-disabled');
7032 onEnable : function(){
7033 this.inputEl().dom.disabled = false;
7034 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7036 // this.el.removeClass('x-item-disabled');
7041 onShow : function(){
7042 var ae = this.getActionEl();
7045 ae.dom.style.display = '';
7046 ae.dom.style.visibility = 'visible';
7052 onHide : function(){
7053 var ae = this.getActionEl();
7054 ae.dom.style.display = 'none';
7058 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7059 * by an implementing function.
7061 * @param {EventObject} e
7063 onTriggerClick : Roo.emptyFn
7067 * Ext JS Library 1.1.1
7068 * Copyright(c) 2006-2007, Ext JS, LLC.
7070 * Originally Released Under LGPL - original licence link has changed is not relivant.
7073 * <script type="text/javascript">
7078 * @class Roo.data.SortTypes
7080 * Defines the default sorting (casting?) comparison functions used when sorting data.
7082 Roo.data.SortTypes = {
7084 * Default sort that does nothing
7085 * @param {Mixed} s The value being converted
7086 * @return {Mixed} The comparison value
7093 * The regular expression used to strip tags
7097 stripTagsRE : /<\/?[^>]+>/gi,
7100 * Strips all HTML tags to sort on text only
7101 * @param {Mixed} s The value being converted
7102 * @return {String} The comparison value
7104 asText : function(s){
7105 return String(s).replace(this.stripTagsRE, "");
7109 * Strips all HTML tags to sort on text only - Case insensitive
7110 * @param {Mixed} s The value being converted
7111 * @return {String} The comparison value
7113 asUCText : function(s){
7114 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7118 * Case insensitive string
7119 * @param {Mixed} s The value being converted
7120 * @return {String} The comparison value
7122 asUCString : function(s) {
7123 return String(s).toUpperCase();
7128 * @param {Mixed} s The value being converted
7129 * @return {Number} The comparison value
7131 asDate : function(s) {
7135 if(s instanceof Date){
7138 return Date.parse(String(s));
7143 * @param {Mixed} s The value being converted
7144 * @return {Float} The comparison value
7146 asFloat : function(s) {
7147 var val = parseFloat(String(s).replace(/,/g, ""));
7148 if(isNaN(val)) val = 0;
7154 * @param {Mixed} s The value being converted
7155 * @return {Number} The comparison value
7157 asInt : function(s) {
7158 var val = parseInt(String(s).replace(/,/g, ""));
7159 if(isNaN(val)) val = 0;
7164 * Ext JS Library 1.1.1
7165 * Copyright(c) 2006-2007, Ext JS, LLC.
7167 * Originally Released Under LGPL - original licence link has changed is not relivant.
7170 * <script type="text/javascript">
7174 * @class Roo.data.Record
7175 * Instances of this class encapsulate both record <em>definition</em> information, and record
7176 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7177 * to access Records cached in an {@link Roo.data.Store} object.<br>
7179 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7180 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7183 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7185 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7186 * {@link #create}. The parameters are the same.
7187 * @param {Array} data An associative Array of data values keyed by the field name.
7188 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7189 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7190 * not specified an integer id is generated.
7192 Roo.data.Record = function(data, id){
7193 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7198 * Generate a constructor for a specific record layout.
7199 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7200 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7201 * Each field definition object may contain the following properties: <ul>
7202 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
7203 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7204 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7205 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7206 * is being used, then this is a string containing the javascript expression to reference the data relative to
7207 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7208 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7209 * this may be omitted.</p></li>
7210 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7211 * <ul><li>auto (Default, implies no conversion)</li>
7216 * <li>date</li></ul></p></li>
7217 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7218 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7219 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7220 * by the Reader into an object that will be stored in the Record. It is passed the
7221 * following parameters:<ul>
7222 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7224 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7226 * <br>usage:<br><pre><code>
7227 var TopicRecord = Roo.data.Record.create(
7228 {name: 'title', mapping: 'topic_title'},
7229 {name: 'author', mapping: 'username'},
7230 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7231 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7232 {name: 'lastPoster', mapping: 'user2'},
7233 {name: 'excerpt', mapping: 'post_text'}
7236 var myNewRecord = new TopicRecord({
7237 title: 'Do my job please',
7240 lastPost: new Date(),
7241 lastPoster: 'Animal',
7242 excerpt: 'No way dude!'
7244 myStore.add(myNewRecord);
7249 Roo.data.Record.create = function(o){
7251 f.superclass.constructor.apply(this, arguments);
7253 Roo.extend(f, Roo.data.Record);
7254 var p = f.prototype;
7255 p.fields = new Roo.util.MixedCollection(false, function(field){
7258 for(var i = 0, len = o.length; i < len; i++){
7259 p.fields.add(new Roo.data.Field(o[i]));
7261 f.getField = function(name){
7262 return p.fields.get(name);
7267 Roo.data.Record.AUTO_ID = 1000;
7268 Roo.data.Record.EDIT = 'edit';
7269 Roo.data.Record.REJECT = 'reject';
7270 Roo.data.Record.COMMIT = 'commit';
7272 Roo.data.Record.prototype = {
7274 * Readonly flag - true if this record has been modified.
7283 join : function(store){
7288 * Set the named field to the specified value.
7289 * @param {String} name The name of the field to set.
7290 * @param {Object} value The value to set the field to.
7292 set : function(name, value){
7293 if(this.data[name] == value){
7300 if(typeof this.modified[name] == 'undefined'){
7301 this.modified[name] = this.data[name];
7303 this.data[name] = value;
7304 if(!this.editing && this.store){
7305 this.store.afterEdit(this);
7310 * Get the value of the named field.
7311 * @param {String} name The name of the field to get the value of.
7312 * @return {Object} The value of the field.
7314 get : function(name){
7315 return this.data[name];
7319 beginEdit : function(){
7320 this.editing = true;
7325 cancelEdit : function(){
7326 this.editing = false;
7327 delete this.modified;
7331 endEdit : function(){
7332 this.editing = false;
7333 if(this.dirty && this.store){
7334 this.store.afterEdit(this);
7339 * Usually called by the {@link Roo.data.Store} which owns the Record.
7340 * Rejects all changes made to the Record since either creation, or the last commit operation.
7341 * Modified fields are reverted to their original values.
7343 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7344 * of reject operations.
7346 reject : function(){
7347 var m = this.modified;
7349 if(typeof m[n] != "function"){
7350 this.data[n] = m[n];
7354 delete this.modified;
7355 this.editing = false;
7357 this.store.afterReject(this);
7362 * Usually called by the {@link Roo.data.Store} which owns the Record.
7363 * Commits all changes made to the Record since either creation, or the last commit operation.
7365 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7366 * of commit operations.
7368 commit : function(){
7370 delete this.modified;
7371 this.editing = false;
7373 this.store.afterCommit(this);
7378 hasError : function(){
7379 return this.error != null;
7383 clearError : function(){
7388 * Creates a copy of this record.
7389 * @param {String} id (optional) A new record id if you don't want to use this record's id
7392 copy : function(newId) {
7393 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7397 * Ext JS Library 1.1.1
7398 * Copyright(c) 2006-2007, Ext JS, LLC.
7400 * Originally Released Under LGPL - original licence link has changed is not relivant.
7403 * <script type="text/javascript">
7409 * @class Roo.data.Store
7410 * @extends Roo.util.Observable
7411 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7412 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7414 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
7415 * has no knowledge of the format of the data returned by the Proxy.<br>
7417 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7418 * instances from the data object. These records are cached and made available through accessor functions.
7420 * Creates a new Store.
7421 * @param {Object} config A config object containing the objects needed for the Store to access data,
7422 * and read the data into Records.
7424 Roo.data.Store = function(config){
7425 this.data = new Roo.util.MixedCollection(false);
7426 this.data.getKey = function(o){
7429 this.baseParams = {};
7436 "multisort" : "_multisort"
7439 if(config && config.data){
7440 this.inlineData = config.data;
7444 Roo.apply(this, config);
7446 if(this.reader){ // reader passed
7447 this.reader = Roo.factory(this.reader, Roo.data);
7448 this.reader.xmodule = this.xmodule || false;
7449 if(!this.recordType){
7450 this.recordType = this.reader.recordType;
7452 if(this.reader.onMetaChange){
7453 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7457 if(this.recordType){
7458 this.fields = this.recordType.prototype.fields;
7464 * @event datachanged
7465 * Fires when the data cache has changed, and a widget which is using this Store
7466 * as a Record cache should refresh its view.
7467 * @param {Store} this
7472 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7473 * @param {Store} this
7474 * @param {Object} meta The JSON metadata
7479 * Fires when Records have been added to the Store
7480 * @param {Store} this
7481 * @param {Roo.data.Record[]} records The array of Records added
7482 * @param {Number} index The index at which the record(s) were added
7487 * Fires when a Record has been removed from the Store
7488 * @param {Store} this
7489 * @param {Roo.data.Record} record The Record that was removed
7490 * @param {Number} index The index at which the record was removed
7495 * Fires when a Record has been updated
7496 * @param {Store} this
7497 * @param {Roo.data.Record} record The Record that was updated
7498 * @param {String} operation The update operation being performed. Value may be one of:
7500 Roo.data.Record.EDIT
7501 Roo.data.Record.REJECT
7502 Roo.data.Record.COMMIT
7508 * Fires when the data cache has been cleared.
7509 * @param {Store} this
7514 * Fires before a request is made for a new data object. If the beforeload handler returns false
7515 * the load action will be canceled.
7516 * @param {Store} this
7517 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7521 * @event beforeloadadd
7522 * Fires after a new set of Records has been loaded.
7523 * @param {Store} this
7524 * @param {Roo.data.Record[]} records The Records that were loaded
7525 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7527 beforeloadadd : true,
7530 * Fires after a new set of Records has been loaded, before they are added to the store.
7531 * @param {Store} this
7532 * @param {Roo.data.Record[]} records The Records that were loaded
7533 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7534 * @params {Object} return from reader
7538 * @event loadexception
7539 * Fires if an exception occurs in the Proxy during loading.
7540 * Called with the signature of the Proxy's "loadexception" event.
7541 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7544 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7545 * @param {Object} load options
7546 * @param {Object} jsonData from your request (normally this contains the Exception)
7548 loadexception : true
7552 this.proxy = Roo.factory(this.proxy, Roo.data);
7553 this.proxy.xmodule = this.xmodule || false;
7554 this.relayEvents(this.proxy, ["loadexception"]);
7556 this.sortToggle = {};
7557 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7559 Roo.data.Store.superclass.constructor.call(this);
7561 if(this.inlineData){
7562 this.loadData(this.inlineData);
7563 delete this.inlineData;
7567 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7569 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7570 * without a remote query - used by combo/forms at present.
7574 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7577 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7580 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7581 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7584 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7585 * on any HTTP request
7588 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7591 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7595 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7596 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7601 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7602 * loaded or when a record is removed. (defaults to false).
7604 pruneModifiedRecords : false,
7610 * Add Records to the Store and fires the add event.
7611 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7613 add : function(records){
7614 records = [].concat(records);
7615 for(var i = 0, len = records.length; i < len; i++){
7616 records[i].join(this);
7618 var index = this.data.length;
7619 this.data.addAll(records);
7620 this.fireEvent("add", this, records, index);
7624 * Remove a Record from the Store and fires the remove event.
7625 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7627 remove : function(record){
7628 var index = this.data.indexOf(record);
7629 this.data.removeAt(index);
7630 if(this.pruneModifiedRecords){
7631 this.modified.remove(record);
7633 this.fireEvent("remove", this, record, index);
7637 * Remove all Records from the Store and fires the clear event.
7639 removeAll : function(){
7641 if(this.pruneModifiedRecords){
7644 this.fireEvent("clear", this);
7648 * Inserts Records to the Store at the given index and fires the add event.
7649 * @param {Number} index The start index at which to insert the passed Records.
7650 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7652 insert : function(index, records){
7653 records = [].concat(records);
7654 for(var i = 0, len = records.length; i < len; i++){
7655 this.data.insert(index, records[i]);
7656 records[i].join(this);
7658 this.fireEvent("add", this, records, index);
7662 * Get the index within the cache of the passed Record.
7663 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7664 * @return {Number} The index of the passed Record. Returns -1 if not found.
7666 indexOf : function(record){
7667 return this.data.indexOf(record);
7671 * Get the index within the cache of the Record with the passed id.
7672 * @param {String} id The id of the Record to find.
7673 * @return {Number} The index of the Record. Returns -1 if not found.
7675 indexOfId : function(id){
7676 return this.data.indexOfKey(id);
7680 * Get the Record with the specified id.
7681 * @param {String} id The id of the Record to find.
7682 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7684 getById : function(id){
7685 return this.data.key(id);
7689 * Get the Record at the specified index.
7690 * @param {Number} index The index of the Record to find.
7691 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7693 getAt : function(index){
7694 return this.data.itemAt(index);
7698 * Returns a range of Records between specified indices.
7699 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7700 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7701 * @return {Roo.data.Record[]} An array of Records
7703 getRange : function(start, end){
7704 return this.data.getRange(start, end);
7708 storeOptions : function(o){
7709 o = Roo.apply({}, o);
7712 this.lastOptions = o;
7716 * Loads the Record cache from the configured Proxy using the configured Reader.
7718 * If using remote paging, then the first load call must specify the <em>start</em>
7719 * and <em>limit</em> properties in the options.params property to establish the initial
7720 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7722 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7723 * and this call will return before the new data has been loaded. Perform any post-processing
7724 * in a callback function, or in a "load" event handler.</strong>
7726 * @param {Object} options An object containing properties which control loading options:<ul>
7727 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7728 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7729 * passed the following arguments:<ul>
7730 * <li>r : Roo.data.Record[]</li>
7731 * <li>options: Options object from the load call</li>
7732 * <li>success: Boolean success indicator</li></ul></li>
7733 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7734 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7737 load : function(options){
7738 options = options || {};
7739 if(this.fireEvent("beforeload", this, options) !== false){
7740 this.storeOptions(options);
7741 var p = Roo.apply(options.params || {}, this.baseParams);
7742 // if meta was not loaded from remote source.. try requesting it.
7743 if (!this.reader.metaFromRemote) {
7746 if(this.sortInfo && this.remoteSort){
7747 var pn = this.paramNames;
7748 p[pn["sort"]] = this.sortInfo.field;
7749 p[pn["dir"]] = this.sortInfo.direction;
7751 if (this.multiSort) {
7752 var pn = this.paramNames;
7753 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7756 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7761 * Reloads the Record cache from the configured Proxy using the configured Reader and
7762 * the options from the last load operation performed.
7763 * @param {Object} options (optional) An object containing properties which may override the options
7764 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7765 * the most recently used options are reused).
7767 reload : function(options){
7768 this.load(Roo.applyIf(options||{}, this.lastOptions));
7772 // Called as a callback by the Reader during a load operation.
7773 loadRecords : function(o, options, success){
7774 if(!o || success === false){
7775 if(success !== false){
7776 this.fireEvent("load", this, [], options, o);
7778 if(options.callback){
7779 options.callback.call(options.scope || this, [], options, false);
7783 // if data returned failure - throw an exception.
7784 if (o.success === false) {
7785 // show a message if no listener is registered.
7786 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7787 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7789 // loadmask wil be hooked into this..
7790 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7793 var r = o.records, t = o.totalRecords || r.length;
7795 this.fireEvent("beforeloadadd", this, r, options, o);
7797 if(!options || options.add !== true){
7798 if(this.pruneModifiedRecords){
7801 for(var i = 0, len = r.length; i < len; i++){
7805 this.data = this.snapshot;
7806 delete this.snapshot;
7809 this.data.addAll(r);
7810 this.totalLength = t;
7812 this.fireEvent("datachanged", this);
7814 this.totalLength = Math.max(t, this.data.length+r.length);
7817 this.fireEvent("load", this, r, options, o);
7818 if(options.callback){
7819 options.callback.call(options.scope || this, r, options, true);
7825 * Loads data from a passed data block. A Reader which understands the format of the data
7826 * must have been configured in the constructor.
7827 * @param {Object} data The data block from which to read the Records. The format of the data expected
7828 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7829 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7831 loadData : function(o, append){
7832 var r = this.reader.readRecords(o);
7833 this.loadRecords(r, {add: append}, true);
7837 * Gets the number of cached records.
7839 * <em>If using paging, this may not be the total size of the dataset. If the data object
7840 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7841 * the data set size</em>
7843 getCount : function(){
7844 return this.data.length || 0;
7848 * Gets the total number of records in the dataset as returned by the server.
7850 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7851 * the dataset size</em>
7853 getTotalCount : function(){
7854 return this.totalLength || 0;
7858 * Returns the sort state of the Store as an object with two properties:
7860 field {String} The name of the field by which the Records are sorted
7861 direction {String} The sort order, "ASC" or "DESC"
7864 getSortState : function(){
7865 return this.sortInfo;
7869 applySort : function(){
7870 if(this.sortInfo && !this.remoteSort){
7871 var s = this.sortInfo, f = s.field;
7872 var st = this.fields.get(f).sortType;
7873 var fn = function(r1, r2){
7874 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7875 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7877 this.data.sort(s.direction, fn);
7878 if(this.snapshot && this.snapshot != this.data){
7879 this.snapshot.sort(s.direction, fn);
7885 * Sets the default sort column and order to be used by the next load operation.
7886 * @param {String} fieldName The name of the field to sort by.
7887 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7889 setDefaultSort : function(field, dir){
7890 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7895 * If remote sorting is used, the sort is performed on the server, and the cache is
7896 * reloaded. If local sorting is used, the cache is sorted internally.
7897 * @param {String} fieldName The name of the field to sort by.
7898 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7900 sort : function(fieldName, dir){
7901 var f = this.fields.get(fieldName);
7903 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7905 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7906 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7911 this.sortToggle[f.name] = dir;
7912 this.sortInfo = {field: f.name, direction: dir};
7913 if(!this.remoteSort){
7915 this.fireEvent("datachanged", this);
7917 this.load(this.lastOptions);
7922 * Calls the specified function for each of the Records in the cache.
7923 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7924 * Returning <em>false</em> aborts and exits the iteration.
7925 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7927 each : function(fn, scope){
7928 this.data.each(fn, scope);
7932 * Gets all records modified since the last commit. Modified records are persisted across load operations
7933 * (e.g., during paging).
7934 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7936 getModifiedRecords : function(){
7937 return this.modified;
7941 createFilterFn : function(property, value, anyMatch){
7942 if(!value.exec){ // not a regex
7943 value = String(value);
7944 if(value.length == 0){
7947 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7950 return value.test(r.data[property]);
7955 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7956 * @param {String} property A field on your records
7957 * @param {Number} start The record index to start at (defaults to 0)
7958 * @param {Number} end The last record index to include (defaults to length - 1)
7959 * @return {Number} The sum
7961 sum : function(property, start, end){
7962 var rs = this.data.items, v = 0;
7964 end = (end || end === 0) ? end : rs.length-1;
7966 for(var i = start; i <= end; i++){
7967 v += (rs[i].data[property] || 0);
7973 * Filter the records by a specified property.
7974 * @param {String} field A field on your records
7975 * @param {String/RegExp} value Either a string that the field
7976 * should start with or a RegExp to test against the field
7977 * @param {Boolean} anyMatch True to match any part not just the beginning
7979 filter : function(property, value, anyMatch){
7980 var fn = this.createFilterFn(property, value, anyMatch);
7981 return fn ? this.filterBy(fn) : this.clearFilter();
7985 * Filter by a function. The specified function will be called with each
7986 * record in this data source. If the function returns true the record is included,
7987 * otherwise it is filtered.
7988 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7989 * @param {Object} scope (optional) The scope of the function (defaults to this)
7991 filterBy : function(fn, scope){
7992 this.snapshot = this.snapshot || this.data;
7993 this.data = this.queryBy(fn, scope||this);
7994 this.fireEvent("datachanged", this);
7998 * Query the records by a specified property.
7999 * @param {String} field A field on your records
8000 * @param {String/RegExp} value Either a string that the field
8001 * should start with or a RegExp to test against the field
8002 * @param {Boolean} anyMatch True to match any part not just the beginning
8003 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8005 query : function(property, value, anyMatch){
8006 var fn = this.createFilterFn(property, value, anyMatch);
8007 return fn ? this.queryBy(fn) : this.data.clone();
8011 * Query by a function. The specified function will be called with each
8012 * record in this data source. If the function returns true the record is included
8014 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8015 * @param {Object} scope (optional) The scope of the function (defaults to this)
8016 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8018 queryBy : function(fn, scope){
8019 var data = this.snapshot || this.data;
8020 return data.filterBy(fn, scope||this);
8024 * Collects unique values for a particular dataIndex from this store.
8025 * @param {String} dataIndex The property to collect
8026 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8027 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8028 * @return {Array} An array of the unique values
8030 collect : function(dataIndex, allowNull, bypassFilter){
8031 var d = (bypassFilter === true && this.snapshot) ?
8032 this.snapshot.items : this.data.items;
8033 var v, sv, r = [], l = {};
8034 for(var i = 0, len = d.length; i < len; i++){
8035 v = d[i].data[dataIndex];
8037 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8046 * Revert to a view of the Record cache with no filtering applied.
8047 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8049 clearFilter : function(suppressEvent){
8050 if(this.snapshot && this.snapshot != this.data){
8051 this.data = this.snapshot;
8052 delete this.snapshot;
8053 if(suppressEvent !== true){
8054 this.fireEvent("datachanged", this);
8060 afterEdit : function(record){
8061 if(this.modified.indexOf(record) == -1){
8062 this.modified.push(record);
8064 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8068 afterReject : function(record){
8069 this.modified.remove(record);
8070 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8074 afterCommit : function(record){
8075 this.modified.remove(record);
8076 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8080 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8081 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8083 commitChanges : function(){
8084 var m = this.modified.slice(0);
8086 for(var i = 0, len = m.length; i < len; i++){
8092 * Cancel outstanding changes on all changed records.
8094 rejectChanges : function(){
8095 var m = this.modified.slice(0);
8097 for(var i = 0, len = m.length; i < len; i++){
8102 onMetaChange : function(meta, rtype, o){
8103 this.recordType = rtype;
8104 this.fields = rtype.prototype.fields;
8105 delete this.snapshot;
8106 this.sortInfo = meta.sortInfo || this.sortInfo;
8108 this.fireEvent('metachange', this, this.reader.meta);
8111 moveIndex : function(data, type)
8113 var index = this.indexOf(data);
8115 var newIndex = index + type;
8119 this.insert(newIndex, data);
8124 * Ext JS Library 1.1.1
8125 * Copyright(c) 2006-2007, Ext JS, LLC.
8127 * Originally Released Under LGPL - original licence link has changed is not relivant.
8130 * <script type="text/javascript">
8134 * @class Roo.data.SimpleStore
8135 * @extends Roo.data.Store
8136 * Small helper class to make creating Stores from Array data easier.
8137 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8138 * @cfg {Array} fields An array of field definition objects, or field name strings.
8139 * @cfg {Array} data The multi-dimensional array of data
8141 * @param {Object} config
8143 Roo.data.SimpleStore = function(config){
8144 Roo.data.SimpleStore.superclass.constructor.call(this, {
8146 reader: new Roo.data.ArrayReader({
8149 Roo.data.Record.create(config.fields)
8151 proxy : new Roo.data.MemoryProxy(config.data)
8155 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8157 * Ext JS Library 1.1.1
8158 * Copyright(c) 2006-2007, Ext JS, LLC.
8160 * Originally Released Under LGPL - original licence link has changed is not relivant.
8163 * <script type="text/javascript">
8168 * @extends Roo.data.Store
8169 * @class Roo.data.JsonStore
8170 * Small helper class to make creating Stores for JSON data easier. <br/>
8172 var store = new Roo.data.JsonStore({
8173 url: 'get-images.php',
8175 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8178 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8179 * JsonReader and HttpProxy (unless inline data is provided).</b>
8180 * @cfg {Array} fields An array of field definition objects, or field name strings.
8182 * @param {Object} config
8184 Roo.data.JsonStore = function(c){
8185 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8186 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8187 reader: new Roo.data.JsonReader(c, c.fields)
8190 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8192 * Ext JS Library 1.1.1
8193 * Copyright(c) 2006-2007, Ext JS, LLC.
8195 * Originally Released Under LGPL - original licence link has changed is not relivant.
8198 * <script type="text/javascript">
8202 Roo.data.Field = function(config){
8203 if(typeof config == "string"){
8204 config = {name: config};
8206 Roo.apply(this, config);
8212 var st = Roo.data.SortTypes;
8213 // named sortTypes are supported, here we look them up
8214 if(typeof this.sortType == "string"){
8215 this.sortType = st[this.sortType];
8218 // set default sortType for strings and dates
8222 this.sortType = st.asUCString;
8225 this.sortType = st.asDate;
8228 this.sortType = st.none;
8233 var stripRe = /[\$,%]/g;
8235 // prebuilt conversion function for this field, instead of
8236 // switching every time we're reading a value
8238 var cv, dateFormat = this.dateFormat;
8243 cv = function(v){ return v; };
8246 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8250 return v !== undefined && v !== null && v !== '' ?
8251 parseInt(String(v).replace(stripRe, ""), 10) : '';
8256 return v !== undefined && v !== null && v !== '' ?
8257 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8262 cv = function(v){ return v === true || v === "true" || v == 1; };
8269 if(v instanceof Date){
8273 if(dateFormat == "timestamp"){
8274 return new Date(v*1000);
8276 return Date.parseDate(v, dateFormat);
8278 var parsed = Date.parse(v);
8279 return parsed ? new Date(parsed) : null;
8288 Roo.data.Field.prototype = {
8296 * Ext JS Library 1.1.1
8297 * Copyright(c) 2006-2007, Ext JS, LLC.
8299 * Originally Released Under LGPL - original licence link has changed is not relivant.
8302 * <script type="text/javascript">
8305 // Base class for reading structured data from a data source. This class is intended to be
8306 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8309 * @class Roo.data.DataReader
8310 * Base class for reading structured data from a data source. This class is intended to be
8311 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8314 Roo.data.DataReader = function(meta, recordType){
8318 this.recordType = recordType instanceof Array ?
8319 Roo.data.Record.create(recordType) : recordType;
8322 Roo.data.DataReader.prototype = {
8324 * Create an empty record
8325 * @param {Object} data (optional) - overlay some values
8326 * @return {Roo.data.Record} record created.
8328 newRow : function(d) {
8330 this.recordType.prototype.fields.each(function(c) {
8332 case 'int' : da[c.name] = 0; break;
8333 case 'date' : da[c.name] = new Date(); break;
8334 case 'float' : da[c.name] = 0.0; break;
8335 case 'boolean' : da[c.name] = false; break;
8336 default : da[c.name] = ""; break;
8340 return new this.recordType(Roo.apply(da, d));
8345 * Ext JS Library 1.1.1
8346 * Copyright(c) 2006-2007, Ext JS, LLC.
8348 * Originally Released Under LGPL - original licence link has changed is not relivant.
8351 * <script type="text/javascript">
8355 * @class Roo.data.DataProxy
8356 * @extends Roo.data.Observable
8357 * This class is an abstract base class for implementations which provide retrieval of
8358 * unformatted data objects.<br>
8360 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8361 * (of the appropriate type which knows how to parse the data object) to provide a block of
8362 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8364 * Custom implementations must implement the load method as described in
8365 * {@link Roo.data.HttpProxy#load}.
8367 Roo.data.DataProxy = function(){
8371 * Fires before a network request is made to retrieve a data object.
8372 * @param {Object} This DataProxy object.
8373 * @param {Object} params The params parameter to the load function.
8378 * Fires before the load method's callback is called.
8379 * @param {Object} This DataProxy object.
8380 * @param {Object} o The data object.
8381 * @param {Object} arg The callback argument object passed to the load function.
8385 * @event loadexception
8386 * Fires if an Exception occurs during data retrieval.
8387 * @param {Object} This DataProxy object.
8388 * @param {Object} o The data object.
8389 * @param {Object} arg The callback argument object passed to the load function.
8390 * @param {Object} e The Exception.
8392 loadexception : true
8394 Roo.data.DataProxy.superclass.constructor.call(this);
8397 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8400 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8404 * Ext JS Library 1.1.1
8405 * Copyright(c) 2006-2007, Ext JS, LLC.
8407 * Originally Released Under LGPL - original licence link has changed is not relivant.
8410 * <script type="text/javascript">
8413 * @class Roo.data.MemoryProxy
8414 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8415 * to the Reader when its load method is called.
8417 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8419 Roo.data.MemoryProxy = function(data){
8423 Roo.data.MemoryProxy.superclass.constructor.call(this);
8427 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8429 * Load data from the requested source (in this case an in-memory
8430 * data object passed to the constructor), read the data object into
8431 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8432 * process that block using the passed callback.
8433 * @param {Object} params This parameter is not used by the MemoryProxy class.
8434 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8435 * object into a block of Roo.data.Records.
8436 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8437 * The function must be passed <ul>
8438 * <li>The Record block object</li>
8439 * <li>The "arg" argument from the load function</li>
8440 * <li>A boolean success indicator</li>
8442 * @param {Object} scope The scope in which to call the callback
8443 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8445 load : function(params, reader, callback, scope, arg){
8446 params = params || {};
8449 result = reader.readRecords(this.data);
8451 this.fireEvent("loadexception", this, arg, null, e);
8452 callback.call(scope, null, arg, false);
8455 callback.call(scope, result, arg, true);
8459 update : function(params, records){
8464 * Ext JS Library 1.1.1
8465 * Copyright(c) 2006-2007, Ext JS, LLC.
8467 * Originally Released Under LGPL - original licence link has changed is not relivant.
8470 * <script type="text/javascript">
8473 * @class Roo.data.HttpProxy
8474 * @extends Roo.data.DataProxy
8475 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8476 * configured to reference a certain URL.<br><br>
8478 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8479 * from which the running page was served.<br><br>
8481 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8483 * Be aware that to enable the browser to parse an XML document, the server must set
8484 * the Content-Type header in the HTTP response to "text/xml".
8486 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8487 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8488 * will be used to make the request.
8490 Roo.data.HttpProxy = function(conn){
8491 Roo.data.HttpProxy.superclass.constructor.call(this);
8492 // is conn a conn config or a real conn?
8494 this.useAjax = !conn || !conn.events;
8498 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8499 // thse are take from connection...
8502 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8505 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8506 * extra parameters to each request made by this object. (defaults to undefined)
8509 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8510 * to each request made by this object. (defaults to undefined)
8513 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
8516 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8519 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8525 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8529 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8530 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8531 * a finer-grained basis than the DataProxy events.
8533 getConnection : function(){
8534 return this.useAjax ? Roo.Ajax : this.conn;
8538 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8539 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8540 * process that block using the passed callback.
8541 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8542 * for the request to the remote server.
8543 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8544 * object into a block of Roo.data.Records.
8545 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8546 * The function must be passed <ul>
8547 * <li>The Record block object</li>
8548 * <li>The "arg" argument from the load function</li>
8549 * <li>A boolean success indicator</li>
8551 * @param {Object} scope The scope in which to call the callback
8552 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8554 load : function(params, reader, callback, scope, arg){
8555 if(this.fireEvent("beforeload", this, params) !== false){
8557 params : params || {},
8559 callback : callback,
8564 callback : this.loadResponse,
8568 Roo.applyIf(o, this.conn);
8569 if(this.activeRequest){
8570 Roo.Ajax.abort(this.activeRequest);
8572 this.activeRequest = Roo.Ajax.request(o);
8574 this.conn.request(o);
8577 callback.call(scope||this, null, arg, false);
8582 loadResponse : function(o, success, response){
8583 delete this.activeRequest;
8585 this.fireEvent("loadexception", this, o, response);
8586 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8591 result = o.reader.read(response);
8593 this.fireEvent("loadexception", this, o, response, e);
8594 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8598 this.fireEvent("load", this, o, o.request.arg);
8599 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8603 update : function(dataSet){
8608 updateResponse : function(dataSet){
8613 * Ext JS Library 1.1.1
8614 * Copyright(c) 2006-2007, Ext JS, LLC.
8616 * Originally Released Under LGPL - original licence link has changed is not relivant.
8619 * <script type="text/javascript">
8623 * @class Roo.data.ScriptTagProxy
8624 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8625 * other than the originating domain of the running page.<br><br>
8627 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
8628 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8630 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8631 * source code that is used as the source inside a <script> tag.<br><br>
8633 * In order for the browser to process the returned data, the server must wrap the data object
8634 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8635 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8636 * depending on whether the callback name was passed:
8639 boolean scriptTag = false;
8640 String cb = request.getParameter("callback");
8643 response.setContentType("text/javascript");
8645 response.setContentType("application/x-json");
8647 Writer out = response.getWriter();
8649 out.write(cb + "(");
8651 out.print(dataBlock.toJsonString());
8658 * @param {Object} config A configuration object.
8660 Roo.data.ScriptTagProxy = function(config){
8661 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8662 Roo.apply(this, config);
8663 this.head = document.getElementsByTagName("head")[0];
8666 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8668 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8670 * @cfg {String} url The URL from which to request the data object.
8673 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8677 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8678 * the server the name of the callback function set up by the load call to process the returned data object.
8679 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8680 * javascript output which calls this named function passing the data object as its only parameter.
8682 callbackParam : "callback",
8684 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8685 * name to the request.
8690 * Load data from the configured URL, read the data object into
8691 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8692 * process that block using the passed callback.
8693 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8694 * for the request to the remote server.
8695 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8696 * object into a block of Roo.data.Records.
8697 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8698 * The function must be passed <ul>
8699 * <li>The Record block object</li>
8700 * <li>The "arg" argument from the load function</li>
8701 * <li>A boolean success indicator</li>
8703 * @param {Object} scope The scope in which to call the callback
8704 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8706 load : function(params, reader, callback, scope, arg){
8707 if(this.fireEvent("beforeload", this, params) !== false){
8709 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8712 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8714 url += "&_dc=" + (new Date().getTime());
8716 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8719 cb : "stcCallback"+transId,
8720 scriptId : "stcScript"+transId,
8724 callback : callback,
8730 window[trans.cb] = function(o){
8731 conn.handleResponse(o, trans);
8734 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8736 if(this.autoAbort !== false){
8740 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8742 var script = document.createElement("script");
8743 script.setAttribute("src", url);
8744 script.setAttribute("type", "text/javascript");
8745 script.setAttribute("id", trans.scriptId);
8746 this.head.appendChild(script);
8750 callback.call(scope||this, null, arg, false);
8755 isLoading : function(){
8756 return this.trans ? true : false;
8760 * Abort the current server request.
8763 if(this.isLoading()){
8764 this.destroyTrans(this.trans);
8769 destroyTrans : function(trans, isLoaded){
8770 this.head.removeChild(document.getElementById(trans.scriptId));
8771 clearTimeout(trans.timeoutId);
8773 window[trans.cb] = undefined;
8775 delete window[trans.cb];
8778 // if hasn't been loaded, wait for load to remove it to prevent script error
8779 window[trans.cb] = function(){
8780 window[trans.cb] = undefined;
8782 delete window[trans.cb];
8789 handleResponse : function(o, trans){
8791 this.destroyTrans(trans, true);
8794 result = trans.reader.readRecords(o);
8796 this.fireEvent("loadexception", this, o, trans.arg, e);
8797 trans.callback.call(trans.scope||window, null, trans.arg, false);
8800 this.fireEvent("load", this, o, trans.arg);
8801 trans.callback.call(trans.scope||window, result, trans.arg, true);
8805 handleFailure : function(trans){
8807 this.destroyTrans(trans, false);
8808 this.fireEvent("loadexception", this, null, trans.arg);
8809 trans.callback.call(trans.scope||window, null, trans.arg, false);
8813 * Ext JS Library 1.1.1
8814 * Copyright(c) 2006-2007, Ext JS, LLC.
8816 * Originally Released Under LGPL - original licence link has changed is not relivant.
8819 * <script type="text/javascript">
8823 * @class Roo.data.JsonReader
8824 * @extends Roo.data.DataReader
8825 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8826 * based on mappings in a provided Roo.data.Record constructor.
8828 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8829 * in the reply previously.
8834 var RecordDef = Roo.data.Record.create([
8835 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8836 {name: 'occupation'} // This field will use "occupation" as the mapping.
8838 var myReader = new Roo.data.JsonReader({
8839 totalProperty: "results", // The property which contains the total dataset size (optional)
8840 root: "rows", // The property which contains an Array of row objects
8841 id: "id" // The property within each row object that provides an ID for the record (optional)
8845 * This would consume a JSON file like this:
8847 { 'results': 2, 'rows': [
8848 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8849 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8852 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8853 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8854 * paged from the remote server.
8855 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8856 * @cfg {String} root name of the property which contains the Array of row objects.
8857 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8859 * Create a new JsonReader
8860 * @param {Object} meta Metadata configuration options
8861 * @param {Object} recordType Either an Array of field definition objects,
8862 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8864 Roo.data.JsonReader = function(meta, recordType){
8867 // set some defaults:
8869 totalProperty: 'total',
8870 successProperty : 'success',
8875 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8877 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8880 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8881 * Used by Store query builder to append _requestMeta to params.
8884 metaFromRemote : false,
8886 * This method is only used by a DataProxy which has retrieved data from a remote server.
8887 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8888 * @return {Object} data A data block which is used by an Roo.data.Store object as
8889 * a cache of Roo.data.Records.
8891 read : function(response){
8892 var json = response.responseText;
8894 var o = /* eval:var:o */ eval("("+json+")");
8896 throw {message: "JsonReader.read: Json object not found"};
8902 this.metaFromRemote = true;
8903 this.meta = o.metaData;
8904 this.recordType = Roo.data.Record.create(o.metaData.fields);
8905 this.onMetaChange(this.meta, this.recordType, o);
8907 return this.readRecords(o);
8910 // private function a store will implement
8911 onMetaChange : function(meta, recordType, o){
8918 simpleAccess: function(obj, subsc) {
8925 getJsonAccessor: function(){
8927 return function(expr) {
8929 return(re.test(expr))
8930 ? new Function("obj", "return obj." + expr)
8940 * Create a data block containing Roo.data.Records from an XML document.
8941 * @param {Object} o An object which contains an Array of row objects in the property specified
8942 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8943 * which contains the total size of the dataset.
8944 * @return {Object} data A data block which is used by an Roo.data.Store object as
8945 * a cache of Roo.data.Records.
8947 readRecords : function(o){
8949 * After any data loads, the raw JSON data is available for further custom processing.
8953 var s = this.meta, Record = this.recordType,
8954 f = Record.prototype.fields, fi = f.items, fl = f.length;
8956 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8958 if(s.totalProperty) {
8959 this.getTotal = this.getJsonAccessor(s.totalProperty);
8961 if(s.successProperty) {
8962 this.getSuccess = this.getJsonAccessor(s.successProperty);
8964 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8966 var g = this.getJsonAccessor(s.id);
8967 this.getId = function(rec) {
8969 return (r === undefined || r === "") ? null : r;
8972 this.getId = function(){return null;};
8975 for(var jj = 0; jj < fl; jj++){
8977 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8978 this.ef[jj] = this.getJsonAccessor(map);
8982 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8983 if(s.totalProperty){
8984 var vt = parseInt(this.getTotal(o), 10);
8989 if(s.successProperty){
8990 var vs = this.getSuccess(o);
8991 if(vs === false || vs === 'false'){
8996 for(var i = 0; i < c; i++){
8999 var id = this.getId(n);
9000 for(var j = 0; j < fl; j++){
9002 var v = this.ef[j](n);
9004 Roo.log('missing convert for ' + f.name);
9008 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9010 var record = new Record(values, id);
9012 records[i] = record;
9018 totalRecords : totalRecords
9023 * Ext JS Library 1.1.1
9024 * Copyright(c) 2006-2007, Ext JS, LLC.
9026 * Originally Released Under LGPL - original licence link has changed is not relivant.
9029 * <script type="text/javascript">
9033 * @class Roo.data.ArrayReader
9034 * @extends Roo.data.DataReader
9035 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9036 * Each element of that Array represents a row of data fields. The
9037 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9038 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9042 var RecordDef = Roo.data.Record.create([
9043 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9044 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9046 var myReader = new Roo.data.ArrayReader({
9047 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9051 * This would consume an Array like this:
9053 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9055 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9057 * Create a new JsonReader
9058 * @param {Object} meta Metadata configuration options.
9059 * @param {Object} recordType Either an Array of field definition objects
9060 * as specified to {@link Roo.data.Record#create},
9061 * or an {@link Roo.data.Record} object
9062 * created using {@link Roo.data.Record#create}.
9064 Roo.data.ArrayReader = function(meta, recordType){
9065 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9068 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9070 * Create a data block containing Roo.data.Records from an XML document.
9071 * @param {Object} o An Array of row objects which represents the dataset.
9072 * @return {Object} data A data block which is used by an Roo.data.Store object as
9073 * a cache of Roo.data.Records.
9075 readRecords : function(o){
9076 var sid = this.meta ? this.meta.id : null;
9077 var recordType = this.recordType, fields = recordType.prototype.fields;
9080 for(var i = 0; i < root.length; i++){
9083 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9084 for(var j = 0, jlen = fields.length; j < jlen; j++){
9085 var f = fields.items[j];
9086 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9087 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9091 var record = new recordType(values, id);
9093 records[records.length] = record;
9097 totalRecords : records.length
9106 * @class Roo.bootstrap.ComboBox
9107 * @extends Roo.bootstrap.TriggerField
9108 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9109 * @cfg {Boolean} append (true|false) default false
9111 * Create a new ComboBox.
9112 * @param {Object} config Configuration options
9114 Roo.bootstrap.ComboBox = function(config){
9115 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9119 * Fires when the dropdown list is expanded
9120 * @param {Roo.bootstrap.ComboBox} combo This combo box
9125 * Fires when the dropdown list is collapsed
9126 * @param {Roo.bootstrap.ComboBox} combo This combo box
9130 * @event beforeselect
9131 * Fires before a list item is selected. Return false to cancel the selection.
9132 * @param {Roo.bootstrap.ComboBox} combo This combo box
9133 * @param {Roo.data.Record} record The data record returned from the underlying store
9134 * @param {Number} index The index of the selected item in the dropdown list
9136 'beforeselect' : true,
9139 * Fires when a list item is selected
9140 * @param {Roo.bootstrap.ComboBox} combo This combo box
9141 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9142 * @param {Number} index The index of the selected item in the dropdown list
9146 * @event beforequery
9147 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9148 * The event object passed has these properties:
9149 * @param {Roo.bootstrap.ComboBox} combo This combo box
9150 * @param {String} query The query
9151 * @param {Boolean} forceAll true to force "all" query
9152 * @param {Boolean} cancel true to cancel the query
9153 * @param {Object} e The query event object
9155 'beforequery': true,
9158 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9159 * @param {Roo.bootstrap.ComboBox} combo This combo box
9164 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9165 * @param {Roo.bootstrap.ComboBox} combo This combo box
9166 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9171 * Fires when the remove value from the combobox array
9172 * @param {Roo.bootstrap.ComboBox} combo This combo box
9179 this.selectedIndex = -1;
9180 if(this.mode == 'local'){
9181 if(config.queryDelay === undefined){
9182 this.queryDelay = 10;
9184 if(config.minChars === undefined){
9190 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9193 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9194 * rendering into an Roo.Editor, defaults to false)
9197 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9198 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9201 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9204 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9205 * the dropdown list (defaults to undefined, with no header element)
9209 * @cfg {String/Roo.Template} tpl The template to use to render the output
9213 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9215 listWidth: undefined,
9217 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9218 * mode = 'remote' or 'text' if mode = 'local')
9220 displayField: undefined,
9222 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9223 * mode = 'remote' or 'value' if mode = 'local').
9224 * Note: use of a valueField requires the user make a selection
9225 * in order for a value to be mapped.
9227 valueField: undefined,
9231 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9232 * field's data value (defaults to the underlying DOM element's name)
9234 hiddenName: undefined,
9236 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9240 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9242 selectedClass: 'active',
9245 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9249 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9250 * anchor positions (defaults to 'tl-bl')
9252 listAlign: 'tl-bl?',
9254 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9258 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9259 * query specified by the allQuery config option (defaults to 'query')
9261 triggerAction: 'query',
9263 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9264 * (defaults to 4, does not apply if editable = false)
9268 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9269 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9273 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9274 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9278 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9279 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9283 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9284 * when editable = true (defaults to false)
9286 selectOnFocus:false,
9288 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9290 queryParam: 'query',
9292 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9293 * when mode = 'remote' (defaults to 'Loading...')
9295 loadingText: 'Loading...',
9297 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9301 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9305 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9306 * traditional select (defaults to true)
9310 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9314 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9318 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9319 * listWidth has a higher value)
9323 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9324 * allow the user to set arbitrary text into the field (defaults to false)
9326 forceSelection:false,
9328 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9329 * if typeAhead = true (defaults to 250)
9331 typeAheadDelay : 250,
9333 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9334 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9336 valueNotFoundText : undefined,
9338 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9343 * @cfg {Boolean} disableClear Disable showing of clear button.
9345 disableClear : false,
9347 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9349 alwaysQuery : false,
9352 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9366 // element that contains real text value.. (when hidden is used..)
9369 initEvents: function(){
9372 throw "can not find store for combo";
9374 this.store = Roo.factory(this.store, Roo.data);
9378 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9381 if(this.hiddenName){
9383 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9385 this.hiddenField.dom.value =
9386 this.hiddenValue !== undefined ? this.hiddenValue :
9387 this.value !== undefined ? this.value : '';
9389 // prevent input submission
9390 this.el.dom.removeAttribute('name');
9391 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9396 // this.el.dom.setAttribute('autocomplete', 'off');
9399 var cls = 'x-combo-list';
9400 this.list = this.el.select('ul.dropdown-menu',true).first();
9402 //this.list = new Roo.Layer({
9403 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9406 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9407 this.list.setWidth(lw);
9409 this.list.on('mouseover', this.onViewOver, this);
9410 this.list.on('mousemove', this.onViewMove, this);
9412 this.list.on('scroll', this.onViewScroll, this);
9415 this.list.swallowEvent('mousewheel');
9416 this.assetHeight = 0;
9419 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9420 this.assetHeight += this.header.getHeight();
9423 this.innerList = this.list.createChild({cls:cls+'-inner'});
9424 this.innerList.on('mouseover', this.onViewOver, this);
9425 this.innerList.on('mousemove', this.onViewMove, this);
9426 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9428 if(this.allowBlank && !this.pageSize && !this.disableClear){
9429 this.footer = this.list.createChild({cls:cls+'-ft'});
9430 this.pageTb = new Roo.Toolbar(this.footer);
9434 this.footer = this.list.createChild({cls:cls+'-ft'});
9435 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9436 {pageSize: this.pageSize});
9440 if (this.pageTb && this.allowBlank && !this.disableClear) {
9442 this.pageTb.add(new Roo.Toolbar.Fill(), {
9443 cls: 'x-btn-icon x-btn-clear',
9449 _this.onSelect(false, -1);
9454 this.assetHeight += this.footer.getHeight();
9459 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9462 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9463 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9465 //this.view.wrapEl.setDisplayed(false);
9466 this.view.on('click', this.onViewClick, this);
9470 this.store.on('beforeload', this.onBeforeLoad, this);
9471 this.store.on('load', this.onLoad, this);
9472 this.store.on('loadexception', this.onLoadException, this);
9475 this.resizer = new Roo.Resizable(this.list, {
9476 pinned:true, handles:'se'
9478 this.resizer.on('resize', function(r, w, h){
9479 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9481 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9482 this.restrictHeight();
9484 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9488 this.editable = true;
9489 this.setEditable(false);
9494 if (typeof(this.events.add.listeners) != 'undefined') {
9496 this.addicon = this.wrap.createChild(
9497 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9499 this.addicon.on('click', function(e) {
9500 this.fireEvent('add', this);
9503 if (typeof(this.events.edit.listeners) != 'undefined') {
9505 this.editicon = this.wrap.createChild(
9506 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9508 this.editicon.setStyle('margin-left', '40px');
9510 this.editicon.on('click', function(e) {
9512 // we fire even if inothing is selected..
9513 this.fireEvent('edit', this, this.lastData );
9519 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9521 this.inKeyMode = true;
9525 "down" : function(e){
9526 if(!this.isExpanded()){
9527 this.onTriggerClick();
9529 this.inKeyMode = true;
9534 "enter" : function(e){
9539 "esc" : function(e){
9543 "tab" : function(e){
9546 if(this.fireEvent("specialkey", this, e)){
9547 this.onViewClick(false);
9555 doRelay : function(foo, bar, hname){
9556 if(hname == 'down' || this.scope.isExpanded()){
9557 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9566 this.queryDelay = Math.max(this.queryDelay || 10,
9567 this.mode == 'local' ? 10 : 250);
9570 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9573 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9575 if(this.editable !== false){
9576 this.inputEl().on("keyup", this.onKeyUp, this);
9578 if(this.forceSelection){
9579 this.inputEl().on('blur', this.doForce, this);
9583 this.choices = this.el.select('ul.select2-choices', true).first();
9584 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9588 onDestroy : function(){
9590 this.view.setStore(null);
9591 this.view.el.removeAllListeners();
9592 this.view.el.remove();
9593 this.view.purgeListeners();
9596 this.list.dom.innerHTML = '';
9599 this.store.un('beforeload', this.onBeforeLoad, this);
9600 this.store.un('load', this.onLoad, this);
9601 this.store.un('loadexception', this.onLoadException, this);
9603 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9607 fireKey : function(e){
9608 if(e.isNavKeyPress() && !this.list.isVisible()){
9609 this.fireEvent("specialkey", this, e);
9614 onResize: function(w, h){
9615 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9617 // if(typeof w != 'number'){
9618 // // we do not handle it!?!?
9621 // var tw = this.trigger.getWidth();
9622 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9623 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9625 // this.inputEl().setWidth( this.adjustWidth('input', x));
9627 // //this.trigger.setStyle('left', x+'px');
9629 // if(this.list && this.listWidth === undefined){
9630 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9631 // this.list.setWidth(lw);
9632 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9640 * Allow or prevent the user from directly editing the field text. If false is passed,
9641 * the user will only be able to select from the items defined in the dropdown list. This method
9642 * is the runtime equivalent of setting the 'editable' config option at config time.
9643 * @param {Boolean} value True to allow the user to directly edit the field text
9645 setEditable : function(value){
9646 if(value == this.editable){
9649 this.editable = value;
9651 this.inputEl().dom.setAttribute('readOnly', true);
9652 this.inputEl().on('mousedown', this.onTriggerClick, this);
9653 this.inputEl().addClass('x-combo-noedit');
9655 this.inputEl().dom.setAttribute('readOnly', false);
9656 this.inputEl().un('mousedown', this.onTriggerClick, this);
9657 this.inputEl().removeClass('x-combo-noedit');
9663 onBeforeLoad : function(combo,opts){
9668 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9670 this.restrictHeight();
9671 this.selectedIndex = -1;
9675 onLoad : function(){
9677 this.hasQuery = false;
9683 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9684 this.loading.hide();
9687 if(this.store.getCount() > 0){
9689 this.restrictHeight();
9690 if(this.lastQuery == this.allQuery){
9692 this.inputEl().dom.select();
9694 if(!this.selectByValue(this.value, true)){
9695 this.select(0, true);
9699 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9700 this.taTask.delay(this.typeAheadDelay);
9704 this.onEmptyResults();
9710 onLoadException : function()
9712 this.hasQuery = false;
9714 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9715 this.loading.hide();
9719 Roo.log(this.store.reader.jsonData);
9720 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9722 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9728 onTypeAhead : function(){
9729 if(this.store.getCount() > 0){
9730 var r = this.store.getAt(0);
9731 var newValue = r.data[this.displayField];
9732 var len = newValue.length;
9733 var selStart = this.getRawValue().length;
9735 if(selStart != len){
9736 this.setRawValue(newValue);
9737 this.selectText(selStart, newValue.length);
9743 onSelect : function(record, index){
9745 if(this.fireEvent('beforeselect', this, record, index) !== false){
9747 this.setFromData(index > -1 ? record.data : false);
9750 this.fireEvent('select', this, record, index);
9755 * Returns the currently selected field value or empty string if no value is set.
9756 * @return {String} value The selected value
9758 getValue : function(){
9761 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9764 if(this.valueField){
9765 return typeof this.value != 'undefined' ? this.value : '';
9767 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9772 * Clears any text/value currently set in the field
9774 clearValue : function(){
9775 if(this.hiddenField){
9776 this.hiddenField.dom.value = '';
9779 this.setRawValue('');
9780 this.lastSelectionText = '';
9785 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9786 * will be displayed in the field. If the value does not match the data value of an existing item,
9787 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9788 * Otherwise the field will be blank (although the value will still be set).
9789 * @param {String} value The value to match
9791 setValue : function(v){
9798 if(this.valueField){
9799 var r = this.findRecord(this.valueField, v);
9801 text = r.data[this.displayField];
9802 }else if(this.valueNotFoundText !== undefined){
9803 text = this.valueNotFoundText;
9806 this.lastSelectionText = text;
9807 if(this.hiddenField){
9808 this.hiddenField.dom.value = v;
9810 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9814 * @property {Object} the last set data for the element
9819 * Sets the value of the field based on a object which is related to the record format for the store.
9820 * @param {Object} value the value to set as. or false on reset?
9822 setFromData : function(o){
9829 var dv = ''; // display value
9830 var vv = ''; // value value..
9832 if (this.displayField) {
9833 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9835 // this is an error condition!!!
9836 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9839 if(this.valueField){
9840 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9843 if(this.hiddenField){
9844 this.hiddenField.dom.value = vv;
9846 this.lastSelectionText = dv;
9847 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9851 // no hidden field.. - we store the value in 'value', but still display
9852 // display field!!!!
9853 this.lastSelectionText = dv;
9854 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9861 // overridden so that last data is reset..
9862 this.setValue(this.originalValue);
9863 this.clearInvalid();
9864 this.lastData = false;
9866 this.view.clearSelections();
9870 findRecord : function(prop, value){
9872 if(this.store.getCount() > 0){
9873 this.store.each(function(r){
9874 if(r.data[prop] == value){
9886 // returns hidden if it's set..
9887 if (!this.rendered) {return ''};
9888 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9892 onViewMove : function(e, t){
9893 this.inKeyMode = false;
9897 onViewOver : function(e, t){
9898 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9901 var item = this.view.findItemFromChild(t);
9903 var index = this.view.indexOf(item);
9904 this.select(index, false);
9909 onViewClick : function(doFocus)
9911 var index = this.view.getSelectedIndexes()[0];
9912 var r = this.store.getAt(index);
9914 this.onSelect(r, index);
9916 if(doFocus !== false && !this.blockFocus){
9917 this.inputEl().focus();
9922 restrictHeight : function(){
9923 //this.innerList.dom.style.height = '';
9924 //var inner = this.innerList.dom;
9925 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9926 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9927 //this.list.beginUpdate();
9928 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9929 this.list.alignTo(this.inputEl(), this.listAlign);
9930 //this.list.endUpdate();
9934 onEmptyResults : function(){
9939 * Returns true if the dropdown list is expanded, else false.
9941 isExpanded : function(){
9942 return this.list.isVisible();
9946 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9947 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9948 * @param {String} value The data value of the item to select
9949 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9950 * selected item if it is not currently in view (defaults to true)
9951 * @return {Boolean} True if the value matched an item in the list, else false
9953 selectByValue : function(v, scrollIntoView){
9954 if(v !== undefined && v !== null){
9955 var r = this.findRecord(this.valueField || this.displayField, v);
9957 this.select(this.store.indexOf(r), scrollIntoView);
9965 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9966 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9967 * @param {Number} index The zero-based index of the list item to select
9968 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9969 * selected item if it is not currently in view (defaults to true)
9971 select : function(index, scrollIntoView){
9972 this.selectedIndex = index;
9973 this.view.select(index);
9974 if(scrollIntoView !== false){
9975 var el = this.view.getNode(index);
9977 //this.innerList.scrollChildIntoView(el, false);
9984 selectNext : function(){
9985 var ct = this.store.getCount();
9987 if(this.selectedIndex == -1){
9989 }else if(this.selectedIndex < ct-1){
9990 this.select(this.selectedIndex+1);
9996 selectPrev : function(){
9997 var ct = this.store.getCount();
9999 if(this.selectedIndex == -1){
10001 }else if(this.selectedIndex != 0){
10002 this.select(this.selectedIndex-1);
10008 onKeyUp : function(e){
10009 if(this.editable !== false && !e.isSpecialKey()){
10010 this.lastKey = e.getKey();
10011 this.dqTask.delay(this.queryDelay);
10016 validateBlur : function(){
10017 return !this.list || !this.list.isVisible();
10021 initQuery : function(){
10022 this.doQuery(this.getRawValue());
10026 doForce : function(){
10027 if(this.inputEl().dom.value.length > 0){
10028 this.inputEl().dom.value =
10029 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10035 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10036 * query allowing the query action to be canceled if needed.
10037 * @param {String} query The SQL query to execute
10038 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10039 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10040 * saved in the current store (defaults to false)
10042 doQuery : function(q, forceAll){
10044 if(q === undefined || q === null){
10049 forceAll: forceAll,
10053 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10058 forceAll = qe.forceAll;
10059 if(forceAll === true || (q.length >= this.minChars)){
10061 this.hasQuery = true;
10063 if(this.lastQuery != q || this.alwaysQuery){
10064 this.lastQuery = q;
10065 if(this.mode == 'local'){
10066 this.selectedIndex = -1;
10068 this.store.clearFilter();
10070 this.store.filter(this.displayField, q);
10074 this.store.baseParams[this.queryParam] = q;
10076 var options = {params : this.getParams(q)};
10079 options.add = true;
10080 options.params.start = this.page * this.pageSize;
10083 this.store.load(options);
10087 this.selectedIndex = -1;
10092 this.loadNext = false;
10096 getParams : function(q){
10098 //p[this.queryParam] = q;
10102 p.limit = this.pageSize;
10108 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10110 collapse : function(){
10111 if(!this.isExpanded()){
10116 Roo.get(document).un('mousedown', this.collapseIf, this);
10117 Roo.get(document).un('mousewheel', this.collapseIf, this);
10118 if (!this.editable) {
10119 Roo.get(document).un('keydown', this.listKeyPress, this);
10121 this.fireEvent('collapse', this);
10125 collapseIf : function(e){
10126 var in_combo = e.within(this.el);
10127 var in_list = e.within(this.list);
10129 if (in_combo || in_list) {
10130 //e.stopPropagation();
10139 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10141 expand : function(){
10143 if(this.isExpanded() || !this.hasFocus){
10147 this.list.alignTo(this.inputEl(), this.listAlign);
10149 Roo.get(document).on('mousedown', this.collapseIf, this);
10150 Roo.get(document).on('mousewheel', this.collapseIf, this);
10151 if (!this.editable) {
10152 Roo.get(document).on('keydown', this.listKeyPress, this);
10155 this.fireEvent('expand', this);
10159 // Implements the default empty TriggerField.onTriggerClick function
10160 onTriggerClick : function()
10162 Roo.log('trigger click');
10169 this.loadNext = false;
10171 if(this.isExpanded()){
10173 if (!this.blockFocus) {
10174 this.inputEl().focus();
10178 this.hasFocus = true;
10179 if(this.triggerAction == 'all') {
10180 this.doQuery(this.allQuery, true);
10182 this.doQuery(this.getRawValue());
10184 if (!this.blockFocus) {
10185 this.inputEl().focus();
10189 listKeyPress : function(e)
10191 //Roo.log('listkeypress');
10192 // scroll to first matching element based on key pres..
10193 if (e.isSpecialKey()) {
10196 var k = String.fromCharCode(e.getKey()).toUpperCase();
10199 var csel = this.view.getSelectedNodes();
10200 var cselitem = false;
10202 var ix = this.view.indexOf(csel[0]);
10203 cselitem = this.store.getAt(ix);
10204 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10210 this.store.each(function(v) {
10212 // start at existing selection.
10213 if (cselitem.id == v.id) {
10219 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10220 match = this.store.indexOf(v);
10226 if (match === false) {
10227 return true; // no more action?
10230 this.view.select(match);
10231 var sn = Roo.get(this.view.getSelectedNodes()[0])
10232 //sn.scrollIntoView(sn.dom.parentNode, false);
10235 onViewScroll : function(e, t){
10237 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10241 this.hasQuery = true;
10243 this.loading = this.list.select('.loading', true).first();
10245 if(this.loading === null){
10246 this.list.createChild({
10248 cls: 'loading select2-more-results select2-active',
10249 html: 'Loading more results...'
10252 this.loading = this.list.select('.loading', true).first();
10254 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10256 this.loading.hide();
10259 this.loading.show();
10264 this.loadNext = true;
10266 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10271 addItem : function(o)
10273 var dv = ''; // display value
10275 if (this.displayField) {
10276 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10278 // this is an error condition!!!
10279 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10286 var choice = this.choices.createChild({
10288 cls: 'select2-search-choice',
10297 cls: 'select2-search-choice-close',
10302 }, this.searchField);
10304 var close = choice.select('a.select2-search-choice-close', true).first()
10306 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10313 this.inputEl().dom.value = '';
10317 onRemoveItem : function(e, _self, o)
10319 e.preventDefault();
10320 var index = this.item.indexOf(o.data) * 1;
10323 Roo.log('not this item?!');
10327 this.item.splice(index, 1);
10332 this.fireEvent('remove', this, e);
10336 syncValue : function()
10338 if(!this.item.length){
10345 Roo.each(this.item, function(i){
10346 if(_this.valueField){
10347 value.push(i[_this.valueField]);
10354 this.value = value.join(',');
10356 if(this.hiddenField){
10357 this.hiddenField.dom.value = this.value;
10361 clearItem : function()
10363 if(!this.multiple){
10369 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10379 * @cfg {Boolean} grow
10383 * @cfg {Number} growMin
10387 * @cfg {Number} growMax
10397 * Ext JS Library 1.1.1
10398 * Copyright(c) 2006-2007, Ext JS, LLC.
10400 * Originally Released Under LGPL - original licence link has changed is not relivant.
10403 * <script type="text/javascript">
10408 * @extends Roo.util.Observable
10409 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10410 * This class also supports single and multi selection modes. <br>
10411 * Create a data model bound view:
10413 var store = new Roo.data.Store(...);
10415 var view = new Roo.View({
10417 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10419 singleSelect: true,
10420 selectedClass: "ydataview-selected",
10424 // listen for node click?
10425 view.on("click", function(vw, index, node, e){
10426 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10430 dataModel.load("foobar.xml");
10432 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10434 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10435 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10437 * Note: old style constructor is still suported (container, template, config)
10440 * Create a new View
10441 * @param {Object} config The config object
10444 Roo.View = function(config, depreciated_tpl, depreciated_config){
10446 if (typeof(depreciated_tpl) == 'undefined') {
10447 // new way.. - universal constructor.
10448 Roo.apply(this, config);
10449 this.el = Roo.get(this.el);
10452 this.el = Roo.get(config);
10453 this.tpl = depreciated_tpl;
10454 Roo.apply(this, depreciated_config);
10456 this.wrapEl = this.el.wrap().wrap();
10457 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10460 if(typeof(this.tpl) == "string"){
10461 this.tpl = new Roo.Template(this.tpl);
10463 // support xtype ctors..
10464 this.tpl = new Roo.factory(this.tpl, Roo);
10468 this.tpl.compile();
10476 * @event beforeclick
10477 * Fires before a click is processed. Returns false to cancel the default action.
10478 * @param {Roo.View} this
10479 * @param {Number} index The index of the target node
10480 * @param {HTMLElement} node The target node
10481 * @param {Roo.EventObject} e The raw event object
10483 "beforeclick" : true,
10486 * Fires when a template node is clicked.
10487 * @param {Roo.View} this
10488 * @param {Number} index The index of the target node
10489 * @param {HTMLElement} node The target node
10490 * @param {Roo.EventObject} e The raw event object
10495 * Fires when a template node is double clicked.
10496 * @param {Roo.View} this
10497 * @param {Number} index The index of the target node
10498 * @param {HTMLElement} node The target node
10499 * @param {Roo.EventObject} e The raw event object
10503 * @event contextmenu
10504 * Fires when a template node is right clicked.
10505 * @param {Roo.View} this
10506 * @param {Number} index The index of the target node
10507 * @param {HTMLElement} node The target node
10508 * @param {Roo.EventObject} e The raw event object
10510 "contextmenu" : true,
10512 * @event selectionchange
10513 * Fires when the selected nodes change.
10514 * @param {Roo.View} this
10515 * @param {Array} selections Array of the selected nodes
10517 "selectionchange" : true,
10520 * @event beforeselect
10521 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10522 * @param {Roo.View} this
10523 * @param {HTMLElement} node The node to be selected
10524 * @param {Array} selections Array of currently selected nodes
10526 "beforeselect" : true,
10528 * @event preparedata
10529 * Fires on every row to render, to allow you to change the data.
10530 * @param {Roo.View} this
10531 * @param {Object} data to be rendered (change this)
10533 "preparedata" : true
10541 "click": this.onClick,
10542 "dblclick": this.onDblClick,
10543 "contextmenu": this.onContextMenu,
10547 this.selections = [];
10549 this.cmp = new Roo.CompositeElementLite([]);
10551 this.store = Roo.factory(this.store, Roo.data);
10552 this.setStore(this.store, true);
10555 if ( this.footer && this.footer.xtype) {
10557 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10559 this.footer.dataSource = this.store
10560 this.footer.container = fctr;
10561 this.footer = Roo.factory(this.footer, Roo);
10562 fctr.insertFirst(this.el);
10564 // this is a bit insane - as the paging toolbar seems to detach the el..
10565 // dom.parentNode.parentNode.parentNode
10566 // they get detached?
10570 Roo.View.superclass.constructor.call(this);
10575 Roo.extend(Roo.View, Roo.util.Observable, {
10578 * @cfg {Roo.data.Store} store Data store to load data from.
10583 * @cfg {String|Roo.Element} el The container element.
10588 * @cfg {String|Roo.Template} tpl The template used by this View
10592 * @cfg {String} dataName the named area of the template to use as the data area
10593 * Works with domtemplates roo-name="name"
10597 * @cfg {String} selectedClass The css class to add to selected nodes
10599 selectedClass : "x-view-selected",
10601 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10606 * @cfg {String} text to display on mask (default Loading)
10610 * @cfg {Boolean} multiSelect Allow multiple selection
10612 multiSelect : false,
10614 * @cfg {Boolean} singleSelect Allow single selection
10616 singleSelect: false,
10619 * @cfg {Boolean} toggleSelect - selecting
10621 toggleSelect : false,
10624 * Returns the element this view is bound to.
10625 * @return {Roo.Element}
10627 getEl : function(){
10628 return this.wrapEl;
10634 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10636 refresh : function(){
10637 Roo.log('refresh');
10640 // if we are using something like 'domtemplate', then
10641 // the what gets used is:
10642 // t.applySubtemplate(NAME, data, wrapping data..)
10643 // the outer template then get' applied with
10644 // the store 'extra data'
10645 // and the body get's added to the
10646 // roo-name="data" node?
10647 // <span class='roo-tpl-{name}'></span> ?????
10651 this.clearSelections();
10652 this.el.update("");
10654 var records = this.store.getRange();
10655 if(records.length < 1) {
10657 // is this valid?? = should it render a template??
10659 this.el.update(this.emptyText);
10663 if (this.dataName) {
10664 this.el.update(t.apply(this.store.meta)); //????
10665 el = this.el.child('.roo-tpl-' + this.dataName);
10668 for(var i = 0, len = records.length; i < len; i++){
10669 var data = this.prepareData(records[i].data, i, records[i]);
10670 this.fireEvent("preparedata", this, data, i, records[i]);
10671 html[html.length] = Roo.util.Format.trim(
10673 t.applySubtemplate(this.dataName, data, this.store.meta) :
10680 el.update(html.join(""));
10681 this.nodes = el.dom.childNodes;
10682 this.updateIndexes(0);
10687 * Function to override to reformat the data that is sent to
10688 * the template for each node.
10689 * DEPRICATED - use the preparedata event handler.
10690 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10691 * a JSON object for an UpdateManager bound view).
10693 prepareData : function(data, index, record)
10695 this.fireEvent("preparedata", this, data, index, record);
10699 onUpdate : function(ds, record){
10700 Roo.log('on update');
10701 this.clearSelections();
10702 var index = this.store.indexOf(record);
10703 var n = this.nodes[index];
10704 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10705 n.parentNode.removeChild(n);
10706 this.updateIndexes(index, index);
10712 onAdd : function(ds, records, index)
10714 Roo.log(['on Add', ds, records, index] );
10715 this.clearSelections();
10716 if(this.nodes.length == 0){
10720 var n = this.nodes[index];
10721 for(var i = 0, len = records.length; i < len; i++){
10722 var d = this.prepareData(records[i].data, i, records[i]);
10724 this.tpl.insertBefore(n, d);
10727 this.tpl.append(this.el, d);
10730 this.updateIndexes(index);
10733 onRemove : function(ds, record, index){
10734 Roo.log('onRemove');
10735 this.clearSelections();
10736 var el = this.dataName ?
10737 this.el.child('.roo-tpl-' + this.dataName) :
10740 el.dom.removeChild(this.nodes[index]);
10741 this.updateIndexes(index);
10745 * Refresh an individual node.
10746 * @param {Number} index
10748 refreshNode : function(index){
10749 this.onUpdate(this.store, this.store.getAt(index));
10752 updateIndexes : function(startIndex, endIndex){
10753 var ns = this.nodes;
10754 startIndex = startIndex || 0;
10755 endIndex = endIndex || ns.length - 1;
10756 for(var i = startIndex; i <= endIndex; i++){
10757 ns[i].nodeIndex = i;
10762 * Changes the data store this view uses and refresh the view.
10763 * @param {Store} store
10765 setStore : function(store, initial){
10766 if(!initial && this.store){
10767 this.store.un("datachanged", this.refresh);
10768 this.store.un("add", this.onAdd);
10769 this.store.un("remove", this.onRemove);
10770 this.store.un("update", this.onUpdate);
10771 this.store.un("clear", this.refresh);
10772 this.store.un("beforeload", this.onBeforeLoad);
10773 this.store.un("load", this.onLoad);
10774 this.store.un("loadexception", this.onLoad);
10778 store.on("datachanged", this.refresh, this);
10779 store.on("add", this.onAdd, this);
10780 store.on("remove", this.onRemove, this);
10781 store.on("update", this.onUpdate, this);
10782 store.on("clear", this.refresh, this);
10783 store.on("beforeload", this.onBeforeLoad, this);
10784 store.on("load", this.onLoad, this);
10785 store.on("loadexception", this.onLoad, this);
10793 * onbeforeLoad - masks the loading area.
10796 onBeforeLoad : function(store,opts)
10798 Roo.log('onBeforeLoad');
10800 this.el.update("");
10802 this.el.mask(this.mask ? this.mask : "Loading" );
10804 onLoad : function ()
10811 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10812 * @param {HTMLElement} node
10813 * @return {HTMLElement} The template node
10815 findItemFromChild : function(node){
10816 var el = this.dataName ?
10817 this.el.child('.roo-tpl-' + this.dataName,true) :
10820 if(!node || node.parentNode == el){
10823 var p = node.parentNode;
10824 while(p && p != el){
10825 if(p.parentNode == el){
10834 onClick : function(e){
10835 var item = this.findItemFromChild(e.getTarget());
10837 var index = this.indexOf(item);
10838 if(this.onItemClick(item, index, e) !== false){
10839 this.fireEvent("click", this, index, item, e);
10842 this.clearSelections();
10847 onContextMenu : function(e){
10848 var item = this.findItemFromChild(e.getTarget());
10850 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10855 onDblClick : function(e){
10856 var item = this.findItemFromChild(e.getTarget());
10858 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10862 onItemClick : function(item, index, e)
10864 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10867 if (this.toggleSelect) {
10868 var m = this.isSelected(item) ? 'unselect' : 'select';
10871 _t[m](item, true, false);
10874 if(this.multiSelect || this.singleSelect){
10875 if(this.multiSelect && e.shiftKey && this.lastSelection){
10876 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10878 this.select(item, this.multiSelect && e.ctrlKey);
10879 this.lastSelection = item;
10881 e.preventDefault();
10887 * Get the number of selected nodes.
10890 getSelectionCount : function(){
10891 return this.selections.length;
10895 * Get the currently selected nodes.
10896 * @return {Array} An array of HTMLElements
10898 getSelectedNodes : function(){
10899 return this.selections;
10903 * Get the indexes of the selected nodes.
10906 getSelectedIndexes : function(){
10907 var indexes = [], s = this.selections;
10908 for(var i = 0, len = s.length; i < len; i++){
10909 indexes.push(s[i].nodeIndex);
10915 * Clear all selections
10916 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10918 clearSelections : function(suppressEvent){
10919 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10920 this.cmp.elements = this.selections;
10921 this.cmp.removeClass(this.selectedClass);
10922 this.selections = [];
10923 if(!suppressEvent){
10924 this.fireEvent("selectionchange", this, this.selections);
10930 * Returns true if the passed node is selected
10931 * @param {HTMLElement/Number} node The node or node index
10932 * @return {Boolean}
10934 isSelected : function(node){
10935 var s = this.selections;
10939 node = this.getNode(node);
10940 return s.indexOf(node) !== -1;
10945 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
10946 * @param {Boolean} keepExisting (optional) true to keep existing selections
10947 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10949 select : function(nodeInfo, keepExisting, suppressEvent){
10950 if(nodeInfo instanceof Array){
10952 this.clearSelections(true);
10954 for(var i = 0, len = nodeInfo.length; i < len; i++){
10955 this.select(nodeInfo[i], true, true);
10959 var node = this.getNode(nodeInfo);
10960 if(!node || this.isSelected(node)){
10961 return; // already selected.
10964 this.clearSelections(true);
10966 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10967 Roo.fly(node).addClass(this.selectedClass);
10968 this.selections.push(node);
10969 if(!suppressEvent){
10970 this.fireEvent("selectionchange", this, this.selections);
10978 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
10979 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10980 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10982 unselect : function(nodeInfo, keepExisting, suppressEvent)
10984 if(nodeInfo instanceof Array){
10985 Roo.each(this.selections, function(s) {
10986 this.unselect(s, nodeInfo);
10990 var node = this.getNode(nodeInfo);
10991 if(!node || !this.isSelected(node)){
10992 Roo.log("not selected");
10993 return; // not selected.
10997 Roo.each(this.selections, function(s) {
10999 Roo.fly(node).removeClass(this.selectedClass);
11006 this.selections= ns;
11007 this.fireEvent("selectionchange", this, this.selections);
11011 * Gets a template node.
11012 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11013 * @return {HTMLElement} The node or null if it wasn't found
11015 getNode : function(nodeInfo){
11016 if(typeof nodeInfo == "string"){
11017 return document.getElementById(nodeInfo);
11018 }else if(typeof nodeInfo == "number"){
11019 return this.nodes[nodeInfo];
11025 * Gets a range template nodes.
11026 * @param {Number} startIndex
11027 * @param {Number} endIndex
11028 * @return {Array} An array of nodes
11030 getNodes : function(start, end){
11031 var ns = this.nodes;
11032 start = start || 0;
11033 end = typeof end == "undefined" ? ns.length - 1 : end;
11036 for(var i = start; i <= end; i++){
11040 for(var i = start; i >= end; i--){
11048 * Finds the index of the passed node
11049 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11050 * @return {Number} The index of the node or -1
11052 indexOf : function(node){
11053 node = this.getNode(node);
11054 if(typeof node.nodeIndex == "number"){
11055 return node.nodeIndex;
11057 var ns = this.nodes;
11058 for(var i = 0, len = ns.length; i < len; i++){
11069 * based on jquery fullcalendar
11073 Roo.bootstrap = Roo.bootstrap || {};
11075 * @class Roo.bootstrap.Calendar
11076 * @extends Roo.bootstrap.Component
11077 * Bootstrap Calendar class
11078 * @cfg {Boolean} loadMask (true|false) default false
11079 * @cfg {Object} header generate the user specific header of the calendar, default false
11082 * Create a new Container
11083 * @param {Object} config The config object
11088 Roo.bootstrap.Calendar = function(config){
11089 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11093 * Fires when a date is selected
11094 * @param {DatePicker} this
11095 * @param {Date} date The selected date
11099 * @event monthchange
11100 * Fires when the displayed month changes
11101 * @param {DatePicker} this
11102 * @param {Date} date The selected month
11104 'monthchange': true,
11106 * @event evententer
11107 * Fires when mouse over an event
11108 * @param {Calendar} this
11109 * @param {event} Event
11111 'evententer': true,
11113 * @event eventleave
11114 * Fires when the mouse leaves an
11115 * @param {Calendar} this
11118 'eventleave': true,
11120 * @event eventclick
11121 * Fires when the mouse click an
11122 * @param {Calendar} this
11131 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11134 * @cfg {Number} startDay
11135 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11143 getAutoCreate : function(){
11146 var fc_button = function(name, corner, style, content ) {
11147 return Roo.apply({},{
11149 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11151 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11154 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11165 style : 'width:100%',
11172 cls : 'fc-header-left',
11174 fc_button('prev', 'left', 'arrow', '‹' ),
11175 fc_button('next', 'right', 'arrow', '›' ),
11176 { tag: 'span', cls: 'fc-header-space' },
11177 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11185 cls : 'fc-header-center',
11189 cls: 'fc-header-title',
11192 html : 'month / year'
11200 cls : 'fc-header-right',
11202 /* fc_button('month', 'left', '', 'month' ),
11203 fc_button('week', '', '', 'week' ),
11204 fc_button('day', 'right', '', 'day' )
11216 header = this.header;
11219 var cal_heads = function() {
11221 // fixme - handle this.
11223 for (var i =0; i < Date.dayNames.length; i++) {
11224 var d = Date.dayNames[i];
11227 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11228 html : d.substring(0,3)
11232 ret[0].cls += ' fc-first';
11233 ret[6].cls += ' fc-last';
11236 var cal_cell = function(n) {
11239 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11244 cls: 'fc-day-number',
11248 cls: 'fc-day-content',
11252 style: 'position: relative;' // height: 17px;
11264 var cal_rows = function() {
11267 for (var r = 0; r < 6; r++) {
11274 for (var i =0; i < Date.dayNames.length; i++) {
11275 var d = Date.dayNames[i];
11276 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11279 row.cn[0].cls+=' fc-first';
11280 row.cn[0].cn[0].style = 'min-height:90px';
11281 row.cn[6].cls+=' fc-last';
11285 ret[0].cls += ' fc-first';
11286 ret[4].cls += ' fc-prev-last';
11287 ret[5].cls += ' fc-last';
11294 cls: 'fc-border-separate',
11295 style : 'width:100%',
11303 cls : 'fc-first fc-last',
11321 cls : 'fc-content',
11322 style : "position: relative;",
11325 cls : 'fc-view fc-view-month fc-grid',
11326 style : 'position: relative',
11327 unselectable : 'on',
11330 cls : 'fc-event-container',
11331 style : 'position:absolute;z-index:8;top:0;left:0;'
11349 initEvents : function()
11352 throw "can not find store for calendar";
11358 style: "text-align:center",
11362 style: "background-color:white;width:50%;margin:250 auto",
11366 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11377 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11379 var size = this.el.select('.fc-content', true).first().getSize();
11380 this.maskEl.setSize(size.width, size.height);
11381 this.maskEl.enableDisplayMode("block");
11382 if(!this.loadMask){
11383 this.maskEl.hide();
11386 this.store = Roo.factory(this.store, Roo.data);
11387 this.store.on('load', this.onLoad, this);
11388 this.store.on('beforeload', this.onBeforeLoad, this);
11392 this.cells = this.el.select('.fc-day',true);
11393 //Roo.log(this.cells);
11394 this.textNodes = this.el.query('.fc-day-number');
11395 this.cells.addClassOnOver('fc-state-hover');
11397 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11398 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11399 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11400 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11402 this.on('monthchange', this.onMonthChange, this);
11404 this.update(new Date().clearTime());
11407 resize : function() {
11408 var sz = this.el.getSize();
11410 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11411 this.el.select('.fc-day-content div',true).setHeight(34);
11416 showPrevMonth : function(e){
11417 this.update(this.activeDate.add("mo", -1));
11419 showToday : function(e){
11420 this.update(new Date().clearTime());
11423 showNextMonth : function(e){
11424 this.update(this.activeDate.add("mo", 1));
11428 showPrevYear : function(){
11429 this.update(this.activeDate.add("y", -1));
11433 showNextYear : function(){
11434 this.update(this.activeDate.add("y", 1));
11439 update : function(date)
11441 var vd = this.activeDate;
11442 this.activeDate = date;
11443 // if(vd && this.el){
11444 // var t = date.getTime();
11445 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11446 // Roo.log('using add remove');
11448 // this.fireEvent('monthchange', this, date);
11450 // this.cells.removeClass("fc-state-highlight");
11451 // this.cells.each(function(c){
11452 // if(c.dateValue == t){
11453 // c.addClass("fc-state-highlight");
11454 // setTimeout(function(){
11455 // try{c.dom.firstChild.focus();}catch(e){}
11465 var days = date.getDaysInMonth();
11467 var firstOfMonth = date.getFirstDateOfMonth();
11468 var startingPos = firstOfMonth.getDay()-this.startDay;
11470 if(startingPos < this.startDay){
11474 var pm = date.add(Date.MONTH, -1);
11475 var prevStart = pm.getDaysInMonth()-startingPos;
11477 this.cells = this.el.select('.fc-day',true);
11478 this.textNodes = this.el.query('.fc-day-number');
11479 this.cells.addClassOnOver('fc-state-hover');
11481 var cells = this.cells.elements;
11482 var textEls = this.textNodes;
11484 Roo.each(cells, function(cell){
11485 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11488 days += startingPos;
11490 // convert everything to numbers so it's fast
11491 var day = 86400000;
11492 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11495 //Roo.log(prevStart);
11497 var today = new Date().clearTime().getTime();
11498 var sel = date.clearTime().getTime();
11499 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11500 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11501 var ddMatch = this.disabledDatesRE;
11502 var ddText = this.disabledDatesText;
11503 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11504 var ddaysText = this.disabledDaysText;
11505 var format = this.format;
11507 var setCellClass = function(cal, cell){
11511 //Roo.log('set Cell Class');
11513 var t = d.getTime();
11517 cell.dateValue = t;
11519 cell.className += " fc-today";
11520 cell.className += " fc-state-highlight";
11521 cell.title = cal.todayText;
11524 // disable highlight in other month..
11525 //cell.className += " fc-state-highlight";
11530 cell.className = " fc-state-disabled";
11531 cell.title = cal.minText;
11535 cell.className = " fc-state-disabled";
11536 cell.title = cal.maxText;
11540 if(ddays.indexOf(d.getDay()) != -1){
11541 cell.title = ddaysText;
11542 cell.className = " fc-state-disabled";
11545 if(ddMatch && format){
11546 var fvalue = d.dateFormat(format);
11547 if(ddMatch.test(fvalue)){
11548 cell.title = ddText.replace("%0", fvalue);
11549 cell.className = " fc-state-disabled";
11553 if (!cell.initialClassName) {
11554 cell.initialClassName = cell.dom.className;
11557 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11562 for(; i < startingPos; i++) {
11563 textEls[i].innerHTML = (++prevStart);
11564 d.setDate(d.getDate()+1);
11566 cells[i].className = "fc-past fc-other-month";
11567 setCellClass(this, cells[i]);
11572 for(; i < days; i++){
11573 intDay = i - startingPos + 1;
11574 textEls[i].innerHTML = (intDay);
11575 d.setDate(d.getDate()+1);
11577 cells[i].className = ''; // "x-date-active";
11578 setCellClass(this, cells[i]);
11582 for(; i < 42; i++) {
11583 textEls[i].innerHTML = (++extraDays);
11584 d.setDate(d.getDate()+1);
11586 cells[i].className = "fc-future fc-other-month";
11587 setCellClass(this, cells[i]);
11590 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11592 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11594 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11595 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11597 if(totalRows != 6){
11598 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11599 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11602 this.fireEvent('monthchange', this, date);
11606 if(!this.internalRender){
11607 var main = this.el.dom.firstChild;
11608 var w = main.offsetWidth;
11609 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11610 Roo.fly(main).setWidth(w);
11611 this.internalRender = true;
11612 // opera does not respect the auto grow header center column
11613 // then, after it gets a width opera refuses to recalculate
11614 // without a second pass
11615 if(Roo.isOpera && !this.secondPass){
11616 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11617 this.secondPass = true;
11618 this.update.defer(10, this, [date]);
11625 findCell : function(dt) {
11626 dt = dt.clearTime().getTime();
11628 this.cells.each(function(c){
11629 //Roo.log("check " +c.dateValue + '?=' + dt);
11630 if(c.dateValue == dt){
11640 findCells : function(ev) {
11641 var s = ev.start.clone().clearTime().getTime();
11643 var e= ev.end.clone().clearTime().getTime();
11646 this.cells.each(function(c){
11647 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11649 if(c.dateValue > e){
11652 if(c.dateValue < s){
11661 // findBestRow: function(cells)
11665 // for (var i =0 ; i < cells.length;i++) {
11666 // ret = Math.max(cells[i].rows || 0,ret);
11673 addItem : function(ev)
11675 // look for vertical location slot in
11676 var cells = this.findCells(ev);
11678 // ev.row = this.findBestRow(cells);
11680 // work out the location.
11684 for(var i =0; i < cells.length; i++) {
11686 cells[i].row = cells[0].row;
11689 cells[i].row = cells[i].row + 1;
11699 if (crow.start.getY() == cells[i].getY()) {
11701 crow.end = cells[i];
11718 cells[0].events.push(ev);
11720 // if((typeof(cells[0].events) == 'undefined')){
11721 // cells[0].events = [];
11724 // cells[0].events.push(ev);
11725 // ev.rendered = false;
11726 // for (var i = 0; i < cells.length;i++) {
11727 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11731 this.calevents.push(ev);
11734 clearEvents: function() {
11736 if(!this.calevents){
11740 Roo.each(this.cells.elements, function(c){
11746 Roo.each(this.calevents, function(e) {
11747 Roo.each(e.els, function(el) {
11748 el.un('mouseenter' ,this.onEventEnter, this);
11749 el.un('mouseleave' ,this.onEventLeave, this);
11754 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11760 renderEvents: function()
11762 // for (var e = 0; e < this.calevents.length; e++) {
11764 // var ev = this.calevents[e];
11765 // var cells = ev.cells;
11766 // var rows = ev.rows;
11768 // for (var j = 0; j < cells.length; j++){
11770 // if(!cells[j].more.length){
11773 // if(cells[j].row > 3){
11774 // cells[j].more.push(ev);
11778 // cells[j].events.push(ev);
11782 // for (var i = 0; i < rows.length; i++){
11783 // // how many rows should it span..
11786 // cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11787 // style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11789 // unselectable : "on",
11792 // cls: 'fc-event-inner',
11796 //// cls: 'fc-event-time',
11797 //// html : cells.length > 1 ? '' : ev.time
11801 // cls: 'fc-event-title',
11802 // html : String.format('{0}', ev.title)
11809 // cls: 'ui-resizable-handle ui-resizable-e',
11810 // html : '  '
11817 // cfg.cls += ' fc-event-start';
11819 // if ((i+1) == rows.length) {
11820 // cfg.cls += ' fc-event-end';
11823 // var ctr = this.el.select('.fc-event-container',true).first();
11824 // var cg = ctr.createChild(cfg);
11826 // var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11827 // var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11829 // cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11830 // cg.setWidth(ebox.right - sbox.x -2);
11832 // cg.on('mouseenter' ,this.onEventEnter, this, ev);
11833 // cg.on('mouseleave' ,this.onEventLeave, this, ev);
11834 // cg.on('click', this.onEventClick, this, ev);
11836 // ev.els.push(cg);
11844 this.cells.each(function(c) {
11853 if(c.row != c.events.length){
11854 r = 4 - (4 - (c.row - c.events.length));
11857 c.events = ev.slice(0, r);
11858 c.more = ev.slice(r);
11860 if(c.more.length && c.more.length == 1){
11861 c.events.push(c.more.pop());
11864 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
11868 // for (var e = 0; e < this.calevents.length; e++) {
11870 // var ev = this.calevents[e];
11871 // var cells = ev.cells;
11872 // var rows = ev.rows;
11874 // for(var i = 0; i < cells.length; i++){
11876 // var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11878 // if(cells.length < 2 && cbox.rows.length > 3){
11879 // cbox.more.push(ev);
11883 // cbox.rows.push(ev);
11887 this.cells.each(function(c) {
11889 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
11892 for (var e = 0; e < c.events.length; e++){
11893 var ev = c.events[e];
11894 var rows = ev.rows;
11896 for(var i = 0; i < rows.length; i++) {
11898 // how many rows should it span..
11901 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11902 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11904 unselectable : "on",
11907 cls: 'fc-event-inner',
11911 // cls: 'fc-event-time',
11912 // html : cells.length > 1 ? '' : ev.time
11916 cls: 'fc-event-title',
11917 html : String.format('{0}', ev.title)
11924 cls: 'ui-resizable-handle ui-resizable-e',
11925 html : '  '
11932 cfg.cls += ' fc-event-start';
11934 if ((i+1) == rows.length) {
11935 cfg.cls += ' fc-event-end';
11938 var ctr = _this.el.select('.fc-event-container',true).first();
11939 var cg = ctr.createChild(cfg);
11941 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11942 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11944 var r = (c.more.length) ? 1 : 0;
11945 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
11946 cg.setWidth(ebox.right - sbox.x -2);
11948 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11949 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11950 cg.on('click', _this.onEventClick, _this, ev);
11961 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11962 style : 'position: absolute',
11963 unselectable : "on",
11966 cls: 'fc-event-inner',
11970 cls: 'fc-event-title',
11978 cls: 'ui-resizable-handle ui-resizable-e',
11979 html : '  '
11985 var ctr = _this.el.select('.fc-event-container',true).first();
11986 var cg = ctr.createChild(cfg);
11988 var sbox = c.select('.fc-day-content',true).first().getBox();
11989 var ebox = c.select('.fc-day-content',true).first().getBox();
11991 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
11992 cg.setWidth(ebox.right - sbox.x -2);
11994 cg.on('click', _this.onMoreEventClick, _this, c.more);
12004 onEventEnter: function (e, el,event,d) {
12005 this.fireEvent('evententer', this, el, event);
12008 onEventLeave: function (e, el,event,d) {
12009 this.fireEvent('eventleave', this, el, event);
12012 onEventClick: function (e, el,event,d) {
12013 this.fireEvent('eventclick', this, el, event);
12016 onMonthChange: function () {
12020 onMoreEventClick: function(e, el, more)
12024 this.calpopover.placement = 'right';
12025 this.calpopover.setTitle('More');
12027 this.calpopover.setContent('');
12029 var ctr = this.calpopover.el.select('.popover-content', true).first();
12031 Roo.each(more, function(m){
12033 cls : 'fc-event-hori fc-event-draggable',
12036 var cg = ctr.createChild(cfg);
12038 cg.on('click', _this.onEventClick, _this, m);
12041 this.calpopover.show(el);
12046 onLoad: function ()
12048 this.calevents = [];
12051 if(this.store.getCount() > 0){
12052 this.store.data.each(function(d){
12055 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
12056 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
12057 time : d.data.start_time,
12058 title : d.data.title,
12059 description : d.data.description,
12060 venue : d.data.venue
12065 this.renderEvents();
12067 if(this.calevents.length && this.loadMask){
12068 this.maskEl.hide();
12072 onBeforeLoad: function()
12074 this.clearEvents();
12076 this.maskEl.show();
12090 * @class Roo.bootstrap.Popover
12091 * @extends Roo.bootstrap.Component
12092 * Bootstrap Popover class
12093 * @cfg {String} html contents of the popover (or false to use children..)
12094 * @cfg {String} title of popover (or false to hide)
12095 * @cfg {String} placement how it is placed
12096 * @cfg {String} trigger click || hover (or false to trigger manually)
12097 * @cfg {String} over what (parent or false to trigger manually.)
12100 * Create a new Popover
12101 * @param {Object} config The config object
12104 Roo.bootstrap.Popover = function(config){
12105 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
12108 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
12110 title: 'Fill in a title',
12113 placement : 'right',
12114 trigger : 'hover', // hover
12118 can_build_overlaid : false,
12120 getChildContainer : function()
12122 return this.el.select('.popover-content',true).first();
12125 getAutoCreate : function(){
12126 Roo.log('make popover?');
12128 cls : 'popover roo-dynamic',
12129 style: 'display:block',
12135 cls : 'popover-inner',
12139 cls: 'popover-title',
12143 cls : 'popover-content',
12154 setTitle: function(str)
12156 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12158 setContent: function(str)
12160 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12162 // as it get's added to the bottom of the page.
12163 onRender : function(ct, position)
12165 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12167 var cfg = Roo.apply({}, this.getAutoCreate());
12171 cfg.cls += ' ' + this.cls;
12174 cfg.style = this.style;
12176 Roo.log("adding to ")
12177 this.el = Roo.get(document.body).createChild(cfg, position);
12183 initEvents : function()
12185 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12186 this.el.enableDisplayMode('block');
12188 if (this.over === false) {
12191 if (this.triggers === false) {
12194 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12195 var triggers = this.trigger ? this.trigger.split(' ') : [];
12196 Roo.each(triggers, function(trigger) {
12198 if (trigger == 'click') {
12199 on_el.on('click', this.toggle, this);
12200 } else if (trigger != 'manual') {
12201 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12202 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12204 on_el.on(eventIn ,this.enter, this);
12205 on_el.on(eventOut, this.leave, this);
12216 toggle : function () {
12217 this.hoverState == 'in' ? this.leave() : this.enter();
12220 enter : function () {
12223 clearTimeout(this.timeout);
12225 this.hoverState = 'in'
12227 if (!this.delay || !this.delay.show) {
12232 this.timeout = setTimeout(function () {
12233 if (_t.hoverState == 'in') {
12236 }, this.delay.show)
12238 leave : function() {
12239 clearTimeout(this.timeout);
12241 this.hoverState = 'out'
12243 if (!this.delay || !this.delay.hide) {
12248 this.timeout = setTimeout(function () {
12249 if (_t.hoverState == 'out') {
12252 }, this.delay.hide)
12255 show : function (on_el)
12258 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12261 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12262 if (this.html !== false) {
12263 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12265 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12266 if (!this.title.length) {
12267 this.el.select('.popover-title',true).hide();
12270 var placement = typeof this.placement == 'function' ?
12271 this.placement.call(this, this.el, on_el) :
12274 var autoToken = /\s?auto?\s?/i;
12275 var autoPlace = autoToken.test(placement);
12277 placement = placement.replace(autoToken, '') || 'top';
12281 //this.el.setXY([0,0]);
12283 this.el.dom.style.display='block';
12284 this.el.addClass(placement);
12286 //this.el.appendTo(on_el);
12288 var p = this.getPosition();
12289 var box = this.el.getBox();
12294 var align = Roo.bootstrap.Popover.alignment[placement]
12295 this.el.alignTo(on_el, align[0],align[1]);
12296 //var arrow = this.el.select('.arrow',true).first();
12297 //arrow.set(align[2],
12299 this.el.addClass('in');
12300 this.hoverState = null;
12302 if (this.el.hasClass('fade')) {
12309 this.el.setXY([0,0]);
12310 this.el.removeClass('in');
12317 Roo.bootstrap.Popover.alignment = {
12318 'left' : ['r-l', [-10,0], 'right'],
12319 'right' : ['l-r', [10,0], 'left'],
12320 'bottom' : ['t-b', [0,10], 'top'],
12321 'top' : [ 'b-t', [0,-10], 'bottom']
12332 * @class Roo.bootstrap.Progress
12333 * @extends Roo.bootstrap.Component
12334 * Bootstrap Progress class
12335 * @cfg {Boolean} striped striped of the progress bar
12336 * @cfg {Boolean} active animated of the progress bar
12340 * Create a new Progress
12341 * @param {Object} config The config object
12344 Roo.bootstrap.Progress = function(config){
12345 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12348 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12353 getAutoCreate : function(){
12361 cfg.cls += ' progress-striped';
12365 cfg.cls += ' active';
12384 * @class Roo.bootstrap.ProgressBar
12385 * @extends Roo.bootstrap.Component
12386 * Bootstrap ProgressBar class
12387 * @cfg {Number} aria_valuenow aria-value now
12388 * @cfg {Number} aria_valuemin aria-value min
12389 * @cfg {Number} aria_valuemax aria-value max
12390 * @cfg {String} label label for the progress bar
12391 * @cfg {String} panel (success | info | warning | danger )
12392 * @cfg {String} role role of the progress bar
12393 * @cfg {String} sr_only text
12397 * Create a new ProgressBar
12398 * @param {Object} config The config object
12401 Roo.bootstrap.ProgressBar = function(config){
12402 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12405 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12409 aria_valuemax : 100,
12415 getAutoCreate : function()
12420 cls: 'progress-bar',
12421 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12433 cfg.role = this.role;
12436 if(this.aria_valuenow){
12437 cfg['aria-valuenow'] = this.aria_valuenow;
12440 if(this.aria_valuemin){
12441 cfg['aria-valuemin'] = this.aria_valuemin;
12444 if(this.aria_valuemax){
12445 cfg['aria-valuemax'] = this.aria_valuemax;
12448 if(this.label && !this.sr_only){
12449 cfg.html = this.label;
12453 cfg.cls += ' progress-bar-' + this.panel;
12459 update : function(aria_valuenow)
12461 this.aria_valuenow = aria_valuenow;
12463 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12478 * @class Roo.bootstrap.TabPanel
12479 * @extends Roo.bootstrap.Component
12480 * Bootstrap TabPanel class
12481 * @cfg {Boolean} active panel active
12482 * @cfg {String} html panel content
12483 * @cfg {String} tabId tab relate id
12484 * @cfg {String} navId The navbar which triggers show hide
12488 * Create a new TabPanel
12489 * @param {Object} config The config object
12492 Roo.bootstrap.TabPanel = function(config){
12493 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12497 * Fires when the active status changes
12498 * @param {Roo.bootstrap.TabPanel} this
12499 * @param {Boolean} state the new state
12506 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12513 getAutoCreate : function(){
12517 html: this.html || ''
12521 cfg.cls += ' active';
12525 cfg.tabId = this.tabId;
12530 onRender : function(ct, position)
12532 // Roo.log("Call onRender: " + this.xtype);
12534 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12536 if (this.navId && this.tabId) {
12537 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12539 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12541 item.on('changed', function(item, state) {
12542 this.setActive(state);
12548 setActive: function(state)
12550 Roo.log("panel - set active " + this.tabId + "=" + state);
12552 this.active = state;
12554 this.el.removeClass('active');
12556 } else if (!this.el.hasClass('active')) {
12557 this.el.addClass('active');
12559 this.fireEvent('changed', this, state);
12576 * @class Roo.bootstrap.DateField
12577 * @extends Roo.bootstrap.Input
12578 * Bootstrap DateField class
12579 * @cfg {Number} weekStart default 0
12580 * @cfg {Number} weekStart default 0
12581 * @cfg {Number} viewMode default empty, (months|years)
12582 * @cfg {Number} minViewMode default empty, (months|years)
12583 * @cfg {Number} startDate default -Infinity
12584 * @cfg {Number} endDate default Infinity
12585 * @cfg {Boolean} todayHighlight default false
12586 * @cfg {Boolean} todayBtn default false
12587 * @cfg {Boolean} calendarWeeks default false
12588 * @cfg {Object} daysOfWeekDisabled default empty
12590 * @cfg {Boolean} keyboardNavigation default true
12591 * @cfg {String} language default en
12594 * Create a new DateField
12595 * @param {Object} config The config object
12598 Roo.bootstrap.DateField = function(config){
12599 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12603 * Fires when this field show.
12604 * @param {Roo.bootstrap.DateField} this
12605 * @param {Mixed} date The date value
12610 * Fires when this field hide.
12611 * @param {Roo.bootstrap.DateField} this
12612 * @param {Mixed} date The date value
12617 * Fires when select a date.
12618 * @param {Roo.bootstrap.DateField} this
12619 * @param {Mixed} date The date value
12625 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12628 * @cfg {String} format
12629 * The default date format string which can be overriden for localization support. The format must be
12630 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12634 * @cfg {String} altFormats
12635 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12636 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12638 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12646 todayHighlight : false,
12652 keyboardNavigation: true,
12654 calendarWeeks: false,
12656 startDate: -Infinity,
12660 daysOfWeekDisabled: [],
12664 UTCDate: function()
12666 return new Date(Date.UTC.apply(Date, arguments));
12669 UTCToday: function()
12671 var today = new Date();
12672 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12675 getDate: function() {
12676 var d = this.getUTCDate();
12677 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12680 getUTCDate: function() {
12684 setDate: function(d) {
12685 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12688 setUTCDate: function(d) {
12690 this.setValue(this.formatDate(this.date));
12693 onRender: function(ct, position)
12696 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12698 this.language = this.language || 'en';
12699 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12700 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12702 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12703 this.format = this.format || 'm/d/y';
12704 this.isInline = false;
12705 this.isInput = true;
12706 this.component = this.el.select('.add-on', true).first() || false;
12707 this.component = (this.component && this.component.length === 0) ? false : this.component;
12708 this.hasInput = this.component && this.inputEL().length;
12710 if (typeof(this.minViewMode === 'string')) {
12711 switch (this.minViewMode) {
12713 this.minViewMode = 1;
12716 this.minViewMode = 2;
12719 this.minViewMode = 0;
12724 if (typeof(this.viewMode === 'string')) {
12725 switch (this.viewMode) {
12738 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12740 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12742 this.picker().on('mousedown', this.onMousedown, this);
12743 this.picker().on('click', this.onClick, this);
12745 this.picker().addClass('datepicker-dropdown');
12747 this.startViewMode = this.viewMode;
12750 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12751 if(!this.calendarWeeks){
12756 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12757 v.attr('colspan', function(i, val){
12758 return parseInt(val) + 1;
12763 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12765 this.setStartDate(this.startDate);
12766 this.setEndDate(this.endDate);
12768 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12775 if(this.isInline) {
12780 picker : function()
12782 return this.el.select('.datepicker', true).first();
12785 fillDow: function()
12787 var dowCnt = this.weekStart;
12796 if(this.calendarWeeks){
12804 while (dowCnt < this.weekStart + 7) {
12808 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12812 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12815 fillMonths: function()
12818 var months = this.picker().select('>.datepicker-months td', true).first();
12820 months.dom.innerHTML = '';
12826 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12829 months.createChild(month);
12834 update: function(){
12836 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12838 if (this.date < this.startDate) {
12839 this.viewDate = new Date(this.startDate);
12840 } else if (this.date > this.endDate) {
12841 this.viewDate = new Date(this.endDate);
12843 this.viewDate = new Date(this.date);
12850 var d = new Date(this.viewDate),
12851 year = d.getUTCFullYear(),
12852 month = d.getUTCMonth(),
12853 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12854 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12855 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12856 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12857 currentDate = this.date && this.date.valueOf(),
12858 today = this.UTCToday();
12860 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12862 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12864 // this.picker.select('>tfoot th.today').
12865 // .text(dates[this.language].today)
12866 // .toggle(this.todayBtn !== false);
12868 this.updateNavArrows();
12871 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12873 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12875 prevMonth.setUTCDate(day);
12877 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12879 var nextMonth = new Date(prevMonth);
12881 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12883 nextMonth = nextMonth.valueOf();
12885 var fillMonths = false;
12887 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12889 while(prevMonth.valueOf() < nextMonth) {
12892 if (prevMonth.getUTCDay() === this.weekStart) {
12894 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12902 if(this.calendarWeeks){
12903 // ISO 8601: First week contains first thursday.
12904 // ISO also states week starts on Monday, but we can be more abstract here.
12906 // Start of current week: based on weekstart/current date
12907 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12908 // Thursday of this week
12909 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12910 // First Thursday of year, year from thursday
12911 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12912 // Calendar week: ms between thursdays, div ms per day, div 7 days
12913 calWeek = (th - yth) / 864e5 / 7 + 1;
12915 fillMonths.cn.push({
12923 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12925 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12928 if (this.todayHighlight &&
12929 prevMonth.getUTCFullYear() == today.getFullYear() &&
12930 prevMonth.getUTCMonth() == today.getMonth() &&
12931 prevMonth.getUTCDate() == today.getDate()) {
12932 clsName += ' today';
12935 if (currentDate && prevMonth.valueOf() === currentDate) {
12936 clsName += ' active';
12939 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12940 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12941 clsName += ' disabled';
12944 fillMonths.cn.push({
12946 cls: 'day ' + clsName,
12947 html: prevMonth.getDate()
12950 prevMonth.setDate(prevMonth.getDate()+1);
12953 var currentYear = this.date && this.date.getUTCFullYear();
12954 var currentMonth = this.date && this.date.getUTCMonth();
12956 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12958 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12959 v.removeClass('active');
12961 if(currentYear === year && k === currentMonth){
12962 v.addClass('active');
12965 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12966 v.addClass('disabled');
12972 year = parseInt(year/10, 10) * 10;
12974 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12976 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12979 for (var i = -1; i < 11; i++) {
12980 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12982 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12990 showMode: function(dir) {
12992 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12994 Roo.each(this.picker().select('>div',true).elements, function(v){
12995 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12998 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
13003 if(this.isInline) return;
13005 this.picker().removeClass(['bottom', 'top']);
13007 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13009 * place to the top of element!
13013 this.picker().addClass('top');
13014 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13019 this.picker().addClass('bottom');
13021 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13024 parseDate : function(value){
13025 if(!value || value instanceof Date){
13028 var v = Date.parseDate(value, this.format);
13029 if (!v && this.useIso) {
13030 v = Date.parseDate(value, 'Y-m-d');
13032 if(!v && this.altFormats){
13033 if(!this.altFormatsArray){
13034 this.altFormatsArray = this.altFormats.split("|");
13036 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
13037 v = Date.parseDate(value, this.altFormatsArray[i]);
13043 formatDate : function(date, fmt){
13044 return (!date || !(date instanceof Date)) ?
13045 date : date.dateFormat(fmt || this.format);
13048 onFocus : function()
13050 Roo.bootstrap.DateField.superclass.onFocus.call(this);
13054 onBlur : function()
13056 Roo.bootstrap.DateField.superclass.onBlur.call(this);
13062 this.picker().show();
13066 this.fireEvent('show', this, this.date);
13071 if(this.isInline) return;
13072 this.picker().hide();
13073 this.viewMode = this.startViewMode;
13076 this.fireEvent('hide', this, this.date);
13080 onMousedown: function(e){
13081 e.stopPropagation();
13082 e.preventDefault();
13085 keyup: function(e){
13086 Roo.bootstrap.DateField.superclass.keyup.call(this);
13091 setValue: function(v){
13092 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
13094 this.fireEvent('select', this, this.date);
13098 fireKey: function(e){
13099 if (!this.picker().isVisible()){
13100 if (e.keyCode == 27) // allow escape to hide and re-show picker
13104 var dateChanged = false,
13106 newDate, newViewDate;
13110 e.preventDefault();
13114 if (!this.keyboardNavigation) break;
13115 dir = e.keyCode == 37 ? -1 : 1;
13118 newDate = this.moveYear(this.date, dir);
13119 newViewDate = this.moveYear(this.viewDate, dir);
13120 } else if (e.shiftKey){
13121 newDate = this.moveMonth(this.date, dir);
13122 newViewDate = this.moveMonth(this.viewDate, dir);
13124 newDate = new Date(this.date);
13125 newDate.setUTCDate(this.date.getUTCDate() + dir);
13126 newViewDate = new Date(this.viewDate);
13127 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13129 if (this.dateWithinRange(newDate)){
13130 this.date = newDate;
13131 this.viewDate = newViewDate;
13132 this.setValue(this.formatDate(this.date));
13134 e.preventDefault();
13135 dateChanged = true;
13140 if (!this.keyboardNavigation) break;
13141 dir = e.keyCode == 38 ? -1 : 1;
13143 newDate = this.moveYear(this.date, dir);
13144 newViewDate = this.moveYear(this.viewDate, dir);
13145 } else if (e.shiftKey){
13146 newDate = this.moveMonth(this.date, dir);
13147 newViewDate = this.moveMonth(this.viewDate, dir);
13149 newDate = new Date(this.date);
13150 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13151 newViewDate = new Date(this.viewDate);
13152 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13154 if (this.dateWithinRange(newDate)){
13155 this.date = newDate;
13156 this.viewDate = newViewDate;
13157 this.setValue(this.formatDate(this.date));
13159 e.preventDefault();
13160 dateChanged = true;
13164 this.setValue(this.formatDate(this.date));
13166 e.preventDefault();
13169 this.setValue(this.formatDate(this.date));
13176 onClick: function(e) {
13177 e.stopPropagation();
13178 e.preventDefault();
13180 var target = e.getTarget();
13182 if(target.nodeName.toLowerCase() === 'i'){
13183 target = Roo.get(target).dom.parentNode;
13186 var nodeName = target.nodeName;
13187 var className = target.className;
13188 var html = target.innerHTML;
13190 switch(nodeName.toLowerCase()) {
13192 switch(className) {
13198 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13199 switch(this.viewMode){
13201 this.viewDate = this.moveMonth(this.viewDate, dir);
13205 this.viewDate = this.moveYear(this.viewDate, dir);
13211 var date = new Date();
13212 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13214 this.setValue(this.formatDate(this.date));
13220 if (className.indexOf('disabled') === -1) {
13221 this.viewDate.setUTCDate(1);
13222 if (className.indexOf('month') !== -1) {
13223 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13225 var year = parseInt(html, 10) || 0;
13226 this.viewDate.setUTCFullYear(year);
13235 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13236 var day = parseInt(html, 10) || 1;
13237 var year = this.viewDate.getUTCFullYear(),
13238 month = this.viewDate.getUTCMonth();
13240 if (className.indexOf('old') !== -1) {
13247 } else if (className.indexOf('new') !== -1) {
13255 this.date = this.UTCDate(year, month, day,0,0,0,0);
13256 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13258 this.setValue(this.formatDate(this.date));
13265 setStartDate: function(startDate){
13266 this.startDate = startDate || -Infinity;
13267 if (this.startDate !== -Infinity) {
13268 this.startDate = this.parseDate(this.startDate);
13271 this.updateNavArrows();
13274 setEndDate: function(endDate){
13275 this.endDate = endDate || Infinity;
13276 if (this.endDate !== Infinity) {
13277 this.endDate = this.parseDate(this.endDate);
13280 this.updateNavArrows();
13283 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13284 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13285 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13286 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13288 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13289 return parseInt(d, 10);
13292 this.updateNavArrows();
13295 updateNavArrows: function() {
13296 var d = new Date(this.viewDate),
13297 year = d.getUTCFullYear(),
13298 month = d.getUTCMonth();
13300 Roo.each(this.picker().select('.prev', true).elements, function(v){
13302 switch (this.viewMode) {
13305 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13311 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13318 Roo.each(this.picker().select('.next', true).elements, function(v){
13320 switch (this.viewMode) {
13323 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13329 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13337 moveMonth: function(date, dir){
13338 if (!dir) return date;
13339 var new_date = new Date(date.valueOf()),
13340 day = new_date.getUTCDate(),
13341 month = new_date.getUTCMonth(),
13342 mag = Math.abs(dir),
13344 dir = dir > 0 ? 1 : -1;
13347 // If going back one month, make sure month is not current month
13348 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13350 return new_date.getUTCMonth() == month;
13352 // If going forward one month, make sure month is as expected
13353 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13355 return new_date.getUTCMonth() != new_month;
13357 new_month = month + dir;
13358 new_date.setUTCMonth(new_month);
13359 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13360 if (new_month < 0 || new_month > 11)
13361 new_month = (new_month + 12) % 12;
13363 // For magnitudes >1, move one month at a time...
13364 for (var i=0; i<mag; i++)
13365 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13366 new_date = this.moveMonth(new_date, dir);
13367 // ...then reset the day, keeping it in the new month
13368 new_month = new_date.getUTCMonth();
13369 new_date.setUTCDate(day);
13371 return new_month != new_date.getUTCMonth();
13374 // Common date-resetting loop -- if date is beyond end of month, make it
13377 new_date.setUTCDate(--day);
13378 new_date.setUTCMonth(new_month);
13383 moveYear: function(date, dir){
13384 return this.moveMonth(date, dir*12);
13387 dateWithinRange: function(date){
13388 return date >= this.startDate && date <= this.endDate;
13392 remove: function() {
13393 this.picker().remove();
13398 Roo.apply(Roo.bootstrap.DateField, {
13409 html: '<i class="icon-arrow-left"/>'
13419 html: '<i class="icon-arrow-right"/>'
13461 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13462 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13463 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13464 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13465 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13478 navFnc: 'FullYear',
13483 navFnc: 'FullYear',
13488 Roo.apply(Roo.bootstrap.DateField, {
13492 cls: 'datepicker dropdown-menu',
13496 cls: 'datepicker-days',
13500 cls: 'table-condensed',
13502 Roo.bootstrap.DateField.head,
13506 Roo.bootstrap.DateField.footer
13513 cls: 'datepicker-months',
13517 cls: 'table-condensed',
13519 Roo.bootstrap.DateField.head,
13520 Roo.bootstrap.DateField.content,
13521 Roo.bootstrap.DateField.footer
13528 cls: 'datepicker-years',
13532 cls: 'table-condensed',
13534 Roo.bootstrap.DateField.head,
13535 Roo.bootstrap.DateField.content,
13536 Roo.bootstrap.DateField.footer
13555 * @class Roo.bootstrap.TimeField
13556 * @extends Roo.bootstrap.Input
13557 * Bootstrap DateField class
13561 * Create a new TimeField
13562 * @param {Object} config The config object
13565 Roo.bootstrap.TimeField = function(config){
13566 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13570 * Fires when this field show.
13571 * @param {Roo.bootstrap.DateField} this
13572 * @param {Mixed} date The date value
13577 * Fires when this field hide.
13578 * @param {Roo.bootstrap.DateField} this
13579 * @param {Mixed} date The date value
13584 * Fires when select a date.
13585 * @param {Roo.bootstrap.DateField} this
13586 * @param {Mixed} date The date value
13592 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13595 * @cfg {String} format
13596 * The default time format string which can be overriden for localization support. The format must be
13597 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13601 onRender: function(ct, position)
13604 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13606 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13608 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13610 this.pop = this.picker().select('>.datepicker-time',true).first();
13611 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13613 this.picker().on('mousedown', this.onMousedown, this);
13614 this.picker().on('click', this.onClick, this);
13616 this.picker().addClass('datepicker-dropdown');
13621 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13622 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13623 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13624 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13625 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13626 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13630 fireKey: function(e){
13631 if (!this.picker().isVisible()){
13632 if (e.keyCode == 27) // allow escape to hide and re-show picker
13637 e.preventDefault();
13645 this.onTogglePeriod();
13648 this.onIncrementMinutes();
13651 this.onDecrementMinutes();
13660 onClick: function(e) {
13661 e.stopPropagation();
13662 e.preventDefault();
13665 picker : function()
13667 return this.el.select('.datepicker', true).first();
13670 fillTime: function()
13672 var time = this.pop.select('tbody', true).first();
13674 time.dom.innerHTML = '';
13689 cls: 'hours-up glyphicon glyphicon-chevron-up'
13709 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13730 cls: 'timepicker-hour',
13745 cls: 'timepicker-minute',
13760 cls: 'btn btn-primary period',
13782 cls: 'hours-down glyphicon glyphicon-chevron-down'
13802 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13820 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13827 var hours = this.time.getHours();
13828 var minutes = this.time.getMinutes();
13841 hours = hours - 12;
13845 hours = '0' + hours;
13849 minutes = '0' + minutes;
13852 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13853 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13854 this.pop.select('button', true).first().dom.innerHTML = period;
13860 this.picker().removeClass(['bottom', 'top']);
13862 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13864 * place to the top of element!
13868 this.picker().addClass('top');
13869 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13874 this.picker().addClass('bottom');
13876 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13879 onFocus : function()
13881 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13885 onBlur : function()
13887 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13893 this.picker().show();
13898 this.fireEvent('show', this, this.date);
13903 this.picker().hide();
13906 this.fireEvent('hide', this, this.date);
13909 setTime : function()
13912 this.setValue(this.time.format(this.format));
13914 this.fireEvent('select', this, this.date);
13919 onMousedown: function(e){
13920 e.stopPropagation();
13921 e.preventDefault();
13924 onIncrementHours: function()
13926 Roo.log('onIncrementHours');
13927 this.time = this.time.add(Date.HOUR, 1);
13932 onDecrementHours: function()
13934 Roo.log('onDecrementHours');
13935 this.time = this.time.add(Date.HOUR, -1);
13939 onIncrementMinutes: function()
13941 Roo.log('onIncrementMinutes');
13942 this.time = this.time.add(Date.MINUTE, 1);
13946 onDecrementMinutes: function()
13948 Roo.log('onDecrementMinutes');
13949 this.time = this.time.add(Date.MINUTE, -1);
13953 onTogglePeriod: function()
13955 Roo.log('onTogglePeriod');
13956 this.time = this.time.add(Date.HOUR, 12);
13963 Roo.apply(Roo.bootstrap.TimeField, {
13993 cls: 'btn btn-info ok',
14005 Roo.apply(Roo.bootstrap.TimeField, {
14009 cls: 'datepicker dropdown-menu',
14013 cls: 'datepicker-time',
14017 cls: 'table-condensed',
14019 Roo.bootstrap.TimeField.content,
14020 Roo.bootstrap.TimeField.footer
14039 * @class Roo.bootstrap.CheckBox
14040 * @extends Roo.bootstrap.Input
14041 * Bootstrap CheckBox class
14043 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
14044 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
14045 * @cfg {String} boxLabel The text that appears beside the checkbox
14046 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
14047 * @cfg {Boolean} checked initnal the element
14051 * Create a new CheckBox
14052 * @param {Object} config The config object
14055 Roo.bootstrap.CheckBox = function(config){
14056 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
14061 * Fires when the element is checked or unchecked.
14062 * @param {Roo.bootstrap.CheckBox} this This input
14063 * @param {Boolean} checked The new checked value
14069 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
14071 inputType: 'checkbox',
14078 getAutoCreate : function()
14080 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14086 cfg.cls = 'form-group checkbox' //input-group
14094 type : this.inputType,
14095 value : (!this.checked) ? this.valueOff : this.inputValue,
14096 cls : 'roo-checkbox', //'form-box',
14097 placeholder : this.placeholder || ''
14101 if (this.weight) { // Validity check?
14102 cfg.cls += " checkbox-" + this.weight;
14105 if (this.disabled) {
14106 input.disabled=true;
14110 input.checked = this.checked;
14114 input.name = this.name;
14118 input.cls += ' input-' + this.size;
14122 ['xs','sm','md','lg'].map(function(size){
14123 if (settings[size]) {
14124 cfg.cls += ' col-' + size + '-' + settings[size];
14130 var inputblock = input;
14135 if (this.before || this.after) {
14138 cls : 'input-group',
14142 inputblock.cn.push({
14144 cls : 'input-group-addon',
14148 inputblock.cn.push(input);
14150 inputblock.cn.push({
14152 cls : 'input-group-addon',
14159 if (align ==='left' && this.fieldLabel.length) {
14160 Roo.log("left and has label");
14166 cls : 'control-label col-md-' + this.labelWidth,
14167 html : this.fieldLabel
14171 cls : "col-md-" + (12 - this.labelWidth),
14178 } else if ( this.fieldLabel.length) {
14183 tag: this.boxLabel ? 'span' : 'label',
14185 cls: 'control-label box-input-label',
14186 //cls : 'input-group-addon',
14187 html : this.fieldLabel
14197 Roo.log(" no label && no align");
14198 cfg.cn = [ inputblock ] ;
14207 html: this.boxLabel
14219 * return the real input element.
14221 inputEl: function ()
14223 return this.el.select('input.roo-checkbox',true).first();
14228 return this.el.select('label.control-label',true).first();
14231 initEvents : function()
14233 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14235 this.inputEl().on('click', this.onClick, this);
14239 onClick : function()
14241 this.setChecked(!this.checked);
14244 setChecked : function(state,suppressEvent)
14246 this.checked = state;
14248 this.inputEl().dom.checked = state;
14250 if(suppressEvent !== true){
14251 this.fireEvent('check', this, state);
14254 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14258 setValue : function(v,suppressEvent)
14260 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14274 * @class Roo.bootstrap.Radio
14275 * @extends Roo.bootstrap.CheckBox
14276 * Bootstrap Radio class
14279 * Create a new Radio
14280 * @param {Object} config The config object
14283 Roo.bootstrap.Radio = function(config){
14284 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14288 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14290 inputType: 'radio',
14294 getAutoCreate : function()
14296 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14302 cfg.cls = 'form-group radio' //input-group
14307 type : this.inputType,
14308 value : (!this.checked) ? this.valueOff : this.inputValue,
14310 placeholder : this.placeholder || ''
14313 if (this.weight) { // Validity check?
14314 cfg.cls += " radio-" + this.weight;
14316 if (this.disabled) {
14317 input.disabled=true;
14321 input.checked = this.checked;
14325 input.name = this.name;
14329 input.cls += ' input-' + this.size;
14333 ['xs','sm','md','lg'].map(function(size){
14334 if (settings[size]) {
14335 cfg.cls += ' col-' + size + '-' + settings[size];
14339 var inputblock = input;
14341 if (this.before || this.after) {
14344 cls : 'input-group',
14348 inputblock.cn.push({
14350 cls : 'input-group-addon',
14354 inputblock.cn.push(input);
14356 inputblock.cn.push({
14358 cls : 'input-group-addon',
14365 if (align ==='left' && this.fieldLabel.length) {
14366 Roo.log("left and has label");
14372 cls : 'control-label col-md-' + this.labelWidth,
14373 html : this.fieldLabel
14377 cls : "col-md-" + (12 - this.labelWidth),
14384 } else if ( this.fieldLabel.length) {
14391 cls: 'control-label box-input-label',
14392 //cls : 'input-group-addon',
14393 html : this.fieldLabel
14403 Roo.log(" no label && no align");
14418 html: this.boxLabel
14425 inputEl: function ()
14427 return this.el.select('input.roo-radio',true).first();
14429 onClick : function()
14431 this.setChecked(true);
14434 setChecked : function(state,suppressEvent)
14437 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14438 v.dom.checked = false;
14442 this.checked = state;
14443 this.inputEl().dom.checked = state;
14445 if(suppressEvent !== true){
14446 this.fireEvent('check', this, state);
14449 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14453 getGroupValue : function()
14456 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14457 if(v.dom.checked == true){
14458 value = v.dom.value;
14466 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14467 * @return {Mixed} value The field value
14469 getValue : function(){
14470 return this.getGroupValue();
14476 //<script type="text/javascript">
14479 * Based Ext JS Library 1.1.1
14480 * Copyright(c) 2006-2007, Ext JS, LLC.
14486 * @class Roo.HtmlEditorCore
14487 * @extends Roo.Component
14488 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14490 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14493 Roo.HtmlEditorCore = function(config){
14496 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14499 * @event initialize
14500 * Fires when the editor is fully initialized (including the iframe)
14501 * @param {Roo.HtmlEditorCore} this
14506 * Fires when the editor is first receives the focus. Any insertion must wait
14507 * until after this event.
14508 * @param {Roo.HtmlEditorCore} this
14512 * @event beforesync
14513 * Fires before the textarea is updated with content from the editor iframe. Return false
14514 * to cancel the sync.
14515 * @param {Roo.HtmlEditorCore} this
14516 * @param {String} html
14520 * @event beforepush
14521 * Fires before the iframe editor is updated with content from the textarea. Return false
14522 * to cancel the push.
14523 * @param {Roo.HtmlEditorCore} this
14524 * @param {String} html
14529 * Fires when the textarea is updated with content from the editor iframe.
14530 * @param {Roo.HtmlEditorCore} this
14531 * @param {String} html
14536 * Fires when the iframe editor is updated with content from the textarea.
14537 * @param {Roo.HtmlEditorCore} this
14538 * @param {String} html
14543 * @event editorevent
14544 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14545 * @param {Roo.HtmlEditorCore} this
14553 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14557 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14563 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14568 * @cfg {Number} height (in pixels)
14572 * @cfg {Number} width (in pixels)
14577 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14580 stylesheets: false,
14585 // private properties
14586 validationEvent : false,
14588 initialized : false,
14590 sourceEditMode : false,
14591 onFocus : Roo.emptyFn,
14593 hideMode:'offsets',
14601 * Protected method that will not generally be called directly. It
14602 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14603 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14605 getDocMarkup : function(){
14608 Roo.log(this.stylesheets);
14610 // inherit styels from page...??
14611 if (this.stylesheets === false) {
14613 Roo.get(document.head).select('style').each(function(node) {
14614 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14617 Roo.get(document.head).select('link').each(function(node) {
14618 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14621 } else if (!this.stylesheets.length) {
14623 st = '<style type="text/css">' +
14624 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14627 Roo.each(this.stylesheets, function(s) {
14628 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14633 st += '<style type="text/css">' +
14634 'IMG { cursor: pointer } ' +
14638 return '<html><head>' + st +
14639 //<style type="text/css">' +
14640 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14642 ' </head><body class="roo-htmleditor-body"></body></html>';
14646 onRender : function(ct, position)
14649 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14650 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14653 this.el.dom.style.border = '0 none';
14654 this.el.dom.setAttribute('tabIndex', -1);
14655 this.el.addClass('x-hidden hide');
14659 if(Roo.isIE){ // fix IE 1px bogus margin
14660 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14664 this.frameId = Roo.id();
14668 var iframe = this.owner.wrap.createChild({
14670 cls: 'form-control', // bootstrap..
14672 name: this.frameId,
14673 frameBorder : 'no',
14674 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14679 this.iframe = iframe.dom;
14681 this.assignDocWin();
14683 this.doc.designMode = 'on';
14686 this.doc.write(this.getDocMarkup());
14690 var task = { // must defer to wait for browser to be ready
14692 //console.log("run task?" + this.doc.readyState);
14693 this.assignDocWin();
14694 if(this.doc.body || this.doc.readyState == 'complete'){
14696 this.doc.designMode="on";
14700 Roo.TaskMgr.stop(task);
14701 this.initEditor.defer(10, this);
14708 Roo.TaskMgr.start(task);
14715 onResize : function(w, h)
14717 Roo.log('resize: ' +w + ',' + h );
14718 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14722 if(typeof w == 'number'){
14724 this.iframe.style.width = w + 'px';
14726 if(typeof h == 'number'){
14728 this.iframe.style.height = h + 'px';
14730 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14737 * Toggles the editor between standard and source edit mode.
14738 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14740 toggleSourceEdit : function(sourceEditMode){
14742 this.sourceEditMode = sourceEditMode === true;
14744 if(this.sourceEditMode){
14746 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14749 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14750 //this.iframe.className = '';
14753 //this.setSize(this.owner.wrap.getSize());
14754 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14761 * Protected method that will not generally be called directly. If you need/want
14762 * custom HTML cleanup, this is the method you should override.
14763 * @param {String} html The HTML to be cleaned
14764 * return {String} The cleaned HTML
14766 cleanHtml : function(html){
14767 html = String(html);
14768 if(html.length > 5){
14769 if(Roo.isSafari){ // strip safari nonsense
14770 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14773 if(html == ' '){
14780 * HTML Editor -> Textarea
14781 * Protected method that will not generally be called directly. Syncs the contents
14782 * of the editor iframe with the textarea.
14784 syncValue : function(){
14785 if(this.initialized){
14786 var bd = (this.doc.body || this.doc.documentElement);
14787 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14788 var html = bd.innerHTML;
14790 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14791 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14793 html = '<div style="'+m[0]+'">' + html + '</div>';
14796 html = this.cleanHtml(html);
14797 // fix up the special chars.. normaly like back quotes in word...
14798 // however we do not want to do this with chinese..
14799 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14800 var cc = b.charCodeAt();
14802 (cc >= 0x4E00 && cc < 0xA000 ) ||
14803 (cc >= 0x3400 && cc < 0x4E00 ) ||
14804 (cc >= 0xf900 && cc < 0xfb00 )
14810 if(this.owner.fireEvent('beforesync', this, html) !== false){
14811 this.el.dom.value = html;
14812 this.owner.fireEvent('sync', this, html);
14818 * Protected method that will not generally be called directly. Pushes the value of the textarea
14819 * into the iframe editor.
14821 pushValue : function(){
14822 if(this.initialized){
14823 var v = this.el.dom.value.trim();
14825 // if(v.length < 1){
14829 if(this.owner.fireEvent('beforepush', this, v) !== false){
14830 var d = (this.doc.body || this.doc.documentElement);
14832 this.cleanUpPaste();
14833 this.el.dom.value = d.innerHTML;
14834 this.owner.fireEvent('push', this, v);
14840 deferFocus : function(){
14841 this.focus.defer(10, this);
14845 focus : function(){
14846 if(this.win && !this.sourceEditMode){
14853 assignDocWin: function()
14855 var iframe = this.iframe;
14858 this.doc = iframe.contentWindow.document;
14859 this.win = iframe.contentWindow;
14861 if (!Roo.get(this.frameId)) {
14864 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14865 this.win = Roo.get(this.frameId).dom.contentWindow;
14870 initEditor : function(){
14871 //console.log("INIT EDITOR");
14872 this.assignDocWin();
14876 this.doc.designMode="on";
14878 this.doc.write(this.getDocMarkup());
14881 var dbody = (this.doc.body || this.doc.documentElement);
14882 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14883 // this copies styles from the containing element into thsi one..
14884 // not sure why we need all of this..
14885 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14887 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
14888 //ss['background-attachment'] = 'fixed'; // w3c
14889 dbody.bgProperties = 'fixed'; // ie
14890 //Roo.DomHelper.applyStyles(dbody, ss);
14891 Roo.EventManager.on(this.doc, {
14892 //'mousedown': this.onEditorEvent,
14893 'mouseup': this.onEditorEvent,
14894 'dblclick': this.onEditorEvent,
14895 'click': this.onEditorEvent,
14896 'keyup': this.onEditorEvent,
14901 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14903 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14904 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14906 this.initialized = true;
14908 this.owner.fireEvent('initialize', this);
14913 onDestroy : function(){
14919 //for (var i =0; i < this.toolbars.length;i++) {
14920 // // fixme - ask toolbars for heights?
14921 // this.toolbars[i].onDestroy();
14924 //this.wrap.dom.innerHTML = '';
14925 //this.wrap.remove();
14930 onFirstFocus : function(){
14932 this.assignDocWin();
14935 this.activated = true;
14938 if(Roo.isGecko){ // prevent silly gecko errors
14940 var s = this.win.getSelection();
14941 if(!s.focusNode || s.focusNode.nodeType != 3){
14942 var r = s.getRangeAt(0);
14943 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14948 this.execCmd('useCSS', true);
14949 this.execCmd('styleWithCSS', false);
14952 this.owner.fireEvent('activate', this);
14956 adjustFont: function(btn){
14957 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14958 //if(Roo.isSafari){ // safari
14961 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14962 if(Roo.isSafari){ // safari
14963 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14964 v = (v < 10) ? 10 : v;
14965 v = (v > 48) ? 48 : v;
14966 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14971 v = Math.max(1, v+adjust);
14973 this.execCmd('FontSize', v );
14976 onEditorEvent : function(e){
14977 this.owner.fireEvent('editorevent', this, e);
14978 // this.updateToolbar();
14979 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14982 insertTag : function(tg)
14984 // could be a bit smarter... -> wrap the current selected tRoo..
14985 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14987 range = this.createRange(this.getSelection());
14988 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14989 wrappingNode.appendChild(range.extractContents());
14990 range.insertNode(wrappingNode);
14997 this.execCmd("formatblock", tg);
15001 insertText : function(txt)
15005 var range = this.createRange();
15006 range.deleteContents();
15007 //alert(Sender.getAttribute('label'));
15009 range.insertNode(this.doc.createTextNode(txt));
15015 * Executes a Midas editor command on the editor document and performs necessary focus and
15016 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
15017 * @param {String} cmd The Midas command
15018 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15020 relayCmd : function(cmd, value){
15022 this.execCmd(cmd, value);
15023 this.owner.fireEvent('editorevent', this);
15024 //this.updateToolbar();
15025 this.owner.deferFocus();
15029 * Executes a Midas editor command directly on the editor document.
15030 * For visual commands, you should use {@link #relayCmd} instead.
15031 * <b>This should only be called after the editor is initialized.</b>
15032 * @param {String} cmd The Midas command
15033 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15035 execCmd : function(cmd, value){
15036 this.doc.execCommand(cmd, false, value === undefined ? null : value);
15043 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
15045 * @param {String} text | dom node..
15047 insertAtCursor : function(text)
15052 if(!this.activated){
15058 var r = this.doc.selection.createRange();
15069 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
15073 // from jquery ui (MIT licenced)
15075 var win = this.win;
15077 if (win.getSelection && win.getSelection().getRangeAt) {
15078 range = win.getSelection().getRangeAt(0);
15079 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
15080 range.insertNode(node);
15081 } else if (win.document.selection && win.document.selection.createRange) {
15082 // no firefox support
15083 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15084 win.document.selection.createRange().pasteHTML(txt);
15086 // no firefox support
15087 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15088 this.execCmd('InsertHTML', txt);
15097 mozKeyPress : function(e){
15099 var c = e.getCharCode(), cmd;
15102 c = String.fromCharCode(c).toLowerCase();
15116 this.cleanUpPaste.defer(100, this);
15124 e.preventDefault();
15132 fixKeys : function(){ // load time branching for fastest keydown performance
15134 return function(e){
15135 var k = e.getKey(), r;
15138 r = this.doc.selection.createRange();
15141 r.pasteHTML('    ');
15148 r = this.doc.selection.createRange();
15150 var target = r.parentElement();
15151 if(!target || target.tagName.toLowerCase() != 'li'){
15153 r.pasteHTML('<br />');
15159 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15160 this.cleanUpPaste.defer(100, this);
15166 }else if(Roo.isOpera){
15167 return function(e){
15168 var k = e.getKey();
15172 this.execCmd('InsertHTML','    ');
15175 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15176 this.cleanUpPaste.defer(100, this);
15181 }else if(Roo.isSafari){
15182 return function(e){
15183 var k = e.getKey();
15187 this.execCmd('InsertText','\t');
15191 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15192 this.cleanUpPaste.defer(100, this);
15200 getAllAncestors: function()
15202 var p = this.getSelectedNode();
15205 a.push(p); // push blank onto stack..
15206 p = this.getParentElement();
15210 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15214 a.push(this.doc.body);
15218 lastSelNode : false,
15221 getSelection : function()
15223 this.assignDocWin();
15224 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15227 getSelectedNode: function()
15229 // this may only work on Gecko!!!
15231 // should we cache this!!!!
15236 var range = this.createRange(this.getSelection()).cloneRange();
15239 var parent = range.parentElement();
15241 var testRange = range.duplicate();
15242 testRange.moveToElementText(parent);
15243 if (testRange.inRange(range)) {
15246 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15249 parent = parent.parentElement;
15254 // is ancestor a text element.
15255 var ac = range.commonAncestorContainer;
15256 if (ac.nodeType == 3) {
15257 ac = ac.parentNode;
15260 var ar = ac.childNodes;
15263 var other_nodes = [];
15264 var has_other_nodes = false;
15265 for (var i=0;i<ar.length;i++) {
15266 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15269 // fullly contained node.
15271 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15276 // probably selected..
15277 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15278 other_nodes.push(ar[i]);
15282 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15287 has_other_nodes = true;
15289 if (!nodes.length && other_nodes.length) {
15290 nodes= other_nodes;
15292 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15298 createRange: function(sel)
15300 // this has strange effects when using with
15301 // top toolbar - not sure if it's a great idea.
15302 //this.editor.contentWindow.focus();
15303 if (typeof sel != "undefined") {
15305 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15307 return this.doc.createRange();
15310 return this.doc.createRange();
15313 getParentElement: function()
15316 this.assignDocWin();
15317 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15319 var range = this.createRange(sel);
15322 var p = range.commonAncestorContainer;
15323 while (p.nodeType == 3) { // text node
15334 * Range intersection.. the hard stuff...
15338 * [ -- selected range --- ]
15342 * if end is before start or hits it. fail.
15343 * if start is after end or hits it fail.
15345 * if either hits (but other is outside. - then it's not
15351 // @see http://www.thismuchiknow.co.uk/?p=64.
15352 rangeIntersectsNode : function(range, node)
15354 var nodeRange = node.ownerDocument.createRange();
15356 nodeRange.selectNode(node);
15358 nodeRange.selectNodeContents(node);
15361 var rangeStartRange = range.cloneRange();
15362 rangeStartRange.collapse(true);
15364 var rangeEndRange = range.cloneRange();
15365 rangeEndRange.collapse(false);
15367 var nodeStartRange = nodeRange.cloneRange();
15368 nodeStartRange.collapse(true);
15370 var nodeEndRange = nodeRange.cloneRange();
15371 nodeEndRange.collapse(false);
15373 return rangeStartRange.compareBoundaryPoints(
15374 Range.START_TO_START, nodeEndRange) == -1 &&
15375 rangeEndRange.compareBoundaryPoints(
15376 Range.START_TO_START, nodeStartRange) == 1;
15380 rangeCompareNode : function(range, node)
15382 var nodeRange = node.ownerDocument.createRange();
15384 nodeRange.selectNode(node);
15386 nodeRange.selectNodeContents(node);
15390 range.collapse(true);
15392 nodeRange.collapse(true);
15394 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15395 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15397 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15399 var nodeIsBefore = ss == 1;
15400 var nodeIsAfter = ee == -1;
15402 if (nodeIsBefore && nodeIsAfter)
15404 if (!nodeIsBefore && nodeIsAfter)
15405 return 1; //right trailed.
15407 if (nodeIsBefore && !nodeIsAfter)
15408 return 2; // left trailed.
15413 // private? - in a new class?
15414 cleanUpPaste : function()
15416 // cleans up the whole document..
15417 Roo.log('cleanuppaste');
15419 this.cleanUpChildren(this.doc.body);
15420 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15421 if (clean != this.doc.body.innerHTML) {
15422 this.doc.body.innerHTML = clean;
15427 cleanWordChars : function(input) {// change the chars to hex code
15428 var he = Roo.HtmlEditorCore;
15430 var output = input;
15431 Roo.each(he.swapCodes, function(sw) {
15432 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15434 output = output.replace(swapper, sw[1]);
15441 cleanUpChildren : function (n)
15443 if (!n.childNodes.length) {
15446 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15447 this.cleanUpChild(n.childNodes[i]);
15454 cleanUpChild : function (node)
15457 //console.log(node);
15458 if (node.nodeName == "#text") {
15459 // clean up silly Windows -- stuff?
15462 if (node.nodeName == "#comment") {
15463 node.parentNode.removeChild(node);
15464 // clean up silly Windows -- stuff?
15468 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15470 node.parentNode.removeChild(node);
15475 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15477 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15478 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15480 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15481 // remove_keep_children = true;
15484 if (remove_keep_children) {
15485 this.cleanUpChildren(node);
15486 // inserts everything just before this node...
15487 while (node.childNodes.length) {
15488 var cn = node.childNodes[0];
15489 node.removeChild(cn);
15490 node.parentNode.insertBefore(cn, node);
15492 node.parentNode.removeChild(node);
15496 if (!node.attributes || !node.attributes.length) {
15497 this.cleanUpChildren(node);
15501 function cleanAttr(n,v)
15504 if (v.match(/^\./) || v.match(/^\//)) {
15507 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15510 if (v.match(/^#/)) {
15513 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15514 node.removeAttribute(n);
15518 function cleanStyle(n,v)
15520 if (v.match(/expression/)) { //XSS?? should we even bother..
15521 node.removeAttribute(n);
15524 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15525 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15528 var parts = v.split(/;/);
15531 Roo.each(parts, function(p) {
15532 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15536 var l = p.split(':').shift().replace(/\s+/g,'');
15537 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15539 if ( cblack.indexOf(l) > -1) {
15540 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15541 //node.removeAttribute(n);
15545 // only allow 'c whitelisted system attributes'
15546 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15547 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15548 //node.removeAttribute(n);
15558 if (clean.length) {
15559 node.setAttribute(n, clean.join(';'));
15561 node.removeAttribute(n);
15567 for (var i = node.attributes.length-1; i > -1 ; i--) {
15568 var a = node.attributes[i];
15571 if (a.name.toLowerCase().substr(0,2)=='on') {
15572 node.removeAttribute(a.name);
15575 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15576 node.removeAttribute(a.name);
15579 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15580 cleanAttr(a.name,a.value); // fixme..
15583 if (a.name == 'style') {
15584 cleanStyle(a.name,a.value);
15587 /// clean up MS crap..
15588 // tecnically this should be a list of valid class'es..
15591 if (a.name == 'class') {
15592 if (a.value.match(/^Mso/)) {
15593 node.className = '';
15596 if (a.value.match(/body/)) {
15597 node.className = '';
15608 this.cleanUpChildren(node);
15613 * Clean up MS wordisms...
15615 cleanWord : function(node)
15618 var cleanWordChildren = function()
15620 if (!node.childNodes.length) {
15623 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15624 _t.cleanWord(node.childNodes[i]);
15630 this.cleanWord(this.doc.body);
15633 if (node.nodeName == "#text") {
15634 // clean up silly Windows -- stuff?
15637 if (node.nodeName == "#comment") {
15638 node.parentNode.removeChild(node);
15639 // clean up silly Windows -- stuff?
15643 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15644 node.parentNode.removeChild(node);
15648 // remove - but keep children..
15649 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15650 while (node.childNodes.length) {
15651 var cn = node.childNodes[0];
15652 node.removeChild(cn);
15653 node.parentNode.insertBefore(cn, node);
15655 node.parentNode.removeChild(node);
15656 cleanWordChildren();
15660 if (node.className.length) {
15662 var cn = node.className.split(/\W+/);
15664 Roo.each(cn, function(cls) {
15665 if (cls.match(/Mso[a-zA-Z]+/)) {
15670 node.className = cna.length ? cna.join(' ') : '';
15672 node.removeAttribute("class");
15676 if (node.hasAttribute("lang")) {
15677 node.removeAttribute("lang");
15680 if (node.hasAttribute("style")) {
15682 var styles = node.getAttribute("style").split(";");
15684 Roo.each(styles, function(s) {
15685 if (!s.match(/:/)) {
15688 var kv = s.split(":");
15689 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15692 // what ever is left... we allow.
15695 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15696 if (!nstyle.length) {
15697 node.removeAttribute('style');
15701 cleanWordChildren();
15705 domToHTML : function(currentElement, depth, nopadtext) {
15707 depth = depth || 0;
15708 nopadtext = nopadtext || false;
15710 if (!currentElement) {
15711 return this.domToHTML(this.doc.body);
15714 //Roo.log(currentElement);
15716 var allText = false;
15717 var nodeName = currentElement.nodeName;
15718 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15720 if (nodeName == '#text') {
15721 return currentElement.nodeValue;
15726 if (nodeName != 'BODY') {
15729 // Prints the node tagName, such as <A>, <IMG>, etc
15732 for(i = 0; i < currentElement.attributes.length;i++) {
15734 var aname = currentElement.attributes.item(i).name;
15735 if (!currentElement.attributes.item(i).value.length) {
15738 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15741 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15750 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15753 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15758 // Traverse the tree
15760 var currentElementChild = currentElement.childNodes.item(i);
15761 var allText = true;
15762 var innerHTML = '';
15764 while (currentElementChild) {
15765 // Formatting code (indent the tree so it looks nice on the screen)
15766 var nopad = nopadtext;
15767 if (lastnode == 'SPAN') {
15771 if (currentElementChild.nodeName == '#text') {
15772 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15773 if (!nopad && toadd.length > 80) {
15774 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15776 innerHTML += toadd;
15779 currentElementChild = currentElement.childNodes.item(i);
15785 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15787 // Recursively traverse the tree structure of the child node
15788 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15789 lastnode = currentElementChild.nodeName;
15791 currentElementChild=currentElement.childNodes.item(i);
15797 // The remaining code is mostly for formatting the tree
15798 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15803 ret+= "</"+tagName+">";
15809 // hide stuff that is not compatible
15823 * @event specialkey
15827 * @cfg {String} fieldClass @hide
15830 * @cfg {String} focusClass @hide
15833 * @cfg {String} autoCreate @hide
15836 * @cfg {String} inputType @hide
15839 * @cfg {String} invalidClass @hide
15842 * @cfg {String} invalidText @hide
15845 * @cfg {String} msgFx @hide
15848 * @cfg {String} validateOnBlur @hide
15852 Roo.HtmlEditorCore.white = [
15853 'area', 'br', 'img', 'input', 'hr', 'wbr',
15855 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15856 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15857 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15858 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15859 'table', 'ul', 'xmp',
15861 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15864 'dir', 'menu', 'ol', 'ul', 'dl',
15870 Roo.HtmlEditorCore.black = [
15871 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15873 'base', 'basefont', 'bgsound', 'blink', 'body',
15874 'frame', 'frameset', 'head', 'html', 'ilayer',
15875 'iframe', 'layer', 'link', 'meta', 'object',
15876 'script', 'style' ,'title', 'xml' // clean later..
15878 Roo.HtmlEditorCore.clean = [
15879 'script', 'style', 'title', 'xml'
15881 Roo.HtmlEditorCore.remove = [
15886 Roo.HtmlEditorCore.ablack = [
15890 Roo.HtmlEditorCore.aclean = [
15891 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15895 Roo.HtmlEditorCore.pwhite= [
15896 'http', 'https', 'mailto'
15899 // white listed style attributes.
15900 Roo.HtmlEditorCore.cwhite= [
15901 // 'text-align', /// default is to allow most things..
15907 // black listed style attributes.
15908 Roo.HtmlEditorCore.cblack= [
15909 // 'font-size' -- this can be set by the project
15913 Roo.HtmlEditorCore.swapCodes =[
15932 * @class Roo.bootstrap.HtmlEditor
15933 * @extends Roo.bootstrap.TextArea
15934 * Bootstrap HtmlEditor class
15937 * Create a new HtmlEditor
15938 * @param {Object} config The config object
15941 Roo.bootstrap.HtmlEditor = function(config){
15942 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15943 if (!this.toolbars) {
15944 this.toolbars = [];
15946 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15949 * @event initialize
15950 * Fires when the editor is fully initialized (including the iframe)
15951 * @param {HtmlEditor} this
15956 * Fires when the editor is first receives the focus. Any insertion must wait
15957 * until after this event.
15958 * @param {HtmlEditor} this
15962 * @event beforesync
15963 * Fires before the textarea is updated with content from the editor iframe. Return false
15964 * to cancel the sync.
15965 * @param {HtmlEditor} this
15966 * @param {String} html
15970 * @event beforepush
15971 * Fires before the iframe editor is updated with content from the textarea. Return false
15972 * to cancel the push.
15973 * @param {HtmlEditor} this
15974 * @param {String} html
15979 * Fires when the textarea is updated with content from the editor iframe.
15980 * @param {HtmlEditor} this
15981 * @param {String} html
15986 * Fires when the iframe editor is updated with content from the textarea.
15987 * @param {HtmlEditor} this
15988 * @param {String} html
15992 * @event editmodechange
15993 * Fires when the editor switches edit modes
15994 * @param {HtmlEditor} this
15995 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15997 editmodechange: true,
15999 * @event editorevent
16000 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16001 * @param {HtmlEditor} this
16005 * @event firstfocus
16006 * Fires when on first focus - needed by toolbars..
16007 * @param {HtmlEditor} this
16012 * Auto save the htmlEditor value as a file into Events
16013 * @param {HtmlEditor} this
16017 * @event savedpreview
16018 * preview the saved version of htmlEditor
16019 * @param {HtmlEditor} this
16026 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
16030 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
16035 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16040 * @cfg {Number} height (in pixels)
16044 * @cfg {Number} width (in pixels)
16049 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16052 stylesheets: false,
16057 // private properties
16058 validationEvent : false,
16060 initialized : false,
16063 onFocus : Roo.emptyFn,
16065 hideMode:'offsets',
16068 tbContainer : false,
16070 toolbarContainer :function() {
16071 return this.wrap.select('.x-html-editor-tb',true).first();
16075 * Protected method that will not generally be called directly. It
16076 * is called when the editor creates its toolbar. Override this method if you need to
16077 * add custom toolbar buttons.
16078 * @param {HtmlEditor} editor
16080 createToolbar : function(){
16082 Roo.log("create toolbars");
16084 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
16085 this.toolbars[0].render(this.toolbarContainer());
16089 // if (!editor.toolbars || !editor.toolbars.length) {
16090 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
16093 // for (var i =0 ; i < editor.toolbars.length;i++) {
16094 // editor.toolbars[i] = Roo.factory(
16095 // typeof(editor.toolbars[i]) == 'string' ?
16096 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
16097 // Roo.bootstrap.HtmlEditor);
16098 // editor.toolbars[i].init(editor);
16104 onRender : function(ct, position)
16106 // Roo.log("Call onRender: " + this.xtype);
16108 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
16110 this.wrap = this.inputEl().wrap({
16111 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16114 this.editorcore.onRender(ct, position);
16116 if (this.resizable) {
16117 this.resizeEl = new Roo.Resizable(this.wrap, {
16121 minHeight : this.height,
16122 height: this.height,
16123 handles : this.resizable,
16126 resize : function(r, w, h) {
16127 _t.onResize(w,h); // -something
16133 this.createToolbar(this);
16136 if(!this.width && this.resizable){
16137 this.setSize(this.wrap.getSize());
16139 if (this.resizeEl) {
16140 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16141 // should trigger onReize..
16147 onResize : function(w, h)
16149 Roo.log('resize: ' +w + ',' + h );
16150 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16154 if(this.inputEl() ){
16155 if(typeof w == 'number'){
16156 var aw = w - this.wrap.getFrameWidth('lr');
16157 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16160 if(typeof h == 'number'){
16161 var tbh = -11; // fixme it needs to tool bar size!
16162 for (var i =0; i < this.toolbars.length;i++) {
16163 // fixme - ask toolbars for heights?
16164 tbh += this.toolbars[i].el.getHeight();
16165 //if (this.toolbars[i].footer) {
16166 // tbh += this.toolbars[i].footer.el.getHeight();
16174 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16175 ah -= 5; // knock a few pixes off for look..
16176 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16180 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16181 this.editorcore.onResize(ew,eh);
16186 * Toggles the editor between standard and source edit mode.
16187 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16189 toggleSourceEdit : function(sourceEditMode)
16191 this.editorcore.toggleSourceEdit(sourceEditMode);
16193 if(this.editorcore.sourceEditMode){
16194 Roo.log('editor - showing textarea');
16197 // Roo.log(this.syncValue());
16199 this.inputEl().removeClass('hide');
16200 this.inputEl().dom.removeAttribute('tabIndex');
16201 this.inputEl().focus();
16203 Roo.log('editor - hiding textarea');
16205 // Roo.log(this.pushValue());
16208 this.inputEl().addClass('hide');
16209 this.inputEl().dom.setAttribute('tabIndex', -1);
16210 //this.deferFocus();
16213 if(this.resizable){
16214 this.setSize(this.wrap.getSize());
16217 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16220 // private (for BoxComponent)
16221 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16223 // private (for BoxComponent)
16224 getResizeEl : function(){
16228 // private (for BoxComponent)
16229 getPositionEl : function(){
16234 initEvents : function(){
16235 this.originalValue = this.getValue();
16239 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16242 // markInvalid : Roo.emptyFn,
16244 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16247 // clearInvalid : Roo.emptyFn,
16249 setValue : function(v){
16250 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16251 this.editorcore.pushValue();
16256 deferFocus : function(){
16257 this.focus.defer(10, this);
16261 focus : function(){
16262 this.editorcore.focus();
16268 onDestroy : function(){
16274 for (var i =0; i < this.toolbars.length;i++) {
16275 // fixme - ask toolbars for heights?
16276 this.toolbars[i].onDestroy();
16279 this.wrap.dom.innerHTML = '';
16280 this.wrap.remove();
16285 onFirstFocus : function(){
16286 //Roo.log("onFirstFocus");
16287 this.editorcore.onFirstFocus();
16288 for (var i =0; i < this.toolbars.length;i++) {
16289 this.toolbars[i].onFirstFocus();
16295 syncValue : function()
16297 this.editorcore.syncValue();
16300 pushValue : function()
16302 this.editorcore.pushValue();
16306 // hide stuff that is not compatible
16320 * @event specialkey
16324 * @cfg {String} fieldClass @hide
16327 * @cfg {String} focusClass @hide
16330 * @cfg {String} autoCreate @hide
16333 * @cfg {String} inputType @hide
16336 * @cfg {String} invalidClass @hide
16339 * @cfg {String} invalidText @hide
16342 * @cfg {String} msgFx @hide
16345 * @cfg {String} validateOnBlur @hide
16354 Roo.namespace('Roo.bootstrap.htmleditor');
16356 * @class Roo.bootstrap.HtmlEditorToolbar1
16361 new Roo.bootstrap.HtmlEditor({
16364 new Roo.bootstrap.HtmlEditorToolbar1({
16365 disable : { fonts: 1 , format: 1, ..., ... , ...],
16371 * @cfg {Object} disable List of elements to disable..
16372 * @cfg {Array} btns List of additional buttons.
16376 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16379 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16382 Roo.apply(this, config);
16384 // default disabled, based on 'good practice'..
16385 this.disable = this.disable || {};
16386 Roo.applyIf(this.disable, {
16389 specialElements : true
16391 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16393 this.editor = config.editor;
16394 this.editorcore = config.editor.editorcore;
16396 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16398 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16399 // dont call parent... till later.
16401 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16406 editorcore : false,
16411 "h1","h2","h3","h4","h5","h6",
16413 "abbr", "acronym", "address", "cite", "samp", "var",
16417 onRender : function(ct, position)
16419 // Roo.log("Call onRender: " + this.xtype);
16421 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16423 this.el.dom.style.marginBottom = '0';
16425 var editorcore = this.editorcore;
16426 var editor= this.editor;
16429 var btn = function(id,cmd , toggle, handler){
16431 var event = toggle ? 'toggle' : 'click';
16436 xns: Roo.bootstrap,
16439 enableToggle:toggle !== false,
16441 pressed : toggle ? false : null,
16444 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16445 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16454 xns: Roo.bootstrap,
16455 glyphicon : 'font',
16459 xns: Roo.bootstrap,
16463 Roo.each(this.formats, function(f) {
16464 style.menu.items.push({
16466 xns: Roo.bootstrap,
16467 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16472 editorcore.insertTag(this.tagname);
16479 children.push(style);
16482 btn('bold',false,true);
16483 btn('italic',false,true);
16484 btn('align-left', 'justifyleft',true);
16485 btn('align-center', 'justifycenter',true);
16486 btn('align-right' , 'justifyright',true);
16487 btn('link', false, false, function(btn) {
16488 //Roo.log("create link?");
16489 var url = prompt(this.createLinkText, this.defaultLinkValue);
16490 if(url && url != 'http:/'+'/'){
16491 this.editorcore.relayCmd('createlink', url);
16494 btn('list','insertunorderedlist',true);
16495 btn('pencil', false,true, function(btn){
16498 this.toggleSourceEdit(btn.pressed);
16504 xns: Roo.bootstrap,
16509 xns: Roo.bootstrap,
16514 cog.menu.items.push({
16516 xns: Roo.bootstrap,
16517 html : Clean styles,
16522 editorcore.insertTag(this.tagname);
16531 this.xtype = 'NavSimplebar';
16533 for(var i=0;i< children.length;i++) {
16535 this.buttons.add(this.addxtypeChild(children[i]));
16539 editor.on('editorevent', this.updateToolbar, this);
16541 onBtnClick : function(id)
16543 this.editorcore.relayCmd(id);
16544 this.editorcore.focus();
16548 * Protected method that will not generally be called directly. It triggers
16549 * a toolbar update by reading the markup state of the current selection in the editor.
16551 updateToolbar: function(){
16553 if(!this.editorcore.activated){
16554 this.editor.onFirstFocus(); // is this neeed?
16558 var btns = this.buttons;
16559 var doc = this.editorcore.doc;
16560 btns.get('bold').setActive(doc.queryCommandState('bold'));
16561 btns.get('italic').setActive(doc.queryCommandState('italic'));
16562 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16564 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16565 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16566 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16568 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16569 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16572 var ans = this.editorcore.getAllAncestors();
16573 if (this.formatCombo) {
16576 var store = this.formatCombo.store;
16577 this.formatCombo.setValue("");
16578 for (var i =0; i < ans.length;i++) {
16579 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16581 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16589 // hides menus... - so this cant be on a menu...
16590 Roo.bootstrap.MenuMgr.hideAll();
16592 Roo.bootstrap.MenuMgr.hideAll();
16593 //this.editorsyncValue();
16595 onFirstFocus: function() {
16596 this.buttons.each(function(item){
16600 toggleSourceEdit : function(sourceEditMode){
16603 if(sourceEditMode){
16604 Roo.log("disabling buttons");
16605 this.buttons.each( function(item){
16606 if(item.cmd != 'pencil'){
16612 Roo.log("enabling buttons");
16613 if(this.editorcore.initialized){
16614 this.buttons.each( function(item){
16620 Roo.log("calling toggole on editor");
16621 // tell the editor that it's been pressed..
16622 this.editor.toggleSourceEdit(sourceEditMode);
16632 * @class Roo.bootstrap.Table.AbstractSelectionModel
16633 * @extends Roo.util.Observable
16634 * Abstract base class for grid SelectionModels. It provides the interface that should be
16635 * implemented by descendant classes. This class should not be directly instantiated.
16638 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16639 this.locked = false;
16640 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16644 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16645 /** @ignore Called by the grid automatically. Do not call directly. */
16646 init : function(grid){
16652 * Locks the selections.
16655 this.locked = true;
16659 * Unlocks the selections.
16661 unlock : function(){
16662 this.locked = false;
16666 * Returns true if the selections are locked.
16667 * @return {Boolean}
16669 isLocked : function(){
16670 return this.locked;
16674 * @class Roo.bootstrap.Table.ColumnModel
16675 * @extends Roo.util.Observable
16676 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16677 * the columns in the table.
16680 * @param {Object} config An Array of column config objects. See this class's
16681 * config objects for details.
16683 Roo.bootstrap.Table.ColumnModel = function(config){
16685 * The config passed into the constructor
16687 this.config = config;
16690 // if no id, create one
16691 // if the column does not have a dataIndex mapping,
16692 // map it to the order it is in the config
16693 for(var i = 0, len = config.length; i < len; i++){
16695 if(typeof c.dataIndex == "undefined"){
16698 if(typeof c.renderer == "string"){
16699 c.renderer = Roo.util.Format[c.renderer];
16701 if(typeof c.id == "undefined"){
16704 // if(c.editor && c.editor.xtype){
16705 // c.editor = Roo.factory(c.editor, Roo.grid);
16707 // if(c.editor && c.editor.isFormField){
16708 // c.editor = new Roo.grid.GridEditor(c.editor);
16711 this.lookup[c.id] = c;
16715 * The width of columns which have no width specified (defaults to 100)
16718 this.defaultWidth = 100;
16721 * Default sortable of columns which have no sortable specified (defaults to false)
16724 this.defaultSortable = false;
16728 * @event widthchange
16729 * Fires when the width of a column changes.
16730 * @param {ColumnModel} this
16731 * @param {Number} columnIndex The column index
16732 * @param {Number} newWidth The new width
16734 "widthchange": true,
16736 * @event headerchange
16737 * Fires when the text of a header changes.
16738 * @param {ColumnModel} this
16739 * @param {Number} columnIndex The column index
16740 * @param {Number} newText The new header text
16742 "headerchange": true,
16744 * @event hiddenchange
16745 * Fires when a column is hidden or "unhidden".
16746 * @param {ColumnModel} this
16747 * @param {Number} columnIndex The column index
16748 * @param {Boolean} hidden true if hidden, false otherwise
16750 "hiddenchange": true,
16752 * @event columnmoved
16753 * Fires when a column is moved.
16754 * @param {ColumnModel} this
16755 * @param {Number} oldIndex
16756 * @param {Number} newIndex
16758 "columnmoved" : true,
16760 * @event columlockchange
16761 * Fires when a column's locked state is changed
16762 * @param {ColumnModel} this
16763 * @param {Number} colIndex
16764 * @param {Boolean} locked true if locked
16766 "columnlockchange" : true
16768 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16770 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16772 * @cfg {String} header The header text to display in the Grid view.
16775 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16776 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16777 * specified, the column's index is used as an index into the Record's data Array.
16780 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16781 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16784 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16785 * Defaults to the value of the {@link #defaultSortable} property.
16786 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16789 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16792 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16795 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16798 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16801 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16802 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16803 * default renderer uses the raw data value.
16806 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16810 * Returns the id of the column at the specified index.
16811 * @param {Number} index The column index
16812 * @return {String} the id
16814 getColumnId : function(index){
16815 return this.config[index].id;
16819 * Returns the column for a specified id.
16820 * @param {String} id The column id
16821 * @return {Object} the column
16823 getColumnById : function(id){
16824 return this.lookup[id];
16829 * Returns the column for a specified dataIndex.
16830 * @param {String} dataIndex The column dataIndex
16831 * @return {Object|Boolean} the column or false if not found
16833 getColumnByDataIndex: function(dataIndex){
16834 var index = this.findColumnIndex(dataIndex);
16835 return index > -1 ? this.config[index] : false;
16839 * Returns the index for a specified column id.
16840 * @param {String} id The column id
16841 * @return {Number} the index, or -1 if not found
16843 getIndexById : function(id){
16844 for(var i = 0, len = this.config.length; i < len; i++){
16845 if(this.config[i].id == id){
16853 * Returns the index for a specified column dataIndex.
16854 * @param {String} dataIndex The column dataIndex
16855 * @return {Number} the index, or -1 if not found
16858 findColumnIndex : function(dataIndex){
16859 for(var i = 0, len = this.config.length; i < len; i++){
16860 if(this.config[i].dataIndex == dataIndex){
16868 moveColumn : function(oldIndex, newIndex){
16869 var c = this.config[oldIndex];
16870 this.config.splice(oldIndex, 1);
16871 this.config.splice(newIndex, 0, c);
16872 this.dataMap = null;
16873 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16876 isLocked : function(colIndex){
16877 return this.config[colIndex].locked === true;
16880 setLocked : function(colIndex, value, suppressEvent){
16881 if(this.isLocked(colIndex) == value){
16884 this.config[colIndex].locked = value;
16885 if(!suppressEvent){
16886 this.fireEvent("columnlockchange", this, colIndex, value);
16890 getTotalLockedWidth : function(){
16891 var totalWidth = 0;
16892 for(var i = 0; i < this.config.length; i++){
16893 if(this.isLocked(i) && !this.isHidden(i)){
16894 this.totalWidth += this.getColumnWidth(i);
16900 getLockedCount : function(){
16901 for(var i = 0, len = this.config.length; i < len; i++){
16902 if(!this.isLocked(i)){
16909 * Returns the number of columns.
16912 getColumnCount : function(visibleOnly){
16913 if(visibleOnly === true){
16915 for(var i = 0, len = this.config.length; i < len; i++){
16916 if(!this.isHidden(i)){
16922 return this.config.length;
16926 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16927 * @param {Function} fn
16928 * @param {Object} scope (optional)
16929 * @return {Array} result
16931 getColumnsBy : function(fn, scope){
16933 for(var i = 0, len = this.config.length; i < len; i++){
16934 var c = this.config[i];
16935 if(fn.call(scope||this, c, i) === true){
16943 * Returns true if the specified column is sortable.
16944 * @param {Number} col The column index
16945 * @return {Boolean}
16947 isSortable : function(col){
16948 if(typeof this.config[col].sortable == "undefined"){
16949 return this.defaultSortable;
16951 return this.config[col].sortable;
16955 * Returns the rendering (formatting) function defined for the column.
16956 * @param {Number} col The column index.
16957 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16959 getRenderer : function(col){
16960 if(!this.config[col].renderer){
16961 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16963 return this.config[col].renderer;
16967 * Sets the rendering (formatting) function for a column.
16968 * @param {Number} col The column index
16969 * @param {Function} fn The function to use to process the cell's raw data
16970 * to return HTML markup for the grid view. The render function is called with
16971 * the following parameters:<ul>
16972 * <li>Data value.</li>
16973 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16974 * <li>css A CSS style string to apply to the table cell.</li>
16975 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16976 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16977 * <li>Row index</li>
16978 * <li>Column index</li>
16979 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16981 setRenderer : function(col, fn){
16982 this.config[col].renderer = fn;
16986 * Returns the width for the specified column.
16987 * @param {Number} col The column index
16990 getColumnWidth : function(col){
16991 return this.config[col].width * 1 || this.defaultWidth;
16995 * Sets the width for a column.
16996 * @param {Number} col The column index
16997 * @param {Number} width The new width
16999 setColumnWidth : function(col, width, suppressEvent){
17000 this.config[col].width = width;
17001 this.totalWidth = null;
17002 if(!suppressEvent){
17003 this.fireEvent("widthchange", this, col, width);
17008 * Returns the total width of all columns.
17009 * @param {Boolean} includeHidden True to include hidden column widths
17012 getTotalWidth : function(includeHidden){
17013 if(!this.totalWidth){
17014 this.totalWidth = 0;
17015 for(var i = 0, len = this.config.length; i < len; i++){
17016 if(includeHidden || !this.isHidden(i)){
17017 this.totalWidth += this.getColumnWidth(i);
17021 return this.totalWidth;
17025 * Returns the header for the specified column.
17026 * @param {Number} col The column index
17029 getColumnHeader : function(col){
17030 return this.config[col].header;
17034 * Sets the header for a column.
17035 * @param {Number} col The column index
17036 * @param {String} header The new header
17038 setColumnHeader : function(col, header){
17039 this.config[col].header = header;
17040 this.fireEvent("headerchange", this, col, header);
17044 * Returns the tooltip for the specified column.
17045 * @param {Number} col The column index
17048 getColumnTooltip : function(col){
17049 return this.config[col].tooltip;
17052 * Sets the tooltip for a column.
17053 * @param {Number} col The column index
17054 * @param {String} tooltip The new tooltip
17056 setColumnTooltip : function(col, tooltip){
17057 this.config[col].tooltip = tooltip;
17061 * Returns the dataIndex for the specified column.
17062 * @param {Number} col The column index
17065 getDataIndex : function(col){
17066 return this.config[col].dataIndex;
17070 * Sets the dataIndex for a column.
17071 * @param {Number} col The column index
17072 * @param {Number} dataIndex The new dataIndex
17074 setDataIndex : function(col, dataIndex){
17075 this.config[col].dataIndex = dataIndex;
17081 * Returns true if the cell is editable.
17082 * @param {Number} colIndex The column index
17083 * @param {Number} rowIndex The row index
17084 * @return {Boolean}
17086 isCellEditable : function(colIndex, rowIndex){
17087 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
17091 * Returns the editor defined for the cell/column.
17092 * return false or null to disable editing.
17093 * @param {Number} colIndex The column index
17094 * @param {Number} rowIndex The row index
17097 getCellEditor : function(colIndex, rowIndex){
17098 return this.config[colIndex].editor;
17102 * Sets if a column is editable.
17103 * @param {Number} col The column index
17104 * @param {Boolean} editable True if the column is editable
17106 setEditable : function(col, editable){
17107 this.config[col].editable = editable;
17112 * Returns true if the column is hidden.
17113 * @param {Number} colIndex The column index
17114 * @return {Boolean}
17116 isHidden : function(colIndex){
17117 return this.config[colIndex].hidden;
17122 * Returns true if the column width cannot be changed
17124 isFixed : function(colIndex){
17125 return this.config[colIndex].fixed;
17129 * Returns true if the column can be resized
17130 * @return {Boolean}
17132 isResizable : function(colIndex){
17133 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
17136 * Sets if a column is hidden.
17137 * @param {Number} colIndex The column index
17138 * @param {Boolean} hidden True if the column is hidden
17140 setHidden : function(colIndex, hidden){
17141 this.config[colIndex].hidden = hidden;
17142 this.totalWidth = null;
17143 this.fireEvent("hiddenchange", this, colIndex, hidden);
17147 * Sets the editor for a column.
17148 * @param {Number} col The column index
17149 * @param {Object} editor The editor object
17151 setEditor : function(col, editor){
17152 this.config[col].editor = editor;
17156 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
17157 if(typeof value == "string" && value.length < 1){
17163 // Alias for backwards compatibility
17164 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
17167 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17168 * @class Roo.bootstrap.Table.RowSelectionModel
17169 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17170 * It supports multiple selections and keyboard selection/navigation.
17172 * @param {Object} config
17175 Roo.bootstrap.Table.RowSelectionModel = function(config){
17176 Roo.apply(this, config);
17177 this.selections = new Roo.util.MixedCollection(false, function(o){
17182 this.lastActive = false;
17186 * @event selectionchange
17187 * Fires when the selection changes
17188 * @param {SelectionModel} this
17190 "selectionchange" : true,
17192 * @event afterselectionchange
17193 * Fires after the selection changes (eg. by key press or clicking)
17194 * @param {SelectionModel} this
17196 "afterselectionchange" : true,
17198 * @event beforerowselect
17199 * Fires when a row is selected being selected, return false to cancel.
17200 * @param {SelectionModel} this
17201 * @param {Number} rowIndex The selected index
17202 * @param {Boolean} keepExisting False if other selections will be cleared
17204 "beforerowselect" : true,
17207 * Fires when a row is selected.
17208 * @param {SelectionModel} this
17209 * @param {Number} rowIndex The selected index
17210 * @param {Roo.data.Record} r The record
17212 "rowselect" : true,
17214 * @event rowdeselect
17215 * Fires when a row is deselected.
17216 * @param {SelectionModel} this
17217 * @param {Number} rowIndex The selected index
17219 "rowdeselect" : true
17221 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17222 this.locked = false;
17225 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17227 * @cfg {Boolean} singleSelect
17228 * True to allow selection of only one row at a time (defaults to false)
17230 singleSelect : false,
17233 initEvents : function(){
17235 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17236 this.grid.on("mousedown", this.handleMouseDown, this);
17237 }else{ // allow click to work like normal
17238 this.grid.on("rowclick", this.handleDragableRowClick, this);
17241 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17242 "up" : function(e){
17244 this.selectPrevious(e.shiftKey);
17245 }else if(this.last !== false && this.lastActive !== false){
17246 var last = this.last;
17247 this.selectRange(this.last, this.lastActive-1);
17248 this.grid.getView().focusRow(this.lastActive);
17249 if(last !== false){
17253 this.selectFirstRow();
17255 this.fireEvent("afterselectionchange", this);
17257 "down" : function(e){
17259 this.selectNext(e.shiftKey);
17260 }else if(this.last !== false && this.lastActive !== false){
17261 var last = this.last;
17262 this.selectRange(this.last, this.lastActive+1);
17263 this.grid.getView().focusRow(this.lastActive);
17264 if(last !== false){
17268 this.selectFirstRow();
17270 this.fireEvent("afterselectionchange", this);
17275 var view = this.grid.view;
17276 view.on("refresh", this.onRefresh, this);
17277 view.on("rowupdated", this.onRowUpdated, this);
17278 view.on("rowremoved", this.onRemove, this);
17282 onRefresh : function(){
17283 var ds = this.grid.dataSource, i, v = this.grid.view;
17284 var s = this.selections;
17285 s.each(function(r){
17286 if((i = ds.indexOfId(r.id)) != -1){
17295 onRemove : function(v, index, r){
17296 this.selections.remove(r);
17300 onRowUpdated : function(v, index, r){
17301 if(this.isSelected(r)){
17302 v.onRowSelect(index);
17308 * @param {Array} records The records to select
17309 * @param {Boolean} keepExisting (optional) True to keep existing selections
17311 selectRecords : function(records, keepExisting){
17313 this.clearSelections();
17315 var ds = this.grid.dataSource;
17316 for(var i = 0, len = records.length; i < len; i++){
17317 this.selectRow(ds.indexOf(records[i]), true);
17322 * Gets the number of selected rows.
17325 getCount : function(){
17326 return this.selections.length;
17330 * Selects the first row in the grid.
17332 selectFirstRow : function(){
17337 * Select the last row.
17338 * @param {Boolean} keepExisting (optional) True to keep existing selections
17340 selectLastRow : function(keepExisting){
17341 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17345 * Selects the row immediately following the last selected row.
17346 * @param {Boolean} keepExisting (optional) True to keep existing selections
17348 selectNext : function(keepExisting){
17349 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17350 this.selectRow(this.last+1, keepExisting);
17351 this.grid.getView().focusRow(this.last);
17356 * Selects the row that precedes the last selected row.
17357 * @param {Boolean} keepExisting (optional) True to keep existing selections
17359 selectPrevious : function(keepExisting){
17361 this.selectRow(this.last-1, keepExisting);
17362 this.grid.getView().focusRow(this.last);
17367 * Returns the selected records
17368 * @return {Array} Array of selected records
17370 getSelections : function(){
17371 return [].concat(this.selections.items);
17375 * Returns the first selected record.
17378 getSelected : function(){
17379 return this.selections.itemAt(0);
17384 * Clears all selections.
17386 clearSelections : function(fast){
17387 if(this.locked) return;
17389 var ds = this.grid.dataSource;
17390 var s = this.selections;
17391 s.each(function(r){
17392 this.deselectRow(ds.indexOfId(r.id));
17396 this.selections.clear();
17403 * Selects all rows.
17405 selectAll : function(){
17406 if(this.locked) return;
17407 this.selections.clear();
17408 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17409 this.selectRow(i, true);
17414 * Returns True if there is a selection.
17415 * @return {Boolean}
17417 hasSelection : function(){
17418 return this.selections.length > 0;
17422 * Returns True if the specified row is selected.
17423 * @param {Number/Record} record The record or index of the record to check
17424 * @return {Boolean}
17426 isSelected : function(index){
17427 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17428 return (r && this.selections.key(r.id) ? true : false);
17432 * Returns True if the specified record id is selected.
17433 * @param {String} id The id of record to check
17434 * @return {Boolean}
17436 isIdSelected : function(id){
17437 return (this.selections.key(id) ? true : false);
17441 handleMouseDown : function(e, t){
17442 var view = this.grid.getView(), rowIndex;
17443 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17446 if(e.shiftKey && this.last !== false){
17447 var last = this.last;
17448 this.selectRange(last, rowIndex, e.ctrlKey);
17449 this.last = last; // reset the last
17450 view.focusRow(rowIndex);
17452 var isSelected = this.isSelected(rowIndex);
17453 if(e.button !== 0 && isSelected){
17454 view.focusRow(rowIndex);
17455 }else if(e.ctrlKey && isSelected){
17456 this.deselectRow(rowIndex);
17457 }else if(!isSelected){
17458 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17459 view.focusRow(rowIndex);
17462 this.fireEvent("afterselectionchange", this);
17465 handleDragableRowClick : function(grid, rowIndex, e)
17467 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17468 this.selectRow(rowIndex, false);
17469 grid.view.focusRow(rowIndex);
17470 this.fireEvent("afterselectionchange", this);
17475 * Selects multiple rows.
17476 * @param {Array} rows Array of the indexes of the row to select
17477 * @param {Boolean} keepExisting (optional) True to keep existing selections
17479 selectRows : function(rows, keepExisting){
17481 this.clearSelections();
17483 for(var i = 0, len = rows.length; i < len; i++){
17484 this.selectRow(rows[i], true);
17489 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17490 * @param {Number} startRow The index of the first row in the range
17491 * @param {Number} endRow The index of the last row in the range
17492 * @param {Boolean} keepExisting (optional) True to retain existing selections
17494 selectRange : function(startRow, endRow, keepExisting){
17495 if(this.locked) return;
17497 this.clearSelections();
17499 if(startRow <= endRow){
17500 for(var i = startRow; i <= endRow; i++){
17501 this.selectRow(i, true);
17504 for(var i = startRow; i >= endRow; i--){
17505 this.selectRow(i, true);
17511 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17512 * @param {Number} startRow The index of the first row in the range
17513 * @param {Number} endRow The index of the last row in the range
17515 deselectRange : function(startRow, endRow, preventViewNotify){
17516 if(this.locked) return;
17517 for(var i = startRow; i <= endRow; i++){
17518 this.deselectRow(i, preventViewNotify);
17524 * @param {Number} row The index of the row to select
17525 * @param {Boolean} keepExisting (optional) True to keep existing selections
17527 selectRow : function(index, keepExisting, preventViewNotify){
17528 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17529 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17530 if(!keepExisting || this.singleSelect){
17531 this.clearSelections();
17533 var r = this.grid.dataSource.getAt(index);
17534 this.selections.add(r);
17535 this.last = this.lastActive = index;
17536 if(!preventViewNotify){
17537 this.grid.getView().onRowSelect(index);
17539 this.fireEvent("rowselect", this, index, r);
17540 this.fireEvent("selectionchange", this);
17546 * @param {Number} row The index of the row to deselect
17548 deselectRow : function(index, preventViewNotify){
17549 if(this.locked) return;
17550 if(this.last == index){
17553 if(this.lastActive == index){
17554 this.lastActive = false;
17556 var r = this.grid.dataSource.getAt(index);
17557 this.selections.remove(r);
17558 if(!preventViewNotify){
17559 this.grid.getView().onRowDeselect(index);
17561 this.fireEvent("rowdeselect", this, index);
17562 this.fireEvent("selectionchange", this);
17566 restoreLast : function(){
17568 this.last = this._last;
17573 acceptsNav : function(row, col, cm){
17574 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17578 onEditorKey : function(field, e){
17579 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17584 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17586 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17588 }else if(k == e.ENTER && !e.ctrlKey){
17592 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17594 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17596 }else if(k == e.ESC){
17600 g.startEditing(newCell[0], newCell[1]);
17611 * @class Roo.bootstrap.MessageBar
17612 * @extends Roo.bootstrap.Component
17613 * Bootstrap MessageBar class
17614 * @cfg {String} html contents of the MessageBar
17615 * @cfg {String} weight (info | success | warning | danger) default info
17616 * @cfg {String} beforeClass insert the bar before the given class
17617 * @cfg {Boolean} closable (true | false) default false
17618 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17621 * Create a new Element
17622 * @param {Object} config The config object
17625 Roo.bootstrap.MessageBar = function(config){
17626 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17629 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17635 beforeClass: 'bootstrap-sticky-wrap',
17637 getAutoCreate : function(){
17641 cls: 'alert alert-dismissable alert-' + this.weight,
17646 html: this.html || ''
17652 cfg.cls += ' alert-messages-fixed';
17666 onRender : function(ct, position)
17668 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17671 var cfg = Roo.apply({}, this.getAutoCreate());
17675 cfg.cls += ' ' + this.cls;
17678 cfg.style = this.style;
17680 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17682 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17685 this.el.select('>button.close').on('click', this.hide, this);
17691 if (!this.rendered) {
17697 this.fireEvent('show', this);
17703 if (!this.rendered) {
17709 this.fireEvent('hide', this);
17712 update : function()
17714 // var e = this.el.dom.firstChild;
17716 // if(this.closable){
17717 // e = e.nextSibling;
17720 // e.data = this.html || '';
17722 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';