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';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1160 if(!this.href || this.preventDefault){
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3180 Roo.bootstrap.NavGroup.register(this);
3184 * Fires when the active item changes
3185 * @param {Roo.bootstrap.NavGroup} this
3186 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3187 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3194 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3205 getAutoCreate : function()
3207 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3214 if (['tabs','pills'].indexOf(this.type)!==-1) {
3215 cfg.cls += ' nav-' + this.type
3217 if (this.type!=='nav') {
3218 Roo.log('nav type must be nav/tabs/pills')
3220 cfg.cls += ' navbar-nav'
3223 if (this.parent().sidebar) {
3226 cls: 'dashboard-menu sidebar-menu'
3232 if (this.form === true) {
3238 if (this.align === 'right') {
3239 cfg.cls += ' navbar-right';
3241 cfg.cls += ' navbar-left';
3245 if (this.align === 'right') {
3246 cfg.cls += ' navbar-right';
3250 cfg.cls += ' navbar-inverse';
3258 setActiveItem : function(item)
3261 Roo.each(this.navItems, function(v){
3266 v.setActive(false, true);
3273 item.setActive(true, true);
3274 this.fireEvent('changed', this, item, prev);
3279 addItem : function(cfg)
3281 var cn = new Roo.bootstrap.NavItem(cfg);
3283 cn.parentId = this.id;
3284 cn.onRender(this.el, null);
3288 register : function(item)
3290 this.navItems.push( item);
3291 item.navId = this.navId;
3294 getNavItem: function(tabId)
3297 Roo.each(this.navItems, function(e) {
3298 if (e.tabId == tabId) {
3314 Roo.apply(Roo.bootstrap.NavGroup, {
3318 register : function(navgrp)
3320 this.groups[navgrp.navId] = navgrp;
3323 get: function(navId) {
3324 return this.groups[navId];
3339 * @class Roo.bootstrap.NavItem
3340 * @extends Roo.bootstrap.Component
3341 * Bootstrap Navbar.NavItem class
3342 * @cfg {String} href link to
3343 * @cfg {String} html content of button
3344 * @cfg {String} badge text inside badge
3345 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3346 * @cfg {String} glyphicon name of glyphicon
3347 * @cfg {String} icon name of font awesome icon
3348 * @cfg {Boolean} active Is item active
3349 * @cfg {Boolean} disabled Is item disabled
3351 * @cfg {Boolean} preventDefault (true | false) default false
3352 * @cfg {String} tabId the tab that this item activates.
3353 * @cfg {String} tagtype (a|span) render as a href or span?
3356 * Create a new Navbar Item
3357 * @param {Object} config The config object
3359 Roo.bootstrap.NavItem = function(config){
3360 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3365 * The raw click event for the entire grid.
3366 * @param {Roo.EventObject} e
3371 * Fires when the active item active state changes
3372 * @param {Roo.bootstrap.NavItem} this
3373 * @param {boolean} state the new state
3381 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3389 preventDefault : false,
3394 getAutoCreate : function(){
3402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3404 if (this.disabled) {
3405 cfg.cls += ' disabled';
3408 if (this.href || this.html || this.glyphicon || this.icon) {
3412 href : this.href || "#",
3413 html: this.html || ''
3418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3421 if(this.glyphicon) {
3422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3427 cfg.cn[0].html += " <span class='caret'></span>";
3431 if (this.badge !== '') {
3433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3441 initEvents: function() {
3442 // Roo.log('init events?');
3443 // Roo.log(this.el.dom);
3444 if (typeof (this.menu) != 'undefined') {
3445 this.menu.parentType = this.xtype;
3446 this.menu.triggerEl = this.el;
3447 this.addxtype(Roo.apply({}, this.menu));
3451 this.el.select('a',true).on('click', this.onClick, this);
3452 // at this point parent should be available..
3453 this.parent().register(this);
3456 onClick : function(e)
3459 if(this.preventDefault){
3462 if (this.disabled) {
3465 Roo.log("fire event clicked");
3466 if(this.fireEvent('click', this, e) === false){
3470 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3471 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3472 this.parent().setActiveItem(this);
3480 isActive: function () {
3483 setActive : function(state, fire)
3485 this.active = state;
3487 this.el.removeClass('active');
3488 } else if (!this.el.hasClass('active')) {
3489 this.el.addClass('active');
3492 this.fireEvent('changed', this, state);
3497 // this should not be here...
3498 setDisabled : function(state)
3500 this.disabled = state;
3502 this.el.removeClass('disabled');
3503 } else if (!this.el.hasClass('disabled')) {
3504 this.el.addClass('disabled');
3517 * <span> icon </span>
3518 * <span> text </span>
3519 * <span>badge </span>
3523 * @class Roo.bootstrap.NavSidebarItem
3524 * @extends Roo.bootstrap.NavItem
3525 * Bootstrap Navbar.NavSidebarItem class
3527 * Create a new Navbar Button
3528 * @param {Object} config The config object
3530 Roo.bootstrap.NavSidebarItem = function(config){
3531 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3536 * The raw click event for the entire grid.
3537 * @param {Roo.EventObject} e
3542 * Fires when the active item active state changes
3543 * @param {Roo.bootstrap.NavSidebarItem} this
3544 * @param {boolean} state the new state
3552 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3555 getAutoCreate : function(){
3560 href : this.href || '#',
3572 html : this.html || ''
3577 cfg.cls += ' active';
3581 if (this.glyphicon || this.icon) {
3582 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3583 a.cn.push({ tag : 'i', cls : c }) ;
3588 if (this.badge !== '') {
3589 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3593 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3594 a.cls += 'dropdown-toggle treeview' ;
3618 * @class Roo.bootstrap.Row
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Row class (contains columns...)
3624 * @param {Object} config The config object
3627 Roo.bootstrap.Row = function(config){
3628 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3631 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3652 * @class Roo.bootstrap.Element
3653 * @extends Roo.bootstrap.Component
3654 * Bootstrap Element class
3655 * @cfg {String} html contents of the element
3656 * @cfg {String} tag tag of the element
3657 * @cfg {String} cls class of the element
3660 * Create a new Element
3661 * @param {Object} config The config object
3664 Roo.bootstrap.Element = function(config){
3665 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3675 getAutoCreate : function(){
3700 * @class Roo.bootstrap.Pagination
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap Pagination class
3703 * @cfg {String} size xs | sm | md | lg
3704 * @cfg {Boolean} inverse false | true
3707 * Create a new Pagination
3708 * @param {Object} config The config object
3711 Roo.bootstrap.Pagination = function(config){
3712 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3715 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3721 getAutoCreate : function(){
3727 cfg.cls += ' inverse';
3733 cfg.cls += " " + this.cls;
3751 * @class Roo.bootstrap.PaginationItem
3752 * @extends Roo.bootstrap.Component
3753 * Bootstrap PaginationItem class
3754 * @cfg {String} html text
3755 * @cfg {String} href the link
3756 * @cfg {Boolean} preventDefault (true | false) default true
3757 * @cfg {Boolean} active (true | false) default false
3761 * Create a new PaginationItem
3762 * @param {Object} config The config object
3766 Roo.bootstrap.PaginationItem = function(config){
3767 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3772 * The raw click event for the entire grid.
3773 * @param {Roo.EventObject} e
3779 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3783 preventDefault: true,
3787 getAutoCreate : function(){
3793 href : this.href ? this.href : '#',
3794 html : this.html ? this.html : ''
3804 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3810 initEvents: function() {
3812 this.el.on('click', this.onClick, this);
3815 onClick : function(e)
3817 Roo.log('PaginationItem on click ');
3818 if(this.preventDefault){
3822 this.fireEvent('click', this, e);
3838 * @class Roo.bootstrap.Slider
3839 * @extends Roo.bootstrap.Component
3840 * Bootstrap Slider class
3843 * Create a new Slider
3844 * @param {Object} config The config object
3847 Roo.bootstrap.Slider = function(config){
3848 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3851 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3853 getAutoCreate : function(){
3857 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3861 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.grid.ColumnModel
3885 * @extends Roo.util.Observable
3886 * This is the default implementation of a ColumnModel used by the Grid. It defines
3887 * the columns in the grid.
3890 var colModel = new Roo.grid.ColumnModel([
3891 {header: "Ticker", width: 60, sortable: true, locked: true},
3892 {header: "Company Name", width: 150, sortable: true},
3893 {header: "Market Cap.", width: 100, sortable: true},
3894 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3895 {header: "Employees", width: 100, sortable: true, resizable: false}
3900 * The config options listed for this class are options which may appear in each
3901 * individual column definition.
3902 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3904 * @param {Object} config An Array of column config objects. See this class's
3905 * config objects for details.
3907 Roo.grid.ColumnModel = function(config){
3909 * The config passed into the constructor
3911 this.config = config;
3914 // if no id, create one
3915 // if the column does not have a dataIndex mapping,
3916 // map it to the order it is in the config
3917 for(var i = 0, len = config.length; i < len; i++){
3919 if(typeof c.dataIndex == "undefined"){
3922 if(typeof c.renderer == "string"){
3923 c.renderer = Roo.util.Format[c.renderer];
3925 if(typeof c.id == "undefined"){
3928 if(c.editor && c.editor.xtype){
3929 c.editor = Roo.factory(c.editor, Roo.grid);
3931 if(c.editor && c.editor.isFormField){
3932 c.editor = new Roo.grid.GridEditor(c.editor);
3934 this.lookup[c.id] = c;
3938 * The width of columns which have no width specified (defaults to 100)
3941 this.defaultWidth = 100;
3944 * Default sortable of columns which have no sortable specified (defaults to false)
3947 this.defaultSortable = false;
3951 * @event widthchange
3952 * Fires when the width of a column changes.
3953 * @param {ColumnModel} this
3954 * @param {Number} columnIndex The column index
3955 * @param {Number} newWidth The new width
3957 "widthchange": true,
3959 * @event headerchange
3960 * Fires when the text of a header changes.
3961 * @param {ColumnModel} this
3962 * @param {Number} columnIndex The column index
3963 * @param {Number} newText The new header text
3965 "headerchange": true,
3967 * @event hiddenchange
3968 * Fires when a column is hidden or "unhidden".
3969 * @param {ColumnModel} this
3970 * @param {Number} columnIndex The column index
3971 * @param {Boolean} hidden true if hidden, false otherwise
3973 "hiddenchange": true,
3975 * @event columnmoved
3976 * Fires when a column is moved.
3977 * @param {ColumnModel} this
3978 * @param {Number} oldIndex
3979 * @param {Number} newIndex
3981 "columnmoved" : true,
3983 * @event columlockchange
3984 * Fires when a column's locked state is changed
3985 * @param {ColumnModel} this
3986 * @param {Number} colIndex
3987 * @param {Boolean} locked true if locked
3989 "columnlockchange" : true
3991 Roo.grid.ColumnModel.superclass.constructor.call(this);
3993 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3995 * @cfg {String} header The header text to display in the Grid view.
3998 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3999 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4000 * specified, the column's index is used as an index into the Record's data Array.
4003 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4004 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4007 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4008 * Defaults to the value of the {@link #defaultSortable} property.
4009 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4012 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4015 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4018 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4021 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4024 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4025 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4026 * default renderer uses the raw data value.
4029 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4032 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4036 * Returns the id of the column at the specified index.
4037 * @param {Number} index The column index
4038 * @return {String} the id
4040 getColumnId : function(index){
4041 return this.config[index].id;
4045 * Returns the column for a specified id.
4046 * @param {String} id The column id
4047 * @return {Object} the column
4049 getColumnById : function(id){
4050 return this.lookup[id];
4055 * Returns the column for a specified dataIndex.
4056 * @param {String} dataIndex The column dataIndex
4057 * @return {Object|Boolean} the column or false if not found
4059 getColumnByDataIndex: function(dataIndex){
4060 var index = this.findColumnIndex(dataIndex);
4061 return index > -1 ? this.config[index] : false;
4065 * Returns the index for a specified column id.
4066 * @param {String} id The column id
4067 * @return {Number} the index, or -1 if not found
4069 getIndexById : function(id){
4070 for(var i = 0, len = this.config.length; i < len; i++){
4071 if(this.config[i].id == id){
4079 * Returns the index for a specified column dataIndex.
4080 * @param {String} dataIndex The column dataIndex
4081 * @return {Number} the index, or -1 if not found
4084 findColumnIndex : function(dataIndex){
4085 for(var i = 0, len = this.config.length; i < len; i++){
4086 if(this.config[i].dataIndex == dataIndex){
4094 moveColumn : function(oldIndex, newIndex){
4095 var c = this.config[oldIndex];
4096 this.config.splice(oldIndex, 1);
4097 this.config.splice(newIndex, 0, c);
4098 this.dataMap = null;
4099 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4102 isLocked : function(colIndex){
4103 return this.config[colIndex].locked === true;
4106 setLocked : function(colIndex, value, suppressEvent){
4107 if(this.isLocked(colIndex) == value){
4110 this.config[colIndex].locked = value;
4112 this.fireEvent("columnlockchange", this, colIndex, value);
4116 getTotalLockedWidth : function(){
4118 for(var i = 0; i < this.config.length; i++){
4119 if(this.isLocked(i) && !this.isHidden(i)){
4120 this.totalWidth += this.getColumnWidth(i);
4126 getLockedCount : function(){
4127 for(var i = 0, len = this.config.length; i < len; i++){
4128 if(!this.isLocked(i)){
4135 * Returns the number of columns.
4138 getColumnCount : function(visibleOnly){
4139 if(visibleOnly === true){
4141 for(var i = 0, len = this.config.length; i < len; i++){
4142 if(!this.isHidden(i)){
4148 return this.config.length;
4152 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4153 * @param {Function} fn
4154 * @param {Object} scope (optional)
4155 * @return {Array} result
4157 getColumnsBy : function(fn, scope){
4159 for(var i = 0, len = this.config.length; i < len; i++){
4160 var c = this.config[i];
4161 if(fn.call(scope||this, c, i) === true){
4169 * Returns true if the specified column is sortable.
4170 * @param {Number} col The column index
4173 isSortable : function(col){
4174 if(typeof this.config[col].sortable == "undefined"){
4175 return this.defaultSortable;
4177 return this.config[col].sortable;
4181 * Returns the rendering (formatting) function defined for the column.
4182 * @param {Number} col The column index.
4183 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4185 getRenderer : function(col){
4186 if(!this.config[col].renderer){
4187 return Roo.grid.ColumnModel.defaultRenderer;
4189 return this.config[col].renderer;
4193 * Sets the rendering (formatting) function for a column.
4194 * @param {Number} col The column index
4195 * @param {Function} fn The function to use to process the cell's raw data
4196 * to return HTML markup for the grid view. The render function is called with
4197 * the following parameters:<ul>
4198 * <li>Data value.</li>
4199 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4200 * <li>css A CSS style string to apply to the table cell.</li>
4201 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4202 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4203 * <li>Row index</li>
4204 * <li>Column index</li>
4205 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4207 setRenderer : function(col, fn){
4208 this.config[col].renderer = fn;
4212 * Returns the width for the specified column.
4213 * @param {Number} col The column index
4216 getColumnWidth : function(col){
4217 return this.config[col].width * 1 || this.defaultWidth;
4221 * Sets the width for a column.
4222 * @param {Number} col The column index
4223 * @param {Number} width The new width
4225 setColumnWidth : function(col, width, suppressEvent){
4226 this.config[col].width = width;
4227 this.totalWidth = null;
4229 this.fireEvent("widthchange", this, col, width);
4234 * Returns the total width of all columns.
4235 * @param {Boolean} includeHidden True to include hidden column widths
4238 getTotalWidth : function(includeHidden){
4239 if(!this.totalWidth){
4240 this.totalWidth = 0;
4241 for(var i = 0, len = this.config.length; i < len; i++){
4242 if(includeHidden || !this.isHidden(i)){
4243 this.totalWidth += this.getColumnWidth(i);
4247 return this.totalWidth;
4251 * Returns the header for the specified column.
4252 * @param {Number} col The column index
4255 getColumnHeader : function(col){
4256 return this.config[col].header;
4260 * Sets the header for a column.
4261 * @param {Number} col The column index
4262 * @param {String} header The new header
4264 setColumnHeader : function(col, header){
4265 this.config[col].header = header;
4266 this.fireEvent("headerchange", this, col, header);
4270 * Returns the tooltip for the specified column.
4271 * @param {Number} col The column index
4274 getColumnTooltip : function(col){
4275 return this.config[col].tooltip;
4278 * Sets the tooltip for a column.
4279 * @param {Number} col The column index
4280 * @param {String} tooltip The new tooltip
4282 setColumnTooltip : function(col, tooltip){
4283 this.config[col].tooltip = tooltip;
4287 * Returns the dataIndex for the specified column.
4288 * @param {Number} col The column index
4291 getDataIndex : function(col){
4292 return this.config[col].dataIndex;
4296 * Sets the dataIndex for a column.
4297 * @param {Number} col The column index
4298 * @param {Number} dataIndex The new dataIndex
4300 setDataIndex : function(col, dataIndex){
4301 this.config[col].dataIndex = dataIndex;
4307 * Returns true if the cell is editable.
4308 * @param {Number} colIndex The column index
4309 * @param {Number} rowIndex The row index
4312 isCellEditable : function(colIndex, rowIndex){
4313 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4317 * Returns the editor defined for the cell/column.
4318 * return false or null to disable editing.
4319 * @param {Number} colIndex The column index
4320 * @param {Number} rowIndex The row index
4323 getCellEditor : function(colIndex, rowIndex){
4324 return this.config[colIndex].editor;
4328 * Sets if a column is editable.
4329 * @param {Number} col The column index
4330 * @param {Boolean} editable True if the column is editable
4332 setEditable : function(col, editable){
4333 this.config[col].editable = editable;
4338 * Returns true if the column is hidden.
4339 * @param {Number} colIndex The column index
4342 isHidden : function(colIndex){
4343 return this.config[colIndex].hidden;
4348 * Returns true if the column width cannot be changed
4350 isFixed : function(colIndex){
4351 return this.config[colIndex].fixed;
4355 * Returns true if the column can be resized
4358 isResizable : function(colIndex){
4359 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4362 * Sets if a column is hidden.
4363 * @param {Number} colIndex The column index
4364 * @param {Boolean} hidden True if the column is hidden
4366 setHidden : function(colIndex, hidden){
4367 this.config[colIndex].hidden = hidden;
4368 this.totalWidth = null;
4369 this.fireEvent("hiddenchange", this, colIndex, hidden);
4373 * Sets the editor for a column.
4374 * @param {Number} col The column index
4375 * @param {Object} editor The editor object
4377 setEditor : function(col, editor){
4378 this.config[col].editor = editor;
4382 Roo.grid.ColumnModel.defaultRenderer = function(value){
4383 if(typeof value == "string" && value.length < 1){
4389 // Alias for backwards compatibility
4390 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4393 * Ext JS Library 1.1.1
4394 * Copyright(c) 2006-2007, Ext JS, LLC.
4396 * Originally Released Under LGPL - original licence link has changed is not relivant.
4399 * <script type="text/javascript">
4403 * @class Roo.LoadMask
4404 * A simple utility class for generically masking elements while loading data. If the element being masked has
4405 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4406 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4407 * element's UpdateManager load indicator and will be destroyed after the initial load.
4409 * Create a new LoadMask
4410 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4411 * @param {Object} config The config object
4413 Roo.LoadMask = function(el, config){
4414 this.el = Roo.get(el);
4415 Roo.apply(this, config);
4417 this.store.on('beforeload', this.onBeforeLoad, this);
4418 this.store.on('load', this.onLoad, this);
4419 this.store.on('loadexception', this.onLoadException, this);
4420 this.removeMask = false;
4422 var um = this.el.getUpdateManager();
4423 um.showLoadIndicator = false; // disable the default indicator
4424 um.on('beforeupdate', this.onBeforeLoad, this);
4425 um.on('update', this.onLoad, this);
4426 um.on('failure', this.onLoad, this);
4427 this.removeMask = true;
4431 Roo.LoadMask.prototype = {
4433 * @cfg {Boolean} removeMask
4434 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4435 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4439 * The text to display in a centered loading message box (defaults to 'Loading...')
4443 * @cfg {String} msgCls
4444 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4446 msgCls : 'x-mask-loading',
4449 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4455 * Disables the mask to prevent it from being displayed
4457 disable : function(){
4458 this.disabled = true;
4462 * Enables the mask so that it can be displayed
4464 enable : function(){
4465 this.disabled = false;
4468 onLoadException : function()
4472 if (typeof(arguments[3]) != 'undefined') {
4473 Roo.MessageBox.alert("Error loading",arguments[3]);
4477 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4478 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4487 this.el.unmask(this.removeMask);
4492 this.el.unmask(this.removeMask);
4496 onBeforeLoad : function(){
4498 this.el.mask(this.msg, this.msgCls);
4503 destroy : function(){
4505 this.store.un('beforeload', this.onBeforeLoad, this);
4506 this.store.un('load', this.onLoad, this);
4507 this.store.un('loadexception', this.onLoadException, this);
4509 var um = this.el.getUpdateManager();
4510 um.un('beforeupdate', this.onBeforeLoad, this);
4511 um.un('update', this.onLoad, this);
4512 um.un('failure', this.onLoad, this);
4523 * @class Roo.bootstrap.Table
4524 * @extends Roo.bootstrap.Component
4525 * Bootstrap Table class
4526 * @cfg {String} cls table class
4527 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4528 * @cfg {String} bgcolor Specifies the background color for a table
4529 * @cfg {Number} border Specifies whether the table cells should have borders or not
4530 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4531 * @cfg {Number} cellspacing Specifies the space between cells
4532 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4533 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4534 * @cfg {String} sortable Specifies that the table should be sortable
4535 * @cfg {String} summary Specifies a summary of the content of a table
4536 * @cfg {Number} width Specifies the width of a table
4537 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4539 * @cfg {boolean} striped Should the rows be alternative striped
4540 * @cfg {boolean} bordered Add borders to the table
4541 * @cfg {boolean} hover Add hover highlighting
4542 * @cfg {boolean} condensed Format condensed
4543 * @cfg {boolean} responsive Format condensed
4544 * @cfg {Boolean} loadMask (true|false) default false
4545 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4546 * @cfg {Boolean} thead (true|false) generate thead, default true
4547 * @cfg {Boolean} RowSelection (true|false) default false
4548 * @cfg {Boolean} CellSelection (true|false) default false
4550 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4554 * Create a new Table
4555 * @param {Object} config The config object
4558 Roo.bootstrap.Table = function(config){
4559 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4562 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4563 this.sm = this.selModel;
4564 this.sm.xmodule = this.xmodule || false;
4566 if (this.cm && typeof(this.cm.config) == 'undefined') {
4567 this.colModel = new Roo.grid.ColumnModel(this.cm);
4568 this.cm = this.colModel;
4569 this.cm.xmodule = this.xmodule || false;
4572 this.store= Roo.factory(this.store, Roo.data);
4573 this.ds = this.store;
4574 this.ds.xmodule = this.xmodule || false;
4577 if (this.footer && this.store) {
4578 this.footer.dataSource = this.ds;
4579 this.footer = Roo.factory(this.footer);
4586 * Fires when a cell is clicked
4587 * @param {Roo.bootstrap.Table} this
4588 * @param {Roo.Element} el
4589 * @param {Number} rowIndex
4590 * @param {Number} columnIndex
4591 * @param {Roo.EventObject} e
4595 * @event celldblclick
4596 * Fires when a cell is double clicked
4597 * @param {Roo.bootstrap.Table} this
4598 * @param {Roo.Element} el
4599 * @param {Number} rowIndex
4600 * @param {Number} columnIndex
4601 * @param {Roo.EventObject} e
4603 "celldblclick" : true,
4606 * Fires when a row is clicked
4607 * @param {Roo.bootstrap.Table} this
4608 * @param {Roo.Element} el
4609 * @param {Number} rowIndex
4610 * @param {Roo.EventObject} e
4614 * @event rowdblclick
4615 * Fires when a row is double clicked
4616 * @param {Roo.bootstrap.Table} this
4617 * @param {Roo.Element} el
4618 * @param {Number} rowIndex
4619 * @param {Roo.EventObject} e
4621 "rowdblclick" : true,
4624 * Fires when a mouseover occur
4625 * @param {Roo.bootstrap.Table} this
4626 * @param {Roo.Element} el
4627 * @param {Number} rowIndex
4628 * @param {Number} columnIndex
4629 * @param {Roo.EventObject} e
4634 * Fires when a mouseout occur
4635 * @param {Roo.bootstrap.Table} this
4636 * @param {Roo.Element} el
4637 * @param {Number} rowIndex
4638 * @param {Number} columnIndex
4639 * @param {Roo.EventObject} e
4644 * Fires when a row is rendered, so you can change add a style to it.
4645 * @param {Roo.bootstrap.Table} this
4646 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4653 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4677 RowSelection : false,
4678 CellSelection : false,
4681 // Roo.Element - the tbody
4684 getAutoCreate : function(){
4685 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4694 cfg.cls += ' table-striped';
4698 cfg.cls += ' table-hover';
4700 if (this.bordered) {
4701 cfg.cls += ' table-bordered';
4703 if (this.condensed) {
4704 cfg.cls += ' table-condensed';
4706 if (this.responsive) {
4707 cfg.cls += ' table-responsive';
4711 cfg.cls+= ' ' +this.cls;
4714 // this lot should be simplifed...
4717 cfg.align=this.align;
4720 cfg.bgcolor=this.bgcolor;
4723 cfg.border=this.border;
4725 if (this.cellpadding) {
4726 cfg.cellpadding=this.cellpadding;
4728 if (this.cellspacing) {
4729 cfg.cellspacing=this.cellspacing;
4732 cfg.frame=this.frame;
4735 cfg.rules=this.rules;
4737 if (this.sortable) {
4738 cfg.sortable=this.sortable;
4741 cfg.summary=this.summary;
4744 cfg.width=this.width;
4747 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4750 if(this.store || this.cm){
4752 cfg.cn.push(this.renderHeader());
4755 cfg.cn.push(this.renderBody());
4758 cfg.cn.push(this.renderFooter());
4761 cfg.cls+= ' TableGrid';
4764 return { cn : [ cfg ] };
4767 initEvents : function()
4769 if(!this.store || !this.cm){
4773 //Roo.log('initEvents with ds!!!!');
4775 this.mainBody = this.el.select('tbody', true).first();
4780 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4781 e.on('click', _this.sort, _this);
4784 this.el.on("click", this.onClick, this);
4785 this.el.on("dblclick", this.onDblClick, this);
4787 this.parent().el.setStyle('position', 'relative');
4789 this.footer.parentId = this.id;
4790 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4793 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4795 this.store.on('load', this.onLoad, this);
4796 this.store.on('beforeload', this.onBeforeLoad, this);
4797 this.store.on('update', this.onUpdate, this);
4801 onMouseover : function(e, el)
4803 var cell = Roo.get(el);
4809 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4810 cell = cell.findParent('td', false, true);
4813 var row = cell.findParent('tr', false, true);
4814 var cellIndex = cell.dom.cellIndex;
4815 var rowIndex = row.dom.rowIndex - 1; // start from 0
4817 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4821 onMouseout : function(e, el)
4823 var cell = Roo.get(el);
4829 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4830 cell = cell.findParent('td', false, true);
4833 var row = cell.findParent('tr', false, true);
4834 var cellIndex = cell.dom.cellIndex;
4835 var rowIndex = row.dom.rowIndex - 1; // start from 0
4837 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4841 onClick : function(e, el)
4843 var cell = Roo.get(el);
4845 if(!cell || (!this.CellSelection && !this.RowSelection)){
4850 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4851 cell = cell.findParent('td', false, true);
4854 var row = cell.findParent('tr', false, true);
4855 var cellIndex = cell.dom.cellIndex;
4856 var rowIndex = row.dom.rowIndex - 1;
4858 if(this.CellSelection){
4859 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4862 if(this.RowSelection){
4863 this.fireEvent('rowclick', this, row, rowIndex, e);
4869 onDblClick : function(e,el)
4871 var cell = Roo.get(el);
4873 if(!cell || (!this.CellSelection && !this.RowSelection)){
4877 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4878 cell = cell.findParent('td', false, true);
4881 var row = cell.findParent('tr', false, true);
4882 var cellIndex = cell.dom.cellIndex;
4883 var rowIndex = row.dom.rowIndex - 1;
4885 if(this.CellSelection){
4886 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4889 if(this.RowSelection){
4890 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4894 sort : function(e,el)
4896 var col = Roo.get(el)
4898 if(!col.hasClass('sortable')){
4902 var sort = col.attr('sort');
4905 if(col.hasClass('glyphicon-arrow-up')){
4909 this.store.sortInfo = {field : sort, direction : dir};
4912 Roo.log("calling footer first");
4913 this.footer.onClick('first');
4916 this.store.load({ params : { start : 0 } });
4920 renderHeader : function()
4929 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4931 var config = cm.config[i];
4936 html: cm.getColumnHeader(i)
4939 if(typeof(config.hidden) != 'undefined' && config.hidden){
4940 c.style += ' display:none;';
4943 if(typeof(config.dataIndex) != 'undefined'){
4944 c.sort = config.dataIndex;
4947 if(typeof(config.sortable) != 'undefined' && config.sortable){
4951 // if(typeof(config.align) != 'undefined' && config.align.length){
4952 // c.style += ' text-align:' + config.align + ';';
4955 if(typeof(config.width) != 'undefined'){
4956 c.style += ' width:' + config.width + 'px;';
4965 renderBody : function()
4975 colspan : this.cm.getColumnCount()
4985 renderFooter : function()
4995 colspan : this.cm.getColumnCount()
5009 Roo.log('ds onload');
5014 var ds = this.store;
5016 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5017 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5019 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5020 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5023 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5024 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5028 var tbody = this.mainBody;
5032 if(ds.getCount() > 0){
5033 ds.data.each(function(d,rowIndex){
5034 var row = this.renderRow(cm, ds, rowIndex);
5036 tbody.createChild(row);
5040 if(row.renders.length){
5041 Roo.each(row.renders, function(r){
5042 _this.renderColumn(r);
5049 Roo.each(this.el.select('tbody td', true).elements, function(e){
5050 e.on('mouseover', _this.onMouseover, _this);
5053 Roo.each(this.el.select('tbody td', true).elements, function(e){
5054 e.on('mouseout', _this.onMouseout, _this);
5057 //if(this.loadMask){
5058 // this.maskEl.hide();
5063 onUpdate : function(ds,record)
5065 this.refreshRow(record);
5067 onRemove : function(ds, record, index, isUpdate){
5068 if(isUpdate !== true){
5069 this.fireEvent("beforerowremoved", this, index, record);
5071 var bt = this.mainBody.dom;
5073 bt.removeChild(bt.rows[index]);
5076 if(isUpdate !== true){
5077 //this.stripeRows(index);
5078 //this.syncRowHeights(index, index);
5080 this.fireEvent("rowremoved", this, index, record);
5085 refreshRow : function(record){
5086 var ds = this.store, index;
5087 if(typeof record == 'number'){
5089 record = ds.getAt(index);
5091 index = ds.indexOf(record);
5093 this.insertRow(ds, index, true);
5094 this.onRemove(ds, record, index+1, true);
5095 //this.syncRowHeights(index, index);
5097 this.fireEvent("rowupdated", this, index, record);
5100 insertRow : function(dm, rowIndex, isUpdate){
5103 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
5105 //var s = this.getScrollState();
5106 var row = this.renderRow(this.cm, this.store, rowIndex);
5107 // insert before rowIndex..
5108 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5112 this.fireEvent("rowsinserted", this, firstRow, lastRow);
5113 //this.syncRowHeights(firstRow, lastRow);
5114 //this.stripeRows(firstRow);
5121 getRowDom : function(rowIndex)
5123 // not sure if I need to check this.. but let's do it anyway..
5124 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5125 this.mainBody.dom.rows[rowIndex] : false
5127 // returns the object tree for a tr..
5130 renderRow : function(cm, ds, rowIndex) {
5132 var d = ds.getAt(rowIndex);
5141 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5142 var config = cm.config[i];
5144 var renderer = cm.getRenderer(i);
5148 if(typeof(renderer) !== 'undefined'){
5149 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5152 if(typeof(value) === 'object'){
5161 rowIndex : rowIndex,
5166 this.fireEvent('rowclass', this, rowcfg);
5171 cls : rowcfg.rowClass,
5173 html: (typeof(value) === 'object') ? '' : value
5176 if(typeof(config.hidden) != 'undefined' && config.hidden){
5177 td.style += ' display:none;';
5180 if(typeof(config.align) != 'undefined' && config.align.length){
5181 td.style += ' text-align:' + config.align + ';';
5184 if(typeof(config.width) != 'undefined'){
5185 td.style += ' width:' + config.width + 'px;';
5192 row.renders = renders;
5200 onBeforeLoad : function()
5202 //Roo.log('ds onBeforeLoad');
5206 //if(this.loadMask){
5207 // this.maskEl.show();
5213 this.el.select('tbody', true).first().dom.innerHTML = '';
5216 getSelectionModel : function(){
5218 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5220 return this.selModel;
5223 renderColumn : function(r)
5227 var t = r.cfg.render(r.container);
5230 Roo.each(r.cfg.cn, function(c){
5232 container: t.getChildContainer(),
5235 _this.renderColumn(child);
5252 * @class Roo.bootstrap.TableCell
5253 * @extends Roo.bootstrap.Component
5254 * Bootstrap TableCell class
5255 * @cfg {String} html cell contain text
5256 * @cfg {String} cls cell class
5257 * @cfg {String} tag cell tag (td|th) default td
5258 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5259 * @cfg {String} align Aligns the content in a cell
5260 * @cfg {String} axis Categorizes cells
5261 * @cfg {String} bgcolor Specifies the background color of a cell
5262 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5263 * @cfg {Number} colspan Specifies the number of columns a cell should span
5264 * @cfg {String} headers Specifies one or more header cells a cell is related to
5265 * @cfg {Number} height Sets the height of a cell
5266 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5267 * @cfg {Number} rowspan Sets the number of rows a cell should span
5268 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5269 * @cfg {String} valign Vertical aligns the content in a cell
5270 * @cfg {Number} width Specifies the width of a cell
5273 * Create a new TableCell
5274 * @param {Object} config The config object
5277 Roo.bootstrap.TableCell = function(config){
5278 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5281 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5301 getAutoCreate : function(){
5302 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5322 cfg.align=this.align
5328 cfg.bgcolor=this.bgcolor
5331 cfg.charoff=this.charoff
5334 cfg.colspan=this.colspan
5337 cfg.headers=this.headers
5340 cfg.height=this.height
5343 cfg.nowrap=this.nowrap
5346 cfg.rowspan=this.rowspan
5349 cfg.scope=this.scope
5352 cfg.valign=this.valign
5355 cfg.width=this.width
5374 * @class Roo.bootstrap.TableRow
5375 * @extends Roo.bootstrap.Component
5376 * Bootstrap TableRow class
5377 * @cfg {String} cls row class
5378 * @cfg {String} align Aligns the content in a table row
5379 * @cfg {String} bgcolor Specifies a background color for a table row
5380 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5381 * @cfg {String} valign Vertical aligns the content in a table row
5384 * Create a new TableRow
5385 * @param {Object} config The config object
5388 Roo.bootstrap.TableRow = function(config){
5389 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5392 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5400 getAutoCreate : function(){
5401 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5411 cfg.align = this.align;
5414 cfg.bgcolor = this.bgcolor;
5417 cfg.charoff = this.charoff;
5420 cfg.valign = this.valign;
5438 * @class Roo.bootstrap.TableBody
5439 * @extends Roo.bootstrap.Component
5440 * Bootstrap TableBody class
5441 * @cfg {String} cls element class
5442 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5443 * @cfg {String} align Aligns the content inside the element
5444 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5445 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5448 * Create a new TableBody
5449 * @param {Object} config The config object
5452 Roo.bootstrap.TableBody = function(config){
5453 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5456 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5464 getAutoCreate : function(){
5465 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5479 cfg.align = this.align;
5482 cfg.charoff = this.charoff;
5485 cfg.valign = this.valign;
5492 // initEvents : function()
5499 // this.store = Roo.factory(this.store, Roo.data);
5500 // this.store.on('load', this.onLoad, this);
5502 // this.store.load();
5506 // onLoad: function ()
5508 // this.fireEvent('load', this);
5518 * Ext JS Library 1.1.1
5519 * Copyright(c) 2006-2007, Ext JS, LLC.
5521 * Originally Released Under LGPL - original licence link has changed is not relivant.
5524 * <script type="text/javascript">
5527 // as we use this in bootstrap.
5528 Roo.namespace('Roo.form');
5530 * @class Roo.form.Action
5531 * Internal Class used to handle form actions
5533 * @param {Roo.form.BasicForm} el The form element or its id
5534 * @param {Object} config Configuration options
5539 // define the action interface
5540 Roo.form.Action = function(form, options){
5542 this.options = options || {};
5545 * Client Validation Failed
5548 Roo.form.Action.CLIENT_INVALID = 'client';
5550 * Server Validation Failed
5553 Roo.form.Action.SERVER_INVALID = 'server';
5555 * Connect to Server Failed
5558 Roo.form.Action.CONNECT_FAILURE = 'connect';
5560 * Reading Data from Server Failed
5563 Roo.form.Action.LOAD_FAILURE = 'load';
5565 Roo.form.Action.prototype = {
5567 failureType : undefined,
5568 response : undefined,
5572 run : function(options){
5577 success : function(response){
5582 handleResponse : function(response){
5586 // default connection failure
5587 failure : function(response){
5589 this.response = response;
5590 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5591 this.form.afterAction(this, false);
5594 processResponse : function(response){
5595 this.response = response;
5596 if(!response.responseText){
5599 this.result = this.handleResponse(response);
5603 // utility functions used internally
5604 getUrl : function(appendParams){
5605 var url = this.options.url || this.form.url || this.form.el.dom.action;
5607 var p = this.getParams();
5609 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5615 getMethod : function(){
5616 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5619 getParams : function(){
5620 var bp = this.form.baseParams;
5621 var p = this.options.params;
5623 if(typeof p == "object"){
5624 p = Roo.urlEncode(Roo.applyIf(p, bp));
5625 }else if(typeof p == 'string' && bp){
5626 p += '&' + Roo.urlEncode(bp);
5629 p = Roo.urlEncode(bp);
5634 createCallback : function(){
5636 success: this.success,
5637 failure: this.failure,
5639 timeout: (this.form.timeout*1000),
5640 upload: this.form.fileUpload ? this.success : undefined
5645 Roo.form.Action.Submit = function(form, options){
5646 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5649 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5652 haveProgress : false,
5653 uploadComplete : false,
5655 // uploadProgress indicator.
5656 uploadProgress : function()
5658 if (!this.form.progressUrl) {
5662 if (!this.haveProgress) {
5663 Roo.MessageBox.progress("Uploading", "Uploading");
5665 if (this.uploadComplete) {
5666 Roo.MessageBox.hide();
5670 this.haveProgress = true;
5672 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5674 var c = new Roo.data.Connection();
5676 url : this.form.progressUrl,
5681 success : function(req){
5682 //console.log(data);
5686 rdata = Roo.decode(req.responseText)
5688 Roo.log("Invalid data from server..");
5692 if (!rdata || !rdata.success) {
5694 Roo.MessageBox.alert(Roo.encode(rdata));
5697 var data = rdata.data;
5699 if (this.uploadComplete) {
5700 Roo.MessageBox.hide();
5705 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5706 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5709 this.uploadProgress.defer(2000,this);
5712 failure: function(data) {
5713 Roo.log('progress url failed ');
5724 // run get Values on the form, so it syncs any secondary forms.
5725 this.form.getValues();
5727 var o = this.options;
5728 var method = this.getMethod();
5729 var isPost = method == 'POST';
5730 if(o.clientValidation === false || this.form.isValid()){
5732 if (this.form.progressUrl) {
5733 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5734 (new Date() * 1) + '' + Math.random());
5739 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5740 form:this.form.el.dom,
5741 url:this.getUrl(!isPost),
5743 params:isPost ? this.getParams() : null,
5744 isUpload: this.form.fileUpload
5747 this.uploadProgress();
5749 }else if (o.clientValidation !== false){ // client validation failed
5750 this.failureType = Roo.form.Action.CLIENT_INVALID;
5751 this.form.afterAction(this, false);
5755 success : function(response)
5757 this.uploadComplete= true;
5758 if (this.haveProgress) {
5759 Roo.MessageBox.hide();
5763 var result = this.processResponse(response);
5764 if(result === true || result.success){
5765 this.form.afterAction(this, true);
5769 this.form.markInvalid(result.errors);
5770 this.failureType = Roo.form.Action.SERVER_INVALID;
5772 this.form.afterAction(this, false);
5774 failure : function(response)
5776 this.uploadComplete= true;
5777 if (this.haveProgress) {
5778 Roo.MessageBox.hide();
5781 this.response = response;
5782 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5783 this.form.afterAction(this, false);
5786 handleResponse : function(response){
5787 if(this.form.errorReader){
5788 var rs = this.form.errorReader.read(response);
5791 for(var i = 0, len = rs.records.length; i < len; i++) {
5792 var r = rs.records[i];
5796 if(errors.length < 1){
5800 success : rs.success,
5806 ret = Roo.decode(response.responseText);
5810 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5820 Roo.form.Action.Load = function(form, options){
5821 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5822 this.reader = this.form.reader;
5825 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5830 Roo.Ajax.request(Roo.apply(
5831 this.createCallback(), {
5832 method:this.getMethod(),
5833 url:this.getUrl(false),
5834 params:this.getParams()
5838 success : function(response){
5840 var result = this.processResponse(response);
5841 if(result === true || !result.success || !result.data){
5842 this.failureType = Roo.form.Action.LOAD_FAILURE;
5843 this.form.afterAction(this, false);
5846 this.form.clearInvalid();
5847 this.form.setValues(result.data);
5848 this.form.afterAction(this, true);
5851 handleResponse : function(response){
5852 if(this.form.reader){
5853 var rs = this.form.reader.read(response);
5854 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5856 success : rs.success,
5860 return Roo.decode(response.responseText);
5864 Roo.form.Action.ACTION_TYPES = {
5865 'load' : Roo.form.Action.Load,
5866 'submit' : Roo.form.Action.Submit
5875 * @class Roo.bootstrap.Form
5876 * @extends Roo.bootstrap.Component
5877 * Bootstrap Form class
5878 * @cfg {String} method GET | POST (default POST)
5879 * @cfg {String} labelAlign top | left (default top)
5880 * @cfg {String} align left | right - for navbars
5885 * @param {Object} config The config object
5889 Roo.bootstrap.Form = function(config){
5890 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5893 * @event clientvalidation
5894 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5895 * @param {Form} this
5896 * @param {Boolean} valid true if the form has passed client-side validation
5898 clientvalidation: true,
5900 * @event beforeaction
5901 * Fires before any action is performed. Return false to cancel the action.
5902 * @param {Form} this
5903 * @param {Action} action The action to be performed
5907 * @event actionfailed
5908 * Fires when an action fails.
5909 * @param {Form} this
5910 * @param {Action} action The action that failed
5912 actionfailed : true,
5914 * @event actioncomplete
5915 * Fires when an action is completed.
5916 * @param {Form} this
5917 * @param {Action} action The action that completed
5919 actioncomplete : true
5924 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5927 * @cfg {String} method
5928 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5933 * The URL to use for form actions if one isn't supplied in the action options.
5936 * @cfg {Boolean} fileUpload
5937 * Set to true if this form is a file upload.
5941 * @cfg {Object} baseParams
5942 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5946 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5950 * @cfg {Sting} align (left|right) for navbar forms
5955 activeAction : null,
5958 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5959 * element by passing it or its id or mask the form itself by passing in true.
5962 waitMsgTarget : false,
5967 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5968 * element by passing it or its id or mask the form itself by passing in true.
5972 getAutoCreate : function(){
5976 method : this.method || 'POST',
5977 id : this.id || Roo.id(),
5980 if (this.parent().xtype.match(/^Nav/)) {
5981 cfg.cls = 'navbar-form navbar-' + this.align;
5985 if (this.labelAlign == 'left' ) {
5986 cfg.cls += ' form-horizontal';
5992 initEvents : function()
5994 this.el.on('submit', this.onSubmit, this);
5995 // this was added as random key presses on the form where triggering form submit.
5996 this.el.on('keypress', function(e) {
5997 if (e.getCharCode() != 13) {
6000 // we might need to allow it for textareas.. and some other items.
6001 // check e.getTarget().
6003 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6007 Roo.log("keypress blocked");
6015 onSubmit : function(e){
6020 * Returns true if client-side validation on the form is successful.
6023 isValid : function(){
6024 var items = this.getItems();
6026 items.each(function(f){
6035 * Returns true if any fields in this form have changed since their original load.
6038 isDirty : function(){
6040 var items = this.getItems();
6041 items.each(function(f){
6051 * Performs a predefined action (submit or load) or custom actions you define on this form.
6052 * @param {String} actionName The name of the action type
6053 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6054 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6055 * accept other config options):
6057 Property Type Description
6058 ---------------- --------------- ----------------------------------------------------------------------------------
6059 url String The url for the action (defaults to the form's url)
6060 method String The form method to use (defaults to the form's method, or POST if not defined)
6061 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6062 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6063 validate the form on the client (defaults to false)
6065 * @return {BasicForm} this
6067 doAction : function(action, options){
6068 if(typeof action == 'string'){
6069 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6071 if(this.fireEvent('beforeaction', this, action) !== false){
6072 this.beforeAction(action);
6073 action.run.defer(100, action);
6079 beforeAction : function(action){
6080 var o = action.options;
6082 // not really supported yet.. ??
6084 //if(this.waitMsgTarget === true){
6085 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6086 //}else if(this.waitMsgTarget){
6087 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6088 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6090 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6096 afterAction : function(action, success){
6097 this.activeAction = null;
6098 var o = action.options;
6100 //if(this.waitMsgTarget === true){
6102 //}else if(this.waitMsgTarget){
6103 // this.waitMsgTarget.unmask();
6105 // Roo.MessageBox.updateProgress(1);
6106 // Roo.MessageBox.hide();
6113 Roo.callback(o.success, o.scope, [this, action]);
6114 this.fireEvent('actioncomplete', this, action);
6118 // failure condition..
6119 // we have a scenario where updates need confirming.
6120 // eg. if a locking scenario exists..
6121 // we look for { errors : { needs_confirm : true }} in the response.
6123 (typeof(action.result) != 'undefined') &&
6124 (typeof(action.result.errors) != 'undefined') &&
6125 (typeof(action.result.errors.needs_confirm) != 'undefined')
6128 Roo.log("not supported yet");
6131 Roo.MessageBox.confirm(
6132 "Change requires confirmation",
6133 action.result.errorMsg,
6138 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6148 Roo.callback(o.failure, o.scope, [this, action]);
6149 // show an error message if no failed handler is set..
6150 if (!this.hasListener('actionfailed')) {
6151 Roo.log("need to add dialog support");
6153 Roo.MessageBox.alert("Error",
6154 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6155 action.result.errorMsg :
6156 "Saving Failed, please check your entries or try again"
6161 this.fireEvent('actionfailed', this, action);
6166 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6167 * @param {String} id The value to search for
6170 findField : function(id){
6171 var items = this.getItems();
6172 var field = items.get(id);
6174 items.each(function(f){
6175 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6182 return field || null;
6185 * Mark fields in this form invalid in bulk.
6186 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6187 * @return {BasicForm} this
6189 markInvalid : function(errors){
6190 if(errors instanceof Array){
6191 for(var i = 0, len = errors.length; i < len; i++){
6192 var fieldError = errors[i];
6193 var f = this.findField(fieldError.id);
6195 f.markInvalid(fieldError.msg);
6201 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6202 field.markInvalid(errors[id]);
6206 //Roo.each(this.childForms || [], function (f) {
6207 // f.markInvalid(errors);
6214 * Set values for fields in this form in bulk.
6215 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6216 * @return {BasicForm} this
6218 setValues : function(values){
6219 if(values instanceof Array){ // array of objects
6220 for(var i = 0, len = values.length; i < len; i++){
6222 var f = this.findField(v.id);
6224 f.setValue(v.value);
6225 if(this.trackResetOnLoad){
6226 f.originalValue = f.getValue();
6230 }else{ // object hash
6233 if(typeof values[id] != 'function' && (field = this.findField(id))){
6235 if (field.setFromData &&
6237 field.displayField &&
6238 // combos' with local stores can
6239 // be queried via setValue()
6240 // to set their value..
6241 (field.store && !field.store.isLocal)
6245 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6246 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6247 field.setFromData(sd);
6250 field.setValue(values[id]);
6254 if(this.trackResetOnLoad){
6255 field.originalValue = field.getValue();
6261 //Roo.each(this.childForms || [], function (f) {
6262 // f.setValues(values);
6269 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6270 * they are returned as an array.
6271 * @param {Boolean} asString
6274 getValues : function(asString){
6275 //if (this.childForms) {
6276 // copy values from the child forms
6277 // Roo.each(this.childForms, function (f) {
6278 // this.setValues(f.getValues());
6284 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6285 if(asString === true){
6288 return Roo.urlDecode(fs);
6292 * Returns the fields in this form as an object with key/value pairs.
6293 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6296 getFieldValues : function(with_hidden)
6298 var items = this.getItems();
6300 items.each(function(f){
6304 var v = f.getValue();
6305 if (f.inputType =='radio') {
6306 if (typeof(ret[f.getName()]) == 'undefined') {
6307 ret[f.getName()] = ''; // empty..
6310 if (!f.el.dom.checked) {
6318 // not sure if this supported any more..
6319 if ((typeof(v) == 'object') && f.getRawValue) {
6320 v = f.getRawValue() ; // dates..
6322 // combo boxes where name != hiddenName...
6323 if (f.name != f.getName()) {
6324 ret[f.name] = f.getRawValue();
6326 ret[f.getName()] = v;
6333 * Clears all invalid messages in this form.
6334 * @return {BasicForm} this
6336 clearInvalid : function(){
6337 var items = this.getItems();
6339 items.each(function(f){
6350 * @return {BasicForm} this
6353 var items = this.getItems();
6354 items.each(function(f){
6358 Roo.each(this.childForms || [], function (f) {
6365 getItems : function()
6367 var r=new Roo.util.MixedCollection(false, function(o){
6368 return o.id || (o.id = Roo.id());
6370 var iter = function(el) {
6377 Roo.each(el.items,function(e) {
6396 * Ext JS Library 1.1.1
6397 * Copyright(c) 2006-2007, Ext JS, LLC.
6399 * Originally Released Under LGPL - original licence link has changed is not relivant.
6402 * <script type="text/javascript">
6405 * @class Roo.form.VTypes
6406 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6409 Roo.form.VTypes = function(){
6410 // closure these in so they are only created once.
6411 var alpha = /^[a-zA-Z_]+$/;
6412 var alphanum = /^[a-zA-Z0-9_]+$/;
6413 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6414 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6416 // All these messages and functions are configurable
6419 * The function used to validate email addresses
6420 * @param {String} value The email address
6422 'email' : function(v){
6423 return email.test(v);
6426 * The error text to display when the email validation function returns false
6429 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6431 * The keystroke filter mask to be applied on email input
6434 'emailMask' : /[a-z0-9_\.\-@]/i,
6437 * The function used to validate URLs
6438 * @param {String} value The URL
6440 'url' : function(v){
6444 * The error text to display when the url validation function returns false
6447 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6450 * The function used to validate alpha values
6451 * @param {String} value The value
6453 'alpha' : function(v){
6454 return alpha.test(v);
6457 * The error text to display when the alpha validation function returns false
6460 'alphaText' : 'This field should only contain letters and _',
6462 * The keystroke filter mask to be applied on alpha input
6465 'alphaMask' : /[a-z_]/i,
6468 * The function used to validate alphanumeric values
6469 * @param {String} value The value
6471 'alphanum' : function(v){
6472 return alphanum.test(v);
6475 * The error text to display when the alphanumeric validation function returns false
6478 'alphanumText' : 'This field should only contain letters, numbers and _',
6480 * The keystroke filter mask to be applied on alphanumeric input
6483 'alphanumMask' : /[a-z0-9_]/i
6493 * @class Roo.bootstrap.Input
6494 * @extends Roo.bootstrap.Component
6495 * Bootstrap Input class
6496 * @cfg {Boolean} disabled is it disabled
6497 * @cfg {String} fieldLabel - the label associated
6498 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6499 * @cfg {String} name name of the input
6500 * @cfg {string} fieldLabel - the label associated
6501 * @cfg {string} inputType - input / file submit ...
6502 * @cfg {string} placeholder - placeholder to put in text.
6503 * @cfg {string} before - input group add on before
6504 * @cfg {string} after - input group add on after
6505 * @cfg {string} size - (lg|sm) or leave empty..
6506 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6507 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6508 * @cfg {Number} md colspan out of 12 for computer-sized screens
6509 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6510 * @cfg {string} value default value of the input
6511 * @cfg {Number} labelWidth set the width of label (0-12)
6512 * @cfg {String} labelAlign (top|left)
6513 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6514 * @cfg {String} align (left|center|right) Default left
6518 * Create a new Input
6519 * @param {Object} config The config object
6522 Roo.bootstrap.Input = function(config){
6523 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6528 * Fires when this field receives input focus.
6529 * @param {Roo.form.Field} this
6534 * Fires when this field loses input focus.
6535 * @param {Roo.form.Field} this
6540 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6541 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6542 * @param {Roo.form.Field} this
6543 * @param {Roo.EventObject} e The event object
6548 * Fires just before the field blurs if the field value has changed.
6549 * @param {Roo.form.Field} this
6550 * @param {Mixed} newValue The new value
6551 * @param {Mixed} oldValue The original value
6556 * Fires after the field has been marked as invalid.
6557 * @param {Roo.form.Field} this
6558 * @param {String} msg The validation message
6563 * Fires after the field has been validated with no errors.
6564 * @param {Roo.form.Field} this
6569 * Fires after the key up
6570 * @param {Roo.form.Field} this
6571 * @param {Roo.EventObject} e The event Object
6577 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6579 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6580 automatic validation (defaults to "keyup").
6582 validationEvent : "keyup",
6584 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6586 validateOnBlur : true,
6588 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6590 validationDelay : 250,
6592 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6594 focusClass : "x-form-focus", // not needed???
6598 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6600 invalidClass : "has-error",
6603 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6605 selectOnFocus : false,
6608 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6612 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6617 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6619 disableKeyFilter : false,
6622 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6626 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6630 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6632 blankText : "This field is required",
6635 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6639 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6641 maxLength : Number.MAX_VALUE,
6643 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6645 minLengthText : "The minimum length for this field is {0}",
6647 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6649 maxLengthText : "The maximum length for this field is {0}",
6653 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6654 * If available, this function will be called only after the basic validators all return true, and will be passed the
6655 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6659 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6660 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6661 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6665 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6688 formatedValue : false,
6690 parentLabelAlign : function()
6693 while (parent.parent()) {
6694 parent = parent.parent();
6695 if (typeof(parent.labelAlign) !='undefined') {
6696 return parent.labelAlign;
6703 getAutoCreate : function(){
6705 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6711 if(this.inputType != 'hidden'){
6712 cfg.cls = 'form-group' //input-group
6718 type : this.inputType,
6720 cls : 'form-control',
6721 placeholder : this.placeholder || ''
6726 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6729 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6730 input.maxLength = this.maxLength;
6733 if (this.disabled) {
6734 input.disabled=true;
6737 if (this.readOnly) {
6738 input.readonly=true;
6742 input.name = this.name;
6745 input.cls += ' input-' + this.size;
6748 ['xs','sm','md','lg'].map(function(size){
6749 if (settings[size]) {
6750 cfg.cls += ' col-' + size + '-' + settings[size];
6754 var inputblock = input;
6756 if (this.before || this.after) {
6759 cls : 'input-group',
6762 if (this.before && typeof(this.before) == 'string') {
6764 inputblock.cn.push({
6766 cls : 'roo-input-before input-group-addon',
6770 if (this.before && typeof(this.before) == 'object') {
6771 this.before = Roo.factory(this.before);
6772 Roo.log(this.before);
6773 inputblock.cn.push({
6775 cls : 'roo-input-before input-group-' +
6776 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6780 inputblock.cn.push(input);
6782 if (this.after && typeof(this.after) == 'string') {
6783 inputblock.cn.push({
6785 cls : 'roo-input-after input-group-addon',
6789 if (this.after && typeof(this.after) == 'object') {
6790 this.after = Roo.factory(this.after);
6791 Roo.log(this.after);
6792 inputblock.cn.push({
6794 cls : 'roo-input-after input-group-' +
6795 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6800 if (align ==='left' && this.fieldLabel.length) {
6801 Roo.log("left and has label");
6807 cls : 'control-label col-sm-' + this.labelWidth,
6808 html : this.fieldLabel
6812 cls : "col-sm-" + (12 - this.labelWidth),
6819 } else if ( this.fieldLabel.length) {
6825 //cls : 'input-group-addon',
6826 html : this.fieldLabel
6836 Roo.log(" no label && no align");
6845 Roo.log('input-parentType: ' + this.parentType);
6847 if (this.parentType === 'Navbar' && this.parent().bar) {
6848 cfg.cls += ' navbar-form';
6856 * return the real input element.
6858 inputEl: function ()
6860 return this.el.select('input.form-control',true).first();
6862 setDisabled : function(v)
6864 var i = this.inputEl().dom;
6866 i.removeAttribute('disabled');
6870 i.setAttribute('disabled','true');
6872 initEvents : function()
6875 this.inputEl().on("keydown" , this.fireKey, this);
6876 this.inputEl().on("focus", this.onFocus, this);
6877 this.inputEl().on("blur", this.onBlur, this);
6879 this.inputEl().relayEvent('keyup', this);
6881 // reference to original value for reset
6882 this.originalValue = this.getValue();
6883 //Roo.form.TextField.superclass.initEvents.call(this);
6884 if(this.validationEvent == 'keyup'){
6885 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6886 this.inputEl().on('keyup', this.filterValidation, this);
6888 else if(this.validationEvent !== false){
6889 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6892 if(this.selectOnFocus){
6893 this.on("focus", this.preFocus, this);
6896 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6897 this.inputEl().on("keypress", this.filterKeys, this);
6900 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6901 this.el.on("click", this.autoSize, this);
6904 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6905 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6908 if (typeof(this.before) == 'object') {
6909 this.before.render(this.el.select('.roo-input-before',true).first());
6911 if (typeof(this.after) == 'object') {
6912 this.after.render(this.el.select('.roo-input-after',true).first());
6917 filterValidation : function(e){
6918 if(!e.isNavKeyPress()){
6919 this.validationTask.delay(this.validationDelay);
6923 * Validates the field value
6924 * @return {Boolean} True if the value is valid, else false
6926 validate : function(){
6927 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6928 if(this.disabled || this.validateValue(this.getRawValue())){
6929 this.clearInvalid();
6937 * Validates a value according to the field's validation rules and marks the field as invalid
6938 * if the validation fails
6939 * @param {Mixed} value The value to validate
6940 * @return {Boolean} True if the value is valid, else false
6942 validateValue : function(value){
6943 if(value.length < 1) { // if it's blank
6944 if(this.allowBlank){
6945 this.clearInvalid();
6948 this.markInvalid(this.blankText);
6952 if(value.length < this.minLength){
6953 this.markInvalid(String.format(this.minLengthText, this.minLength));
6956 if(value.length > this.maxLength){
6957 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6961 var vt = Roo.form.VTypes;
6962 if(!vt[this.vtype](value, this)){
6963 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6967 if(typeof this.validator == "function"){
6968 var msg = this.validator(value);
6970 this.markInvalid(msg);
6974 if(this.regex && !this.regex.test(value)){
6975 this.markInvalid(this.regexText);
6984 fireKey : function(e){
6985 //Roo.log('field ' + e.getKey());
6986 if(e.isNavKeyPress()){
6987 this.fireEvent("specialkey", this, e);
6990 focus : function (selectText){
6992 this.inputEl().focus();
6993 if(selectText === true){
6994 this.inputEl().dom.select();
7000 onFocus : function(){
7001 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7002 // this.el.addClass(this.focusClass);
7005 this.hasFocus = true;
7006 this.startValue = this.getValue();
7007 this.fireEvent("focus", this);
7011 beforeBlur : Roo.emptyFn,
7015 onBlur : function(){
7017 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7018 //this.el.removeClass(this.focusClass);
7020 this.hasFocus = false;
7021 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7024 var v = this.getValue();
7025 if(String(v) !== String(this.startValue)){
7026 this.fireEvent('change', this, v, this.startValue);
7028 this.fireEvent("blur", this);
7032 * Resets the current field value to the originally loaded value and clears any validation messages
7035 this.setValue(this.originalValue);
7036 this.clearInvalid();
7039 * Returns the name of the field
7040 * @return {Mixed} name The name field
7042 getName: function(){
7046 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7047 * @return {Mixed} value The field value
7049 getValue : function(){
7051 var v = this.inputEl().getValue();
7056 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7057 * @return {Mixed} value The field value
7059 getRawValue : function(){
7060 var v = this.inputEl().getValue();
7066 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7067 * @param {Mixed} value The value to set
7069 setRawValue : function(v){
7070 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7073 selectText : function(start, end){
7074 var v = this.getRawValue();
7076 start = start === undefined ? 0 : start;
7077 end = end === undefined ? v.length : end;
7078 var d = this.inputEl().dom;
7079 if(d.setSelectionRange){
7080 d.setSelectionRange(start, end);
7081 }else if(d.createTextRange){
7082 var range = d.createTextRange();
7083 range.moveStart("character", start);
7084 range.moveEnd("character", v.length-end);
7091 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7092 * @param {Mixed} value The value to set
7094 setValue : function(v){
7097 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7103 processValue : function(value){
7104 if(this.stripCharsRe){
7105 var newValue = value.replace(this.stripCharsRe, '');
7106 if(newValue !== value){
7107 this.setRawValue(newValue);
7114 preFocus : function(){
7116 if(this.selectOnFocus){
7117 this.inputEl().dom.select();
7120 filterKeys : function(e){
7122 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7125 var c = e.getCharCode(), cc = String.fromCharCode(c);
7126 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7129 if(!this.maskRe.test(cc)){
7134 * Clear any invalid styles/messages for this field
7136 clearInvalid : function(){
7138 if(!this.el || this.preventMark){ // not rendered
7141 this.el.removeClass(this.invalidClass);
7143 switch(this.msgTarget){
7145 this.el.dom.qtip = '';
7148 this.el.dom.title = '';
7152 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7157 this.errorIcon.dom.qtip = '';
7158 this.errorIcon.hide();
7159 this.un('resize', this.alignErrorIcon, this);
7163 var t = Roo.getDom(this.msgTarget);
7165 t.style.display = 'none';
7169 this.fireEvent('valid', this);
7172 * Mark this field as invalid
7173 * @param {String} msg The validation message
7175 markInvalid : function(msg){
7176 if(!this.el || this.preventMark){ // not rendered
7179 this.el.addClass(this.invalidClass);
7181 msg = msg || this.invalidText;
7182 switch(this.msgTarget){
7184 this.el.dom.qtip = msg;
7185 this.el.dom.qclass = 'x-form-invalid-tip';
7186 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7187 Roo.QuickTips.enable();
7191 this.el.dom.title = msg;
7195 var elp = this.el.findParent('.x-form-element', 5, true);
7196 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7197 this.errorEl.setWidth(elp.getWidth(true)-20);
7199 this.errorEl.update(msg);
7200 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7203 if(!this.errorIcon){
7204 var elp = this.el.findParent('.x-form-element', 5, true);
7205 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7207 this.alignErrorIcon();
7208 this.errorIcon.dom.qtip = msg;
7209 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7210 this.errorIcon.show();
7211 this.on('resize', this.alignErrorIcon, this);
7214 var t = Roo.getDom(this.msgTarget);
7216 t.style.display = this.msgDisplay;
7220 this.fireEvent('invalid', this, msg);
7223 SafariOnKeyDown : function(event)
7225 // this is a workaround for a password hang bug on chrome/ webkit.
7227 var isSelectAll = false;
7229 if(this.inputEl().dom.selectionEnd > 0){
7230 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7232 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7233 event.preventDefault();
7238 if(isSelectAll){ // backspace and delete key
7240 event.preventDefault();
7241 // this is very hacky as keydown always get's upper case.
7243 var cc = String.fromCharCode(event.getCharCode());
7244 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7248 adjustWidth : function(tag, w){
7249 tag = tag.toLowerCase();
7250 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7251 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7255 if(tag == 'textarea'){
7258 }else if(Roo.isOpera){
7262 if(tag == 'textarea'){
7281 * @class Roo.bootstrap.TextArea
7282 * @extends Roo.bootstrap.Input
7283 * Bootstrap TextArea class
7284 * @cfg {Number} cols Specifies the visible width of a text area
7285 * @cfg {Number} rows Specifies the visible number of lines in a text area
7286 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7287 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7288 * @cfg {string} html text
7291 * Create a new TextArea
7292 * @param {Object} config The config object
7295 Roo.bootstrap.TextArea = function(config){
7296 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7300 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7310 getAutoCreate : function(){
7312 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7323 value : this.value || '',
7324 html: this.html || '',
7325 cls : 'form-control',
7326 placeholder : this.placeholder || ''
7330 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7331 input.maxLength = this.maxLength;
7335 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7339 input.cols = this.cols;
7342 if (this.readOnly) {
7343 input.readonly = true;
7347 input.name = this.name;
7351 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7355 ['xs','sm','md','lg'].map(function(size){
7356 if (settings[size]) {
7357 cfg.cls += ' col-' + size + '-' + settings[size];
7361 var inputblock = input;
7363 if (this.before || this.after) {
7366 cls : 'input-group',
7370 inputblock.cn.push({
7372 cls : 'input-group-addon',
7376 inputblock.cn.push(input);
7378 inputblock.cn.push({
7380 cls : 'input-group-addon',
7387 if (align ==='left' && this.fieldLabel.length) {
7388 Roo.log("left and has label");
7394 cls : 'control-label col-sm-' + this.labelWidth,
7395 html : this.fieldLabel
7399 cls : "col-sm-" + (12 - this.labelWidth),
7406 } else if ( this.fieldLabel.length) {
7412 //cls : 'input-group-addon',
7413 html : this.fieldLabel
7423 Roo.log(" no label && no align");
7433 if (this.disabled) {
7434 input.disabled=true;
7441 * return the real textarea element.
7443 inputEl: function ()
7445 return this.el.select('textarea.form-control',true).first();
7453 * trigger field - base class for combo..
7458 * @class Roo.bootstrap.TriggerField
7459 * @extends Roo.bootstrap.Input
7460 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7461 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7462 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7463 * for which you can provide a custom implementation. For example:
7465 var trigger = new Roo.bootstrap.TriggerField();
7466 trigger.onTriggerClick = myTriggerFn;
7467 trigger.applyTo('my-field');
7470 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7471 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7472 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7473 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7475 * Create a new TriggerField.
7476 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7477 * to the base TextField)
7479 Roo.bootstrap.TriggerField = function(config){
7480 this.mimicing = false;
7481 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7484 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7486 * @cfg {String} triggerClass A CSS class to apply to the trigger
7489 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7493 /** @cfg {Boolean} grow @hide */
7494 /** @cfg {Number} growMin @hide */
7495 /** @cfg {Number} growMax @hide */
7501 autoSize: Roo.emptyFn,
7508 actionMode : 'wrap',
7512 getAutoCreate : function(){
7514 var parent = this.parent();
7516 var align = this.labelAlign || this.parentLabelAlign();
7521 cls: 'form-group' //input-group
7528 type : this.inputType,
7529 cls : 'form-control',
7530 autocomplete: 'off',
7531 placeholder : this.placeholder || ''
7535 input.name = this.name;
7538 input.cls += ' input-' + this.size;
7541 if (this.disabled) {
7542 input.disabled=true;
7545 var inputblock = input;
7547 if (this.before || this.after) {
7550 cls : 'input-group',
7554 inputblock.cn.push({
7556 cls : 'input-group-addon',
7560 inputblock.cn.push(input);
7562 inputblock.cn.push({
7564 cls : 'input-group-addon',
7577 cls: 'form-hidden-field'
7585 Roo.log('multiple');
7593 cls: 'form-hidden-field'
7597 cls: 'select2-choices',
7601 cls: 'select2-search-field',
7614 cls: 'select2-container input-group',
7619 cls: 'typeahead typeahead-long dropdown-menu',
7620 style: 'display:none'
7628 cls : 'input-group-addon btn dropdown-toggle',
7636 cls: 'combobox-clear',
7650 combobox.cls += ' select2-container-multi';
7653 if (align ==='left' && this.fieldLabel.length) {
7655 Roo.log("left and has label");
7661 cls : 'control-label col-sm-' + this.labelWidth,
7662 html : this.fieldLabel
7666 cls : "col-sm-" + (12 - this.labelWidth),
7673 } else if ( this.fieldLabel.length) {
7679 //cls : 'input-group-addon',
7680 html : this.fieldLabel
7690 Roo.log(" no label && no align");
7697 ['xs','sm','md','lg'].map(function(size){
7698 if (settings[size]) {
7699 cfg.cls += ' col-' + size + '-' + settings[size];
7710 onResize : function(w, h){
7711 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7712 // if(typeof w == 'number'){
7713 // var x = w - this.trigger.getWidth();
7714 // this.inputEl().setWidth(this.adjustWidth('input', x));
7715 // this.trigger.setStyle('left', x+'px');
7720 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7723 getResizeEl : function(){
7724 return this.inputEl();
7728 getPositionEl : function(){
7729 return this.inputEl();
7733 alignErrorIcon : function(){
7734 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7738 initEvents : function(){
7740 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7741 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7743 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7744 if(this.hideTrigger){
7745 this.trigger.setDisplayed(false);
7747 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7751 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7754 //this.trigger.addClassOnOver('x-form-trigger-over');
7755 //this.trigger.addClassOnClick('x-form-trigger-click');
7758 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7763 initTrigger : function(){
7768 onDestroy : function(){
7770 this.trigger.removeAllListeners();
7771 // this.trigger.remove();
7774 // this.wrap.remove();
7776 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7780 onFocus : function(){
7781 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7784 this.wrap.addClass('x-trigger-wrap-focus');
7785 this.mimicing = true;
7786 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7787 if(this.monitorTab){
7788 this.el.on("keydown", this.checkTab, this);
7795 checkTab : function(e){
7796 if(e.getKey() == e.TAB){
7802 onBlur : function(){
7807 mimicBlur : function(e, t){
7809 if(!this.wrap.contains(t) && this.validateBlur()){
7816 triggerBlur : function(){
7817 this.mimicing = false;
7818 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7819 if(this.monitorTab){
7820 this.el.un("keydown", this.checkTab, this);
7822 //this.wrap.removeClass('x-trigger-wrap-focus');
7823 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7827 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7828 validateBlur : function(e, t){
7833 onDisable : function(){
7834 this.inputEl().dom.disabled = true;
7835 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7837 // this.wrap.addClass('x-item-disabled');
7842 onEnable : function(){
7843 this.inputEl().dom.disabled = false;
7844 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7846 // this.el.removeClass('x-item-disabled');
7851 onShow : function(){
7852 var ae = this.getActionEl();
7855 ae.dom.style.display = '';
7856 ae.dom.style.visibility = 'visible';
7862 onHide : function(){
7863 var ae = this.getActionEl();
7864 ae.dom.style.display = 'none';
7868 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7869 * by an implementing function.
7871 * @param {EventObject} e
7873 onTriggerClick : Roo.emptyFn
7877 * Ext JS Library 1.1.1
7878 * Copyright(c) 2006-2007, Ext JS, LLC.
7880 * Originally Released Under LGPL - original licence link has changed is not relivant.
7883 * <script type="text/javascript">
7888 * @class Roo.data.SortTypes
7890 * Defines the default sorting (casting?) comparison functions used when sorting data.
7892 Roo.data.SortTypes = {
7894 * Default sort that does nothing
7895 * @param {Mixed} s The value being converted
7896 * @return {Mixed} The comparison value
7903 * The regular expression used to strip tags
7907 stripTagsRE : /<\/?[^>]+>/gi,
7910 * Strips all HTML tags to sort on text only
7911 * @param {Mixed} s The value being converted
7912 * @return {String} The comparison value
7914 asText : function(s){
7915 return String(s).replace(this.stripTagsRE, "");
7919 * Strips all HTML tags to sort on text only - Case insensitive
7920 * @param {Mixed} s The value being converted
7921 * @return {String} The comparison value
7923 asUCText : function(s){
7924 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7928 * Case insensitive string
7929 * @param {Mixed} s The value being converted
7930 * @return {String} The comparison value
7932 asUCString : function(s) {
7933 return String(s).toUpperCase();
7938 * @param {Mixed} s The value being converted
7939 * @return {Number} The comparison value
7941 asDate : function(s) {
7945 if(s instanceof Date){
7948 return Date.parse(String(s));
7953 * @param {Mixed} s The value being converted
7954 * @return {Float} The comparison value
7956 asFloat : function(s) {
7957 var val = parseFloat(String(s).replace(/,/g, ""));
7958 if(isNaN(val)) val = 0;
7964 * @param {Mixed} s The value being converted
7965 * @return {Number} The comparison value
7967 asInt : function(s) {
7968 var val = parseInt(String(s).replace(/,/g, ""));
7969 if(isNaN(val)) val = 0;
7974 * Ext JS Library 1.1.1
7975 * Copyright(c) 2006-2007, Ext JS, LLC.
7977 * Originally Released Under LGPL - original licence link has changed is not relivant.
7980 * <script type="text/javascript">
7984 * @class Roo.data.Record
7985 * Instances of this class encapsulate both record <em>definition</em> information, and record
7986 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7987 * to access Records cached in an {@link Roo.data.Store} object.<br>
7989 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7990 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7993 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7995 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7996 * {@link #create}. The parameters are the same.
7997 * @param {Array} data An associative Array of data values keyed by the field name.
7998 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7999 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8000 * not specified an integer id is generated.
8002 Roo.data.Record = function(data, id){
8003 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8008 * Generate a constructor for a specific record layout.
8009 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8010 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8011 * Each field definition object may contain the following properties: <ul>
8012 * <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,
8013 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8014 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8015 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8016 * is being used, then this is a string containing the javascript expression to reference the data relative to
8017 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8018 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8019 * this may be omitted.</p></li>
8020 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8021 * <ul><li>auto (Default, implies no conversion)</li>
8026 * <li>date</li></ul></p></li>
8027 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8028 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8029 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8030 * by the Reader into an object that will be stored in the Record. It is passed the
8031 * following parameters:<ul>
8032 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8034 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8036 * <br>usage:<br><pre><code>
8037 var TopicRecord = Roo.data.Record.create(
8038 {name: 'title', mapping: 'topic_title'},
8039 {name: 'author', mapping: 'username'},
8040 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8041 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8042 {name: 'lastPoster', mapping: 'user2'},
8043 {name: 'excerpt', mapping: 'post_text'}
8046 var myNewRecord = new TopicRecord({
8047 title: 'Do my job please',
8050 lastPost: new Date(),
8051 lastPoster: 'Animal',
8052 excerpt: 'No way dude!'
8054 myStore.add(myNewRecord);
8059 Roo.data.Record.create = function(o){
8061 f.superclass.constructor.apply(this, arguments);
8063 Roo.extend(f, Roo.data.Record);
8064 var p = f.prototype;
8065 p.fields = new Roo.util.MixedCollection(false, function(field){
8068 for(var i = 0, len = o.length; i < len; i++){
8069 p.fields.add(new Roo.data.Field(o[i]));
8071 f.getField = function(name){
8072 return p.fields.get(name);
8077 Roo.data.Record.AUTO_ID = 1000;
8078 Roo.data.Record.EDIT = 'edit';
8079 Roo.data.Record.REJECT = 'reject';
8080 Roo.data.Record.COMMIT = 'commit';
8082 Roo.data.Record.prototype = {
8084 * Readonly flag - true if this record has been modified.
8093 join : function(store){
8098 * Set the named field to the specified value.
8099 * @param {String} name The name of the field to set.
8100 * @param {Object} value The value to set the field to.
8102 set : function(name, value){
8103 if(this.data[name] == value){
8110 if(typeof this.modified[name] == 'undefined'){
8111 this.modified[name] = this.data[name];
8113 this.data[name] = value;
8114 if(!this.editing && this.store){
8115 this.store.afterEdit(this);
8120 * Get the value of the named field.
8121 * @param {String} name The name of the field to get the value of.
8122 * @return {Object} The value of the field.
8124 get : function(name){
8125 return this.data[name];
8129 beginEdit : function(){
8130 this.editing = true;
8135 cancelEdit : function(){
8136 this.editing = false;
8137 delete this.modified;
8141 endEdit : function(){
8142 this.editing = false;
8143 if(this.dirty && this.store){
8144 this.store.afterEdit(this);
8149 * Usually called by the {@link Roo.data.Store} which owns the Record.
8150 * Rejects all changes made to the Record since either creation, or the last commit operation.
8151 * Modified fields are reverted to their original values.
8153 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8154 * of reject operations.
8156 reject : function(){
8157 var m = this.modified;
8159 if(typeof m[n] != "function"){
8160 this.data[n] = m[n];
8164 delete this.modified;
8165 this.editing = false;
8167 this.store.afterReject(this);
8172 * Usually called by the {@link Roo.data.Store} which owns the Record.
8173 * Commits all changes made to the Record since either creation, or the last commit operation.
8175 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8176 * of commit operations.
8178 commit : function(){
8180 delete this.modified;
8181 this.editing = false;
8183 this.store.afterCommit(this);
8188 hasError : function(){
8189 return this.error != null;
8193 clearError : function(){
8198 * Creates a copy of this record.
8199 * @param {String} id (optional) A new record id if you don't want to use this record's id
8202 copy : function(newId) {
8203 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8207 * Ext JS Library 1.1.1
8208 * Copyright(c) 2006-2007, Ext JS, LLC.
8210 * Originally Released Under LGPL - original licence link has changed is not relivant.
8213 * <script type="text/javascript">
8219 * @class Roo.data.Store
8220 * @extends Roo.util.Observable
8221 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8222 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8224 * 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
8225 * has no knowledge of the format of the data returned by the Proxy.<br>
8227 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8228 * instances from the data object. These records are cached and made available through accessor functions.
8230 * Creates a new Store.
8231 * @param {Object} config A config object containing the objects needed for the Store to access data,
8232 * and read the data into Records.
8234 Roo.data.Store = function(config){
8235 this.data = new Roo.util.MixedCollection(false);
8236 this.data.getKey = function(o){
8239 this.baseParams = {};
8246 "multisort" : "_multisort"
8249 if(config && config.data){
8250 this.inlineData = config.data;
8254 Roo.apply(this, config);
8256 if(this.reader){ // reader passed
8257 this.reader = Roo.factory(this.reader, Roo.data);
8258 this.reader.xmodule = this.xmodule || false;
8259 if(!this.recordType){
8260 this.recordType = this.reader.recordType;
8262 if(this.reader.onMetaChange){
8263 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8267 if(this.recordType){
8268 this.fields = this.recordType.prototype.fields;
8274 * @event datachanged
8275 * Fires when the data cache has changed, and a widget which is using this Store
8276 * as a Record cache should refresh its view.
8277 * @param {Store} this
8282 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8283 * @param {Store} this
8284 * @param {Object} meta The JSON metadata
8289 * Fires when Records have been added to the Store
8290 * @param {Store} this
8291 * @param {Roo.data.Record[]} records The array of Records added
8292 * @param {Number} index The index at which the record(s) were added
8297 * Fires when a Record has been removed from the Store
8298 * @param {Store} this
8299 * @param {Roo.data.Record} record The Record that was removed
8300 * @param {Number} index The index at which the record was removed
8305 * Fires when a Record has been updated
8306 * @param {Store} this
8307 * @param {Roo.data.Record} record The Record that was updated
8308 * @param {String} operation The update operation being performed. Value may be one of:
8310 Roo.data.Record.EDIT
8311 Roo.data.Record.REJECT
8312 Roo.data.Record.COMMIT
8318 * Fires when the data cache has been cleared.
8319 * @param {Store} this
8324 * Fires before a request is made for a new data object. If the beforeload handler returns false
8325 * the load action will be canceled.
8326 * @param {Store} this
8327 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8331 * @event beforeloadadd
8332 * Fires after a new set of Records has been loaded.
8333 * @param {Store} this
8334 * @param {Roo.data.Record[]} records The Records that were loaded
8335 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8337 beforeloadadd : true,
8340 * Fires after a new set of Records has been loaded, before they are added to the store.
8341 * @param {Store} this
8342 * @param {Roo.data.Record[]} records The Records that were loaded
8343 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8344 * @params {Object} return from reader
8348 * @event loadexception
8349 * Fires if an exception occurs in the Proxy during loading.
8350 * Called with the signature of the Proxy's "loadexception" event.
8351 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8354 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8355 * @param {Object} load options
8356 * @param {Object} jsonData from your request (normally this contains the Exception)
8358 loadexception : true
8362 this.proxy = Roo.factory(this.proxy, Roo.data);
8363 this.proxy.xmodule = this.xmodule || false;
8364 this.relayEvents(this.proxy, ["loadexception"]);
8366 this.sortToggle = {};
8367 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8369 Roo.data.Store.superclass.constructor.call(this);
8371 if(this.inlineData){
8372 this.loadData(this.inlineData);
8373 delete this.inlineData;
8377 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8379 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8380 * without a remote query - used by combo/forms at present.
8384 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8387 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8390 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8391 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8394 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8395 * on any HTTP request
8398 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8401 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8405 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8406 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8411 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8412 * loaded or when a record is removed. (defaults to false).
8414 pruneModifiedRecords : false,
8420 * Add Records to the Store and fires the add event.
8421 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8423 add : function(records){
8424 records = [].concat(records);
8425 for(var i = 0, len = records.length; i < len; i++){
8426 records[i].join(this);
8428 var index = this.data.length;
8429 this.data.addAll(records);
8430 this.fireEvent("add", this, records, index);
8434 * Remove a Record from the Store and fires the remove event.
8435 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8437 remove : function(record){
8438 var index = this.data.indexOf(record);
8439 this.data.removeAt(index);
8440 if(this.pruneModifiedRecords){
8441 this.modified.remove(record);
8443 this.fireEvent("remove", this, record, index);
8447 * Remove all Records from the Store and fires the clear event.
8449 removeAll : function(){
8451 if(this.pruneModifiedRecords){
8454 this.fireEvent("clear", this);
8458 * Inserts Records to the Store at the given index and fires the add event.
8459 * @param {Number} index The start index at which to insert the passed Records.
8460 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8462 insert : function(index, records){
8463 records = [].concat(records);
8464 for(var i = 0, len = records.length; i < len; i++){
8465 this.data.insert(index, records[i]);
8466 records[i].join(this);
8468 this.fireEvent("add", this, records, index);
8472 * Get the index within the cache of the passed Record.
8473 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8474 * @return {Number} The index of the passed Record. Returns -1 if not found.
8476 indexOf : function(record){
8477 return this.data.indexOf(record);
8481 * Get the index within the cache of the Record with the passed id.
8482 * @param {String} id The id of the Record to find.
8483 * @return {Number} The index of the Record. Returns -1 if not found.
8485 indexOfId : function(id){
8486 return this.data.indexOfKey(id);
8490 * Get the Record with the specified id.
8491 * @param {String} id The id of the Record to find.
8492 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8494 getById : function(id){
8495 return this.data.key(id);
8499 * Get the Record at the specified index.
8500 * @param {Number} index The index of the Record to find.
8501 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8503 getAt : function(index){
8504 return this.data.itemAt(index);
8508 * Returns a range of Records between specified indices.
8509 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8510 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8511 * @return {Roo.data.Record[]} An array of Records
8513 getRange : function(start, end){
8514 return this.data.getRange(start, end);
8518 storeOptions : function(o){
8519 o = Roo.apply({}, o);
8522 this.lastOptions = o;
8526 * Loads the Record cache from the configured Proxy using the configured Reader.
8528 * If using remote paging, then the first load call must specify the <em>start</em>
8529 * and <em>limit</em> properties in the options.params property to establish the initial
8530 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8532 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8533 * and this call will return before the new data has been loaded. Perform any post-processing
8534 * in a callback function, or in a "load" event handler.</strong>
8536 * @param {Object} options An object containing properties which control loading options:<ul>
8537 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8538 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8539 * passed the following arguments:<ul>
8540 * <li>r : Roo.data.Record[]</li>
8541 * <li>options: Options object from the load call</li>
8542 * <li>success: Boolean success indicator</li></ul></li>
8543 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8544 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8547 load : function(options){
8548 options = options || {};
8549 if(this.fireEvent("beforeload", this, options) !== false){
8550 this.storeOptions(options);
8551 var p = Roo.apply(options.params || {}, this.baseParams);
8552 // if meta was not loaded from remote source.. try requesting it.
8553 if (!this.reader.metaFromRemote) {
8556 if(this.sortInfo && this.remoteSort){
8557 var pn = this.paramNames;
8558 p[pn["sort"]] = this.sortInfo.field;
8559 p[pn["dir"]] = this.sortInfo.direction;
8561 if (this.multiSort) {
8562 var pn = this.paramNames;
8563 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8566 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8571 * Reloads the Record cache from the configured Proxy using the configured Reader and
8572 * the options from the last load operation performed.
8573 * @param {Object} options (optional) An object containing properties which may override the options
8574 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8575 * the most recently used options are reused).
8577 reload : function(options){
8578 this.load(Roo.applyIf(options||{}, this.lastOptions));
8582 // Called as a callback by the Reader during a load operation.
8583 loadRecords : function(o, options, success){
8584 if(!o || success === false){
8585 if(success !== false){
8586 this.fireEvent("load", this, [], options, o);
8588 if(options.callback){
8589 options.callback.call(options.scope || this, [], options, false);
8593 // if data returned failure - throw an exception.
8594 if (o.success === false) {
8595 // show a message if no listener is registered.
8596 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8597 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8599 // loadmask wil be hooked into this..
8600 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8603 var r = o.records, t = o.totalRecords || r.length;
8605 this.fireEvent("beforeloadadd", this, r, options, o);
8607 if(!options || options.add !== true){
8608 if(this.pruneModifiedRecords){
8611 for(var i = 0, len = r.length; i < len; i++){
8615 this.data = this.snapshot;
8616 delete this.snapshot;
8619 this.data.addAll(r);
8620 this.totalLength = t;
8622 this.fireEvent("datachanged", this);
8624 this.totalLength = Math.max(t, this.data.length+r.length);
8627 this.fireEvent("load", this, r, options, o);
8628 if(options.callback){
8629 options.callback.call(options.scope || this, r, options, true);
8635 * Loads data from a passed data block. A Reader which understands the format of the data
8636 * must have been configured in the constructor.
8637 * @param {Object} data The data block from which to read the Records. The format of the data expected
8638 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8639 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8641 loadData : function(o, append){
8642 var r = this.reader.readRecords(o);
8643 this.loadRecords(r, {add: append}, true);
8647 * Gets the number of cached records.
8649 * <em>If using paging, this may not be the total size of the dataset. If the data object
8650 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8651 * the data set size</em>
8653 getCount : function(){
8654 return this.data.length || 0;
8658 * Gets the total number of records in the dataset as returned by the server.
8660 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8661 * the dataset size</em>
8663 getTotalCount : function(){
8664 return this.totalLength || 0;
8668 * Returns the sort state of the Store as an object with two properties:
8670 field {String} The name of the field by which the Records are sorted
8671 direction {String} The sort order, "ASC" or "DESC"
8674 getSortState : function(){
8675 return this.sortInfo;
8679 applySort : function(){
8680 if(this.sortInfo && !this.remoteSort){
8681 var s = this.sortInfo, f = s.field;
8682 var st = this.fields.get(f).sortType;
8683 var fn = function(r1, r2){
8684 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8685 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8687 this.data.sort(s.direction, fn);
8688 if(this.snapshot && this.snapshot != this.data){
8689 this.snapshot.sort(s.direction, fn);
8695 * Sets the default sort column and order to be used by the next load operation.
8696 * @param {String} fieldName The name of the field to sort by.
8697 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8699 setDefaultSort : function(field, dir){
8700 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8705 * If remote sorting is used, the sort is performed on the server, and the cache is
8706 * reloaded. If local sorting is used, the cache is sorted internally.
8707 * @param {String} fieldName The name of the field to sort by.
8708 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8710 sort : function(fieldName, dir){
8711 var f = this.fields.get(fieldName);
8713 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8715 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8716 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8721 this.sortToggle[f.name] = dir;
8722 this.sortInfo = {field: f.name, direction: dir};
8723 if(!this.remoteSort){
8725 this.fireEvent("datachanged", this);
8727 this.load(this.lastOptions);
8732 * Calls the specified function for each of the Records in the cache.
8733 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8734 * Returning <em>false</em> aborts and exits the iteration.
8735 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8737 each : function(fn, scope){
8738 this.data.each(fn, scope);
8742 * Gets all records modified since the last commit. Modified records are persisted across load operations
8743 * (e.g., during paging).
8744 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8746 getModifiedRecords : function(){
8747 return this.modified;
8751 createFilterFn : function(property, value, anyMatch){
8752 if(!value.exec){ // not a regex
8753 value = String(value);
8754 if(value.length == 0){
8757 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8760 return value.test(r.data[property]);
8765 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8766 * @param {String} property A field on your records
8767 * @param {Number} start The record index to start at (defaults to 0)
8768 * @param {Number} end The last record index to include (defaults to length - 1)
8769 * @return {Number} The sum
8771 sum : function(property, start, end){
8772 var rs = this.data.items, v = 0;
8774 end = (end || end === 0) ? end : rs.length-1;
8776 for(var i = start; i <= end; i++){
8777 v += (rs[i].data[property] || 0);
8783 * Filter the records by a specified property.
8784 * @param {String} field A field on your records
8785 * @param {String/RegExp} value Either a string that the field
8786 * should start with or a RegExp to test against the field
8787 * @param {Boolean} anyMatch True to match any part not just the beginning
8789 filter : function(property, value, anyMatch){
8790 var fn = this.createFilterFn(property, value, anyMatch);
8791 return fn ? this.filterBy(fn) : this.clearFilter();
8795 * Filter by a function. The specified function will be called with each
8796 * record in this data source. If the function returns true the record is included,
8797 * otherwise it is filtered.
8798 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8799 * @param {Object} scope (optional) The scope of the function (defaults to this)
8801 filterBy : function(fn, scope){
8802 this.snapshot = this.snapshot || this.data;
8803 this.data = this.queryBy(fn, scope||this);
8804 this.fireEvent("datachanged", this);
8808 * Query the records by a specified property.
8809 * @param {String} field A field on your records
8810 * @param {String/RegExp} value Either a string that the field
8811 * should start with or a RegExp to test against the field
8812 * @param {Boolean} anyMatch True to match any part not just the beginning
8813 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8815 query : function(property, value, anyMatch){
8816 var fn = this.createFilterFn(property, value, anyMatch);
8817 return fn ? this.queryBy(fn) : this.data.clone();
8821 * Query by a function. The specified function will be called with each
8822 * record in this data source. If the function returns true the record is included
8824 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8825 * @param {Object} scope (optional) The scope of the function (defaults to this)
8826 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8828 queryBy : function(fn, scope){
8829 var data = this.snapshot || this.data;
8830 return data.filterBy(fn, scope||this);
8834 * Collects unique values for a particular dataIndex from this store.
8835 * @param {String} dataIndex The property to collect
8836 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8837 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8838 * @return {Array} An array of the unique values
8840 collect : function(dataIndex, allowNull, bypassFilter){
8841 var d = (bypassFilter === true && this.snapshot) ?
8842 this.snapshot.items : this.data.items;
8843 var v, sv, r = [], l = {};
8844 for(var i = 0, len = d.length; i < len; i++){
8845 v = d[i].data[dataIndex];
8847 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8856 * Revert to a view of the Record cache with no filtering applied.
8857 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8859 clearFilter : function(suppressEvent){
8860 if(this.snapshot && this.snapshot != this.data){
8861 this.data = this.snapshot;
8862 delete this.snapshot;
8863 if(suppressEvent !== true){
8864 this.fireEvent("datachanged", this);
8870 afterEdit : function(record){
8871 if(this.modified.indexOf(record) == -1){
8872 this.modified.push(record);
8874 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8878 afterReject : function(record){
8879 this.modified.remove(record);
8880 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8884 afterCommit : function(record){
8885 this.modified.remove(record);
8886 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8890 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8891 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8893 commitChanges : function(){
8894 var m = this.modified.slice(0);
8896 for(var i = 0, len = m.length; i < len; i++){
8902 * Cancel outstanding changes on all changed records.
8904 rejectChanges : function(){
8905 var m = this.modified.slice(0);
8907 for(var i = 0, len = m.length; i < len; i++){
8912 onMetaChange : function(meta, rtype, o){
8913 this.recordType = rtype;
8914 this.fields = rtype.prototype.fields;
8915 delete this.snapshot;
8916 this.sortInfo = meta.sortInfo || this.sortInfo;
8918 this.fireEvent('metachange', this, this.reader.meta);
8921 moveIndex : function(data, type)
8923 var index = this.indexOf(data);
8925 var newIndex = index + type;
8929 this.insert(newIndex, data);
8934 * Ext JS Library 1.1.1
8935 * Copyright(c) 2006-2007, Ext JS, LLC.
8937 * Originally Released Under LGPL - original licence link has changed is not relivant.
8940 * <script type="text/javascript">
8944 * @class Roo.data.SimpleStore
8945 * @extends Roo.data.Store
8946 * Small helper class to make creating Stores from Array data easier.
8947 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8948 * @cfg {Array} fields An array of field definition objects, or field name strings.
8949 * @cfg {Array} data The multi-dimensional array of data
8951 * @param {Object} config
8953 Roo.data.SimpleStore = function(config){
8954 Roo.data.SimpleStore.superclass.constructor.call(this, {
8956 reader: new Roo.data.ArrayReader({
8959 Roo.data.Record.create(config.fields)
8961 proxy : new Roo.data.MemoryProxy(config.data)
8965 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8967 * Ext JS Library 1.1.1
8968 * Copyright(c) 2006-2007, Ext JS, LLC.
8970 * Originally Released Under LGPL - original licence link has changed is not relivant.
8973 * <script type="text/javascript">
8978 * @extends Roo.data.Store
8979 * @class Roo.data.JsonStore
8980 * Small helper class to make creating Stores for JSON data easier. <br/>
8982 var store = new Roo.data.JsonStore({
8983 url: 'get-images.php',
8985 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8988 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8989 * JsonReader and HttpProxy (unless inline data is provided).</b>
8990 * @cfg {Array} fields An array of field definition objects, or field name strings.
8992 * @param {Object} config
8994 Roo.data.JsonStore = function(c){
8995 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8996 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8997 reader: new Roo.data.JsonReader(c, c.fields)
9000 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9002 * Ext JS Library 1.1.1
9003 * Copyright(c) 2006-2007, Ext JS, LLC.
9005 * Originally Released Under LGPL - original licence link has changed is not relivant.
9008 * <script type="text/javascript">
9012 Roo.data.Field = function(config){
9013 if(typeof config == "string"){
9014 config = {name: config};
9016 Roo.apply(this, config);
9022 var st = Roo.data.SortTypes;
9023 // named sortTypes are supported, here we look them up
9024 if(typeof this.sortType == "string"){
9025 this.sortType = st[this.sortType];
9028 // set default sortType for strings and dates
9032 this.sortType = st.asUCString;
9035 this.sortType = st.asDate;
9038 this.sortType = st.none;
9043 var stripRe = /[\$,%]/g;
9045 // prebuilt conversion function for this field, instead of
9046 // switching every time we're reading a value
9048 var cv, dateFormat = this.dateFormat;
9053 cv = function(v){ return v; };
9056 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9060 return v !== undefined && v !== null && v !== '' ?
9061 parseInt(String(v).replace(stripRe, ""), 10) : '';
9066 return v !== undefined && v !== null && v !== '' ?
9067 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9072 cv = function(v){ return v === true || v === "true" || v == 1; };
9079 if(v instanceof Date){
9083 if(dateFormat == "timestamp"){
9084 return new Date(v*1000);
9086 return Date.parseDate(v, dateFormat);
9088 var parsed = Date.parse(v);
9089 return parsed ? new Date(parsed) : null;
9098 Roo.data.Field.prototype = {
9106 * Ext JS Library 1.1.1
9107 * Copyright(c) 2006-2007, Ext JS, LLC.
9109 * Originally Released Under LGPL - original licence link has changed is not relivant.
9112 * <script type="text/javascript">
9115 // Base class for reading structured data from a data source. This class is intended to be
9116 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9119 * @class Roo.data.DataReader
9120 * Base class for reading structured data from a data source. This class is intended to be
9121 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9124 Roo.data.DataReader = function(meta, recordType){
9128 this.recordType = recordType instanceof Array ?
9129 Roo.data.Record.create(recordType) : recordType;
9132 Roo.data.DataReader.prototype = {
9134 * Create an empty record
9135 * @param {Object} data (optional) - overlay some values
9136 * @return {Roo.data.Record} record created.
9138 newRow : function(d) {
9140 this.recordType.prototype.fields.each(function(c) {
9142 case 'int' : da[c.name] = 0; break;
9143 case 'date' : da[c.name] = new Date(); break;
9144 case 'float' : da[c.name] = 0.0; break;
9145 case 'boolean' : da[c.name] = false; break;
9146 default : da[c.name] = ""; break;
9150 return new this.recordType(Roo.apply(da, d));
9155 * Ext JS Library 1.1.1
9156 * Copyright(c) 2006-2007, Ext JS, LLC.
9158 * Originally Released Under LGPL - original licence link has changed is not relivant.
9161 * <script type="text/javascript">
9165 * @class Roo.data.DataProxy
9166 * @extends Roo.data.Observable
9167 * This class is an abstract base class for implementations which provide retrieval of
9168 * unformatted data objects.<br>
9170 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9171 * (of the appropriate type which knows how to parse the data object) to provide a block of
9172 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9174 * Custom implementations must implement the load method as described in
9175 * {@link Roo.data.HttpProxy#load}.
9177 Roo.data.DataProxy = function(){
9181 * Fires before a network request is made to retrieve a data object.
9182 * @param {Object} This DataProxy object.
9183 * @param {Object} params The params parameter to the load function.
9188 * Fires before the load method's callback is called.
9189 * @param {Object} This DataProxy object.
9190 * @param {Object} o The data object.
9191 * @param {Object} arg The callback argument object passed to the load function.
9195 * @event loadexception
9196 * Fires if an Exception occurs during data retrieval.
9197 * @param {Object} This DataProxy object.
9198 * @param {Object} o The data object.
9199 * @param {Object} arg The callback argument object passed to the load function.
9200 * @param {Object} e The Exception.
9202 loadexception : true
9204 Roo.data.DataProxy.superclass.constructor.call(this);
9207 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9210 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9214 * Ext JS Library 1.1.1
9215 * Copyright(c) 2006-2007, Ext JS, LLC.
9217 * Originally Released Under LGPL - original licence link has changed is not relivant.
9220 * <script type="text/javascript">
9223 * @class Roo.data.MemoryProxy
9224 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9225 * to the Reader when its load method is called.
9227 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9229 Roo.data.MemoryProxy = function(data){
9233 Roo.data.MemoryProxy.superclass.constructor.call(this);
9237 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9239 * Load data from the requested source (in this case an in-memory
9240 * data object passed to the constructor), read the data object into
9241 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9242 * process that block using the passed callback.
9243 * @param {Object} params This parameter is not used by the MemoryProxy class.
9244 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9245 * object into a block of Roo.data.Records.
9246 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9247 * The function must be passed <ul>
9248 * <li>The Record block object</li>
9249 * <li>The "arg" argument from the load function</li>
9250 * <li>A boolean success indicator</li>
9252 * @param {Object} scope The scope in which to call the callback
9253 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9255 load : function(params, reader, callback, scope, arg){
9256 params = params || {};
9259 result = reader.readRecords(this.data);
9261 this.fireEvent("loadexception", this, arg, null, e);
9262 callback.call(scope, null, arg, false);
9265 callback.call(scope, result, arg, true);
9269 update : function(params, records){
9274 * Ext JS Library 1.1.1
9275 * Copyright(c) 2006-2007, Ext JS, LLC.
9277 * Originally Released Under LGPL - original licence link has changed is not relivant.
9280 * <script type="text/javascript">
9283 * @class Roo.data.HttpProxy
9284 * @extends Roo.data.DataProxy
9285 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9286 * configured to reference a certain URL.<br><br>
9288 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9289 * from which the running page was served.<br><br>
9291 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9293 * Be aware that to enable the browser to parse an XML document, the server must set
9294 * the Content-Type header in the HTTP response to "text/xml".
9296 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9297 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9298 * will be used to make the request.
9300 Roo.data.HttpProxy = function(conn){
9301 Roo.data.HttpProxy.superclass.constructor.call(this);
9302 // is conn a conn config or a real conn?
9304 this.useAjax = !conn || !conn.events;
9308 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9309 // thse are take from connection...
9312 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9315 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9316 * extra parameters to each request made by this object. (defaults to undefined)
9319 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9320 * to each request made by this object. (defaults to undefined)
9323 * @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)
9326 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9329 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9335 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9339 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9340 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9341 * a finer-grained basis than the DataProxy events.
9343 getConnection : function(){
9344 return this.useAjax ? Roo.Ajax : this.conn;
9348 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9349 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9350 * process that block using the passed callback.
9351 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9352 * for the request to the remote server.
9353 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9354 * object into a block of Roo.data.Records.
9355 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9356 * The function must be passed <ul>
9357 * <li>The Record block object</li>
9358 * <li>The "arg" argument from the load function</li>
9359 * <li>A boolean success indicator</li>
9361 * @param {Object} scope The scope in which to call the callback
9362 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9364 load : function(params, reader, callback, scope, arg){
9365 if(this.fireEvent("beforeload", this, params) !== false){
9367 params : params || {},
9369 callback : callback,
9374 callback : this.loadResponse,
9378 Roo.applyIf(o, this.conn);
9379 if(this.activeRequest){
9380 Roo.Ajax.abort(this.activeRequest);
9382 this.activeRequest = Roo.Ajax.request(o);
9384 this.conn.request(o);
9387 callback.call(scope||this, null, arg, false);
9392 loadResponse : function(o, success, response){
9393 delete this.activeRequest;
9395 this.fireEvent("loadexception", this, o, response);
9396 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9401 result = o.reader.read(response);
9403 this.fireEvent("loadexception", this, o, response, e);
9404 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9408 this.fireEvent("load", this, o, o.request.arg);
9409 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9413 update : function(dataSet){
9418 updateResponse : function(dataSet){
9423 * Ext JS Library 1.1.1
9424 * Copyright(c) 2006-2007, Ext JS, LLC.
9426 * Originally Released Under LGPL - original licence link has changed is not relivant.
9429 * <script type="text/javascript">
9433 * @class Roo.data.ScriptTagProxy
9434 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9435 * other than the originating domain of the running page.<br><br>
9437 * <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
9438 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9440 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9441 * source code that is used as the source inside a <script> tag.<br><br>
9443 * In order for the browser to process the returned data, the server must wrap the data object
9444 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9445 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9446 * depending on whether the callback name was passed:
9449 boolean scriptTag = false;
9450 String cb = request.getParameter("callback");
9453 response.setContentType("text/javascript");
9455 response.setContentType("application/x-json");
9457 Writer out = response.getWriter();
9459 out.write(cb + "(");
9461 out.print(dataBlock.toJsonString());
9468 * @param {Object} config A configuration object.
9470 Roo.data.ScriptTagProxy = function(config){
9471 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9472 Roo.apply(this, config);
9473 this.head = document.getElementsByTagName("head")[0];
9476 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9478 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9480 * @cfg {String} url The URL from which to request the data object.
9483 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9487 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9488 * the server the name of the callback function set up by the load call to process the returned data object.
9489 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9490 * javascript output which calls this named function passing the data object as its only parameter.
9492 callbackParam : "callback",
9494 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9495 * name to the request.
9500 * Load data from the configured URL, read the data object into
9501 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9502 * process that block using the passed callback.
9503 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9504 * for the request to the remote server.
9505 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9506 * object into a block of Roo.data.Records.
9507 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9508 * The function must be passed <ul>
9509 * <li>The Record block object</li>
9510 * <li>The "arg" argument from the load function</li>
9511 * <li>A boolean success indicator</li>
9513 * @param {Object} scope The scope in which to call the callback
9514 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9516 load : function(params, reader, callback, scope, arg){
9517 if(this.fireEvent("beforeload", this, params) !== false){
9519 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9522 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9524 url += "&_dc=" + (new Date().getTime());
9526 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9529 cb : "stcCallback"+transId,
9530 scriptId : "stcScript"+transId,
9534 callback : callback,
9540 window[trans.cb] = function(o){
9541 conn.handleResponse(o, trans);
9544 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9546 if(this.autoAbort !== false){
9550 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9552 var script = document.createElement("script");
9553 script.setAttribute("src", url);
9554 script.setAttribute("type", "text/javascript");
9555 script.setAttribute("id", trans.scriptId);
9556 this.head.appendChild(script);
9560 callback.call(scope||this, null, arg, false);
9565 isLoading : function(){
9566 return this.trans ? true : false;
9570 * Abort the current server request.
9573 if(this.isLoading()){
9574 this.destroyTrans(this.trans);
9579 destroyTrans : function(trans, isLoaded){
9580 this.head.removeChild(document.getElementById(trans.scriptId));
9581 clearTimeout(trans.timeoutId);
9583 window[trans.cb] = undefined;
9585 delete window[trans.cb];
9588 // if hasn't been loaded, wait for load to remove it to prevent script error
9589 window[trans.cb] = function(){
9590 window[trans.cb] = undefined;
9592 delete window[trans.cb];
9599 handleResponse : function(o, trans){
9601 this.destroyTrans(trans, true);
9604 result = trans.reader.readRecords(o);
9606 this.fireEvent("loadexception", this, o, trans.arg, e);
9607 trans.callback.call(trans.scope||window, null, trans.arg, false);
9610 this.fireEvent("load", this, o, trans.arg);
9611 trans.callback.call(trans.scope||window, result, trans.arg, true);
9615 handleFailure : function(trans){
9617 this.destroyTrans(trans, false);
9618 this.fireEvent("loadexception", this, null, trans.arg);
9619 trans.callback.call(trans.scope||window, null, trans.arg, false);
9623 * Ext JS Library 1.1.1
9624 * Copyright(c) 2006-2007, Ext JS, LLC.
9626 * Originally Released Under LGPL - original licence link has changed is not relivant.
9629 * <script type="text/javascript">
9633 * @class Roo.data.JsonReader
9634 * @extends Roo.data.DataReader
9635 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9636 * based on mappings in a provided Roo.data.Record constructor.
9638 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9639 * in the reply previously.
9644 var RecordDef = Roo.data.Record.create([
9645 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9646 {name: 'occupation'} // This field will use "occupation" as the mapping.
9648 var myReader = new Roo.data.JsonReader({
9649 totalProperty: "results", // The property which contains the total dataset size (optional)
9650 root: "rows", // The property which contains an Array of row objects
9651 id: "id" // The property within each row object that provides an ID for the record (optional)
9655 * This would consume a JSON file like this:
9657 { 'results': 2, 'rows': [
9658 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9659 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9662 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9663 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9664 * paged from the remote server.
9665 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9666 * @cfg {String} root name of the property which contains the Array of row objects.
9667 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9669 * Create a new JsonReader
9670 * @param {Object} meta Metadata configuration options
9671 * @param {Object} recordType Either an Array of field definition objects,
9672 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9674 Roo.data.JsonReader = function(meta, recordType){
9677 // set some defaults:
9679 totalProperty: 'total',
9680 successProperty : 'success',
9685 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9687 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9690 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9691 * Used by Store query builder to append _requestMeta to params.
9694 metaFromRemote : false,
9696 * This method is only used by a DataProxy which has retrieved data from a remote server.
9697 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9698 * @return {Object} data A data block which is used by an Roo.data.Store object as
9699 * a cache of Roo.data.Records.
9701 read : function(response){
9702 var json = response.responseText;
9704 var o = /* eval:var:o */ eval("("+json+")");
9706 throw {message: "JsonReader.read: Json object not found"};
9712 this.metaFromRemote = true;
9713 this.meta = o.metaData;
9714 this.recordType = Roo.data.Record.create(o.metaData.fields);
9715 this.onMetaChange(this.meta, this.recordType, o);
9717 return this.readRecords(o);
9720 // private function a store will implement
9721 onMetaChange : function(meta, recordType, o){
9728 simpleAccess: function(obj, subsc) {
9735 getJsonAccessor: function(){
9737 return function(expr) {
9739 return(re.test(expr))
9740 ? new Function("obj", "return obj." + expr)
9750 * Create a data block containing Roo.data.Records from an XML document.
9751 * @param {Object} o An object which contains an Array of row objects in the property specified
9752 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9753 * which contains the total size of the dataset.
9754 * @return {Object} data A data block which is used by an Roo.data.Store object as
9755 * a cache of Roo.data.Records.
9757 readRecords : function(o){
9759 * After any data loads, the raw JSON data is available for further custom processing.
9763 var s = this.meta, Record = this.recordType,
9764 f = Record.prototype.fields, fi = f.items, fl = f.length;
9766 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9768 if(s.totalProperty) {
9769 this.getTotal = this.getJsonAccessor(s.totalProperty);
9771 if(s.successProperty) {
9772 this.getSuccess = this.getJsonAccessor(s.successProperty);
9774 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9776 var g = this.getJsonAccessor(s.id);
9777 this.getId = function(rec) {
9779 return (r === undefined || r === "") ? null : r;
9782 this.getId = function(){return null;};
9785 for(var jj = 0; jj < fl; jj++){
9787 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9788 this.ef[jj] = this.getJsonAccessor(map);
9792 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9793 if(s.totalProperty){
9794 var vt = parseInt(this.getTotal(o), 10);
9799 if(s.successProperty){
9800 var vs = this.getSuccess(o);
9801 if(vs === false || vs === 'false'){
9806 for(var i = 0; i < c; i++){
9809 var id = this.getId(n);
9810 for(var j = 0; j < fl; j++){
9812 var v = this.ef[j](n);
9814 Roo.log('missing convert for ' + f.name);
9818 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9820 var record = new Record(values, id);
9822 records[i] = record;
9828 totalRecords : totalRecords
9833 * Ext JS Library 1.1.1
9834 * Copyright(c) 2006-2007, Ext JS, LLC.
9836 * Originally Released Under LGPL - original licence link has changed is not relivant.
9839 * <script type="text/javascript">
9843 * @class Roo.data.ArrayReader
9844 * @extends Roo.data.DataReader
9845 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9846 * Each element of that Array represents a row of data fields. The
9847 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9848 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9852 var RecordDef = Roo.data.Record.create([
9853 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9854 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9856 var myReader = new Roo.data.ArrayReader({
9857 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9861 * This would consume an Array like this:
9863 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9865 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9867 * Create a new JsonReader
9868 * @param {Object} meta Metadata configuration options.
9869 * @param {Object} recordType Either an Array of field definition objects
9870 * as specified to {@link Roo.data.Record#create},
9871 * or an {@link Roo.data.Record} object
9872 * created using {@link Roo.data.Record#create}.
9874 Roo.data.ArrayReader = function(meta, recordType){
9875 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9878 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9880 * Create a data block containing Roo.data.Records from an XML document.
9881 * @param {Object} o An Array of row objects which represents the dataset.
9882 * @return {Object} data A data block which is used by an Roo.data.Store object as
9883 * a cache of Roo.data.Records.
9885 readRecords : function(o){
9886 var sid = this.meta ? this.meta.id : null;
9887 var recordType = this.recordType, fields = recordType.prototype.fields;
9890 for(var i = 0; i < root.length; i++){
9893 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9894 for(var j = 0, jlen = fields.length; j < jlen; j++){
9895 var f = fields.items[j];
9896 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9897 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9901 var record = new recordType(values, id);
9903 records[records.length] = record;
9907 totalRecords : records.length
9916 * @class Roo.bootstrap.ComboBox
9917 * @extends Roo.bootstrap.TriggerField
9918 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9919 * @cfg {Boolean} append (true|false) default false
9920 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9921 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9922 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9924 * Create a new ComboBox.
9925 * @param {Object} config Configuration options
9927 Roo.bootstrap.ComboBox = function(config){
9928 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9932 * Fires when the dropdown list is expanded
9933 * @param {Roo.bootstrap.ComboBox} combo This combo box
9938 * Fires when the dropdown list is collapsed
9939 * @param {Roo.bootstrap.ComboBox} combo This combo box
9943 * @event beforeselect
9944 * Fires before a list item is selected. Return false to cancel the selection.
9945 * @param {Roo.bootstrap.ComboBox} combo This combo box
9946 * @param {Roo.data.Record} record The data record returned from the underlying store
9947 * @param {Number} index The index of the selected item in the dropdown list
9949 'beforeselect' : true,
9952 * Fires when a list item is selected
9953 * @param {Roo.bootstrap.ComboBox} combo This combo box
9954 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9955 * @param {Number} index The index of the selected item in the dropdown list
9959 * @event beforequery
9960 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9961 * The event object passed has these properties:
9962 * @param {Roo.bootstrap.ComboBox} combo This combo box
9963 * @param {String} query The query
9964 * @param {Boolean} forceAll true to force "all" query
9965 * @param {Boolean} cancel true to cancel the query
9966 * @param {Object} e The query event object
9968 'beforequery': true,
9971 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9972 * @param {Roo.bootstrap.ComboBox} combo This combo box
9977 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9978 * @param {Roo.bootstrap.ComboBox} combo This combo box
9979 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9984 * Fires when the remove value from the combobox array
9985 * @param {Roo.bootstrap.ComboBox} combo This combo box
9992 this.tickItems = [];
9994 this.selectedIndex = -1;
9995 if(this.mode == 'local'){
9996 if(config.queryDelay === undefined){
9997 this.queryDelay = 10;
9999 if(config.minChars === undefined){
10005 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10008 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10009 * rendering into an Roo.Editor, defaults to false)
10012 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10013 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10016 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10019 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10020 * the dropdown list (defaults to undefined, with no header element)
10024 * @cfg {String/Roo.Template} tpl The template to use to render the output
10028 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10030 listWidth: undefined,
10032 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10033 * mode = 'remote' or 'text' if mode = 'local')
10035 displayField: undefined,
10037 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10038 * mode = 'remote' or 'value' if mode = 'local').
10039 * Note: use of a valueField requires the user make a selection
10040 * in order for a value to be mapped.
10042 valueField: undefined,
10046 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10047 * field's data value (defaults to the underlying DOM element's name)
10049 hiddenName: undefined,
10051 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10055 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10057 selectedClass: 'active',
10060 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10064 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10065 * anchor positions (defaults to 'tl-bl')
10067 listAlign: 'tl-bl?',
10069 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10073 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10074 * query specified by the allQuery config option (defaults to 'query')
10076 triggerAction: 'query',
10078 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10079 * (defaults to 4, does not apply if editable = false)
10083 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10084 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10088 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10089 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10093 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10094 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10098 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10099 * when editable = true (defaults to false)
10101 selectOnFocus:false,
10103 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10105 queryParam: 'query',
10107 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10108 * when mode = 'remote' (defaults to 'Loading...')
10110 loadingText: 'Loading...',
10112 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10116 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10120 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10121 * traditional select (defaults to true)
10125 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10129 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10133 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10134 * listWidth has a higher value)
10138 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10139 * allow the user to set arbitrary text into the field (defaults to false)
10141 forceSelection:false,
10143 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10144 * if typeAhead = true (defaults to 250)
10146 typeAheadDelay : 250,
10148 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10149 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10151 valueNotFoundText : undefined,
10153 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10155 blockFocus : false,
10158 * @cfg {Boolean} disableClear Disable showing of clear button.
10160 disableClear : false,
10162 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10164 alwaysQuery : false,
10167 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10181 btnPosition : 'right',
10183 // element that contains real text value.. (when hidden is used..)
10185 getAutoCreate : function()
10192 if(!this.tickable){
10193 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10198 * ComboBox with tickable selections
10201 var align = this.labelAlign || this.parentLabelAlign();
10204 cls : 'form-group roo-combobox-tickable' //input-group
10210 cls : 'tickable-buttons',
10215 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10222 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10229 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10236 Roo.each(buttons.cn, function(c){
10238 c.cls += ' btn-' + _this.size;
10241 if (_this.disabled) {
10252 cls: 'form-hidden-field'
10256 cls: 'select2-choices',
10260 cls: 'select2-search-field',
10272 cls: 'select2-container input-group select2-container-multi',
10277 cls: 'typeahead typeahead-long dropdown-menu',
10278 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10283 if (align ==='left' && this.fieldLabel.length) {
10285 Roo.log("left and has label");
10291 cls : 'control-label col-sm-' + this.labelWidth,
10292 html : this.fieldLabel
10296 cls : "col-sm-" + (12 - this.labelWidth),
10303 } else if ( this.fieldLabel.length) {
10309 //cls : 'input-group-addon',
10310 html : this.fieldLabel
10320 Roo.log(" no label && no align");
10327 ['xs','sm','md','lg'].map(function(size){
10328 if (settings[size]) {
10329 cfg.cls += ' col-' + size + '-' + settings[size];
10338 initEvents: function()
10342 throw "can not find store for combo";
10344 this.store = Roo.factory(this.store, Roo.data);
10347 this.initTickableEvnets();
10351 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10354 if(this.hiddenName){
10356 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10358 this.hiddenField.dom.value =
10359 this.hiddenValue !== undefined ? this.hiddenValue :
10360 this.value !== undefined ? this.value : '';
10362 // prevent input submission
10363 this.el.dom.removeAttribute('name');
10364 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10369 // this.el.dom.setAttribute('autocomplete', 'off');
10372 var cls = 'x-combo-list';
10373 this.list = this.el.select('ul.dropdown-menu',true).first();
10375 //this.list = new Roo.Layer({
10376 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10382 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10383 _this.list.setWidth(lw);
10386 this.list.on('mouseover', this.onViewOver, this);
10387 this.list.on('mousemove', this.onViewMove, this);
10389 this.list.on('scroll', this.onViewScroll, this);
10392 this.list.swallowEvent('mousewheel');
10393 this.assetHeight = 0;
10396 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10397 this.assetHeight += this.header.getHeight();
10400 this.innerList = this.list.createChild({cls:cls+'-inner'});
10401 this.innerList.on('mouseover', this.onViewOver, this);
10402 this.innerList.on('mousemove', this.onViewMove, this);
10403 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10405 if(this.allowBlank && !this.pageSize && !this.disableClear){
10406 this.footer = this.list.createChild({cls:cls+'-ft'});
10407 this.pageTb = new Roo.Toolbar(this.footer);
10411 this.footer = this.list.createChild({cls:cls+'-ft'});
10412 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10413 {pageSize: this.pageSize});
10417 if (this.pageTb && this.allowBlank && !this.disableClear) {
10419 this.pageTb.add(new Roo.Toolbar.Fill(), {
10420 cls: 'x-btn-icon x-btn-clear',
10422 handler: function()
10425 _this.clearValue();
10426 _this.onSelect(false, -1);
10431 this.assetHeight += this.footer.getHeight();
10436 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10439 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10440 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10442 //this.view.wrapEl.setDisplayed(false);
10443 this.view.on('click', this.onViewClick, this);
10447 this.store.on('beforeload', this.onBeforeLoad, this);
10448 this.store.on('load', this.onLoad, this);
10449 this.store.on('loadexception', this.onLoadException, this);
10451 if(this.resizable){
10452 this.resizer = new Roo.Resizable(this.list, {
10453 pinned:true, handles:'se'
10455 this.resizer.on('resize', function(r, w, h){
10456 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10457 this.listWidth = w;
10458 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10459 this.restrictHeight();
10461 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10464 if(!this.editable){
10465 this.editable = true;
10466 this.setEditable(false);
10471 if (typeof(this.events.add.listeners) != 'undefined') {
10473 this.addicon = this.wrap.createChild(
10474 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10476 this.addicon.on('click', function(e) {
10477 this.fireEvent('add', this);
10480 if (typeof(this.events.edit.listeners) != 'undefined') {
10482 this.editicon = this.wrap.createChild(
10483 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10484 if (this.addicon) {
10485 this.editicon.setStyle('margin-left', '40px');
10487 this.editicon.on('click', function(e) {
10489 // we fire even if inothing is selected..
10490 this.fireEvent('edit', this, this.lastData );
10496 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10497 "up" : function(e){
10498 this.inKeyMode = true;
10502 "down" : function(e){
10503 if(!this.isExpanded()){
10504 this.onTriggerClick();
10506 this.inKeyMode = true;
10511 "enter" : function(e){
10512 // this.onViewClick();
10516 if(this.fireEvent("specialkey", this, e)){
10517 this.onViewClick(false);
10523 "esc" : function(e){
10527 "tab" : function(e){
10530 if(this.fireEvent("specialkey", this, e)){
10531 this.onViewClick(false);
10539 doRelay : function(foo, bar, hname){
10540 if(hname == 'down' || this.scope.isExpanded()){
10541 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10550 this.queryDelay = Math.max(this.queryDelay || 10,
10551 this.mode == 'local' ? 10 : 250);
10554 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10556 if(this.typeAhead){
10557 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10559 if(this.editable !== false){
10560 this.inputEl().on("keyup", this.onKeyUp, this);
10562 if(this.forceSelection){
10563 this.inputEl().on('blur', this.doForce, this);
10567 this.choices = this.el.select('ul.select2-choices', true).first();
10568 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10572 initTickableEvnets: function()
10574 if(this.hiddenName){
10576 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10578 this.hiddenField.dom.value =
10579 this.hiddenValue !== undefined ? this.hiddenValue :
10580 this.value !== undefined ? this.value : '';
10582 // prevent input submission
10583 this.el.dom.removeAttribute('name');
10584 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10589 this.list = this.el.select('ul.dropdown-menu',true).first();
10591 this.choices = this.el.select('ul.select2-choices', true).first();
10592 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10593 this.searchField.on("click", this.onTriggerClick, this, {preventDefault:true});
10595 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10596 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10598 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10599 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10601 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10602 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10604 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10605 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10606 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10609 this.cancelBtn.hide();
10614 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10615 _this.list.setWidth(lw);
10618 this.list.on('mouseover', this.onViewOver, this);
10619 this.list.on('mousemove', this.onViewMove, this);
10621 this.list.on('scroll', this.onViewScroll, this);
10624 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10627 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10628 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10631 //this.view.wrapEl.setDisplayed(false);
10632 this.view.on('click', this.onViewClick, this);
10636 this.store.on('beforeload', this.onBeforeLoad, this);
10637 this.store.on('load', this.onLoad, this);
10638 this.store.on('loadexception', this.onLoadException, this);
10640 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10641 // "up" : function(e){
10642 // this.inKeyMode = true;
10643 // this.selectPrev();
10646 // "down" : function(e){
10647 // if(!this.isExpanded()){
10648 // this.onTriggerClick();
10650 // this.inKeyMode = true;
10651 // this.selectNext();
10655 // "enter" : function(e){
10656 //// this.onViewClick();
10658 // this.collapse();
10660 // if(this.fireEvent("specialkey", this, e)){
10661 // this.onViewClick(false);
10667 // "esc" : function(e){
10668 // this.collapse();
10671 // "tab" : function(e){
10672 // this.collapse();
10674 // if(this.fireEvent("specialkey", this, e)){
10675 // this.onViewClick(false);
10683 // doRelay : function(foo, bar, hname){
10684 // if(hname == 'down' || this.scope.isExpanded()){
10685 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10690 // forceKeyDown: true
10694 this.queryDelay = Math.max(this.queryDelay || 10,
10695 this.mode == 'local' ? 10 : 250);
10698 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10700 if(this.typeAhead){
10701 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10705 onDestroy : function(){
10707 this.view.setStore(null);
10708 this.view.el.removeAllListeners();
10709 this.view.el.remove();
10710 this.view.purgeListeners();
10713 this.list.dom.innerHTML = '';
10717 this.store.un('beforeload', this.onBeforeLoad, this);
10718 this.store.un('load', this.onLoad, this);
10719 this.store.un('loadexception', this.onLoadException, this);
10721 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10725 fireKey : function(e){
10726 if(e.isNavKeyPress() && !this.list.isVisible()){
10727 this.fireEvent("specialkey", this, e);
10732 onResize: function(w, h){
10733 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10735 // if(typeof w != 'number'){
10736 // // we do not handle it!?!?
10739 // var tw = this.trigger.getWidth();
10740 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10741 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10743 // this.inputEl().setWidth( this.adjustWidth('input', x));
10745 // //this.trigger.setStyle('left', x+'px');
10747 // if(this.list && this.listWidth === undefined){
10748 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10749 // this.list.setWidth(lw);
10750 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10758 * Allow or prevent the user from directly editing the field text. If false is passed,
10759 * the user will only be able to select from the items defined in the dropdown list. This method
10760 * is the runtime equivalent of setting the 'editable' config option at config time.
10761 * @param {Boolean} value True to allow the user to directly edit the field text
10763 setEditable : function(value){
10764 if(value == this.editable){
10767 this.editable = value;
10769 this.inputEl().dom.setAttribute('readOnly', true);
10770 this.inputEl().on('mousedown', this.onTriggerClick, this);
10771 this.inputEl().addClass('x-combo-noedit');
10773 this.inputEl().dom.setAttribute('readOnly', false);
10774 this.inputEl().un('mousedown', this.onTriggerClick, this);
10775 this.inputEl().removeClass('x-combo-noedit');
10781 onBeforeLoad : function(combo,opts){
10782 if(!this.hasFocus){
10786 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10788 this.restrictHeight();
10789 this.selectedIndex = -1;
10793 onLoad : function(){
10795 this.hasQuery = false;
10797 if(!this.hasFocus){
10801 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10802 this.loading.hide();
10805 if(this.store.getCount() > 0){
10807 this.restrictHeight();
10808 if(this.lastQuery == this.allQuery){
10809 if(this.editable && !this.tickable){
10810 this.inputEl().dom.select();
10812 if(!this.selectByValue(this.value, true) && this.autoFocus){
10813 this.select(0, true);
10816 if(this.autoFocus){
10819 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10820 this.taTask.delay(this.typeAheadDelay);
10824 this.onEmptyResults();
10830 onLoadException : function()
10832 this.hasQuery = false;
10834 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10835 this.loading.hide();
10839 Roo.log(this.store.reader.jsonData);
10840 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10842 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10848 onTypeAhead : function(){
10849 if(this.store.getCount() > 0){
10850 var r = this.store.getAt(0);
10851 var newValue = r.data[this.displayField];
10852 var len = newValue.length;
10853 var selStart = this.getRawValue().length;
10855 if(selStart != len){
10856 this.setRawValue(newValue);
10857 this.selectText(selStart, newValue.length);
10863 onSelect : function(record, index){
10865 if(this.fireEvent('beforeselect', this, record, index) !== false){
10867 this.setFromData(index > -1 ? record.data : false);
10870 this.fireEvent('select', this, record, index);
10875 * Returns the currently selected field value or empty string if no value is set.
10876 * @return {String} value The selected value
10878 getValue : function(){
10881 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10884 if(this.valueField){
10885 return typeof this.value != 'undefined' ? this.value : '';
10887 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10892 * Clears any text/value currently set in the field
10894 clearValue : function(){
10895 if(this.hiddenField){
10896 this.hiddenField.dom.value = '';
10899 this.setRawValue('');
10900 this.lastSelectionText = '';
10905 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10906 * will be displayed in the field. If the value does not match the data value of an existing item,
10907 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10908 * Otherwise the field will be blank (although the value will still be set).
10909 * @param {String} value The value to match
10911 setValue : function(v){
10918 if(this.valueField){
10919 var r = this.findRecord(this.valueField, v);
10921 text = r.data[this.displayField];
10922 }else if(this.valueNotFoundText !== undefined){
10923 text = this.valueNotFoundText;
10926 this.lastSelectionText = text;
10927 if(this.hiddenField){
10928 this.hiddenField.dom.value = v;
10930 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10934 * @property {Object} the last set data for the element
10939 * Sets the value of the field based on a object which is related to the record format for the store.
10940 * @param {Object} value the value to set as. or false on reset?
10942 setFromData : function(o){
10949 var dv = ''; // display value
10950 var vv = ''; // value value..
10952 if (this.displayField) {
10953 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10955 // this is an error condition!!!
10956 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10959 if(this.valueField){
10960 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10963 if(this.hiddenField){
10964 this.hiddenField.dom.value = vv;
10966 this.lastSelectionText = dv;
10967 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10971 // no hidden field.. - we store the value in 'value', but still display
10972 // display field!!!!
10973 this.lastSelectionText = dv;
10974 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10980 reset : function(){
10981 // overridden so that last data is reset..
10982 this.setValue(this.originalValue);
10983 this.clearInvalid();
10984 this.lastData = false;
10986 this.view.clearSelections();
10990 findRecord : function(prop, value){
10992 if(this.store.getCount() > 0){
10993 this.store.each(function(r){
10994 if(r.data[prop] == value){
11004 getName: function()
11006 // returns hidden if it's set..
11007 if (!this.rendered) {return ''};
11008 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11012 onViewMove : function(e, t){
11013 this.inKeyMode = false;
11017 onViewOver : function(e, t){
11018 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11021 var item = this.view.findItemFromChild(t);
11024 var index = this.view.indexOf(item);
11025 this.select(index, false);
11030 onViewClick : function(view, doFocus, el, e)
11032 var index = this.view.getSelectedIndexes()[0];
11034 var r = this.store.getAt(index);
11038 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11045 Roo.each(this.tickItems, function(v,k){
11047 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11048 _this.tickItems.splice(k, 1);
11058 this.tickItems.push(r.data);
11063 this.onSelect(r, index);
11065 if(doFocus !== false && !this.blockFocus){
11066 this.inputEl().focus();
11071 restrictHeight : function(){
11072 //this.innerList.dom.style.height = '';
11073 //var inner = this.innerList.dom;
11074 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11075 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11076 //this.list.beginUpdate();
11077 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11078 this.list.alignTo(this.inputEl(), this.listAlign);
11079 //this.list.endUpdate();
11083 onEmptyResults : function(){
11088 * Returns true if the dropdown list is expanded, else false.
11090 isExpanded : function(){
11091 return this.list.isVisible();
11095 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11096 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11097 * @param {String} value The data value of the item to select
11098 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11099 * selected item if it is not currently in view (defaults to true)
11100 * @return {Boolean} True if the value matched an item in the list, else false
11102 selectByValue : function(v, scrollIntoView){
11103 if(v !== undefined && v !== null){
11104 var r = this.findRecord(this.valueField || this.displayField, v);
11106 this.select(this.store.indexOf(r), scrollIntoView);
11114 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11115 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11116 * @param {Number} index The zero-based index of the list item to select
11117 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11118 * selected item if it is not currently in view (defaults to true)
11120 select : function(index, scrollIntoView){
11121 this.selectedIndex = index;
11122 this.view.select(index);
11123 if(scrollIntoView !== false){
11124 var el = this.view.getNode(index);
11126 //this.innerList.scrollChildIntoView(el, false);
11133 selectNext : function(){
11134 var ct = this.store.getCount();
11136 if(this.selectedIndex == -1){
11138 }else if(this.selectedIndex < ct-1){
11139 this.select(this.selectedIndex+1);
11145 selectPrev : function(){
11146 var ct = this.store.getCount();
11148 if(this.selectedIndex == -1){
11150 }else if(this.selectedIndex != 0){
11151 this.select(this.selectedIndex-1);
11157 onKeyUp : function(e){
11158 if(this.editable !== false && !e.isSpecialKey()){
11159 this.lastKey = e.getKey();
11160 this.dqTask.delay(this.queryDelay);
11165 validateBlur : function(){
11166 return !this.list || !this.list.isVisible();
11170 initQuery : function(){
11171 this.doQuery(this.getRawValue());
11175 doForce : function(){
11176 if(this.inputEl().dom.value.length > 0){
11177 this.inputEl().dom.value =
11178 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11184 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11185 * query allowing the query action to be canceled if needed.
11186 * @param {String} query The SQL query to execute
11187 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11188 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11189 * saved in the current store (defaults to false)
11191 doQuery : function(q, forceAll){
11193 if(q === undefined || q === null){
11198 forceAll: forceAll,
11202 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11207 forceAll = qe.forceAll;
11208 if(forceAll === true || (q.length >= this.minChars)){
11210 this.hasQuery = true;
11212 if(this.lastQuery != q || this.alwaysQuery){
11213 this.lastQuery = q;
11214 if(this.mode == 'local'){
11215 this.selectedIndex = -1;
11217 this.store.clearFilter();
11219 this.store.filter(this.displayField, q);
11223 this.store.baseParams[this.queryParam] = q;
11225 var options = {params : this.getParams(q)};
11228 options.add = true;
11229 options.params.start = this.page * this.pageSize;
11232 this.store.load(options);
11234 * this code will make the page width larger, at the beginning, the list not align correctly,
11235 * we should expand the list on onLoad
11236 * so command out it
11241 this.selectedIndex = -1;
11246 this.loadNext = false;
11250 getParams : function(q){
11252 //p[this.queryParam] = q;
11256 p.limit = this.pageSize;
11262 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11264 collapse : function(){
11265 if(!this.isExpanded()){
11273 this.cancelBtn.hide();
11274 this.trigger.show();
11277 Roo.get(document).un('mousedown', this.collapseIf, this);
11278 Roo.get(document).un('mousewheel', this.collapseIf, this);
11279 if (!this.editable) {
11280 Roo.get(document).un('keydown', this.listKeyPress, this);
11282 this.fireEvent('collapse', this);
11286 collapseIf : function(e){
11287 var in_combo = e.within(this.el);
11288 var in_list = e.within(this.list);
11290 if (in_combo || in_list) {
11291 //e.stopPropagation();
11296 this.onTickableFooterButtonClick(e, false, false);
11304 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11306 expand : function(){
11308 if(this.isExpanded() || !this.hasFocus){
11312 this.list.alignTo(this.inputEl(), this.listAlign);
11317 this.tickItems = Roo.apply([], this.item);
11320 this.cancelBtn.show();
11321 this.trigger.hide();
11325 Roo.get(document).on('mousedown', this.collapseIf, this);
11326 Roo.get(document).on('mousewheel', this.collapseIf, this);
11327 if (!this.editable) {
11328 Roo.get(document).on('keydown', this.listKeyPress, this);
11331 this.fireEvent('expand', this);
11335 // Implements the default empty TriggerField.onTriggerClick function
11336 onTriggerClick : function()
11338 Roo.log('trigger click');
11345 this.onTickableTriggerClick();
11350 this.loadNext = false;
11352 if(this.isExpanded()){
11354 if (!this.blockFocus) {
11355 this.inputEl().focus();
11359 this.hasFocus = true;
11360 if(this.triggerAction == 'all') {
11361 this.doQuery(this.allQuery, true);
11363 this.doQuery(this.getRawValue());
11365 if (!this.blockFocus) {
11366 this.inputEl().focus();
11371 onTickableTriggerClick : function()
11374 this.loadNext = false;
11375 this.hasFocus = true;
11377 if(this.triggerAction == 'all') {
11378 this.doQuery(this.allQuery, true);
11380 this.doQuery(this.getRawValue());
11384 listKeyPress : function(e)
11386 //Roo.log('listkeypress');
11387 // scroll to first matching element based on key pres..
11388 if (e.isSpecialKey()) {
11391 var k = String.fromCharCode(e.getKey()).toUpperCase();
11394 var csel = this.view.getSelectedNodes();
11395 var cselitem = false;
11397 var ix = this.view.indexOf(csel[0]);
11398 cselitem = this.store.getAt(ix);
11399 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11405 this.store.each(function(v) {
11407 // start at existing selection.
11408 if (cselitem.id == v.id) {
11414 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11415 match = this.store.indexOf(v);
11421 if (match === false) {
11422 return true; // no more action?
11425 this.view.select(match);
11426 var sn = Roo.get(this.view.getSelectedNodes()[0])
11427 //sn.scrollIntoView(sn.dom.parentNode, false);
11430 onViewScroll : function(e, t){
11432 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11436 this.hasQuery = true;
11438 this.loading = this.list.select('.loading', true).first();
11440 if(this.loading === null){
11441 this.list.createChild({
11443 cls: 'loading select2-more-results select2-active',
11444 html: 'Loading more results...'
11447 this.loading = this.list.select('.loading', true).first();
11449 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11451 this.loading.hide();
11454 this.loading.show();
11459 this.loadNext = true;
11461 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11466 addItem : function(o)
11468 var dv = ''; // display value
11470 if (this.displayField) {
11471 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11473 // this is an error condition!!!
11474 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11481 var choice = this.choices.createChild({
11483 cls: 'select2-search-choice',
11492 cls: 'select2-search-choice-close',
11497 }, this.searchField);
11499 var close = choice.select('a.select2-search-choice-close', true).first()
11501 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11509 this.inputEl().dom.value = '';
11513 onRemoveItem : function(e, _self, o)
11515 e.preventDefault();
11516 var index = this.item.indexOf(o.data) * 1;
11519 Roo.log('not this item?!');
11523 this.item.splice(index, 1);
11528 this.fireEvent('remove', this, e);
11532 syncValue : function()
11534 if(!this.item.length){
11541 Roo.each(this.item, function(i){
11542 if(_this.valueField){
11543 value.push(i[_this.valueField]);
11550 this.value = value.join(',');
11552 if(this.hiddenField){
11553 this.hiddenField.dom.value = this.value;
11557 clearItem : function()
11559 if(!this.multiple){
11565 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11572 inputEl: function ()
11575 return this.searchField;
11577 return this.el.select('input.form-control',true).first();
11581 onTickableFooterButtonClick : function(e, btn, el)
11583 e.preventDefault();
11585 if(btn && btn.name == 'cancel'){
11586 this.tickItems = Roo.apply([], this.item);
11595 Roo.each(this.tickItems, function(o){
11606 * @cfg {Boolean} grow
11610 * @cfg {Number} growMin
11614 * @cfg {Number} growMax
11624 * Ext JS Library 1.1.1
11625 * Copyright(c) 2006-2007, Ext JS, LLC.
11627 * Originally Released Under LGPL - original licence link has changed is not relivant.
11630 * <script type="text/javascript">
11635 * @extends Roo.util.Observable
11636 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11637 * This class also supports single and multi selection modes. <br>
11638 * Create a data model bound view:
11640 var store = new Roo.data.Store(...);
11642 var view = new Roo.View({
11644 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11646 singleSelect: true,
11647 selectedClass: "ydataview-selected",
11651 // listen for node click?
11652 view.on("click", function(vw, index, node, e){
11653 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11657 dataModel.load("foobar.xml");
11659 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11661 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11662 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11664 * Note: old style constructor is still suported (container, template, config)
11667 * Create a new View
11668 * @param {Object} config The config object
11671 Roo.View = function(config, depreciated_tpl, depreciated_config){
11673 this.parent = false;
11675 if (typeof(depreciated_tpl) == 'undefined') {
11676 // new way.. - universal constructor.
11677 Roo.apply(this, config);
11678 this.el = Roo.get(this.el);
11681 this.el = Roo.get(config);
11682 this.tpl = depreciated_tpl;
11683 Roo.apply(this, depreciated_config);
11685 this.wrapEl = this.el.wrap().wrap();
11686 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11689 if(typeof(this.tpl) == "string"){
11690 this.tpl = new Roo.Template(this.tpl);
11692 // support xtype ctors..
11693 this.tpl = new Roo.factory(this.tpl, Roo);
11697 this.tpl.compile();
11702 * @event beforeclick
11703 * Fires before a click is processed. Returns false to cancel the default action.
11704 * @param {Roo.View} this
11705 * @param {Number} index The index of the target node
11706 * @param {HTMLElement} node The target node
11707 * @param {Roo.EventObject} e The raw event object
11709 "beforeclick" : true,
11712 * Fires when a template node is clicked.
11713 * @param {Roo.View} this
11714 * @param {Number} index The index of the target node
11715 * @param {HTMLElement} node The target node
11716 * @param {Roo.EventObject} e The raw event object
11721 * Fires when a template node is double clicked.
11722 * @param {Roo.View} this
11723 * @param {Number} index The index of the target node
11724 * @param {HTMLElement} node The target node
11725 * @param {Roo.EventObject} e The raw event object
11729 * @event contextmenu
11730 * Fires when a template node is right clicked.
11731 * @param {Roo.View} this
11732 * @param {Number} index The index of the target node
11733 * @param {HTMLElement} node The target node
11734 * @param {Roo.EventObject} e The raw event object
11736 "contextmenu" : true,
11738 * @event selectionchange
11739 * Fires when the selected nodes change.
11740 * @param {Roo.View} this
11741 * @param {Array} selections Array of the selected nodes
11743 "selectionchange" : true,
11746 * @event beforeselect
11747 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11748 * @param {Roo.View} this
11749 * @param {HTMLElement} node The node to be selected
11750 * @param {Array} selections Array of currently selected nodes
11752 "beforeselect" : true,
11754 * @event preparedata
11755 * Fires on every row to render, to allow you to change the data.
11756 * @param {Roo.View} this
11757 * @param {Object} data to be rendered (change this)
11759 "preparedata" : true
11767 "click": this.onClick,
11768 "dblclick": this.onDblClick,
11769 "contextmenu": this.onContextMenu,
11773 this.selections = [];
11775 this.cmp = new Roo.CompositeElementLite([]);
11777 this.store = Roo.factory(this.store, Roo.data);
11778 this.setStore(this.store, true);
11781 if ( this.footer && this.footer.xtype) {
11783 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11785 this.footer.dataSource = this.store
11786 this.footer.container = fctr;
11787 this.footer = Roo.factory(this.footer, Roo);
11788 fctr.insertFirst(this.el);
11790 // this is a bit insane - as the paging toolbar seems to detach the el..
11791 // dom.parentNode.parentNode.parentNode
11792 // they get detached?
11796 Roo.View.superclass.constructor.call(this);
11801 Roo.extend(Roo.View, Roo.util.Observable, {
11804 * @cfg {Roo.data.Store} store Data store to load data from.
11809 * @cfg {String|Roo.Element} el The container element.
11814 * @cfg {String|Roo.Template} tpl The template used by this View
11818 * @cfg {String} dataName the named area of the template to use as the data area
11819 * Works with domtemplates roo-name="name"
11823 * @cfg {String} selectedClass The css class to add to selected nodes
11825 selectedClass : "x-view-selected",
11827 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11832 * @cfg {String} text to display on mask (default Loading)
11836 * @cfg {Boolean} multiSelect Allow multiple selection
11838 multiSelect : false,
11840 * @cfg {Boolean} singleSelect Allow single selection
11842 singleSelect: false,
11845 * @cfg {Boolean} toggleSelect - selecting
11847 toggleSelect : false,
11850 * @cfg {Boolean} tickable - selecting
11855 * Returns the element this view is bound to.
11856 * @return {Roo.Element}
11858 getEl : function(){
11859 return this.wrapEl;
11865 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11867 refresh : function(){
11868 Roo.log('refresh');
11871 // if we are using something like 'domtemplate', then
11872 // the what gets used is:
11873 // t.applySubtemplate(NAME, data, wrapping data..)
11874 // the outer template then get' applied with
11875 // the store 'extra data'
11876 // and the body get's added to the
11877 // roo-name="data" node?
11878 // <span class='roo-tpl-{name}'></span> ?????
11882 this.clearSelections();
11883 this.el.update("");
11885 var records = this.store.getRange();
11886 if(records.length < 1) {
11888 // is this valid?? = should it render a template??
11890 this.el.update(this.emptyText);
11894 if (this.dataName) {
11895 this.el.update(t.apply(this.store.meta)); //????
11896 el = this.el.child('.roo-tpl-' + this.dataName);
11899 for(var i = 0, len = records.length; i < len; i++){
11900 var data = this.prepareData(records[i].data, i, records[i]);
11901 this.fireEvent("preparedata", this, data, i, records[i]);
11903 var d = Roo.apply({}, data);
11906 Roo.apply(d, {'roo-id' : Roo.id()});
11910 Roo.each(this.parent.item, function(item){
11911 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11914 Roo.apply(d, {'roo-data-checked' : 'checked'});
11918 html[html.length] = Roo.util.Format.trim(
11920 t.applySubtemplate(this.dataName, d, this.store.meta) :
11927 el.update(html.join(""));
11928 this.nodes = el.dom.childNodes;
11929 this.updateIndexes(0);
11934 * Function to override to reformat the data that is sent to
11935 * the template for each node.
11936 * DEPRICATED - use the preparedata event handler.
11937 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11938 * a JSON object for an UpdateManager bound view).
11940 prepareData : function(data, index, record)
11942 this.fireEvent("preparedata", this, data, index, record);
11946 onUpdate : function(ds, record){
11947 Roo.log('on update');
11948 this.clearSelections();
11949 var index = this.store.indexOf(record);
11950 var n = this.nodes[index];
11951 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11952 n.parentNode.removeChild(n);
11953 this.updateIndexes(index, index);
11959 onAdd : function(ds, records, index)
11961 Roo.log(['on Add', ds, records, index] );
11962 this.clearSelections();
11963 if(this.nodes.length == 0){
11967 var n = this.nodes[index];
11968 for(var i = 0, len = records.length; i < len; i++){
11969 var d = this.prepareData(records[i].data, i, records[i]);
11971 this.tpl.insertBefore(n, d);
11974 this.tpl.append(this.el, d);
11977 this.updateIndexes(index);
11980 onRemove : function(ds, record, index){
11981 Roo.log('onRemove');
11982 this.clearSelections();
11983 var el = this.dataName ?
11984 this.el.child('.roo-tpl-' + this.dataName) :
11987 el.dom.removeChild(this.nodes[index]);
11988 this.updateIndexes(index);
11992 * Refresh an individual node.
11993 * @param {Number} index
11995 refreshNode : function(index){
11996 this.onUpdate(this.store, this.store.getAt(index));
11999 updateIndexes : function(startIndex, endIndex){
12000 var ns = this.nodes;
12001 startIndex = startIndex || 0;
12002 endIndex = endIndex || ns.length - 1;
12003 for(var i = startIndex; i <= endIndex; i++){
12004 ns[i].nodeIndex = i;
12009 * Changes the data store this view uses and refresh the view.
12010 * @param {Store} store
12012 setStore : function(store, initial){
12013 if(!initial && this.store){
12014 this.store.un("datachanged", this.refresh);
12015 this.store.un("add", this.onAdd);
12016 this.store.un("remove", this.onRemove);
12017 this.store.un("update", this.onUpdate);
12018 this.store.un("clear", this.refresh);
12019 this.store.un("beforeload", this.onBeforeLoad);
12020 this.store.un("load", this.onLoad);
12021 this.store.un("loadexception", this.onLoad);
12025 store.on("datachanged", this.refresh, this);
12026 store.on("add", this.onAdd, this);
12027 store.on("remove", this.onRemove, this);
12028 store.on("update", this.onUpdate, this);
12029 store.on("clear", this.refresh, this);
12030 store.on("beforeload", this.onBeforeLoad, this);
12031 store.on("load", this.onLoad, this);
12032 store.on("loadexception", this.onLoad, this);
12040 * onbeforeLoad - masks the loading area.
12043 onBeforeLoad : function(store,opts)
12045 Roo.log('onBeforeLoad');
12047 this.el.update("");
12049 this.el.mask(this.mask ? this.mask : "Loading" );
12051 onLoad : function ()
12058 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12059 * @param {HTMLElement} node
12060 * @return {HTMLElement} The template node
12062 findItemFromChild : function(node){
12063 var el = this.dataName ?
12064 this.el.child('.roo-tpl-' + this.dataName,true) :
12067 if(!node || node.parentNode == el){
12070 var p = node.parentNode;
12071 while(p && p != el){
12072 if(p.parentNode == el){
12081 onClick : function(e){
12082 var item = this.findItemFromChild(e.getTarget());
12084 var index = this.indexOf(item);
12085 if(this.onItemClick(item, index, e) !== false){
12086 this.fireEvent("click", this, index, item, e);
12089 this.clearSelections();
12094 onContextMenu : function(e){
12095 var item = this.findItemFromChild(e.getTarget());
12097 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12102 onDblClick : function(e){
12103 var item = this.findItemFromChild(e.getTarget());
12105 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12109 onItemClick : function(item, index, e)
12111 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12114 if (this.toggleSelect) {
12115 var m = this.isSelected(item) ? 'unselect' : 'select';
12118 _t[m](item, true, false);
12121 if(this.multiSelect || this.singleSelect){
12122 if(this.multiSelect && e.shiftKey && this.lastSelection){
12123 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12125 this.select(item, this.multiSelect && e.ctrlKey);
12126 this.lastSelection = item;
12129 if(!this.tickable){
12130 e.preventDefault();
12138 * Get the number of selected nodes.
12141 getSelectionCount : function(){
12142 return this.selections.length;
12146 * Get the currently selected nodes.
12147 * @return {Array} An array of HTMLElements
12149 getSelectedNodes : function(){
12150 return this.selections;
12154 * Get the indexes of the selected nodes.
12157 getSelectedIndexes : function(){
12158 var indexes = [], s = this.selections;
12159 for(var i = 0, len = s.length; i < len; i++){
12160 indexes.push(s[i].nodeIndex);
12166 * Clear all selections
12167 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12169 clearSelections : function(suppressEvent){
12170 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12171 this.cmp.elements = this.selections;
12172 this.cmp.removeClass(this.selectedClass);
12173 this.selections = [];
12174 if(!suppressEvent){
12175 this.fireEvent("selectionchange", this, this.selections);
12181 * Returns true if the passed node is selected
12182 * @param {HTMLElement/Number} node The node or node index
12183 * @return {Boolean}
12185 isSelected : function(node){
12186 var s = this.selections;
12190 node = this.getNode(node);
12191 return s.indexOf(node) !== -1;
12196 * @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
12197 * @param {Boolean} keepExisting (optional) true to keep existing selections
12198 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12200 select : function(nodeInfo, keepExisting, suppressEvent){
12201 if(nodeInfo instanceof Array){
12203 this.clearSelections(true);
12205 for(var i = 0, len = nodeInfo.length; i < len; i++){
12206 this.select(nodeInfo[i], true, true);
12210 var node = this.getNode(nodeInfo);
12211 if(!node || this.isSelected(node)){
12212 return; // already selected.
12215 this.clearSelections(true);
12217 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12218 Roo.fly(node).addClass(this.selectedClass);
12219 this.selections.push(node);
12220 if(!suppressEvent){
12221 this.fireEvent("selectionchange", this, this.selections);
12229 * @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
12230 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12231 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12233 unselect : function(nodeInfo, keepExisting, suppressEvent)
12235 if(nodeInfo instanceof Array){
12236 Roo.each(this.selections, function(s) {
12237 this.unselect(s, nodeInfo);
12241 var node = this.getNode(nodeInfo);
12242 if(!node || !this.isSelected(node)){
12243 Roo.log("not selected");
12244 return; // not selected.
12248 Roo.each(this.selections, function(s) {
12250 Roo.fly(node).removeClass(this.selectedClass);
12257 this.selections= ns;
12258 this.fireEvent("selectionchange", this, this.selections);
12262 * Gets a template node.
12263 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12264 * @return {HTMLElement} The node or null if it wasn't found
12266 getNode : function(nodeInfo){
12267 if(typeof nodeInfo == "string"){
12268 return document.getElementById(nodeInfo);
12269 }else if(typeof nodeInfo == "number"){
12270 return this.nodes[nodeInfo];
12276 * Gets a range template nodes.
12277 * @param {Number} startIndex
12278 * @param {Number} endIndex
12279 * @return {Array} An array of nodes
12281 getNodes : function(start, end){
12282 var ns = this.nodes;
12283 start = start || 0;
12284 end = typeof end == "undefined" ? ns.length - 1 : end;
12287 for(var i = start; i <= end; i++){
12291 for(var i = start; i >= end; i--){
12299 * Finds the index of the passed node
12300 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12301 * @return {Number} The index of the node or -1
12303 indexOf : function(node){
12304 node = this.getNode(node);
12305 if(typeof node.nodeIndex == "number"){
12306 return node.nodeIndex;
12308 var ns = this.nodes;
12309 for(var i = 0, len = ns.length; i < len; i++){
12320 * based on jquery fullcalendar
12324 Roo.bootstrap = Roo.bootstrap || {};
12326 * @class Roo.bootstrap.Calendar
12327 * @extends Roo.bootstrap.Component
12328 * Bootstrap Calendar class
12329 * @cfg {Boolean} loadMask (true|false) default false
12330 * @cfg {Object} header generate the user specific header of the calendar, default false
12333 * Create a new Container
12334 * @param {Object} config The config object
12339 Roo.bootstrap.Calendar = function(config){
12340 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12344 * Fires when a date is selected
12345 * @param {DatePicker} this
12346 * @param {Date} date The selected date
12350 * @event monthchange
12351 * Fires when the displayed month changes
12352 * @param {DatePicker} this
12353 * @param {Date} date The selected month
12355 'monthchange': true,
12357 * @event evententer
12358 * Fires when mouse over an event
12359 * @param {Calendar} this
12360 * @param {event} Event
12362 'evententer': true,
12364 * @event eventleave
12365 * Fires when the mouse leaves an
12366 * @param {Calendar} this
12369 'eventleave': true,
12371 * @event eventclick
12372 * Fires when the mouse click an
12373 * @param {Calendar} this
12382 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12385 * @cfg {Number} startDay
12386 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12394 getAutoCreate : function(){
12397 var fc_button = function(name, corner, style, content ) {
12398 return Roo.apply({},{
12400 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12402 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12405 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12416 style : 'width:100%',
12423 cls : 'fc-header-left',
12425 fc_button('prev', 'left', 'arrow', '‹' ),
12426 fc_button('next', 'right', 'arrow', '›' ),
12427 { tag: 'span', cls: 'fc-header-space' },
12428 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12436 cls : 'fc-header-center',
12440 cls: 'fc-header-title',
12443 html : 'month / year'
12451 cls : 'fc-header-right',
12453 /* fc_button('month', 'left', '', 'month' ),
12454 fc_button('week', '', '', 'week' ),
12455 fc_button('day', 'right', '', 'day' )
12467 header = this.header;
12470 var cal_heads = function() {
12472 // fixme - handle this.
12474 for (var i =0; i < Date.dayNames.length; i++) {
12475 var d = Date.dayNames[i];
12478 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12479 html : d.substring(0,3)
12483 ret[0].cls += ' fc-first';
12484 ret[6].cls += ' fc-last';
12487 var cal_cell = function(n) {
12490 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12495 cls: 'fc-day-number',
12499 cls: 'fc-day-content',
12503 style: 'position: relative;' // height: 17px;
12515 var cal_rows = function() {
12518 for (var r = 0; r < 6; r++) {
12525 for (var i =0; i < Date.dayNames.length; i++) {
12526 var d = Date.dayNames[i];
12527 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12530 row.cn[0].cls+=' fc-first';
12531 row.cn[0].cn[0].style = 'min-height:90px';
12532 row.cn[6].cls+=' fc-last';
12536 ret[0].cls += ' fc-first';
12537 ret[4].cls += ' fc-prev-last';
12538 ret[5].cls += ' fc-last';
12545 cls: 'fc-border-separate',
12546 style : 'width:100%',
12554 cls : 'fc-first fc-last',
12572 cls : 'fc-content',
12573 style : "position: relative;",
12576 cls : 'fc-view fc-view-month fc-grid',
12577 style : 'position: relative',
12578 unselectable : 'on',
12581 cls : 'fc-event-container',
12582 style : 'position:absolute;z-index:8;top:0;left:0;'
12600 initEvents : function()
12603 throw "can not find store for calendar";
12609 style: "text-align:center",
12613 style: "background-color:white;width:50%;margin:250 auto",
12617 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12628 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12630 var size = this.el.select('.fc-content', true).first().getSize();
12631 this.maskEl.setSize(size.width, size.height);
12632 this.maskEl.enableDisplayMode("block");
12633 if(!this.loadMask){
12634 this.maskEl.hide();
12637 this.store = Roo.factory(this.store, Roo.data);
12638 this.store.on('load', this.onLoad, this);
12639 this.store.on('beforeload', this.onBeforeLoad, this);
12643 this.cells = this.el.select('.fc-day',true);
12644 //Roo.log(this.cells);
12645 this.textNodes = this.el.query('.fc-day-number');
12646 this.cells.addClassOnOver('fc-state-hover');
12648 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12649 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12650 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12651 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12653 this.on('monthchange', this.onMonthChange, this);
12655 this.update(new Date().clearTime());
12658 resize : function() {
12659 var sz = this.el.getSize();
12661 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12662 this.el.select('.fc-day-content div',true).setHeight(34);
12667 showPrevMonth : function(e){
12668 this.update(this.activeDate.add("mo", -1));
12670 showToday : function(e){
12671 this.update(new Date().clearTime());
12674 showNextMonth : function(e){
12675 this.update(this.activeDate.add("mo", 1));
12679 showPrevYear : function(){
12680 this.update(this.activeDate.add("y", -1));
12684 showNextYear : function(){
12685 this.update(this.activeDate.add("y", 1));
12690 update : function(date)
12692 var vd = this.activeDate;
12693 this.activeDate = date;
12694 // if(vd && this.el){
12695 // var t = date.getTime();
12696 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12697 // Roo.log('using add remove');
12699 // this.fireEvent('monthchange', this, date);
12701 // this.cells.removeClass("fc-state-highlight");
12702 // this.cells.each(function(c){
12703 // if(c.dateValue == t){
12704 // c.addClass("fc-state-highlight");
12705 // setTimeout(function(){
12706 // try{c.dom.firstChild.focus();}catch(e){}
12716 var days = date.getDaysInMonth();
12718 var firstOfMonth = date.getFirstDateOfMonth();
12719 var startingPos = firstOfMonth.getDay()-this.startDay;
12721 if(startingPos < this.startDay){
12725 var pm = date.add(Date.MONTH, -1);
12726 var prevStart = pm.getDaysInMonth()-startingPos;
12728 this.cells = this.el.select('.fc-day',true);
12729 this.textNodes = this.el.query('.fc-day-number');
12730 this.cells.addClassOnOver('fc-state-hover');
12732 var cells = this.cells.elements;
12733 var textEls = this.textNodes;
12735 Roo.each(cells, function(cell){
12736 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12739 days += startingPos;
12741 // convert everything to numbers so it's fast
12742 var day = 86400000;
12743 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12746 //Roo.log(prevStart);
12748 var today = new Date().clearTime().getTime();
12749 var sel = date.clearTime().getTime();
12750 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12751 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12752 var ddMatch = this.disabledDatesRE;
12753 var ddText = this.disabledDatesText;
12754 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12755 var ddaysText = this.disabledDaysText;
12756 var format = this.format;
12758 var setCellClass = function(cal, cell){
12762 //Roo.log('set Cell Class');
12764 var t = d.getTime();
12768 cell.dateValue = t;
12770 cell.className += " fc-today";
12771 cell.className += " fc-state-highlight";
12772 cell.title = cal.todayText;
12775 // disable highlight in other month..
12776 //cell.className += " fc-state-highlight";
12781 cell.className = " fc-state-disabled";
12782 cell.title = cal.minText;
12786 cell.className = " fc-state-disabled";
12787 cell.title = cal.maxText;
12791 if(ddays.indexOf(d.getDay()) != -1){
12792 cell.title = ddaysText;
12793 cell.className = " fc-state-disabled";
12796 if(ddMatch && format){
12797 var fvalue = d.dateFormat(format);
12798 if(ddMatch.test(fvalue)){
12799 cell.title = ddText.replace("%0", fvalue);
12800 cell.className = " fc-state-disabled";
12804 if (!cell.initialClassName) {
12805 cell.initialClassName = cell.dom.className;
12808 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12813 for(; i < startingPos; i++) {
12814 textEls[i].innerHTML = (++prevStart);
12815 d.setDate(d.getDate()+1);
12817 cells[i].className = "fc-past fc-other-month";
12818 setCellClass(this, cells[i]);
12823 for(; i < days; i++){
12824 intDay = i - startingPos + 1;
12825 textEls[i].innerHTML = (intDay);
12826 d.setDate(d.getDate()+1);
12828 cells[i].className = ''; // "x-date-active";
12829 setCellClass(this, cells[i]);
12833 for(; i < 42; i++) {
12834 textEls[i].innerHTML = (++extraDays);
12835 d.setDate(d.getDate()+1);
12837 cells[i].className = "fc-future fc-other-month";
12838 setCellClass(this, cells[i]);
12841 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12843 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12845 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12846 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12848 if(totalRows != 6){
12849 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12850 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12853 this.fireEvent('monthchange', this, date);
12857 if(!this.internalRender){
12858 var main = this.el.dom.firstChild;
12859 var w = main.offsetWidth;
12860 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12861 Roo.fly(main).setWidth(w);
12862 this.internalRender = true;
12863 // opera does not respect the auto grow header center column
12864 // then, after it gets a width opera refuses to recalculate
12865 // without a second pass
12866 if(Roo.isOpera && !this.secondPass){
12867 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12868 this.secondPass = true;
12869 this.update.defer(10, this, [date]);
12876 findCell : function(dt) {
12877 dt = dt.clearTime().getTime();
12879 this.cells.each(function(c){
12880 //Roo.log("check " +c.dateValue + '?=' + dt);
12881 if(c.dateValue == dt){
12891 findCells : function(ev) {
12892 var s = ev.start.clone().clearTime().getTime();
12894 var e= ev.end.clone().clearTime().getTime();
12897 this.cells.each(function(c){
12898 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12900 if(c.dateValue > e){
12903 if(c.dateValue < s){
12912 // findBestRow: function(cells)
12916 // for (var i =0 ; i < cells.length;i++) {
12917 // ret = Math.max(cells[i].rows || 0,ret);
12924 addItem : function(ev)
12926 // look for vertical location slot in
12927 var cells = this.findCells(ev);
12929 // ev.row = this.findBestRow(cells);
12931 // work out the location.
12935 for(var i =0; i < cells.length; i++) {
12937 cells[i].row = cells[0].row;
12940 cells[i].row = cells[i].row + 1;
12950 if (crow.start.getY() == cells[i].getY()) {
12952 crow.end = cells[i];
12969 cells[0].events.push(ev);
12971 this.calevents.push(ev);
12974 clearEvents: function() {
12976 if(!this.calevents){
12980 Roo.each(this.cells.elements, function(c){
12986 Roo.each(this.calevents, function(e) {
12987 Roo.each(e.els, function(el) {
12988 el.un('mouseenter' ,this.onEventEnter, this);
12989 el.un('mouseleave' ,this.onEventLeave, this);
12994 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13000 renderEvents: function()
13004 this.cells.each(function(c) {
13013 if(c.row != c.events.length){
13014 r = 4 - (4 - (c.row - c.events.length));
13017 c.events = ev.slice(0, r);
13018 c.more = ev.slice(r);
13020 if(c.more.length && c.more.length == 1){
13021 c.events.push(c.more.pop());
13024 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13028 this.cells.each(function(c) {
13030 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13033 for (var e = 0; e < c.events.length; e++){
13034 var ev = c.events[e];
13035 var rows = ev.rows;
13037 for(var i = 0; i < rows.length; i++) {
13039 // how many rows should it span..
13042 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13043 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13045 unselectable : "on",
13048 cls: 'fc-event-inner',
13052 // cls: 'fc-event-time',
13053 // html : cells.length > 1 ? '' : ev.time
13057 cls: 'fc-event-title',
13058 html : String.format('{0}', ev.title)
13065 cls: 'ui-resizable-handle ui-resizable-e',
13066 html : '  '
13073 cfg.cls += ' fc-event-start';
13075 if ((i+1) == rows.length) {
13076 cfg.cls += ' fc-event-end';
13079 var ctr = _this.el.select('.fc-event-container',true).first();
13080 var cg = ctr.createChild(cfg);
13082 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13083 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13085 var r = (c.more.length) ? 1 : 0;
13086 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13087 cg.setWidth(ebox.right - sbox.x -2);
13089 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13090 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13091 cg.on('click', _this.onEventClick, _this, ev);
13102 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13103 style : 'position: absolute',
13104 unselectable : "on",
13107 cls: 'fc-event-inner',
13111 cls: 'fc-event-title',
13119 cls: 'ui-resizable-handle ui-resizable-e',
13120 html : '  '
13126 var ctr = _this.el.select('.fc-event-container',true).first();
13127 var cg = ctr.createChild(cfg);
13129 var sbox = c.select('.fc-day-content',true).first().getBox();
13130 var ebox = c.select('.fc-day-content',true).first().getBox();
13132 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13133 cg.setWidth(ebox.right - sbox.x -2);
13135 cg.on('click', _this.onMoreEventClick, _this, c.more);
13145 onEventEnter: function (e, el,event,d) {
13146 this.fireEvent('evententer', this, el, event);
13149 onEventLeave: function (e, el,event,d) {
13150 this.fireEvent('eventleave', this, el, event);
13153 onEventClick: function (e, el,event,d) {
13154 this.fireEvent('eventclick', this, el, event);
13157 onMonthChange: function () {
13161 onMoreEventClick: function(e, el, more)
13165 this.calpopover.placement = 'right';
13166 this.calpopover.setTitle('More');
13168 this.calpopover.setContent('');
13170 var ctr = this.calpopover.el.select('.popover-content', true).first();
13172 Roo.each(more, function(m){
13174 cls : 'fc-event-hori fc-event-draggable',
13177 var cg = ctr.createChild(cfg);
13179 cg.on('click', _this.onEventClick, _this, m);
13182 this.calpopover.show(el);
13187 onLoad: function ()
13189 this.calevents = [];
13192 if(this.store.getCount() > 0){
13193 this.store.data.each(function(d){
13196 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13197 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13198 time : d.data.start_time,
13199 title : d.data.title,
13200 description : d.data.description,
13201 venue : d.data.venue
13206 this.renderEvents();
13208 if(this.calevents.length && this.loadMask){
13209 this.maskEl.hide();
13213 onBeforeLoad: function()
13215 this.clearEvents();
13217 this.maskEl.show();
13231 * @class Roo.bootstrap.Popover
13232 * @extends Roo.bootstrap.Component
13233 * Bootstrap Popover class
13234 * @cfg {String} html contents of the popover (or false to use children..)
13235 * @cfg {String} title of popover (or false to hide)
13236 * @cfg {String} placement how it is placed
13237 * @cfg {String} trigger click || hover (or false to trigger manually)
13238 * @cfg {String} over what (parent or false to trigger manually.)
13241 * Create a new Popover
13242 * @param {Object} config The config object
13245 Roo.bootstrap.Popover = function(config){
13246 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13249 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13251 title: 'Fill in a title',
13254 placement : 'right',
13255 trigger : 'hover', // hover
13259 can_build_overlaid : false,
13261 getChildContainer : function()
13263 return this.el.select('.popover-content',true).first();
13266 getAutoCreate : function(){
13267 Roo.log('make popover?');
13269 cls : 'popover roo-dynamic',
13270 style: 'display:block',
13276 cls : 'popover-inner',
13280 cls: 'popover-title',
13284 cls : 'popover-content',
13295 setTitle: function(str)
13297 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13299 setContent: function(str)
13301 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13303 // as it get's added to the bottom of the page.
13304 onRender : function(ct, position)
13306 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13308 var cfg = Roo.apply({}, this.getAutoCreate());
13312 cfg.cls += ' ' + this.cls;
13315 cfg.style = this.style;
13317 Roo.log("adding to ")
13318 this.el = Roo.get(document.body).createChild(cfg, position);
13324 initEvents : function()
13326 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13327 this.el.enableDisplayMode('block');
13329 if (this.over === false) {
13332 if (this.triggers === false) {
13335 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13336 var triggers = this.trigger ? this.trigger.split(' ') : [];
13337 Roo.each(triggers, function(trigger) {
13339 if (trigger == 'click') {
13340 on_el.on('click', this.toggle, this);
13341 } else if (trigger != 'manual') {
13342 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13343 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13345 on_el.on(eventIn ,this.enter, this);
13346 on_el.on(eventOut, this.leave, this);
13357 toggle : function () {
13358 this.hoverState == 'in' ? this.leave() : this.enter();
13361 enter : function () {
13364 clearTimeout(this.timeout);
13366 this.hoverState = 'in'
13368 if (!this.delay || !this.delay.show) {
13373 this.timeout = setTimeout(function () {
13374 if (_t.hoverState == 'in') {
13377 }, this.delay.show)
13379 leave : function() {
13380 clearTimeout(this.timeout);
13382 this.hoverState = 'out'
13384 if (!this.delay || !this.delay.hide) {
13389 this.timeout = setTimeout(function () {
13390 if (_t.hoverState == 'out') {
13393 }, this.delay.hide)
13396 show : function (on_el)
13399 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13402 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13403 if (this.html !== false) {
13404 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13406 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13407 if (!this.title.length) {
13408 this.el.select('.popover-title',true).hide();
13411 var placement = typeof this.placement == 'function' ?
13412 this.placement.call(this, this.el, on_el) :
13415 var autoToken = /\s?auto?\s?/i;
13416 var autoPlace = autoToken.test(placement);
13418 placement = placement.replace(autoToken, '') || 'top';
13422 //this.el.setXY([0,0]);
13424 this.el.dom.style.display='block';
13425 this.el.addClass(placement);
13427 //this.el.appendTo(on_el);
13429 var p = this.getPosition();
13430 var box = this.el.getBox();
13435 var align = Roo.bootstrap.Popover.alignment[placement]
13436 this.el.alignTo(on_el, align[0],align[1]);
13437 //var arrow = this.el.select('.arrow',true).first();
13438 //arrow.set(align[2],
13440 this.el.addClass('in');
13441 this.hoverState = null;
13443 if (this.el.hasClass('fade')) {
13450 this.el.setXY([0,0]);
13451 this.el.removeClass('in');
13458 Roo.bootstrap.Popover.alignment = {
13459 'left' : ['r-l', [-10,0], 'right'],
13460 'right' : ['l-r', [10,0], 'left'],
13461 'bottom' : ['t-b', [0,10], 'top'],
13462 'top' : [ 'b-t', [0,-10], 'bottom']
13473 * @class Roo.bootstrap.Progress
13474 * @extends Roo.bootstrap.Component
13475 * Bootstrap Progress class
13476 * @cfg {Boolean} striped striped of the progress bar
13477 * @cfg {Boolean} active animated of the progress bar
13481 * Create a new Progress
13482 * @param {Object} config The config object
13485 Roo.bootstrap.Progress = function(config){
13486 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13489 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13494 getAutoCreate : function(){
13502 cfg.cls += ' progress-striped';
13506 cfg.cls += ' active';
13525 * @class Roo.bootstrap.ProgressBar
13526 * @extends Roo.bootstrap.Component
13527 * Bootstrap ProgressBar class
13528 * @cfg {Number} aria_valuenow aria-value now
13529 * @cfg {Number} aria_valuemin aria-value min
13530 * @cfg {Number} aria_valuemax aria-value max
13531 * @cfg {String} label label for the progress bar
13532 * @cfg {String} panel (success | info | warning | danger )
13533 * @cfg {String} role role of the progress bar
13534 * @cfg {String} sr_only text
13538 * Create a new ProgressBar
13539 * @param {Object} config The config object
13542 Roo.bootstrap.ProgressBar = function(config){
13543 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13546 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13550 aria_valuemax : 100,
13556 getAutoCreate : function()
13561 cls: 'progress-bar',
13562 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13574 cfg.role = this.role;
13577 if(this.aria_valuenow){
13578 cfg['aria-valuenow'] = this.aria_valuenow;
13581 if(this.aria_valuemin){
13582 cfg['aria-valuemin'] = this.aria_valuemin;
13585 if(this.aria_valuemax){
13586 cfg['aria-valuemax'] = this.aria_valuemax;
13589 if(this.label && !this.sr_only){
13590 cfg.html = this.label;
13594 cfg.cls += ' progress-bar-' + this.panel;
13600 update : function(aria_valuenow)
13602 this.aria_valuenow = aria_valuenow;
13604 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13619 * @class Roo.bootstrap.TabPanel
13620 * @extends Roo.bootstrap.Component
13621 * Bootstrap TabPanel class
13622 * @cfg {Boolean} active panel active
13623 * @cfg {String} html panel content
13624 * @cfg {String} tabId tab relate id
13625 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13629 * Create a new TabPanel
13630 * @param {Object} config The config object
13633 Roo.bootstrap.TabPanel = function(config){
13634 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13638 * Fires when the active status changes
13639 * @param {Roo.bootstrap.TabPanel} this
13640 * @param {Boolean} state the new state
13647 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13654 getAutoCreate : function(){
13658 html: this.html || ''
13662 cfg.cls += ' active';
13666 cfg.tabId = this.tabId;
13671 onRender : function(ct, position)
13673 // Roo.log("Call onRender: " + this.xtype);
13675 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13677 if (this.navId && this.tabId) {
13678 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13680 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13682 item.on('changed', function(item, state) {
13683 this.setActive(state);
13689 setActive: function(state)
13691 Roo.log("panel - set active " + this.tabId + "=" + state);
13693 this.active = state;
13695 this.el.removeClass('active');
13697 } else if (!this.el.hasClass('active')) {
13698 this.el.addClass('active');
13700 this.fireEvent('changed', this, state);
13717 * @class Roo.bootstrap.DateField
13718 * @extends Roo.bootstrap.Input
13719 * Bootstrap DateField class
13720 * @cfg {Number} weekStart default 0
13721 * @cfg {Number} weekStart default 0
13722 * @cfg {Number} viewMode default empty, (months|years)
13723 * @cfg {Number} minViewMode default empty, (months|years)
13724 * @cfg {Number} startDate default -Infinity
13725 * @cfg {Number} endDate default Infinity
13726 * @cfg {Boolean} todayHighlight default false
13727 * @cfg {Boolean} todayBtn default false
13728 * @cfg {Boolean} calendarWeeks default false
13729 * @cfg {Object} daysOfWeekDisabled default empty
13731 * @cfg {Boolean} keyboardNavigation default true
13732 * @cfg {String} language default en
13735 * Create a new DateField
13736 * @param {Object} config The config object
13739 Roo.bootstrap.DateField = function(config){
13740 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13744 * Fires when this field show.
13745 * @param {Roo.bootstrap.DateField} this
13746 * @param {Mixed} date The date value
13751 * Fires when this field hide.
13752 * @param {Roo.bootstrap.DateField} this
13753 * @param {Mixed} date The date value
13758 * Fires when select a date.
13759 * @param {Roo.bootstrap.DateField} this
13760 * @param {Mixed} date The date value
13766 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13769 * @cfg {String} format
13770 * The default date format string which can be overriden for localization support. The format must be
13771 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13775 * @cfg {String} altFormats
13776 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13777 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13779 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13787 todayHighlight : false,
13793 keyboardNavigation: true,
13795 calendarWeeks: false,
13797 startDate: -Infinity,
13801 daysOfWeekDisabled: [],
13805 UTCDate: function()
13807 return new Date(Date.UTC.apply(Date, arguments));
13810 UTCToday: function()
13812 var today = new Date();
13813 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13816 getDate: function() {
13817 var d = this.getUTCDate();
13818 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13821 getUTCDate: function() {
13825 setDate: function(d) {
13826 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13829 setUTCDate: function(d) {
13831 this.setValue(this.formatDate(this.date));
13834 onRender: function(ct, position)
13837 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13839 this.language = this.language || 'en';
13840 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13841 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13843 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13844 this.format = this.format || 'm/d/y';
13845 this.isInline = false;
13846 this.isInput = true;
13847 this.component = this.el.select('.add-on', true).first() || false;
13848 this.component = (this.component && this.component.length === 0) ? false : this.component;
13849 this.hasInput = this.component && this.inputEL().length;
13851 if (typeof(this.minViewMode === 'string')) {
13852 switch (this.minViewMode) {
13854 this.minViewMode = 1;
13857 this.minViewMode = 2;
13860 this.minViewMode = 0;
13865 if (typeof(this.viewMode === 'string')) {
13866 switch (this.viewMode) {
13879 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13881 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13883 this.picker().on('mousedown', this.onMousedown, this);
13884 this.picker().on('click', this.onClick, this);
13886 this.picker().addClass('datepicker-dropdown');
13888 this.startViewMode = this.viewMode;
13891 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13892 if(!this.calendarWeeks){
13897 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13898 v.attr('colspan', function(i, val){
13899 return parseInt(val) + 1;
13904 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13906 this.setStartDate(this.startDate);
13907 this.setEndDate(this.endDate);
13909 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13916 if(this.isInline) {
13921 picker : function()
13923 return this.el.select('.datepicker', true).first();
13926 fillDow: function()
13928 var dowCnt = this.weekStart;
13937 if(this.calendarWeeks){
13945 while (dowCnt < this.weekStart + 7) {
13949 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13953 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13956 fillMonths: function()
13959 var months = this.picker().select('>.datepicker-months td', true).first();
13961 months.dom.innerHTML = '';
13967 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13970 months.createChild(month);
13978 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13980 if (this.date < this.startDate) {
13981 this.viewDate = new Date(this.startDate);
13982 } else if (this.date > this.endDate) {
13983 this.viewDate = new Date(this.endDate);
13985 this.viewDate = new Date(this.date);
13993 var d = new Date(this.viewDate),
13994 year = d.getUTCFullYear(),
13995 month = d.getUTCMonth(),
13996 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13997 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13998 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13999 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14000 currentDate = this.date && this.date.valueOf(),
14001 today = this.UTCToday();
14003 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14005 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14007 // this.picker.select('>tfoot th.today').
14008 // .text(dates[this.language].today)
14009 // .toggle(this.todayBtn !== false);
14011 this.updateNavArrows();
14014 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14016 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14018 prevMonth.setUTCDate(day);
14020 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14022 var nextMonth = new Date(prevMonth);
14024 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14026 nextMonth = nextMonth.valueOf();
14028 var fillMonths = false;
14030 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14032 while(prevMonth.valueOf() < nextMonth) {
14035 if (prevMonth.getUTCDay() === this.weekStart) {
14037 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14045 if(this.calendarWeeks){
14046 // ISO 8601: First week contains first thursday.
14047 // ISO also states week starts on Monday, but we can be more abstract here.
14049 // Start of current week: based on weekstart/current date
14050 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14051 // Thursday of this week
14052 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14053 // First Thursday of year, year from thursday
14054 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14055 // Calendar week: ms between thursdays, div ms per day, div 7 days
14056 calWeek = (th - yth) / 864e5 / 7 + 1;
14058 fillMonths.cn.push({
14066 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14068 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14071 if (this.todayHighlight &&
14072 prevMonth.getUTCFullYear() == today.getFullYear() &&
14073 prevMonth.getUTCMonth() == today.getMonth() &&
14074 prevMonth.getUTCDate() == today.getDate()) {
14075 clsName += ' today';
14078 if (currentDate && prevMonth.valueOf() === currentDate) {
14079 clsName += ' active';
14082 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14083 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14084 clsName += ' disabled';
14087 fillMonths.cn.push({
14089 cls: 'day ' + clsName,
14090 html: prevMonth.getDate()
14093 prevMonth.setDate(prevMonth.getDate()+1);
14096 var currentYear = this.date && this.date.getUTCFullYear();
14097 var currentMonth = this.date && this.date.getUTCMonth();
14099 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14101 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14102 v.removeClass('active');
14104 if(currentYear === year && k === currentMonth){
14105 v.addClass('active');
14108 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14109 v.addClass('disabled');
14115 year = parseInt(year/10, 10) * 10;
14117 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14119 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14122 for (var i = -1; i < 11; i++) {
14123 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14125 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14133 showMode: function(dir)
14136 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14138 Roo.each(this.picker().select('>div',true).elements, function(v){
14139 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14142 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14147 if(this.isInline) return;
14149 this.picker().removeClass(['bottom', 'top']);
14151 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14153 * place to the top of element!
14157 this.picker().addClass('top');
14158 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14163 this.picker().addClass('bottom');
14165 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14168 parseDate : function(value)
14170 if(!value || value instanceof Date){
14173 var v = Date.parseDate(value, this.format);
14174 if (!v && this.useIso) {
14175 v = Date.parseDate(value, 'Y-m-d');
14177 if(!v && this.altFormats){
14178 if(!this.altFormatsArray){
14179 this.altFormatsArray = this.altFormats.split("|");
14181 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14182 v = Date.parseDate(value, this.altFormatsArray[i]);
14188 formatDate : function(date, fmt)
14190 return (!date || !(date instanceof Date)) ?
14191 date : date.dateFormat(fmt || this.format);
14194 onFocus : function()
14196 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14200 onBlur : function()
14202 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14204 var d = this.inputEl().getValue();
14215 this.picker().show();
14219 this.fireEvent('show', this, this.date);
14224 if(this.isInline) return;
14225 this.picker().hide();
14226 this.viewMode = this.startViewMode;
14229 this.fireEvent('hide', this, this.date);
14233 onMousedown: function(e)
14235 e.stopPropagation();
14236 e.preventDefault();
14241 Roo.bootstrap.DateField.superclass.keyup.call(this);
14245 setValue: function(v)
14247 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14249 var d = new Date(v);
14251 if(isNaN(d.getTime())){
14255 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14259 this.fireEvent('select', this, this.date);
14263 getValue: function()
14265 return this.formatDate(this.date);
14268 fireKey: function(e)
14270 if (!this.picker().isVisible()){
14271 if (e.keyCode == 27) // allow escape to hide and re-show picker
14275 var dateChanged = false,
14277 newDate, newViewDate;
14282 e.preventDefault();
14286 if (!this.keyboardNavigation) break;
14287 dir = e.keyCode == 37 ? -1 : 1;
14290 newDate = this.moveYear(this.date, dir);
14291 newViewDate = this.moveYear(this.viewDate, dir);
14292 } else if (e.shiftKey){
14293 newDate = this.moveMonth(this.date, dir);
14294 newViewDate = this.moveMonth(this.viewDate, dir);
14296 newDate = new Date(this.date);
14297 newDate.setUTCDate(this.date.getUTCDate() + dir);
14298 newViewDate = new Date(this.viewDate);
14299 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14301 if (this.dateWithinRange(newDate)){
14302 this.date = newDate;
14303 this.viewDate = newViewDate;
14304 this.setValue(this.formatDate(this.date));
14306 e.preventDefault();
14307 dateChanged = true;
14312 if (!this.keyboardNavigation) break;
14313 dir = e.keyCode == 38 ? -1 : 1;
14315 newDate = this.moveYear(this.date, dir);
14316 newViewDate = this.moveYear(this.viewDate, dir);
14317 } else if (e.shiftKey){
14318 newDate = this.moveMonth(this.date, dir);
14319 newViewDate = this.moveMonth(this.viewDate, dir);
14321 newDate = new Date(this.date);
14322 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14323 newViewDate = new Date(this.viewDate);
14324 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14326 if (this.dateWithinRange(newDate)){
14327 this.date = newDate;
14328 this.viewDate = newViewDate;
14329 this.setValue(this.formatDate(this.date));
14331 e.preventDefault();
14332 dateChanged = true;
14336 this.setValue(this.formatDate(this.date));
14338 e.preventDefault();
14341 this.setValue(this.formatDate(this.date));
14349 onClick: function(e)
14351 e.stopPropagation();
14352 e.preventDefault();
14354 var target = e.getTarget();
14356 if(target.nodeName.toLowerCase() === 'i'){
14357 target = Roo.get(target).dom.parentNode;
14360 var nodeName = target.nodeName;
14361 var className = target.className;
14362 var html = target.innerHTML;
14364 switch(nodeName.toLowerCase()) {
14366 switch(className) {
14372 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14373 switch(this.viewMode){
14375 this.viewDate = this.moveMonth(this.viewDate, dir);
14379 this.viewDate = this.moveYear(this.viewDate, dir);
14385 var date = new Date();
14386 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14388 this.setValue(this.formatDate(this.date));
14395 if (className.indexOf('disabled') === -1) {
14396 this.viewDate.setUTCDate(1);
14397 if (className.indexOf('month') !== -1) {
14398 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14400 var year = parseInt(html, 10) || 0;
14401 this.viewDate.setUTCFullYear(year);
14410 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14411 var day = parseInt(html, 10) || 1;
14412 var year = this.viewDate.getUTCFullYear(),
14413 month = this.viewDate.getUTCMonth();
14415 if (className.indexOf('old') !== -1) {
14422 } else if (className.indexOf('new') !== -1) {
14430 this.date = this.UTCDate(year, month, day,0,0,0,0);
14431 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14433 this.setValue(this.formatDate(this.date));
14440 setStartDate: function(startDate)
14442 this.startDate = startDate || -Infinity;
14443 if (this.startDate !== -Infinity) {
14444 this.startDate = this.parseDate(this.startDate);
14447 this.updateNavArrows();
14450 setEndDate: function(endDate)
14452 this.endDate = endDate || Infinity;
14453 if (this.endDate !== Infinity) {
14454 this.endDate = this.parseDate(this.endDate);
14457 this.updateNavArrows();
14460 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14462 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14463 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14464 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14466 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14467 return parseInt(d, 10);
14470 this.updateNavArrows();
14473 updateNavArrows: function()
14475 var d = new Date(this.viewDate),
14476 year = d.getUTCFullYear(),
14477 month = d.getUTCMonth();
14479 Roo.each(this.picker().select('.prev', true).elements, function(v){
14481 switch (this.viewMode) {
14484 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14490 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14497 Roo.each(this.picker().select('.next', true).elements, function(v){
14499 switch (this.viewMode) {
14502 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14508 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14516 moveMonth: function(date, dir)
14518 if (!dir) return date;
14519 var new_date = new Date(date.valueOf()),
14520 day = new_date.getUTCDate(),
14521 month = new_date.getUTCMonth(),
14522 mag = Math.abs(dir),
14524 dir = dir > 0 ? 1 : -1;
14527 // If going back one month, make sure month is not current month
14528 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14530 return new_date.getUTCMonth() == month;
14532 // If going forward one month, make sure month is as expected
14533 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14535 return new_date.getUTCMonth() != new_month;
14537 new_month = month + dir;
14538 new_date.setUTCMonth(new_month);
14539 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14540 if (new_month < 0 || new_month > 11)
14541 new_month = (new_month + 12) % 12;
14543 // For magnitudes >1, move one month at a time...
14544 for (var i=0; i<mag; i++)
14545 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14546 new_date = this.moveMonth(new_date, dir);
14547 // ...then reset the day, keeping it in the new month
14548 new_month = new_date.getUTCMonth();
14549 new_date.setUTCDate(day);
14551 return new_month != new_date.getUTCMonth();
14554 // Common date-resetting loop -- if date is beyond end of month, make it
14557 new_date.setUTCDate(--day);
14558 new_date.setUTCMonth(new_month);
14563 moveYear: function(date, dir)
14565 return this.moveMonth(date, dir*12);
14568 dateWithinRange: function(date)
14570 return date >= this.startDate && date <= this.endDate;
14576 this.picker().remove();
14581 Roo.apply(Roo.bootstrap.DateField, {
14592 html: '<i class="fa fa-arrow-left"/>'
14602 html: '<i class="fa fa-arrow-right"/>'
14644 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14645 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14646 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14647 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14648 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14661 navFnc: 'FullYear',
14666 navFnc: 'FullYear',
14671 Roo.apply(Roo.bootstrap.DateField, {
14675 cls: 'datepicker dropdown-menu',
14679 cls: 'datepicker-days',
14683 cls: 'table-condensed',
14685 Roo.bootstrap.DateField.head,
14689 Roo.bootstrap.DateField.footer
14696 cls: 'datepicker-months',
14700 cls: 'table-condensed',
14702 Roo.bootstrap.DateField.head,
14703 Roo.bootstrap.DateField.content,
14704 Roo.bootstrap.DateField.footer
14711 cls: 'datepicker-years',
14715 cls: 'table-condensed',
14717 Roo.bootstrap.DateField.head,
14718 Roo.bootstrap.DateField.content,
14719 Roo.bootstrap.DateField.footer
14738 * @class Roo.bootstrap.TimeField
14739 * @extends Roo.bootstrap.Input
14740 * Bootstrap DateField class
14744 * Create a new TimeField
14745 * @param {Object} config The config object
14748 Roo.bootstrap.TimeField = function(config){
14749 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14753 * Fires when this field show.
14754 * @param {Roo.bootstrap.DateField} this
14755 * @param {Mixed} date The date value
14760 * Fires when this field hide.
14761 * @param {Roo.bootstrap.DateField} this
14762 * @param {Mixed} date The date value
14767 * Fires when select a date.
14768 * @param {Roo.bootstrap.DateField} this
14769 * @param {Mixed} date The date value
14775 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14778 * @cfg {String} format
14779 * The default time format string which can be overriden for localization support. The format must be
14780 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14784 onRender: function(ct, position)
14787 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14789 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14791 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14793 this.pop = this.picker().select('>.datepicker-time',true).first();
14794 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14796 this.picker().on('mousedown', this.onMousedown, this);
14797 this.picker().on('click', this.onClick, this);
14799 this.picker().addClass('datepicker-dropdown');
14804 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14805 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14806 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14807 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14808 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14809 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14813 fireKey: function(e){
14814 if (!this.picker().isVisible()){
14815 if (e.keyCode == 27) // allow escape to hide and re-show picker
14820 e.preventDefault();
14828 this.onTogglePeriod();
14831 this.onIncrementMinutes();
14834 this.onDecrementMinutes();
14843 onClick: function(e) {
14844 e.stopPropagation();
14845 e.preventDefault();
14848 picker : function()
14850 return this.el.select('.datepicker', true).first();
14853 fillTime: function()
14855 var time = this.pop.select('tbody', true).first();
14857 time.dom.innerHTML = '';
14872 cls: 'hours-up glyphicon glyphicon-chevron-up'
14892 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14913 cls: 'timepicker-hour',
14928 cls: 'timepicker-minute',
14943 cls: 'btn btn-primary period',
14965 cls: 'hours-down glyphicon glyphicon-chevron-down'
14985 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15003 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15010 var hours = this.time.getHours();
15011 var minutes = this.time.getMinutes();
15024 hours = hours - 12;
15028 hours = '0' + hours;
15032 minutes = '0' + minutes;
15035 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15036 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15037 this.pop.select('button', true).first().dom.innerHTML = period;
15043 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15045 var cls = ['bottom'];
15047 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15054 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15059 this.picker().addClass(cls.join('-'));
15063 Roo.each(cls, function(c){
15065 _this.picker().setTop(_this.inputEl().getHeight());
15069 _this.picker().setTop(0 - _this.picker().getHeight());
15074 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15078 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15085 onFocus : function()
15087 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15091 onBlur : function()
15093 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15099 this.picker().show();
15104 this.fireEvent('show', this, this.date);
15109 this.picker().hide();
15112 this.fireEvent('hide', this, this.date);
15115 setTime : function()
15118 this.setValue(this.time.format(this.format));
15120 this.fireEvent('select', this, this.date);
15125 onMousedown: function(e){
15126 e.stopPropagation();
15127 e.preventDefault();
15130 onIncrementHours: function()
15132 Roo.log('onIncrementHours');
15133 this.time = this.time.add(Date.HOUR, 1);
15138 onDecrementHours: function()
15140 Roo.log('onDecrementHours');
15141 this.time = this.time.add(Date.HOUR, -1);
15145 onIncrementMinutes: function()
15147 Roo.log('onIncrementMinutes');
15148 this.time = this.time.add(Date.MINUTE, 1);
15152 onDecrementMinutes: function()
15154 Roo.log('onDecrementMinutes');
15155 this.time = this.time.add(Date.MINUTE, -1);
15159 onTogglePeriod: function()
15161 Roo.log('onTogglePeriod');
15162 this.time = this.time.add(Date.HOUR, 12);
15169 Roo.apply(Roo.bootstrap.TimeField, {
15199 cls: 'btn btn-info ok',
15211 Roo.apply(Roo.bootstrap.TimeField, {
15215 cls: 'datepicker dropdown-menu',
15219 cls: 'datepicker-time',
15223 cls: 'table-condensed',
15225 Roo.bootstrap.TimeField.content,
15226 Roo.bootstrap.TimeField.footer
15245 * @class Roo.bootstrap.CheckBox
15246 * @extends Roo.bootstrap.Input
15247 * Bootstrap CheckBox class
15249 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15250 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15251 * @cfg {String} boxLabel The text that appears beside the checkbox
15252 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15253 * @cfg {Boolean} checked initnal the element
15257 * Create a new CheckBox
15258 * @param {Object} config The config object
15261 Roo.bootstrap.CheckBox = function(config){
15262 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15267 * Fires when the element is checked or unchecked.
15268 * @param {Roo.bootstrap.CheckBox} this This input
15269 * @param {Boolean} checked The new checked value
15275 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15277 inputType: 'checkbox',
15284 getAutoCreate : function()
15286 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15292 cfg.cls = 'form-group checkbox' //input-group
15300 type : this.inputType,
15301 value : (!this.checked) ? this.valueOff : this.inputValue,
15302 cls : 'roo-checkbox', //'form-box',
15303 placeholder : this.placeholder || ''
15307 if (this.weight) { // Validity check?
15308 cfg.cls += " checkbox-" + this.weight;
15311 if (this.disabled) {
15312 input.disabled=true;
15316 input.checked = this.checked;
15320 input.name = this.name;
15324 input.cls += ' input-' + this.size;
15328 ['xs','sm','md','lg'].map(function(size){
15329 if (settings[size]) {
15330 cfg.cls += ' col-' + size + '-' + settings[size];
15336 var inputblock = input;
15341 if (this.before || this.after) {
15344 cls : 'input-group',
15348 inputblock.cn.push({
15350 cls : 'input-group-addon',
15354 inputblock.cn.push(input);
15356 inputblock.cn.push({
15358 cls : 'input-group-addon',
15365 if (align ==='left' && this.fieldLabel.length) {
15366 Roo.log("left and has label");
15372 cls : 'control-label col-md-' + this.labelWidth,
15373 html : this.fieldLabel
15377 cls : "col-md-" + (12 - this.labelWidth),
15384 } else if ( this.fieldLabel.length) {
15389 tag: this.boxLabel ? 'span' : 'label',
15391 cls: 'control-label box-input-label',
15392 //cls : 'input-group-addon',
15393 html : this.fieldLabel
15403 Roo.log(" no label && no align");
15404 cfg.cn = [ inputblock ] ;
15413 html: this.boxLabel
15425 * return the real input element.
15427 inputEl: function ()
15429 return this.el.select('input.roo-checkbox',true).first();
15434 return this.el.select('label.control-label',true).first();
15437 initEvents : function()
15439 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15441 this.inputEl().on('click', this.onClick, this);
15445 onClick : function()
15447 this.setChecked(!this.checked);
15450 setChecked : function(state,suppressEvent)
15452 this.checked = state;
15454 this.inputEl().dom.checked = state;
15456 if(suppressEvent !== true){
15457 this.fireEvent('check', this, state);
15460 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15464 setValue : function(v,suppressEvent)
15466 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15480 * @class Roo.bootstrap.Radio
15481 * @extends Roo.bootstrap.CheckBox
15482 * Bootstrap Radio class
15485 * Create a new Radio
15486 * @param {Object} config The config object
15489 Roo.bootstrap.Radio = function(config){
15490 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15494 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15496 inputType: 'radio',
15500 getAutoCreate : function()
15502 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15508 cfg.cls = 'form-group radio' //input-group
15513 type : this.inputType,
15514 value : (!this.checked) ? this.valueOff : this.inputValue,
15516 placeholder : this.placeholder || ''
15519 if (this.weight) { // Validity check?
15520 cfg.cls += " radio-" + this.weight;
15522 if (this.disabled) {
15523 input.disabled=true;
15527 input.checked = this.checked;
15531 input.name = this.name;
15535 input.cls += ' input-' + this.size;
15539 ['xs','sm','md','lg'].map(function(size){
15540 if (settings[size]) {
15541 cfg.cls += ' col-' + size + '-' + settings[size];
15545 var inputblock = input;
15547 if (this.before || this.after) {
15550 cls : 'input-group',
15554 inputblock.cn.push({
15556 cls : 'input-group-addon',
15560 inputblock.cn.push(input);
15562 inputblock.cn.push({
15564 cls : 'input-group-addon',
15571 if (align ==='left' && this.fieldLabel.length) {
15572 Roo.log("left and has label");
15578 cls : 'control-label col-md-' + this.labelWidth,
15579 html : this.fieldLabel
15583 cls : "col-md-" + (12 - this.labelWidth),
15590 } else if ( this.fieldLabel.length) {
15597 cls: 'control-label box-input-label',
15598 //cls : 'input-group-addon',
15599 html : this.fieldLabel
15609 Roo.log(" no label && no align");
15624 html: this.boxLabel
15631 inputEl: function ()
15633 return this.el.select('input.roo-radio',true).first();
15635 onClick : function()
15637 this.setChecked(true);
15640 setChecked : function(state,suppressEvent)
15643 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15644 v.dom.checked = false;
15648 this.checked = state;
15649 this.inputEl().dom.checked = state;
15651 if(suppressEvent !== true){
15652 this.fireEvent('check', this, state);
15655 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15659 getGroupValue : function()
15662 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15663 if(v.dom.checked == true){
15664 value = v.dom.value;
15672 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15673 * @return {Mixed} value The field value
15675 getValue : function(){
15676 return this.getGroupValue();
15682 //<script type="text/javascript">
15685 * Based Ext JS Library 1.1.1
15686 * Copyright(c) 2006-2007, Ext JS, LLC.
15692 * @class Roo.HtmlEditorCore
15693 * @extends Roo.Component
15694 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15696 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15699 Roo.HtmlEditorCore = function(config){
15702 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15705 * @event initialize
15706 * Fires when the editor is fully initialized (including the iframe)
15707 * @param {Roo.HtmlEditorCore} this
15712 * Fires when the editor is first receives the focus. Any insertion must wait
15713 * until after this event.
15714 * @param {Roo.HtmlEditorCore} this
15718 * @event beforesync
15719 * Fires before the textarea is updated with content from the editor iframe. Return false
15720 * to cancel the sync.
15721 * @param {Roo.HtmlEditorCore} this
15722 * @param {String} html
15726 * @event beforepush
15727 * Fires before the iframe editor is updated with content from the textarea. Return false
15728 * to cancel the push.
15729 * @param {Roo.HtmlEditorCore} this
15730 * @param {String} html
15735 * Fires when the textarea is updated with content from the editor iframe.
15736 * @param {Roo.HtmlEditorCore} this
15737 * @param {String} html
15742 * Fires when the iframe editor is updated with content from the textarea.
15743 * @param {Roo.HtmlEditorCore} this
15744 * @param {String} html
15749 * @event editorevent
15750 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15751 * @param {Roo.HtmlEditorCore} this
15759 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15763 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15769 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15774 * @cfg {Number} height (in pixels)
15778 * @cfg {Number} width (in pixels)
15783 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15786 stylesheets: false,
15791 // private properties
15792 validationEvent : false,
15794 initialized : false,
15796 sourceEditMode : false,
15797 onFocus : Roo.emptyFn,
15799 hideMode:'offsets',
15807 * Protected method that will not generally be called directly. It
15808 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15809 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15811 getDocMarkup : function(){
15814 Roo.log(this.stylesheets);
15816 // inherit styels from page...??
15817 if (this.stylesheets === false) {
15819 Roo.get(document.head).select('style').each(function(node) {
15820 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15823 Roo.get(document.head).select('link').each(function(node) {
15824 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15827 } else if (!this.stylesheets.length) {
15829 st = '<style type="text/css">' +
15830 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15833 Roo.each(this.stylesheets, function(s) {
15834 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15839 st += '<style type="text/css">' +
15840 'IMG { cursor: pointer } ' +
15844 return '<html><head>' + st +
15845 //<style type="text/css">' +
15846 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15848 ' </head><body class="roo-htmleditor-body"></body></html>';
15852 onRender : function(ct, position)
15855 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15856 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15859 this.el.dom.style.border = '0 none';
15860 this.el.dom.setAttribute('tabIndex', -1);
15861 this.el.addClass('x-hidden hide');
15865 if(Roo.isIE){ // fix IE 1px bogus margin
15866 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15870 this.frameId = Roo.id();
15874 var iframe = this.owner.wrap.createChild({
15876 cls: 'form-control', // bootstrap..
15878 name: this.frameId,
15879 frameBorder : 'no',
15880 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15885 this.iframe = iframe.dom;
15887 this.assignDocWin();
15889 this.doc.designMode = 'on';
15892 this.doc.write(this.getDocMarkup());
15896 var task = { // must defer to wait for browser to be ready
15898 //console.log("run task?" + this.doc.readyState);
15899 this.assignDocWin();
15900 if(this.doc.body || this.doc.readyState == 'complete'){
15902 this.doc.designMode="on";
15906 Roo.TaskMgr.stop(task);
15907 this.initEditor.defer(10, this);
15914 Roo.TaskMgr.start(task);
15921 onResize : function(w, h)
15923 Roo.log('resize: ' +w + ',' + h );
15924 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15928 if(typeof w == 'number'){
15930 this.iframe.style.width = w + 'px';
15932 if(typeof h == 'number'){
15934 this.iframe.style.height = h + 'px';
15936 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15943 * Toggles the editor between standard and source edit mode.
15944 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15946 toggleSourceEdit : function(sourceEditMode){
15948 this.sourceEditMode = sourceEditMode === true;
15950 if(this.sourceEditMode){
15952 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15955 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15956 //this.iframe.className = '';
15959 //this.setSize(this.owner.wrap.getSize());
15960 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15967 * Protected method that will not generally be called directly. If you need/want
15968 * custom HTML cleanup, this is the method you should override.
15969 * @param {String} html The HTML to be cleaned
15970 * return {String} The cleaned HTML
15972 cleanHtml : function(html){
15973 html = String(html);
15974 if(html.length > 5){
15975 if(Roo.isSafari){ // strip safari nonsense
15976 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15979 if(html == ' '){
15986 * HTML Editor -> Textarea
15987 * Protected method that will not generally be called directly. Syncs the contents
15988 * of the editor iframe with the textarea.
15990 syncValue : function(){
15991 if(this.initialized){
15992 var bd = (this.doc.body || this.doc.documentElement);
15993 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15994 var html = bd.innerHTML;
15996 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15997 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15999 html = '<div style="'+m[0]+'">' + html + '</div>';
16002 html = this.cleanHtml(html);
16003 // fix up the special chars.. normaly like back quotes in word...
16004 // however we do not want to do this with chinese..
16005 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16006 var cc = b.charCodeAt();
16008 (cc >= 0x4E00 && cc < 0xA000 ) ||
16009 (cc >= 0x3400 && cc < 0x4E00 ) ||
16010 (cc >= 0xf900 && cc < 0xfb00 )
16016 if(this.owner.fireEvent('beforesync', this, html) !== false){
16017 this.el.dom.value = html;
16018 this.owner.fireEvent('sync', this, html);
16024 * Protected method that will not generally be called directly. Pushes the value of the textarea
16025 * into the iframe editor.
16027 pushValue : function(){
16028 if(this.initialized){
16029 var v = this.el.dom.value.trim();
16031 // if(v.length < 1){
16035 if(this.owner.fireEvent('beforepush', this, v) !== false){
16036 var d = (this.doc.body || this.doc.documentElement);
16038 this.cleanUpPaste();
16039 this.el.dom.value = d.innerHTML;
16040 this.owner.fireEvent('push', this, v);
16046 deferFocus : function(){
16047 this.focus.defer(10, this);
16051 focus : function(){
16052 if(this.win && !this.sourceEditMode){
16059 assignDocWin: function()
16061 var iframe = this.iframe;
16064 this.doc = iframe.contentWindow.document;
16065 this.win = iframe.contentWindow;
16067 if (!Roo.get(this.frameId)) {
16070 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16071 this.win = Roo.get(this.frameId).dom.contentWindow;
16076 initEditor : function(){
16077 //console.log("INIT EDITOR");
16078 this.assignDocWin();
16082 this.doc.designMode="on";
16084 this.doc.write(this.getDocMarkup());
16087 var dbody = (this.doc.body || this.doc.documentElement);
16088 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16089 // this copies styles from the containing element into thsi one..
16090 // not sure why we need all of this..
16091 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16093 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16094 //ss['background-attachment'] = 'fixed'; // w3c
16095 dbody.bgProperties = 'fixed'; // ie
16096 //Roo.DomHelper.applyStyles(dbody, ss);
16097 Roo.EventManager.on(this.doc, {
16098 //'mousedown': this.onEditorEvent,
16099 'mouseup': this.onEditorEvent,
16100 'dblclick': this.onEditorEvent,
16101 'click': this.onEditorEvent,
16102 'keyup': this.onEditorEvent,
16107 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16109 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16110 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16112 this.initialized = true;
16114 this.owner.fireEvent('initialize', this);
16119 onDestroy : function(){
16125 //for (var i =0; i < this.toolbars.length;i++) {
16126 // // fixme - ask toolbars for heights?
16127 // this.toolbars[i].onDestroy();
16130 //this.wrap.dom.innerHTML = '';
16131 //this.wrap.remove();
16136 onFirstFocus : function(){
16138 this.assignDocWin();
16141 this.activated = true;
16144 if(Roo.isGecko){ // prevent silly gecko errors
16146 var s = this.win.getSelection();
16147 if(!s.focusNode || s.focusNode.nodeType != 3){
16148 var r = s.getRangeAt(0);
16149 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16154 this.execCmd('useCSS', true);
16155 this.execCmd('styleWithCSS', false);
16158 this.owner.fireEvent('activate', this);
16162 adjustFont: function(btn){
16163 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16164 //if(Roo.isSafari){ // safari
16167 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16168 if(Roo.isSafari){ // safari
16169 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16170 v = (v < 10) ? 10 : v;
16171 v = (v > 48) ? 48 : v;
16172 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16177 v = Math.max(1, v+adjust);
16179 this.execCmd('FontSize', v );
16182 onEditorEvent : function(e){
16183 this.owner.fireEvent('editorevent', this, e);
16184 // this.updateToolbar();
16185 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16188 insertTag : function(tg)
16190 // could be a bit smarter... -> wrap the current selected tRoo..
16191 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16193 range = this.createRange(this.getSelection());
16194 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16195 wrappingNode.appendChild(range.extractContents());
16196 range.insertNode(wrappingNode);
16203 this.execCmd("formatblock", tg);
16207 insertText : function(txt)
16211 var range = this.createRange();
16212 range.deleteContents();
16213 //alert(Sender.getAttribute('label'));
16215 range.insertNode(this.doc.createTextNode(txt));
16221 * Executes a Midas editor command on the editor document and performs necessary focus and
16222 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16223 * @param {String} cmd The Midas command
16224 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16226 relayCmd : function(cmd, value){
16228 this.execCmd(cmd, value);
16229 this.owner.fireEvent('editorevent', this);
16230 //this.updateToolbar();
16231 this.owner.deferFocus();
16235 * Executes a Midas editor command directly on the editor document.
16236 * For visual commands, you should use {@link #relayCmd} instead.
16237 * <b>This should only be called after the editor is initialized.</b>
16238 * @param {String} cmd The Midas command
16239 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16241 execCmd : function(cmd, value){
16242 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16249 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16251 * @param {String} text | dom node..
16253 insertAtCursor : function(text)
16258 if(!this.activated){
16264 var r = this.doc.selection.createRange();
16275 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16279 // from jquery ui (MIT licenced)
16281 var win = this.win;
16283 if (win.getSelection && win.getSelection().getRangeAt) {
16284 range = win.getSelection().getRangeAt(0);
16285 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16286 range.insertNode(node);
16287 } else if (win.document.selection && win.document.selection.createRange) {
16288 // no firefox support
16289 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16290 win.document.selection.createRange().pasteHTML(txt);
16292 // no firefox support
16293 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16294 this.execCmd('InsertHTML', txt);
16303 mozKeyPress : function(e){
16305 var c = e.getCharCode(), cmd;
16308 c = String.fromCharCode(c).toLowerCase();
16322 this.cleanUpPaste.defer(100, this);
16330 e.preventDefault();
16338 fixKeys : function(){ // load time branching for fastest keydown performance
16340 return function(e){
16341 var k = e.getKey(), r;
16344 r = this.doc.selection.createRange();
16347 r.pasteHTML('    ');
16354 r = this.doc.selection.createRange();
16356 var target = r.parentElement();
16357 if(!target || target.tagName.toLowerCase() != 'li'){
16359 r.pasteHTML('<br />');
16365 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16366 this.cleanUpPaste.defer(100, this);
16372 }else if(Roo.isOpera){
16373 return function(e){
16374 var k = e.getKey();
16378 this.execCmd('InsertHTML','    ');
16381 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16382 this.cleanUpPaste.defer(100, this);
16387 }else if(Roo.isSafari){
16388 return function(e){
16389 var k = e.getKey();
16393 this.execCmd('InsertText','\t');
16397 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16398 this.cleanUpPaste.defer(100, this);
16406 getAllAncestors: function()
16408 var p = this.getSelectedNode();
16411 a.push(p); // push blank onto stack..
16412 p = this.getParentElement();
16416 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16420 a.push(this.doc.body);
16424 lastSelNode : false,
16427 getSelection : function()
16429 this.assignDocWin();
16430 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16433 getSelectedNode: function()
16435 // this may only work on Gecko!!!
16437 // should we cache this!!!!
16442 var range = this.createRange(this.getSelection()).cloneRange();
16445 var parent = range.parentElement();
16447 var testRange = range.duplicate();
16448 testRange.moveToElementText(parent);
16449 if (testRange.inRange(range)) {
16452 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16455 parent = parent.parentElement;
16460 // is ancestor a text element.
16461 var ac = range.commonAncestorContainer;
16462 if (ac.nodeType == 3) {
16463 ac = ac.parentNode;
16466 var ar = ac.childNodes;
16469 var other_nodes = [];
16470 var has_other_nodes = false;
16471 for (var i=0;i<ar.length;i++) {
16472 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16475 // fullly contained node.
16477 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16482 // probably selected..
16483 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16484 other_nodes.push(ar[i]);
16488 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16493 has_other_nodes = true;
16495 if (!nodes.length && other_nodes.length) {
16496 nodes= other_nodes;
16498 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16504 createRange: function(sel)
16506 // this has strange effects when using with
16507 // top toolbar - not sure if it's a great idea.
16508 //this.editor.contentWindow.focus();
16509 if (typeof sel != "undefined") {
16511 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16513 return this.doc.createRange();
16516 return this.doc.createRange();
16519 getParentElement: function()
16522 this.assignDocWin();
16523 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16525 var range = this.createRange(sel);
16528 var p = range.commonAncestorContainer;
16529 while (p.nodeType == 3) { // text node
16540 * Range intersection.. the hard stuff...
16544 * [ -- selected range --- ]
16548 * if end is before start or hits it. fail.
16549 * if start is after end or hits it fail.
16551 * if either hits (but other is outside. - then it's not
16557 // @see http://www.thismuchiknow.co.uk/?p=64.
16558 rangeIntersectsNode : function(range, node)
16560 var nodeRange = node.ownerDocument.createRange();
16562 nodeRange.selectNode(node);
16564 nodeRange.selectNodeContents(node);
16567 var rangeStartRange = range.cloneRange();
16568 rangeStartRange.collapse(true);
16570 var rangeEndRange = range.cloneRange();
16571 rangeEndRange.collapse(false);
16573 var nodeStartRange = nodeRange.cloneRange();
16574 nodeStartRange.collapse(true);
16576 var nodeEndRange = nodeRange.cloneRange();
16577 nodeEndRange.collapse(false);
16579 return rangeStartRange.compareBoundaryPoints(
16580 Range.START_TO_START, nodeEndRange) == -1 &&
16581 rangeEndRange.compareBoundaryPoints(
16582 Range.START_TO_START, nodeStartRange) == 1;
16586 rangeCompareNode : function(range, node)
16588 var nodeRange = node.ownerDocument.createRange();
16590 nodeRange.selectNode(node);
16592 nodeRange.selectNodeContents(node);
16596 range.collapse(true);
16598 nodeRange.collapse(true);
16600 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16601 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16603 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16605 var nodeIsBefore = ss == 1;
16606 var nodeIsAfter = ee == -1;
16608 if (nodeIsBefore && nodeIsAfter)
16610 if (!nodeIsBefore && nodeIsAfter)
16611 return 1; //right trailed.
16613 if (nodeIsBefore && !nodeIsAfter)
16614 return 2; // left trailed.
16619 // private? - in a new class?
16620 cleanUpPaste : function()
16622 // cleans up the whole document..
16623 Roo.log('cleanuppaste');
16625 this.cleanUpChildren(this.doc.body);
16626 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16627 if (clean != this.doc.body.innerHTML) {
16628 this.doc.body.innerHTML = clean;
16633 cleanWordChars : function(input) {// change the chars to hex code
16634 var he = Roo.HtmlEditorCore;
16636 var output = input;
16637 Roo.each(he.swapCodes, function(sw) {
16638 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16640 output = output.replace(swapper, sw[1]);
16647 cleanUpChildren : function (n)
16649 if (!n.childNodes.length) {
16652 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16653 this.cleanUpChild(n.childNodes[i]);
16660 cleanUpChild : function (node)
16663 //console.log(node);
16664 if (node.nodeName == "#text") {
16665 // clean up silly Windows -- stuff?
16668 if (node.nodeName == "#comment") {
16669 node.parentNode.removeChild(node);
16670 // clean up silly Windows -- stuff?
16674 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16676 node.parentNode.removeChild(node);
16681 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16683 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16684 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16686 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16687 // remove_keep_children = true;
16690 if (remove_keep_children) {
16691 this.cleanUpChildren(node);
16692 // inserts everything just before this node...
16693 while (node.childNodes.length) {
16694 var cn = node.childNodes[0];
16695 node.removeChild(cn);
16696 node.parentNode.insertBefore(cn, node);
16698 node.parentNode.removeChild(node);
16702 if (!node.attributes || !node.attributes.length) {
16703 this.cleanUpChildren(node);
16707 function cleanAttr(n,v)
16710 if (v.match(/^\./) || v.match(/^\//)) {
16713 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16716 if (v.match(/^#/)) {
16719 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16720 node.removeAttribute(n);
16724 function cleanStyle(n,v)
16726 if (v.match(/expression/)) { //XSS?? should we even bother..
16727 node.removeAttribute(n);
16730 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16731 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16734 var parts = v.split(/;/);
16737 Roo.each(parts, function(p) {
16738 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16742 var l = p.split(':').shift().replace(/\s+/g,'');
16743 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16745 if ( cblack.indexOf(l) > -1) {
16746 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16747 //node.removeAttribute(n);
16751 // only allow 'c whitelisted system attributes'
16752 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16753 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16754 //node.removeAttribute(n);
16764 if (clean.length) {
16765 node.setAttribute(n, clean.join(';'));
16767 node.removeAttribute(n);
16773 for (var i = node.attributes.length-1; i > -1 ; i--) {
16774 var a = node.attributes[i];
16777 if (a.name.toLowerCase().substr(0,2)=='on') {
16778 node.removeAttribute(a.name);
16781 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16782 node.removeAttribute(a.name);
16785 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16786 cleanAttr(a.name,a.value); // fixme..
16789 if (a.name == 'style') {
16790 cleanStyle(a.name,a.value);
16793 /// clean up MS crap..
16794 // tecnically this should be a list of valid class'es..
16797 if (a.name == 'class') {
16798 if (a.value.match(/^Mso/)) {
16799 node.className = '';
16802 if (a.value.match(/body/)) {
16803 node.className = '';
16814 this.cleanUpChildren(node);
16819 * Clean up MS wordisms...
16821 cleanWord : function(node)
16824 var cleanWordChildren = function()
16826 if (!node.childNodes.length) {
16829 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16830 _t.cleanWord(node.childNodes[i]);
16836 this.cleanWord(this.doc.body);
16839 if (node.nodeName == "#text") {
16840 // clean up silly Windows -- stuff?
16843 if (node.nodeName == "#comment") {
16844 node.parentNode.removeChild(node);
16845 // clean up silly Windows -- stuff?
16849 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16850 node.parentNode.removeChild(node);
16854 // remove - but keep children..
16855 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16856 while (node.childNodes.length) {
16857 var cn = node.childNodes[0];
16858 node.removeChild(cn);
16859 node.parentNode.insertBefore(cn, node);
16861 node.parentNode.removeChild(node);
16862 cleanWordChildren();
16866 if (node.className.length) {
16868 var cn = node.className.split(/\W+/);
16870 Roo.each(cn, function(cls) {
16871 if (cls.match(/Mso[a-zA-Z]+/)) {
16876 node.className = cna.length ? cna.join(' ') : '';
16878 node.removeAttribute("class");
16882 if (node.hasAttribute("lang")) {
16883 node.removeAttribute("lang");
16886 if (node.hasAttribute("style")) {
16888 var styles = node.getAttribute("style").split(";");
16890 Roo.each(styles, function(s) {
16891 if (!s.match(/:/)) {
16894 var kv = s.split(":");
16895 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16898 // what ever is left... we allow.
16901 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16902 if (!nstyle.length) {
16903 node.removeAttribute('style');
16907 cleanWordChildren();
16911 domToHTML : function(currentElement, depth, nopadtext) {
16913 depth = depth || 0;
16914 nopadtext = nopadtext || false;
16916 if (!currentElement) {
16917 return this.domToHTML(this.doc.body);
16920 //Roo.log(currentElement);
16922 var allText = false;
16923 var nodeName = currentElement.nodeName;
16924 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16926 if (nodeName == '#text') {
16927 return currentElement.nodeValue;
16932 if (nodeName != 'BODY') {
16935 // Prints the node tagName, such as <A>, <IMG>, etc
16938 for(i = 0; i < currentElement.attributes.length;i++) {
16940 var aname = currentElement.attributes.item(i).name;
16941 if (!currentElement.attributes.item(i).value.length) {
16944 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16947 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16956 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16959 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16964 // Traverse the tree
16966 var currentElementChild = currentElement.childNodes.item(i);
16967 var allText = true;
16968 var innerHTML = '';
16970 while (currentElementChild) {
16971 // Formatting code (indent the tree so it looks nice on the screen)
16972 var nopad = nopadtext;
16973 if (lastnode == 'SPAN') {
16977 if (currentElementChild.nodeName == '#text') {
16978 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16979 if (!nopad && toadd.length > 80) {
16980 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16982 innerHTML += toadd;
16985 currentElementChild = currentElement.childNodes.item(i);
16991 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16993 // Recursively traverse the tree structure of the child node
16994 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16995 lastnode = currentElementChild.nodeName;
16997 currentElementChild=currentElement.childNodes.item(i);
17003 // The remaining code is mostly for formatting the tree
17004 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17009 ret+= "</"+tagName+">";
17015 // hide stuff that is not compatible
17029 * @event specialkey
17033 * @cfg {String} fieldClass @hide
17036 * @cfg {String} focusClass @hide
17039 * @cfg {String} autoCreate @hide
17042 * @cfg {String} inputType @hide
17045 * @cfg {String} invalidClass @hide
17048 * @cfg {String} invalidText @hide
17051 * @cfg {String} msgFx @hide
17054 * @cfg {String} validateOnBlur @hide
17058 Roo.HtmlEditorCore.white = [
17059 'area', 'br', 'img', 'input', 'hr', 'wbr',
17061 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17062 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17063 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17064 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17065 'table', 'ul', 'xmp',
17067 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17070 'dir', 'menu', 'ol', 'ul', 'dl',
17076 Roo.HtmlEditorCore.black = [
17077 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17079 'base', 'basefont', 'bgsound', 'blink', 'body',
17080 'frame', 'frameset', 'head', 'html', 'ilayer',
17081 'iframe', 'layer', 'link', 'meta', 'object',
17082 'script', 'style' ,'title', 'xml' // clean later..
17084 Roo.HtmlEditorCore.clean = [
17085 'script', 'style', 'title', 'xml'
17087 Roo.HtmlEditorCore.remove = [
17092 Roo.HtmlEditorCore.ablack = [
17096 Roo.HtmlEditorCore.aclean = [
17097 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17101 Roo.HtmlEditorCore.pwhite= [
17102 'http', 'https', 'mailto'
17105 // white listed style attributes.
17106 Roo.HtmlEditorCore.cwhite= [
17107 // 'text-align', /// default is to allow most things..
17113 // black listed style attributes.
17114 Roo.HtmlEditorCore.cblack= [
17115 // 'font-size' -- this can be set by the project
17119 Roo.HtmlEditorCore.swapCodes =[
17138 * @class Roo.bootstrap.HtmlEditor
17139 * @extends Roo.bootstrap.TextArea
17140 * Bootstrap HtmlEditor class
17143 * Create a new HtmlEditor
17144 * @param {Object} config The config object
17147 Roo.bootstrap.HtmlEditor = function(config){
17148 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17149 if (!this.toolbars) {
17150 this.toolbars = [];
17152 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17155 * @event initialize
17156 * Fires when the editor is fully initialized (including the iframe)
17157 * @param {HtmlEditor} this
17162 * Fires when the editor is first receives the focus. Any insertion must wait
17163 * until after this event.
17164 * @param {HtmlEditor} this
17168 * @event beforesync
17169 * Fires before the textarea is updated with content from the editor iframe. Return false
17170 * to cancel the sync.
17171 * @param {HtmlEditor} this
17172 * @param {String} html
17176 * @event beforepush
17177 * Fires before the iframe editor is updated with content from the textarea. Return false
17178 * to cancel the push.
17179 * @param {HtmlEditor} this
17180 * @param {String} html
17185 * Fires when the textarea is updated with content from the editor iframe.
17186 * @param {HtmlEditor} this
17187 * @param {String} html
17192 * Fires when the iframe editor is updated with content from the textarea.
17193 * @param {HtmlEditor} this
17194 * @param {String} html
17198 * @event editmodechange
17199 * Fires when the editor switches edit modes
17200 * @param {HtmlEditor} this
17201 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17203 editmodechange: true,
17205 * @event editorevent
17206 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17207 * @param {HtmlEditor} this
17211 * @event firstfocus
17212 * Fires when on first focus - needed by toolbars..
17213 * @param {HtmlEditor} this
17218 * Auto save the htmlEditor value as a file into Events
17219 * @param {HtmlEditor} this
17223 * @event savedpreview
17224 * preview the saved version of htmlEditor
17225 * @param {HtmlEditor} this
17232 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17236 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17241 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17246 * @cfg {Number} height (in pixels)
17250 * @cfg {Number} width (in pixels)
17255 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17258 stylesheets: false,
17263 // private properties
17264 validationEvent : false,
17266 initialized : false,
17269 onFocus : Roo.emptyFn,
17271 hideMode:'offsets',
17274 tbContainer : false,
17276 toolbarContainer :function() {
17277 return this.wrap.select('.x-html-editor-tb',true).first();
17281 * Protected method that will not generally be called directly. It
17282 * is called when the editor creates its toolbar. Override this method if you need to
17283 * add custom toolbar buttons.
17284 * @param {HtmlEditor} editor
17286 createToolbar : function(){
17288 Roo.log("create toolbars");
17290 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17291 this.toolbars[0].render(this.toolbarContainer());
17295 // if (!editor.toolbars || !editor.toolbars.length) {
17296 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17299 // for (var i =0 ; i < editor.toolbars.length;i++) {
17300 // editor.toolbars[i] = Roo.factory(
17301 // typeof(editor.toolbars[i]) == 'string' ?
17302 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17303 // Roo.bootstrap.HtmlEditor);
17304 // editor.toolbars[i].init(editor);
17310 onRender : function(ct, position)
17312 // Roo.log("Call onRender: " + this.xtype);
17314 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17316 this.wrap = this.inputEl().wrap({
17317 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17320 this.editorcore.onRender(ct, position);
17322 if (this.resizable) {
17323 this.resizeEl = new Roo.Resizable(this.wrap, {
17327 minHeight : this.height,
17328 height: this.height,
17329 handles : this.resizable,
17332 resize : function(r, w, h) {
17333 _t.onResize(w,h); // -something
17339 this.createToolbar(this);
17342 if(!this.width && this.resizable){
17343 this.setSize(this.wrap.getSize());
17345 if (this.resizeEl) {
17346 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17347 // should trigger onReize..
17353 onResize : function(w, h)
17355 Roo.log('resize: ' +w + ',' + h );
17356 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17360 if(this.inputEl() ){
17361 if(typeof w == 'number'){
17362 var aw = w - this.wrap.getFrameWidth('lr');
17363 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17366 if(typeof h == 'number'){
17367 var tbh = -11; // fixme it needs to tool bar size!
17368 for (var i =0; i < this.toolbars.length;i++) {
17369 // fixme - ask toolbars for heights?
17370 tbh += this.toolbars[i].el.getHeight();
17371 //if (this.toolbars[i].footer) {
17372 // tbh += this.toolbars[i].footer.el.getHeight();
17380 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17381 ah -= 5; // knock a few pixes off for look..
17382 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17386 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17387 this.editorcore.onResize(ew,eh);
17392 * Toggles the editor between standard and source edit mode.
17393 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17395 toggleSourceEdit : function(sourceEditMode)
17397 this.editorcore.toggleSourceEdit(sourceEditMode);
17399 if(this.editorcore.sourceEditMode){
17400 Roo.log('editor - showing textarea');
17403 // Roo.log(this.syncValue());
17405 this.inputEl().removeClass(['hide', 'x-hidden']);
17406 this.inputEl().dom.removeAttribute('tabIndex');
17407 this.inputEl().focus();
17409 Roo.log('editor - hiding textarea');
17411 // Roo.log(this.pushValue());
17414 this.inputEl().addClass(['hide', 'x-hidden']);
17415 this.inputEl().dom.setAttribute('tabIndex', -1);
17416 //this.deferFocus();
17419 if(this.resizable){
17420 this.setSize(this.wrap.getSize());
17423 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17426 // private (for BoxComponent)
17427 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17429 // private (for BoxComponent)
17430 getResizeEl : function(){
17434 // private (for BoxComponent)
17435 getPositionEl : function(){
17440 initEvents : function(){
17441 this.originalValue = this.getValue();
17445 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17448 // markInvalid : Roo.emptyFn,
17450 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17453 // clearInvalid : Roo.emptyFn,
17455 setValue : function(v){
17456 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17457 this.editorcore.pushValue();
17462 deferFocus : function(){
17463 this.focus.defer(10, this);
17467 focus : function(){
17468 this.editorcore.focus();
17474 onDestroy : function(){
17480 for (var i =0; i < this.toolbars.length;i++) {
17481 // fixme - ask toolbars for heights?
17482 this.toolbars[i].onDestroy();
17485 this.wrap.dom.innerHTML = '';
17486 this.wrap.remove();
17491 onFirstFocus : function(){
17492 //Roo.log("onFirstFocus");
17493 this.editorcore.onFirstFocus();
17494 for (var i =0; i < this.toolbars.length;i++) {
17495 this.toolbars[i].onFirstFocus();
17501 syncValue : function()
17503 this.editorcore.syncValue();
17506 pushValue : function()
17508 this.editorcore.pushValue();
17512 // hide stuff that is not compatible
17526 * @event specialkey
17530 * @cfg {String} fieldClass @hide
17533 * @cfg {String} focusClass @hide
17536 * @cfg {String} autoCreate @hide
17539 * @cfg {String} inputType @hide
17542 * @cfg {String} invalidClass @hide
17545 * @cfg {String} invalidText @hide
17548 * @cfg {String} msgFx @hide
17551 * @cfg {String} validateOnBlur @hide
17560 Roo.namespace('Roo.bootstrap.htmleditor');
17562 * @class Roo.bootstrap.HtmlEditorToolbar1
17567 new Roo.bootstrap.HtmlEditor({
17570 new Roo.bootstrap.HtmlEditorToolbar1({
17571 disable : { fonts: 1 , format: 1, ..., ... , ...],
17577 * @cfg {Object} disable List of elements to disable..
17578 * @cfg {Array} btns List of additional buttons.
17582 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17585 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17588 Roo.apply(this, config);
17590 // default disabled, based on 'good practice'..
17591 this.disable = this.disable || {};
17592 Roo.applyIf(this.disable, {
17595 specialElements : true
17597 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17599 this.editor = config.editor;
17600 this.editorcore = config.editor.editorcore;
17602 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17604 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17605 // dont call parent... till later.
17607 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17612 editorcore : false,
17617 "h1","h2","h3","h4","h5","h6",
17619 "abbr", "acronym", "address", "cite", "samp", "var",
17623 onRender : function(ct, position)
17625 // Roo.log("Call onRender: " + this.xtype);
17627 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17629 this.el.dom.style.marginBottom = '0';
17631 var editorcore = this.editorcore;
17632 var editor= this.editor;
17635 var btn = function(id,cmd , toggle, handler){
17637 var event = toggle ? 'toggle' : 'click';
17642 xns: Roo.bootstrap,
17645 enableToggle:toggle !== false,
17647 pressed : toggle ? false : null,
17650 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17651 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17660 xns: Roo.bootstrap,
17661 glyphicon : 'font',
17665 xns: Roo.bootstrap,
17669 Roo.each(this.formats, function(f) {
17670 style.menu.items.push({
17672 xns: Roo.bootstrap,
17673 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17678 editorcore.insertTag(this.tagname);
17685 children.push(style);
17688 btn('bold',false,true);
17689 btn('italic',false,true);
17690 btn('align-left', 'justifyleft',true);
17691 btn('align-center', 'justifycenter',true);
17692 btn('align-right' , 'justifyright',true);
17693 btn('link', false, false, function(btn) {
17694 //Roo.log("create link?");
17695 var url = prompt(this.createLinkText, this.defaultLinkValue);
17696 if(url && url != 'http:/'+'/'){
17697 this.editorcore.relayCmd('createlink', url);
17700 btn('list','insertunorderedlist',true);
17701 btn('pencil', false,true, function(btn){
17704 this.toggleSourceEdit(btn.pressed);
17710 xns: Roo.bootstrap,
17715 xns: Roo.bootstrap,
17720 cog.menu.items.push({
17722 xns: Roo.bootstrap,
17723 html : Clean styles,
17728 editorcore.insertTag(this.tagname);
17737 this.xtype = 'NavSimplebar';
17739 for(var i=0;i< children.length;i++) {
17741 this.buttons.add(this.addxtypeChild(children[i]));
17745 editor.on('editorevent', this.updateToolbar, this);
17747 onBtnClick : function(id)
17749 this.editorcore.relayCmd(id);
17750 this.editorcore.focus();
17754 * Protected method that will not generally be called directly. It triggers
17755 * a toolbar update by reading the markup state of the current selection in the editor.
17757 updateToolbar: function(){
17759 if(!this.editorcore.activated){
17760 this.editor.onFirstFocus(); // is this neeed?
17764 var btns = this.buttons;
17765 var doc = this.editorcore.doc;
17766 btns.get('bold').setActive(doc.queryCommandState('bold'));
17767 btns.get('italic').setActive(doc.queryCommandState('italic'));
17768 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17770 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17771 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17772 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17774 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17775 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17778 var ans = this.editorcore.getAllAncestors();
17779 if (this.formatCombo) {
17782 var store = this.formatCombo.store;
17783 this.formatCombo.setValue("");
17784 for (var i =0; i < ans.length;i++) {
17785 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17787 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17795 // hides menus... - so this cant be on a menu...
17796 Roo.bootstrap.MenuMgr.hideAll();
17798 Roo.bootstrap.MenuMgr.hideAll();
17799 //this.editorsyncValue();
17801 onFirstFocus: function() {
17802 this.buttons.each(function(item){
17806 toggleSourceEdit : function(sourceEditMode){
17809 if(sourceEditMode){
17810 Roo.log("disabling buttons");
17811 this.buttons.each( function(item){
17812 if(item.cmd != 'pencil'){
17818 Roo.log("enabling buttons");
17819 if(this.editorcore.initialized){
17820 this.buttons.each( function(item){
17826 Roo.log("calling toggole on editor");
17827 // tell the editor that it's been pressed..
17828 this.editor.toggleSourceEdit(sourceEditMode);
17838 * @class Roo.bootstrap.Table.AbstractSelectionModel
17839 * @extends Roo.util.Observable
17840 * Abstract base class for grid SelectionModels. It provides the interface that should be
17841 * implemented by descendant classes. This class should not be directly instantiated.
17844 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17845 this.locked = false;
17846 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17850 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17851 /** @ignore Called by the grid automatically. Do not call directly. */
17852 init : function(grid){
17858 * Locks the selections.
17861 this.locked = true;
17865 * Unlocks the selections.
17867 unlock : function(){
17868 this.locked = false;
17872 * Returns true if the selections are locked.
17873 * @return {Boolean}
17875 isLocked : function(){
17876 return this.locked;
17880 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17881 * @class Roo.bootstrap.Table.RowSelectionModel
17882 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17883 * It supports multiple selections and keyboard selection/navigation.
17885 * @param {Object} config
17888 Roo.bootstrap.Table.RowSelectionModel = function(config){
17889 Roo.apply(this, config);
17890 this.selections = new Roo.util.MixedCollection(false, function(o){
17895 this.lastActive = false;
17899 * @event selectionchange
17900 * Fires when the selection changes
17901 * @param {SelectionModel} this
17903 "selectionchange" : true,
17905 * @event afterselectionchange
17906 * Fires after the selection changes (eg. by key press or clicking)
17907 * @param {SelectionModel} this
17909 "afterselectionchange" : true,
17911 * @event beforerowselect
17912 * Fires when a row is selected being selected, return false to cancel.
17913 * @param {SelectionModel} this
17914 * @param {Number} rowIndex The selected index
17915 * @param {Boolean} keepExisting False if other selections will be cleared
17917 "beforerowselect" : true,
17920 * Fires when a row is selected.
17921 * @param {SelectionModel} this
17922 * @param {Number} rowIndex The selected index
17923 * @param {Roo.data.Record} r The record
17925 "rowselect" : true,
17927 * @event rowdeselect
17928 * Fires when a row is deselected.
17929 * @param {SelectionModel} this
17930 * @param {Number} rowIndex The selected index
17932 "rowdeselect" : true
17934 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17935 this.locked = false;
17938 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17940 * @cfg {Boolean} singleSelect
17941 * True to allow selection of only one row at a time (defaults to false)
17943 singleSelect : false,
17946 initEvents : function(){
17948 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17949 this.grid.on("mousedown", this.handleMouseDown, this);
17950 }else{ // allow click to work like normal
17951 this.grid.on("rowclick", this.handleDragableRowClick, this);
17954 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17955 "up" : function(e){
17957 this.selectPrevious(e.shiftKey);
17958 }else if(this.last !== false && this.lastActive !== false){
17959 var last = this.last;
17960 this.selectRange(this.last, this.lastActive-1);
17961 this.grid.getView().focusRow(this.lastActive);
17962 if(last !== false){
17966 this.selectFirstRow();
17968 this.fireEvent("afterselectionchange", this);
17970 "down" : function(e){
17972 this.selectNext(e.shiftKey);
17973 }else if(this.last !== false && this.lastActive !== false){
17974 var last = this.last;
17975 this.selectRange(this.last, this.lastActive+1);
17976 this.grid.getView().focusRow(this.lastActive);
17977 if(last !== false){
17981 this.selectFirstRow();
17983 this.fireEvent("afterselectionchange", this);
17988 var view = this.grid.view;
17989 view.on("refresh", this.onRefresh, this);
17990 view.on("rowupdated", this.onRowUpdated, this);
17991 view.on("rowremoved", this.onRemove, this);
17995 onRefresh : function(){
17996 var ds = this.grid.dataSource, i, v = this.grid.view;
17997 var s = this.selections;
17998 s.each(function(r){
17999 if((i = ds.indexOfId(r.id)) != -1){
18008 onRemove : function(v, index, r){
18009 this.selections.remove(r);
18013 onRowUpdated : function(v, index, r){
18014 if(this.isSelected(r)){
18015 v.onRowSelect(index);
18021 * @param {Array} records The records to select
18022 * @param {Boolean} keepExisting (optional) True to keep existing selections
18024 selectRecords : function(records, keepExisting){
18026 this.clearSelections();
18028 var ds = this.grid.dataSource;
18029 for(var i = 0, len = records.length; i < len; i++){
18030 this.selectRow(ds.indexOf(records[i]), true);
18035 * Gets the number of selected rows.
18038 getCount : function(){
18039 return this.selections.length;
18043 * Selects the first row in the grid.
18045 selectFirstRow : function(){
18050 * Select the last row.
18051 * @param {Boolean} keepExisting (optional) True to keep existing selections
18053 selectLastRow : function(keepExisting){
18054 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18058 * Selects the row immediately following the last selected row.
18059 * @param {Boolean} keepExisting (optional) True to keep existing selections
18061 selectNext : function(keepExisting){
18062 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18063 this.selectRow(this.last+1, keepExisting);
18064 this.grid.getView().focusRow(this.last);
18069 * Selects the row that precedes the last selected row.
18070 * @param {Boolean} keepExisting (optional) True to keep existing selections
18072 selectPrevious : function(keepExisting){
18074 this.selectRow(this.last-1, keepExisting);
18075 this.grid.getView().focusRow(this.last);
18080 * Returns the selected records
18081 * @return {Array} Array of selected records
18083 getSelections : function(){
18084 return [].concat(this.selections.items);
18088 * Returns the first selected record.
18091 getSelected : function(){
18092 return this.selections.itemAt(0);
18097 * Clears all selections.
18099 clearSelections : function(fast){
18100 if(this.locked) return;
18102 var ds = this.grid.dataSource;
18103 var s = this.selections;
18104 s.each(function(r){
18105 this.deselectRow(ds.indexOfId(r.id));
18109 this.selections.clear();
18116 * Selects all rows.
18118 selectAll : function(){
18119 if(this.locked) return;
18120 this.selections.clear();
18121 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18122 this.selectRow(i, true);
18127 * Returns True if there is a selection.
18128 * @return {Boolean}
18130 hasSelection : function(){
18131 return this.selections.length > 0;
18135 * Returns True if the specified row is selected.
18136 * @param {Number/Record} record The record or index of the record to check
18137 * @return {Boolean}
18139 isSelected : function(index){
18140 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18141 return (r && this.selections.key(r.id) ? true : false);
18145 * Returns True if the specified record id is selected.
18146 * @param {String} id The id of record to check
18147 * @return {Boolean}
18149 isIdSelected : function(id){
18150 return (this.selections.key(id) ? true : false);
18154 handleMouseDown : function(e, t){
18155 var view = this.grid.getView(), rowIndex;
18156 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18159 if(e.shiftKey && this.last !== false){
18160 var last = this.last;
18161 this.selectRange(last, rowIndex, e.ctrlKey);
18162 this.last = last; // reset the last
18163 view.focusRow(rowIndex);
18165 var isSelected = this.isSelected(rowIndex);
18166 if(e.button !== 0 && isSelected){
18167 view.focusRow(rowIndex);
18168 }else if(e.ctrlKey && isSelected){
18169 this.deselectRow(rowIndex);
18170 }else if(!isSelected){
18171 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18172 view.focusRow(rowIndex);
18175 this.fireEvent("afterselectionchange", this);
18178 handleDragableRowClick : function(grid, rowIndex, e)
18180 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18181 this.selectRow(rowIndex, false);
18182 grid.view.focusRow(rowIndex);
18183 this.fireEvent("afterselectionchange", this);
18188 * Selects multiple rows.
18189 * @param {Array} rows Array of the indexes of the row to select
18190 * @param {Boolean} keepExisting (optional) True to keep existing selections
18192 selectRows : function(rows, keepExisting){
18194 this.clearSelections();
18196 for(var i = 0, len = rows.length; i < len; i++){
18197 this.selectRow(rows[i], true);
18202 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18203 * @param {Number} startRow The index of the first row in the range
18204 * @param {Number} endRow The index of the last row in the range
18205 * @param {Boolean} keepExisting (optional) True to retain existing selections
18207 selectRange : function(startRow, endRow, keepExisting){
18208 if(this.locked) return;
18210 this.clearSelections();
18212 if(startRow <= endRow){
18213 for(var i = startRow; i <= endRow; i++){
18214 this.selectRow(i, true);
18217 for(var i = startRow; i >= endRow; i--){
18218 this.selectRow(i, true);
18224 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18225 * @param {Number} startRow The index of the first row in the range
18226 * @param {Number} endRow The index of the last row in the range
18228 deselectRange : function(startRow, endRow, preventViewNotify){
18229 if(this.locked) return;
18230 for(var i = startRow; i <= endRow; i++){
18231 this.deselectRow(i, preventViewNotify);
18237 * @param {Number} row The index of the row to select
18238 * @param {Boolean} keepExisting (optional) True to keep existing selections
18240 selectRow : function(index, keepExisting, preventViewNotify){
18241 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18242 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18243 if(!keepExisting || this.singleSelect){
18244 this.clearSelections();
18246 var r = this.grid.dataSource.getAt(index);
18247 this.selections.add(r);
18248 this.last = this.lastActive = index;
18249 if(!preventViewNotify){
18250 this.grid.getView().onRowSelect(index);
18252 this.fireEvent("rowselect", this, index, r);
18253 this.fireEvent("selectionchange", this);
18259 * @param {Number} row The index of the row to deselect
18261 deselectRow : function(index, preventViewNotify){
18262 if(this.locked) return;
18263 if(this.last == index){
18266 if(this.lastActive == index){
18267 this.lastActive = false;
18269 var r = this.grid.dataSource.getAt(index);
18270 this.selections.remove(r);
18271 if(!preventViewNotify){
18272 this.grid.getView().onRowDeselect(index);
18274 this.fireEvent("rowdeselect", this, index);
18275 this.fireEvent("selectionchange", this);
18279 restoreLast : function(){
18281 this.last = this._last;
18286 acceptsNav : function(row, col, cm){
18287 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18291 onEditorKey : function(field, e){
18292 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18297 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18299 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18301 }else if(k == e.ENTER && !e.ctrlKey){
18305 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18307 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18309 }else if(k == e.ESC){
18313 g.startEditing(newCell[0], newCell[1]);
18318 * Ext JS Library 1.1.1
18319 * Copyright(c) 2006-2007, Ext JS, LLC.
18321 * Originally Released Under LGPL - original licence link has changed is not relivant.
18324 * <script type="text/javascript">
18328 * @class Roo.bootstrap.PagingToolbar
18330 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18332 * Create a new PagingToolbar
18333 * @param {Object} config The config object
18335 Roo.bootstrap.PagingToolbar = function(config)
18337 // old args format still supported... - xtype is prefered..
18338 // created from xtype...
18339 var ds = config.dataSource;
18340 this.toolbarItems = [];
18341 if (config.items) {
18342 this.toolbarItems = config.items;
18343 // config.items = [];
18346 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18353 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18357 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18359 * @cfg {Roo.data.Store} dataSource
18360 * The underlying data store providing the paged data
18363 * @cfg {String/HTMLElement/Element} container
18364 * container The id or element that will contain the toolbar
18367 * @cfg {Boolean} displayInfo
18368 * True to display the displayMsg (defaults to false)
18371 * @cfg {Number} pageSize
18372 * The number of records to display per page (defaults to 20)
18376 * @cfg {String} displayMsg
18377 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18379 displayMsg : 'Displaying {0} - {1} of {2}',
18381 * @cfg {String} emptyMsg
18382 * The message to display when no records are found (defaults to "No data to display")
18384 emptyMsg : 'No data to display',
18386 * Customizable piece of the default paging text (defaults to "Page")
18389 beforePageText : "Page",
18391 * Customizable piece of the default paging text (defaults to "of %0")
18394 afterPageText : "of {0}",
18396 * Customizable piece of the default paging text (defaults to "First Page")
18399 firstText : "First Page",
18401 * Customizable piece of the default paging text (defaults to "Previous Page")
18404 prevText : "Previous Page",
18406 * Customizable piece of the default paging text (defaults to "Next Page")
18409 nextText : "Next Page",
18411 * Customizable piece of the default paging text (defaults to "Last Page")
18414 lastText : "Last Page",
18416 * Customizable piece of the default paging text (defaults to "Refresh")
18419 refreshText : "Refresh",
18423 onRender : function(ct, position)
18425 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18426 this.navgroup.parentId = this.id;
18427 this.navgroup.onRender(this.el, null);
18428 // add the buttons to the navgroup
18430 if(this.displayInfo){
18431 Roo.log(this.el.select('ul.navbar-nav',true).first());
18432 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18433 this.displayEl = this.el.select('.x-paging-info', true).first();
18434 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18435 // this.displayEl = navel.el.select('span',true).first();
18441 Roo.each(_this.buttons, function(e){
18442 Roo.factory(e).onRender(_this.el, null);
18446 Roo.each(_this.toolbarItems, function(e) {
18447 _this.navgroup.addItem(e);
18450 this.first = this.navgroup.addItem({
18451 tooltip: this.firstText,
18453 icon : 'fa fa-backward',
18455 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18458 this.prev = this.navgroup.addItem({
18459 tooltip: this.prevText,
18461 icon : 'fa fa-step-backward',
18463 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18465 //this.addSeparator();
18468 var field = this.navgroup.addItem( {
18470 cls : 'x-paging-position',
18472 html : this.beforePageText +
18473 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18474 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18477 this.field = field.el.select('input', true).first();
18478 this.field.on("keydown", this.onPagingKeydown, this);
18479 this.field.on("focus", function(){this.dom.select();});
18482 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18483 //this.field.setHeight(18);
18484 //this.addSeparator();
18485 this.next = this.navgroup.addItem({
18486 tooltip: this.nextText,
18488 html : ' <i class="fa fa-step-forward">',
18490 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18492 this.last = this.navgroup.addItem({
18493 tooltip: this.lastText,
18494 icon : 'fa fa-forward',
18497 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18499 //this.addSeparator();
18500 this.loading = this.navgroup.addItem({
18501 tooltip: this.refreshText,
18502 icon: 'fa fa-refresh',
18504 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18510 updateInfo : function(){
18511 if(this.displayEl){
18512 var count = this.ds.getCount();
18513 var msg = count == 0 ?
18517 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18519 this.displayEl.update(msg);
18524 onLoad : function(ds, r, o){
18525 this.cursor = o.params ? o.params.start : 0;
18526 var d = this.getPageData(),
18530 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18531 this.field.dom.value = ap;
18532 this.first.setDisabled(ap == 1);
18533 this.prev.setDisabled(ap == 1);
18534 this.next.setDisabled(ap == ps);
18535 this.last.setDisabled(ap == ps);
18536 this.loading.enable();
18541 getPageData : function(){
18542 var total = this.ds.getTotalCount();
18545 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18546 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18551 onLoadError : function(){
18552 this.loading.enable();
18556 onPagingKeydown : function(e){
18557 var k = e.getKey();
18558 var d = this.getPageData();
18560 var v = this.field.dom.value, pageNum;
18561 if(!v || isNaN(pageNum = parseInt(v, 10))){
18562 this.field.dom.value = d.activePage;
18565 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18566 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18569 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
18571 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18572 this.field.dom.value = pageNum;
18573 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18576 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18578 var v = this.field.dom.value, pageNum;
18579 var increment = (e.shiftKey) ? 10 : 1;
18580 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18582 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18583 this.field.dom.value = d.activePage;
18586 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18588 this.field.dom.value = parseInt(v, 10) + increment;
18589 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18590 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18597 beforeLoad : function(){
18599 this.loading.disable();
18604 onClick : function(which){
18611 ds.load({params:{start: 0, limit: this.pageSize}});
18614 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18617 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18620 var total = ds.getTotalCount();
18621 var extra = total % this.pageSize;
18622 var lastStart = extra ? (total - extra) : total-this.pageSize;
18623 ds.load({params:{start: lastStart, limit: this.pageSize}});
18626 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18632 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18633 * @param {Roo.data.Store} store The data store to unbind
18635 unbind : function(ds){
18636 ds.un("beforeload", this.beforeLoad, this);
18637 ds.un("load", this.onLoad, this);
18638 ds.un("loadexception", this.onLoadError, this);
18639 ds.un("remove", this.updateInfo, this);
18640 ds.un("add", this.updateInfo, this);
18641 this.ds = undefined;
18645 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18646 * @param {Roo.data.Store} store The data store to bind
18648 bind : function(ds){
18649 ds.on("beforeload", this.beforeLoad, this);
18650 ds.on("load", this.onLoad, this);
18651 ds.on("loadexception", this.onLoadError, this);
18652 ds.on("remove", this.updateInfo, this);
18653 ds.on("add", this.updateInfo, this);
18664 * @class Roo.bootstrap.MessageBar
18665 * @extends Roo.bootstrap.Component
18666 * Bootstrap MessageBar class
18667 * @cfg {String} html contents of the MessageBar
18668 * @cfg {String} weight (info | success | warning | danger) default info
18669 * @cfg {String} beforeClass insert the bar before the given class
18670 * @cfg {Boolean} closable (true | false) default false
18671 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18674 * Create a new Element
18675 * @param {Object} config The config object
18678 Roo.bootstrap.MessageBar = function(config){
18679 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18682 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18688 beforeClass: 'bootstrap-sticky-wrap',
18690 getAutoCreate : function(){
18694 cls: 'alert alert-dismissable alert-' + this.weight,
18699 html: this.html || ''
18705 cfg.cls += ' alert-messages-fixed';
18719 onRender : function(ct, position)
18721 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18724 var cfg = Roo.apply({}, this.getAutoCreate());
18728 cfg.cls += ' ' + this.cls;
18731 cfg.style = this.style;
18733 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18735 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18738 this.el.select('>button.close').on('click', this.hide, this);
18744 if (!this.rendered) {
18750 this.fireEvent('show', this);
18756 if (!this.rendered) {
18762 this.fireEvent('hide', this);
18765 update : function()
18767 // var e = this.el.dom.firstChild;
18769 // if(this.closable){
18770 // e = e.nextSibling;
18773 // e.data = this.html || '';
18775 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18791 * @class Roo.bootstrap.Graph
18792 * @extends Roo.bootstrap.Component
18793 * Bootstrap Graph class
18797 @cfg {String} graphtype bar | vbar | pie
18798 @cfg {number} g_x coodinator | centre x (pie)
18799 @cfg {number} g_y coodinator | centre y (pie)
18800 @cfg {number} g_r radius (pie)
18801 @cfg {number} g_height height of the chart (respected by all elements in the set)
18802 @cfg {number} g_width width of the chart (respected by all elements in the set)
18803 @cfg {Object} title The title of the chart
18806 -opts (object) options for the chart
18808 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18809 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18811 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
18812 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18814 o stretch (boolean)
18816 -opts (object) options for the pie
18819 o startAngle (number)
18820 o endAngle (number)
18824 * Create a new Input
18825 * @param {Object} config The config object
18828 Roo.bootstrap.Graph = function(config){
18829 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18835 * The img click event for the img.
18836 * @param {Roo.EventObject} e
18842 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18853 //g_colors: this.colors,
18860 getAutoCreate : function(){
18871 onRender : function(ct,position){
18872 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18873 this.raphael = Raphael(this.el.dom);
18875 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18876 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18877 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18878 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18880 r.text(160, 10, "Single Series Chart").attr(txtattr);
18881 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18882 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18883 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18885 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18886 r.barchart(330, 10, 300, 220, data1);
18887 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18888 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18891 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18892 // r.barchart(30, 30, 560, 250, xdata, {
18893 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18894 // axis : "0 0 1 1",
18895 // axisxlabels : xdata
18896 // //yvalues : cols,
18899 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18901 // this.load(null,xdata,{
18902 // axis : "0 0 1 1",
18903 // axisxlabels : xdata
18908 load : function(graphtype,xdata,opts){
18909 this.raphael.clear();
18911 graphtype = this.graphtype;
18916 var r = this.raphael,
18917 fin = function () {
18918 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18920 fout = function () {
18921 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18923 pfin = function() {
18924 this.sector.stop();
18925 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18928 this.label[0].stop();
18929 this.label[0].attr({ r: 7.5 });
18930 this.label[1].attr({ "font-weight": 800 });
18933 pfout = function() {
18934 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18937 this.label[0].animate({ r: 5 }, 500, "bounce");
18938 this.label[1].attr({ "font-weight": 400 });
18944 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18947 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18950 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18951 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18953 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18960 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18965 setTitle: function(o)
18970 initEvents: function() {
18973 this.el.on('click', this.onClick, this);
18977 onClick : function(e)
18979 Roo.log('img onclick');
18980 this.fireEvent('click', this, e);
18992 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18995 * @class Roo.bootstrap.dash.NumberBox
18996 * @extends Roo.bootstrap.Component
18997 * Bootstrap NumberBox class
18998 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18999 * @cfg {String} headline Box headline
19000 * @cfg {String} content Box content
19001 * @cfg {String} icon Box icon
19002 * @cfg {String} footer Footer text
19003 * @cfg {String} fhref Footer href
19006 * Create a new NumberBox
19007 * @param {Object} config The config object
19011 Roo.bootstrap.dash.NumberBox = function(config){
19012 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19016 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19026 getAutoCreate : function(){
19030 cls : 'small-box bg-' + this.bgcolor,
19038 cls : 'roo-headline',
19039 html : this.headline
19043 cls : 'roo-content',
19044 html : this.content
19058 cls : 'ion ' + this.icon
19067 cls : 'small-box-footer',
19068 href : this.fhref || '#',
19072 cfg.cn.push(footer);
19079 onRender : function(ct,position){
19080 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19087 setHeadline: function (value)
19089 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19092 setFooter: function (value, href)
19094 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19097 this.el.select('a.small-box-footer',true).first().attr('href', href);
19102 setContent: function (value)
19104 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19107 initEvents: function()
19121 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19124 * @class Roo.bootstrap.dash.TabBox
19125 * @extends Roo.bootstrap.Component
19126 * Bootstrap TabBox class
19127 * @cfg {String} title Title of the TabBox
19128 * @cfg {String} icon Icon of the TabBox
19131 * Create a new TabBox
19132 * @param {Object} config The config object
19136 Roo.bootstrap.dash.TabBox = function(config){
19137 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19142 * When a pane is added
19143 * @param {Roo.bootstrap.dash.TabPane} pane
19150 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19155 getChildContainer : function()
19157 return this.el.select('.tab-content', true).first();
19160 getAutoCreate : function(){
19164 cls: 'pull-left header',
19172 cls: 'fa ' + this.icon
19179 cls: 'nav-tabs-custom',
19183 cls: 'nav nav-tabs pull-right',
19190 cls: 'tab-content no-padding',
19198 initEvents : function()
19200 //Roo.log('add add pane handler');
19201 this.on('addpane', this.onAddPane, this);
19204 * Updates the box title
19205 * @param {String} html to set the title to.
19207 setTitle : function(value)
19209 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19211 onAddPane : function(pane)
19213 //Roo.log('addpane');
19215 // tabs are rendere left to right..
19216 var ctr = this.el.select('.nav-tabs', true).first();
19219 var existing = ctr.select('.nav-tab',true);
19220 var qty = existing.getCount();;
19223 var tab = ctr.createChild({
19225 cls : 'nav-tab' + (qty ? '' : ' active'),
19233 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19236 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19238 pane.el.addClass('active');
19243 onTabClick : function(ev,un,ob,pane)
19245 //Roo.log('tab - prev default');
19246 ev.preventDefault();
19249 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19250 pane.tab.addClass('active');
19251 //Roo.log(pane.title);
19252 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19253 // technically we should have a deactivate event.. but maybe add later.
19254 // and it should not de-activate the selected tab...
19256 pane.el.addClass('active');
19257 pane.fireEvent('activate');
19272 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19274 * @class Roo.bootstrap.TabPane
19275 * @extends Roo.bootstrap.Component
19276 * Bootstrap TabPane class
19277 * @cfg {Boolean} active (false | true) Default false
19278 * @cfg {String} title title of panel
19282 * Create a new TabPane
19283 * @param {Object} config The config object
19286 Roo.bootstrap.dash.TabPane = function(config){
19287 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19291 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19296 // the tabBox that this is attached to.
19299 getAutoCreate : function()
19307 cfg.cls += ' active';
19312 initEvents : function()
19314 //Roo.log('trigger add pane handler');
19315 this.parent().fireEvent('addpane', this)
19319 * Updates the tab title
19320 * @param {String} html to set the title to.
19322 setTitle: function(str)
19328 this.tab.select('a'.true).first().dom.innerHTML = str;
19345 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19348 * @class Roo.bootstrap.menu.Menu
19349 * @extends Roo.bootstrap.Component
19350 * Bootstrap Menu class - container for Menu
19351 * @cfg {String} html Text of the menu
19352 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19353 * @cfg {String} icon Font awesome icon
19354 * @cfg {String} pos Menu align to (top | bottom) default bottom
19358 * Create a new Menu
19359 * @param {Object} config The config object
19363 Roo.bootstrap.menu.Menu = function(config){
19364 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19368 * @event beforeshow
19369 * Fires before this menu is displayed
19370 * @param {Roo.bootstrap.menu.Menu} this
19374 * @event beforehide
19375 * Fires before this menu is hidden
19376 * @param {Roo.bootstrap.menu.Menu} this
19381 * Fires after this menu is displayed
19382 * @param {Roo.bootstrap.menu.Menu} this
19387 * Fires after this menu is hidden
19388 * @param {Roo.bootstrap.menu.Menu} this
19393 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19394 * @param {Roo.bootstrap.menu.Menu} this
19395 * @param {Roo.EventObject} e
19402 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19406 weight : 'default',
19411 getChildContainer : function() {
19412 if(this.isSubMenu){
19416 return this.el.select('ul.dropdown-menu', true).first();
19419 getAutoCreate : function()
19424 cls : 'roo-menu-text',
19432 cls : 'fa ' + this.icon
19443 cls : 'dropdown-button btn btn-' + this.weight,
19448 cls : 'dropdown-toggle btn btn-' + this.weight,
19458 cls : 'dropdown-menu'
19464 if(this.pos == 'top'){
19465 cfg.cls += ' dropup';
19468 if(this.isSubMenu){
19471 cls : 'dropdown-menu'
19478 onRender : function(ct, position)
19480 this.isSubMenu = ct.hasClass('dropdown-submenu');
19482 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19485 initEvents : function()
19487 if(this.isSubMenu){
19491 this.hidden = true;
19493 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19494 this.triggerEl.on('click', this.onTriggerPress, this);
19496 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19497 this.buttonEl.on('click', this.onClick, this);
19503 if(this.isSubMenu){
19507 return this.el.select('ul.dropdown-menu', true).first();
19510 onClick : function(e)
19512 this.fireEvent("click", this, e);
19515 onTriggerPress : function(e)
19517 if (this.isVisible()) {
19524 isVisible : function(){
19525 return !this.hidden;
19530 this.fireEvent("beforeshow", this);
19532 this.hidden = false;
19533 this.el.addClass('open');
19535 Roo.get(document).on("mouseup", this.onMouseUp, this);
19537 this.fireEvent("show", this);
19544 this.fireEvent("beforehide", this);
19546 this.hidden = true;
19547 this.el.removeClass('open');
19549 Roo.get(document).un("mouseup", this.onMouseUp);
19551 this.fireEvent("hide", this);
19554 onMouseUp : function()
19568 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19571 * @class Roo.bootstrap.menu.Item
19572 * @extends Roo.bootstrap.Component
19573 * Bootstrap MenuItem class
19574 * @cfg {Boolean} submenu (true | false) default false
19575 * @cfg {String} html text of the item
19576 * @cfg {String} href the link
19577 * @cfg {Boolean} disable (true | false) default false
19578 * @cfg {Boolean} preventDefault (true | false) default true
19579 * @cfg {String} icon Font awesome icon
19580 * @cfg {String} pos Submenu align to (left | right) default right
19584 * Create a new Item
19585 * @param {Object} config The config object
19589 Roo.bootstrap.menu.Item = function(config){
19590 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19594 * Fires when the mouse is hovering over this menu
19595 * @param {Roo.bootstrap.menu.Item} this
19596 * @param {Roo.EventObject} e
19601 * Fires when the mouse exits this menu
19602 * @param {Roo.bootstrap.menu.Item} this
19603 * @param {Roo.EventObject} e
19609 * The raw click event for the entire grid.
19610 * @param {Roo.EventObject} e
19616 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19621 preventDefault: true,
19626 getAutoCreate : function()
19631 cls : 'roo-menu-item-text',
19639 cls : 'fa ' + this.icon
19648 href : this.href || '#',
19655 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19659 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19661 if(this.pos == 'left'){
19662 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19669 initEvents : function()
19671 this.el.on('mouseover', this.onMouseOver, this);
19672 this.el.on('mouseout', this.onMouseOut, this);
19674 this.el.select('a', true).first().on('click', this.onClick, this);
19678 onClick : function(e)
19680 if(this.preventDefault){
19681 e.preventDefault();
19684 this.fireEvent("click", this, e);
19687 onMouseOver : function(e)
19689 if(this.submenu && this.pos == 'left'){
19690 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19693 this.fireEvent("mouseover", this, e);
19696 onMouseOut : function(e)
19698 this.fireEvent("mouseout", this, e);
19710 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19713 * @class Roo.bootstrap.menu.Separator
19714 * @extends Roo.bootstrap.Component
19715 * Bootstrap Separator class
19718 * Create a new Separator
19719 * @param {Object} config The config object
19723 Roo.bootstrap.menu.Separator = function(config){
19724 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19727 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19729 getAutoCreate : function(){